You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Merge pull request #255 from rocky/3.6-store_annotation
Add 3.6 STORE_ANNOTATION
This commit is contained in:
BIN
test/bytecode_3.6/05_ann_mopdule2.pyc
Normal file
BIN
test/bytecode_3.6/05_ann_mopdule2.pyc
Normal file
Binary file not shown.
37
test/simple_source/bug36/05_ann_mopdule2.py
Normal file
37
test/simple_source/bug36/05_ann_mopdule2.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# This is from Python 3.6's test directory.
|
||||||
|
"""
|
||||||
|
Some correct syntax for variable annotation here.
|
||||||
|
More examples are in test_grammar and test_parser.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import no_type_check, ClassVar
|
||||||
|
|
||||||
|
i: int = 1
|
||||||
|
j: int
|
||||||
|
x: float = i/10
|
||||||
|
|
||||||
|
def f():
|
||||||
|
class C: ...
|
||||||
|
return C()
|
||||||
|
|
||||||
|
f().new_attr: object = object()
|
||||||
|
|
||||||
|
class C:
|
||||||
|
def __init__(self, x: int) -> None:
|
||||||
|
self.x = x
|
||||||
|
|
||||||
|
c = C(5)
|
||||||
|
c.new_attr: int = 10
|
||||||
|
|
||||||
|
__annotations__ = {}
|
||||||
|
|
||||||
|
|
||||||
|
@no_type_check
|
||||||
|
class NTC:
|
||||||
|
def meth(self, param: complex) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
class CV:
|
||||||
|
var: ClassVar['CV']
|
||||||
|
|
||||||
|
CV.var = CV()
|
@@ -30,8 +30,7 @@ class Python36Parser(Python35Parser):
|
|||||||
|
|
||||||
|
|
||||||
def p_36misc(self, args):
|
def p_36misc(self, args):
|
||||||
"""
|
"""sstmt ::= sstmt RETURN_LAST
|
||||||
sstmt ::= sstmt RETURN_LAST
|
|
||||||
|
|
||||||
# 3.6 redoes how return_closure works. FIXME: Isolate to LOAD_CLOSURE
|
# 3.6 redoes how return_closure works. FIXME: Isolate to LOAD_CLOSURE
|
||||||
return_closure ::= LOAD_CLOSURE DUP_TOP STORE_NAME RETURN_VALUE RETURN_LAST
|
return_closure ::= LOAD_CLOSURE DUP_TOP STORE_NAME RETURN_VALUE RETURN_LAST
|
||||||
@@ -143,6 +142,7 @@ class Python36Parser(Python35Parser):
|
|||||||
COME_FROM_FINALLY
|
COME_FROM_FINALLY
|
||||||
|
|
||||||
compare_chained2 ::= expr COMPARE_OP come_froms JUMP_FORWARD
|
compare_chained2 ::= expr COMPARE_OP come_froms JUMP_FORWARD
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def customize_grammar_rules(self, tokens, customize):
|
def customize_grammar_rules(self, tokens, customize):
|
||||||
@@ -264,6 +264,23 @@ class Python36Parser(Python35Parser):
|
|||||||
self.addRule(rule, nop_func)
|
self.addRule(rule, nop_func)
|
||||||
rule = ('starred ::= %s %s' % ('expr ' * v, opname))
|
rule = ('starred ::= %s %s' % ('expr ' * v, opname))
|
||||||
self.addRule(rule, nop_func)
|
self.addRule(rule, nop_func)
|
||||||
|
elif opname == 'SETUP_ANNOTATIONS':
|
||||||
|
# 3.6 Variable Annotations PEP 526
|
||||||
|
# This seems to come before STORE_ANNOTATION, and doesn't
|
||||||
|
# correspond to direct Python source code.
|
||||||
|
rule = """
|
||||||
|
stmt ::= SETUP_ANNOTATIONS
|
||||||
|
stmt ::= ann_assign_init_value
|
||||||
|
stmt ::= ann_assign_no_init
|
||||||
|
|
||||||
|
ann_assign_init_value ::= expr store store_annotation
|
||||||
|
ann_assign_no_init ::= store_annotation
|
||||||
|
store_annotation ::= LOAD_NAME STORE_ANNOTATION
|
||||||
|
store_annotation ::= subscript STORE_ANNOTATION
|
||||||
|
"""
|
||||||
|
self.addRule(rule, nop_func)
|
||||||
|
# Check to combine assignment + annotation into one statement
|
||||||
|
self.check_reduce['assign'] = 'token'
|
||||||
elif opname == 'SETUP_WITH':
|
elif opname == 'SETUP_WITH':
|
||||||
rules_str = """
|
rules_str = """
|
||||||
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH
|
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH
|
||||||
@@ -289,6 +306,7 @@ class Python36Parser(Python35Parser):
|
|||||||
self.addRule(rules_str, nop_func)
|
self.addRule(rules_str, nop_func)
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
def custom_classfunc_rule(self, opname, token, customize, next_token):
|
def custom_classfunc_rule(self, opname, token, customize, next_token):
|
||||||
|
|
||||||
@@ -388,6 +406,15 @@ class Python36Parser(Python35Parser):
|
|||||||
tokens, first, last)
|
tokens, first, last)
|
||||||
if invalid:
|
if invalid:
|
||||||
return invalid
|
return invalid
|
||||||
|
if rule[0] == 'assign':
|
||||||
|
# Try to combine assignment + annotation into one statement
|
||||||
|
if (len(tokens) >= last + 1 and
|
||||||
|
tokens[last] == 'LOAD_NAME' and
|
||||||
|
tokens[last+1] == 'STORE_ANNOTATION' and
|
||||||
|
tokens[last-1].pattr == tokens[last+1].pattr):
|
||||||
|
# Will handle as ann_assign_init_value
|
||||||
|
return True
|
||||||
|
pass
|
||||||
if rule[0] == 'call_kw':
|
if rule[0] == 'call_kw':
|
||||||
# Make sure we don't derive call_kw
|
# Make sure we don't derive call_kw
|
||||||
nt = ast[0]
|
nt = ast[0]
|
||||||
|
@@ -60,6 +60,15 @@ def customize_for_version36(self, version):
|
|||||||
'call_ex' : (
|
'call_ex' : (
|
||||||
'%c(%p)',
|
'%c(%p)',
|
||||||
(0, 'expr'), (1, 100)),
|
(0, 'expr'), (1, 100)),
|
||||||
|
'store_annotation': (
|
||||||
|
'%[1]{pattr}: %c',
|
||||||
|
0
|
||||||
|
),
|
||||||
|
'ann_assign_init_value': (
|
||||||
|
'%|%c = %p\n',
|
||||||
|
(-1, 'store_annotation'), (0, 'expr', 200)),
|
||||||
|
'ann_assign_no_init': (
|
||||||
|
'%|%c\n', (0, 'store_annotation')),
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -2107,6 +2107,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
have_qualname = False
|
have_qualname = False
|
||||||
if self.version < 3.0:
|
if self.version < 3.0:
|
||||||
# Should we ditch this in favor of the "else" case?
|
# Should we ditch this in favor of the "else" case?
|
||||||
@@ -2338,11 +2339,21 @@ def code_deparse(co, out=sys.stdout, version=None, debug_opts=DEFAULT_DEBUG_OPTS
|
|||||||
|
|
||||||
# convert leading '__doc__ = "..." into doc string
|
# convert leading '__doc__ = "..." into doc string
|
||||||
try:
|
try:
|
||||||
if deparsed.ast[0][0] == ASSIGN_DOC_STRING(co.co_consts[0], load_op):
|
stmts = deparsed.ast
|
||||||
|
first_stmt = stmts[0][0]
|
||||||
|
if version >= 3.6:
|
||||||
|
if first_stmt[0] == 'SETUP_ANNOTATIONS':
|
||||||
|
del stmts[0]
|
||||||
|
assert stmts[0] == 'sstmt'
|
||||||
|
# Nuke sstmt
|
||||||
|
first_stmt = stmts[0][0]
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
if first_stmt == ASSIGN_DOC_STRING(co.co_consts[0], load_op):
|
||||||
print_docstring(deparsed, '', co.co_consts[0])
|
print_docstring(deparsed, '', co.co_consts[0])
|
||||||
del deparsed.ast[0]
|
del stmts[0]
|
||||||
if deparsed.ast[-1] == RETURN_NONE:
|
if stmts[-1] == RETURN_NONE:
|
||||||
deparsed.ast.pop() # remove last node
|
stmts.pop() # remove last node
|
||||||
# todo: if empty, add 'pass'
|
# todo: if empty, add 'pass'
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
Reference in New Issue
Block a user