%PDF- %PDF-
| Direktori : /lib/python3/dist-packages/pythran/ |
| Current File : //lib/python3/dist-packages/pythran/conversion.py |
""" This module provides way to convert a Python value into an ast. """
import gast as ast
import numpy as np
import numbers
# Maximum length of folded sequences
# Containers larger than this are not unfolded to limit code size growth
MAX_LEN = 2 ** 8
class ConversionError(Exception):
""" Exception raised when conversion from value to ast can't be done. """
class ToNotEval(Exception):
"""
Exception raised when we don't want to evaluate the value.
It is case of too long expression for example.
"""
def totuple(l):
try:
return tuple(map(totuple, l))
except TypeError:
return l
def dtype_to_ast(name):
if name in ('bool',):
return ast.Attribute(
ast.Name('builtins', ast.Load(), None, None),
name,
ast.Load())
else:
return ast.Attribute(
ast.Name(mangle('numpy'), ast.Load(), None, None),
name,
ast.Load())
def size_container_folding(value):
"""
Convert value to ast expression if size is not too big.
Converter for sized container.
"""
def size(x):
return len(getattr(x, 'flatten', lambda: x)())
if size(value) < MAX_LEN:
if isinstance(value, list):
return ast.List([to_ast(elt) for elt in value], ast.Load())
elif isinstance(value, tuple):
return ast.Tuple([to_ast(elt) for elt in value], ast.Load())
elif isinstance(value, set):
if value:
return ast.Set([to_ast(elt) for elt in value])
else:
return ast.Call(func=ast.Attribute(
ast.Name(mangle('builtins'), ast.Load(), None, None),
'set',
ast.Load()),
args=[],
keywords=[])
elif isinstance(value, dict):
keys = [to_ast(elt) for elt in value.keys()]
values = [to_ast(elt) for elt in value.values()]
return ast.Dict(keys, values)
elif isinstance(value, np.ndarray):
if len(value) == 0:
return ast.Call(func=ast.Attribute(
ast.Name(mangle('numpy'), ast.Load(), None, None),
'empty',
ast.Load()),
args=[to_ast(value.shape),
dtype_to_ast(value.dtype.name)],
keywords=[])
else:
return ast.Call(func=ast.Attribute(
ast.Name(mangle('numpy'), ast.Load(), None, None),
'array',
ast.Load()),
args=[to_ast(totuple(value.tolist())),
dtype_to_ast(value.dtype.name)],
keywords=[])
else:
raise ConversionError()
else:
raise ToNotEval()
def builtin_folding(value):
""" Convert builtin function to ast expression. """
if isinstance(value, (type(None), bool)):
name = str(value)
else:
name = value.__name__
return ast.Attribute(ast.Name('builtins', ast.Load(), None, None),
name, ast.Load())
def to_ast(value):
"""
Turn a value into ast expression.
>>> a = 1
>>> print(ast.dump(to_ast(a)))
Num(n=1)
>>> a = [1, 2, 3]
>>> print(ast.dump(to_ast(a)))
List(elts=[Num(n=1), Num(n=2), Num(n=3)], ctx=Load())
"""
if any(value is t for t in (bool, int, float)):
iinfo = np.iinfo(int)
if isinstance(value, int) and not (iinfo.min <= value <= iinfo.max):
from pythran.syntax import PythranSyntaxError
raise PythranSyntaxError("constant folding results in big int")
return builtin_folding(value)
elif isinstance(value, np.generic):
return to_ast(value.item())
elif isinstance(value, (numbers.Number, str, bool, type(None))):
return ast.Constant(value, None)
elif isinstance(value, (list, tuple, set, dict, np.ndarray)):
return size_container_folding(value)
elif hasattr(value, "__module__") and value.__module__ == "builtins":
# TODO Can be done the same way for others modules
return builtin_folding(value)
# only meaningful for python3
elif isinstance(value, (filter, map, zip)):
return to_ast(list(value))
elif isinstance(value, np._globals._NoValueType):
return ast.Attribute(ast.Attribute(ast.Name('numpy', ast.Load(), None,
None), '_globals',
ast.Load()),
'_NoValueType', ast.Load())
raise ToNotEval()
PYTHRAN_IMPORT_MANGLING = '__pythran_import_'
def mangle(name):
'''
Mangle a module name, except the builtins module
>>> mangle('numpy')
__pythran_import_numpy
>>> mangle('builtins')
builtins
'''
if name == 'builtins':
return name
else:
return PYTHRAN_IMPORT_MANGLING + name
def demangle(name):
'''
Demangle a module name, if needed
>>> demangle('__pythran_import_numpy')
numpy
>>> mangle('numpy')
numpy
'''
if name.startswith(PYTHRAN_IMPORT_MANGLING):
return name[len(PYTHRAN_IMPORT_MANGLING):]
else:
return name