#  Copyright (c) 2018, 2022 Rocky Bernstein

from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6.parser import PythonParserSingle, nop_func
from uncompyle6.parsers.parse15 import Python15Parser

class Python14Parser(Python15Parser):

    def p_misc14(self, args):
        """
        # Not much here yet, but will probably need to add UNARY_CALL,
        # LOAD_LOCAL, SET_FUNC_ARGS

        args            ::= RESERVE_FAST UNPACK_ARG args_store
        args_store      ::= STORE_FAST*
        call            ::= expr tuple BINARY_CALL
        expr            ::= call
        kv              ::= DUP_TOP expr ROT_TWO LOAD_CONST STORE_SUBSCR
        mkfunc          ::= LOAD_CODE BUILD_FUNCTION
        print_expr_stmt ::= expr PRINT_EXPR
        raise_stmt2     ::= expr expr RAISE_EXCEPTION
        star_args       ::= RESERVE_FAST UNPACK_VARARG_1 args_store
        stmt            ::= args
        stmt            ::= print_expr_stmt
        stmt            ::= star_args
        stmt            ::= varargs
        varargs         ::= RESERVE_FAST UNPACK_VARARG_0 args_store

        # Not strictly needed, but tidies up output

        stmt     ::= doc_junk
        doc_junk ::= LOAD_CONST POP_TOP

        # Not sure why later Python's omit the COME_FROM
        jb_pop14  ::= JUMP_BACK COME_FROM POP_TOP

        whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt
                          jb_pop14
                          POP_BLOCK else_suitel COME_FROM

        print_items_nl_stmt ::= expr PRINT_ITEM_CONT print_items_opt PRINT_NEWLINE_CONT


        # 1.4 doesn't have linenotab, and although this shouldn't
        # be a show stopper, our CONTINUE detection is off here.
        continue ::= JUMP_BACK
        """

    def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
        super(Python14Parser, self).__init__(debug_parser)
        self.customized = {}

    def customize_grammar_rules(self, tokens, customize):
        super(Python14Parser, self).customize_grammar_rules(tokens, customize)
        self.remove_rules("""
        whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt
                          jb_pop
                          POP_BLOCK else_suitel COME_FROM
        """)
        self.check_reduce["doc_junk"] = "tokens"
        for i, token in enumerate(tokens):
            opname = token.kind
            opname_base = opname[:opname.rfind("_")]

            if opname_base == "UNPACK_VARARG":
                if token.attr > 1:
                    self.addRule(f"star_args ::= RESERVE_FAST {opname} args_store", nop_func)


    def reduce_is_invalid(self, rule, ast, tokens, first, last):
        invalid = super(Python14Parser,
                        self).reduce_is_invalid(rule, ast,
                                                tokens, first, last)
        if invalid or tokens is None:
            return invalid
        if rule[0] == 'doc_junk':
            return not isinstance(tokens[first].pattr, str)



class Python14ParserSingle(Python14Parser, PythonParserSingle):
    pass

if __name__ == '__main__':
    # Check grammar
    p = Python14Parser()
    p.check_grammar()
    p.dump_grammar()

# local variables:
# tab-width: 4
