Grammar action with more than one line of code

In the grammar rule, we will return a value that must be matched with the rule return type while we building our AST. However, everything goes OK with me when I have one statement inside the action block because it will be placed as a value for _res variable in the generated code which is clear for me.

Arbitrary code:

notify[expr_ty]:
    | 'notify' '->' a=expression {
        a->kind != Call_kind
         ? _PyAST_Constant(PyUnicode_FromString("!function"), NULL, EXTRA)
         : a->v.Call.func
 }

What about writing an action block with more than one line?

notify[expr_ty]:
    | 'notify' '->' a=expression {
        if(a->kind == Call_kind)
          return a->v.Call.func;
        return _PyAST_Constant(PyUnicode_FromString("!function"), NULL, EXTRA);
    }

Any hint?

I have found this in the documentation under Generating AST objects:

As a general rule, if an action spawns multiple lines or requires something more complicated than a single expression of C code, is normally better to create a custom helper in Parser/action_helpers.c and expose it in the Parser/pegen.h header file so that it can be used from the grammar.

Step 1: Create a custom helper in Parser/action_helpers.c

expr_ty _PyPegen_notify_expression(expr_ty expression, int lineno,
                                   int col_offset, int end_lineno,
                                   int end_col_offset, PyArena *arena){
    if(expression->kind == Call_kind){
        return expression->v.Call.func;
    }else{
        return _PyAST_Constant(
                     PyUnicode_FromString("!function"), NULL, lineno,
                     col_offset, end_lineno, end_col_offset, arena);
    }
}

Step 2: expose it in the Parser/pegen.h header file:

expr_ty _PyPegen_notify_expression(expr_ty expression, int lineno,
                                   int col_offset, int end_lineno,
                                   int end_col_offset, PyArena *arena);

Step 3: Use it from the grammar:

notify[expr_ty]:
    | 'notify' '->' a=expression { _PyPegen_notify_expression(a, EXTRA) }

It worked :+1:

1 Like