Class: Walrat::MemoizingCache
- Inherits:
-
Object
- Object
- Walrat::MemoizingCache
- Defined in:
- lib/walrat/memoizing_cache.rb
Overview
The MemoizingCache class memoizes the outcomes of parse operations. The functionality is implemented as a separate class so as to minimize the amount of “contamination” of other classes by memoizing code, and to allow memoizing to be cleanly turned on or off at will. If a MemoizingCache is passed to a Parslet, ParsletCombination or Predicate as a value for the :memoizer key in the options hash passed to a parse method, the class implementing that method will call the parse method on the cache rather than proceeding normally. The cache will either propagate the previously memoized result, or will defer back to the original class to obtain the result. A circular dependency is avoided by setting the :skip_memoizer flag in the options dictionary. If no MemoizingCache is passed then normal program flow takes place.
Defined Under Namespace
Classes: NoValueForKey
Instance Method Summary collapse
- #check_left_recursion(parseable, options = {}) ⇒ Object
-
#initialize ⇒ MemoizingCache
constructor
A new instance of MemoizingCache.
-
#parse(string, options = {}) ⇒ Object
The receiver checks whether there is already a stored result corresponding to that a unique identifier that specifies the “coordinates” of a parsing operation (location, parseable, skipping override).
Constructor Details
#initialize ⇒ MemoizingCache
Returns a new instance of MemoizingCache.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/walrat/memoizing_cache.rb', line 45 def initialize # The results of parse operations are stored (memoized) in a cache, keyed # on a unique identifier comprising the Parslet, ParsletCombination or # Predicate used in the parse operation, the location of the operation # (the line_start and column_start), and the skipping override (if any). # The values may be: # # - ParseErrors raised during parsing # - SkippedSubstringExceptions raised during parsing # - :ZeroWidthParseSuccess symbols thrown during parsing # - :AndPredicateSuccess symbols thrown during parsing # - :NotPredicateSuccess symbols thrown during parsing # - String instances returned as parse results # - MatchDataWrapper instance returned as parse results # - Array instances containing ordered collections of parse results # - Node subclass instances containing AST productions @cache = Hash.new NoValueForKey.instance end |
Instance Method Details
#check_left_recursion(parseable, options = {}) ⇒ Object
118 119 120 121 122 123 124 |
# File 'lib/walrat/memoizing_cache.rb', line 118 def check_left_recursion parseable, = {} if parseable.kind_of? SymbolParslet and @last_seen_symbol_parslet == parseable and @last_seen_symbol_parslet_location == [[:line_start], [:column_start]] raise LeftRecursionException end end |
#parse(string, options = {}) ⇒ Object
The receiver checks whether there is already a stored result corresponding to that a unique identifier that specifies the “coordinates” of a parsing operation (location, parseable, skipping override). If found propogates the result directly to the caller rather than performing the parse method all over again. Here “propagation” means re-raising parse errors, re-throwing symbols, and returning object references. If not found, performs the parsing operation and stores the result in the cache before propagating it.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/walrat/memoizing_cache.rb', line 72 def parse string, = {} raise ArgumentError if string.nil? # construct a unique identifier identifier = [[:parseable], [:line_start], [:column_start]] identifier << [:origin] if .has_key? :origin identifier << [:skipping_override] if .has_key? :skipping_override if (result = @cache[identifier]) != NoValueForKey.instance if result.kind_of? Symbol throw result elsif result.kind_of? Exception raise result else return result end else # first time for this parseable/location/skipping_override (etc) # combination; capture result and propagate catch :NotPredicateSuccess do catch :AndPredicateSuccess do catch :ZeroWidthParseSuccess do begin [:ignore_memoizer] = true # short-circuit left recursion here rather than infinite # looping if [:parseable].kind_of? SymbolParslet check_left_recursion([:parseable], ) @last_seen_symbol_parslet = [:parseable] @last_seen_symbol_parslet_location = [[:line_start], [:column_start]] end return @cache[identifier] = [:parseable].memoizing_parse(string, ) # store and return rescue Exception => e raise @cache[identifier] = e # store and re-raise end end throw @cache[identifier] = :ZeroWidthParseSuccess # store and re-throw end throw @cache[identifier] = :AndPredicateSuccess # store and re-throw end throw @cache[identifier] = :NotPredicateSuccess # store and re-throw end end |