Permalink
Browse files

unique @children list for all the atoms

/!\ probably requires a rework of the files in example/
/!\ this children thing is circular
  • Loading branch information...
1 parent 821aec6 commit fc6961e2261364d3c21082ea2aa0886fc2925ff7 @jmettraux committed Apr 16, 2012
@@ -7,7 +7,6 @@
# str('a') | str('b') # matches either 'a' or 'b'
#
class Parslet::Atoms::Alternative < Parslet::Atoms::Base
- attr_reader :alternatives
# Constructs an Alternative instance using all given parslets in the order
# given. This is what happens if you call '|' on existing parslets, like
@@ -16,18 +15,19 @@ class Parslet::Atoms::Alternative < Parslet::Atoms::Base
# str('a') | str('b')
#
def initialize(*alternatives)
- super()
+ super(alternatives)
- @alternatives = alternatives
@error_msg = "Expected one of #{alternatives.inspect}"
end
+ alias alternatives children
+
#---
# Don't construct a hanging tree of Alternative parslets, instead store them
# all here. This reduces the number of objects created.
#+++
def |(parslet) # :nodoc:
- self.class.new(*@alternatives + [parslet])
+ self.class.new(*alternatives + [parslet])
end
def try(source) # :nodoc:
@@ -22,6 +22,21 @@ class Success < Struct.new(:result)
def error?; false end
end
+ # An array of children parslets. A parslet with an empty children list
+ # is a leaf.
+ #
+ attr_reader :children
+
+ def initialize(children=[])
+ @children = children
+ end
+
+ alias parslets children
+
+ def parslet
+ @children.first
+ end
+
# Given a string or an IO object, this will attempt a parse of its contents
# and return a result. If the parse fails, a Parslet::ParseFailed exception
# will be thrown.
@@ -22,9 +22,13 @@ def try(source) # :nodoc:
end
def parslet
- @parslet ||= @block.call.tap { |p|
- raise_not_implemented unless p
- }
+ resolve
+ @children.first
+ end
+
+ def children
+ resolve
+ @children
end
def to_s_inner(prec) # :nodoc:
@@ -37,10 +41,14 @@ def error_tree # :nodoc:
private
def raise_not_implemented # :nodoc:
- trace = caller.reject {|l| l =~ %r{#{Regexp.escape(__FILE__)}}} # blatantly stolen from dependencies.rb in activesupport
- exception = NotImplementedError.new("rule(#{name.inspect}) { ... } returns nil. Still not implemented, but already used?")
- exception.set_backtrace(trace)
+ raise(
+ NotImplementedError,
+ "rule(#{name.inspect}) { ... } returns nil. Still not implemented, but already used?",
+ caller.reject { |l| l =~ %r{#{Regexp.escape(__FILE__)}}}) # blatantly stolen from dependencies.rb in activesupport
+ end
- raise exception
+ def resolve
+ return if @children.any?
+ @children << @block.call.tap { |pa| raise_not_implemented unless pa }
end
end
@@ -6,21 +6,21 @@
#
class Parslet::Atoms::Lookahead < Parslet::Atoms::Base
attr_reader :positive
- attr_reader :bound_parslet
def initialize(bound_parslet, positive=true) # :nodoc:
- super()
+ super([ bound_parslet ])
# Model positive and negative lookahead by testing this flag.
@positive = positive
- @bound_parslet = bound_parslet
@error_msgs = {
:positive => ["Input should start with ", bound_parslet],
:negative => ["Input should not start with ", bound_parslet]
}
end
+ alias bound_parslet parslet
+
def try(source) # :nodoc:
pos = source.pos
@@ -6,11 +6,11 @@
# str('foo').as(:foo) # will return :foo => 'foo'
#
class Parslet::Atoms::Named < Parslet::Atoms::Base
- attr_reader :parslet, :name
+ attr_reader :name
def initialize(parslet, name) # :nodoc:
- super()
+ super([ parslet ])
- @parslet, @name = parslet, name
+ @name = name
end
def apply(source) # :nodoc:
@@ -7,11 +7,10 @@
# str('a').maybe # matches 'a' if it is present in the input (repeat(0,1))
#
class Parslet::Atoms::Repetition < Parslet::Atoms::Base
- attr_reader :min, :max, :parslet
+ attr_reader :min, :max
def initialize(parslet, min, max, tag=:repetition)
- super()
+ super([ parslet ])
- @parslet = parslet
@min, @max = min, max
@tag = tag
@error_msgs = {
@@ -5,22 +5,20 @@
# str('a') >> str('b') # matches 'a', then 'b'
#
class Parslet::Atoms::Sequence < Parslet::Atoms::Base
- attr_reader :parslets
def initialize(*parslets)
- super()
+ super(parslets)
- @parslets = parslets
@error_msgs = {
:failed => "Failed to match sequence (#{self.inspect})"
}
end
def >>(parslet) # :nodoc:
- self.class.new(* @parslets+[parslet])
+ self.class.new(*(parslets + [parslet]))
end
def try(source) # :nodoc:
- success([:sequence]+parslets.map { |p|
+ success([:sequence] + parslets.map { |p|
# Save each parslet as potentially offending (raising an error).
@offending_parslet = p

0 comments on commit fc6961e

Please sign in to comment.