| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658 |
- # Copyright (c) 2017-2020, 2022-2024 Rocky Bernstein
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- """
- spark grammar differences over Python 3.7 for Python 3.8
- """
- from __future__ import print_function
- from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
- from uncompyle6.parser import PythonParserSingle, nop_func
- from uncompyle6.parsers.parse37 import Python37Parser
- from uncompyle6.parsers.reducecheck.pop_return import pop_return_check
- class Python38Parser(Python37Parser):
- def p_38_stmt(self, args):
- """
- stmt ::= async_for_stmt38
- stmt ::= async_forelse_stmt38
- stmt ::= call_stmt
- stmt ::= continue
- stmt ::= for38
- stmt ::= forelselaststmt38
- stmt ::= forelselaststmtl38
- stmt ::= forelsestmt38
- stmt ::= try_elsestmtl38
- stmt ::= try_except38
- stmt ::= try_except38r
- stmt ::= try_except38r2
- stmt ::= try_except38r3
- stmt ::= try_except38r4
- stmt ::= try_except_as
- stmt ::= try_except_ret38
- stmt ::= tryfinally38astmt
- stmt ::= tryfinally38rstmt
- stmt ::= tryfinally38rstmt2
- stmt ::= tryfinally38rstmt3
- stmt ::= tryfinally38stmt
- stmt ::= whileTruestmt38
- stmt ::= whilestmt38
- call_stmt ::= call
- break ::= POP_BLOCK BREAK_LOOP
- break ::= POP_BLOCK POP_TOP BREAK_LOOP
- break ::= POP_TOP BREAK_LOOP
- break ::= POP_EXCEPT BREAK_LOOP
- # The "continue" rule is a weird one. In 3.8, CONTINUE_LOOP was removed.
- # Inside an loop we can have this, which can only appear in side a try/except
- # And it can also appear at the end of the try except.
- continue ::= POP_EXCEPT JUMP_BACK
- # FIXME: this should be restricted to being inside a try block
- stmt ::= except_ret38
- stmt ::= except_ret38a
- # FIXME: this should be added only when seeing GET_AITER or YIELD_FROM
- async_for ::= GET_AITER _come_froms
- SETUP_FINALLY GET_ANEXT LOAD_CONST YIELD_FROM POP_BLOCK
- async_for_stmt38 ::= expr async_for
- store for_block
- COME_FROM_FINALLY
- END_ASYNC_FOR
- genexpr_func_async ::= LOAD_ARG func_async_prefix
- store comp_iter
- JUMP_BACK COME_FROM_FINALLY
- END_ASYNC_FOR
- # FIXME: "come_froms" after the "else_suite" or END_ASYNC_FOR distinguish which of
- # for / forelse is used. Add "come_froms" and check of add up control-flow detection phase.
- async_forelse_stmt38 ::= expr
- GET_AITER
- SETUP_FINALLY
- GET_ANEXT
- LOAD_CONST
- YIELD_FROM
- POP_BLOCK
- store for_block
- COME_FROM_FINALLY
- END_ASYNC_FOR
- else_suite
- # Seems to be used to discard values before a return in a "for" loop
- discard_top ::= ROT_TWO POP_TOP
- discard_tops ::= discard_top+
- return ::= return_expr
- discard_tops RETURN_VALUE
- return ::= popb_return
- return ::= pop_return
- return ::= pop_ex_return
- except_stmt ::= pop_ex_return
- pop_return ::= POP_TOP return_expr RETURN_VALUE
- popb_return ::= return_expr POP_BLOCK RETURN_VALUE
- pop_ex_return ::= return_expr ROT_FOUR POP_EXCEPT RETURN_VALUE
- # 3.8 can push a looping JUMP_BACK into into a JUMP_ from a statement that jumps to it
- lastl_stmt ::= ifpoplaststmtl
- ifpoplaststmtl ::= testexpr POP_TOP c_stmts_opt
- ifelsestmtl ::= testexpr c_stmts_opt jb_cfs else_suitel JUMP_BACK come_froms
- # Keep indices the same in ifelsestmtl
- cf_pt ::= COME_FROM POP_TOP
- ifelsestmtl ::= testexpr c_stmts cf_pt else_suite
- for38 ::= expr get_iter store for_block JUMP_BACK
- for38 ::= expr get_for_iter store for_block JUMP_BACK
- for38 ::= expr get_for_iter store for_block JUMP_BACK POP_BLOCK
- for38 ::= expr get_for_iter store for_block
- forelsestmt38 ::= expr get_for_iter store for_block POP_BLOCK else_suite
- forelsestmt38 ::= expr get_for_iter store for_block JUMP_BACK _come_froms
- else_suite
- forelselaststmt38 ::= expr get_for_iter store for_block POP_BLOCK else_suitec
- forelselaststmtl38 ::= expr get_for_iter store for_block POP_BLOCK else_suitel
- returns_in_except ::= _stmts except_return_value
- except_return_value ::= POP_BLOCK return
- except_return_value ::= expr POP_BLOCK RETURN_VALUE
- whilestmt38 ::= _come_froms testexpr l_stmts_opt COME_FROM JUMP_BACK
- POP_BLOCK
- whilestmt38 ::= _come_froms testexpr l_stmts_opt JUMP_BACK POP_BLOCK
- whilestmt38 ::= _come_froms testexpr l_stmts_opt JUMP_BACK come_froms
- whilestmt38 ::= _come_froms testexpr returns POP_BLOCK
- whilestmt38 ::= _come_froms testexpr l_stmts JUMP_BACK
- whilestmt38 ::= _come_froms testexpr l_stmts come_froms
- # while1elsestmt ::= l_stmts JUMP_BACK
- whileTruestmt ::= _come_froms l_stmts JUMP_BACK POP_BLOCK
- while1stmt ::= _come_froms l_stmts COME_FROM JUMP_BACK COME_FROM_LOOP
- whileTruestmt38 ::= _come_froms l_stmts JUMP_BACK
- whileTruestmt38 ::= _come_froms l_stmts JUMP_BACK COME_FROM_EXCEPT_CLAUSE
- whileTruestmt38 ::= _come_froms pass JUMP_BACK
- for_block ::= _come_froms l_stmts_opt _come_from_loops JUMP_BACK
- except_cond1 ::= DUP_TOP expr COMPARE_OP jmp_false
- POP_TOP POP_TOP POP_TOP
- POP_EXCEPT
- except_cond_as ::= DUP_TOP expr COMPARE_OP POP_JUMP_IF_FALSE
- POP_TOP STORE_FAST POP_TOP
- try_elsestmtl38 ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
- except_handler38 COME_FROM
- else_suitel opt_come_from_except
- try_except ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
- except_handler38
- try_except38 ::= SETUP_FINALLY POP_BLOCK POP_TOP suite_stmts_opt
- except_handler38a
- # suite_stmts has a return
- try_except38 ::= SETUP_FINALLY POP_BLOCK suite_stmts
- except_handler38b
- try_except38r ::= SETUP_FINALLY return_except
- except_handler38b
- return_except ::= stmts POP_BLOCK return
- # In 3.8 there seems to be some sort of code fiddle with POP_EXCEPT when there
- # is a final return in the "except" block.
- # So we treat the "return" separate from the other statements
- cond_except_stmt ::= except_cond1 except_stmts
- cond_except_stmts_opt ::= cond_except_stmt*
- try_except38r2 ::= SETUP_FINALLY
- suite_stmts_opt
- POP_BLOCK JUMP_FORWARD
- COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP
- cond_except_stmts_opt
- POP_EXCEPT return
- END_FINALLY
- COME_FROM
- try_except38r3 ::= SETUP_FINALLY
- suite_stmts_opt
- POP_BLOCK JUMP_FORWARD
- COME_FROM_FINALLY
- cond_except_stmts_opt
- POP_EXCEPT return
- COME_FROM
- END_FINALLY
- COME_FROM
- try_except38r4 ::= SETUP_FINALLY
- returns_in_except
- COME_FROM_FINALLY
- except_cond1
- return
- COME_FROM
- END_FINALLY
- # suite_stmts has a return
- try_except38 ::= SETUP_FINALLY POP_BLOCK suite_stmts
- except_handler38b
- try_except_as ::= SETUP_FINALLY POP_BLOCK suite_stmts
- except_handler_as END_FINALLY COME_FROM
- try_except_as ::= SETUP_FINALLY suite_stmts
- except_handler_as END_FINALLY COME_FROM
- try_except_ret38 ::= SETUP_FINALLY returns except_ret38a
- try_except_ret38a ::= SETUP_FINALLY returns except_handler38c
- END_FINALLY come_from_opt
- # Note: there is a suite_stmts_opt which seems
- # to be bookkeeping which is not expressed in source code
- except_ret38 ::= SETUP_FINALLY expr ROT_FOUR POP_BLOCK POP_EXCEPT
- CALL_FINALLY RETURN_VALUE COME_FROM
- COME_FROM_FINALLY
- suite_stmts_opt END_FINALLY
- except_ret38a ::= COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP
- expr ROT_FOUR
- POP_EXCEPT RETURN_VALUE END_FINALLY
- except_handler38 ::= _jump COME_FROM_FINALLY
- except_stmts END_FINALLY opt_come_from_except
- except_handler38a ::= COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP
- POP_EXCEPT POP_TOP stmts END_FINALLY
- except_handler38c ::= COME_FROM_FINALLY except_cond1a except_stmts
- POP_EXCEPT JUMP_FORWARD COME_FROM
- except_handler_as ::= COME_FROM_FINALLY except_cond_as tryfinallystmt
- POP_EXCEPT JUMP_FORWARD COME_FROM
- tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
- BEGIN_FINALLY COME_FROM_FINALLY suite_stmts_opt
- END_FINALLY
- lc_setup_finally ::= LOAD_CONST SETUP_FINALLY
- call_finally_pt ::= CALL_FINALLY POP_TOP
- cf_cf_finally ::= come_from_opt COME_FROM_FINALLY
- pop_finally_pt ::= POP_FINALLY POP_TOP
- ss_end_finally ::= suite_stmts END_FINALLY
- sf_pb_call_returns ::= SETUP_FINALLY POP_BLOCK CALL_FINALLY returns
- # FIXME: DRY rules below
- tryfinally38rstmt ::= sf_pb_call_returns
- cf_cf_finally
- ss_end_finally
- tryfinally38rstmt ::= sf_pb_call_returns
- cf_cf_finally END_FINALLY
- suite_stmts
- tryfinally38rstmt ::= sf_pb_call_returns
- cf_cf_finally POP_FINALLY
- ss_end_finally
- tryfinally38rstmt ::= sf_bp_call_returns
- COME_FROM_FINALLY POP_FINALLY
- ss_end_finally
- tryfinally38rstmt2 ::= lc_setup_finally POP_BLOCK call_finally_pt
- returns
- cf_cf_finally pop_finally_pt
- ss_end_finally POP_TOP
- tryfinally38rstmt3 ::= SETUP_FINALLY expr POP_BLOCK CALL_FINALLY RETURN_VALUE
- COME_FROM COME_FROM_FINALLY
- ss_end_finally
- tryfinally38stmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
- BEGIN_FINALLY COME_FROM_FINALLY
- POP_FINALLY suite_stmts_opt END_FINALLY
- tryfinally38astmt ::= LOAD_CONST SETUP_FINALLY suite_stmts_opt POP_BLOCK
- BEGIN_FINALLY COME_FROM_FINALLY
- POP_FINALLY POP_TOP suite_stmts_opt END_FINALLY POP_TOP
- """
- def p_38walrus(self, args):
- """
- # named_expr is also known as the "walrus op" :=
- expr ::= named_expr
- named_expr ::= expr DUP_TOP store
- """
- def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
- super(Python38Parser, self).__init__(debug_parser)
- self.customized = {}
- def remove_rules_38(self):
- self.remove_rules(
- """
- stmt ::= async_for_stmt37
- stmt ::= for
- stmt ::= forelsestmt
- stmt ::= try_except36
- stmt ::= async_forelse_stmt
- async_for_stmt ::= setup_loop expr
- GET_AITER
- SETUP_EXCEPT GET_ANEXT LOAD_CONST
- YIELD_FROM
- store
- POP_BLOCK JUMP_FORWARD COME_FROM_EXCEPT DUP_TOP
- LOAD_GLOBAL COMPARE_OP POP_JUMP_IF_TRUE
- END_FINALLY COME_FROM
- for_block
- COME_FROM
- POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP POP_BLOCK
- COME_FROM_LOOP
- async_for_stmt37 ::= setup_loop expr
- GET_AITER
- SETUP_EXCEPT GET_ANEXT
- LOAD_CONST YIELD_FROM
- store
- POP_BLOCK JUMP_BACK COME_FROM_EXCEPT DUP_TOP
- LOAD_GLOBAL COMPARE_OP POP_JUMP_IF_TRUE
- END_FINALLY for_block COME_FROM
- POP_TOP POP_TOP POP_TOP POP_EXCEPT
- POP_TOP POP_BLOCK
- COME_FROM_LOOP
- async_forelse_stmt ::= setup_loop expr
- GET_AITER
- SETUP_EXCEPT GET_ANEXT LOAD_CONST
- YIELD_FROM
- store
- POP_BLOCK JUMP_FORWARD COME_FROM_EXCEPT DUP_TOP
- LOAD_GLOBAL COMPARE_OP POP_JUMP_IF_TRUE
- END_FINALLY COME_FROM
- for_block
- COME_FROM
- POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP POP_BLOCK
- else_suite COME_FROM_LOOP
- for ::= setup_loop expr get_for_iter store for_block POP_BLOCK
- for ::= setup_loop expr get_for_iter store for_block POP_BLOCK NOP
- for_block ::= l_stmts_opt COME_FROM_LOOP JUMP_BACK
- forelsestmt ::= setup_loop expr get_for_iter store for_block POP_BLOCK else_suite
- forelselaststmt ::= setup_loop expr get_for_iter store for_block POP_BLOCK else_suitec
- forelselaststmtl ::= setup_loop expr get_for_iter store for_block POP_BLOCK else_suitel
- tryelsestmtl3 ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
- except_handler COME_FROM else_suitel
- opt_come_from_except
- try_except ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
- except_handler opt_come_from_except
- tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
- LOAD_CONST COME_FROM_FINALLY suite_stmts_opt
- END_FINALLY
- tryfinally36 ::= SETUP_FINALLY returns
- COME_FROM_FINALLY suite_stmts_opt END_FINALLY
- tryfinally_return_stmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
- LOAD_CONST COME_FROM_FINALLY
- """
- )
- def customize_reduce_checks_full38(self, tokens, customize):
- """
- Extra tests when a reduction is made in the full grammar.
- Reductions here are extended from those used in the lambda grammar
- """
- self.remove_rules_38()
- self.check_reduce["pop_return"] = "tokens"
- self.check_reduce["whileTruestmt38"] = "tokens"
- self.check_reduce["whilestmt38"] = "tokens"
- self.check_reduce["try_elsestmtl38"] = "AST"
- self.reduce_check_table["pop_return"] = pop_return_check
- def customize_grammar_rules(self, tokens, customize):
- super(Python37Parser, self).customize_grammar_rules(tokens, customize)
- self.customize_reduce_checks_full38(tokens, customize)
- # For a rough break out on the first word. This may
- # include instructions that don't need customization,
- # but we'll do a finer check after the rough breakout.
- customize_instruction_basenames = frozenset(
- (
- "BEFORE",
- "BUILD",
- "CALL",
- "DICT",
- "GET",
- "FORMAT",
- "LIST",
- "LOAD",
- "MAKE",
- "SETUP",
- "UNPACK",
- )
- )
- # Opcode names in the custom_ops_processed set have rules that get added
- # unconditionally and the rules are constant. So they need to be done
- # only once and if we see the opcode a second we don't have to consider
- # adding more rules.
- #
- custom_ops_processed = frozenset()
- # A set of instruction operation names that exist in the token stream.
- # We use this customize the grammar that we create.
- # 2.6-compatible set comprehensions
- self.seen_ops = frozenset([t.kind for t in tokens])
- self.seen_op_basenames = frozenset(
- [opname[: opname.rfind("_")] for opname in self.seen_ops]
- )
- custom_ops_processed = {"DICT_MERGE"}
- # Loop over instructions adding custom grammar rules based on
- # a specific instruction seen.
- if "PyPy" in customize:
- self.addRule(
- """
- stmt ::= assign3_pypy
- stmt ::= assign2_pypy
- assign3_pypy ::= expr expr expr store store store
- assign2_pypy ::= expr expr store store
- """,
- nop_func,
- )
- n = len(tokens)
- # Determine if we have an iteration CALL_FUNCTION_1.
- has_get_iter_call_function1 = False
- for i, token in enumerate(tokens):
- if token == "GET_ITER" and i < n - 2 and tokens[i + 1] == "CALL_FUNCTION_1":
- has_get_iter_call_function1 = True
- for i, token in enumerate(tokens):
- opname = token.kind
- # Do a quick breakout before testing potentially
- # each of the dozen or so instruction in if elif.
- if (
- opname[: opname.find("_")] not in customize_instruction_basenames
- or opname in custom_ops_processed
- ):
- continue
- opname_base = opname[: opname.rfind("_")]
- # Do a quick breakout before testing potentially
- # each of the dozen or so instruction in if elif.
- if (
- opname[: opname.find("_")] not in customize_instruction_basenames
- or opname in custom_ops_processed
- ):
- continue
- if opname_base in (
- "BUILD_LIST",
- "BUILD_SET",
- "BUILD_SET_UNPACK",
- "BUILD_TUPLE",
- "BUILD_TUPLE_UNPACK",
- ):
- v = token.attr
- is_LOAD_CLOSURE = False
- if opname_base == "BUILD_TUPLE":
- # If is part of a "load_closure", then it is not part of a
- # "list".
- is_LOAD_CLOSURE = True
- for j in range(v):
- if tokens[i - j - 1].kind != "LOAD_CLOSURE":
- is_LOAD_CLOSURE = False
- break
- if is_LOAD_CLOSURE:
- rule = "load_closure ::= %s%s" % (("LOAD_CLOSURE " * v), opname)
- self.add_unique_rule(rule, opname, token.attr, customize)
- elif opname_base == "BUILD_LIST":
- v = token.attr
- if v == 0:
- rule_str = """
- list ::= BUILD_LIST_0
- list_unpack ::= BUILD_LIST_0 expr LIST_EXTEND
- list ::= list_unpack
- """
- self.add_unique_doc_rules(rule_str, customize)
- elif opname == "BUILD_TUPLE_UNPACK_WITH_CALL":
- # FIXME: should this be parameterized by EX value?
- self.addRule(
- """expr ::= call_ex_kw3
- call_ex_kw3 ::= expr
- build_tuple_unpack_with_call
- expr
- CALL_FUNCTION_EX_KW
- """,
- nop_func,
- )
- if not is_LOAD_CLOSURE or v == 0:
- # We do this complicated test to speed up parsing of
- # pathelogically long literals, especially those over 1024.
- build_count = token.attr
- thousands = build_count // 1024
- thirty32s = (build_count // 32) % 32
- if thirty32s > 0:
- rule = "expr32 ::=%s" % (" expr" * 32)
- self.add_unique_rule(rule, opname_base, build_count, customize)
- pass
- if thousands > 0:
- self.add_unique_rule(
- "expr1024 ::=%s" % (" expr32" * 32),
- opname_base,
- build_count,
- customize,
- )
- pass
- collection = opname_base[opname_base.find("_") + 1 :].lower()
- rule = (
- ("%s ::= " % collection)
- + "expr1024 " * thousands
- + "expr32 " * thirty32s
- + "expr " * (build_count % 32)
- + opname
- )
- self.add_unique_rules(["expr ::= %s" % collection, rule], customize)
- continue
- continue
- elif opname == "BUILD_STRING_2":
- self.addRule(
- """
- expr ::= formatted_value_debug
- formatted_value_debug ::= LOAD_STR formatted_value2 BUILD_STRING_2
- formatted_value_debug ::= LOAD_STR formatted_value1 BUILD_STRING_2
- """,
- nop_func,
- )
- custom_ops_processed.add(opname)
- elif opname == "BUILD_STRING_3":
- self.addRule(
- """
- expr ::= formatted_value_debug
- formatted_value_debug ::= LOAD_STR formatted_value2 LOAD_STR BUILD_STRING_3
- formatted_value_debug ::= LOAD_STR formatted_value1 LOAD_STR BUILD_STRING_3
- """,
- nop_func,
- )
- custom_ops_processed.add(opname)
- elif opname == "LOAD_CLOSURE":
- self.addRule("""load_closure ::= LOAD_CLOSURE+""", nop_func)
- elif opname == "LOOKUP_METHOD":
- # A PyPy speciality - DRY with parse3
- self.addRule(
- """
- expr ::= attribute
- attribute ::= expr LOOKUP_METHOD
- """,
- nop_func,
- )
- custom_ops_processed.add(opname)
- elif opname == "MAKE_FUNCTION_8":
- if "LOAD_DICTCOMP" in self.seen_ops:
- # Is there something general going on here?
- rule = """
- dict_comp ::= load_closure LOAD_DICTCOMP LOAD_STR
- MAKE_FUNCTION_8 expr
- GET_ITER CALL_FUNCTION_1
- """
- self.addRule(rule, nop_func)
- elif "LOAD_SETCOMP" in self.seen_ops:
- rule = """
- set_comp ::= load_closure LOAD_SETCOMP LOAD_STR
- MAKE_FUNCTION_CLOSURE expr
- GET_ITER CALL_FUNCTION_1
- """
- self.addRule(rule, nop_func)
- elif opname == "SETUP_WITH":
- rules_str = """
- stmt ::= with_as_pass
- with_as_pass ::= expr
- SETUP_WITH store pass
- POP_BLOCK BEGIN_FINALLY COME_FROM_WITH
- with_suffix
- """
- self.addRule(rules_str, nop_func)
- def reduce_is_invalid(self, rule, ast, tokens, first, last):
- invalid = super(Python38Parser, self).reduce_is_invalid(
- rule, ast, tokens, first, last
- )
- self.remove_rules_38()
- if invalid:
- return invalid
- lhs = rule[0]
- if lhs in ("whileTruestmt38", "whilestmt38"):
- jb_index = last - 1
- while jb_index > 0 and tokens[jb_index].kind.startswith("COME_FROM"):
- jb_index -= 1
- t = tokens[jb_index]
- if t.kind != "JUMP_BACK":
- return True
- return t.attr != tokens[first].off2int()
- pass
- return False
- class Python38ParserSingle(Python38Parser, PythonParserSingle):
- pass
- if __name__ == "__main__":
- # Check grammar
- # FIXME: DRY this with other parseXX.py routines
- p = Python38Parser()
- p.remove_rules_38()
- p.check_grammar()
- from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE
- if PYTHON_VERSION_TRIPLE[:2] == (3, 8):
- lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets()
- from uncompyle6.scanner import get_scanner
- s = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY)
- opcode_set = set(s.opc.opname).union(
- set(
- """JUMP_BACK CONTINUE RETURN_END_IF COME_FROM
- LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP LOAD_CLASSNAME
- LAMBDA_MARKER RETURN_LAST
- """.split()
- )
- )
- remain_tokens = set(tokens) - opcode_set
- import re
- remain_tokens = set([re.sub(r"_\d+$", "", t) for t in remain_tokens])
- remain_tokens = set([re.sub("_CONT$", "", t) for t in remain_tokens])
- remain_tokens = set(remain_tokens) - opcode_set
- print(remain_tokens)
- import sys
- if len(sys.argv) > 1:
- from spark_parser.spark import rule2str
- for rule in sorted(p.rule2name.items()):
- print(rule2str(rule[0]))
|