Why "undefined method 'content' for Treetop..." ?

33 views
Skip to first unread message

Dave Collins

unread,
Jun 10, 2017, 8:13:32 PM6/10/17
to Treetop Development
Hello,

   Very new to using Treetop and working on a simple proof-of-concept grammar where I need to define my own internal methods in Treetop nodes.

A very simple example such as this is working fine:

grammar SimpleHTML
  rule document
    (text / tag)* {
      def content
        elements.map{ |e| e.content }
      end
    }
  end

  rule text
    [^<]+ {
      def content
        [:text, text_value]
      end
    }
  end

  rule tag
    "<" [^>]+ ">" {
      def content
        [:tag, text_value]
      end
    }
  end
end


However, When I try to use another grammar of mine that is working (as far as parsing) to add the "content" methods I keep getting:
NoMethodError: undefined method `content' for #<Treetop::Runtime::SyntaxNode:0x007f91e414d228>
no matter what I try.  I've added def content ... end in EVERY node of the grammar, and tried many variations:

grammar EquipmentGrammar
 
  rule top
    (equipment)* {
      def content
        elements.map{ |e| e.content }
      end
    }
  end

  rule equipment
    (manufacturer ws capacity ws system) /
    (manufacturer ws system) {
      def content
        elements.map{ |e| e.content }
      end
    }
  end

  rule manufacturer
    'Frigoboat'i / 'Jabsco'i {
      def content
        [text_value]
      end
    }
  end

  rule system
    system_ac / system_plumbing {
      def content
        [elements.first.content]
      end
    }
  end

  rule system_ac
    'air conditioning system'i / 'air conditioning'i / 'a/c'i  {
      def content
        ['A/C']
      end
    }
  end

  rule system_plumbing
    'plumbing' / 'plumbing system' {
      def content
        ['Plumbing']
      end
    }
  end

  rule capacity
    '6,000 BTU' {
      def content
        [elements.first.content]
      end
    }
  end

  rule ws
    [\s\n\t\r]* {
      def content
        [' ']
      end
    }
  end

end


Now if I use that to parse a sample string:
[22] pry(main)> Treetop.load 'app/grammars/equipment_grammar'
=> EquipmentGrammarParser
[23] pry(main)> parser = EquipmentGrammarParser.new
=> #<EquipmentGrammarParser:0x007f91dcea94b0 @consume_all_input=true>
[24] pry(main)> tree = parser.parse("Frigoboat 6,000 BTU air conditioning system")
=> SyntaxNode+Top0 offset=0, "... conditioning system" (content):
  SyntaxNode+Equipment0 offset=0, "... conditioning system" (system,manufacturer,ws1,capacity,ws2):
    SyntaxNode offset=0, "Frigoboat"
    SyntaxNode+Ws0 offset=9, " " (content):
      SyntaxNode offset=9, " "
    SyntaxNode+Capacity0 offset=10, "6,000 BTU" (content)
    SyntaxNode+Ws0 offset=19, " " (content):
      SyntaxNode offset=19, " "
    SyntaxNode offset=20, "... conditioning system"
[25] pry(main)> tree.content
NoMethodError: undefined method `content' for #<Treetop::Runtime::SyntaxNode:0x007f91e414d228>
from (eval):10:in `block in content'



Any help or suggestions on defining and/or using your own methods would be greatly appreciated!




Clifford Heath

unread,
Jun 12, 2017, 2:07:01 AM6/12/17
to treet...@googlegroups.com
Dave,

I think your problem is with parentheses. Specifically this:

> rule equipment
> (manufacturer ws capacity ws system) /
> (manufacturer ws system) {
> def content
> elements.map{ |e| e.content }
> end
> }
> end

applies the "content" method only to the second alternative, not the first.
If you want to apply it to both, you need parentheses around them before
the open-curly {.

You don't need the other parentheses in that rule.
Alternation "/" has lower precedence than conjunction (sequence).

> rule system...

> rule system_ac...
> rule system_plumbing...

Same problem in these three rules.

Clifford Heath.

Dave Collins

unread,
Jun 12, 2017, 8:35:21 PM6/12/17
to Treetop Development
Thank you so much Clifford!  That solved the problem.

Much appreciated.
Dave
Reply all
Reply to author
Forward
0 new messages