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.
18 19 20 21 22 |
# File 'lib/qed/parser.rb', line 18 def initialize(file, ={}) @file = file @options = @ast = [] end |
Instance Attribute Details
#ast ⇒ Object (readonly)
Abstract Syntax Tree
25 26 27 |
# File 'lib/qed/parser.rb', line 25 def ast @ast end |
#file ⇒ Object (readonly)
File to parse.
28 29 30 |
# File 'lib/qed/parser.rb', line 28 def file @file end |
#options ⇒ Object (readonly)
Parser options.
31 32 33 |
# File 'lib/qed/parser.rb', line 31 def @options end |
Instance Method Details
#lines ⇒ Object
34 35 36 |
# File 'lib/qed/parser.rb', line 34 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
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 178 179 180 181 182 |
# File 'lib/qed/parser.rb', line 148 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.
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 80 81 82 83 84 |
# File 'lib/qed/parser.rb', line 53 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
39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/qed/parser.rb', line 39 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 |