Class: TracLang::Parser
- Inherits:
-
Object
- Object
- TracLang::Parser
- Defined in:
- lib/trac_lang/parser.rb
Overview
Parser for TRAC input. Given the input a character at a time, it creates an active string and then executes it when the string is completed.
Instance Method Summary collapse
-
#concat(c) ⇒ Object
Add character to current expression, ignore if no expression exists.
-
#parens(c) ⇒ Object
Handler while reading inside protective parentheses.
-
#parse(str, &blk) ⇒ Object
Parses the given string and executes it, until the active string is empty.
-
#reading(c, &blk) ⇒ Object
Handler while actively reading the active string.
-
#start_proc(c, &blk) ⇒ Object
Handler for the start of an expression.
Instance Method Details
#concat(c) ⇒ Object
Add character to current expression, ignore if no expression exists
31 32 33 34 35 |
# File 'lib/trac_lang/parser.rb', line 31 def concat(c) unless @expressions.empty? @expressions.last.concat(c) end end |
#parens(c) ⇒ Object
Handler while reading inside protective parentheses. Copies all characters to current expression while keeping track of current parentheses nesting. When a matching parenthesis is found, go back to reading handler.
74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/trac_lang/parser.rb', line 74 def parens(c) case c when '(' @nesting += 1 when ')' @nesting -= 1 if @nesting == 0 @handler = :reading return end end concat(c) end |
#parse(str, &blk) ⇒ Object
Parses the given string and executes it, until the active string is empty.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/trac_lang/parser.rb', line 11 def parse(str, &blk) @active = str @handler = :reading @expressions = [] loop do if @active.empty? # if handler is parens, we've read a open paren w/o a matching closing one throw :reset if @handler == :parens # if handler if reading, and expressions is not empty # we've read #( without a matching end paren throw :reset if @handler == :reading && !@expressions.empty? # if hander is :start_proc, we've just read a bunch of #s # so we can ignore them without throwing an error return end self.send(@handler, @active.slice!(0), &blk) end end |
#reading(c, &blk) ⇒ Object
Handler while actively reading the active string. If you start an expression, switch to the start_proc handler. If you see an open parenthesis, switch to the parens handler. Comma marks a new argument in the current expression, and end parenthesis marks the end of an expression. When an expression is ended, execute it and handle the results.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/trac_lang/parser.rb', line 42 def reading(c, &blk) case c when '#' @expressions.push Expression.new @handler = :start_proc when '(' @nesting = 1 @handler = :parens when ',' unless @expressions.empty? @expressions.last.newarg end when ')' throw :reset if @expressions.empty? expression = @expressions.pop result = blk.call(expression) if result[:force] || expression.active? @active.prepend(result[:value]) else concat(result[:value]) end when "\n", "\r" # ignore cr and lf else concat(c) end end |
#start_proc(c, &blk) ⇒ Object
Handler for the start of an expression. Mark the expression as active or not, depending on whether it starts with #(…) or ##(…).
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/trac_lang/parser.rb', line 90 def start_proc(c, &blk) case c when '#' throw :reset if @expressions.empty? if @expressions.last.active? @expressions.last.active = false else unless @expressions.size == 1 @expressions[-2].concat(c) end end when '(' @handler = :reading else throw :reset if @expressions.empty? discard = @expressions.pop concat(discard.active? ? '#' : '##') @handler = :reading reading(c, &blk) end end |