from .parser_helpers import *

# Code @generated by parsergen; do not edit!
from parsergen.parser_utils import GeneratedParser, TokenStream, Node, Filler
from parsergen.parser_utils import memoize, memoize_left_rec
from functools import reduce
class EcpParser(GeneratedParser):
    @memoize
    def program(self):
        pos = self.mark()
        """
        p=compound EOF { Module(body=p, type_ignores=[], **self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.compound()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('EOF')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            p = parts[0]
            return Module(body=p, type_ignores=[], **self.loc)
        self.goto(pos)
        
        return None
        
    @memoize
    def compound(self):
        pos = self.mark()
        """
        c=statement* { PyECP_Compound(c, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self._loop_0()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            c = parts[0]
            return PyECP_Compound(c, self.loc)
        self.goto(pos)
        
        return None
        
    def _loop_0(self):
        """
        statement*
        """
        children = []
        while True:
            pos = self.mark()
            part = self.statement()
            if self.match(part): children.append(part)
            else:
                self.goto(pos)
                break
        return children
    @memoize
    def statement(self):
        pos = self.mark()
        """
        e=if_statement | for_loop | while_loop | repeat_until_loop | record_definition | try_catch | suboroutine_definition | class_definition | import_statement | assignment_statement { e };
        """
        parts = []
        for _ in range(1):
            part = self._or_1()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[0]
            return e
        self.goto(pos)
        
        """
        e=expr { PyECP_ExprStatement(e) };
        """
        parts = []
        for _ in range(1):
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[0]
            return PyECP_ExprStatement(e)
        self.goto(pos)
        
        return None
        
    def _or_1(self):
        """
        if_statement | for_loop | while_loop | repeat_until_loop | record_definition | try_catch | suboroutine_definition | class_definition | import_statement | assignment_statement
        """
        pos = self.mark()
        part = self.if_statement()
        if self.match(part): return part
        self.goto(pos)
        part = self.for_loop()
        if self.match(part): return part
        self.goto(pos)
        part = self.while_loop()
        if self.match(part): return part
        self.goto(pos)
        part = self.repeat_until_loop()
        if self.match(part): return part
        self.goto(pos)
        part = self.record_definition()
        if self.match(part): return part
        self.goto(pos)
        part = self.try_catch()
        if self.match(part): return part
        self.goto(pos)
        part = self.suboroutine_definition()
        if self.match(part): return part
        self.goto(pos)
        part = self.class_definition()
        if self.match(part): return part
        self.goto(pos)
        part = self.import_statement()
        if self.match(part): return part
        self.goto(pos)
        part = self.assignment_statement()
        if self.match(part): return part
        self.goto(pos)
        self.fail()
        return None
    @memoize
    def assignment_statement(self):
        pos = self.mark()
        """
        target=variable (COLON ID)? ASSIGN value=expr { PyECP_Assign(target, value, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.variable()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_2()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ASSIGN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            target = parts[0]
            value = parts[3]
            return PyECP_Assign(target, value, self.loc)
        self.goto(pos)
        
        return None
        
    def _maybe_2(self):
        """
        (COLON ID)?
        """
        pos = self.mark()
        part = self._expr_list_3()
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    def _expr_list_3(self):
        """
        (COLON ID)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('COLON')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ID')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    @memoize
    def variable(self):
        pos = self.mark()
        """
        CONSTANT? name=ID indexing=indexing { PyECP_Variable(name, indexing, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self._maybe_4()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ID')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.indexing()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            name = parts[1]
            indexing = parts[2]
            return PyECP_Variable(name, indexing, self.loc)
        self.goto(pos)
        
        return None
        
    def _maybe_4(self):
        """
        CONSTANT?
        """
        pos = self.mark()
        part = self.expect('CONSTANT')
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    @memoize
    def parameters(self):
        pos = self.mark()
        """
        params=(expr !ASSIGN (COMMA expr !ASSIGN)* COMMA?)? { PyECP_Parameters(params) };
        """
        parts = []
        for _ in range(1):
            part = self._maybe_5()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            params = parts[0]
            return PyECP_Parameters(params)
        self.goto(pos)
        
        return None
        
    def _maybe_5(self):
        """
        (expr !ASSIGN (COMMA expr !ASSIGN)* COMMA?)?
        """
        pos = self.mark()
        part = self._expr_list_6()
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    def _expr_list_6(self):
        """
        (expr !ASSIGN (COMMA expr !ASSIGN)* COMMA?)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            predicate_pos = self.mark()
            part = self.expect('ASSIGN')
            self.goto(predicate_pos)
            if self.match(part):
                self.fail()
                break
            part = self._loop_7()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_8()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    def _loop_7(self):
        """
        (COMMA expr !ASSIGN)*
        """
        children = []
        while True:
            pos = self.mark()
            part = self._expr_list_9()
            if self.match(part): children.append(part)
            else:
                self.goto(pos)
                break
        return children
    def _expr_list_9(self):
        """
        (COMMA expr !ASSIGN)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('COMMA')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            predicate_pos = self.mark()
            part = self.expect('ASSIGN')
            self.goto(predicate_pos)
            if self.match(part):
                self.fail()
                break
            return parts
        self.goto(pos)
        return None
    def _maybe_8(self):
        """
        COMMA?
        """
        pos = self.mark()
        part = self.expect('COMMA')
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    @memoize
    def kw_parameters(self):
        pos = self.mark()
        """
        params=(ID ASSIGN expr (COMMA ID ASSIGN expr)* COMMA?)? { PyECP_KwParameters(params) };
        """
        parts = []
        for _ in range(1):
            part = self._maybe_10()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            params = parts[0]
            return PyECP_KwParameters(params)
        self.goto(pos)
        
        return None
        
    def _maybe_10(self):
        """
        (ID ASSIGN expr (COMMA ID ASSIGN expr)* COMMA?)?
        """
        pos = self.mark()
        part = self._expr_list_11()
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    def _expr_list_11(self):
        """
        (ID ASSIGN expr (COMMA ID ASSIGN expr)* COMMA?)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('ID')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ASSIGN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._loop_12()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_13()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    def _loop_12(self):
        """
        (COMMA ID ASSIGN expr)*
        """
        children = []
        while True:
            pos = self.mark()
            part = self._expr_list_14()
            if self.match(part): children.append(part)
            else:
                self.goto(pos)
                break
        return children
    def _expr_list_14(self):
        """
        (COMMA ID ASSIGN expr)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('COMMA')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ID')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ASSIGN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    def _maybe_13(self):
        """
        COMMA?
        """
        pos = self.mark()
        part = self.expect('COMMA')
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    @memoize
    def attr_index(self):
        pos = self.mark()
        """
        DOT i=ID { "attr", i.value };
        """
        parts = []
        for _ in range(1):
            part = self.expect('DOT')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ID')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            i = parts[1]
            return "attr", i.value
        self.goto(pos)
        
        return None
        
    @memoize
    def subscript_index(self):
        pos = self.mark()
        """
        LS_PAREN i=expr RS_PAREN { "subscript", i };
        """
        parts = []
        for _ in range(1):
            part = self.expect('LS_PAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('RS_PAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            i = parts[1]
            return "subscript", i
        self.goto(pos)
        
        return None
        
    @memoize
    def call(self):
        pos = self.mark()
        """
        LPAREN params=parameters kw_params=kw_parameters RPAREN { "call", (params, kw_params) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('LPAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.parameters()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.kw_parameters()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('RPAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            params = parts[1]
            kw_params = parts[2]
            return "call", (params, kw_params)
        self.goto(pos)
        
        return None
        
    @memoize
    def indexing(self):
        pos = self.mark()
        """
        indexes=(attr_index | subscript_index | call)* { [i for [i] in indexes] };
        """
        parts = []
        for _ in range(1):
            part = self._loop_15()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            indexes = parts[0]
            return [i for [i] in indexes]
        self.goto(pos)
        
        return None
        
    def _loop_15(self):
        """
        (attr_index | subscript_index | call)*
        """
        children = []
        while True:
            pos = self.mark()
            part = self._expr_list_16()
            if self.match(part): children.append(part)
            else:
                self.goto(pos)
                break
        return children
    def _expr_list_16(self):
        """
        (attr_index | subscript_index | call)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self._or_17()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    def _or_17(self):
        """
        attr_index | subscript_index | call
        """
        pos = self.mark()
        part = self.attr_index()
        if self.match(part): return part
        self.goto(pos)
        part = self.subscript_index()
        if self.match(part): return part
        self.goto(pos)
        part = self.call()
        if self.match(part): return part
        self.goto(pos)
        self.fail()
        return None
    @memoize_left_rec
    def factor(self):
        pos = self.mark()
        """
        f=factor_part i=indexing { PyECP_Factor(f, i, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.factor_part()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.indexing()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            f = parts[0]
            i = parts[1]
            return PyECP_Factor(f, i, self.loc)
        self.goto(pos)
        
        return None
        
    @memoize_left_rec
    def factor_part(self):
        pos = self.mark()
        """
        t=INT | FLOAT | BOOLEAN | STRING | NONE { PyECP_Constant(t, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self._or_18()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            t = parts[0]
            return PyECP_Constant(t, self.loc)
        self.goto(pos)
        
        """
        LPAREN e=expr RPAREN { e };
        """
        parts = []
        for _ in range(1):
            part = self.expect('LPAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('RPAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[1]
            return e
        self.goto(pos)
        
        """
        p=array | dictionary | tuple | magic_function | variable { p };
        """
        parts = []
        for _ in range(1):
            part = self._or_19()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            p = parts[0]
            return p
        self.goto(pos)
        
        """
        op=PLUS | SUB | NOT e=factor { PyECP_UnaryOp(op, e) };
        """
        parts = []
        for _ in range(1):
            part = self._or_20()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.factor()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            op = parts[0]
            e = parts[1]
            return PyECP_UnaryOp(op, e)
        self.goto(pos)
        
        return None
        
    def _or_18(self):
        """
        INT | FLOAT | BOOLEAN | STRING | NONE
        """
        pos = self.mark()
        part = self.expect('INT')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('FLOAT')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('BOOLEAN')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('STRING')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('NONE')
        if self.match(part): return part
        self.goto(pos)
        self.fail()
        return None
    def _or_19(self):
        """
        array | dictionary | tuple | magic_function | variable
        """
        pos = self.mark()
        part = self.array()
        if self.match(part): return part
        self.goto(pos)
        part = self.dictionary()
        if self.match(part): return part
        self.goto(pos)
        part = self.tuple()
        if self.match(part): return part
        self.goto(pos)
        part = self.magic_function()
        if self.match(part): return part
        self.goto(pos)
        part = self.variable()
        if self.match(part): return part
        self.goto(pos)
        self.fail()
        return None
    def _or_20(self):
        """
        PLUS | SUB | NOT
        """
        pos = self.mark()
        part = self.expect('PLUS')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('SUB')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('NOT')
        if self.match(part): return part
        self.goto(pos)
        self.fail()
        return None
    @memoize_left_rec
    def expr(self):
        pos = self.mark()
        """
        e=op_or { e };
        """
        parts = []
        for _ in range(1):
            part = self.op_or()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[0]
            return e
        self.goto(pos)
        
        return None
        
    @memoize_left_rec
    def op_or(self):
        pos = self.mark()
        """
        base=op_and others=(OR op_and)+ { PyECP_BoolOp(base, "OR", others, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.op_and()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._loop_21()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            base = parts[0]
            others = parts[1]
            return PyECP_BoolOp(base, "OR", others, self.loc)
        self.goto(pos)
        
        """
        e=op_and { e };
        """
        parts = []
        for _ in range(1):
            part = self.op_and()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[0]
            return e
        self.goto(pos)
        
        return None
        
    def _loop_21(self):
        """
        (OR op_and)+
        """
        children = []
        while True:
            pos = self.mark()
            part = self._expr_list_22()
            if self.match(part): children.append(part)
            else:
                if len(children) == 0:
                    self.fail()
                self.goto(pos)
                break
        return children if len(children) > 0 else None
    def _expr_list_22(self):
        """
        (OR op_and)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('OR')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.op_and()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    @memoize_left_rec
    def op_and(self):
        pos = self.mark()
        """
        base=inversion others=(AND inversion)+ { PyECP_BoolOp(base, "AND", others, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.inversion()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._loop_23()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            base = parts[0]
            others = parts[1]
            return PyECP_BoolOp(base, "AND", others, self.loc)
        self.goto(pos)
        
        """
        e=inversion { e };
        """
        parts = []
        for _ in range(1):
            part = self.inversion()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[0]
            return e
        self.goto(pos)
        
        return None
        
    def _loop_23(self):
        """
        (AND inversion)+
        """
        children = []
        while True:
            pos = self.mark()
            part = self._expr_list_24()
            if self.match(part): children.append(part)
            else:
                if len(children) == 0:
                    self.fail()
                self.goto(pos)
                break
        return children if len(children) > 0 else None
    def _expr_list_24(self):
        """
        (AND inversion)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('AND')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.inversion()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    @memoize_left_rec
    def inversion(self):
        pos = self.mark()
        """
        op=NOT e=inversion { PyECP_UnaryOp(op, e) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('NOT')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.inversion()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            op = parts[0]
            e = parts[1]
            return PyECP_UnaryOp(op, e)
        self.goto(pos)
        
        """
        e=comparison { e };
        """
        parts = []
        for _ in range(1):
            part = self.comparison()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[0]
            return e
        self.goto(pos)
        
        return None
        
    @memoize_left_rec
    def comparison(self):
        pos = self.mark()
        """
        base=sum others=(LT | GT | LE | GE | EQ | NE sum)+ { PyECP_Comparison(base, others, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.sum()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._loop_25()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            base = parts[0]
            others = parts[1]
            return PyECP_Comparison(base, others, self.loc)
        self.goto(pos)
        
        """
        e=sum { e };
        """
        parts = []
        for _ in range(1):
            part = self.sum()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[0]
            return e
        self.goto(pos)
        
        return None
        
    def _loop_25(self):
        """
        (LT | GT | LE | GE | EQ | NE sum)+
        """
        children = []
        while True:
            pos = self.mark()
            part = self._expr_list_26()
            if self.match(part): children.append(part)
            else:
                if len(children) == 0:
                    self.fail()
                self.goto(pos)
                break
        return children if len(children) > 0 else None
    def _expr_list_26(self):
        """
        (LT | GT | LE | GE | EQ | NE sum)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self._or_27()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.sum()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    def _or_27(self):
        """
        LT | GT | LE | GE | EQ | NE
        """
        pos = self.mark()
        part = self.expect('LT')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('GT')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('LE')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('GE')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('EQ')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('NE')
        if self.match(part): return part
        self.goto(pos)
        self.fail()
        return None
    @memoize_left_rec
    def sum(self):
        pos = self.mark()
        """
        left=sum op=ADD | SUB right=term { PyECP_BinOp(left, right, op, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.sum()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._or_28()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.term()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            left = parts[0]
            op = parts[1]
            right = parts[2]
            return PyECP_BinOp(left, right, op, self.loc)
        self.goto(pos)
        
        """
        e=term { e };
        """
        parts = []
        for _ in range(1):
            part = self.term()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[0]
            return e
        self.goto(pos)
        
        return None
        
    def _or_28(self):
        """
        ADD | SUB
        """
        pos = self.mark()
        part = self.expect('ADD')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('SUB')
        if self.match(part): return part
        self.goto(pos)
        self.fail()
        return None
    @memoize_left_rec
    def term(self):
        pos = self.mark()
        """
        left=term op=MUL | DIV | INT_DIV | MOD right=uop { PyECP_BinOp(left, right, op, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.term()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._or_29()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.uop()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            left = parts[0]
            op = parts[1]
            right = parts[2]
            return PyECP_BinOp(left, right, op, self.loc)
        self.goto(pos)
        
        """
        e=uop { e };
        """
        parts = []
        for _ in range(1):
            part = self.uop()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[0]
            return e
        self.goto(pos)
        
        return None
        
    def _or_29(self):
        """
        MUL | DIV | INT_DIV | MOD
        """
        pos = self.mark()
        part = self.expect('MUL')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('DIV')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('INT_DIV')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('MOD')
        if self.match(part): return part
        self.goto(pos)
        self.fail()
        return None
    @memoize_left_rec
    def uop(self):
        pos = self.mark()
        """
        op=ADD | SUB e=uop { PyECP_UnaryOp(op, e) };
        """
        parts = []
        for _ in range(1):
            part = self._or_30()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.uop()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            op = parts[0]
            e = parts[1]
            return PyECP_UnaryOp(op, e)
        self.goto(pos)
        
        """
        e=power { e };
        """
        parts = []
        for _ in range(1):
            part = self.power()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[0]
            return e
        self.goto(pos)
        
        return None
        
    def _or_30(self):
        """
        ADD | SUB
        """
        pos = self.mark()
        part = self.expect('ADD')
        if self.match(part): return part
        self.goto(pos)
        part = self.expect('SUB')
        if self.match(part): return part
        self.goto(pos)
        self.fail()
        return None
    @memoize_left_rec
    def power(self):
        pos = self.mark()
        """
        left=power op=POW right=factor { PyECP_BinOp(left, right, op, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.power()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('POW')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.factor()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            left = parts[0]
            op = parts[1]
            right = parts[2]
            return PyECP_BinOp(left, right, op, self.loc)
        self.goto(pos)
        
        """
        e=factor { e };
        """
        parts = []
        for _ in range(1):
            part = self.factor()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            e = parts[0]
            return e
        self.goto(pos)
        
        return None
        
    @memoize
    def magic_function(self):
        pos = self.mark()
        """
        name=MAGIC parameters=parameters { PyECP_Magic(name.value, parameters, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('MAGIC')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.parameters()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            name = parts[0]
            parameters = parts[1]
            return PyECP_Magic(name.value, parameters, self.loc)
        self.goto(pos)
        
        return None
        
    @memoize
    def param_definition(self):
        pos = self.mark()
        """
        name=ID (COLON ID)? { arg(arg=name.value, annotation=None, **self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('ID')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_31()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            name = parts[0]
            return arg(arg=name.value, annotation=None, **self.loc)
        self.goto(pos)
        
        return None
        
    def _maybe_31(self):
        """
        (COLON ID)?
        """
        pos = self.mark()
        part = self._expr_list_32()
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    def _expr_list_32(self):
        """
        (COLON ID)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('COLON')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ID')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    @memoize
    def suboroutine_definition(self):
        pos = self.mark()
        """
        SUBROUTINE name=ID LPAREN params=(param_definition (COMMA param_definition)* COMMA?)? RPAREN block=compound END { PyECP_SubroutineDef(name, params, block, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('SUBROUTINE')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ID')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('LPAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_33()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('RPAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.compound()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('END')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            name = parts[1]
            params = parts[3]
            block = parts[5]
            return PyECP_SubroutineDef(name, params, block, self.loc)
        self.goto(pos)
        
        return None
        
    def _maybe_33(self):
        """
        (param_definition (COMMA param_definition)* COMMA?)?
        """
        pos = self.mark()
        part = self._expr_list_34()
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    def _expr_list_34(self):
        """
        (param_definition (COMMA param_definition)* COMMA?)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.param_definition()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._loop_35()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_36()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    def _loop_35(self):
        """
        (COMMA param_definition)*
        """
        children = []
        while True:
            pos = self.mark()
            part = self._expr_list_37()
            if self.match(part): children.append(part)
            else:
                self.goto(pos)
                break
        return children
    def _expr_list_37(self):
        """
        (COMMA param_definition)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('COMMA')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.param_definition()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    def _maybe_36(self):
        """
        COMMA?
        """
        pos = self.mark()
        part = self.expect('COMMA')
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    @memoize
    def if_statement(self):
        pos = self.mark()
        """
        i=_if_statement END { i };
        """
        parts = []
        for _ in range(1):
            part = self._if_statement()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('END')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            i = parts[0]
            return i
        self.goto(pos)
        
        return None
        
    @memoize
    def _if_statement(self):
        pos = self.mark()
        """
        IF condition=expr THEN block=compound other=(elseif_statement | else_statement)? { PyECP_IfStatement(condition, block, other, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('IF')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('THEN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.compound()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_38()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            condition = parts[1]
            block = parts[3]
            other = parts[4]
            return PyECP_IfStatement(condition, block, other, self.loc)
        self.goto(pos)
        
        return None
        
    def _maybe_38(self):
        """
        (elseif_statement | else_statement)?
        """
        pos = self.mark()
        part = self._expr_list_39()
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    def _expr_list_39(self):
        """
        (elseif_statement | else_statement)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self._or_40()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    def _or_40(self):
        """
        elseif_statement | else_statement
        """
        pos = self.mark()
        part = self.elseif_statement()
        if self.match(part): return part
        self.goto(pos)
        part = self.else_statement()
        if self.match(part): return part
        self.goto(pos)
        self.fail()
        return None
    @memoize
    def elseif_statement(self):
        pos = self.mark()
        """
        ELSE otherwise=_if_statement { [otherwise] };
        """
        parts = []
        for _ in range(1):
            part = self.expect('ELSE')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._if_statement()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            otherwise = parts[1]
            return [otherwise]
        self.goto(pos)
        
        return None
        
    @memoize
    def else_statement(self):
        pos = self.mark()
        """
        ELSE block=compound { block };
        """
        parts = []
        for _ in range(1):
            part = self.expect('ELSE')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.compound()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            block = parts[1]
            return block
        self.goto(pos)
        
        return None
        
    @memoize
    def while_loop(self):
        pos = self.mark()
        """
        WHILE condition=expr block=compound END { PyECP_While(condition, block, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('WHILE')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.compound()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('END')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            condition = parts[1]
            block = parts[2]
            return PyECP_While(condition, block, self.loc)
        self.goto(pos)
        
        return None
        
    @memoize
    def repeat_until_loop(self):
        pos = self.mark()
        """
        REPEAT block=compound UNTIL condition=expr { PyECP_RepeatUntil(condition, block, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('REPEAT')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.compound()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('UNTIL')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            block = parts[1]
            condition = parts[3]
            return PyECP_RepeatUntil(condition, block, self.loc)
        self.goto(pos)
        
        return None
        
    @memoize
    def array(self):
        pos = self.mark()
        """
        LS_PAREN values=parameters RS_PAREN { PyECP_Array(values, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('LS_PAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.parameters()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('RS_PAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            values = parts[1]
            return PyECP_Array(values, self.loc)
        self.goto(pos)
        
        return None
        
    @memoize
    def tuple(self):
        pos = self.mark()
        """
        LPAREN values=parameters RPAREN { PyECP_Tuple(values, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('LPAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.parameters()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('RPAREN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            values = parts[1]
            return PyECP_Tuple(values, self.loc)
        self.goto(pos)
        
        return None
        
    @memoize
    def dictionary(self):
        pos = self.mark()
        """
        LC_BRACE kv_pairs=(expr COLON expr (COMMA expr COLON expr)* COMMA?)? RC_BRACE { PyECP_Dictionary(kv_pairs, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('LC_BRACE')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_41()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('RC_BRACE')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            kv_pairs = parts[1]
            return PyECP_Dictionary(kv_pairs, self.loc)
        self.goto(pos)
        
        return None
        
    def _maybe_41(self):
        """
        (expr COLON expr (COMMA expr COLON expr)* COMMA?)?
        """
        pos = self.mark()
        part = self._expr_list_42()
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    def _expr_list_42(self):
        """
        (expr COLON expr (COMMA expr COLON expr)* COMMA?)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('COLON')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._loop_43()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_44()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    def _loop_43(self):
        """
        (COMMA expr COLON expr)*
        """
        children = []
        while True:
            pos = self.mark()
            part = self._expr_list_45()
            if self.match(part): children.append(part)
            else:
                self.goto(pos)
                break
        return children
    def _expr_list_45(self):
        """
        (COMMA expr COLON expr)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('COMMA')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('COLON')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    def _maybe_44(self):
        """
        COMMA?
        """
        pos = self.mark()
        part = self.expect('COMMA')
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    @memoize
    def for_loop(self):
        pos = self.mark()
        """
        FOR v=variable ASSIGN start=expr TO end=expr step=(STEP expr)? block=compound END { PyECP_ForTo(v, start, end, step, block, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('FOR')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.variable()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ASSIGN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('TO')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_46()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.compound()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('END')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            v = parts[1]
            start = parts[3]
            end = parts[5]
            step = parts[6]
            block = parts[7]
            return PyECP_ForTo(v, start, end, step, block, self.loc)
        self.goto(pos)
        
        """
        FOR v=variable IN iterator=expr block=compound END { PyECP_ForIn(v, iterator, block, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('FOR')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.variable()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('IN')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.compound()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('END')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            v = parts[1]
            iterator = parts[3]
            block = parts[4]
            return PyECP_ForIn(v, iterator, block, self.loc)
        self.goto(pos)
        
        return None
        
    def _maybe_46(self):
        """
        (STEP expr)?
        """
        pos = self.mark()
        part = self._expr_list_47()
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    def _expr_list_47(self):
        """
        (STEP expr)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('STEP')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    @memoize
    def record_definition(self):
        pos = self.mark()
        """
        RECORD name=ID values=(variable (COLON ID)?)* END { PyECP_Record(name, values, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('RECORD')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ID')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._loop_48()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('END')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            name = parts[1]
            values = parts[2]
            return PyECP_Record(name, values, self.loc)
        self.goto(pos)
        
        return None
        
    def _loop_48(self):
        """
        (variable (COLON ID)?)*
        """
        children = []
        while True:
            pos = self.mark()
            part = self._expr_list_49()
            if self.match(part): children.append(part)
            else:
                self.goto(pos)
                break
        return children
    def _expr_list_49(self):
        """
        (variable (COLON ID)?)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.variable()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_50()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    def _maybe_50(self):
        """
        (COLON ID)?
        """
        pos = self.mark()
        part = self._expr_list_51()
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    def _expr_list_51(self):
        """
        (COLON ID)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('COLON')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('ID')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
    @memoize
    def try_catch(self):
        pos = self.mark()
        """
        TRY try_block=compound CATCH catch_block=compound END { PyECP_Try(try_block, catch_block, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('TRY')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.compound()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('CATCH')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.compound()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('END')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            try_block = parts[1]
            catch_block = parts[3]
            return PyECP_Try(try_block, catch_block, self.loc)
        self.goto(pos)
        
        return None
        
    @memoize
    def class_definition(self):
        pos = self.mark()
        """
        CLASS name=variable body=compound END { PyECP_Class(name, body, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('CLASS')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.variable()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.compound()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expect('END')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            name = parts[1]
            body = parts[2]
            return PyECP_Class(name, body, self.loc)
        self.goto(pos)
        
        return None
        
    @memoize
    def import_statement(self):
        pos = self.mark()
        """
        IMPORT location=expr target=(AS expr)? { PyECP_Import(location, target, self.loc) };
        """
        parts = []
        for _ in range(1):
            part = self.expect('IMPORT')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self._maybe_52()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            # match:
            location = parts[1]
            target = parts[2]
            return PyECP_Import(location, target, self.loc)
        self.goto(pos)
        
        return None
        
    def _maybe_52(self):
        """
        (AS expr)?
        """
        pos = self.mark()
        part = self._expr_list_53()
        if self.match(part): return part
        self.goto(pos)
        return Filler()
    def _expr_list_53(self):
        """
        (AS expr)
        """
        pos = self.mark()
        parts = []
        for _ in range(1):
            part = self.expect('AS')
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            part = self.expr()
            if not self.match(part):
                self.fail()
                break
            parts.append(part)
            return parts
        self.goto(pos)
        return None
