Search code examples
rubytreetop

How to code an action trigger with treetop?


I'm trying to have some bit of code running each time the parser recognises a token.

Let's say

grammar FooBar

  rule start
    (foo "\n")+
  end

  rule foo
    stuff_i_want:([a-z]+) {
       puts "Hi there I found: #{stuff_i_want.text_value}"
     }
  end

end

The idea here would be to have this puts action execute each time the foo token is found. Coded as is, it does not work as it is triggered only once (at the class loading time) and of course stuff_i_want.text_value does not exist then.

Any idea? Is it even possible? The lack of documentation on the library does not make it easy to tell.


Solution

  • Well, I'm not sure what I did to deserve the downvote.

    Anyway, here is the solution I used:

    node_extension.rb

    module Crawlable
    
      def crawl *args
        continue = true
        continue = action(*args) if respond_to? :action
    
        return if !continue || elements.nil?
    
        elements.each do |elt|
          elt.crawl(*args)
        end
      end
    
    end
    
    # reopen the SyntaxNode class and include the module to add the functionality
    class Treetop::Runtime::SyntaxNode
    
      include Crawlable
    
    end
    

    then all is left is to define a action(*args) method on each node you want to trigger an effect on and have to start the crawling on the top parser node (the one returned by the parse call

    parse_tree = FooBarParser.new.parse "mycontent"
    parse_tree.crawl # add optional parameters for context/state
    

    The optional parameters are passed to each action method. You can also return a falsey value (false or nil) in action in order to stop the subtree crawling.

    grammar FooBar
    
      rule start
        (foo "\n")+
      end
    
      rule foo
        stuff_i_want:([a-z]+) {
           def action
             puts "Hi there I found: #{stuff_i_want.text_value}"
    
             false
           end
         }
      end
    
    end