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 ")" )  

wrong_tree.png


in Live Preview it works correct and builds good PSI tree

Live_preview.png

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;

  }

5 comments
Comment actions Permalink

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

0
Comment actions Permalink

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 ")"

0
Comment actions Permalink

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;
}
0
Comment actions Permalink

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 )

0
Comment actions Permalink

The pinned part is  "(type)" and not just "(".

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

0

Please sign in to leave a comment.