%PDF- %PDF-
| Direktori : /proc/self/root/usr/lib/python3/dist-packages/pythran/transformations/ |
| Current File : //proc/self/root/usr/lib/python3/dist-packages/pythran/transformations/normalize_compare.py |
""" NormalizeCompare turns complex compare into function calls. """
from pythran.analyses import ImportedIds
from pythran.passmanager import Transformation
from pythran.utils import path_to_attr
import pythran.metadata as metadata
import gast as ast
def is_trivially_copied(node):
try:
ast.literal_eval(node)
return True
except ValueError:
pass
if isinstance(node, (ast.Name, ast.Attribute)):
return True
return False
class NormalizeCompare(Transformation):
'''
Turns multiple compare into a function with proper temporaries.
>>> import gast as ast
>>> from pythran import passmanager, backend
>>> node = ast.parse("def foo(a): return 0 < a + 1 < 3")
>>> pm = passmanager.PassManager("test")
>>> _, node = pm.apply(NormalizeCompare, node)
>>> print(pm.dump(backend.Python, node))
def foo(a):
return foo_compare0(a)
def foo_compare0(a):
$1 = (a + 1)
if (0 < $1):
pass
else:
return builtins.False
if ($1 < 3):
pass
else:
return builtins.False
return builtins.True
'''
def visit_Module(self, node):
self.compare_functions = list()
self.generic_visit(node)
node.body.extend(self.compare_functions)
self.update |= bool(self.compare_functions)
return node
def visit_FunctionDef(self, node):
self.prefix = node.name
self.generic_visit(node)
return node
def visit_Assert(self, node):
# Assume no side effect in asserts function.
# This is checked in extended_syntax check.
return node
def visit_Compare(self, node):
node = self.generic_visit(node)
if len(node.ops) > 1:
# in case we have more than one compare operator
# we generate an auxiliary function
# that lazily evaluates the needed parameters
imported_ids = self.gather(ImportedIds, node)
imported_ids = sorted(imported_ids)
binded_args = [ast.Name(i, ast.Load(), None, None)
for i in imported_ids]
# name of the new function
forged_name = "{0}_compare{1}".format(self.prefix,
len(self.compare_functions))
# call site
call = ast.Call(
ast.Name(forged_name, ast.Load(), None, None),
binded_args,
[])
# new function
arg_names = [ast.Name(i, ast.Param(), None, None)
for i in imported_ids]
args = ast.arguments(arg_names, [], None, [], [], None, [])
body = [] # iteratively fill the body (yeah, feel your body!)
if is_trivially_copied(node.left):
prev_holder = node.left
else:
body.append(
ast.Assign(
[ast.Name('$0', ast.Store(), None, None)],
node.left, None))
prev_holder = ast.Name('$0', ast.Load(), None, None)
for i, exp in enumerate(node.comparators):
if is_trivially_copied(exp):
holder = exp
else:
body.append(ast.Assign([ast.Name('${}'.format(i+1),
ast.Store(), None, None)],
exp, None))
holder = ast.Name('${}'.format(i+1), ast.Load(),
None, None)
cond = ast.Compare(prev_holder,
[node.ops[i]],
[holder])
body.append(
ast.If(cond,
[ast.Pass()],
[ast.Return(path_to_attr(('builtins', 'False')))]))
prev_holder = holder
body.append(ast.Return(path_to_attr(('builtins', 'True'))))
forged_fdef = ast.FunctionDef(forged_name, args, body, [], None,
None)
metadata.add(forged_fdef, metadata.Local())
self.compare_functions.append(forged_fdef)
return call
else:
return node