diff options
Diffstat (limited to 'test-chill/testchill/_cpp_validate_env.py')
-rw-r--r-- | test-chill/testchill/_cpp_validate_env.py | 654 |
1 files changed, 654 insertions, 0 deletions
diff --git a/test-chill/testchill/_cpp_validate_env.py b/test-chill/testchill/_cpp_validate_env.py new file mode 100644 index 0000000..9ef5a71 --- /dev/null +++ b/test-chill/testchill/_cpp_validate_env.py @@ -0,0 +1,654 @@ +import ast as _pyast +import collections as _pycollections +import functools as _pyfunctools +import itertools as _pyitertools +import random as _pyrandom +import struct as _pystruct +import types as _pytypes + +from . import util as _chill_util + +_pylambdatype = _pycollections.namedtuple('LambdaType', ['paramtypes','exprtype']) +_pyarraytype = _pycollections.namedtuple('ArrayType', ['dimensions','basetype']) + +_runtime_globals = dict({ + '_pyitertools':_pyitertools, + '_pyrandom':_pyrandom + }) + +def _evalexpr(expr, target_type, bindings): + glbls = dict(bindings) + glbls.update(_runtime_globals) + if target_type is None: + pytype = None + else: + pytype = target_type.getpytype() + expr = _pyast.Expression(expr.compile_expr(pytype)) + expr = _pyast.fix_missing_locations(expr) + return eval(compile(expr, '<string>', 'eval'), glbls) + +def _addbindings(expr, binding_frame): + if hasattr(expr, 'binding_stack'): + expr.binding_stack = [binding_frame] + expr.binding_stack + return expr + + +class _TreeNode(object): + def print_tree(self, stream=None, indent=0): + strname = type(self).__name__ + stream.write(strname + ':\n') + indent += 2 + for k,v in vars(self).items(): + if isinstance(v, _TreeNode): + stream.write(('{}{}:'.format(' '*indent, k))) + v.print_tree(stream, indent + len(k)) + elif isinstance(v, list): + stream.write(('{}{}: [\n'.format(' '*indent, k))) + for itm in v: + if isinstance(itm, _TreeNode): + stream.write(' '*indent) + itm.print_tree(stream, indent + len(k) + 1) + else: + stream.write('{}{}\n'.format(' '*(indent + 1), str(itm))) + else: + stream.write(('{}{}: {}\n'.format(' '*indent, k, str(v)))) + +class _CppType(_TreeNode): + def __init__(self): + pass + + def __repr__(self): + return "{}".format(str(self)) + + def statictype(self, bindings): + return self + + def formatdata(self, data): + raise NotImplementedError + + def get_cdecl_stmt(self, param_name): + raise NotImplementedError + + def get_cread_stmt(self, param_name, istream_name, dims): + raise NotImplementedError + + def get_cwrite_stmt(self, param_name, ostream_name, dims): + raise NotImplementedError + + def getfreevars(self, glbls): + raise NotImplementedError + + +class _CppPrimitiveType(_CppType): + _bycppname = { + 'char': ('char', 'c', 1, False, False, True, False), + 'signed char': ('signed char', 'b', 1, True, False, False, False), + 'unsigned char': ('unsigned char', 'B', 1, True, False, False, False), + 'short': ('short', 'h', 2, True, False, False, True), + 'unsigned short': ('unsigned short', 'H', 2, True, False, False, False), + 'int': ('int', 'i', 4, True, False, False, True), + 'unsigned int': ('unsigned int', 'I', 4, True, False, False, False), + 'long': ('long', 'l', 4, True, False, False, True), + 'unsigned long': ('unsigned long', 'L', 4, True, False, False, False), + 'long long': ('long long', 'q', 8, True, False, False, True), + 'unsigned long long': ('unsigned long long', 'Q', 8, True, False, False, False), + 'float': ('float', 'f', 4, False, True, False, True), + 'double': ('double', 'd', 8, False, True, False, True) + } + def __init__(self, cppname, structfmt, size, isint, isfloat, ischar, issigned): + _CppType.__init__(self) + self.cppname = cppname + self.size = size + self.size_expr = 'sizeof(' + cppname + ')' + self.structfmt = structfmt + self.isint = isint + self.isfloat = isfloat + self.ischar = ischar + self.issigned = issigned + + @staticmethod + def get_from_cppname(cppname): + return _CppPrimitiveType(*_CppPrimitiveType._bycppname[cppname]) + + def getfreevars(self, glbls): + return set() + + def getpytype(self): + if self.ischar: + return str + elif self.isint: + return int + elif self.isfloat: + return float + + def __str__(self): + return self.cppname + + def formatdata(self, data): + return [1], _pystruct.pack(self.structfmt, data) + + def get_cdecl_stmt(self, param_name): + return '{} {};'.format(self.cppname, param_name) + + def get_cread_stmt(self, param_name, istream_name, dims): + return '{}.read((const char*)&{}, {});'.format(istream_name, param_name, self.size_expr) + + def get_cwrite_stmt(self, param_name, ostream_name, dims): + return '{}.write((const char*)&{}, {});'.format(ostream_name, param_name, self.size_expr) + + +class _CppVoidType(_CppType): + def __init__(self): + self.cppname = 'void' + + def getfreevars(self, glbls): + return set() + + def getpytype(self): + return type(None) + + def __str__(self): + return 'void' + + +class _CppArrayType(_CppType): + def __init__(self, basetype, dims=[None]): + _CppType.__init__(self) + self.basetype = basetype + self.dimensions = dims + + def getfreevars(self, glbls): + freevars = self.basetype.getfreevars(glbls) + for fv in iter(d.getfreevars(glbls) for d in self.dimensions if hasattr(d, 'getfreevars')): + freevars = freevars | fv + return freevars + + def getpytype(self): + return _pyarraytype(self.dimensions, self.basetype.getpytype()) + + def __str__(self): + return '{}[{}]'.format(str(self.basetype), ']['.join(map(str,self.dimensions))) + + def statictype(self, bindings): + dim_list = list() + for dim in self.dimensions: + if dim is None: + dim_list.append(None) + else: + dim_list.append(_evalexpr(dim, _CppPrimitiveType.get_from_cppname('int'), bindings)) + return _CppArrayType(self.basetype.statictype(bindings), dim_list) + + def _formatdata_array(self, unit_length, data): + read_length = 0 + if _chill_util.python_version_major == 2: + read_data = '' + else: + read_data = bytes() + while read_length < len(data): + for i in range(unit_length): + _, b = self.basetype.formatdata(data[read_length+i]) + read_data += b + read_length += unit_length + return read_data + + def formatdata(self, data): + prod = lambda l: _pyfunctools.reduce(lambda a,v: a*v, l, 1) + if self.dimensions[0] is None: + return self.dimensions, self._formatdata_array(prod(self.dimensions[1:]), data) + else: + return self.dimensions, self._formatdata_array(prod(self.dimensions), data) + + def get_cdecl_stmt(self, param_name): + return '{} {}[{}];'.format(str(self.basetype), param_name, ']['.join(map(str,self.dimensions))) + + def get_cread_stmt(self, param_name, istream_name, dims): + length = _pyfunctools.reduce(lambda a,v: a*v, self.dimensions) + #TODO: use dims + if isinstance(self.basetype, _CppPrimitiveType): + size_expr = '{}*{}'.format(length, self.basetype.size_expr) + return '{}.read((char*){}, {});'.format(istream_name, param_name, size_expr) + else: + raise NotImplementedError + + def get_cwrite_stmt(self, param_name, ostream_name, dims): + length = _pyfunctools.reduce(lambda a,v: a*v, self.dimensions) + #TODO: use dims + if isinstance(self.basetype, _CppPrimitiveType): + size_expr = '{}*{}'.format(length, self.basetype.size_expr) + return '{}.write((char*){}, {});'.format(ostream_name, param_name, size_expr) + else: + raise NotImplementedError + + +class _CppPointerType(_CppType): + def __init__(self, basetype): + _CppType.__init__(self) + self.basetype = basetype + + def getfreevars(self, glbls): + return self.basetype.getfreevars(glbls) + + def getpytype(self): + return self.basetype.getpytype() + + def __str__(self): + return '{}*'.format(str(self.basetype)) + + def statictype(self, bindings): + return _CppPointerType(self.basetype.statictype(bindings)) + + def formatdata(self, data): + if isinstance(data, list): + if _chill_util.python_version_major == 2: + read_data = '' + else: + read_data = bytes() + for data_item in data: + next_dims, b = self.basetype.formatdata(data_item) + read_data += b + return [len(data)] + next_dims, read_data + else: + dims, fmt_data = self.basetype.formatdata(data) + return [1] + dims, fmt_data + + +class _CppReferenceType(_CppType): + def __init__(self, basetype): + _CppType.__init__(self) + self.basetype = basetype + + def getfreevars(self, glbls): + return self.basetype.getfreevars(glbls) + + def getpytype(self): + return self.basetype.getpytype() + + def __str__(self): + return '{}&'.format(str(self.basetype)) + + def statictype(self, bindings): + return _CppReferenceType(self.basetype.statictype(bindings)) + + def formatdata(self, data): + dims, fmt_data = self.basetype.formatdata(data) + return dims, fmt_data + + +class _Parameter(_TreeNode): + def __init__(self, name, cpptype, direction, init_expr=None): + self.name = name + self.direction = direction + self.cpptype = cpptype + self.init_expr = init_expr + self._generated = None + + @staticmethod + def order_by_freevars(param_list, glbls=set()): + defined_names = set() + parameter_names = set(p.name for p in param_list) + param_queue = _pycollections.deque(param_list) + while len(param_queue): + param = param_queue.popleft() + freevars = (parameter_names & param.getfreevars(glbls)) - defined_names + if not len(freevars): + defined_names.add(param.name) + yield param + else: + param_queue.append(param) + + def getfreevars(self, glbls=set()): + freevars = set() + if self.init_expr is not None: + freevars = freevars | self.init_expr.getfreevars(glbls) + freevars = freevars | self.cpptype.getfreevars(glbls) + return freevars + + def generatedata(self, bindings=dict()): + if self._generated is None: + if self.init_expr is None: + py_data = None + else: + py_data = _evalexpr(self.init_expr, self.cpptype, bindings) + static_type = self.cpptype.statictype(bindings) + dims, data = static_type.formatdata(py_data) + self._generated = (self.name, static_type, dims, data) + return self.name, static_type, dims, data + else: + return self._generated + + +class _Procedure(_TreeNode): + def __init__(self, name, rtype, parameters): + self.name = name + self.rtype = rtype + self.parameters = parameters + self.binding_stack = [] + self._bindings = None + self._params_orderd = None + self._invoke_str = '{}({});'.format(self.name, ','.join([p.name for p in parameters])) + + def _order_params(self): + if not self._params_orderd: + self._params_orderd = list(_Parameter.order_by_freevars(self.parameters)) + + def _compute_bindings(self, global_bindings): + local_bindings = dict(global_bindings) + if self._bindings is None: + new_bindings = dict() + for binding_frame in self.binding_stack: + for name, (ctype, expr) in binding_frame.items(): + value = _evalexpr(expr, ctype, local_bindings) + new_bindings[name] = value + local_bindings[name] = value + self._bindings = new_bindings + local_bindings.update(self._bindings) + return local_bindings + + def generatedata(self, direction_list, global_bindings=None): + self._order_params() + if global_bindings is None: + global_bindings = dict() + bindings = self._compute_bindings(global_bindings) + for param in (p for p in self._params_orderd if p.direction in direction_list): + p_name, p_statictype, p_dims, p_data = param.generatedata(bindings) + #TODO: add binding + yield p_name, p_statictype, p_dims, p_data + + def generatedecls(self, bindings): + for p_name, p_statictype, p_dims, p_data in self.generatedata(['in','out','inout'], bindings): + yield p_statictype.get_cdecl_stmt(p_name) + #for p_name, p_statictype, p_dims, p_data in self.generatedata('out', bindings): + # yield p_statictype.get_cdecl_stmt(p_name) + + def generatereads(self, direction_list, stream, bindings): + for p_name, p_statictype, p_dims, p_data in self.generatedata(direction_list, bindings): + yield p_statictype.get_cread_stmt(p_name, stream, p_dims) + + def generatewrites(self, stream, bindings): + for p_name, p_statictype, p_dims, p_data in self.generatedata(['inout', 'out'], bindings): + yield p_statictype.get_cwrite_stmt(p_name, stream, p_dims) + + def getinvokestr(self): + return self._invoke_str + + +class _Expr(_TreeNode): + def __init__(self): + pass + + def getfreevars(self, glbls): + raise NotImplementedError + + def compile_to_lambda(self, glbls, target_type): + args = _pyast.arguments(list(_pyast.Name(n, _pyast.Param()) for n in self.getfreevars(self, glbls)), None, None, []) + expr = _pyast.Expression(_pyast.Lambda(args, self.compile_expr(target_type))) + expr = _pyast.fix_missing_locations(expr) + return eval(compile(expr, '<string>', 'eval')) + + def compile_expr(self, target_type): + raise NotImplementedError + + +class _ConstantExpr(_Expr): + def __init__(self, value): + self.value = value + + def compile_expr(self, target_type): + if target_type is None: + return _pyast.parse(self.value, '<string>', 'eval').body + elif target_type == chr: + return _pyast.Str(chr(self.value)) + elif target_type == int: + return _pyast.Num(int(self.value)) + elif target_type == str: + return _pyast.Str(str(self.value)) + elif target_type == float: + return _pyast.Num(float(self.value)) + + def getfreevars(self, glbls): + return set() + + def __str__(self): + return self.value + + +class _NameExpr(_Expr): + def __init__(self, name): + self.name = name + + def compile_expr(self, target_type): + return _pyast.Name(self.name, _pyast.Load()) + + def getfreevars(self, glbls): + if self.name not in glbls: + return set([self.name]) + else: + return set() + + def __str__(self): + return self.name + + +class _AttributeExpr(_Expr): + def __init__(self, expr, name): + self.expr = expr + self.name = name + + def compile_expr(self, target_type): + return _pyast.Attribute( + self.expr.compile_expr(None), + self.name, + _pyast.Load()) + + def getfreevars(self, glbls): + return self.expr.getfreevars(glbls) + + def __str__(self): + return '{}.{}'.format(str(self.expr), self.name) + + +class _BinExpr(_Expr): + _optypes = { + '+': _pyast.Add, + '-': _pyast.Sub, + '*': _pyast.Mult, + '**': _pyast.Pow, + '/': _pyast.Div + } + def __init__(self, left, op, right): + self.left = left + self.right = right + self.op = op + + def compile_expr(self, target_type): + return _pyast.BinOp( + self.left.compile_expr(target_type), + _BinExpr._optypes[self.op](), + self.right.compile_expr(target_type)) + + def getfreevars(self, glbls): + return self.left.getfreevars(glbls) | self.right.getfreevars(glbls) + + def __str__(self): + return '({}{}{})'.format(str(self.left),self.op,str(self.right)) + + +class _UnaryExpr(_Expr): + _optypes = { + '-': _pyast.USub + } + def __init__(self, op, expr): + self.op = op + self.expr = expr + + def compile_expr(self, target_type): + return _pyast.UnaryOp( + _UnaryExpr._optypes[self.op](), + self.expr.compile_expr(target_type)) + + def getfreevars(self, glbls): + return self.expr.getfreevars(glbls) + + def __str__(self): + return '({}{})'.format(self.op, str(self.expr)) + + +class _LambdaExpr(_Expr): + def __init__(self, params, expr): + self.params = params + self.expr = expr + + def compile_expr(self, target_type): + if target_type is None: + exprtype = None + else: + assert hasattr(target_type, 'paramtypes') + assert hasattr(target_type, 'exprtype') + exprtype = target_type.exprtype + if _chill_util.python_version_major == 2: + return _pyast.Lambda( + _pyast.arguments([_pyast.Name(p, _pyast.Param()) for p in self.params], None, None, []), + self.expr.compile_expr(exprtype)) + else: + return _pyast.Lambda( + _pyast.arguments([_pyast.arg(p, None) for p in self.params], None, None, [], None, None, [], []), + self.expr.compile_expr(exprtype)) + + def getfreevars(self, glbls): + new_glbls = set(glbls) + new_glbls = new_glbls | set(self.params) + return self.expr.getfreevars(new_glbls) + + def __str__(self): + return 'lambda {}:{}'.format(','.join(map(str,self.params)), str(self.expr)) + + +class _InvokeExpr(_Expr): + def __init__(self, func, parameters): + self.func = func + self.parameters = parameters + + def compile_expr(self, target_type): + if target_type is None: + lt = None + else: + lt = _pylambdatype([None for p in self.parameters], target_type) + return _pyast.Call( + self.func.compile_expr(lt), + [p.compile_expr(None) for p in self.parameters], + [], + None, + None) + + def getfreevars(self, glbls): + return set( + self.func.getfreevars(glbls) | + _pyfunctools.reduce(lambda a,v: a | v.getfreevars(glbls), self.parameters, set())) + + def __str__(self): + return '{}({})'.format(str(self.func),','.join(map(str,self.parameters))) + + +class _Generator(_Expr): + def __init__(self): + _Expr.__init__(self) + + +class _MatrixGenerator(_Generator): + def __init__(self, dims, genexpr): + self.dimensions = dims + self.genexpr = genexpr + + def _compile_dims(self, target_type): + if hasattr(target_type, 'dimensions'): + dim_exprs = list() + assert len(target_type.dimensions) == len(self.dimensions) + for i, d in enumerate(target_type.dimensions): + if d is None: + d = self.dimensions[i] + dim_exprs += [d.compile_expr(int)] + else: + dim_exprs = [d.compile_expr(int) for d in self.dimensions] + return _pyast.List(dim_exprs, _pyast.Load()) + + def _lambda_type(self, target_type): + if hasattr(target_type, 'dimensions'): + return _pylambdatype([int for d in target_type.dimensions], target_type.basetype) + else: + return _pylambdatype([int for d in self.dimensions], target_type) + + def compile_expr(self, target_type): + assert target_type is not None + dims = self._compile_dims(target_type) + ltype = self._lambda_type(target_type) + + #def array(func,dims): + # return [func(*d) for d in itertools.product(*(map(range,dims))] + elt_expr = _pyast.Call(self.genexpr.compile_expr(ltype), [], [], _pyast.Name('_d', _pyast.Load()), None) # func(*d) + # elt_expr = _pyast.Call(_pyast.Name('tuple', _pyast.Load()), [_pyast.Name('_d', _pyast.Load()), elt_expr], [], None, None) # tuple(d, func(*d)) + pdt_expr = _pyast.Attribute(_pyast.Name('_pyitertools', _pyast.Load()), 'product', _pyast.Load()) # itertools.product + itr_expr = _pyast.Call(_pyast.Name('map', _pyast.Load()), [_pyast.Name('range', _pyast.Load()), dims], [], None, None) # map(range,dims) + itr_expr = _pyast.Call(pdt_expr, [], [], itr_expr, None) # itertools.product(*(map(range,dims))) + return _pyast.ListComp( + elt_expr, + [_pyast.comprehension(_pyast.Name('_d', _pyast.Store()), itr_expr, [])]) + + def getfreevars(self, glbls): + return set( + self.genexpr.getfreevars(glbls) | + _pyfunctools.reduce(lambda a,v: a | v.getfreevars(glbls), filter(lambda x: x is not None, self.dimensions), set())) + + def __str__(self): + return 'matrix([{}],{})'.format(','.join(map(str,self.dimensions)),str(self.genexpr)) + + +class _RandomExpr(_Expr): + def __init__(self, minexpr, maxexpr): + self.minexpr = minexpr + self.maxexpr = maxexpr + self.expr = _BinExpr( + _BinExpr( + _InvokeExpr(_AttributeExpr(_NameExpr('_pyrandom'),'random'),[]), + '*', + _BinExpr(maxexpr, '-', minexpr)), + '+', + minexpr) + + def getfreevars(self, glbls): + return self.minexpr.getfreevars(glbls) | self.maxexpr.getfreevars(glbls) + + def compile_expr(self, target_type): + if target_type == int: + return _pyast.Call(_pyast.Name('int', _pyast.Load()),[self.expr.compile_expr(float)],[],None,None) + elif target_type == float: + return self.expr.compile_expr(target_type) + elif target_type is None: + return self.expr.compile_expr(None) + assert False + + def __str__(self): + return 'random({},{})'.format(str(self.minexpr),str(self.maxexpr)) + + +### What to import from * ### +addbindings = _addbindings + +CppType = _CppType +CppPrimitiveType = _CppPrimitiveType +CppVoidType = _CppVoidType +CppArrayType = _CppArrayType +CppPointerType = _CppPointerType + +ConstantExpr = _ConstantExpr +NameExpr = _NameExpr +AttributeExpr = _AttributeExpr +BinExpr = _BinExpr +UnaryExpr = _UnaryExpr +LambdaExpr = _LambdaExpr +InvokeExpr = _InvokeExpr +MatrixGenerator = _MatrixGenerator +RandomExpr = _RandomExpr + +Procedure = _Procedure +Parameter = _Parameter + |