def _create_wrapper_check(self, check_var, parse_args, types_dict, used_names, func_name): check_func_body = [] flags = (len(types_dict) - 1) * 4 for arg in types_dict: var_name = "" body = [] types = [] arg_type_check_list = list(types_dict[arg]) arg_type_check_list.sort(key= lambda x : x[0].precision) for elem in arg_type_check_list: var_name = elem[0].name value = elem[2] << flags body.append((elem[1], [AugAssign(check_var, '+' ,value)])) types.append(elem[0]) flags -= 4 error = ' or '.join(['{} bit {}'.format(v.precision * 8 , str_dtype(v.dtype)) if not isinstance(v.dtype, NativeBool) else str_dtype(v.dtype) for v in types]) body.append((LiteralTrue(), [PyErr_SetString('PyExc_TypeError', '"{} must be {}"'.format(var_name, error)), Return([LiteralInteger(0)])])) check_func_body += [If(*body)] check_func_body = [Assign(check_var, LiteralInteger(0))] + check_func_body check_func_body.append(Return([check_var])) # Creating check function definition check_func_name = self.get_new_name(used_names.union(self._global_names), 'type_check') self._global_names.add(check_func_name) check_func_def = FunctionDef(name = check_func_name, arguments = parse_args, results = [check_var], body = check_func_body, local_vars = []) return check_func_def
def _visit_Constant(self, stmt): # New in python3.8 this class contains NameConstant, Num, and String types if stmt.value is None: return Nil() elif stmt.value is True: return LiteralTrue() elif stmt.value is False: return LiteralFalse() elif isinstance(stmt.value, int): return LiteralInteger(stmt.value) elif isinstance(stmt.value, float): return LiteralFloat(stmt.value) elif isinstance(stmt.value, complex): return LiteralComplex(LiteralFloat(stmt.value.real), LiteralFloat(stmt.value.imag)) elif isinstance(stmt.value, str): return self._visit_Str(stmt) else: raise NotImplementedError('Constant type {} not recognised'.format( type(stmt.value)))
def _create_collecting_value_body(self, variable, collect_var, tmp_variable = None): """ Create If block to differentiate between python and numpy data types when collecting value format : if (collect_var is numpy_scalar) collect_value from numpy type else collect value from python type Parameters: ---------- variable: variable the variable needed to collect collect_var : variable the pyobject variable tmp_variable : variable temporary variable to hold value default None Returns ------- body : If block """ var = tmp_variable if tmp_variable else variable python_type_collect_func_call = self.get_collect_function_call(variable, collect_var) numpy_type_collect_func_call = FunctionCall(PyArray_ScalarAsCtype, [collect_var, var]) check_scalar_type = FunctionCall(PyArray_CheckScalar, [collect_var]) body = If((check_scalar_type, [numpy_type_collect_func_call]), (LiteralTrue() , [Assign(var, python_type_collect_func_call)])) return body
def _visit_If(self, stmt): test = self._visit(stmt.test) body = self._visit(stmt.body) orelse = self._visit(stmt.orelse) if len(orelse) == 1 and isinstance(orelse[0], If): orelse = orelse[0]._args return If(Tuple(test, body, sympify=False), *orelse) else: orelse = Tuple(LiteralTrue(), orelse, sympify=False) return If(Tuple(test, body, sympify=False), orelse)
def _visit_NameConstant(self, stmt): if stmt.value is None: return Nil() elif stmt.value is True: return LiteralTrue() elif stmt.value is False: return LiteralFalse() else: raise NotImplementedError("Unknown NameConstant : {}".format(stmt.value))
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 _print_If(self, expr): lines = [] for i, (c, e) in enumerate(expr.args): var = self._print(e) if (var == ''): break if i == 0: lines.append("if (%s)\n{" % self._print(c)) elif i == len(expr.args) - 1 and c is LiteralTrue(): lines.append("else\n{") else: lines.append("else if (%s)\n{" % self._print(c)) lines.append("%s\n}" % var) return "\n".join(lines)
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