Exemple #1
0
    def get_collect_function_call(self, variable, collect_var):
        """
        Represents a call to cast function responsible of collecting value from python object.

        Parameters:
        ----------
        variable: variable
            the variable needed to collect
        collect_var :
            the pyobject variable
        """
        if variable.rank > 0:
            return FunctionCall(numpy_get_data, [collect_var])
        if isinstance(variable.dtype, NativeComplex):
            return self.get_cast_function_call('pycomplex_to_complex',
                                               collect_var)

        if isinstance(variable.dtype, NativeBool):
            return self.get_cast_function_call('pybool_to_bool', collect_var)
        try:
            collect_function = collect_function_registry[variable.dtype]
        except KeyError:
            errors.report(PYCCEL_RESTRICTION_TODO,
                          symbol=variable.dtype,
                          severity='fatal')
        return FunctionCall(collect_function, [collect_var])
Exemple #2
0
    def _visit_Call(self, stmt):

        args = []
        if stmt.args:
            args += self._visit(stmt.args)
        if stmt.keywords:
            args += self._visit(stmt.keywords)

        if len(args) == 0:
            args = ()

        func = self._visit(stmt.func)

        if isinstance(func, Symbol):
            f_name = str(func.name)
            if f_name == "print":
                func = PythonPrint(PythonTuple(*args))
            else:
                func = FunctionCall(f_name, args)
        elif isinstance(func, DottedName):
            f_name = str(func.name[-1])
            func_attr = FunctionCall(f_name, args)
            func = DottedName(*func.name[:-1], func_attr)
        else:
            raise NotImplementedError(' Unknown function type {}'.format(
                str(type(func))))

        return func
Exemple #3
0
    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
Exemple #4
0
    def get_cast_function_call(self, cast_type, arg):
        """
        Represents a call to cast function responsible of the conversion of one data type into another.

        Parameters:
        ----------
        cast_type: string
            The type of cast function on format 'data type_to_data type'
        arg: variable
            the variable needed to cast
        """

        if cast_type in self._cast_functions_dict:
            cast_function = self._cast_functions_dict[cast_type]

        else:
            cast_function_name = self.get_new_name(self._global_names,
                                                   cast_type)

            try:
                cast_function = cast_function_registry[cast_type](
                    cast_function_name)
            except KeyError as e:
                raise NotImplementedError(
                    "No conversion function : {}".format(cast_type)) from e

            self._cast_functions_dict[cast_type] = cast_function

        return FunctionCall(cast_function, [arg])
Exemple #5
0
 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
Exemple #6
0
def as_static_function_call(func, mod_name, name=None):

    assert isinstance(func, FunctionDef)
    assert isinstance(mod_name, str)

    # create function alias by prepending 'mod_' to its name
    func_alias = func.clone('mod_' + str(func.name))

    # from module import func as func_alias
    imports = [Import(target=AsName(func.name, func_alias.name), source=mod_name)]

    # function arguments
    args = sanitize_arguments(func.arguments)
    # function body
    call    = FunctionCall(func_alias, args)
    results = func.results
    results = results[0] if len(results) == 1 else results
    stmt    = call if len(func.results) == 0 else Assign(results, call)
    body    = [stmt]

    # new function declaration
    new_func = FunctionDef(func.name, list(args), func.results, body,
                       arguments_inout = func.arguments_inout,
                       functions = func.functions,
                       interfaces = func.interfaces,
                       imports = imports,
                       doc_string = func.doc_string,
                       )

    # make it compatible with c
    static_func = as_static_function(new_func, name)

    return static_func
Exemple #7
0
    def _visit_GeneratorExp(self, stmt):

        result = self._visit(stmt.elt)

        generators = self._visit(stmt.generators)
        parent = self._scope[-3]
        if not isinstance(parent, ast.Call):
            raise NotImplementedError(
                "GeneratorExp is not the argument of a function call")

        name = str(self._visit(parent.func))

        grandparent = self._scope[-4]
        if isinstance(grandparent, ast.Assign):
            if len(grandparent.targets) != 1:
                raise NotImplementedError(
                    "Cannot unpack function with generator expression argument"
                )
            lhs = self._visit(grandparent.targets[0])
        else:
            lhs = self.get_new_variable()

        body = result
        if name == 'sum':
            body = AugAssign(lhs, '+', body)
        else:
            body = FunctionCall(name, (lhs, body))
            body = Assign(lhs, body)

        body.set_fst(parent)
        indices = []
        generators = list(generators)
        while len(generators) > 0:
            indices.append(generators[-1].target)
            generators[-1].insert2body(body)
            body = generators.pop()
        indices = indices[::-1]
        body = [body]
        if name == 'sum':
            expr = FunctionalSum(body, result, lhs, indices, None)
        elif name == 'min':
            expr = FunctionalMin(body, result, lhs, indices, None)
        elif name == 'max':
            expr = FunctionalMax(body, result, lhs, indices, None)
        else:
            errors.report(PYCCEL_RESTRICTION_TODO,
                          symbol=name,
                          bounding_box=(stmt.lineno, stmt.col_offset),
                          severity='fatal')

        expr.set_fst(stmt)
        return expr
Exemple #8
0
def as_static_function_call(func):
    assert (isinstance(func, FunctionDef))

    args = func.arguments
    args = sanitize_arguments(args)
    functions = func.functions
    body = [FunctionCall(func, args)]

    func = FunctionDef(func.name,
                       list(args), [],
                       body,
                       arguments_inout=func.arguments_inout,
                       functions=functions)
    static_func = as_static_function(func)

    return static_func
Exemple #9
0
    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
Exemple #10
0
    def __call__(self, arguments):
        # ...
        if not isinstance(arguments, (list, tuple, Tuple)):
            arguments = [arguments]
        arguments = Tuple(*arguments)

        assert(len(self.target) == len(arguments))
        assert(isinstance(self.funcdef, FunctionDef))
        # ...

        # ...
        func      = self.func
        target    = self.target
        funcdef   = self.funcdef
        func_args = funcdef.arguments
        # ...

        # ...
        target_arg_names = [x.name for x in list(target.keys())]
        args = []
        current = 0
        for x in func_args:
            if x.name in target_arg_names:
                arg = [a for k,a in target.items() if k.name == x.name]
                assert(len(arg) == 1)
                arg = arg[0]

                args += [arg]

            else:
                args += [arguments[current]]
                current += 1
        # ...

        args = Tuple(*args)
        return FunctionCall(func.name, args)
Exemple #11
0
 def __call__(self, *args):
     args = Tuple(*args)
     return FunctionCall(self.name, args)
Exemple #12
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)
Exemple #13
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)
Exemple #14
0
    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
Exemple #15
0
    def __new__(cls, func, import_lambda):

        # ...
        m_results = func.m_results

        name = 'interface_{}'.format(func.name)
        args = [i for i in func.arguments if not i in m_results]
        s_results = func.results

        results = list(s_results) + list(m_results)
        # ...

        # ...
        imports = [import_lambda]
        stmts = []
        # ...

        # ... out argument
        if len(results) == 1:
            outs = [Symbol('out')]

        else:
            outs = [Symbol('out_{}'.format(i)) for i in range(0, len(results))]
        # ...

        # ...
        generators = func.generators
        d_shapes = {}
        for i in m_results:
            d_shapes[i] = compute_shape(i, generators)
        # ...

        # ... TODO build statements
        if_cond = Is(Symbol('out'), Nil())

        if_body = []

        # TODO add imports from numpy
        if_body += [Import('zeros', 'numpy')]
        if_body += [Import('float64', 'numpy')]

        for i, var in enumerate(results):
            if var in m_results:
                shaping = d_shapes[var]

                if_body += shaping.stmts
                if_body += [Assign(outs[i], Zeros(shaping.var, var.dtype))]

        # update statements
        stmts = [If((if_cond, if_body))]
        # ...

        # ... add call to the python or pyccelized function
        stmts += [FunctionCall(func, args + outs)]
        # ...

        # ... add return out
        if len(outs) == 1:
            stmts += [Return(outs[0])]

        else:
            stmts += [Return(outs)]
        # ...

        # ...
        body = imports + stmts
        # ...

        # update arguments with optional
        args += [Assign(Symbol('out'), Nil())]

        return FunctionDef(name, args, results, body)
Exemple #16
0
    def _visit_FunctionDef(self, stmt):

        #  TODO check all inputs and which ones should be treated in stage 1 or 2

        name = self._visit(stmt.name)
        name = name.replace("'", '')

        arguments = self._visit(stmt.args)

        local_vars = []
        global_vars = []
        headers = []
        templates = {}
        is_pure = False
        is_elemental = False
        is_private = False
        imports = []
        doc_string = None

        def fill_types(ls):
            container = []
            for arg in ls:
                if isinstance(arg, Symbol):
                    arg = arg.name
                    container.append(arg)
                elif isinstance(arg, LiteralString):
                    arg = str(arg)
                    arg = arg.strip("'").strip('"')
                    container.append(arg)
                else:
                    msg = 'Invalid argument of type {} passed to types decorator'.format(
                        type(arg))
                    errors.report(msg,
                                  bounding_box=(stmt.lineno, stmt.col_offset),
                                  severity='error')
            return container

        decorators = {}

        # add the decorator @types if the arguments are annotated
        annotated_args = []
        for a in arguments:
            if isinstance(a, Argument):
                annotated_args.append(a.annotation)
            elif isinstance(a, ValuedArgument):
                annotated_args.append(a.argument.annotation)

        if all(not isinstance(a, Nil) for a in annotated_args):
            if stmt.returns:
                returns = ValuedArgument(Symbol('results'),
                                         self._visit(stmt.returns))
                annotated_args.append(returns)
            decorators['types'] = [FunctionCall('types', annotated_args)]

        for d in self._visit(stmt.decorator_list):
            tmp_var = str(d) if isinstance(d, Symbol) else str(d.funcdef)
            if tmp_var in decorators:
                decorators[tmp_var] += [d]
            else:
                decorators[tmp_var] = [d]

        if 'bypass' in decorators:
            return EmptyNode()

        if 'stack_array' in decorators:
            decorators['stack_array'] = tuple(
                str(b) for a in decorators['stack_array'] for b in a.args)

        if 'allow_negative_index' in decorators:
            decorators['allow_negative_index'] = tuple(
                str(b) for a in decorators['allow_negative_index']
                for b in a.args)

        # extract the templates
        if 'template' in decorators:
            for comb_types in decorators['template']:
                cache.clear_cache()
                types = []
                if len(comb_types.args) != 2:
                    msg = 'Number of Arguments provided to the template decorator is not valid'
                    errors.report(msg,
                                  symbol=comb_types,
                                  bounding_box=(stmt.lineno, stmt.col_offset),
                                  severity='error')

                for i in comb_types.args:
                    if isinstance(i,
                                  ValuedArgument) and not i.name in ('name',
                                                                     'types'):
                        msg = 'Argument provided to the template decorator is not valid'
                        errors.report(msg,
                                      symbol=comb_types,
                                      bounding_box=(stmt.lineno,
                                                    stmt.col_offset),
                                      severity='error')
                if all(isinstance(i, ValuedArgument) for i in comb_types.args):
                    tp_name, ls = (comb_types.args[0].value, comb_types.args[1].value) if\
                            comb_types.args[0].name == 'name' else\
                            (comb_types.args[1].value, comb_types.args[0].value)
                else:
                    tp_name = comb_types.args[0]
                    ls = comb_types.args[1]
                    ls = ls.value if isinstance(ls, ValuedArgument) else ls
                try:
                    tp_name = str(tp_name)
                    ls = ls if isinstance(ls, PythonTuple) else list(ls)
                except TypeError:
                    msg = 'Argument provided to the template decorator is not valid'
                    errors.report(msg,
                                  symbol=comb_types,
                                  bounding_box=(stmt.lineno, stmt.col_offset),
                                  severity='fatal')

                types = fill_types(ls)

                txt = '#$ header template ' + str(tp_name)
                txt += '(' + '|'.join(types) + ')'
                if tp_name in templates:
                    msg = 'The template "{}" is duplicated'.format(tp_name)
                    errors.report(msg,
                                  bounding_box=(stmt.lineno, stmt.col_offset),
                                  severity='warning')

                templates[tp_name] = hdr_parse(stmts=txt)

        # extract the types to construct a header
        if 'types' in decorators:
            for comb_types in decorators['types']:

                cache.clear_cache()
                results = []
                ls = comb_types.args

                if len(ls) > 0 and isinstance(ls[-1], ValuedArgument):
                    arg_name = ls[-1].name
                    if not arg_name == 'results':
                        msg = 'Argument "{}" provided to the types decorator is not valid'.format(
                            arg_name)
                        errors.report(msg,
                                      symbol=comb_types,
                                      bounding_box=(stmt.lineno,
                                                    stmt.col_offset),
                                      severity='error')
                    else:
                        container = ls[-1].value
                        container = container if isinstance(
                            container, PythonTuple) else [container]
                        results = fill_types(container)
                    types = fill_types(ls[:-1])
                else:
                    types = fill_types(ls)

                txt = '#$ header ' + name
                txt += '(' + ','.join(types) + ')'

                if results:
                    txt += ' results(' + ','.join(results) + ')'

                header = hdr_parse(stmts=txt)
                if name in self.namespace.static_functions:
                    header = header.to_static()
                headers += [header]

        body = stmt.body

        if 'sympy' in decorators.keys():
            # TODO maybe we should run pylint here
            stmt.decorators.pop()
            func = SympyFunction(name, arguments, [], [stmt.__str__()])
            func.set_fst(stmt)
            self.insert_function(func)
            return EmptyNode()

        elif 'python' in decorators.keys():

            # TODO maybe we should run pylint here

            stmt.decorators.pop()
            func = PythonFunction(name, arguments, [], [stmt.__str__()])
            func.set_fst(stmt)
            self.insert_function(func)
            return EmptyNode()

        else:
            body = self._visit(body)
        if len(body) > 0 and isinstance(body[0], CommentBlock):
            doc_string = body[0]
            doc_string.header = ''
            body = body[1:]

        if 'pure' in decorators.keys():
            is_pure = True

        if 'elemental' in decorators.keys():
            is_elemental = True
            if len(arguments) > 1:
                errors.report(FORTRAN_ELEMENTAL_SINGLE_ARGUMENT,
                              symbol=decorators['elemental'],
                              bounding_box=(stmt.lineno, stmt.col_offset),
                              severity='error')

        if 'private' in decorators.keys():
            is_private = True

        returns = [i.expr for i in _atomic(body, cls=Return)]
        assert all(len(i) == len(returns[0]) for i in returns)
        results = []
        result_counter = 1
        for i in zip(*returns):
            if not all(i[0] == j for j in i) or not isinstance(i[0], Symbol):
                result_name, result_counter = create_variable(
                    self._used_names, prefix='Out', counter=result_counter)
                results.append(result_name)
            elif isinstance(i[0], Symbol) and any(i[0].name == x.name
                                                  for x in arguments):
                result_name, result_counter = create_variable(
                    self._used_names, prefix='Out', counter=result_counter)
                results.append(result_name)
            else:
                results.append(i[0])

        func = FunctionDef(name,
                           arguments,
                           results,
                           body,
                           local_vars=local_vars,
                           global_vars=global_vars,
                           is_pure=is_pure,
                           is_elemental=is_elemental,
                           is_private=is_private,
                           imports=imports,
                           decorators=decorators,
                           headers=headers,
                           templates=templates,
                           doc_string=doc_string)

        func.set_fst(stmt)
        return func