Open nak1114 opened 5 years ago
If you use scope, context cache will hit incorrectly. Bug reproduction example:
scope
require 'parslet' class Mini < Parslet::Parser NewLine="\n" root(:root) rule(:root) { init >> (exp >> nl).repeat } rule(:init) { dynamic{|s,c|c.captures[:indent]=NewLine;str("")} } rule(:exp){ (int | block).as(:exp) } rule(:space) { match('[ \t\f\v]')} rule(:nl){dynamic{|s,c|str(c.captures[:indent])}} rule(:int) { match('[0-9]').repeat(1) } rule(:block) { str('block').as(:block) >> scope{ indent >> exp >> (nl >>exp).repeat >> dedent } } rule(:dedent){nl.absent?} rule(:indent){(nl >> space.repeat(1) ).capture(:indent)} end str=<<EOS block 123 234 block 345 345 456 567 EOS p Mini.new.parse(str) __END__
Correction example:
require 'parslet' module Parslet::Atoms class Context def scope captures.push @cache = Hash.new { |h, k| h[k] = {} } #<= clear cache when context swithing yield ensure captures.pop @cache = Hash.new { |h, k| h[k] = {} } #<= clear cache when context swithing end end end class Mini < Parslet::Parser NewLine="\n" root(:root) rule(:root) { init >> (exp >> nl).repeat } rule(:init) { dynamic{|s,c|c.captures[:indent]=NewLine;str("")} } rule(:exp){ (int | block).as(:exp) } rule(:space) { match('[ \t\f\v]')} rule(:nl){dynamic{|s,c|str(c.captures[:indent])}} rule(:int) { match('[0-9]').repeat(1) } rule(:block) { str('block').as(:block) >> scope{ indent >> exp >> (nl >>exp).repeat >> dedent } } rule(:dedent){nl.absent?} rule(:indent){(nl >> space.repeat(1) ).capture(:indent)} end str=<<EOS block 123 234 block 345 345 456 567 EOS p Mini.new.parse(str) __END__
I think this is a bad fix. Uncache only objs that use captures.
If you use
scope
, context cache will hit incorrectly. Bug reproduction example:Correction example:
I think this is a bad fix. Uncache only objs that use captures.