def _body_optional_variable(self, tmp_variable, variable, collect_var, check_type=False): """ Responsible for collecting value and managing error and create the body of optional arguments in format if (pyobject == Py_None){ collect Null }else if(Type Check == False){ Print TypeError Wrong Type return Null }else{ assign pyobject value to tmp variable collect the adress of the tmp variable } Parameters: ---------- tmp_variable : Variable The temporary variable to hold result Variable : Variable The optional variable collect_var : variable the pyobject type variable holder of value check_type : Boolean True if the type is needed Returns ------- body : list A list of statements """ body = [(PyccelEq(VariableAddress(collect_var), VariableAddress(Py_None)), [Assign(VariableAddress(variable), Nil())])] if check_type: # Type check check = PyccelNot( PyccelOr(NumpyType_Check(variable, collect_var), PythonType_Check(variable, collect_var))) error = PyErr_SetString( 'PyExc_TypeError', '"{} must be {}"'.format(variable, variable.dtype)) body += [(check, [error, Return([Nil()])])] body += [(LiteralTrue(), [ self._create_collecting_value_body(variable, collect_var, tmp_variable), Assign(VariableAddress(variable), VariableAddress(tmp_variable)) ])] body = [If(*body)] return body
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 _print_AliasAssign(self, expr): lhs = expr.lhs rhs = expr.rhs if isinstance(rhs, Variable): rhs = VariableAddress(rhs) lhs = self._print(lhs.name) rhs = self._print(rhs) return '{} = {};'.format(lhs, rhs)
def _print_Return(self, expr): code = '' args = [ VariableAddress(a) if self.stored_in_c_pointer(a) else a for a in expr.expr ] if expr.stmt: code += self._print(expr.stmt) + '\n' if len(args) == 1: code += 'return {0};'.format(self._print(args[0])) elif len(args) > 1: code += 'return 0;' return code
def _print_FunctionCall(self, expr): func = expr.funcdef # Ensure the correct syntax is used for pointers args = [] for a, f in zip(expr.arguments, func.arguments): if isinstance(a, Variable) and self.stored_in_c_pointer(f): args.append(VariableAddress(a)) elif f.is_optional and not isinstance(a, Nil): tmp_var = self.create_tmp_var(f) assign = Assign(tmp_var, a) self._additional_code += self._print(assign) + '\n' args.append(VariableAddress(tmp_var)) else: args.append(a) args += self._temporary_args self._temporary_args = [] args = ', '.join(['{}'.format(self._print(a)) for a in args]) if not func.results: return '{}({});'.format(func.name, args) return '{}({})'.format(func.name, args)
def _handle_is_operator(self, Op, expr): lhs = self._print(expr.lhs) rhs = self._print(expr.rhs) a = expr.args[0] b = expr.args[1] if Nil() in expr.args: lhs = VariableAddress(expr.lhs) if isinstance( expr.lhs, Variable) else expr.lhs rhs = VariableAddress(expr.rhs) if isinstance( expr.rhs, Variable) else expr.rhs lhs = self._print(lhs) rhs = self._print(rhs) return '{} {} {}'.format(lhs, Op, rhs) if (a.dtype is NativeBool() and b.dtype is NativeBool()): return '{} {} {}'.format(lhs, Op, rhs) else: errors.report(PYCCEL_RESTRICTION_IS_ISNOT, symbol=expr, severity='fatal')
def _get_check_type_statement(self, variable, collect_var): if variable.rank > 0: numpy_dtype = self.find_in_numpy_dtype_registry(variable) check = PyccelEq(FunctionCall(numpy_get_type, [collect_var]), numpy_dtype) else: python_check = PythonType_Check(variable, collect_var) numpy_check = NumpyType_Check(variable, collect_var) if variable.precision == default_precision[str_dtype( variable.dtype)]: check = PyccelOr(python_check, numpy_check) else: check = PyccelAssociativeParenthesis( PyccelAnd(PyccelNot(python_check), numpy_check)) if isinstance(variable, ValuedVariable): default = PyccelNot(VariableAddress( collect_var)) if variable.rank > 0 else PyccelEq( VariableAddress(collect_var), VariableAddress(Py_None)) check = PyccelAssociativeParenthesis(PyccelOr(default, check)) return check
def _print_Assign(self, expr): if isinstance(expr.rhs, FunctionCall) and isinstance( expr.rhs.dtype, NativeTuple): self._temporary_args = [VariableAddress(a) for a in expr.lhs] return '{};'.format(self._print(expr.rhs)) lhs = self._print(expr.lhs) rhs = expr.rhs if isinstance(rhs, (NumpyArray)): if rhs.rank == 0: raise NotImplementedError(expr.lhs + "=" + expr.rhs) dummy_array_name, _ = create_incremented_string( self._parser.used_names, prefix='array_dummy') dtype = self.find_in_dtype_registry(self._print(rhs.dtype), rhs.precision) arg = rhs.arg if rhs.rank > 1: arg = functools.reduce(operator.concat, arg) arg = ', '.join(self._print(i) for i in arg) dummy_array = "%s %s[] = {%s};\n" % (dtype, dummy_array_name, arg) dtype = self.find_in_ndarray_type_registry(format(rhs.dtype), rhs.precision) cpy_data = "memcpy({0}.{2}, {1}, {0}.buffer_size);".format( lhs, dummy_array_name, dtype) return '%s%s\n' % (dummy_array, cpy_data) if isinstance(rhs, (NumpyFull)): code_init = '' if rhs.fill_value is not None: code_init = 'array_fill({0}, {1});'.format( self._print(rhs.fill_value), lhs) else: return '' return '{}\n'.format(code_init) rhs = self._print(rhs) return '{} = {};'.format(lhs, rhs)
def _print_FunctionDef(self, expr): # Save all used names used_names = set([a.name for a in expr.arguments] + [r.name for r in expr.results] + [expr.name.name]) # Find a name for the wrapper function wrapper_name = self._get_wrapper_name(used_names, expr) used_names.add(wrapper_name) # Collect local variables wrapper_vars = {a.name: a for a in expr.arguments} wrapper_vars.update({r.name: r for r in expr.results}) 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 arguments and results wrapper_args = [ python_func_selfarg, python_func_args, python_func_kwargs ] wrapper_results = [self.get_new_PyObject("result", used_names)] if expr.is_private: wrapper_func = FunctionDef( name=wrapper_name, arguments=wrapper_args, results=wrapper_results, body=[ PyErr_SetString( 'PyExc_NotImplementedError', '"Private functions are not accessible from python"'), AliasAssign(wrapper_results[0], Nil()), Return(wrapper_results) ]) return CCodePrinter._print_FunctionDef(self, wrapper_func) if any(isinstance(arg, FunctionAddress) for arg in expr.arguments): wrapper_func = FunctionDef( name=wrapper_name, arguments=wrapper_args, results=wrapper_results, body=[ PyErr_SetString('PyExc_NotImplementedError', '"Cannot pass a function as an argument"'), AliasAssign(wrapper_results[0], Nil()), Return(wrapper_results) ]) return CCodePrinter._print_FunctionDef(self, wrapper_func) # Collect argument names for PyArgParse arg_names = [a.name for a in expr.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 = [] parse_args = [] collect_vars = {} for arg in expr.arguments: collect_var, cast_func = self.get_PyArgParseType(used_names, arg) collect_vars[arg] = collect_var body, tmp_variable = self._body_management(used_names, arg, collect_var, cast_func, True) if tmp_variable: wrapper_vars[tmp_variable.name] = tmp_variable # If the variable cannot be collected from PyArgParse directly wrapper_vars[collect_var.name] = collect_var # Save cast to argument variable wrapper_body_translations.extend(body) parse_args.append(collect_var) # Write default values if isinstance(arg, ValuedVariable): wrapper_body.append( self.get_default_assign(parse_args[-1], arg)) # Parse arguments parse_node = PyArg_ParseTupleNode(python_func_args, python_func_kwargs, expr.arguments, parse_args, keyword_list) wrapper_body.append(If((PyccelNot(parse_node), [Return([Nil()])]))) wrapper_body.extend(wrapper_body_translations) # Call function static_function, static_args, additional_body = self._get_static_function( used_names, expr, collect_vars) wrapper_body.extend(additional_body) for var in static_args: wrapper_vars[var.name] = var if len(expr.results) == 0: func_call = FunctionCall(static_function, static_args) else: results = expr.results if len( expr.results) > 1 else expr.results[0] func_call = Assign(results, FunctionCall(static_function, static_args)) wrapper_body.append(func_call) # Loop over results to carry out necessary casts and collect Py_BuildValue type string res_args = [] for a in expr.results: collect_var, cast_func = self.get_PyBuildValue(used_names, a) if cast_func is not None: wrapper_vars[collect_var.name] = collect_var wrapper_body.append(AliasAssign(collect_var, cast_func)) res_args.append( VariableAddress(collect_var) if collect_var. is_pointer else collect_var) # Call PyBuildNode wrapper_body.append( AliasAssign(wrapper_results[0], PyBuildValueNode(res_args))) # Call free function for python type wrapper_body += [ FunctionCall(Py_DECREF, [i]) for i in self._to_free_PyObject_list ] self._to_free_PyObject_list.clear() #Return wrapper_body.append(Return(wrapper_results)) # Create FunctionDef and write using classic method wrapper_func = FunctionDef(name=wrapper_name, arguments=wrapper_args, results=wrapper_results, body=wrapper_body, local_vars=wrapper_vars.values()) return CCodePrinter._print_FunctionDef(self, wrapper_func)
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 _body_array(self, variable, collect_var, check_type=False): """ Responsible for collecting value and managing error and create the body of arguments with rank greater than 0 in format if (rank check == False){ print TypeError Wrong rank return Null }else if(Type Check == False){ Print TypeError Wrong type return Null }else if (order check == False){ #check for order for rank > 1 Print NotImplementedError Wrong Order return Null } collect the value from PyArrayObject Parameters: ---------- Variable : Variable The optional variable collect_var : variable the pyobject type variable holder of value check_type : Boolean True if the type is needed Returns ------- body : list A list of statements """ body = [] #TODO create and extern rank and order check function #check optional : if variable.is_optional: check = PyccelNot(VariableAddress(collect_var)) body += [(check, [Assign(VariableAddress(variable), Nil())])] #rank check : check = PyccelNe(FunctionCall(numpy_get_ndims, [collect_var]), LiteralInteger(collect_var.rank)) error = PyErr_SetString( 'PyExc_TypeError', '"{} must have rank {}"'.format(collect_var, str(collect_var.rank))) body += [(check, [error, Return([Nil()])])] if check_type: #Type check numpy_dtype = self.find_in_numpy_dtype_registry(variable) arg_dtype = self.find_in_dtype_registry( self._print(variable.dtype), variable.precision) check = PyccelNe(FunctionCall(numpy_get_type, [collect_var]), numpy_dtype) info_dump = PythonPrint( [FunctionCall(numpy_get_type, [collect_var]), numpy_dtype]) error = PyErr_SetString( 'PyExc_TypeError', '"{} must be {}"'.format(variable, arg_dtype)) body += [(check, [info_dump, error, Return([Nil()])])] if collect_var.rank > 1 and self._target_language == 'fortran': #Order check if collect_var.order == 'F': check = FunctionCall(numpy_check_flag, [collect_var, numpy_flag_f_contig]) else: check = FunctionCall(numpy_check_flag, [collect_var, numpy_flag_c_contig]) error = PyErr_SetString( 'PyExc_NotImplementedError', '"Argument does not have the expected ordering ({})"'. format(collect_var.order)) body += [(PyccelNot(check), [error, Return([Nil()])])] body += [(LiteralTrue(), [ Assign(VariableAddress(variable), self.get_collect_function_call(variable, collect_var)) ])] body = [If(*body)] return body