I'm working on some code which uses PegKit and I've hit something I'm not sure how to figure out. I have a syntax that looks like this (simplified):
expr = runtimeExpr | objectExpr;
runtimeExpr = is? runtimeObject;
objectExpr = runtimeObject keyPath;
runtimeObject = '[' string ']';
is = 'is';
keyPath = string;
I'm looking for the following results:
[abc] -> runtime expr.
is [abc] -> runtime expr.
[abc].def -> object expr.
However what is occurring is the generated parser code looks like this:
if ([self predicts:STLOGEXPRESSIONPARSER_TOKEN_KIND_IS, 0]) {
[self runtimeExpr_];
} else if ([self predicts:STLOGEXPRESSIONPARSER_TOKEN_KIND_OPEN_BRACKET, 0]) {
[self objectExpr_];
}
Which effective says that in order to parse a runtime expr, it has to start with 'is'. Which means that [abc]
is being passed as a object expr instead.
So what i need help with is understanding how to express this logic in the grammar syntax:
If the string starts with a 'is', followed by a runtimeObject, or is only an runtimeObject, then process it as a runtimeExpr.
Otherwise process it as an objectExpr.
Creator of PEGKit here.
I believe the problem here is the leading optional is?
. Any rule that begins with an optional prefix like this, and then subsequently matches something similar or identical to another rule (runtimeObject
in this case) can cause problems.
But the solution is easy. Just reorder things a bit. PEGKit is deterministic which means it will try the OR alternatives in the order you specify in the grammar. So in this case just place the longer alternative rule (objectExpr
) first (before runtimeExpr
in the expr
rule).
Try this, I believe everything will work out:
expr = objectExpr | runtimeExpr;
objectExpr = runtimeObject keyPath;
runtimeExpr = is runtimeObject | runtimeObject;
runtimeObject = '[' string ']';
is = 'is';
keyPath = string;
Note the changes I made to both the expr
and runtimeExpr
rules. I suspect only the change to expr
is necessary to solve this problem, but the change to runtimeExpr
is harmless. Experimentation should tell you whether the runtimeExpr
change is actually necessary.