Add kwonly parsing.

* annotation parsing for kwonly args is missing.
* Start filling out runnable tests. More work is needed on tests.
* refresh incorrect bytecode_3.3_run/15_assert.pyc
This commit is contained in:
rocky
2019-06-08 15:22:50 -04:00
parent e9002038f8
commit 117b4ff4f1
6 changed files with 72 additions and 33 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,13 +1,43 @@
# Python 3 annotations
# Python 3 positional, kwonly, varargs, and annotations. Ick.
def foo(a, b: 'annotating b', c: int) -> float:
print(a + b + c)
# RUNNABLE!
def test1(args_1, c: int, w=4, *varargs: int, **kwargs: 'annotating kwargs') -> tuple:
return (args_1, c, w, kwargs)
def test2(args_1, args_2, c: int, w=4, *varargs: int, **kwargs: 'annotating kwargs'):
return (args_1, args_2, c, w, varargs, kwargs)
def test3(c: int, w=4, *varargs: int, **kwargs: 'annotating kwargs') -> float:
return 5.4
def test4(a: float, c: int, *varargs: int, **kwargs: 'annotating kwargs') -> float:
return 5.4
def test5(a: float, c: int = 5, *varargs: int, **kwargs: 'annotating kwargs') -> float:
return 5.4
def test6(a: float, c: int, test=None):
return (a, c, test)
def test7(*varargs: int, **kwargs):
return (varargs, kwargs)
def test8(x=55, *varargs: int, **kwargs) -> list:
return (x, varargs, kwargs)
#def test9(x=55, *varargs: int, y=5, **kwargs):
# return x, varargs, int, y, kwargs
def test10(args_1, b: 'annotating b', c: int) -> float:
return 5.4
class IOBase:
pass
# Python 3.1 _pyio.py uses the -> "IOBase" annotation
def open(file, mode = "r", buffering = None,
encoding = None, errors = None,
newline = None, closefd = True) -> "IOBase":
return text
def o(f, mode = "r", buffering = None) -> "IOBase":
return (f, mode, buffering)
def foo1(x: 'an argument that defaults to 5' = 5):
print(x)
@@ -18,29 +48,36 @@ def div(a: dict(type=float, help='the dividend'),
"""Divide a by b"""
return a / b
class TestSignatureObject():
def test_signature_on_wkwonly(self):
def test(*, a:float, b:str) -> int:
pass
# FIXME:
# class TestSignatureObject():
# def test_signature_on_wkwonly(self):
# def test(*, a:float, b:str) -> int:
# pass
class SupportsInt():
def __int__(self) -> int:
pass
def foo2(a, b: 'annotating b', c: int, *args: str) -> float:
assert foo2.__annotations__['b'] == 'annotating b'
assert foo2.__annotations__['c'] == int
assert foo2.__annotations__['args'] == str
assert foo2.__annotations__['return'] == float
def ann1(args_1, b: 'annotating b', c: int, *varargs: str) -> float:
assert ann1.__annotations__['b'] == 'annotating b'
assert ann1.__annotations__['c'] == int
assert ann1.__annotations__['varargs'] == str
assert ann1.__annotations__['return'] == float
def foo3(a, b: int = 5, **kwargs: float) -> float:
assert foo3.__annotations__['b'] == int
assert foo3.__annotations__['kwargs'] == float
assert foo3.__annotations__['return'] == float
def ann2(args_1, b: int = 5, **kwargs: float) -> float:
assert ann2.__annotations__['b'] == int
assert ann2.__annotations__['kwargs'] == float
assert ann2.__annotations__['return'] == float
assert b == 5
assert test1(1, 5) == (1, 5, 4, {})
assert test1(1, 5, 6, foo='bar') == (1, 5, 6, {'foo': 'bar'})
assert test2(2, 3, 4) == (2, 3, 4, 4, (), {})
### FIXME: fill in...
assert test6(1.2, 3) == (1.2, 3, None)
assert test6(2.3, 4, 5) == (2.3, 4, 5)
foo2(1, 'test', 5)
foo3(1)
ann1(1, 'test', 5)
ann2(1)

View File

@@ -26,6 +26,7 @@ If we succeed in creating a parse tree, then we have a Python program
that a later phase can turn into a sequence of ASCII text.
"""
import re
from uncompyle6.scanners.tok import Token
from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func
from uncompyle6.parsers.treenode import SyntaxTree
@@ -1050,7 +1051,7 @@ class Python3Parser(PythonParser):
(kwargs, 'pos_arg ' * args_pos, opname))
self.add_unique_rule(rule, opname, token.attr, customize)
if opname.startswith('MAKE_FUNCTION_A'):
if re.search('^MAKE_FUNCTION.*_A', opname):
if self.version >= 3.6:
rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST LOAD_CONST %s' %
(('pos_arg ' * (args_pos)),
@@ -1063,21 +1064,21 @@ class Python3Parser(PythonParser):
# Normally we remove EXTENDED_ARG from the opcodes, but in the case of
# annotated functions can use the EXTENDED_ARG tuple to signal we have an annotated function.
# Yes this is a little hacky
rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST LOAD_CONST EXTENDED_ARG %s' %
(('pos_arg ' * (args_pos)),
('call ' * (annotate_args-1)), opname))
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST LOAD_CONST EXTENDED_ARG %s' %
(('pos_arg ' * (args_pos), ('kwargs ' * args_kw),
('call ' * (annotate_args-1)), opname)))
self.add_unique_rule(rule, opname, token.attr, customize)
rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST LOAD_CONST EXTENDED_ARG %s' %
(('pos_arg ' * (args_pos)),
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST LOAD_CONST EXTENDED_ARG %s' %
(('pos_arg ' * (args_pos)), ('kwargs ' * args_kw),
('annotate_arg ' * (annotate_args-1)), opname))
else:
# See above comment about use of EXTENDED_ARG
rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST EXTENDED_ARG %s' %
(('pos_arg ' * (args_pos)),
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST EXTENDED_ARG %s' %
(('pos_arg ' * (args_pos)), ('kwargs ' * args_kw),
('annotate_arg ' * (annotate_args-1)), opname))
self.add_unique_rule(rule, opname, token.attr, customize)
rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST EXTENDED_ARG %s' %
(('pos_arg ' * (args_pos)),
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST EXTENDED_ARG %s' %
(('pos_arg ' * (args_pos)), ('kwargs ' * args_kw),
('call ' * (annotate_args-1)), opname))
self.addRule(rule, nop_func)
elif opname == 'RETURN_VALUE_LAMBDA':

View File

@@ -331,9 +331,10 @@ class Scanner3(Scanner):
attr = attr[:4] # remove last value: attr[5] == False
else:
pos_args, name_pair_args, annotate_args = parse_fn_counts(inst.argval)
pattr = ("%d positional, %d keyword pair, %d annotated" %
pattr = ("%d positional, %d keyword only, %d annotated" %
(pos_args, name_pair_args, annotate_args))
if name_pair_args > 0:
# FIXME: this should probably be K_
opname = '%s_N%d' % (opname, name_pair_args)
pass
if annotate_args > 0: