Пример #1
0
    def identifier(self, token: Token):
        value = token.value
        value = map_shortcut_to_type(value)

        # TODO: Add some kind of external registration / handling of this instead of inlining it all into this function
        if value.startswith("#"):
            if value == "#programMain":
                value = f"{CompilationManager.config.project_name}:main:main"
            elif value == "#programMainFile":
                value = f"{CompilationManager.config.project_name}:main"
            elif value == "#targetTriple":
                value = CompilationManager.codegen.target_machine.triple
                token.type = "STRING"
            elif value == "#targetOS":
                triple = CompilationManager.codegen.target_machine.triple
                token.type = "STRING"

                # TODO: Better detection
                if '-linux-' in triple:
                    value = "linux"
                elif "-windows-" in triple:
                    value = "windows"
                elif "-darwin-" in triple:
                    value = "darwin"
                else:
                    value = triple
        elif value.startswith("@"):
            value = value.replace("@\"", "").rstrip("\"")

        token = token.update(value=value)

        return token
Пример #2
0
 def not_rule(self, nodes):
     return Tree('equal', [
         nodes[0],
         Token('EQUAL', '=='),
         RIALVariable("number", "Int1", ir.IntType(1),
                      ir.Constant(ir.IntType(1), 0))
     ])
Пример #3
0
 def likely_unlikely_modifier(self, nodes: List):
     if len(nodes) == 0:
         return Token('STANDARD_WEIGHT', 50)
     if nodes[0].type == "LIKELY":
         return nodes[0].update(value=100)
     elif nodes[0].type == "UNLIKELY":
         return nodes[0].update(value=10)
     raise KeyError()
Пример #4
0
    def conditional_block(self, tree: Tree):
        nodes = tree.children

        name = self.llvmgen.current_block.block.name
        condition = nodes[0]
        likely_unlikely_modifier: Token = nodes[1]
        body = nodes[2]
        else_conditional: Optional[Tree] = len(nodes) > 3 and nodes[3] or None
        else_likely_unlikely_modifier = Token('STANDARD_WEIGHT', 50)

        if else_conditional is not None:
            if else_conditional.data == "conditional_else_block":
                else_likely_unlikely_modifier = else_conditional.children[0]
                else_conditional.children.pop(0)
            else:
                # Else-If
                # If the IF Condition is likely, then the else if is automatically unlikely
                # If the IF Condition is unlikely, then the else if is automatically likely
                # This is done because the last ELSE is the opposite of the first IF and thus the ELSE IFs are automatically gone through to get there.
                # The original ELSE IF weight is used in the following conditional blocks (that were inserted in this generated ELSE block).
                if likely_unlikely_modifier.type == "LIKELY":
                    else_likely_unlikely_modifier = Token("UNLIKELY", 10)
                else:
                    else_likely_unlikely_modifier = Token("LIKELY", 100)

        else_block = None

        if else_conditional is None:
            (conditional_block, body_block, end_block) = \
                self.llvmgen.create_conditional_block(name, self.llvmgen.current_block)
        else:
            (conditional_block, body_block, else_block, end_block) = \
                self.llvmgen.create_conditional_block_with_else(name,
                                                                self.llvmgen.current_block)

        if likely_unlikely_modifier.type == else_likely_unlikely_modifier.type and likely_unlikely_modifier.type != "STANDARD_WEIGHT":
            log_warn(
                f"{ParserState.module().filename}[{likely_unlikely_modifier.line}:{likely_unlikely_modifier.column}]WARNING 002"
            )
            log_warn(
                f"Specifying the same weight on both conditionals cancels them out."
            )
            log_warn(f"Both can be safely removed.")

        # Create condition
        self.llvmgen.create_jump(conditional_block)
        self.llvmgen.enter_block(conditional_block)
        cond: RIALVariable = self.transform_helper(condition)

        self.llvmgen.create_conditional_jump(
            cond.raw_backing_value, body_block,
            else_block is not None and else_block or end_block,
            likely_unlikely_modifier.value,
            else_likely_unlikely_modifier.value)

        # Create body
        self.llvmgen.enter_block(body_block)

        for node in body.children:
            self.transform_helper(node)

        # Jump out of body
        self.llvmgen.create_jump_if_not_exists(end_block)

        # Create else if necessary
        if len(nodes) > 3:
            self.llvmgen.enter_block(else_block)
            for node in else_conditional.children:
                self.transform_helper(node)
            self.llvmgen.create_jump_if_not_exists(end_block)

        # Leave conditional block
        self.llvmgen.enter_block(end_block)
Пример #5
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)
Пример #6
0
    def conditional_block(self, tree: Tree):
        nodes = tree.children
        name = f"{self.module.current_block.name}.conditional"
        condition = nodes[0]
        likely_unlikely_modifier: Token = nodes[1]
        body = nodes[2]
        else_conditional: Optional[Tree] = len(nodes) > 3 and nodes[3] or None
        else_likely_unlikely_modifier = Token('STANDARD_WEIGHT', 50)

        if else_conditional is not None:
            if else_conditional.data == "conditional_else_block":
                else_likely_unlikely_modifier = else_conditional.children[0]
                else_conditional.children.pop(0)
            else:
                # Else-If
                # If the IF Condition is likely, then the else if is automatically unlikely
                # If the IF Condition is unlikely, then the else if is automatically likely
                # This is done because the last ELSE is the opposite of the first IF and thus the ELSE IFs are automatically gone through to get there.
                # The original ELSE IF weight is used in the following conditional blocks (that were inserted in this generated ELSE block).
                if likely_unlikely_modifier.type == "LIKELY":
                    else_likely_unlikely_modifier = Token("UNLIKELY", 10)
                else:
                    else_likely_unlikely_modifier = Token("LIKELY", 100)

        else_block = None

        conditional_block = self.module.builder.create_block(
            f"{name}.condition", parent=self.module.current_block)
        body_block = self.module.builder.create_block(f"{name}.body",
                                                      parent=conditional_block)
        end_block = self.module.builder.create_block(
            f"{name}.end", sibling=self.module.current_block)
        old_conditional_block = self.module.conditional_block
        old_end_block = self.module.end_block

        if else_conditional is not None:
            else_block = self.module.builder.create_block(
                f"{name}.else", parent=conditional_block)

        if likely_unlikely_modifier.type == else_likely_unlikely_modifier.type and likely_unlikely_modifier.type != "STANDARD_WEIGHT":
            # log_warn(
            #     f"{ParserState.module().filename}[{likely_unlikely_modifier.line}:{likely_unlikely_modifier.column}]WARNING 002")
            # log_warn(f"Specifying the same weight on both conditionals cancels them out.")
            # log_warn(f"Both can be safely removed.")
            pass

        # Create condition
        self.module.builder.create_jump(conditional_block)
        self.module.builder.enter_block(conditional_block)
        cond: RIALVariable = self.transform_helper(condition)
        assert isinstance(cond, RIALVariable)
        self.module.builder.create_conditional_jump(
            cond.get_loaded_if_variable(self.module), body_block,
            else_block is not None and else_block or end_block, [
                likely_unlikely_modifier.value,
                else_likely_unlikely_modifier.value
            ])

        # Create body
        self.module.builder.enter_block(body_block)
        for node in body.children:
            self.transform_helper(node)

        # Jump out of body
        if not self.module.current_block.is_terminated:
            self.module.builder.create_jump(end_block)

        # Create else if necessary
        if len(nodes) > 3:
            self.module.builder.enter_block(else_block)
            for node in else_conditional.children:
                self.transform_helper(node)
            if not self.module.current_block.is_terminated:
                self.module.builder.create_jump(end_block)

        # Leave conditional block
        self.module.builder.enter_block(end_block)
        self.module.conditional_block = old_conditional_block
        self.module.end_block = old_end_block