Module: NonTerminalNode
- Defined in:
- lib/rubypeg.rb
Overview
By default all non terminals that are returned by RubyPeg#parse are Arrays that have been extended with the NonTerminalNode module
If we consider this example:
class BasketPeg < RubyPeg
def root
node :basket do
one_or_more { items }
end
end
def items
node :item do
number && optional_space && fruit && optional_space
end
end
def number
terminal(/\d+/)
end
def fruit
node :fruit do
(terminal("apple") || terminal("pear")) && ignore{ optional{ terminal("s") } }
end
end
def optional_space
ignore{ optional{ terminal(" ") }}
end
end
Then
BasketPeg.parse("1 apple 2 apples 3 pears").should be_kind_of(NonTerminalNode)
This is an array of children of this non terminal. The children may be other non-terminals or terminals The array will be empty if there are no children.
basket = BasketPeg.parse("1 apple 2 apples 3 pears")
basket.class.should == Array
basket.size.should == 3
basket.first.should be_kind_of(NonTerminalNode)
basket.first.type.should == :item
basket.first.class.should == Array
basket.first.size.should == 2
basket.first.first.should be_kind_of(TerminalNode)
basket.first.first.should == "1"
basket.first.last.should be_kind_of(NonTerminalNode)
basket.first.last.type == :fruit
basket.first.last.class.should == Array
basket.first.last.size.should == 1
basket.first.last.first.should be_kind_of(TerminalNode)
basket.first.last.first.should == "apple"
Instance Attribute Summary collapse
-
#type ⇒ Object
Contains the argument given to RubyPeg#node BasketPeg.parse(“1 apple 2 apples 3 pears”).type.should == :basket.
Instance Method Summary collapse
-
#inspect ⇒ Object
Lists the non-terminal node and its children.
-
#to_ast ⇒ Object
Returns the node network as an abstract syntax tree.
-
#to_s ⇒ Object
Returns the result of calling to_s on each of its children.
-
#visit(builder = nil) ⇒ Object
This is a quick way of carrying out the visitor pattern on the parsed structure.
Instance Attribute Details
#type ⇒ Object
Contains the argument given to RubyPeg#node
BasketPeg.parse("1 apple 2 apples 3 pears").type.should == :basket
67 68 69 |
# File 'lib/rubypeg.rb', line 67 def type @type end |
Instance Method Details
#inspect ⇒ Object
Lists the non-terminal node and its children. Same content as #to_ast but in string form.
BasketPeg.parse("1 apple 2 apples 3 pears").inspect.should == '[:basket, [:item, "1", [:fruit, "apple"]], [:item, "2", [:fruit, "apple"]], [:item, "3", [:fruit, "pear"]]]'
119 |
# File 'lib/rubypeg.rb', line 119 def inspect; to_ast.inspect end |
#to_ast ⇒ Object
Returns the node network as an abstract syntax tree
BasketPeg.parse("1 apple 2 apples 3 pears").to_ast.should == [:basket, [:item, "1", [:fruit, "apple"]], [:item, "2", [:fruit, "apple"]], [:item, "3", [:fruit, "pear"]]]
Note that the items wrapped in ignore {} in the parser, shuch as the spaces and the optional ‘s’ in apples and pears do not appear.
113 114 115 |
# File 'lib/rubypeg.rb', line 113 def to_ast [type,*self.map(&:to_ast)] end |
#to_s ⇒ Object
Returns the result of calling to_s on each of its children. By default, TerminalNode#to_s returns its text value, so:
BasketPeg.parse("1 apple 2 apples 3 pears").to_s.should == "1apple2apple3pear"
Note that the items wrapped in ignore {} in the parser, shuch as the spaces and the optional ‘s’ in apples and pears do not appear.
124 |
# File 'lib/rubypeg.rb', line 124 def to_s; self.map(&:to_s).join end |
#visit(builder = nil) ⇒ Object
This is a quick way of carrying out the visitor pattern on the parsed structure.
If no visitor is supplied then a nested array of child nodes is returned, with terminals turned into strings:
BasketPeg.parse("1 apple 2 apples 3 pears").build.should == [["1", "apple"], ["2", "apple"], ["3", "pear"]]
If a visitor is supplied, then each non terminal node checks if there is a method on the visitor with a name the same as the non terminal’s type. If there is, then the method is called with the children of the non terminal as arguments. If there isn’t, then the build methods on the children of this node ar recursively called. E.g.,:
BasketPeg.parse("1 apple 2 apples 3 pears").build.should == [["1", "apple"], ["2", "apple"], ["3", "pear"]]
class BasketPegBuilderExample
attr_accessor :total
def initialize
@total = 0
end
def item(number,kind)
@total = @total + (number.to_f * kind.build(self).to_f)
end
def fruit(kind_of_fruit)
case kind_of_fruit
when "apple"; 3.0
when "pear"; 1.0
else 10.0
end
end
end
counter = BasketPegBuilderExample.new
BasketPeg.parse("1 apple 2 apples 3 pears").build(counter)
counter.total.should == 12.0
103 104 105 106 107 |
# File 'lib/rubypeg.rb', line 103 def visit(builder = nil) return builder.send(type,*self) if builder.respond_to?(type) return self.first.visit(builder) if self.size == 1 self.map { |c| c.visit(builder) } end |