def __init__(self, expr, context):
self.expr = expr
self.context = context
self.expr_table = {
LLLnode: self.get_expr,
ast.Num: self.number,
ast.Str: self.string,
ast.NameConstant: self.constants,
ast.Name: self.variables,
ast.Attribute: self.attribute,
ast.Subscript: self.subscript,
ast.BinOp: self.arithmetic,
ast.Compare: self.compare,
ast.BoolOp: self.boolean_operations,
ast.UnaryOp: self.unary_operations,
ast.Call: self.call,
ast.List: self.list_literals,
ast.Dict: self.struct_literals,
ast.Tuple: self.tuple_literals,
}
expr_type = self.expr.__class__
if expr_type in self.expr_table:
self.lll_node = self.expr_table[expr_type]()
else:
raise Exception("Unsupported operator: %r" % ast.dump(self.expr))
python类NameConstant()的实例源码
def basicTypeSpecialFunction(cv):
"""If you're in a number or string (which has no metadata), move up to the AST to make the special functions work."""
if isinstance(cv, SwapVector) or isinstance(cv, MoveVector):
return cv
if (cv.path[0] in [('n', 'Number'), ('s', 'String'), ('id', 'Name'), ('arg', 'Argument'),
('value', 'Name Constant'), ('s', 'Bytes'), ('name', 'Alias')]):
cvCopy = cv.deepcopy()
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
if cv.path[0] == ('n', 'Number'):
cv.newSubtree = ast.Num(cv.newSubtree)
elif cv.path[0] == ('s', 'String'):
cv.newSubtree = ast.Str(cv.newSubtree)
elif cv.path[0] == ('id', 'Name'):
cv.newSubtree = ast.Name(cv.newSubtree, cv.oldSubtree.ctx)
elif cv.path[0] == ('arg', 'Argument'):
cv.newSubtree = ast.arg(cv.newSubtree, cv.oldSubtree.annotation)
elif cv.path[0] == ('value', 'Name Constant'):
cv.newSubtree = ast.NameConstant(cv.newSubtree)
elif cv.path[0] == ('s', 'Bytes'):
cv.newSubtree = ast.Bytes(cv.newSubtree)
elif cv.path[0] == ('name', 'Alias'):
cv.newSubtree = ast.alias(cv.newSubtree, cv.oldSubtree.asname)
cv.path = cv.path[1:]
return cv
def visit_If(self, node):
"""
If(expr test, stmt* body, stmt* orelse)
"""
if isinstance(node.test, (ast.NameConstant, ast.Compare)):
self.write("if %s" % self.visit(node.test))
else:
self.write("if is_bool(%s)" % self.visit(node.test))
self.indent()
for stmt in node.body:
self.visit(stmt)
self.dedent()
if node.orelse:
self.write("else")
self.indent()
for stmt in node.orelse:
self.visit(stmt)
self.dedent()
self.write("end")
def specialize_constant(node, value):
if value is None or isinstance(value, bool):
new_node = ast.NameConstant(value=value)
elif isinstance(value, (int, float, complex)):
new_node = ast.Num(n=value)
elif isinstance(value, str):
new_node = ast.Str(s=value)
elif isinstance(value, bytes):
new_node = ast.Bytes(s=value)
elif isinstance(value, tuple):
elts = [specialize_constant(node, elt) for elt in value]
new_node = ast.Tuple(elts=elts, ctx=ast.Load())
else:
raise ValueError("unknown constant: %r" % value)
fatoptimizer.tools.copy_lineno(node, new_node)
return new_node
def convert_to_value(item):
if isinstance(item, ast.Str):
return item.s
elif hasattr(ast, 'Bytes') and isinstance(item, ast.Bytes):
return item.s
elif isinstance(item, ast.Tuple):
return tuple(convert_to_value(i) for i in item.elts)
elif isinstance(item, ast.Num):
return item.n
elif isinstance(item, ast.Name):
result = VariableKey(item=item)
constants_lookup = {
'True': True,
'False': False,
'None': None,
}
return constants_lookup.get(
result.name,
result,
)
elif (not PY33) and isinstance(item, ast.NameConstant):
# None, True, False are nameconstants in python3, but names in 2
return item.value
else:
return UnhandledKeyType()
def convert_to_value(item):
if isinstance(item, ast.Str):
return item.s
elif hasattr(ast, 'Bytes') and isinstance(item, ast.Bytes):
return item.s
elif isinstance(item, ast.Tuple):
return tuple(convert_to_value(i) for i in item.elts)
elif isinstance(item, ast.Num):
return item.n
elif isinstance(item, ast.Name):
result = VariableKey(item=item)
constants_lookup = {
'True': True,
'False': False,
'None': None,
}
return constants_lookup.get(
result.name,
result,
)
elif (not PY33) and isinstance(item, ast.NameConstant):
# None, True, False are nameconstants in python3, but names in 2
return item.value
else:
return UnhandledKeyType()
def buildexec(self):
if isinstance(self.schema, Null):
if sys.version_info[0] <= 2:
return ast.Name("None", ast.Load())
else:
return ast.NameConstant(None)
elif isinstance(self.schema, Boolean):
if sys.version_info[0] <= 2:
if self.value:
return ast.Name("True", ast.Load())
else:
return ast.Name("False", ast.Load())
else:
if self.value:
return ast.NameConstant(True)
else:
return ast.NameConstant(False)
elif isinstance(self.schema, Number):
return ast.Num(self.value)
else:
raise NotImplementedError # have to think about this when the case comes up
def reify(kvalue, gen_sym):
value = kvalue.value
if value is True or value is False or value is None:
return ast.NameConstant(value=value), gen_sym, {}
elif type(value) == str:
return ast.Str(s=value), gen_sym, {}
elif type(value) == bytes:
return ast.Bytes(s=value), gen_sym, {}
elif type(value) in (int, float, complex):
return ast.Num(n=value), gen_sym, {}
else:
if kvalue.preferred_name is None:
name, gen_sym = gen_sym('temp')
else:
name = kvalue.preferred_name
return ast.Name(id=name, ctx=ast.Load()), gen_sym, {name: value}
def test_simple_reify():
check_reify(True, ast.NameConstant(value=True))
check_reify(False, ast.NameConstant(value=False))
check_reify(None, ast.NameConstant(value=None))
class Dummy(): pass
x = Dummy()
check_reify(
x, ast.Name(id='__peval_temp_1', ctx=ast.Load()),
expected_binding=dict(__peval_temp_1=x))
check_reify(
x, ast.Name(id='y', ctx=ast.Load()),
preferred_name='y', expected_binding=dict(y=x))
check_reify(1, ast.Num(n=1))
check_reify(2.3, ast.Num(n=2.3))
check_reify(3+4j, ast.Num(n=3+4j))
check_reify('abc', ast.Str(s='abc'))
s = bytes('abc', encoding='ascii')
check_reify(s, ast.Bytes(s=s))
def noneSpecialFunction(cv):
"""If the old type is 'None' (which won't show up in the original), move up in the AST to get the metadata"""
if (not isinstance(cv, AddVector)) and cv.oldSubtree == None:
cvCopy = cv.deepcopy()
if cv.path[0] == ('value', 'Return'):
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
cv.newSubtree = ast.Return(cv.newSubtree)
cv.path = cv.path[1:]
elif cv.path[0] == ('value', 'Name Constant'):
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
cv.newSubtree = ast.NameConstant(cv.newSubtree)
cv.path = cv.path[1:]
elif cv.path[0] in [('lower', 'Slice'), ('upper', 'Slice'), ('step', 'Slice')]:
tmpNew = cv.newSubtree
cvCopy = cv.deepcopy()
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
cv.newSubtree = deepcopy(cv.oldSubtree) # use the same slice
if cv.path[0][0] == 'lower':
cv.newSubtree.lower = tmpNew
elif cv.path[0][0] == 'upper':
cv.newSubtree.upper = tmpNew
else:
cv.newSubtree.step = tmpNew
cv.path = cv.path[1:] # get rid of None and the val
else:
log("Individualize\tmapEdit\tMissing option in None special case 1: " + str(cv.path[0]), "bug")
elif cv.oldSubtree == "None":
cv.path = cv.path[1:] # get rid of None and the id
cvCopy = cv.deepcopy()
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
if cv.path[0] == ('value', 'Return'):
cv.newSubtree = ast.Return(ast.Name(cv.newSubtree, ast.Load()))
else:
log("Individualize\tmapEdit\tMissing option in None special case 2: " + str(cv.path[0]), "bug")
cv.path = cv.path[1:]
return cv
def cleanupEquals(a):
"""Gets rid of silly blah == True statements that students make"""
if not isinstance(a, ast.AST):
return a
if type(a) == ast.Call:
a.func = cleanupEquals(a.func)
for i in range(len(a.args)):
# But test expressions don't carry through to function arguments
a.args[i] = cleanupEquals(a.args[i])
return a
elif type(a) == ast.Compare and type(a.ops[0]) in [ast.Eq, ast.NotEq]:
l = a.left = cleanupEquals(a.left)
r = cleanupEquals(a.comparators[0])
a.comparators = [r]
if type(l) == ast.NameConstant and l.value in [True, False]:
(l,r) = (r,l)
# If we have (boolean expression) == True
if type(r) == ast.NameConstant and r.value in [True, False] and (eventualType(l) == bool):
# Matching types
if (type(a.ops[0]) == ast.Eq and r.value == True) or \
(type(a.ops[0]) == ast.NotEq and r.value == False):
transferMetaData(a, l) # make sure to keep the original location
return l
else:
tmp = ast.UnaryOp(ast.Not(addedNotOp=True), l)
transferMetaData(a, tmp)
return tmp
else:
return a
else:
return applyToChildren(a, cleanupEquals)
def isConstant(x):
"""Determine whether the provided AST is a constant"""
return (type(x) in [ast.Num, ast.Str, ast.Bytes, ast.NameConstant])
def astFormat(x, gid=None):
"""Given a value, turn it into an AST if it's a constant; otherwise, leave it alone."""
if type(x) in [int, float, complex]:
return ast.Num(x)
elif type(x) == bool or x == None:
return ast.NameConstant(x)
elif type(x) == type:
types = { bool : "bool", int : "int", float : "float",
complex : "complex", str : "str", bytes : "bytes", unicode : "unicode",
list : "list", tuple : "tuple", dict : "dict" }
return ast.Name(types[x], ast.Load())
elif type(x) == str: # str or unicode
return ast.Str(x)
elif type(x) == bytes:
return ast.Bytes(x)
elif type(x) == list:
elts = [astFormat(val) for val in x]
return ast.List(elts, ast.Load())
elif type(x) == dict:
keys = []
vals = []
for key in x:
keys.append(astFormat(key))
vals.append(astFormat(x[key]))
return ast.Dict(keys, vals)
elif type(x) == tuple:
elts = [astFormat(val) for val in x]
return ast.Tuple(elts, ast.Load())
elif type(x) == set:
elts = [astFormat(val) for val in x]
if len(elts) == 0: # needs to be a call instead
return ast.Call(ast.Name("set", ast.Load()), [], [])
else:
return ast.Set(elts)
elif type(x) == slice:
return ast.Slice(astFormat(x.start), astFormat(x.stop), astFormat(x.step))
elif isinstance(x, ast.AST):
return x # Do not change if it's not constant!
else:
log("astTools\tastFormat\t" + str(type(x)) + "," + str(x),"bug")
return None
def basicFormat(x):
"""Given an AST, turn it into its value if it's constant; otherwise, leave it alone"""
if type(x) == ast.Num:
return x.n
elif type(x) == ast.NameConstant:
return x.value
elif type(x) == ast.Str:
return x.s
elif type(x) == ast.Bytes:
return x.s
return x # Do not change if it's not a constant!
def visit_IfExp(self, node):
"""
IfExp(expr test, expr body, expr orelse)
"""
body = self.visit(node.body)
or_else = self.visit(node.orelse)
if isinstance(node.test, (ast.NameConstant, ast.Compare)):
return "(%s) ? %s : %s" % (self.visit(node.test), body, or_else)
else:
return "is_bool(%s) ? %s : %s" % (self.visit(node.test), body, or_else)
def visit_NameConstant(self, node):
"""
NameConstant(singleton value)
"""
value = node.value
value = self.name_constant_map[value]
return value
def match(self, node):
if six.PY3:
if node.__class__ != ast.NameConstant:
return False
return node.value is None
elif six.PY2:
if node.__class__ != ast.Name:
return False
return node.id == "None"
def remove_passcontext(self, n):
for d in n.decorator_list:
if not isinstance(d, ast.Call):
continue
for kw in list(d.keywords): # iterate over a copy of the list to avoid removing while iterating
if not isinstance(kw.value, ast.NameConstant):
continue
if kw.arg == 'pass_context': # if the pass_context kwarg is set to True
if self.interactive and not prompt_change(
'A possible change was found to remove the pass_context decorator from {}.'.format(n.name)
):
return n
d.keywords.remove(kw)
stats_counter['coro_changes'] += 1
return n
def test_nameconstant(self):
self.expr(ast.NameConstant(4), "singleton must be True, False, or None")
def __init__(self, operators=None, functions=None, names=None):
"""
Create the evaluator instance. Set up valid operators (+,-, etc)
functions (add, random, get_val, whatever) and names. """
if not operators:
operators = DEFAULT_OPERATORS
if not functions:
functions = DEFAULT_FUNCTIONS
if not names:
names = DEFAULT_NAMES
self.operators = operators
self.functions = functions
self.names = names
self.nodes = {
ast.Num: self._eval_num,
ast.Str: self._eval_str,
ast.Name: self._eval_name,
ast.UnaryOp: self._eval_unaryop,
ast.BinOp: self._eval_binop,
ast.BoolOp: self._eval_boolop,
ast.Compare: self._eval_compare,
ast.IfExp: self._eval_ifexp,
ast.Call: self._eval_call,
ast.keyword: self._eval_keyword,
ast.Subscript: self._eval_subscript,
ast.Attribute: self._eval_attribute,
ast.Index: self._eval_index,
ast.Slice: self._eval_slice,
}
# py3k stuff:
if hasattr(ast, 'NameConstant'):
self.nodes[ast.NameConstant] = self._eval_nameconstant
elif isinstance(self.names, dict) and "None" not in self.names:
self.names["None"] = None
def test_nameconstant(self):
self.expr(ast.NameConstant(4), "singleton must be True, False, or None")
def ast(self):
"""Python AST of this predicate (construct transitively for all indirect children as well).
:return: AST of describing all children predicates
"""
# We should return:
# return ast.NameConstant(value=True)
# but it does not work with codegen
return ast.Name(id='True', ctx=ast.Load())
def ast(self):
"""Python AST of this predicate (construct transitively for all indirect children as well).
:return: AST of describing all children predicates
"""
# We should return:
# return ast.NameConstant(value=True)
# but it does not work with codegen
return ast.Name(id='True', ctx=ast.Load())
def ivy_type_of_lit(self, x):
ast_class = parse_literal_expression(x)
if ast_class is ast.Num:
return 't_intbool'
elif ast_class is ast.Str:
return 't_str'
elif ast_class is ast.NameConstant and x in ['True', 'False']:
return 't_intbool'
elif ast_class is ast.NameConstant and x == 'None':
return 't_none'
else:
return None
def deMorganize(a):
"""Apply De Morgan's law throughout the code in order to canonicalize"""
if not isinstance(a, ast.AST):
return a
# We only care about statements beginning with not
if type(a) == ast.UnaryOp and type(a.op) == ast.Not:
oper = a.operand
top = type(oper)
# not (blah and gah) == (not blah or not gah)
if top == ast.BoolOp:
oper.op = negate(oper.op)
for i in range(len(oper.values)):
oper.values[i] = deMorganize(negate(oper.values[i]))
oper.negated = not oper.negated if hasattr(oper, "negated") else True
transferMetaData(a, oper)
return oper
# not a < b == a >= b
elif top == ast.Compare:
oper.left = deMorganize(oper.left)
oper.ops = [negate(oper.ops[0])]
oper.comparators = [deMorganize(oper.comparators[0])]
oper.negated = not oper.negated if hasattr(oper, "negated") else True
transferMetaData(a, oper)
return oper
# not not blah == blah
elif top == ast.UnaryOp and type(oper.op) == ast.Not:
oper.operand = deMorganize(oper.operand)
if eventualType(oper.operand) != bool:
return a
oper.operand.negated = not oper.operand.negated if hasattr(oper.operand, "negated") else True
return oper.operand
elif top == ast.NameConstant:
if oper.value in [True, False]:
oper = negate(oper)
transferMetaData(a, oper)
return oper
elif oper.value == None:
tmp = ast.NameConstant(True)
transferMetaData(a, tmp)
tmp.negated = True
return tmp
else:
log("Unknown NameConstant: " + str(oper.value), "bug")
return applyToChildren(a, deMorganize)
##### CLEANUP FUNCTIONS #####
def test__get_literal_value(self):
new_context = context.Context()
value = ast.Num(42)
expected = value.n
self.assertEqual(expected, new_context._get_literal_value(value))
value = ast.Str('spam')
expected = value.s
self.assertEqual(expected, new_context._get_literal_value(value))
value = ast.List([ast.Str('spam'), ast.Num(42)], ast.Load())
expected = [ast.Str('spam').s, ast.Num(42).n]
self.assertListEqual(expected, new_context._get_literal_value(value))
value = ast.Tuple([ast.Str('spam'), ast.Num(42)], ast.Load())
expected = (ast.Str('spam').s, ast.Num(42).n)
self.assertTupleEqual(expected, new_context._get_literal_value(value))
value = ast.Set([ast.Str('spam'), ast.Num(42)])
expected = set([ast.Str('spam').s, ast.Num(42).n])
self.assertSetEqual(expected, new_context._get_literal_value(value))
value = ast.Dict(['spam', 'eggs'], [42, 'foo'])
expected = dict(spam=42, eggs='foo')
self.assertDictEqual(expected, new_context._get_literal_value(value))
value = ast.Ellipsis()
self.assertIsNone(new_context._get_literal_value(value))
value = ast.Name('spam', ast.Load())
expected = value.id
self.assertEqual(expected, new_context._get_literal_value(value))
if six.PY3:
value = ast.NameConstant(True)
expected = str(value.value)
self.assertEqual(expected, new_context._get_literal_value(value))
if six.PY3:
value = ast.Bytes(b'spam')
expected = value.s
self.assertEqual(expected, new_context._get_literal_value(value))
self.assertIsNone(new_context._get_literal_value(None))
def infer(node, context, solver, from_call=False):
"""Infer the type of a given AST node"""
if isinstance(node, ast.Num):
return infer_numeric(node, solver)
elif isinstance(node, ast.Str):
return solver.z3_types.string
elif (sys.version_info[0] >= 3 and sys.version_info[1] >= 6 and
(isinstance(node, ast.FormattedValue) or isinstance(node, ast.JoinedStr))):
# Formatted strings were introduced in Python 3.6
return solver.z3_types.string
elif isinstance(node, ast.Bytes):
return solver.z3_types.bytes
elif isinstance(node, ast.List):
return infer_list(node, context, solver)
elif isinstance(node, ast.Dict):
return infer_dict(node, context, solver)
elif isinstance(node, ast.Tuple):
return infer_tuple(node, context, solver)
elif isinstance(node, ast.NameConstant):
return infer_name_constant(node, solver)
elif isinstance(node, ast.Set):
return infer_set(node, context, solver)
elif isinstance(node, ast.BinOp):
return infer_binary_operation(node, context, solver)
elif isinstance(node, ast.BoolOp):
return infer_boolean_operation(node, context, solver)
elif isinstance(node, ast.UnaryOp):
return infer_unary_operation(node, context, solver)
elif isinstance(node, ast.IfExp):
return infer_if_expression(node, context, solver)
elif isinstance(node, ast.Subscript):
return infer_subscript(node, context, solver)
elif sys.version_info[0] >= 3 and sys.version_info[1] >= 5 and isinstance(node, ast.Await):
# Await and Async were introduced in Python 3.5
return infer(node.value, context, solver)
elif isinstance(node, ast.Yield):
return infer(node.value, context, solver)
elif isinstance(node, ast.Compare):
return infer_compare(node, context, solver)
elif isinstance(node, ast.Name):
return infer_name(node, context)
elif isinstance(node, ast.ListComp):
return infer_sequence_comprehension(node, solver.z3_types.list, context, solver)
elif isinstance(node, ast.SetComp):
return infer_sequence_comprehension(node, solver.z3_types.set, context, solver)
elif isinstance(node, ast.DictComp):
return infer_dict_comprehension(node, context, solver)
elif isinstance(node, ast.Call):
return infer_func_call(node, context, solver)
elif isinstance(node, ast.Attribute):
return infer_attribute(node, context, from_call, solver)
elif isinstance(node, ast.Lambda):
return _infer_lambda(node, context, solver)
raise NotImplementedError("Inference for expression {} is not implemented yet.".format(type(node).__name__))
def buildexec(self, target, schema, args, argschemas, newname, references, tonative):
predicates = args[:-1][0::3]
antipredicates = args[:-1][1::3]
consequents = args[:-1][2::3]
alternate = args[-1]
def isNone(expression):
if sys.version_info[0] <= 2:
return isinstance(expression, ast.Name) and expression.id == "None" and isinstance(expression.ctx, ast.Load)
else:
return isinstance(expression, ast.NameConstant) and expression.value is None
def replaceNone(expression):
return expression
if isNullInt(schema):
def replaceNone(expression):
if isNone(expression):
return ast.Num(Number._intNaN)
else:
return expression
elif isNullFloat(schema):
def replaceNone(expression):
if isNone(expression):
return ast.Num(Number._floatNaN)
else:
return expression
chain = statementsToAst("""
OUT = ALT
""", OUT = target, ALT = replaceNone(alternate))
for predicate, consequent in reversed(list(zip(predicates, consequents))):
next = statementsToAst("""
if PRED:
OUT = CONS
else:
REPLACEME
""", OUT = target, PRED = predicate, CONS = replaceNone(consequent))
next[0].orelse = [chain[0]] # replacing REPLACEME
chain = next
return chain
def For_dict(t, x):
"""Special ``for name in dict(expr)`` statement translation.
It detects the ``dict()`` call and converts it to:
.. code:: javascript
var dict_ = expr;
for (var name in dict_) {
if (dict_.hasOwnProperty(name)) {
// ...
}
}
"""
if (isinstance(x.iter, ast.Call) and
isinstance(x.iter.func, ast.Name) and
x.iter.func.id == 'dict' and
len(x.iter.args) <= 2) and (not x.orelse):
t.unsupported(x, not isinstance(x.target, ast.Name),
"Target must be a name")
name = x.target
expr = x.iter.args[0]
body = x.body
dict_ = t.new_name()
# if not ``dict(foo, True)`` filter out inherited values
if not (len(x.iter.args) == 2 and
isinstance(x.iter.args[1], ast.NameConstant) and
x.iter.args[1].value):
body = [
JSIfStatement(
JSCall(
JSAttribute(JSName(dict_), 'hasOwnProperty'),
[JSName(name.id)]
),
body, None
)
]
# set the incoming py_node for the sourcemap
loop = JSForeachStatement(
name.id,
JSName(dict_),
body
)
loop.py_node = x
return JSStatements(
JSVarStatement([dict_], [expr], unmovable=True),
loop
)
def eval_function_def_as_closure(function_def, closure_names, globals_=None, flags=None):
"""
Evaluates an AST of a function definition inside a closure with the variables
from ``closure_names`` set to ``None``, and an optional dictionary of globals.
Returns a callable function (a ``types.FunctionType`` object).
.. warning::
Before the returned function can be actually called, the "fake" closure cells
(filled with ``None``) must be substituted by actual closure cells
that will be used during the call.
"""
assert type(function_def) == ast.FunctionDef
none = ast.NameConstant(value=None)
# We can't possibly recreate ASTs of existing closure variables
# (because all we have are their values).
# So we create fake closure variables for the function to attach to,
# and then substitute the closure cells with the ones obtained from
# the "prototype" of this function (a ``types.FunctionType`` object
# from which this tree was extracted).
fake_closure_vars = [
ast.Assign(
targets=[ast.Name(id=name, ctx=ast.Store())],
value=none)
for name in closure_names]
empty_args = ast.arguments(
args=[],
vararg=None,
kwonlyargs=[],
kwarg=None,
defaults=[],
kw_defaults=[])
wrapper_def = ast.FunctionDef(
name='__peval_wrapper',
args=empty_args,
decorator_list=[],
body=(
fake_closure_vars +
[function_def] +
[ast.Return(value=ast.Name(id=function_def.name, ctx=ast.Load()))]))
wrapper = eval_function_def(wrapper_def, globals_=globals_, flags=flags)
return wrapper()