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