class Parslet::Atoms::Context
Helper class that implements a transient cache that maps position and parslet object to results. This is used for memoization in the packrat style.
Also, error reporter is stored here and error reporting happens through this class. This makes the reporting pluggable.
Attributes
Returns the current captures made on the input (see Parslet::Atoms::Base#capture
). Use as follows:
context.captures[:foobar] # => returns capture :foobar
Public Class Methods
@param reporter [#err, err_at
] Error reporter (leave empty for default
reporter)
# File lib/parslet/atoms/context.rb, line 12 def initialize(reporter=Parslet::ErrorReporter::Tree.new) @cache = Hash.new { |h, k| h[k] = {} } @reporter = reporter @captures = Parslet::Scope.new end
Public Instance Methods
Report an error. @see ErrorReporter
# File lib/parslet/atoms/context.rb, line 61 def err(*args) return [false, @reporter.err(*args)] if @reporter return [false, nil] end
Report an error at a given position. @see ErrorReporter
# File lib/parslet/atoms/context.rb, line 53 def err_at(*args) return [false, @reporter.err_at(*args)] if @reporter return [false, nil] end
Starts a new scope. Use the scope
method of Parslet::Atoms::DSL
to call this.
# File lib/parslet/atoms/context.rb, line 84 def scope captures.push yield ensure captures.pop end
Report a successful parse. @see ErrorReporter::Contextual
# File lib/parslet/atoms/context.rb, line 69 def succ(*args) return [true, @reporter.succ(*args)] if @reporter return [true, nil] end
Caches a parse answer for obj at source.pos. Applying the same parslet at one position of input always yields the same result, unless the input has changed.
We need the entire source here so we can ask for how many characters were consumed by a successful parse. Imitation of such a parse must advance the input pos by the same amount of bytes.
# File lib/parslet/atoms/context.rb, line 26 def try_with_cache(obj, source, consume_all) beg = source.bytepos # Not in cache yet? Return early. unless entry = lookup(obj, beg) result = obj.try(source, self, consume_all) if obj.cached? set obj, beg, [result, source.bytepos-beg] end return result end # the condition in unless has returned true, so entry is not nil. result, advance = entry # The data we're skipping here has been read before. (since it is in # the cache) PLUS the actual contents are not interesting anymore since # we know obj matches at beg. So skip reading. source.bytepos = beg + advance return result end
Private Instance Methods
NOTE These methods use object_id directly, since that seems to bring the most performance benefit. This is a hot spot; going through Atoms::Base#hash doesn't yield as much.
# File lib/parslet/atoms/context.rb, line 96 def lookup(obj, pos) @cache[pos][obj.object_id] end
# File lib/parslet/atoms/context.rb, line 99 def set(obj, pos, val) @cache[pos][obj.object_id] = val end