kschiess / parslet

A small PEG based parser library. See the Hacking page in the Wiki as well.
kschiess.github.com/parslet
MIT License
805 stars 95 forks source link

If you use scope, context cache will hit incorrectly. #197

Open nak1114 opened 5 years ago

nak1114 commented 5 years ago

If you use scope, context cache will hit incorrectly. Bug reproduction example:

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.