Class: QED::Parser
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 a bit of support for Markdown.
Defined Under Namespace
Classes: Block
Instance Attribute Summary collapse
-
#ast ⇒ Object
readonly
Abstract Syntax Tree.
-
#file ⇒ Object
readonly
File to parse.
-
#options ⇒ Object
readonly
Parser options.
Instance Method Summary collapse
-
#initialize(file, options = {}) ⇒ Parser
constructor
A new instance of Parser.
- #lines ⇒ Object
-
#parse ⇒ Object
# Parse the demo into an abstract syntax tree.
-
#parse_comment_lines ⇒ Object
TODO: It would be nice if we could get ther require statement for the comment mode to be relative to an actual loadpath.
- #parse_lines ⇒ Object
Constructor Details
#initialize(file, options = {}) ⇒ Parser
Returns a new instance of Parser.
13 14 15 16 17 |
# File 'lib/qed/parser.rb', line 13 def initialize(file, ={}) @file = file @options = @ast = [] end |
Instance Attribute Details
#ast ⇒ Object (readonly)
Abstract Syntax Tree
20 21 22 |
# File 'lib/qed/parser.rb', line 20 def ast @ast end |
#file ⇒ Object (readonly)
File to parse.
23 24 25 |
# File 'lib/qed/parser.rb', line 23 def file @file end |
#options ⇒ Object (readonly)
Parser options.
26 27 28 |
# File 'lib/qed/parser.rb', line 26 def @options end |
Instance Method Details
#lines ⇒ Object
29 30 31 |
# File 'lib/qed/parser.rb', line 29 def lines @lines ||= parse_lines end |
#parse ⇒ Object
# Parse the demo into an abstract syntax tree.
#
# TODO: I know there has to be a faster way to do this.
def parse
blocks = [[]]
state = :none
lines.each do |lineno, line|
case line
when /^$/
case state
when :code
blocks.last << line
when :blank
blocks.last << line
else
blocks.last << line
state = :blank
end
when /^\s+/
blocks << [] if state != :code
blocks.last << line
state = :code
else
blocks << [] if state != :text
blocks.last << line
state = :text
end
end
blocks.shift if blocks.first.empty?
line_cnt = 1
blocks.each do |block|
text = block.join
case text
when /\A\s+/
add_section(:code, text, line_cnt)
else
add_section(:text, text, line_cnt)
end
line_cnt += block.size
end
#@ast.reject!{ |sect| sect.type == :code && sect.text.strip.empty? }
return @ast
end
#
def add_section(state, text, lineno)
case state
when :code
if ast.last && ast.last.cont?
@ast.last << text #clean_quote(text)
else
@ast << CodeSection.new(text, lineno)
end
else
@ast << TextSection.new(text, lineno)
#cont = (/\.\.\.\s*^/ =~ text ? true : false)
end
end
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/qed/parser.rb', line 143 def parse tree = [] flush = true pend = false block = Block.new(file) lines.each do |lineno, line| case line when /^\s*$/ if flush pend = true unless lineno == 0 block.raw << [lineno, line] else block.raw << [lineno, line] end when /\A\s+/ if flush tree << block.ready!(flush, tree.last) block = Block.new(file) end pend = false flush = false block.raw << [lineno, line] else if pend || !flush tree << block.ready!(flush, tree.last) pend = false flush = true block = Block.new(file) end block.raw << [lineno, line] end end tree << block.ready!(flush, tree.last) @ast = tree end |
#parse_comment_lines ⇒ Object
TODO: It would be nice if we could get ther require statement for the comment mode to be relative to an actual loadpath.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/qed/parser.rb', line 48 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_lines ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/qed/parser.rb', line 34 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 |