def new_variable(dtype, var, tag=None, prefix=None, kind=None): # ... if prefix is None: prefix = '' _prefix = '{}'.format(prefix) # ... # ... if dtype == 'int': if kind == 'len': _prefix = 'n{}'.format(_prefix) elif kind == 'multi': _prefix = 'im{}'.format(_prefix) else: _prefix = 'i{}'.format(_prefix) elif dtype == 'real': _prefix = 'r{}'.format(_prefix) else: raise NotImplementedError() # ... # ... if tag is None: tag = random_string(4) # ... pattern = '{prefix}{dim}_{tag}' _print = lambda d, t: pattern.format(prefix=_prefix, dim=d, tag=t) if isinstance(var, Variable): assert (var.rank > 0) if var.rank == 1: name = _print('', tag) return Variable(dtype, name) else: indices = [] for d in range(0, var.rank): name = _print(d, tag) indices.append(Variable(dtype, name)) return Tuple(*indices) elif isinstance(var, (list, tuple, Tuple)): ls = [ new_variable(dtype, x, tag=tag, prefix=str(i), kind=kind) for i, x in enumerate(var) ] return Tuple(*ls) else: raise NotImplementedError('{} not available'.format(type(var)))
def get_PyArgParseType(self, used_names, variable): """ Responsible for creating any necessary intermediate variables which are used to collect the result of PyArgParse, and collecting the required cast function Parameters: ---------- used_names : list of strings List of variable and function names to avoid name collisions variable : Variable The variable which will be passed to the translated function Returns ------- collect_var : Variable The variable which will be used to collect the argument cast_fun : FunctionCall call to cast function responsible of the conversion of one data type into another """ cast_function = None collect_var = variable if variable.rank > 0: collect_type = PyccelPyArrayObject() collect_var = Variable(dtype=collect_type, is_pointer=True, rank=variable.rank, order=variable.order, name=self.get_new_name( used_names, variable.name + "_tmp")) elif isinstance(variable, ValuedVariable): collect_type = PyccelPyObject() collect_var = Variable(dtype=collect_type, is_pointer=True, name=self.get_new_name( used_names, variable.name + "_tmp")) elif variable.dtype is NativeBool(): collect_type = NativeInteger() collect_var = Variable(dtype=collect_type, precision=4, name=self.get_new_name( used_names, variable.name + "_tmp")) cast_function = self.get_cast_function_call( 'pyint_to_bool', collect_var) elif variable.dtype is NativeComplex(): collect_type = PyccelPyObject() collect_var = Variable(dtype=collect_type, is_pointer=True, name=self.get_new_name( used_names, variable.name + "_tmp")) return collect_var, cast_function
def _get_static_function(self, used_names, function, collect_dict): """ Create arguments and functioncall for arguments rank > 0 in fortran. Format : a is numpy array func(a) ==> static_func(a.DIM , a.DATA) where a.DATA = buffer holding data a.DIM = size of array """ additional_body = [] if self._target_language == 'fortran': static_args = [] for a in function.arguments: if isinstance(a, Variable) and a.rank > 0: # Add shape arguments for static function for i in range(collect_dict[a].rank): var = Variable(dtype=NativeInteger(), name=self.get_new_name( used_names, a.name + "_dim")) body = FunctionCall(numpy_get_dim, [collect_dict[a], i]) if a.is_optional: body = IfTernaryOperator( VariableAddress(collect_dict[a]), body, LiteralInteger(0)) body = Assign(var, body) additional_body.append(body) static_args.append(var) static_args.append(a) static_function = as_static_function_call(function, self._module_name, name=function.name) else: static_function = function static_args = function.arguments return static_function, static_args, additional_body
def _body_management(self, used_names, variable, collect_var, cast_function, check_type=False): """ Responsible for calling functions that take care of body creation """ tmp_variable = None body = [] if variable.rank > 0: body = self._body_array(variable, collect_var, check_type) elif variable.is_optional: tmp_variable = Variable(dtype=variable.dtype, name=self.get_new_name( used_names, variable.name + "_tmp")) body = self._body_optional_variable(tmp_variable, variable, collect_var, check_type) elif isinstance(variable, ValuedVariable): body = self._body_valued_variable(variable, collect_var, check_type) elif isinstance(collect_var.dtype, PyccelPyObject): body = [self._create_collecting_value_body(variable, collect_var)] elif cast_function is not None: body = [Assign(variable, cast_function)] return body, tmp_variable
def get_PyBuildValue(self, used_names, variable): """ Responsible for collecting the variable required to build the result and the necessary cast function Parameters: ---------- used_names : list of strings List of variable and function names to avoid name collisions variable : Variable The variable returned by the translated function Returns ------- collect_var : Variable The variable which will be provided to PyBuild cast_func_stmts : functionCall call to cast function responsible of the conversion of one data type into another """ collect_var = variable cast_function = None if variable.dtype is NativeBool(): collect_type = PyccelPyObject() collect_var = Variable(dtype=collect_type, is_pointer=True, name=self.get_new_name( used_names, variable.name + "_tmp")) cast_function = self.get_cast_function_call( 'bool_to_pyobj', variable) if variable.dtype is NativeComplex(): collect_type = PyccelPyObject() collect_var = Variable(dtype=collect_type, is_pointer=True, name=self.get_new_name( used_names, variable.name + "_tmp")) cast_function = self.get_cast_function_call( 'complex_to_pycomplex', variable) self._to_free_PyObject_list.append(collect_var) return collect_var, cast_function
def _visit_TypeVariable(self, stmt): t_var = stmt d_var = _attributs_default() d_var = _attributs_from_type(t_var, d_var) dtype = d_var.pop('dtype') name = 'dummy_{}'.format(stmt.tag) var = Variable(dtype, name, **d_var) return var
def _visit_TypeList(self, stmt): t_var = stmt rank = len(stmt) var = self._visit(stmt.types) if isinstance(var, Tuple): ls = [] for e, v in enumerate(var): d_var = _attributs_default() d_var = _attributs_from_type(v, d_var) d_var['rank'] += rank dtype = d_var.pop('dtype') name = 'dummy_{}_{}'.format(e, stmt.tag) var = Variable(dtype, name, **d_var) ls.append(var) return Tuple(*ls) elif isinstance(var, Variable): d_var = _attributs_default() d_var = _attributs_from_type(var, d_var) d_var['rank'] += rank dtype = d_var.pop('dtype') name = 'dummy_{}'.format(stmt.tag) var = Variable(dtype, name, **d_var) return var else: msg = 'Expecting a Tuple or Variable, but {} was given' msg = msg.format(type(var)) raise TypeError(msg)
def _visit_TypeTuple(self, stmt): ls = [] for e, t_var in enumerate(stmt.types): d_var = _attributs_default() d_var = _attributs_from_type(t_var, d_var) dtype = d_var.pop('dtype') name = 'dummy_{}_{}'.format(e, stmt.tag) var = Variable(dtype, name, **d_var) ls.append(var) var = Tuple(*ls) if len(var) == 1: return var[0] else: return var
def sanitize_arguments(args): _args = [] for a in args: if isinstance(a, (Variable, FunctionAddress)): _args.append(a) elif isinstance(a, IndexedVariable): a_new = Variable(a.dtype, str(a.name), shape=a.shape, rank=a.rank, order=a.order, precision=a.precision) _args.append(a_new) else: raise NotImplementedError('TODO for {}'.format(type(a))) return _args
def create_tmp_var(self, match_var): tmp_var_name = self._parser.get_new_name('tmp') tmp_var = Variable(name=tmp_var_name, dtype=match_var.dtype) self._additional_declare.append(tmp_var) return tmp_var
def _print_Interface(self, expr): # Collecting all functions funcs = expr.functions # Save all used names used_names = set(n.name for n in funcs) # Find a name for the wrapper function wrapper_name = self._get_wrapper_name(used_names, expr) self._global_names.add(wrapper_name) # Collect local variables python_func_args = self.get_new_PyObject("args", used_names) python_func_kwargs = self.get_new_PyObject("kwargs", used_names) python_func_selfarg = self.get_new_PyObject("self", used_names) # Collect wrapper arguments and results wrapper_args = [ python_func_selfarg, python_func_args, python_func_kwargs ] wrapper_results = [self.get_new_PyObject("result", used_names)] # Collect parser arguments wrapper_vars = {} # Collect argument names for PyArgParse arg_names = [a.name for a in funcs[0].arguments] keyword_list_name = self.get_new_name(used_names, 'kwlist') keyword_list = PyArgKeywords(keyword_list_name, arg_names) wrapper_body = [keyword_list] wrapper_body_translations = [] body_tmp = [] # To store the mini function responsible of collecting value and calling interfaces functions and return the builded value funcs_def = [] default_value = { } # dict to collect all initialisation needed in the wrapper check_var = Variable(dtype=NativeInteger(), name=self.get_new_name(used_names, "check")) wrapper_vars[check_var.name] = check_var types_dict = OrderedDict( (a, set()) for a in funcs[0].arguments ) #dict to collect each variable possible type and the corresponding flags # collect parse arg parse_args = [ Variable(dtype=PyccelPyArrayObject(), is_pointer=True, rank=a.rank, order=a.order, name=self.get_new_name(used_names, a.name + "_tmp")) if a.rank > 0 else Variable(dtype=PyccelPyObject(), name=self.get_new_name(used_names, a.name + "_tmp"), is_pointer=True) for a in funcs[0].arguments ] # Managing the body of wrapper for func in funcs: mini_wrapper_func_body = [] res_args = [] mini_wrapper_func_vars = {a.name: a for a in func.arguments} flags = 0 collect_vars = {} # Loop for all args in every functions and create the corresponding condition and body for p_arg, f_arg in zip(parse_args, func.arguments): collect_vars[f_arg] = p_arg body, tmp_variable = self._body_management( used_names, f_arg, p_arg, None) if tmp_variable: mini_wrapper_func_vars[tmp_variable.name] = tmp_variable # get check type function check = self._get_check_type_statement(f_arg, p_arg) # If the variable cannot be collected from PyArgParse directly wrapper_vars[p_arg.name] = p_arg # Save the body wrapper_body_translations.extend(body) # Write default values if isinstance(f_arg, ValuedVariable): wrapper_body.append( self.get_default_assign(parse_args[-1], f_arg)) flag_value = flags_registry[(f_arg.dtype, f_arg.precision)] flags = (flags << 4) + flag_value # shift by 4 to the left types_dict[f_arg].add( (f_arg, check, flag_value)) # collect variable type for each arguments mini_wrapper_func_body += body # create the corresponding function call static_function, static_args, additional_body = self._get_static_function( used_names, func, collect_vars) mini_wrapper_func_body.extend(additional_body) for var in static_args: mini_wrapper_func_vars[var.name] = var if len(func.results) == 0: func_call = FunctionCall(static_function, static_args) else: results = func.results if len( func.results) > 1 else func.results[0] func_call = Assign(results, FunctionCall(static_function, static_args)) mini_wrapper_func_body.append(func_call) # Loop for all res in every functions and create the corresponding body and cast for r in func.results: collect_var, cast_func = self.get_PyBuildValue(used_names, r) mini_wrapper_func_vars[collect_var.name] = collect_var if cast_func is not None: mini_wrapper_func_vars[r.name] = r mini_wrapper_func_body.append( AliasAssign(collect_var, cast_func)) res_args.append( VariableAddress(collect_var) if collect_var. is_pointer else collect_var) # Building PybuildValue and freeing the allocated variable after. mini_wrapper_func_body.append( AliasAssign(wrapper_results[0], PyBuildValueNode(res_args))) mini_wrapper_func_body += [ FunctionCall(Py_DECREF, [i]) for i in self._to_free_PyObject_list ] mini_wrapper_func_body.append(Return(wrapper_results)) self._to_free_PyObject_list.clear() # Building Mini wrapper function mini_wrapper_func_name = self.get_new_name( used_names.union(self._global_names), func.name.name + '_mini_wrapper') self._global_names.add(mini_wrapper_func_name) mini_wrapper_func_def = FunctionDef( name=mini_wrapper_func_name, arguments=parse_args, results=wrapper_results, body=mini_wrapper_func_body, local_vars=mini_wrapper_func_vars.values()) funcs_def.append(mini_wrapper_func_def) # append check condition to the functioncall body_tmp.append((PyccelEq(check_var, LiteralInteger(flags)), [ AliasAssign(wrapper_results[0], FunctionCall(mini_wrapper_func_def, parse_args)) ])) # Errors / Types management # Creating check_type function check_func_def = self._create_wrapper_check(check_var, parse_args, types_dict, used_names, funcs[0].name.name) funcs_def.append(check_func_def) # Create the wrapper body with collected informations body_tmp = [((PyccelNot(check_var), [Return([Nil()])]))] + body_tmp body_tmp.append((LiteralTrue(), [ PyErr_SetString('PyExc_TypeError', '"Arguments combinations don\'t exist"'), Return([Nil()]) ])) wrapper_body_translations = [If(*body_tmp)] # Parsing Arguments parse_node = PyArg_ParseTupleNode(python_func_args, python_func_kwargs, funcs[0].arguments, parse_args, keyword_list, True) wrapper_body += list(default_value.values()) wrapper_body.append(If((PyccelNot(parse_node), [Return([Nil()])]))) #finishing the wrapper body wrapper_body.append( Assign(check_var, FunctionCall(check_func_def, parse_args))) wrapper_body.extend(wrapper_body_translations) wrapper_body.append(Return(wrapper_results)) # Return # Create FunctionDef funcs_def.append( FunctionDef(name=wrapper_name, arguments=wrapper_args, results=wrapper_results, body=wrapper_body, local_vars=wrapper_vars.values())) sep = self._print(SeparatorComment(40)) return sep + '\n'.join( CCodePrinter._print_FunctionDef(self, f) for f in funcs_def)
def as_static_function(func): assert (isinstance(func, FunctionDef)) args = func.arguments results = func.results body = func.body arguments_inout = func.arguments_inout functions = func.functions _results = [] if results: if len(results) == 1: result = results[0] if result.rank > 0: # updates args args = list(args) + [result] arguments_inout += [False] else: _results = results else: raise NotImplementedError('when len(results) > 1') name = 'f2py_{}'.format(func.name).lower() # ... results_names = [i.name for i in results] _args = [] _arguments_inout = [] for i_a, a in enumerate(args): if not isinstance(a, Variable): raise TypeError('Expecting a Variable type for {}'.format(a)) rank = a.rank if rank > 0: # ... additional_args = [] for i in range(0, rank): n_name = 'n{i}_{name}'.format(name=str(a.name), i=i) n_arg = Variable('int', n_name) additional_args += [n_arg] shape_new = Tuple(*additional_args, sympify=False) # ... _args += additional_args for j in additional_args: _arguments_inout += [False] a_new = Variable(a.dtype, a.name, allocatable=a.allocatable, is_pointer=a.is_pointer, is_target=a.is_target, is_optional=a.is_optional, shape=shape_new, rank=a.rank, order=a.order, precision=a.precision) if not (a.name in results_names): _args += [a_new] else: _results += [a_new] else: _args += [a] intent = arguments_inout[i_a] _arguments_inout += [intent] args = _args results = _results arguments_inout = _arguments_inout # ... return FunctionDef(name, list(args), results, body, local_vars=func.local_vars, is_static=True, arguments_inout=arguments_inout, functions=functions)
def __init__(self, expr, **kwargs): assert (isinstance(expr, Lambda)) self._expr = LampyLambda(expr) # ... self._d_types = {} self._d_domain_types = { } # for each codomain we store its associated domain type self._d_expr = {} self._tag = random_string(8) # TODO to be removed later? self._d_functions = {} # to store current typed expr # this must not be a private variable, # in order to modify it on the fly self.main = self.expr self.main_type = None # ... # ... add types for arguments and results # TODO use domain and codomain optional args for functions self._typed_functions = kwargs.pop('typed_functions', {}) for f in self.typed_functions.values(): type_domain = assign_type(f.arguments) type_codomain = assign_type(f.results) self._set_type(f, value=type_domain, domain=True) self._set_type(f, value=type_codomain, codomain=True) self._set_domain_type(type_domain, type_codomain) self._insert_function(f, type_domain, type_codomain) # ... # ... default Type prefix = kwargs.pop('prefix', 'd') # doubles as default dtype = None precision = None if prefix == 'i': dtype = Int precision = 4 elif prefix == 's': dtype = Real precision = 4 elif prefix == 'd': dtype = Real precision = 8 elif prefix == 'c': dtype = Complex precision = 8 elif prefix == 'z': dtype = Complex precision = 16 else: raise ValueError('Wrong prefix. Available: i, s, d, c, z') var = Variable(dtype, 'dummy_' + self.tag, precision=precision) self._default_type = TypeVariable(var) # ... # ... get all functions functions = list(expr.atoms(FunctionSymbol)) for f in functions: if f.name in _elemental_math_functions: type_domain = self.default_type type_codomain = self.default_type self._set_type(f, value=type_domain, domain=True) self._set_type(f, value=type_codomain, codomain=True) self._set_domain_type(type_domain, type_codomain) self._insert_function(str(f), type_domain, type_codomain) elif not str(f) in list(_internal_applications) + list( self.typed_functions.keys()): raise NotImplementedError('{} not available'.format(str(f)))
def get_new_PyObject(self, name, used_names): return Variable(dtype=PyccelPyObject(), name=self.get_new_name(used_names, name), is_pointer=True)
def as_static_function(func, name=None): assert(isinstance(func, FunctionDef)) args = list(func.arguments) results = list(func.results) body = func.body arguments_inout = func.arguments_inout functions = func.functions _results = [] interfaces = func.interfaces # Convert array results to inout arguments for r in results: if r.rank > 0 and r not in args: args += [r] arguments_inout += [False] elif r.rank == 0: _results += [r] if name is None: name = 'bind_c_{}'.format(func.name).lower() # ... results_names = [i.name for i in _results] _args = [] _arguments_inout = [] for i_a, a in enumerate(args): if not isinstance(a, (Variable, FunctionAddress)): raise TypeError('Expecting a Variable or FunctionAddress type for {}'.format(a)) if not isinstance(a, FunctionAddress) and a.rank > 0: # ... additional_args = [] for i in range(a.rank): n_name = 'n{i}_{name}'.format(name=str(a.name), i=i) n_arg = Variable('int', n_name, precision=4) additional_args += [n_arg] shape_new = Tuple(*additional_args, sympify=False) # ... _args += additional_args _arguments_inout += [False] * len(additional_args) a_new = Variable( a.dtype, a.name, allocatable = a.allocatable, is_pointer = a.is_pointer, is_target = a.is_target, is_optional = a.is_optional, shape = shape_new, rank = a.rank, order = a.order, precision = a.precision) if not( a.name in results_names ): _args += [a_new] else: _results += [a_new] else: _args += [a] intent = arguments_inout[i_a] _arguments_inout += [intent] args = _args results = _results arguments_inout = _arguments_inout # ... return BindCFunctionDef( name, list(args), results, body, local_vars = func.local_vars, is_static = True, arguments_inout = arguments_inout, functions = functions, interfaces = interfaces, imports = func.imports, original_function = func, doc_string = func.doc_string, )
def expr(self): name = str(self.name) dtype = _construct_dtype(self.dtype) # TODO must return a TypedFunction return Variable(dtype, name)
def expr(self): name = str(self.name) dtype = datatype(str(self.dtype)) return Variable(dtype, name)