From 76dcaf9bf070347801dc1221b9f849ffa94d0c25 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 10:38:10 -0400 Subject: [PATCH] Tweaks to x0ret's anotation type handling - match AST names a little better: AnnAssign -> ann_assign... - localize Annotation type grammar change only when we have it - Add reduce rule to combine assignment and annotate declaration - Add annotation-type test from Python 3.6 - Docuemnt what's up with annotation types --- test/bytecode_3.6/05_ann_mopdule2.pyc | Bin 0 -> 1254 bytes uncompyle6/parsers/parse36.py | 33 +++++++++++++++++++++----- uncompyle6/semantics/customize36.py | 7 ++++-- uncompyle6/semantics/pysource.py | 19 +++++++++++---- 4 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 test/bytecode_3.6/05_ann_mopdule2.pyc diff --git a/test/bytecode_3.6/05_ann_mopdule2.pyc b/test/bytecode_3.6/05_ann_mopdule2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e4604ee190ca91072c774eae89b83668017ef2c GIT binary patch literal 1254 zcmbVL&2AGh5VpO$$!7D@w19*Jh&>_YlA>1hR8^I7;6yHk9#%+}yLQ@z{R#F4(yFM3 zR6GSQz!UH;zH;g-aDf@8>5sT!X~y=9$DZ$-@piWxZTn^kff=?i>3@@8FbGk(Lq(HIIXl+ zX&sx>vKI4rQt9}!(3v>ORV>P~szseuWqhKv8b)s_tztD7#WYtY7O=_6xK^g-$66GH z&=4Y*hN;j->0xvQn8|?IZdvjAbgFoIqSB8x9Oc58L!qxI_^%>RDW1fE77t_uVjhA5 zB)}ISVGH(^oRb9s1m5^20FJnzeV9!Llp+ZQnwg|S@C4-=BG4`QBzT47QilJT8MPx_aB z;ya9idteMa)46SERnK&pVj4JbMsa-N%jfi*aOguIhmIjROanrFqwq3V<8;8;Np;gum8{{`GkD{PUu zesupL2On?K2>99RvXHs`c(7rcoXaZZJZZrH$jW1lwbEF7OEbOh<`1qcHkjmI)ZjtsSeDrgn{EV_yGU!?}AYVWUIq!PmY6@+LPM?k<199u~no2GwAF U7E+&fSm^gy&kt$Dd~YNC3lG5i#{d8T literal 0 HcmV?d00001 diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index fed0b346..02186375 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -30,8 +30,7 @@ class Python36Parser(Python35Parser): 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 return_closure ::= LOAD_CLOSURE DUP_TOP STORE_NAME RETURN_VALUE RETURN_LAST @@ -144,10 +143,6 @@ class Python36Parser(Python35Parser): compare_chained2 ::= expr COMPARE_OP come_froms JUMP_FORWARD - stmt ::= SETUP_ANNOTATIONS - stmt ::= annotated_assign - annotated_assign ::= expr store store_annotation - store_annotation ::= LOAD_NAME STORE_ANNOTATION """ def customize_grammar_rules(self, tokens, customize): @@ -269,6 +264,22 @@ class Python36Parser(Python35Parser): self.addRule(rule, nop_func) rule = ('starred ::= %s %s' % ('expr ' * v, opname)) 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 + """ + self.addRule(rule, nop_func) + # Check to combine assignment + annotation into one statement + self.check_reduce['assign'] = 'token' elif opname == 'SETUP_WITH': rules_str = """ withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH @@ -294,6 +305,7 @@ class Python36Parser(Python35Parser): self.addRule(rules_str, nop_func) pass pass + return def custom_classfunc_rule(self, opname, token, customize, next_token): @@ -393,6 +405,15 @@ class Python36Parser(Python35Parser): tokens, first, last) if 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': # Make sure we don't derive call_kw nt = ast[0] diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index 86f426a9..383ed754 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -64,9 +64,12 @@ def customize_for_version36(self, version): '%|%[1]{pattr}: %c', 0 ), - 'annotated_assign': ( + 'ann_assign_init_value': ( '%|%c = %p\n', - (-1, 'store_annotation'), (0, 200)) + (-1, 'store_annotation'), (0, 'expr', 200)), + 'ann_assign_no_init': ( + '%|%c\n', + (0, 200)) }) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 8ce6dee0..1cb6980d 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -2107,6 +2107,7 @@ class SourceWalker(GenericASTTraversal, object): except: pass + have_qualname = False if self.version < 3.0: # 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 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]) - del deparsed.ast[0] - if deparsed.ast[-1] == RETURN_NONE: - deparsed.ast.pop() # remove last node + del stmts[0] + if stmts[-1] == RETURN_NONE: + stmts.pop() # remove last node # todo: if empty, add 'pass' except: pass