Class: TracLang::Parser

Inherits:
Object
  • Object
show all
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

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