A more uniform way to track opcodes seen...

use a set rather than these boolean variables. Done in 3.x
only for now. May do more later..
This commit is contained in:
rocky
2018-04-18 12:01:46 -04:00
parent ab5303f504
commit c481d97866
5 changed files with 69 additions and 80 deletions

View File

@@ -274,12 +274,12 @@ class Python2Parser(PythonParser):
'LOAD', 'LOOKUP', 'MAKE', 'SETUP', 'LOAD', 'LOOKUP', 'MAKE', 'SETUP',
'RAISE', 'UNPACK')) 'RAISE', 'UNPACK'))
# Opcode names in the custom_ops_seen set have rules that get added # Opcode names in the custom_seen_ops set have rules that get added
# unconditionally and the rules are constant. So they need to be done # 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 # only once and if we see the opcode a second we don't have to consider
# adding more rules. # adding more rules.
# #
custom_ops_seen = set() custom_seen_ops = set()
for i, token in enumerate(tokens): for i, token in enumerate(tokens):
opname = token.kind opname = token.kind
@@ -287,7 +287,7 @@ class Python2Parser(PythonParser):
# Do a quick breakout before testing potentially # Do a quick breakout before testing potentially
# each of the dozen or so instruction in if elif. # each of the dozen or so instruction in if elif.
if (opname[:opname.find('_')] not in customize_instruction_basenames if (opname[:opname.find('_')] not in customize_instruction_basenames
or opname in custom_ops_seen): or opname in custom_seen_ops):
continue continue
opname_base = opname[:opname.rfind('_')] opname_base = opname[:opname.rfind('_')]
@@ -355,32 +355,32 @@ class Python2Parser(PythonParser):
+ 'expr ' * nak + opname + 'expr ' * nak + opname
elif opname == 'CONTINUE_LOOP': elif opname == 'CONTINUE_LOOP':
self.addRule('continue ::= CONTINUE_LOOP', nop_func) self.addRule('continue ::= CONTINUE_LOOP', nop_func)
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
continue continue
elif opname == 'DELETE_ATTR': elif opname == 'DELETE_ATTR':
self.addRule('del_stmt ::= expr DELETE_ATTR', nop_func) self.addRule('del_stmt ::= expr DELETE_ATTR', nop_func)
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
continue continue
elif opname == 'DELETE_DEREF': elif opname == 'DELETE_DEREF':
self.addRule(""" self.addRule("""
stmt ::= del_deref_stmt stmt ::= del_deref_stmt
del_deref_stmt ::= DELETE_DEREF del_deref_stmt ::= DELETE_DEREF
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
continue continue
elif opname == 'DELETE_SUBSCR': elif opname == 'DELETE_SUBSCR':
self.addRule(""" self.addRule("""
del_stmt ::= delete_subscr del_stmt ::= delete_subscr
delete_subscr ::= expr expr DELETE_SUBSCR delete_subscr ::= expr expr DELETE_SUBSCR
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
continue continue
elif opname == 'GET_ITER': elif opname == 'GET_ITER':
self.addRule(""" self.addRule("""
expr ::= get_iter expr ::= get_iter
attribute ::= expr GET_ITER attribute ::= expr GET_ITER
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
continue continue
elif opname_base in ('DUP_TOPX', 'RAISE_VARARGS'): elif opname_base in ('DUP_TOPX', 'RAISE_VARARGS'):
# FIXME: remove these conditions if they are not needed. # FIXME: remove these conditions if they are not needed.
@@ -413,18 +413,18 @@ class Python2Parser(PythonParser):
expr ::= attribute expr ::= attribute
attribute ::= expr LOAD_ATTR attribute ::= expr LOAD_ATTR
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
continue continue
elif opname == 'LOAD_LISTCOMP': elif opname == 'LOAD_LISTCOMP':
self.addRule("expr ::= listcomp", nop_func) self.addRule("expr ::= listcomp", nop_func)
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
continue continue
elif opname == 'LOAD_SETCOMP': elif opname == 'LOAD_SETCOMP':
self.add_unique_rules([ self.add_unique_rules([
"expr ::= set_comp", "expr ::= set_comp",
"set_comp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1" "set_comp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1"
], customize) ], customize)
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
continue continue
elif opname == 'LOOKUP_METHOD': elif opname == 'LOOKUP_METHOD':
# A PyPy speciality - DRY with parse3 # A PyPy speciality - DRY with parse3
@@ -433,7 +433,7 @@ class Python2Parser(PythonParser):
attribute ::= expr LOOKUP_METHOD attribute ::= expr LOOKUP_METHOD
""", """,
nop_func) nop_func)
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
continue continue
elif opname_base == 'MAKE_FUNCTION': elif opname_base == 'MAKE_FUNCTION':
if i > 0 and tokens[i-1] == 'LOAD_LAMBDA': if i > 0 and tokens[i-1] == 'LOAD_LAMBDA':
@@ -482,7 +482,7 @@ class Python2Parser(PythonParser):
"try_except_pypy ::= SETUP_EXCEPT suite_stmts_opt except_handler_pypy", "try_except_pypy ::= SETUP_EXCEPT suite_stmts_opt except_handler_pypy",
"except_handler_pypy ::= COME_FROM except_stmts END_FINALLY COME_FROM" "except_handler_pypy ::= COME_FROM except_stmts END_FINALLY COME_FROM"
], customize) ], customize)
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
continue continue
elif opname == 'SETUP_FINALLY': elif opname == 'SETUP_FINALLY':
if 'PyPy' in customize: if 'PyPy' in customize:
@@ -491,13 +491,13 @@ class Python2Parser(PythonParser):
tryfinallystmt_pypy ::= SETUP_FINALLY suite_stmts_opt COME_FROM_FINALLY tryfinallystmt_pypy ::= SETUP_FINALLY suite_stmts_opt COME_FROM_FINALLY
suite_stmts_opt END_FINALLY""", nop_func) suite_stmts_opt END_FINALLY""", nop_func)
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
continue continue
elif opname_base in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'): elif opname_base in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
rule = 'unpack ::= ' + opname + ' store' * token.attr rule = 'unpack ::= ' + opname + ' store' * token.attr
elif opname_base == 'UNPACK_LIST': elif opname_base == 'UNPACK_LIST':
custom_ops_seen.add(opname) custom_seen_ops.add(opname)
rule = 'unpack_list ::= ' + opname + ' store' * token.attr rule = 'unpack_list ::= ' + opname + ' store' * token.attr
else: else:
continue continue

View File

@@ -476,9 +476,7 @@ class Python3Parser(PythonParser):
self.addRule(rule, nop_func) self.addRule(rule, nop_func)
return return
def custom_classfunc_rule(self, opname, token, customize, def custom_classfunc_rule(self, opname, token, customize, next_token):
possible_class_decorator,
seen_GET_AWAITABLE_YIELD_FROM, next_token):
""" """
call ::= expr {expr}^n CALL_FUNCTION_n call ::= expr {expr}^n CALL_FUNCTION_n
call ::= expr {expr}^n CALL_FUNCTION_VAR_n call ::= expr {expr}^n CALL_FUNCTION_VAR_n
@@ -508,7 +506,7 @@ class Python3Parser(PythonParser):
self.add_unique_rule(rule, token.kind, uniq_param, customize) self.add_unique_rule(rule, token.kind, uniq_param, customize)
if possible_class_decorator: if 'LOAD_BUILD_CLASS' in self.seen_ops:
if (next_token == 'CALL_FUNCTION' and next_token.attr == 1 if (next_token == 'CALL_FUNCTION' and next_token.attr == 1
and args_pos > 1): and args_pos > 1):
rule = ('classdefdeco2 ::= LOAD_BUILD_CLASS mkfunc %s%s_%d' rule = ('classdefdeco2 ::= LOAD_BUILD_CLASS mkfunc %s%s_%d'
@@ -556,9 +554,9 @@ class Python3Parser(PythonParser):
customize_instruction_basenames = frozenset( customize_instruction_basenames = frozenset(
('BUILD', 'CALL', 'CONTINUE', 'DELETE', 'GET', ('BUILD', 'CALL', 'CONTINUE', 'DELETE', 'GET',
'JUMP', 'LOAD', 'LOOKUP', 'MAKE', 'JUMP', 'LOAD', 'LOOKUP', 'MAKE',
'RAISE', 'UNPACK')) 'RETURN', 'RAISE', 'UNPACK'))
# Opcode names in the custom_ops_seen set have rules that get added # 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 # 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 # only once and if we see the opcode a second we don't have to consider
# adding more rules. # adding more rules.
@@ -566,18 +564,13 @@ class Python3Parser(PythonParser):
# Note: BUILD_TUPLE_UNPACK_WITH_CALL gets considered by # Note: BUILD_TUPLE_UNPACK_WITH_CALL gets considered by
# default because it starts with BUILD. So we'll set to ignore it from # default because it starts with BUILD. So we'll set to ignore it from
# the start. # the start.
custom_ops_seen = set(('BUILD_TUPLE_UNPACK_WITH_CALL',)) custom_ops_processed = set(('BUILD_TUPLE_UNPACK_WITH_CALL',))
# In constrast to custom_ops_seen, seen_xxx rules here are part of some
# other rule; so if we see them a second time we still have to loop
# over customization
seen_LOAD_BUILD_CLASS = False
seen_GET_AWAITABLE_YIELD_FROM = False
# This is used in parse36.py as well as here
self.seen_LOAD_DICTCOMP = False
self.seen_LOAD_SETCOMP = False
# A set of instruction operation names that exist in the token stream.
# We use this customize the grammar that we create.
self.seen_ops = {t.kind for t in tokens}
self.seen_op_basenames = {opname[:opname.rfind('_')] for opname in self.seen_ops}
from trepan.api import debug; debug()
# Loop over instructions adding custom grammar rules based on # Loop over instructions adding custom grammar rules based on
# a specific instruction seen. # a specific instruction seen.
@@ -595,8 +588,10 @@ class Python3Parser(PythonParser):
return_lambda LAMBDA_MARKER return_lambda LAMBDA_MARKER
""", nop_func) """, nop_func)
has_get_iter_call_function1 = False
n = len(tokens) n = len(tokens)
# Determine if we have an iteration CALL_FUNCTION_1.
has_get_iter_call_function1 = False
max_branches = 0 max_branches = 0
for i, token in enumerate(tokens): for i, token in enumerate(tokens):
if token == 'GET_ITER' and i < n-2 and self.call_fn_name(tokens[i+1]) == 'CALL_FUNCTION_1': if token == 'GET_ITER' and i < n-2 and self.call_fn_name(tokens[i+1]) == 'CALL_FUNCTION_1':
@@ -605,7 +600,6 @@ class Python3Parser(PythonParser):
elif (token == 'GET_AWAITABLE' and i < n-3 elif (token == 'GET_AWAITABLE' and i < n-3
and tokens[i+1] == 'LOAD_CONST' and tokens[i+2] == 'YIELD_FROM'): and tokens[i+1] == 'LOAD_CONST' and tokens[i+2] == 'YIELD_FROM'):
max_branches += 1 max_branches += 1
seen_GET_AWAITABLE_YIELD_FROM = True
if max_branches > 2: if max_branches > 2:
break break
@@ -615,7 +609,7 @@ class Python3Parser(PythonParser):
# Do a quick breakout before testing potentially # Do a quick breakout before testing potentially
# each of the dozen or so instruction in if elif. # each of the dozen or so instruction in if elif.
if (opname[:opname.find('_')] not in customize_instruction_basenames if (opname[:opname.find('_')] not in customize_instruction_basenames
or opname in custom_ops_seen): or opname in custom_ops_processed):
continue continue
opname_base = opname[:opname.rfind('_')] opname_base = opname[:opname.rfind('_')]
@@ -658,7 +652,7 @@ class Python3Parser(PythonParser):
# FIXME: really we need a combination of dict_entry-like things. # FIXME: really we need a combination of dict_entry-like things.
# It just so happens the most common case is not to mix # It just so happens the most common case is not to mix
# dictionary comphensions with dictionary, elements # dictionary comphensions with dictionary, elements
if self.seen_LOAD_DICTCOMP: if 'LOAD_DICTCOMP' in self.seen_ops:
rule = 'dict ::= %s%s' % ('dict_comp ' * token.attr, opname) rule = 'dict ::= %s%s' % ('dict_comp ' * token.attr, opname)
self.addRule(rule, nop_func) self.addRule(rule, nop_func)
rule = """ rule = """
@@ -737,9 +731,9 @@ class Python3Parser(PythonParser):
""" """
self.addRule(rule, nop_func) self.addRule(rule, nop_func)
self.custom_classfunc_rule(opname, token, customize, self.custom_classfunc_rule(opname, token, customize, tokens[i+1])
seen_LOAD_BUILD_CLASS, # Note: don't add to custom_ops_processed.
seen_GET_AWAITABLE_YIELD_FROM, tokens[i+1])
elif opname_base == 'CALL_METHOD': elif opname_base == 'CALL_METHOD':
# PyPy only - DRY with parse2 # PyPy only - DRY with parse2
@@ -754,31 +748,31 @@ class Python3Parser(PythonParser):
self.add_unique_rule(rule, opname, token.attr, customize) self.add_unique_rule(rule, opname, token.attr, customize)
elif opname == 'CONTINUE': elif opname == 'CONTINUE':
self.addRule('continue ::= CONTINUE', nop_func) self.addRule('continue ::= CONTINUE', nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'CONTINUE_LOOP': elif opname == 'CONTINUE_LOOP':
self.addRule('continue ::= CONTINUE_LOOP', nop_func) self.addRule('continue ::= CONTINUE_LOOP', nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'DELETE_ATTR': elif opname == 'DELETE_ATTR':
self.addRule('del_stmt ::= expr DELETE_ATTR', nop_func) self.addRule('del_stmt ::= expr DELETE_ATTR', nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'DELETE_DEREF': elif opname == 'DELETE_DEREF':
self.addRule(""" self.addRule("""
stmt ::= del_deref_stmt stmt ::= del_deref_stmt
del_deref_stmt ::= DELETE_DEREF del_deref_stmt ::= DELETE_DEREF
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'DELETE_SUBSCR': elif opname == 'DELETE_SUBSCR':
self.addRule(""" self.addRule("""
del_stmt ::= delete_subscr del_stmt ::= delete_subscr
delete_subscr ::= expr expr DELETE_SUBSCR delete_subscr ::= expr expr DELETE_SUBSCR
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'GET_ITER': elif opname == 'GET_ITER':
self.addRule(""" self.addRule("""
expr ::= get_iter expr ::= get_iter
attribute ::= expr GET_ITER attribute ::= expr GET_ITER
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'JUMP_IF_NOT_DEBUG': elif opname == 'JUMP_IF_NOT_DEBUG':
v = token.attr v = token.attr
self.addRule(""" self.addRule("""
@@ -793,40 +787,42 @@ class Python3Parser(PythonParser):
LOAD_ASSERT expr CALL_FUNCTION_1 LOAD_ASSERT expr CALL_FUNCTION_1
RAISE_VARARGS_1 COME_FROM, RAISE_VARARGS_1 COME_FROM,
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'LOAD_BUILD_CLASS': elif opname == 'LOAD_BUILD_CLASS':
seen_LOAD_BUILD_CLASS = True
self.custom_build_class_rule(opname, i, token, tokens, customize) self.custom_build_class_rule(opname, i, token, tokens, customize)
# Note: don't add to custom_ops_processed.
elif opname == 'LOAD_CLASSDEREF': elif opname == 'LOAD_CLASSDEREF':
# Python 3.4+ # Python 3.4+
self.addRule("expr ::= LOAD_CLASSDEREF", nop_func) self.addRule("expr ::= LOAD_CLASSDEREF", nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'LOAD_CLASSNAME': elif opname == 'LOAD_CLASSNAME':
self.addRule("expr ::= LOAD_CLASSNAME", nop_func) self.addRule("expr ::= LOAD_CLASSNAME", nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'LOAD_DICTCOMP': elif opname == 'LOAD_DICTCOMP':
self.seen_LOAD_DICTCOMP = True
if has_get_iter_call_function1: if has_get_iter_call_function1:
rule_pat = ("dict_comp ::= LOAD_DICTCOMP %sMAKE_FUNCTION_0 expr " rule_pat = ("dict_comp ::= LOAD_DICTCOMP %sMAKE_FUNCTION_0 expr "
"GET_ITER CALL_FUNCTION_1") "GET_ITER CALL_FUNCTION_1")
self.add_make_function_rule(rule_pat, opname, token.attr, customize) self.add_make_function_rule(rule_pat, opname, token.attr, customize)
# listcomp is a custom Python3 rule pass
custom_ops_processed.add(opname)
elif opname == 'LOAD_ATTR': elif opname == 'LOAD_ATTR':
self.addRule(""" self.addRule("""
expr ::= attribute expr ::= attribute
attribute ::= expr LOAD_ATTR attribute ::= expr LOAD_ATTR
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'LOAD_LISTCOMP': elif opname == 'LOAD_LISTCOMP':
self.add_unique_rule("expr ::= listcomp", opname, token.attr, customize) self.add_unique_rule("expr ::= listcomp", opname, token.attr, customize)
custom_ops_processed.add(opname)
elif opname == 'LOAD_SETCOMP': elif opname == 'LOAD_SETCOMP':
self.seen_LOAD_SETCOMP = True
# Should this be generalized and put under MAKE_FUNCTION? # Should this be generalized and put under MAKE_FUNCTION?
if has_get_iter_call_function1: if has_get_iter_call_function1:
self.addRule("expr ::= set_comp", nop_func) self.addRule("expr ::= set_comp", nop_func)
rule_pat = ("set_comp ::= LOAD_SETCOMP %sMAKE_FUNCTION_0 expr " rule_pat = ("set_comp ::= LOAD_SETCOMP %sMAKE_FUNCTION_0 expr "
"GET_ITER CALL_FUNCTION_1") "GET_ITER CALL_FUNCTION_1")
self.add_make_function_rule(rule_pat, opname, token.attr, customize) self.add_make_function_rule(rule_pat, opname, token.attr, customize)
pass
custom_ops_processed.add(opname)
elif opname == 'LOOKUP_METHOD': elif opname == 'LOOKUP_METHOD':
# A PyPy speciality - DRY with parse3 # A PyPy speciality - DRY with parse3
self.addRule(""" self.addRule("""
@@ -834,12 +830,12 @@ class Python3Parser(PythonParser):
attribute ::= expr LOOKUP_METHOD attribute ::= expr LOOKUP_METHOD
""", """,
nop_func) nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname.startswith('MAKE_CLOSURE'): elif opname.startswith('MAKE_CLOSURE'):
# DRY with MAKE_FUNCTION # DRY with MAKE_FUNCTION
# Note: this probably doesn't handle kwargs proprerly # Note: this probably doesn't handle kwargs proprerly
if opname == 'MAKE_CLOSURE_0' and self.seen_LOAD_DICTCOMP: if opname == 'MAKE_CLOSURE_0' and 'LOAD_DICTCOMP' in self.seen_ops:
# Is there something general going on here? # Is there something general going on here?
# Note that 3.6+ doesn't do this, but we'll remove # Note that 3.6+ doesn't do this, but we'll remove
# this rule in parse36.py # this rule in parse36.py
@@ -1073,25 +1069,25 @@ class Python3Parser(PythonParser):
self.addRule(""" self.addRule("""
return_lambda ::= ret_expr RETURN_VALUE_LAMBDA return_lambda ::= ret_expr RETURN_VALUE_LAMBDA
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'RAISE_VARARGS_0': elif opname == 'RAISE_VARARGS_0':
self.addRule(""" self.addRule("""
stmt ::= raise_stmt0 stmt ::= raise_stmt0
raise_stmt0 ::= RAISE_VARARGS_0 raise_stmt0 ::= RAISE_VARARGS_0
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'RAISE_VARARGS_1': elif opname == 'RAISE_VARARGS_1':
self.addRule(""" self.addRule("""
stmt ::= raise_stmt1 stmt ::= raise_stmt1
raise_stmt1 ::= expr RAISE_VARARGS_1 raise_stmt1 ::= expr RAISE_VARARGS_1
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname == 'RAISE_VARARGS_2': elif opname == 'RAISE_VARARGS_2':
self.addRule(""" self.addRule("""
stmt ::= raise_stmt2 stmt ::= raise_stmt2
raise_stmt2 ::= expr expr RAISE_VARARGS_2 raise_stmt2 ::= expr expr RAISE_VARARGS_2
""", nop_func) """, nop_func)
custom_ops_seen.add(opname) custom_ops_processed.add(opname)
elif opname_base in ('UNPACK_EX',): elif opname_base in ('UNPACK_EX',):
before_count, after_count = token.attr before_count, after_count = token.attr
rule = 'unpack ::= ' + opname + ' store' * (before_count + after_count + 1) rule = 'unpack ::= ' + opname + ' store' * (before_count + after_count + 1)
@@ -1102,6 +1098,10 @@ class Python3Parser(PythonParser):
elif opname_base == 'UNPACK_LIST': elif opname_base == 'UNPACK_LIST':
rule = 'unpack_list ::= ' + opname + ' store' * token.attr rule = 'unpack_list ::= ' + opname + ' store' * token.attr
self.addRule(rule, nop_func) self.addRule(rule, nop_func)
custom_ops_processed.add(opname)
pass
pass
self.check_reduce['aug_assign1'] = 'AST' self.check_reduce['aug_assign1'] = 'AST'
self.check_reduce['aug_assign2'] = 'AST' self.check_reduce['aug_assign2'] = 'AST'
self.check_reduce['while1stmt'] = 'noAST' self.check_reduce['while1stmt'] = 'noAST'

View File

@@ -200,10 +200,7 @@ class Python35Parser(Python34Parser):
pass pass
return return
def custom_classfunc_rule(self, opname, token, customize, def custom_classfunc_rule(self, opname, token, customize, *args):
seen_LOAD_BUILD_CLASS,
seen_GET_AWAITABLE_YIELD_FROM,
*args):
args_pos, args_kw = self.get_pos_kw(token) args_pos, args_kw = self.get_pos_kw(token)
# Additional exprs for * and ** args: # Additional exprs for * and ** args:
@@ -214,7 +211,7 @@ class Python35Parser(Python34Parser):
nak = ( len(opname)-len('CALL_FUNCTION') ) // 3 nak = ( len(opname)-len('CALL_FUNCTION') ) // 3
uniq_param = args_kw + args_pos uniq_param = args_kw + args_pos
if seen_GET_AWAITABLE_YIELD_FROM: if frozenset(('GET_AWAITABLE', 'YIELD_FROM')).issubset(self.seen_ops):
rule = ('async_call ::= expr ' + rule = ('async_call ::= expr ' +
('pos_arg ' * args_pos) + ('pos_arg ' * args_pos) +
('kwarg ' * args_kw) + ('kwarg ' * args_kw) +
@@ -243,10 +240,7 @@ class Python35Parser(Python34Parser):
# zero or not in creating a template rule. # zero or not in creating a template rule.
self.add_unique_rule(rule, token.kind, args_pos, customize) self.add_unique_rule(rule, token.kind, args_pos, customize)
else: else:
super(Python35Parser, self).custom_classfunc_rule(opname, token, customize, super(Python35Parser, self).custom_classfunc_rule(opname, token, customize, *args)
seen_LOAD_BUILD_CLASS,
seen_GET_AWAITABLE_YIELD_FROM,
*args)
class Python35ParserSingle(Python35Parser, PythonParserSingle): class Python35ParserSingle(Python35Parser, PythonParserSingle):
pass pass

View File

@@ -108,7 +108,7 @@ class Python36Parser(Python35Parser):
""" """
self.add_unique_doc_rules(rules_str, customize) self.add_unique_doc_rules(rules_str, customize)
elif opname == 'MAKE_FUNCTION_8': elif opname == 'MAKE_FUNCTION_8':
if self.seen_LOAD_DICTCOMP: if 'LOAD_DICTCOMP' in self.seen_ops:
# Is there something general going on here? # Is there something general going on here?
rule = """ rule = """
dict_comp ::= load_closure LOAD_DICTCOMP LOAD_CONST dict_comp ::= load_closure LOAD_DICTCOMP LOAD_CONST
@@ -116,7 +116,7 @@ class Python36Parser(Python35Parser):
GET_ITER CALL_FUNCTION_1 GET_ITER CALL_FUNCTION_1
""" """
self.addRule(rule, nop_func) self.addRule(rule, nop_func)
elif self.seen_LOAD_SETCOMP: elif 'LOAD_SETCOMP' in self.seen_ops:
rule = """ rule = """
set_comp ::= load_closure LOAD_SETCOMP LOAD_CONST set_comp ::= load_closure LOAD_SETCOMP LOAD_CONST
MAKE_FUNCTION_8 expr MAKE_FUNCTION_8 expr
@@ -192,9 +192,7 @@ class Python36Parser(Python35Parser):
""" """
self.addRule(rules_str, nop_func) self.addRule(rules_str, nop_func)
def custom_classfunc_rule(self, opname, token, customize, def custom_classfunc_rule(self, opname, token, customize, next_token):
possible_class_decorator,
seen_GET_AWAITABLE_YIELD_FROM, next_token):
args_pos, args_kw = self.get_pos_kw(token) args_pos, args_kw = self.get_pos_kw(token)
@@ -206,7 +204,7 @@ class Python36Parser(Python35Parser):
nak = ( len(opname)-len('CALL_FUNCTION') ) // 3 nak = ( len(opname)-len('CALL_FUNCTION') ) // 3
uniq_param = args_kw + args_pos uniq_param = args_kw + args_pos
if seen_GET_AWAITABLE_YIELD_FROM: if frozenset(('GET_AWAITABLE', 'YIELD_FROM')).issubset(self.seen_ops):
rule = ('async_call ::= expr ' + rule = ('async_call ::= expr ' +
('pos_arg ' * args_pos) + ('pos_arg ' * args_pos) +
('kwarg ' * args_kw) + ('kwarg ' * args_kw) +
@@ -261,11 +259,7 @@ class Python36Parser(Python35Parser):
""", nop_func) """, nop_func)
pass pass
else: else:
super(Python36Parser, self).custom_classfunc_rule(opname, token, super(Python36Parser, self).custom_classfunc_rule(opname, token, customize, next_token)
customize,
possible_class_decorator,
seen_GET_AWAITABLE_YIELD_FROM,
next_token)
def reduce_is_invalid(self, rule, ast, tokens, first, last): def reduce_is_invalid(self, rule, ast, tokens, first, last):
invalid = super(Python36Parser, invalid = super(Python36Parser,

View File

@@ -156,6 +156,7 @@ class Scanner3(Scanner):
self.varargs_ops = frozenset(varargs_ops) self.varargs_ops = frozenset(varargs_ops)
# FIXME: remove the above in favor of: # FIXME: remove the above in favor of:
# self.varargs_ops = frozenset(self.opc.hasvargs) # self.varargs_ops = frozenset(self.opc.hasvargs)
return
def ingest(self, co, classname=None, code_objects={}, show_asm=None): def ingest(self, co, classname=None, code_objects={}, show_asm=None):
""" """