You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Redo make_function for *, arg
main(*, file='foo') and things like that now work
This commit is contained in:
BIN
test/bytecode_3.4/03_py3_def.pyc
Normal file
BIN
test/bytecode_3.4/03_py3_def.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.4/15_static_method.pyc
Normal file
BIN
test/bytecode_3.4/15_static_method.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/03_py3_def.pyc
Normal file
BIN
test/bytecode_3.5/03_py3_def.pyc
Normal file
Binary file not shown.
16
test/simple_source/def/03_py3_def.py
Normal file
16
test/simple_source/def/03_py3_def.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Test of Python 3's *, or named parameters
|
||||||
|
# kwargs ::= \e_kwargs kwarg
|
||||||
|
# kwargs ::= kwargs kwarg
|
||||||
|
# mkfunc ::= pos_arg \e_kwargs LOAD_CONST LOAD_CONST MAKE_FUNCTION_N2_1
|
||||||
|
#
|
||||||
|
def x0(*, file='sample_file'):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def x1(a, *, file=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def x2(a=5, *, file='filex2'):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def x3(a=5, *, file='filex2', stuff=None):
|
||||||
|
pass
|
@@ -201,6 +201,8 @@ class Python3Parser(PythonParser):
|
|||||||
del_stmt ::= expr DELETE_ATTR
|
del_stmt ::= expr DELETE_ATTR
|
||||||
|
|
||||||
kwarg ::= LOAD_CONST expr
|
kwarg ::= LOAD_CONST expr
|
||||||
|
kwargs ::= kwargs kwarg
|
||||||
|
kwargs ::=
|
||||||
|
|
||||||
classdef ::= build_class designator
|
classdef ::= build_class designator
|
||||||
# Python3 introduced LOAD_BUILD_CLASS
|
# Python3 introduced LOAD_BUILD_CLASS
|
||||||
@@ -507,21 +509,17 @@ class Python3Parser(PythonParser):
|
|||||||
elif opname_base == 'UNPACK_LIST':
|
elif opname_base == 'UNPACK_LIST':
|
||||||
rule = 'unpack_list ::= ' + opname + ' designator' * token.attr
|
rule = 'unpack_list ::= ' + opname + ' designator' * token.attr
|
||||||
elif opname_base.startswith('MAKE_FUNCTION'):
|
elif opname_base.startswith('MAKE_FUNCTION'):
|
||||||
self.addRule('mklambda ::= %s LOAD_LAMBDA %s' %
|
args_pos, args_kw, annotate_args = token.attr
|
||||||
('expr ' * token.attr, opname), nop_func)
|
self.addRule('mklambda ::= %sLOAD_LAMBDA %s' %
|
||||||
rule = 'mkfunc ::= %sLOAD_CONST %s' % ('expr ' * token.attr, opname)
|
('pos_arg ' * args_pos, opname), nop_func)
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
if self.version > 3.2:
|
||||||
if opname.startswith('MAKE_FUNCTION_N'):
|
rule = ('mkfunc ::= %skwargs %s %s' %
|
||||||
args_pos = token.attr & 0xff
|
|
||||||
args_kw = (token.attr >> 8) & 0xff
|
|
||||||
rule = ('mkfunc ::= %s %s %s %s' %
|
|
||||||
('pos_arg ' * args_pos,
|
('pos_arg ' * args_pos,
|
||||||
'expr ' * args_kw,
|
'LOAD_CONST ' * 2,
|
||||||
'LOAD_CONST ' * 3,
|
|
||||||
opname))
|
opname))
|
||||||
else:
|
else:
|
||||||
rule = 'mkfunc ::= %sLOAD_CONST LOAD_CONST %s' % ('pos_arg ' * token.attr, opname)
|
rule = ('mkfunc ::= %sLOAD_CONST %s' %
|
||||||
pass
|
('pos_arg ' * args_pos, opname))
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
elif opname.startswith('MAKE_CLOSURE'):
|
elif opname.startswith('MAKE_CLOSURE'):
|
||||||
self.add_unique_rule('mklambda ::= %sload_closure LOAD_LAMBDA %s' %
|
self.add_unique_rule('mklambda ::= %sload_closure LOAD_LAMBDA %s' %
|
||||||
|
@@ -306,7 +306,8 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
|
|||||||
elif op in hasfree:
|
elif op in hasfree:
|
||||||
argval, argrepr = _get_name_info(arg, cells)
|
argval, argrepr = _get_name_info(arg, cells)
|
||||||
elif op in hasnargs:
|
elif op in hasnargs:
|
||||||
argrepr = "%d positional, %d keyword pair" % (code[i-2], code[i-1])
|
argrepr = ("%d positional, %d keyword pair, %d annotated" %
|
||||||
|
(code[i-2], code[i-1], code[i]))
|
||||||
yield Instruction(opname[op_num], op,
|
yield Instruction(opname[op_num], op,
|
||||||
arg, argval, argrepr,
|
arg, argval, argrepr,
|
||||||
offset, starts_line, is_jump_target)
|
offset, starts_line, is_jump_target)
|
||||||
|
@@ -167,7 +167,29 @@ class Scanner3(scan.Scanner):
|
|||||||
elif op in op3.hasfree:
|
elif op in op3.hasfree:
|
||||||
pattr = free[oparg]
|
pattr = free[oparg]
|
||||||
|
|
||||||
if op_name in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE',
|
if op_name == 'MAKE_FUNCTION':
|
||||||
|
argc = oparg
|
||||||
|
attr = ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
|
||||||
|
pos_args, name_pair_args, annotate_args = attr
|
||||||
|
if name_pair_args > 0:
|
||||||
|
op_name = 'MAKE_FUNCTION_N%d' % name_pair_args
|
||||||
|
pass
|
||||||
|
if annotate_args > 0:
|
||||||
|
op_name = '%s_A_%d' % [op_name, annotate_args]
|
||||||
|
pass
|
||||||
|
op_name = '%s_%d' % (op_name, pos_args)
|
||||||
|
pattr = ("%d positional, %d keyword pair, %d annotated" %
|
||||||
|
(pos_args, name_pair_args, annotate_args))
|
||||||
|
tokens.append(
|
||||||
|
Token(
|
||||||
|
type_ = op_name,
|
||||||
|
attr = (pos_args, name_pair_args, annotate_args),
|
||||||
|
pattr = pattr,
|
||||||
|
offset = offset,
|
||||||
|
linestart = linestart)
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
elif op_name in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE',
|
||||||
'UNPACK_SEQUENCE',
|
'UNPACK_SEQUENCE',
|
||||||
'MAKE_FUNCTION', 'CALL_FUNCTION', 'MAKE_CLOSURE',
|
'MAKE_FUNCTION', 'CALL_FUNCTION', 'MAKE_CLOSURE',
|
||||||
'CALL_FUNCTION_VAR', 'CALL_FUNCTION_KW',
|
'CALL_FUNCTION_VAR', 'CALL_FUNCTION_KW',
|
||||||
|
@@ -108,10 +108,32 @@ class Scanner34(scan3.Scanner3):
|
|||||||
else:
|
else:
|
||||||
pattr = const
|
pattr = const
|
||||||
pass
|
pass
|
||||||
|
elif opname == 'MAKE_FUNCTION':
|
||||||
|
argc = inst.argval
|
||||||
|
attr = ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
|
||||||
|
pos_args, name_pair_args, annotate_args = attr
|
||||||
|
if name_pair_args > 0:
|
||||||
|
opname = 'MAKE_FUNCTION_N%d' % name_pair_args
|
||||||
|
pass
|
||||||
|
if annotate_args > 0:
|
||||||
|
opname = '%s_A_%d' % [op_name, annotate_args]
|
||||||
|
pass
|
||||||
|
opname = '%s_%d' % (opname, pos_args)
|
||||||
|
pattr = ("%d positional, %d keyword pair, %d annotated" %
|
||||||
|
(pos_args, name_pair_args, annotate_args))
|
||||||
|
tokens.append(
|
||||||
|
Token(
|
||||||
|
type_ = opname,
|
||||||
|
attr = (pos_args, name_pair_args, annotate_args),
|
||||||
|
pattr = pattr,
|
||||||
|
offset = inst.offset,
|
||||||
|
linestart = inst.starts_line)
|
||||||
|
)
|
||||||
|
continue
|
||||||
elif opname in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE',
|
elif opname in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE',
|
||||||
'UNPACK_SEQUENCE',
|
'UNPACK_SEQUENCE',
|
||||||
'MAKE_FUNCTION', 'MAKE_CLOSURE',
|
'MAKE_CLOSURE',
|
||||||
'DUP_TOPX', 'RAISE_VARARGS'
|
'RAISE_VARARGS'
|
||||||
):
|
):
|
||||||
# if opname == 'BUILD_TUPLE' and \
|
# if opname == 'BUILD_TUPLE' and \
|
||||||
# self.code[self.prev[offset]] == LOAD_CLOSURE:
|
# self.code[self.prev[offset]] == LOAD_CLOSURE:
|
||||||
|
@@ -30,6 +30,8 @@ class Scanner35(scan3.Scanner3):
|
|||||||
# we do post-processing like we do here.
|
# we do post-processing like we do here.
|
||||||
def disassemble(self, co, classname=None,
|
def disassemble(self, co, classname=None,
|
||||||
code_objects={}):
|
code_objects={}):
|
||||||
|
|
||||||
|
# dis.disassemble(co) # DEBUG
|
||||||
# Container for tokens
|
# Container for tokens
|
||||||
tokens = []
|
tokens = []
|
||||||
customize = {}
|
customize = {}
|
||||||
@@ -104,28 +106,37 @@ class Scanner35(scan3.Scanner3):
|
|||||||
else:
|
else:
|
||||||
pattr = const
|
pattr = const
|
||||||
pass
|
pass
|
||||||
|
elif opname == 'MAKE_FUNCTION':
|
||||||
|
argc = inst.argval
|
||||||
|
attr = ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
|
||||||
|
pos_args, name_pair_args, annotate_args = attr
|
||||||
|
if name_pair_args > 0:
|
||||||
|
opname = 'MAKE_FUNCTION_N%d' % name_pair_args
|
||||||
|
pass
|
||||||
|
if annotate_args > 0:
|
||||||
|
opname = '%s_A_%d' % [op_name, annotate_args]
|
||||||
|
pass
|
||||||
|
opname = '%s_%d' % (opname, pos_args)
|
||||||
|
pattr = ("%d positional, %d keyword pair, %d annotated" %
|
||||||
|
(pos_args, name_pair_args, annotate_args))
|
||||||
|
tokens.append(
|
||||||
|
Token(
|
||||||
|
type_ = opname,
|
||||||
|
attr = (pos_args, name_pair_args, annotate_args),
|
||||||
|
pattr = pattr,
|
||||||
|
offset = inst.offset,
|
||||||
|
linestart = inst.starts_line)
|
||||||
|
)
|
||||||
|
continue
|
||||||
elif opname in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE',
|
elif opname in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE',
|
||||||
'BUILD_MAP',
|
'BUILD_MAP', 'UNPACK_SEQUENCE', 'MAKE_CLOSURE',
|
||||||
'UNPACK_SEQUENCE',
|
'RAISE_VARARGS'
|
||||||
'MAKE_FUNCTION', 'MAKE_CLOSURE',
|
|
||||||
'DUP_TOPX', 'RAISE_VARARGS'
|
|
||||||
):
|
):
|
||||||
pos_args = inst.argval
|
pos_args = inst.argval
|
||||||
if inst.opname == 'MAKE_FUNCTION':
|
if inst.opname != 'BUILD_SLICE':
|
||||||
argc = inst.argval
|
|
||||||
pos_args = (argc & 0xFF)
|
|
||||||
name_pair_args = (argc >> 8) & 0xFF
|
|
||||||
if name_pair_args > 0:
|
|
||||||
opname = 'MAKE_FUNCTION_N%d' % name_pair_args
|
|
||||||
pass
|
|
||||||
annotate_args = (argc >> 16) & 0x7FFF
|
|
||||||
if annotate_args > 0:
|
|
||||||
opname = '%s_A_%d' % [op_name, annotate_args]
|
|
||||||
pass
|
|
||||||
elif inst.opname != 'BUILD_SLICE':
|
|
||||||
customize[opname] = pos_args
|
customize[opname] = pos_args
|
||||||
|
pass
|
||||||
opname = '%s_%d' % (opname, pos_args)
|
opname = '%s_%d' % (opname, pos_args)
|
||||||
|
|
||||||
elif opname == 'JUMP_ABSOLUTE':
|
elif opname == 'JUMP_ABSOLUTE':
|
||||||
pattr = inst.argval
|
pattr = inst.argval
|
||||||
target = self.get_target(inst.offset)
|
target = self.get_target(inst.offset)
|
||||||
|
@@ -191,7 +191,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||||
self.print_()
|
self.println()
|
||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
|
|
||||||
def n_return_if_stmt(self, node):
|
def n_return_if_stmt(self, node):
|
||||||
@@ -208,7 +208,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self.preorder(node[0])
|
self.preorder(node[0])
|
||||||
if hasattr(node[-1], 'offset'):
|
if hasattr(node[-1], 'offset'):
|
||||||
self.set_pos_info(node[-1], start, len(self.f.getvalue()))
|
self.set_pos_info(node[-1], start, len(self.f.getvalue()))
|
||||||
self.print_()
|
self.println()
|
||||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
|
|
||||||
@@ -350,7 +350,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self.write(sep); sep = ", "
|
self.write(sep); sep = ", "
|
||||||
self.preorder(subnode)
|
self.preorder(subnode)
|
||||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||||
self.print_()
|
self.println()
|
||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
|
|
||||||
def n_ifelsestmtr(self, node):
|
def n_ifelsestmtr(self, node):
|
||||||
@@ -365,7 +365,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
start = len(self.f.getvalue()) + len(self.indent)
|
start = len(self.f.getvalue()) + len(self.indent)
|
||||||
self.write(self.indent, 'if ')
|
self.write(self.indent, 'if ')
|
||||||
self.preorder(node[0])
|
self.preorder(node[0])
|
||||||
self.print_(':')
|
self.println(':')
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
node[1].parent = node
|
node[1].parent = node
|
||||||
self.preorder(node[1])
|
self.preorder(node[1])
|
||||||
@@ -387,13 +387,13 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
else:
|
else:
|
||||||
prev_stmt_is_if_ret = False
|
prev_stmt_is_if_ret = False
|
||||||
if not past_else and not if_ret_at_end:
|
if not past_else and not if_ret_at_end:
|
||||||
self.print_(self.indent, 'else:')
|
self.println(self.indent, 'else:')
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
past_else = True
|
past_else = True
|
||||||
n.parent = node
|
n.parent = node
|
||||||
self.preorder(n)
|
self.preorder(n)
|
||||||
if not past_else or if_ret_at_end:
|
if not past_else or if_ret_at_end:
|
||||||
self.print_(self.indent, 'else:')
|
self.println(self.indent, 'else:')
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
node[2][1].parent = node
|
node[2][1].parent = node
|
||||||
self.preorder(node[2][1])
|
self.preorder(node[2][1])
|
||||||
@@ -414,7 +414,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self.write(self.indent, 'elif ')
|
self.write(self.indent, 'elif ')
|
||||||
node[0].parent = node
|
node[0].parent = node
|
||||||
self.preorder(node[0])
|
self.preorder(node[0])
|
||||||
self.print_(':')
|
self.println(':')
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
node[1].parent = node
|
node[1].parent = node
|
||||||
self.preorder(node[1])
|
self.preorder(node[1])
|
||||||
@@ -424,7 +424,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
n[0].type = 'elifstmt'
|
n[0].type = 'elifstmt'
|
||||||
n.parent = node
|
n.parent = node
|
||||||
self.preorder(n)
|
self.preorder(n)
|
||||||
self.print_(self.indent, 'else:')
|
self.println(self.indent, 'else:')
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
node[2][1].parent = node
|
node[2][1].parent = node
|
||||||
self.preorder(node[2][1])
|
self.preorder(node[2][1])
|
||||||
@@ -680,7 +680,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self.print_super_classes3(subclass_info)
|
self.print_super_classes3(subclass_info)
|
||||||
else:
|
else:
|
||||||
self.print_super_classes(build_list)
|
self.print_super_classes(build_list)
|
||||||
self.print_(':')
|
self.println(':')
|
||||||
|
|
||||||
# class body
|
# class body
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
@@ -704,7 +704,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self.name = name
|
self.name = name
|
||||||
# if code would be empty, append 'pass'
|
# if code would be empty, append 'pass'
|
||||||
if len(ast) == 0:
|
if len(ast) == 0:
|
||||||
self.print_(self.indent, 'pass')
|
self.println(self.indent, 'pass')
|
||||||
else:
|
else:
|
||||||
self.customize(customize)
|
self.customize(customize)
|
||||||
self.text = self.traverse(ast, isLambda=isLambda)
|
self.text = self.traverse(ast, isLambda=isLambda)
|
||||||
@@ -1238,19 +1238,23 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
- handle defaults
|
- handle defaults
|
||||||
- handle format tuple parameters
|
- handle format tuple parameters
|
||||||
"""
|
"""
|
||||||
# if formal parameter is a tuple, the paramater name
|
if self.version < 3.0:
|
||||||
# starts with a dot (eg. '.1', '.2')
|
# if formal parameter is a tuple, the paramater name
|
||||||
if name.startswith('.'):
|
# starts with a dot (eg. '.1', '.2')
|
||||||
# replace the name with the tuple-string
|
if name.startswith('.'):
|
||||||
name = self.get_tuple_parameter(ast, name)
|
# replace the name with the tuple-string
|
||||||
|
name = self.get_tuple_parameter(ast, name)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
if default:
|
if default:
|
||||||
if self.showast:
|
if self.showast:
|
||||||
|
print()
|
||||||
print('--', name)
|
print('--', name)
|
||||||
print(default)
|
print(default)
|
||||||
print('--')
|
print('--')
|
||||||
pass
|
pass
|
||||||
result = '%s = ' % name
|
result = '%s=' % name
|
||||||
old_last_finish = self.last_finish
|
old_last_finish = self.last_finish
|
||||||
self.last_finish = len(result)
|
self.last_finish = len(result)
|
||||||
value = self.traverse(default, indent='')
|
value = self.traverse(default, indent='')
|
||||||
@@ -1262,14 +1266,22 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
else:
|
else:
|
||||||
return name
|
return name
|
||||||
|
|
||||||
# node[-1] == MAKE_xxx_n
|
# node[-1] == MAKE_FUNCTION_n
|
||||||
|
|
||||||
|
args_node = node[-1]
|
||||||
|
if isinstance(args_node.attr, tuple):
|
||||||
|
defparams = node[:args_node.attr[0]]
|
||||||
|
pos_args, kw_args, annotate_args = args_node.attr
|
||||||
|
else:
|
||||||
|
defparams = node[:args_node.attr]
|
||||||
|
kw_args, annotate_args = (0, 0)
|
||||||
|
pos_args = args_node.attr
|
||||||
|
pass
|
||||||
|
|
||||||
defparams = node[:node[-1].attr]
|
|
||||||
code = node[code_index].attr
|
code = node[code_index].attr
|
||||||
|
|
||||||
assert type(code) == CodeType
|
assert iscode(code)
|
||||||
code = Code(code, self.scanner, self.currentclass)
|
code = Code(code, self.scanner, self.currentclass)
|
||||||
# assert isinstance(code, Code)
|
|
||||||
|
|
||||||
# add defaults values to parameter names
|
# add defaults values to parameter names
|
||||||
argc = code.co_argcount
|
argc = code.co_argcount
|
||||||
@@ -1284,7 +1296,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
isLambda = isLambda,
|
isLambda = isLambda,
|
||||||
noneInNames = ('None' in code.co_names))
|
noneInNames = ('None' in code.co_names))
|
||||||
except ParserError as p:
|
except ParserError as p:
|
||||||
self.write( str(p))
|
self.write(str(p))
|
||||||
self.ERROR = p
|
self.ERROR = p
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -1292,12 +1304,6 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
|
|
||||||
params = [build_param(ast, name, default) for
|
params = [build_param(ast, name, default) for
|
||||||
name, default in zip_longest(paramnames, defparams, fillvalue=None)]
|
name, default in zip_longest(paramnames, defparams, fillvalue=None)]
|
||||||
# params = [ build_param(ast, name, default) for
|
|
||||||
# name, default in zip(paramnames, defparams) ]
|
|
||||||
# params = []
|
|
||||||
# for i, name in enumerate(paramnames):
|
|
||||||
# default = defparams[i] if len(defparams) > i else None
|
|
||||||
# params.append( build_param(ast, name, default) )
|
|
||||||
|
|
||||||
params.reverse() # back to correct order
|
params.reverse() # back to correct order
|
||||||
|
|
||||||
@@ -1311,10 +1317,27 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
# dump parameter list (with default values)
|
# dump parameter list (with default values)
|
||||||
indent = self.indent
|
indent = self.indent
|
||||||
if isLambda:
|
if isLambda:
|
||||||
self.write("lambda ", ", ".join(params), ": ")
|
self.write("lambda ", ", ".join(params))
|
||||||
else:
|
else:
|
||||||
self.print_("(", ", ".join(params), "):")
|
self.write("(", ", ".join(params))
|
||||||
# self.print_(indent, '#flags:\t', int(code.co_flags))
|
# self.println(indent, '#flags:\t', int(code.co_flags))
|
||||||
|
|
||||||
|
if kw_args > 0:
|
||||||
|
if argc > 0:
|
||||||
|
self.write(", *, ")
|
||||||
|
else:
|
||||||
|
self.write("*, ")
|
||||||
|
for n in node:
|
||||||
|
if n == 'pos_arg':
|
||||||
|
continue
|
||||||
|
self.preorder(n)
|
||||||
|
break
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isLambda:
|
||||||
|
self.write(": ")
|
||||||
|
else:
|
||||||
|
self.println("):")
|
||||||
|
|
||||||
if len(code.co_consts)>0 and code.co_consts[0] is not None and not isLambda: # ugly
|
if len(code.co_consts)>0 and code.co_consts[0] is not None and not isLambda: # ugly
|
||||||
# docstring exists, dump it
|
# docstring exists, dump it
|
||||||
@@ -1325,7 +1348,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
|
|
||||||
all_globals = find_all_globals(ast, set())
|
all_globals = find_all_globals(ast, set())
|
||||||
for g in ((all_globals & self.mod_globs) | find_globals(ast, set())):
|
for g in ((all_globals & self.mod_globs) | find_globals(ast, set())):
|
||||||
self.print_(self.indent, 'global ', g)
|
self.println(self.indent, 'global ', g)
|
||||||
self.mod_globs -= all_globals
|
self.mod_globs -= all_globals
|
||||||
rn = ('None' in code.co_names) and not find_none(ast)
|
rn = ('None' in code.co_names) and not find_none(ast)
|
||||||
self.gen_source(ast, code.co_name, code._customize, isLambda=isLambda,
|
self.gen_source(ast, code.co_name, code._customize, isLambda=isLambda,
|
||||||
|
@@ -48,6 +48,9 @@ methods implement most of the below.
|
|||||||
%c evaluate children N[A] recursively*
|
%c evaluate children N[A] recursively*
|
||||||
%C evaluate children N[A[0]]..N[A[1]-1] recursively, separate by A[2]*
|
%C evaluate children N[A[0]]..N[A[1]-1] recursively, separate by A[2]*
|
||||||
%P same as %C but sets operator precedence
|
%P same as %C but sets operator precedence
|
||||||
|
%D same as %C but is for left-recursive lists like kwargs which
|
||||||
|
goes to epsilon at the beginning. Using %C an extra separator
|
||||||
|
with an epsilon appears at the beginning
|
||||||
%, print ',' if last %C only printed one item (for tuples--unused)
|
%, print ',' if last %C only printed one item (for tuples--unused)
|
||||||
%| tab to current indentation level
|
%| tab to current indentation level
|
||||||
%+ increase current indentation level
|
%+ increase current indentation level
|
||||||
@@ -261,6 +264,7 @@ TABLE_DIRECT = {
|
|||||||
'classdefdeco': ( '%c', 0),
|
'classdefdeco': ( '%c', 0),
|
||||||
'classdefdeco1': ( '\n\n%|@%c%c', 0, 1),
|
'classdefdeco1': ( '\n\n%|@%c%c', 0, 1),
|
||||||
'kwarg': ( '%[0]{pattr}=%c', 1),
|
'kwarg': ( '%[0]{pattr}=%c', 1),
|
||||||
|
'kwargs': ( '%D', (0, maxint, ', ') ),
|
||||||
'importlist2': ( '%C', (0, maxint, ', ') ),
|
'importlist2': ( '%C', (0, maxint, ', ') ),
|
||||||
|
|
||||||
'assert': ( '%|assert %c\n' , 0 ),
|
'assert': ( '%|assert %c\n' , 0 ),
|
||||||
@@ -597,7 +601,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
out = out[:-self.pending_newlines]
|
out = out[:-self.pending_newlines]
|
||||||
self.f.write(out)
|
self.f.write(out)
|
||||||
|
|
||||||
def print_(self, *data):
|
def println(self, *data):
|
||||||
if data and not(len(data) == 1 and data[0] ==''):
|
if data and not(len(data) == 1 and data[0] ==''):
|
||||||
self.write(*data)
|
self.write(*data)
|
||||||
self.pending_newlines = max(self.pending_newlines, 1)
|
self.pending_newlines = max(self.pending_newlines, 1)
|
||||||
@@ -654,14 +658,14 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
|
|
||||||
self.write(quote)
|
self.write(quote)
|
||||||
if len(trimmed) == 0:
|
if len(trimmed) == 0:
|
||||||
self.print_(quote)
|
self.println(quote)
|
||||||
elif len(trimmed) == 1:
|
elif len(trimmed) == 1:
|
||||||
self.print_(trimmed[0], quote)
|
self.println(trimmed[0], quote)
|
||||||
else:
|
else:
|
||||||
self.print_(trimmed[0])
|
self.println(trimmed[0])
|
||||||
for line in trimmed[1:-1]:
|
for line in trimmed[1:-1]:
|
||||||
self.print_( indent, line )
|
self.println( indent, line )
|
||||||
self.print_(indent, trimmed[-1], quote)
|
self.println(indent, trimmed[-1], quote)
|
||||||
|
|
||||||
def n_return_stmt(self, node):
|
def n_return_stmt(self, node):
|
||||||
if self.params['isLambda']:
|
if self.params['isLambda']:
|
||||||
@@ -672,7 +676,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
if self.return_none or node != AST('return_stmt', [AST('ret_expr', [NONE]), Token('RETURN_VALUE')]):
|
if self.return_none or node != AST('return_stmt', [AST('ret_expr', [NONE]), Token('RETURN_VALUE')]):
|
||||||
self.write(' ')
|
self.write(' ')
|
||||||
self.preorder(node[0])
|
self.preorder(node[0])
|
||||||
self.print_()
|
self.println()
|
||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
|
|
||||||
def n_return_if_stmt(self, node):
|
def n_return_if_stmt(self, node):
|
||||||
@@ -684,7 +688,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
if self.return_none or node != AST('return_stmt', [AST('ret_expr', [NONE]), Token('RETURN_END_IF')]):
|
if self.return_none or node != AST('return_stmt', [AST('ret_expr', [NONE]), Token('RETURN_END_IF')]):
|
||||||
self.write(' ')
|
self.write(' ')
|
||||||
self.preorder(node[0])
|
self.preorder(node[0])
|
||||||
self.print_()
|
self.println()
|
||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
|
|
||||||
def n_yield(self, node):
|
def n_yield(self, node):
|
||||||
@@ -817,7 +821,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
for subnode in node[1]:
|
for subnode in node[1]:
|
||||||
self.write(sep); sep = ", "
|
self.write(sep); sep = ", "
|
||||||
self.preorder(subnode)
|
self.preorder(subnode)
|
||||||
self.print_()
|
self.println()
|
||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
|
|
||||||
def n_ifelsestmt(self, node, preprocess=0):
|
def n_ifelsestmt(self, node, preprocess=0):
|
||||||
@@ -860,7 +864,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
|
|
||||||
self.write(self.indent, 'if ')
|
self.write(self.indent, 'if ')
|
||||||
self.preorder(node[0])
|
self.preorder(node[0])
|
||||||
self.print_(':')
|
self.println(':')
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
self.preorder(node[1])
|
self.preorder(node[1])
|
||||||
self.indentLess()
|
self.indentLess()
|
||||||
@@ -880,12 +884,12 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
else:
|
else:
|
||||||
prev_stmt_is_if_ret = False
|
prev_stmt_is_if_ret = False
|
||||||
if not past_else and not if_ret_at_end:
|
if not past_else and not if_ret_at_end:
|
||||||
self.print_(self.indent, 'else:')
|
self.println(self.indent, 'else:')
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
past_else = True
|
past_else = True
|
||||||
self.preorder(n)
|
self.preorder(n)
|
||||||
if not past_else or if_ret_at_end:
|
if not past_else or if_ret_at_end:
|
||||||
self.print_(self.indent, 'else:')
|
self.println(self.indent, 'else:')
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
self.preorder(node[2][1])
|
self.preorder(node[2][1])
|
||||||
self.indentLess()
|
self.indentLess()
|
||||||
@@ -902,7 +906,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
|
|
||||||
self.write(self.indent, 'elif ')
|
self.write(self.indent, 'elif ')
|
||||||
self.preorder(node[0])
|
self.preorder(node[0])
|
||||||
self.print_(':')
|
self.println(':')
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
self.preorder(node[1])
|
self.preorder(node[1])
|
||||||
self.indentLess()
|
self.indentLess()
|
||||||
@@ -910,7 +914,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
for n in node[2][0]:
|
for n in node[2][0]:
|
||||||
n[0].type = 'elifstmt'
|
n[0].type = 'elifstmt'
|
||||||
self.preorder(n)
|
self.preorder(n)
|
||||||
self.print_(self.indent, 'else:')
|
self.println(self.indent, 'else:')
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
self.preorder(node[2][1])
|
self.preorder(node[2][1])
|
||||||
self.indentLess()
|
self.indentLess()
|
||||||
@@ -952,6 +956,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
|
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
self.make_function(node, isLambda=False, code_index=code_index)
|
self.make_function(node, isLambda=False, code_index=code_index)
|
||||||
|
|
||||||
if len(self.param_stack) > 1:
|
if len(self.param_stack) > 1:
|
||||||
self.write('\n\n')
|
self.write('\n\n')
|
||||||
else:
|
else:
|
||||||
@@ -1135,7 +1140,10 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
if self.version > 3.0:
|
if self.version > 3.0:
|
||||||
currentclass = node[1][0].pattr
|
currentclass = node[1][0].pattr
|
||||||
buildclass = node[0]
|
buildclass = node[0]
|
||||||
subclass = buildclass[1][0].attr
|
if buildclass[1][0] == 'kwargs':
|
||||||
|
subclass = buildclass[1][1].attr
|
||||||
|
else:
|
||||||
|
subclass = buildclass[1][0].attr
|
||||||
subclass_info = node[0]
|
subclass_info = node[0]
|
||||||
else:
|
else:
|
||||||
buildclass = node[0]
|
buildclass = node[0]
|
||||||
@@ -1157,7 +1165,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
self.print_super_classes3(subclass_info)
|
self.print_super_classes3(subclass_info)
|
||||||
else:
|
else:
|
||||||
self.print_super_classes(build_list)
|
self.print_super_classes(build_list)
|
||||||
self.print_(':')
|
self.println(':')
|
||||||
|
|
||||||
# class body
|
# class body
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
@@ -1354,7 +1362,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
%c, %C, and so on.
|
%c, %C, and so on.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# self.print_("-----")
|
# self.println("-----")
|
||||||
# self.print(startnode)
|
# self.print(startnode)
|
||||||
|
|
||||||
fmt = entry[0]
|
fmt = entry[0]
|
||||||
@@ -1412,6 +1420,19 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
if remaining > 0:
|
if remaining > 0:
|
||||||
self.write(sep)
|
self.write(sep)
|
||||||
arg += 1
|
arg += 1
|
||||||
|
elif typ == 'D':
|
||||||
|
low, high, sep = entry[arg]
|
||||||
|
remaining = len(node[low:high])
|
||||||
|
for subnode in node[low:high]:
|
||||||
|
remaining -= 1
|
||||||
|
if len(subnode) > 0:
|
||||||
|
self.preorder(subnode)
|
||||||
|
if remaining > 0:
|
||||||
|
self.write(sep)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
arg += 1
|
||||||
elif typ == 'P':
|
elif typ == 'P':
|
||||||
p = self.prec
|
p = self.prec
|
||||||
low, high, sep, self.prec = entry[arg]
|
low, high, sep, self.prec = entry[arg]
|
||||||
@@ -1530,12 +1551,13 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
- handle format tuple parameters
|
- handle format tuple parameters
|
||||||
"""
|
"""
|
||||||
if self.version < 3.0:
|
if self.version < 3.0:
|
||||||
# rocky: is this still even relevant?
|
|
||||||
# if formal parameter is a tuple, the paramater name
|
# if formal parameter is a tuple, the paramater name
|
||||||
# starts with a dot (eg. '.1', '.2')
|
# starts with a dot (eg. '.1', '.2')
|
||||||
if name.startswith('.'):
|
if name.startswith('.'):
|
||||||
# replace the name with the tuple-string
|
# replace the name with the tuple-string
|
||||||
name = self.get_tuple_parameter(ast, name)
|
name = self.get_tuple_parameter(ast, name)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
if default:
|
if default:
|
||||||
if self.showast:
|
if self.showast:
|
||||||
@@ -1543,15 +1565,25 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
print('--', name)
|
print('--', name)
|
||||||
print(default)
|
print(default)
|
||||||
print('--')
|
print('--')
|
||||||
result = '%s = %s' % (name, self.traverse(default, indent='') )
|
result = '%s=%s' % (name, self.traverse(default, indent='') )
|
||||||
if result[-2:] == '= ': # default was 'LOAD_CONST None'
|
if result[-2:] == '= ': # default was 'LOAD_CONST None'
|
||||||
result += 'None'
|
result += 'None'
|
||||||
return result
|
return result
|
||||||
else:
|
else:
|
||||||
return name
|
return name
|
||||||
# node[-1] == MAKE_xxx_n
|
|
||||||
|
|
||||||
defparams = node[:node[-1].attr]
|
# node[-1] == MAKE_FUNCTION_n
|
||||||
|
|
||||||
|
args_node = node[-1]
|
||||||
|
if isinstance(args_node.attr, tuple):
|
||||||
|
defparams = node[:args_node.attr[0]]
|
||||||
|
pos_args, kw_args, annotate_args = args_node.attr
|
||||||
|
else:
|
||||||
|
defparams = node[:args_node.attr]
|
||||||
|
kw_args, annotate_args = (0, 0)
|
||||||
|
pos_args = args_node.attr
|
||||||
|
pass
|
||||||
|
|
||||||
code = node[code_index].attr
|
code = node[code_index].attr
|
||||||
|
|
||||||
assert iscode(code)
|
assert iscode(code)
|
||||||
@@ -1570,19 +1602,14 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
isLambda = isLambda,
|
isLambda = isLambda,
|
||||||
noneInNames = ('None' in code.co_names))
|
noneInNames = ('None' in code.co_names))
|
||||||
except ParserError as p:
|
except ParserError as p:
|
||||||
self.write( str(p))
|
self.write(str(p))
|
||||||
self.ERROR = p
|
self.ERROR = p
|
||||||
return
|
return
|
||||||
|
|
||||||
# build parameters
|
# build parameters
|
||||||
|
|
||||||
params = [build_param(ast, name, default) for
|
params = [build_param(ast, name, default) for
|
||||||
name, default in zip_longest(paramnames, defparams, fillvalue=None)]
|
name, default in zip_longest(paramnames, defparams, fillvalue=None)]
|
||||||
# params = [ build_param(ast, name, default) for
|
|
||||||
# name, default in zip(paramnames, defparams) ]
|
|
||||||
# params = []
|
|
||||||
# for i, name in enumerate(paramnames):
|
|
||||||
# default = defparams[i] if len(defparams) > i else None
|
|
||||||
# params.append( build_param(ast, name, default) )
|
|
||||||
|
|
||||||
params.reverse() # back to correct order
|
params.reverse() # back to correct order
|
||||||
|
|
||||||
@@ -1596,10 +1623,27 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
# dump parameter list (with default values)
|
# dump parameter list (with default values)
|
||||||
indent = self.indent
|
indent = self.indent
|
||||||
if isLambda:
|
if isLambda:
|
||||||
self.write("lambda ", ", ".join(params), ": ")
|
self.write("lambda ", ", ".join(params))
|
||||||
else:
|
else:
|
||||||
self.print_("(", ", ".join(params), "):")
|
self.write("(", ", ".join(params))
|
||||||
# self.print_(indent, '#flags:\t', int(code.co_flags))
|
# self.println(indent, '#flags:\t', int(code.co_flags))
|
||||||
|
|
||||||
|
if kw_args > 0:
|
||||||
|
if argc > 0:
|
||||||
|
self.write(", *, ")
|
||||||
|
else:
|
||||||
|
self.write("*, ")
|
||||||
|
for n in node:
|
||||||
|
if n == 'pos_arg':
|
||||||
|
continue
|
||||||
|
self.preorder(n)
|
||||||
|
break
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isLambda:
|
||||||
|
self.write(": ")
|
||||||
|
else:
|
||||||
|
self.println("):")
|
||||||
|
|
||||||
if len(code.co_consts)>0 and code.co_consts[0] is not None and not isLambda: # ugly
|
if len(code.co_consts)>0 and code.co_consts[0] is not None and not isLambda: # ugly
|
||||||
# docstring exists, dump it
|
# docstring exists, dump it
|
||||||
@@ -1610,10 +1654,11 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
|
|
||||||
all_globals = find_all_globals(ast, set())
|
all_globals = find_all_globals(ast, set())
|
||||||
for g in ((all_globals & self.mod_globs) | find_globals(ast, set())):
|
for g in ((all_globals & self.mod_globs) | find_globals(ast, set())):
|
||||||
self.print_(self.indent, 'global ', g)
|
self.println(self.indent, 'global ', g)
|
||||||
self.mod_globs -= all_globals
|
self.mod_globs -= all_globals
|
||||||
rn = ('None' in code.co_names) and not find_none(ast)
|
rn = ('None' in code.co_names) and not find_none(ast)
|
||||||
self.gen_source(ast, code.co_name, code._customize, isLambda=isLambda, returnNone=rn)
|
self.gen_source(ast, code.co_name, code._customize, isLambda=isLambda,
|
||||||
|
returnNone=rn)
|
||||||
code._tokens = None; code._customize = None # save memory
|
code._tokens = None; code._customize = None # save memory
|
||||||
|
|
||||||
def build_class(self, code):
|
def build_class(self, code):
|
||||||
@@ -1624,7 +1669,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
code = Code(code, self.scanner, self.currentclass)
|
code = Code(code, self.scanner, self.currentclass)
|
||||||
|
|
||||||
indent = self.indent
|
indent = self.indent
|
||||||
# self.print_(indent, '#flags:\t', int(code.co_flags))
|
# self.println(indent, '#flags:\t', int(code.co_flags))
|
||||||
ast = self.build_ast(code._tokens, code._customize)
|
ast = self.build_ast(code._tokens, code._customize)
|
||||||
code._tokens = None # save memory
|
code._tokens = None # save memory
|
||||||
assert ast == 'stmts'
|
assert ast == 'stmts'
|
||||||
@@ -1664,7 +1709,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
except:
|
except:
|
||||||
docstring = code.co_consts[0]
|
docstring = code.co_consts[0]
|
||||||
self.print_docstring(indent, docstring)
|
self.print_docstring(indent, docstring)
|
||||||
self.print_()
|
self.println()
|
||||||
del ast[i]
|
del ast[i]
|
||||||
|
|
||||||
|
|
||||||
@@ -1676,7 +1721,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
# print ast[-1][-1]
|
# print ast[-1][-1]
|
||||||
|
|
||||||
for g in find_globals(ast, set()):
|
for g in find_globals(ast, set()):
|
||||||
self.print_(indent, 'global ', g)
|
self.println(indent, 'global ', g)
|
||||||
|
|
||||||
self.gen_source(ast, code.co_name, code._customize)
|
self.gen_source(ast, code.co_name, code._customize)
|
||||||
code._tokens = None; code._customize = None # save memory
|
code._tokens = None; code._customize = None # save memory
|
||||||
@@ -1690,14 +1735,14 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
self.name = name
|
self.name = name
|
||||||
# if code would be empty, append 'pass'
|
# if code would be empty, append 'pass'
|
||||||
if len(ast) == 0:
|
if len(ast) == 0:
|
||||||
self.print_(self.indent, 'pass')
|
self.println(self.indent, 'pass')
|
||||||
else:
|
else:
|
||||||
self.customize(customize)
|
self.customize(customize)
|
||||||
if isLambda:
|
if isLambda:
|
||||||
self.write(self.traverse(ast, isLambda=isLambda))
|
self.write(self.traverse(ast, isLambda=isLambda))
|
||||||
else:
|
else:
|
||||||
self.text = self.traverse(ast, isLambda=isLambda)
|
self.text = self.traverse(ast, isLambda=isLambda)
|
||||||
self.print_(self.text)
|
self.println(self.text)
|
||||||
self.return_none = rn
|
self.return_none = rn
|
||||||
|
|
||||||
def build_ast(self, tokens, customize, isLambda=0, noneInNames=False):
|
def build_ast(self, tokens, customize, isLambda=0, noneInNames=False):
|
||||||
@@ -1711,7 +1756,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
except (python_parser.ParserError, AssertionError) as e:
|
except (python_parser.ParserError, AssertionError) as e:
|
||||||
raise ParserError(e, tokens)
|
raise ParserError(e, tokens)
|
||||||
if self.showast:
|
if self.showast:
|
||||||
self.print_(repr(ast))
|
self.println(repr(ast))
|
||||||
return ast
|
return ast
|
||||||
|
|
||||||
# The bytecode for the end of the main routine has a
|
# The bytecode for the end of the main routine has a
|
||||||
@@ -1735,7 +1780,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
raise ParserError(e, tokens)
|
raise ParserError(e, tokens)
|
||||||
|
|
||||||
if self.showast:
|
if self.showast:
|
||||||
self.print_(repr(ast))
|
self.println(repr(ast))
|
||||||
|
|
||||||
return ast
|
return ast
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user