Reputation: 12276
TL;DR : How do you reference an optional rule rulename?
from within a grammar action?
None
(null) when the value
rule is not matched, and accessing an attribute of a null reference gives an error:
| NOP3 value? {print( $value.ret )}
Then I tried this, but now I get the error that I can't reference the RuleContext $value itself but I have to reference one of its attributes: (error(67): missing attribute access on rule reference value in $value)
| NOP3 value? {print( $value.ret if $value is not None else "empty" )}
I was able to make it work with this dirty workaround that injects custom hacky code that plugs to an if whose else clause if triggered when the subrule value is not matched, but it's ugly and I guess there should be a better solution for this:
| NOP3 value? {else:
class obj(object):
pass
localctx._value = obj()
localctx._value.ret = None
print( $value.ret )}
Note: $value.ret is the return value of the sub-rule.
Edit: An iteration on Bart Kiers' answer:
As I really don't need to do anything if the value sub-rule is not matched, I was able to simplify it like this:
| NOP3 ( value {do_something()} )?
So basically made value?
a sub-rule and embedded the action inside it, instead of the parent rule.
Upvotes: 1
Views: 285
Reputation: 170178
I think you must test for None
is that case:
| NOP3 value? {print("nada" if $value is None else $value.ret)}
or something like this:
| NOP3 v=value? {print("nada" if $v is None else $v.ret)}
or even something like this could work:
| NOP3 (value {print($value.ret)} | {print("nada")})
(assuming you're embedding Python code)
However, I highly recommend not embedding target specific code in your grammar: that is better done in a listener or visitor.
Upvotes: 1