Grammar-Kit : Implicit adding of pinned parts for PREFIX expressions
I described bnf with expressions:
expression ::= assignment_expression
| ternary_if_expression
...
...
| type_cast_expression
...
| primary_expression
| parenthesized_expression
type_cast_expression ::= "(" type ")" expression
parenthesized_expression ::= "(" expression ")"
The problem is : in runtime parenthesized_expression was parsed as incomplete type_cast_expression
( like when type_cast_expression ::= cast_type expression {pin=1} cast_type ::= "(" type ")" ) 
in Live Preview it works correct and builds good PSI tree
In priority table, type_cast_expression marks as PREFIX .
I think that generator for all PREFIX expressions add implicit pinned part which equals its prefix.
I wanted change it by adding my own 'mock' pinned part, e.g.
type_cast_expression ::= "(" type ")" expression {pin=4}
but generator ignores pinned part if it point to the last element in a sequense.
Probably I should write my type_cast expression so that it is marked as ATOM?
What right way to solve this?
More information :
method which parse type_cast_expression (with pinned)
public static boolean type_cast_expression(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "type_cast_expression")) return false;
if (!nextTokenIsFast(b, LPAREN)) return false;
boolean r, p;
Marker m = enter_section_(b, l, _NONE_, null);
r = type_cast_expression_0(b, l + 1);
p = r;
r = p && expression(b, l, 19);
exit_section_(b, l, m, TYPE_CAST_EXPRESSION, r, p, null);
return r || p;
}
How this method should look like (for my goal)
//Remove pinned
public static boolean type_cast_expression(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "type_cast_expression")) return false;
if (!nextTokenIsFast(b, LPAREN)) return false;
boolean r;
Marker m = enter_section_(b, l, _NONE_, null);
r = type_cast_expression_0(b, l + 1);
r = r && expression(b, l, 19);
exit_section_(b, l, m, TYPE_CAST_EXPRESSION, r, false, null);
return r;
}
Method in my parser which parse ATOM and PREFIX expressions, and my priority table :
/* ********************************************************** */
// Expression root: expression
// Operator priority table:
// 0: ATOM(soql_expression)
// 1: BINARY(ternary_if_expression)
// 2: POSTFIX(array_access_expression)
// 3: N_ARY(logical_or_expression)
// 4: N_ARY(logical_and_expression)
// 5: BINARY(bit_or_expression)
// 6: BINARY(xor_expression)
// 7 : BINARY(bit_and_expression)
// 8: BINARY(exact_equality_expression)
// 9: BINARY(equality_expression)
// 10: POSTFIX(instanceof_expression)
// 11: BINARY(conditional_expression)
// 12: BINARY(shift_expression)
// 13: BINARY(additive_expression)
// 14: BINARY(multiplicative_expression)
// 15: PREFIX(unary_not_expression)
// 16: N_ARY(assignment_expression)
// 17: PREFIX(prefix_expression)
// 18: POSTFIX(postfix_expression)
// 19: PREFIX(type_cast_expression)
// 20: ATOM(new_instance_expression)
// 21: POSTFIX(call_method_expression)
// 22: BINARY(reference_expression)
// 23: ATOM(primary_expression)
// 24: ATOM(parenthesized_expression)
public static boolean expression(PsiBuilder b, int l, int g) {
if (!recursion_guard_(b, l, "expression")) return false;
addVariant(b, "<expression>");
boolean r, p;
Marker m = enter_section_(b, l, _NONE_, "<expression>");
r = soql_expression(b, l + 1);
if (!r) r = unary_not_expression(b, l + 1);
if (!r) r = prefix_expression(b, l + 1);
if (!r) r = type_cast_expression(b, l + 1);
if (!r) r = new_instance_expression(b, l + 1);
if (!r) r = primary_expression(b, l + 1);
if (!r) r = parenthesized_expression(b, l + 1);
p = r;
r = r && expression_0(b, l + 1, g);
exit_section_(b, l, m, null, r, p, null);
return r || p;
}
Please sign in to leave a comment.
I changed my type_cast_expression and made it more narrow :
Now it looks like : type_cast_expression ::= "(" type ")" (some_expr1 | some_expr2 | some_expr3 ... )
It is marked as ATOM now, so all works fine
Try enclosing cast in parenthesis like this;
type_cast_expression ::= ("(" type ")") expression
or even extract operator like this:
type_cast_expression ::= cast_op expression
private cast_op ::= "(" type ")"
I tried do this, but it was still marked as 'PREFIX' and I got implicit pinned part after regenerating parser code.
public static boolean type_cast_expression(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "type_cast_expression")) return false;
if (!nextTokenIsFast(b, LPAREN)) return false;
boolean r, p;
Marker m = enter_section_(b, l, _NONE_, null);
r = cast_op(b, l + 1);
p = r;
r = p && expression(b, l, 19);
exit_section_(b, l, m, TYPE_CAST_EXPRESSION, r, p, null);
return r || p;
}
When it's marked as 'ATOM' - all work fine. Marking it as ATOM is a mistake?
// "(" type ")" (call_method_expression | reference_expression | primary_expression)public static boolean type_cast_expression(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "type_cast_expression")) return false;
if (!nextTokenIsFast(b, LPAREN)) return false;
boolean r;
Marker m = enter_section_(b);
r = consumeTokenSmart(b, LPAREN);
r = r && type(b, l + 1);
r = r && consumeToken(b, RPAREN);
r = r && type_cast_expression_3(b, l + 1);
exit_section_(b, m, TYPE_CAST_EXPRESSION, r);
return r;
}
PREFIX in this case seems to be OK.
The pinned part is "(type)" and not just "(".
To enforce ATOM try enclosing the whole expr in parenthesis:
cast_expression ::= ( "(" type ")" expr )
or extract everything into a separate private rule:
cast_expression ::= case_expression_impl
private case_expression_impl ::= ( "(" type ")" expr )
Yes :) And when I type Integer intr = (var1) + (var2); //like in java
LivePreviewParser parse it as two parenthesized_expressions inside addition_expression
But GeneratedParser parse it as two type_cast_expressions inside addition_expression.
Why do LivePreviewParser and GeneratedParser build different psi trees for this case?
It will be great if you add sample for this case to https://github.com/JetBrains/Grammar-Kit/blob/master/testData/generator/ExprParser.bnf