Ejemplo n.º 1
0
 def __init__(self, parser, target_language, settings=None):
     CCodePrinter.__init__(self, parser, settings)
     self._target_language = target_language
     self._cast_functions_dict = OrderedDict()
     self._to_free_PyObject_list = []
     self._function_wrapper_names = dict()
     self._global_names = set()
     self._module_name = None
Ejemplo n.º 2
0
 def function_signature(self, expr):
     args = list(expr.arguments)
     if any([isinstance(a, FunctionAddress) for a in args]):
         # Functions with function addresses as arguments cannot be
         # exposed to python so there is no need to print their signature
         return ''
     else:
         return CCodePrinter.function_signature(self, expr)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
 def stored_in_c_pointer(self, a):
     stored_in_c = CCodePrinter.stored_in_c_pointer(self, a)
     if self._target_language == 'fortran':
         return stored_in_c or (isinstance(a, Variable) and a.rank > 0)
     else:
         return stored_in_c
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    def _print_Module(self, expr):
        self._global_names = set(f.name.name for f in expr.funcs)
        self._module_name = expr.name
        sep = self._print(SeparatorComment(40))
        if self._target_language == 'fortran':
            static_funcs = [
                as_static_function_call(f, expr.name, name=f.name)
                for f in expr.funcs
            ]
        else:
            static_funcs = expr.funcs
        function_signatures = '\n'.join(
            '{};'.format(self.function_signature(f)) for f in static_funcs)

        interfaces = expr.interfaces
        interface_funcs = [f.name for i in interfaces for f in i.functions]
        funcs = interfaces + [
            f for f in expr.funcs if f.name not in interface_funcs
        ]

        function_defs = '\n\n'.join(self._print(f) for f in funcs)
        cast_functions = '\n\n'.join(
            CCodePrinter._print_FunctionDef(self, f)
            for f in self._cast_functions_dict.values())
        method_def_func = ',\n'.join(('{{\n'
                                     '"{name}",\n'
                                     '(PyCFunction){wrapper_name},\n'
                                     'METH_VARARGS | METH_KEYWORDS,\n'
                                     '{doc_string}\n'
                                     '}}').format(
                                            name = f.name,
                                            wrapper_name = self._function_wrapper_names[f.name],
                                            doc_string = self._print(LiteralString('\n'.join(f.doc_string.comments))) \
                                                        if f.doc_string else '""')
                                     for f in funcs)

        method_def_name = self.get_new_name(self._global_names,
                                            '{}_methods'.format(expr.name))
        method_def = ('static PyMethodDef {method_def_name}[] = {{\n'
                      '{method_def_func},\n'
                      '{{ NULL, NULL, 0, NULL}}\n'
                      '}};'.format(method_def_name=method_def_name,
                                   method_def_func=method_def_func))

        module_def_name = self.get_new_name(self._global_names,
                                            '{}_module'.format(expr.name))
        module_def = (
            'static struct PyModuleDef {module_def_name} = {{\n'
            'PyModuleDef_HEAD_INIT,\n'
            '/* name of module */\n'
            '\"{mod_name}\",\n'
            '/* module documentation, may be NULL */\n'
            'NULL,\n'  #TODO: Add documentation
            '/* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */\n'
            '-1,\n'
            '{method_def_name}\n'
            '}};'.format(module_def_name=module_def_name,
                         mod_name=expr.name,
                         method_def_name=method_def_name))

        init_func = ('PyMODINIT_FUNC PyInit_{mod_name}(void)\n{{\n'
                     'PyObject *m;\n\n'
                     'import_array();\n\n'
                     'm = PyModule_Create(&{module_def_name});\n'
                     'if (m == NULL) return NULL;\n\n'
                     'return m;\n}}'.format(mod_name=expr.name,
                                            module_def_name=module_def_name))

        # Print imports last to be sure that all additional_imports have been collected
        imports = [Import(s) for s in self._additional_imports]
        imports += [Import('Python')]
        imports += [Import('numpy/arrayobject')]
        imports = '\n'.join(self._print(i) for i in imports)

        numpy_max_acceptable_version = [1, 19]
        numpy_current_version = [
            int(v) for v in np.version.version.split('.')[:2]
        ]
        numpy_api_macro = '#define NPY_NO_DEPRECATED_API NPY_{}_{}_API_VERSION'.format(
            min(numpy_max_acceptable_version[0], numpy_current_version[0]),
            min(numpy_max_acceptable_version[1], numpy_current_version[1]))

        return ('#define PY_SSIZE_T_CLEAN\n'
                '{numpy_api_macro}\n'
                '{imports}\n\n'
                '{function_signatures}\n\n'
                '{sep}\n\n'
                '{cast_functions}\n\n'
                '{sep}\n\n'
                '{function_defs}\n\n'
                '{method_def}\n\n'
                '{sep}\n\n'
                '{module_def}\n\n'
                '{sep}\n\n'
                '{init_func}\n'.format(numpy_api_macro=numpy_api_macro,
                                       imports=imports,
                                       function_signatures=function_signatures,
                                       sep=sep,
                                       cast_functions=cast_functions,
                                       function_defs=function_defs,
                                       method_def=method_def,
                                       module_def=module_def,
                                       init_func=init_func))
Ejemplo n.º 7
0
 def find_in_dtype_registry(self, dtype, prec):
     try:
         return dtype_registry[(dtype, prec)]
     except KeyError:
         return CCodePrinter.find_in_dtype_registry(self, dtype, prec)