From 21fd506fbb61ff1e1a82eaa30c217e9fbf5d300f Mon Sep 17 00:00:00 2001 From: x0ret Date: Sun, 9 Jun 2019 00:49:50 +0430 Subject: [PATCH 1/8] Add 3.6 STORE_ANNOTATION --- uncompyle6/parsers/parse36.py | 5 +++++ uncompyle6/semantics/customize36.py | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index abb80cf4..fed0b346 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -143,6 +143,11 @@ class Python36Parser(Python35Parser): COME_FROM_FINALLY 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): diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index 97191f90..86f426a9 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -60,6 +60,13 @@ def customize_for_version36(self, version): 'call_ex' : ( '%c(%p)', (0, 'expr'), (1, 100)), + 'store_annotation': ( + '%|%[1]{pattr}: %c', + 0 + ), + 'annotated_assign': ( + '%|%c = %p\n', + (-1, 'store_annotation'), (0, 200)) }) From 76dcaf9bf070347801dc1221b9f849ffa94d0c25 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 10:38:10 -0400 Subject: [PATCH 2/8] 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 From 70b07049676b7caabbc195d7b42b4528953acf73 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 11:03:43 -0400 Subject: [PATCH 3/8] CI - remove 2.6 testing, add 3.7 testing --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7fce7351..98fd0ec6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,9 @@ language: python python: - '3.5' - '2.7' - - '2.6' - '3.4' - '3.6' + - '3.7' matrix: include: From 37e4754268de24c644a2dfe1ba1a19ba81cdd780 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 11:10:53 -0400 Subject: [PATCH 4/8] Fix Improper semantic action format --- uncompyle6/semantics/customize36.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index 383ed754..cecec452 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -68,8 +68,7 @@ def customize_for_version36(self, version): '%|%c = %p\n', (-1, 'store_annotation'), (0, 'expr', 200)), 'ann_assign_no_init': ( - '%|%c\n', - (0, 200)) + '%|%c\n', (0, 'store_annotation')), }) From 43348d7d247c5b507c952ec60d2a706bfee67fcd Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 11:13:33 -0400 Subject: [PATCH 5/8] CI testing take 3 This time, for sure! --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 98fd0ec6..015efe5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ python: - '2.7' - '3.4' - '3.6' - - '3.7' matrix: include: From c871a4ecc5a76b3fae245c57d139f1c45dc475b5 Mon Sep 17 00:00:00 2001 From: x0ret Date: Wed, 12 Jun 2019 00:26:34 +0430 Subject: [PATCH 6/8] Fix subscript in store_annotation + indentation --- uncompyle6/parsers/parse36.py | 1 + uncompyle6/semantics/customize36.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 02186375..edacf7e7 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -276,6 +276,7 @@ class Python36Parser(Python35Parser): 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 diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index cecec452..f1a04a01 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -61,7 +61,7 @@ def customize_for_version36(self, version): '%c(%p)', (0, 'expr'), (1, 100)), 'store_annotation': ( - '%|%[1]{pattr}: %c', + '%[1]{pattr}: %c', 0 ), 'ann_assign_init_value': ( From aea1adeb857a7d7e54bb598c1288a4b6bdbdb97b Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 16:04:29 -0400 Subject: [PATCH 7/8] Reinstate test --- test/bytecode_3.6/05_ann_mopdule2.pyc | Bin 1254 -> 1394 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/bytecode_3.6/05_ann_mopdule2.pyc b/test/bytecode_3.6/05_ann_mopdule2.pyc index 5e4604ee190ca91072c774eae89b83668017ef2c..4b33083236f456926bb523ac4998a36b1e663747 100644 GIT binary patch delta 233 zcmaFH`H4%}n3tDpDhETX5fcN$V+JI^0%SV?aq*Oi%C$1?3@JP*ye$kVyv8#44V8K*R?U%CnITP0Gb8SD+XkwGDI<^FhnthGNdx6Fi0}gv!pNrwK3gd zat`y;WG!L?swrXz5gZ_b8A#k>E=w#b;skLK1Q&=a4kVO-xEN#w7bBSOrzv!6vIR>T Z7noNh0hF1%oJE;YYVv6oDP~qaW&n5;B?tfj delta 108 zcmeyw^^8;5n3tE!X#4*dGbRRx#|%h-1;};);^MZ6%C&r{0?iDm0`Y<=Ji!c_yc_ql zF;CvhlEo6mM3BMT!B69)?)6CVo)BNr13vk(UWzP=K@ From 58c8fe5a6674ea70eb761789d9a6ddfe4f686354 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 16:09:04 -0400 Subject: [PATCH 8/8] Oops - forgot to add the test source --- test/simple_source/bug36/05_ann_mopdule2.py | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 test/simple_source/bug36/05_ann_mopdule2.py diff --git a/test/simple_source/bug36/05_ann_mopdule2.py b/test/simple_source/bug36/05_ann_mopdule2.py new file mode 100644 index 00000000..9b36a43e --- /dev/null +++ b/test/simple_source/bug36/05_ann_mopdule2.py @@ -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()