librelist archives

« back to archive

Rule does not fire

Rule does not fire

From:
Thiel Chang
Date:
2011-05-05 @ 11:52
Hi guys,

I am still trying to understand the Parslet transformations.

My rules are:

Rule Leaves:
@t.rule(:ident => simple(:str)) { str
       #Some code
       str
     }

Rule Factor1:
@t.rule(:factor => simple(:str)) { str
       #some code
       str
     }

Rule Factor2:
@t.rule(:factor => simple(:str)) { str
       #Some code
       str
     }

My program code is:

transforms = [Leaves, Factor1, Factor2]
str         =  ' a + b '
tree       = parser.parse_with_debug( str )
puts "PARSING      :  #{str}"
puts "ORIGINAL TREE: "
pp tree
transforms.inject(tree) do | tree, rule |
   puts "\nTRANSFORMED BY RULE: #{rule.to_s}"
   trans = rule.new(st,at,gt)
   tree   = trans.apply(tree)
   pp tree
   tree
end

The output is:

PARSING           :    a + b
ORIGINAL TREE:
{:result=>
   {:term=>
     {:factor=>{:ident=>"a"@2},
      :plus=>"+ "@4,
      :term=>{:factor=>{:ident=>"b"@6}}}}}

TRANSFORMED BY RULE: Leaves
{:result=>{:term=>{:factor=>"a"@2, :plus=>"+ "@4, :term=>{:factor=>"b"@6}}}}

TRANSFORMED BY RULE: Factor1
{:result=>{:term=>{:factor=>"a"@2, :plus=>"+ "@4, :term=>"b"@6}}}

TRANSFORMED BY RULE: Factor2
{:result=>{:term=>{:factor=>"a"@2, :plus=>"+ "@4, :term=>"b"@6}}} <====  ?

My question: "why does not :term=>{factor=>"a" being transformed in 
:term => "a" after firing the Factor2 rule?"

Thanks in advance,

Thiel


Re: [ruby.parslet] Rule does not fire

From:
Ant Skelton
Date:
2011-05-05 @ 11:59
Hi.


> I am still trying to understand the Parslet transformations.
>
> My rules are:
>
> Rule Factor2:
> @t.rule(:factor => simple(:str)) { str
>       #Some code
>       str
>     }
> {:result=>{:term=>{:factor=>"a"@2, :plus=>"+ "@4, :term=>"b"@6}}}
>
>
> My question: "why does not :term=>{factor=>"a" being transformed in
> :term => "a" after firing the Factor2 rule?"
>

Because you asked to match a simple() thing, but in your parse tree, :factor
points to a subtree, not a simple scalar.

Something else that always trips me up is that sequence() only matches
arrays of simple things, not arrays that contain other sequences, or
subtrees.

HTH

ant

Re: [ruby.parslet] Rule does not fire

From:
Thiel Chang
Date:
2011-05-05 @ 12:16
Hi Ant,

Thanks for your answer.

I agree with your comment and changed the Factor2 rule into:

@t.rule(:factor => subtree(:x))  { x
       #Some code
       x
     }

But it still gives the same output:  {:result=>{:term=>{:factor=>"a"@2, 
:plus=>"+ "@4, :term=>"b"@6}}}

I read the Parslet rdoc documentation but unfortunately it lacks genuine 
examples of transformation rules for those who want to do semantic actions.
It requires a lot of patience to struggle on :-)

Cheers,

Thiel

Op 5-5-2011 13:59, Ant Skelton schreef:
> Hi.
>
>     I am still trying to understand the Parslet transformations.
>
>     My rules are:
>
>     Rule Factor2:
>     @t.rule(:factor => simple(:str)) { str
>           #Some code
>           str
>         }
>     {:result=>{:term=>{:factor=>"a"@2, :plus=>"+ "@4, :term=>"b"@6}}}
>
>
>     My question: "why does not :term=>{factor=>"a" being transformed in
>     :term => "a" after firing the Factor2 rule?"
>
>
> Because you asked to match a simple() thing, but in your parse tree, 
> :factor points to a subtree, not a simple scalar.
>
> Something else that always trips me up is that sequence() only matches 
> arrays of simple things, not arrays that contain other sequences, or 
> subtrees.
>
> HTH
>
> ant

Re: [ruby.parslet] Rule does not fire

From:
Ant Skelton
Date:
2011-05-05 @ 12:23
>
> Thanks for your answer.
>
> But it still gives the same output:  {:result=>{:term=>{:factor=>"a"@2,
> :plus=>"+ "@4, :term=>"b"@6}}}
>

Yes, sorry about that. I was engaged in what is known hereabouts as "talking
out of my arse". See later post for some more informed ideas.

ant

Re: [ruby.parslet] Rule does not fire

From:
Ant Skelton
Date:
2011-05-05 @ 12:05
Ignore me, I completely misread your question ;)

ant

Re: [ruby.parslet] Rule does not fire

From:
Ant Skelton
Date:
2011-05-05 @ 12:15
I'll have another crack at it ;)

I think you're problem is that you're only matching on :factor, whereas your
hash contains :plus and :term too, so you need to match those also. The
logic seems to be that you have to explicitly match all labelled terms that
are present. Of course, just because you'ved matched them, you don't have to
use them.

For example:

#!/usr/bin/env ruby
require 'parslet'
require 'ap'

t = {
    :result => {
                :term => {
                            :factor => "a",
                            :plus => "+ ",
                            :term=>"b"
                        }
                }
    }

transform = Parslet::Transform.new do
    rule(:factor => simple(:str), :plus => simple(:str2), :term =>
simple(:str3)) { str }
end

puts "original:"
ap t
puts "transform:"
ap transform.apply(t)  # matches



will give the result:

transform:
{
    :result => {
        :term => "a"
    }
}



Which is closer to what you wanted?

cheers

ant

Re: [ruby.parslet] Rule does not fire

From:
Thiel Chang
Date:
2011-05-05 @ 12:34
Hi Ant,

I copied your solution into the Factor2 rule and it showed the same result.
But the result I want is:

    transform:
    {
         :result => {
                     :term => "a"
                     :plus => "+ ",
                     :term=>"b"
                 }
    }


Any idea how to achieve that?

Cheers,

Thiel

ps If your are busy you may answer later.




Op 5-5-2011 14:15, Ant Skelton schreef:
> I'll have another crack at it ;)
>
> I think you're problem is that you're only matching on :factor, 
> whereas your hash contains :plus and :term too, so you need to match 
> those also. The logic seems to be that you have to explicitly match 
> all labelled terms that are present. Of course, just because you'ved 
> matched them, you don't have to use them.
>
> For example:
>
>     #!/usr/bin/env ruby
>     require 'parslet'
>     require 'ap'
>
>     t = {
>         :result => {
>                     :term => {
>                                 :factor => "a",
>                                 :plus => "+ ",
>                                 :term=>"b"
>                             }
>                     }
>         }
>
>     transform = Parslet::Transform.new do
>         rule(:factor => simple(:str), :plus => simple(:str2), :term =>
>     simple(:str3)) { str }
>     end
>
>     puts "original:"
>     ap t
>     puts "transform:"
>     ap transform.apply(t)  # matches
>
>
>
> will give the result:
>
>     transform:
>     {
>         :result => {
>             :term => "a"
>         }
>     }
>
>
>
> Which is closer to what you wanted?
>
> cheers
>
> ant
>
>

Re: [ruby.parslet] Rule does not fire

From:
Ant Skelton
Date:
2011-05-05 @ 12:46
Hi,


>
>   transform:
>   {
>       :result => {
>                 :term => "a"
>                   :plus => "+ ",
>                 :term=>"b"
>               }
>   }
>
>
> Any idea how to achieve that?
>

Closest I can get with a quick and dirty hack:

transform = Parslet::Transform.new do
    rule(:factor => simple(:str), :plus => simple(:str2), :term =>
simple(:str3)) do
        { term: str, plus: str2, term2: str3 }
    end

    rule(:term => subtree(:x)) { x}

end


There's probably a better way; matching a subtree() like that is usually not
a good idea, because of the epic scope for it going catastrophically wrong.

ant