示例#1
0
    def external_function_decl(self, tree: Tree):
        nodes = tree.children
        access_modifier: RIALAccessModifier = nodes[0].access_modifier
        unsafe: bool = nodes[0].unsafe
        linkage = "external"
        calling_convention = "ccc"
        return_type = nodes[1].value
        name = nodes[2].value

        # External functions cannot be declared in a struct
        if self.llvmgen.current_struct is not None:
            log_fail(f"External function {name} cannot be declared inside a class!")
            raise Discard()

        args: List[RIALVariable] = list()
        var_args = False
        i = 3
        while i < len(nodes):
            if var_args is True:
                log_fail("PARAMS must be last in arguments")
                break
            if nodes[i].type == "PARAMS":
                var_args = True
                i += 1
            if nodes[i].type == "IDENTIFIER":
                arg_type = nodes[i].value
                i += 1
                arg_name = nodes[i].value

                if var_args:
                    arg_name += "..."

                args.append(RIALVariable(arg_name, arg_type, None))
                i += 1

        if not unsafe and not self.llvmgen.currently_unsafe:
            raise PermissionError("Can only declare external functions in unsafe blocks or as unsafe functions.")

        # Map RIAL args to llvm arg types
        llvm_args = [arg.llvm_type for arg in args if not arg.name.endswith("...")]

        # Hasn't been declared previously, redeclare the function type here
        llvm_return_type = ParserState.map_type_to_llvm(return_type)
        func_type = self.llvmgen.create_function_type(llvm_return_type, llvm_args, var_args)

        # Create the actual function in IR
        func = self.llvmgen.create_function_with_type(name, name, func_type, linkage,
                                                      calling_convention,
                                                      FunctionDefinition(return_type, access_modifier, args, "",
                                                                         unsafe))

        # Update backing values
        for i, arg in enumerate(func.args):
            args[i].backing_value = arg

        raise Discard()
示例#2
0
    def break_rule(self, tree: Tree):
        if self.module.end_block is None:
            raise PermissionError("Break outside of loop")

        self.module.builder.branch(self.module.end_block)

        raise Discard()
示例#3
0
    def continue_rule(self, tree: Tree):
        if self.module.conditional_block is None:
            raise PermissionError("Continue outside of loop")

        self.module.builder.branch(self.module.conditional_block)

        raise Discard()
示例#4
0
    def unsafe_block(self, tree: Tree):
        nodes = tree.children
        self.module.currently_unsafe = True
        for node in nodes[1:]:
            self.transform_helper(node)

        raise Discard()
    def global_variable_decl(self, nodes: List):
        body = nodes[1].children
        access_modifier: AccessModifier = nodes[0].access_modifier
        variable_name = body[0].value
        value = body[2]

        if isinstance(value, RIALVariable):
            if value.is_global and value.value.global_constant:
                glob = self.module.declare_global(
                    variable_name, value.rial_type, value.llvm_type,
                    access_modifier.get_linkage(), value.value.initializer,
                    access_modifier, True)
            else:
                with self.module.create_in_global_ctor():
                    glob = self.module.declare_global(
                        variable_name, value.rial_type, value.llvm_type,
                        access_modifier.get_linkage(), None, access_modifier)
                    self.module.builder.store(
                        value.get_loaded_if_variable(self.module), glob.value)
        else:
            with self.module.create_in_global_ctor():
                if not isinstance(value, RIALFunction) and not isinstance(
                        value, RIALVariable):
                    value: RIALVariable = self.main_transformer.visit(value)

                if isinstance(value, RIALFunction):
                    value: RIALFunction
                    # Check if in module, otherwise redeclare
                    # if self.module.get_global_safe(value.name) is None:
                    #     value = self.module.declare_function(value.name, value.canonical_name, value.function_type,
                    #                                          value.linkage, value.calling_convention, value.definition)

                    rial_type = str(value.function_type).replace(
                        "i8*", "Char[]")
                    glob = self.module.declare_global(
                        variable_name, rial_type, value.function_type,
                        access_modifier.get_linkage(), value, access_modifier,
                        False)
                else:
                    glob = self.module.declare_global(
                        variable_name, value.rial_type, value.llvm_type,
                        access_modifier.get_linkage(), null(value.llvm_type),
                        access_modifier)
                    self.module.builder.store(
                        value.get_loaded_if_variable(self.module), glob.value)

        raise Discard()
示例#6
0
    def imported(self, nodes):
        mutability = nodes[0]

        if mutability != VariableMutabilityModifier.CONST:
            raise PermissionError(
                "Cannot import modules as anything but const variables")

        var_name = nodes[1].value

        if var_name in self.module.dependencies:
            raise NameError(var_name)

        mod_name = ':'.join([node.value for node in nodes[3:]])

        if mod_name.startswith("core") or mod_name.startswith(
                "std") or mod_name.startswith("startup"):
            mod_name = f"rial:{mod_name}"

        CompilationManager.request_module(mod_name)
        self.module.dependencies[var_name] = mod_name

        raise Discard()
示例#7
0
    def llvm_ir(self, tree: Tree):
        # Check for unsafe
        with only_allowed_in_unsafe(
                "llvm_ir is only allowed in unsafe functions or blocks!"):
            pass
        nodes = tree.children
        llvm_ir: str = nodes[0].value.strip("\"")
        llvm_ir = eval("'{}'".format(llvm_ir))
        ty = None
        return_name = None

        for node in nodes[1:]:
            if isinstance(node, Tree):
                ty = self.transform_helper(node)
            elif isinstance(node, Token):
                return_name = node.value.strip("\"")

        self.module.builder.ir(ty, llvm_ir)

        if return_name is not None:
            if ty is None:
                raise KeyError(
                    "Need to specify type if you want to use @llvm_ir as a variable!"
                )
            if isinstance(ty, RIALIdentifiedStructType):
                ty_name = ty.name
            else:
                ty_name = map_llvm_to_type(ty)
            variable = self.module.builder.alloca(ty)
            self.module.builder.store(
                LLVMIRInstruction(ty, f"%\"{return_name}\""), variable)
            variable = RIALVariable("llvm_ir", ty_name, ty, variable)
            if return_name in self.module.current_block.named_values:
                raise KeyError(f"{return_name} has been previously defined!")
            self.module.current_block.add_named_value(return_name, variable)
            return variable

        raise Discard()
示例#8
0
    def struct_decl(self, tree: Tree):
        nodes: List = tree.children
        access_modifier = nodes[0].access_modifier
        name = nodes[1].value

        full_name = f"{ParserState.module().name}:{name}"

        if ParserState.search_structs(full_name) is not None:
            log_fail(f"Struct {full_name} has been previously declared!")
            raise Discard()

        body: List[RIALVariable] = list()
        function_decls: List[Tree] = list()
        bases: List[str] = list()

        # Find body of struct (variables)
        i = 2
        while i < len(nodes):
            node: Tree = nodes[i]

            if isinstance(node,
                          Tree) and node.data == "struct_property_declaration":
                variable = node.children
                acc_modifier = variable[0].access_modifier
                rial_type = variable[1].value
                variable_name = variable[2].value
                variable_value = None

                if len(variable) > 3:
                    variable_value = variable[3]

                body.append(
                    RIALVariable(variable_name,
                                 rial_type,
                                 backing_value=variable_value,
                                 access_modifier=acc_modifier))
            elif isinstance(node, Tree) and node.data == "function_decl":
                function_decls.append(node)
            elif isinstance(node, Token) and node.type == "IDENTIFIER":
                bases.append(node.value)
            i += 1

        base_llvm_structs = list()

        for base in bases:
            llvm_struct = ParserState.find_struct(base)

            if llvm_struct is not None:
                base_llvm_structs.append(llvm_struct)
            else:
                log_fail(f"Derived from undeclared type {base}")

        base_constructor = Tree('function_decl', [
            RIALFunctionDeclarationModifier(access_modifier),
            Token('IDENTIFIER', "void"),
            Token('IDENTIFIER', "constructor"), *[
                Tree('function_call', [
                    Token(
                        'IDENTIFIER',
                        mangle_function_name("constructor", [base],
                                             base.name)),
                    Tree('function_args', [
                        Tree('cast', [
                            Token('IDENTIFIER', base.name),
                            Tree('var', [Token('IDENTIFIER', "this")])
                        ])
                    ])
                ]) for base in base_llvm_structs
            ], *[
                Tree('variable_assignment', [
                    Tree('var', [Token('IDENTIFIER', f"this.{bod.name}")]),
                    Token('ASSIGN', '='), bod.backing_value
                ]) for bod in body
            ],
            Tree('return', [Token('IDENTIFIER', "void")])
        ])
        function_decls.insert(0, base_constructor)

        llvm_struct = self.llvmgen.create_identified_struct(
            full_name, access_modifier.get_linkage(), access_modifier,
            base_llvm_structs, body)

        declared_functions = list()

        # Create functions
        for function_decl in function_decls:
            metadata_node = self.fdt.visit(function_decl)
            if metadata_node is not None:
                declared_functions.append(metadata_node)
            try:
                nodes.remove(function_decl)
            except ValueError:
                pass

        self.llvmgen.finish_struct()

        node: Token = nodes[1]
        md_node = MetadataToken(node.type, node.value)

        md_node.metadata['struct_name'] = full_name
        md_node.metadata['functions'] = declared_functions
        nodes.remove(node)
        nodes.insert(0, md_node)

        return Tree('struct_decl', nodes)
    def struct_decl(self, tree: Tree):
        nodes: List = tree.children
        modifier: DeclarationModifier = nodes[0]
        access_modifier = modifier.access_modifier
        name = nodes[1].value

        if name in self.module.context.identified_types:
            log_fail(f"Struct {name} has been previously declared!")
            raise Discard()

        struct_body: Dict[str, List[Union[RIALVariable,
                                          Tree]]] = self.visit(nodes[-1])
        bases: List[List[str]] = list()

        # Find body of struct (variables)
        i = 2
        while i < len(nodes):
            node: Tree = nodes[i]

            if isinstance(node, List):
                bases.append(node)
            else:
                break
            i += 1

        base_llvm_structs = list()

        for base in bases:
            llvm_struct = self.module.get_definition(base)

            if llvm_struct is not None and isinstance(
                    llvm_struct, RIALIdentifiedStructType):
                base_llvm_structs.append(llvm_struct)
            else:
                log_fail(f"Derived from undeclared type {base}")

        # base_constructor = Tree('function_decl',
        #                         [
        #                             DeclarationModifier(access_modifier, False),
        #                             ["void"],
        #                             Token('IDENTIFIER', "constructor"),
        #                             Tree('function_decl_args', [[name], Token('IDENTIFIER', "this")]),
        #                             *[Tree('function_call', [
        #                                 Token('IDENTIFIER', "constructor"),
        #                                 Tree('function_args',
        #                                      [Tree('cast', [Token('IDENTIFIER', base.name),
        #                                                     Tree('var', [Token('IDENTIFIER', "this")])])])])
        #                               for base in base_llvm_structs],
        #                             *[Tree('variable_assignment',
        #                                    [Tree('var', [Token('IDENTIFIER', f"this.{bod.name}")]),
        #                                     Token('ASSIGN', '='),
        #                                     bod.value]) for bod in struct_body['properties']],
        #                             Tree('return', [Token('IDENTIFIER', "void")])
        #                         ]
        #                         )
        # struct_body['function_decls'].insert(0, base_constructor)
        struct = create_identified_struct_type(self.module, name,
                                               access_modifier,
                                               base_llvm_structs,
                                               struct_body['properties'])
        self.module.current_struct = struct

        declared_functions = list()

        # Create functions
        for function_decl in struct_body['function_decls']:
            metadata_node = self.fdt.visit(function_decl)
            if metadata_node is not None:
                declared_functions.append(metadata_node)
            try:
                nodes.remove(function_decl)
            except ValueError:
                pass

        self.module.current_block = None
        self.module.current_func = None
        self.module.current_struct = None

        node: Token = nodes[1]
        nodes.pop(1)

        node: MetadataToken = MetadataToken(node.type, node.value)
        node.metadata['struct'] = struct
        node.metadata['functions'] = declared_functions

        nodes.insert(0, node)

        return Tree('struct_decl', nodes)
示例#10
0
    def function_decl(self, tree: Tree):
        nodes = tree.children
        modifier: DeclarationModifier = nodes[0]

        if isinstance(modifier, MetadataToken):
            return tree

        access_modifier: AccessModifier = modifier.access_modifier
        unsafe: bool = modifier.unsafe
        linkage = access_modifier.get_linkage()
        name = nodes[2].value
        llvm_return_type = self.module.get_definition(nodes[1])

        if isinstance(llvm_return_type, RIALIdentifiedStructType):
            return_type = llvm_return_type.name
        else:
            return_type = map_shortcut_to_type('.'.join(nodes[1]))

        # Builtins can be passed as raw values
        if is_builtin_type(return_type):
            llvm_return_type = llvm_return_type
        # Pointer to first element for still normal arrays
        elif re.match(r".+\[[0-9]+\]$", return_type) is not None:
            llvm_return_type = llvm_return_type.as_pointer()
        elif isinstance(llvm_return_type, RIALIdentifiedStructType):
            llvm_return_type = llvm_return_type.as_pointer()
        else:
            llvm_return_type = llvm_return_type

        args: List[RIALVariable] = list()

        # Add class as implicit parameter
        if self.module.current_struct is not None and not modifier.static:
            args.append(
                RIALVariable("this", self.module.current_struct.name,
                             self.module.current_struct, None))

        args.extend(self.visit(nodes[3]))

        llvm_args = list()

        # Map RIAL args to llvm arg types
        for arg in args:
            if arg.name.endswith("..."):
                continue

            # Pointer for array and struct types
            if isinstance(arg.llvm_type,
                          RIALIdentifiedStructType) or isinstance(
                              arg.llvm_type, ArrayType):
                llvm_type = arg.llvm_type.as_pointer()
            else:
                llvm_type = arg.llvm_type
            llvm_args.append(llvm_type)

        # If the function has the NoMangleAttribute we need to use the normal name
        if 'noduplicate' in self.attributes:
            if modifier.static:
                raise PermissionError(
                    "NoMangle for static function doesn't work")
            full_function_name = name
        else:
            if modifier.static:
                if self.module.current_struct is None:
                    raise PermissionError(
                        "Static functions can only be declared in types")
                full_function_name = self.module.get_unique_function_name(
                    f"{self.module.current_struct.name}::{name}",
                    [arg.rial_type for arg in args])
            else:
                full_function_name = self.module.get_unique_function_name(
                    name, [arg.rial_type for arg in args])

        # Check if main method
        if name.endswith("main") and self.module.name.endswith("main"):
            self.attributes.add('alwaysinline')

            # Check that main method returns either Int32 or void
            if return_type != "Int32" and return_type != "Void":
                log_fail(
                    f"Main method must return an integer status code or void, {return_type} given!"
                )

        # Hasn't been declared previously, redeclare the function type here
        func_type = FunctionType(llvm_return_type, llvm_args, False)

        # Create the actual function in IR
        func = RIALFunction(self.module, func_type, full_function_name, name)
        func.linkage = linkage
        func.calling_convention = self.default_cc
        func.definition = FunctionDefinition(
            return_type, access_modifier, args,
            self.module.current_struct is not None
            and self.module.current_struct or "", unsafe)
        func.attributes = self.attributes

        # Update args
        for i, arg in enumerate(func.args):
            arg.name = args[i].name
            args[i].value = arg

        # If it has no body we do not need to go through it later as it's already declared with this method.
        if not len(nodes) > 4:
            with self.module.create_or_enter_function_body(func):
                self.module.builder.ret_void()
            raise Discard()

        token = nodes[2]
        metadata_token = MetadataToken(token.type, token.value)
        metadata_token.metadata["func"] = func
        metadata_token.metadata["body_start"] = 4
        nodes.remove(token)
        nodes.insert(0, metadata_token)

        return Tree('function_decl', nodes)
示例#11
0
    def extension_function_decl(self, tree: Tree):
        nodes = tree.children
        modifier: DeclarationModifier = nodes[0]

        if isinstance(modifier, MetadataToken):
            return tree

        if modifier.static:
            raise PermissionError("Extension functions cannot be static")

        access_modifier: AccessModifier = modifier.access_modifier
        unsafe: bool = modifier.unsafe
        linkage = access_modifier.get_linkage()
        name = nodes[2].value
        llvm_return_type = self.module.get_definition(nodes[1])

        if isinstance(llvm_return_type, RIALIdentifiedStructType):
            return_type = llvm_return_type.name
        else:
            return_type = map_shortcut_to_type('.'.join(nodes[1]))

        # Builtins can be passed as raw values
        if is_builtin_type(return_type):
            llvm_return_type = llvm_return_type
        # Pointer to first element for still normal arrays
        elif re.match(r".+\[[0-9]+\]$", return_type) is not None:
            llvm_return_type = llvm_return_type.as_pointer()
        elif isinstance(llvm_return_type, RIALIdentifiedStructType):
            llvm_return_type = llvm_return_type.as_pointer()
        else:
            llvm_return_type = llvm_return_type

        # Extension functions cannot be declared inside other classes.
        if self.module.current_struct is not None:
            log_fail(
                f"Extension function {name} cannot be declared inside another class!"
            )
            raise Discard()

        args: List[RIALVariable] = list()
        this_type = self.module.get_definition(nodes[3])

        if isinstance(this_type, RIALIdentifiedStructType):
            rial_type = this_type.name
        else:
            rial_type = map_shortcut_to_type('.'.join(nodes[3]))

        args.append(RIALVariable(nodes[4].value, rial_type, this_type, None))

        if isinstance(nodes[5],
                      Tree) and nodes[5].data == "function_decl_args":
            args.extend(self.visit(nodes[5]))
            body_start = 6
        else:
            body_start = 5

        # If the function has the NoMangleAttribute we need to use the normal name
        if 'noduplicate' in self.attributes:
            full_function_name = name
        else:
            full_function_name = self.module.get_unique_function_name(
                name, [arg.rial_type for arg in args])

        llvm_args = list()

        # Map RIAL args to llvm arg types
        for arg in args:
            if arg.name.endswith("..."):
                continue

            # Builtins can be passed as raw values
            if is_builtin_type(arg.rial_type):
                llvm_args.append(arg.llvm_type)
            # Pointer to first element for still normal arrays
            elif re.match(r".+\[[0-9]+\]$", arg.rial_type) is not None:
                llvm_args.append(arg.llvm_type.as_pointer())
            elif isinstance(arg.llvm_type, RIALIdentifiedStructType):
                llvm_args.append(arg.llvm_type.as_pointer())
            else:
                llvm_args.append(arg.llvm_type)

        # Hasn't been declared previously, redeclare the function type here
        func_type = FunctionType(llvm_return_type, llvm_args)

        # Create the actual function in IR
        func = RIALFunction(self.module, func_type, full_function_name, name)
        func.linkage = linkage
        func.calling_convention = self.default_cc
        func.definition = FunctionDefinition(return_type, access_modifier,
                                             args, args[0].rial_type, unsafe)

        # Update args
        for i, arg in enumerate(func.args):
            arg.name = args[i].name
            args[i].value = arg

        # If it has no body we can discard it now.
        if len(nodes) <= body_start:
            with self.module.create_or_enter_function_body(func):
                self.module.builder.ret_void()
            raise Discard()

        token = nodes[2]
        metadata_token = MetadataToken(token.type, token.value)
        metadata_token.metadata["func"] = func
        metadata_token.metadata["body_start"] = body_start
        nodes.remove(token)
        nodes.insert(0, metadata_token)

        return Tree('function_decl', nodes)
示例#12
0
    def external_function_decl(self, tree: Tree):
        nodes = tree.children
        modifier: DeclarationModifier = nodes[0]

        if isinstance(modifier, MetadataToken):
            return tree

        if modifier.static:
            raise PermissionError("External functions cannot be static")

        access_modifier: AccessModifier = modifier.access_modifier
        unsafe: bool = modifier.unsafe
        name = nodes[2].value
        llvm_return_type = self.module.get_definition(nodes[1])

        if isinstance(llvm_return_type, RIALIdentifiedStructType):
            return_type = llvm_return_type.name
        else:
            return_type = map_shortcut_to_type('.'.join(nodes[1]))

        # Builtins can be passed as raw values
        if is_builtin_type(return_type):
            llvm_return_type = llvm_return_type
        # Pointer to first element for still normal arrays
        elif re.match(r".+\[[0-9]+\]$", return_type) is not None:
            llvm_return_type = llvm_return_type.as_pointer()
        elif isinstance(llvm_return_type, RIALIdentifiedStructType):
            llvm_return_type = llvm_return_type.as_pointer()
        else:
            llvm_return_type = llvm_return_type

        # External functions cannot be declared in a struct
        if self.module.current_struct is not None:
            log_fail(
                f"External function {name} cannot be declared inside a class!")
            raise Discard()

        args: List[RIALVariable] = self.visit(nodes[3])

        llvm_args = list()

        # Map RIAL args to llvm arg types
        for arg in args:
            if arg.name.endswith("..."):
                continue

            # Pointer for array and struct types
            if isinstance(arg.llvm_type,
                          RIALIdentifiedStructType) or isinstance(
                              arg.llvm_type, ArrayType):
                llvm_type = arg.llvm_type.as_pointer()
            else:
                llvm_type = arg.llvm_type
            llvm_args.append(llvm_type)

        var_args = len(args) > 0 and args[-1].name.endswith("...")

        # Hasn't been declared previously, redeclare the function type here
        func_type = FunctionType(llvm_return_type, llvm_args, var_args)

        # Create function definition
        func = RIALFunction(self.module, func_type, name, name)
        func.linkage = "external"
        func.calling_convention = "ccc"
        func.definition = FunctionDefinition(return_type,
                                             access_modifier,
                                             args,
                                             unsafe=True)
        func.attributes = self.attributes

        # Update args
        for i, arg in enumerate(func.args):
            arg.name = args[i].name
            args[i].value = arg

        raise Discard()
示例#13
0
    def function_decl(self, tree: Tree):
        nodes = tree.children

        # Function specialisation
        if isinstance(nodes[0], Tree):
            return self.visit(nodes[0])

        access_modifier: RIALAccessModifier = nodes[0].access_modifier
        unsafe: bool = nodes[0].unsafe
        linkage = access_modifier.get_linkage()
        main_function = False
        calling_convention = self.default_cc
        return_type = nodes[1].value
        name = nodes[2].value

        args: List[RIALVariable] = list()

        # Add class as implicit parameter
        if self.llvmgen.current_struct is not None:
            args.append(RIALVariable("this", self.llvmgen.current_struct.name, None))

        i = 3
        has_body = False

        while i < len(nodes):
            if not isinstance(nodes[i], Token):
                has_body = True
                break
            if nodes[i].type == "IDENTIFIER":
                arg_type = nodes[i].value
                i += 1
                arg_name = nodes[i].value
                args.append(RIALVariable(arg_name, arg_type, None))
                i += 1
            else:
                break

        # Map RIAL args to llvm arg types
        llvm_args = [arg.llvm_type for arg in args if not arg.name.endswith("...")]

        # If the function has the NoMangleAttribute we need to use the normal name
        if not self.mangling:
            full_function_name = name
        else:
            if self.llvmgen.current_struct is not None:
                full_function_name = mangle_function_name(name, llvm_args,
                                                          self.llvmgen.current_struct.name)
            else:
                full_function_name = mangle_function_name(name, llvm_args)
                full_function_name = f"{ParserState.module().name}:{full_function_name}"

        # Check if main method
        if full_function_name.endswith("main:main") and full_function_name.count(':') == 2:
            main_function = True

            # Check that main method returns either Int32 or void
            if return_type != "Int32" and return_type != "void":
                log_fail(f"Main method must return an integer status code or void, {return_type} given!")

        # Search for function in the archives
        # func = ParserState.search_function(full_function_name)

        # Function has been previously declared in other module
        # if func is not None and (func.module.name != ParserState.module().name or not func.is_declaration):
        #     # Check if either:
        #     # - has no body (cannot redeclare functions) or
        #     # - is already implemented and
        #     #   - is either public or
        #     #     - internal and
        #     #     - is in same package (cannot reimplement functions)
        #     # TODO: LLVM checks this anyways but maybe we wanna do it, too?
        #     log_fail(f"Function {full_function_name} already declared elsewhere")
        #     raise Discard()

        # Hasn't been declared previously, redeclare the function type here
        llvm_return_type = ParserState.map_type_to_llvm(return_type)
        func_type = self.llvmgen.create_function_type(llvm_return_type, llvm_args, False)

        # Create the actual function in IR
        func = self.llvmgen.create_function_with_type(full_function_name, name, func_type, linkage,
                                                      calling_convention,
                                                      FunctionDefinition(return_type, access_modifier, args,
                                                                         self.llvmgen.current_struct is not None and self.llvmgen.current_struct.name or "",
                                                                         unsafe))

        # Update backing values
        for i, arg in enumerate(func.args):
            args[i].backing_value = arg

        if self.llvmgen.current_struct is not None:
            self.llvmgen.current_struct.definition.functions.append(func.name)

        # Always inline the main function into the compiler supplied one
        if main_function:
            func.attributes.add('alwaysinline')

        # If it has no body we do not need to go through it later as it's already declared with this method.
        if not has_body:
            raise Discard()

        token = nodes[2]
        metadata_token = MetadataToken(token.type, token.value)
        metadata_token.metadata["func"] = func
        metadata_token.metadata["body_start"] = i
        nodes.remove(token)
        nodes.insert(0, metadata_token)

        return Tree('function_decl', nodes)
示例#14
0
    def extension_function_decl(self, tree: Tree):
        nodes = tree.children
        access_modifier: RIALAccessModifier = nodes[0].access_modifier
        unsafe: bool = nodes[0].unsafe
        linkage = access_modifier.get_linkage()
        calling_convention = self.default_cc
        return_type = nodes[1].value
        name = nodes[2].value

        # Extension functions cannot be declared inside other classes.
        if self.llvmgen.current_struct is not None:
            log_fail(f"Extension function {name} cannot be declared inside another class!")
            raise Discard()

        if not self.mangling:
            log_fail(f"Extension function {name} does not qualify for no mangling.")
            raise Discard()

        args: List[RIALVariable] = list()
        this_arg = map_shortcut_to_type(nodes[3].value)
        has_body = False

        args.append(RIALVariable(nodes[4].value, nodes[3].value, None))

        i = 5
        while i < len(nodes):
            if not isinstance(nodes[i], Token):
                has_body = True
                break
            if nodes[i].type == "IDENTIFIER":
                arg_type = nodes[i].value
                i += 1
                arg_name = nodes[i].value
                args.append(RIALVariable(arg_name, arg_type, None))
                i += 1
            else:
                break

        # Map RIAL args to llvm arg types
        llvm_args = [arg.llvm_type for arg in args if not arg.name.endswith("...")]

        full_function_name = mangle_function_name(name, llvm_args, this_arg)
        full_function_name = f"{ParserState.module().name}:{full_function_name}"

        # Hasn't been declared previously, redeclare the function type here
        llvm_return_type = ParserState.map_type_to_llvm(return_type)
        func_type = self.llvmgen.create_function_type(llvm_return_type, llvm_args, False)

        # Create the actual function in IR
        func = self.llvmgen.create_function_with_type(full_function_name, name, func_type, linkage,
                                                      calling_convention,
                                                      FunctionDefinition(return_type, access_modifier, args,
                                                                         self.llvmgen.current_struct is not None and self.llvmgen.current_struct.name or "",
                                                                         unsafe))

        # Update backing values
        for i, arg in enumerate(func.args):
            args[i].backing_value = arg

        if is_builtin_type(this_arg):
            if this_arg not in ParserState.builtin_types:
                ParserState.builtin_types[this_arg] = dict()

            ParserState.builtin_types[this_arg][func.name] = func

            if not this_arg in ParserState.module().builtin_type_methods:
                ParserState.module().builtin_type_methods[this_arg] = list()
            ParserState.module().builtin_type_methods[this_arg].append(func.name)
        else:
            struct = ParserState.find_struct(this_arg)

            if struct is None:
                log_fail(f"Extension function for non-existing type {this_arg}")
                ParserState.module().functions.remove(func)
                raise Discard()

            struct.definition.functions.append(func.name)

        if not has_body:
            raise Discard()

        token = nodes[2]
        metadata_token = MetadataToken(token.type, token.value)
        metadata_token.metadata["func"] = func
        metadata_token.metadata["body_start"] = i
        nodes.remove(token)
        nodes.insert(0, metadata_token)

        return Tree('function_decl', nodes)