Class: QED::Parser

Inherits:
Object show all
Defined in:
lib/qed/parser.rb

Overview

The parser breaks down a demonstandum into structured object to passed thru the script evaluator.

Technically is defines it's own markup language but for interoperability sake it is RDoc and/or Markdown.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(demo, options = {}) ⇒ Parser

Setup new parser instance.

Options Hash (options):

  • :mode (Symbol)

    Parse in `:comment` mode or default mode.


24
25
26
27
28
# File 'lib/qed/parser.rb', line 24

def initialize(demo, options={})
  @demo  = demo
  @mode  = options[:mode]
  @steps = []
end

Instance Attribute Details

#demoObject (readonly)

The demo to parse.


31
32
33
# File 'lib/qed/parser.rb', line 31

def demo
  @demo
end

#modeObject (readonly)

Parser mode.


34
35
36
# File 'lib/qed/parser.rb', line 34

def mode
  @mode
end

#stepsObject (readonly)

Abstract Syntax Tree


37
38
39
# File 'lib/qed/parser.rb', line 37

def steps
  @steps
end

Instance Method Details

#fileObject

The demo's file to parse.


40
41
42
# File 'lib/qed/parser.rb', line 40

def file
  demo.file
end

#linesObject

Lines of demo, prepared for parsing into steps.


45
46
47
# File 'lib/qed/parser.rb', line 45

def lines
  @lines ||= parse_lines
end

#parseObject

Parse demo file into steps.


100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/qed/parser.rb', line 100

def parse
  steps    = []
  blank    = false
  indented = false
  explain  = []
  example  = [] #Step.new(file)

  lines.each do |lineno, line|
    case line
    when /^\s*$/  # blank line
      blank = true
      if indented
        example << [lineno, line]
      else
        explain << [lineno, line]
      end
    when /\A\s+/  #/\A(\t|\ \ +)/  # indented
      indented = true
      blank    = false
      example << [lineno, line]
    else
      if indented or blank
        steps << Step.new(demo, explain, example, steps.last)
        explain, example = [], [] #Step.new(file)
      end
      indented = false
      blank    = false
      explain << [lineno, line]
    end
  end
  steps << Step.new(demo, explain, example, steps.last)
  @steps = steps
end

#parse_comment_linesObject

Parse comment lines into a format that the parse method can use.


66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/qed/parser.rb', line 66

def parse_comment_lines
  ruby_omit = false
  rdoc_omit = false
  lines = [
    [0, "Load #{File.basename(file)} script.\n"],
    [0, "\n"],
    [0, "  require '#{file}'\n"]
  ]
  index = 1
  File.readlines(file).each do |l|
    case l
    when /^=begin(?!\s+qed)/
      ruby_omit = true
    when /^=end/
      ruby_omit = false
    when /^\s*\#\-\-\s*$/
      rdoc_omit = true
    when /^\s*\#\+\+\s*$/
      rdoc_omit = false    ##when /^\s*\#\ \-\-/  # not needed just double comment
    ##  # -- skip internal comments

    when /^\s*##/      ## skip internal comments

    when /^\s*\#/
      lines << [index, l.lstrip.sub(/^\#\ ?/, '')] unless (ruby_omit or rdoc_omit)
    else
      lines << [index, "\n"] unless lines.last[1] == "\n" unless (ruby_omit or rdoc_omit)
    end
    index += 1
  end
  lines
end

#parse_linesObject

Prepare lines for parsing into steps.


50
51
52
53
54
55
56
57
58
59
60
# File 'lib/qed/parser.rb', line 50

def parse_lines
  case mode
  when :comment
    parse_comment_lines
  else
    index = 0  #-1
    File.readlines(file).to_a.map do |line|
      [index += 1, line]
    end
  end
end