コード例 #1
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
    def create_function_with_type(self, name: str, canonical_name: str, ty: FunctionType,
                                  linkage: str,
                                  calling_convention: str,
                                  function_def: FunctionDefinition) -> RIALFunction:
        """
        Creates an IR Function with the specified arguments. NOTHING MORE.
        :param canonical_name:
        :param canonical_name:
        :param function_def:
        :param name:
        :param ty:
        :param linkage:
        :param calling_convention:
        :return:
        """

        # Create function with specified linkage (internal -> module only)
        func = RIALFunction(ParserState.module(), ty, name=name, canonical_name=canonical_name)
        func.linkage = linkage
        func.calling_convention = calling_convention
        func.definition = function_def

        # Set argument names
        for i, arg in enumerate(func.args):
            arg.name = function_def.rial_args[i].name

        ParserState.module().rial_functions.append(func)

        return func
コード例 #2
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
    def declare_nameless_variable_from_rial_type(self, rial_type: str, value):
        returned_type = ParserState.map_type_to_llvm_no_pointer(rial_type)

        if isinstance(returned_type, ir.VoidType):
            return value
        returned_value = self.builder.alloca(returned_type)

        if isinstance(ParserState.map_type_to_llvm(rial_type), PointerType):
            self.builder.store(self.builder.load(value), returned_value)
        else:
            self.builder.store(value, returned_value)

        return returned_value
コード例 #3
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
    def check_struct_access_allowed(self, struct: RIALIdentifiedStructType):
        # Public is always okay
        if struct.definition.access_modifier == RIALAccessModifier.PUBLIC:
            return True

        # Private and same module
        if struct.definition.access_modifier == RIALAccessModifier.PRIVATE:
            return struct.module_name == ParserState.module().name

        # Internal and same TLM
        if struct.definition.access_modifier == RIALAccessModifier.INTERNAL:
            return struct.module_name.split(':')[0] == ParserState.module().name.split(':')[0]

        return False
コード例 #4
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
    def declare_non_constant_global_variable(self, identifier: str, value, access_modifier: RIALAccessModifier,
                                             linkage: str):
        """
        Needs to be called with create_in_global_ctor or otherwise the store/load operations are going to fail.
        :param identifier:
        :param value:
        :param access_modifier:
        :param linkage:
        :return:
        """
        if ParserState.module().get_global_safe(identifier) is not None:
            return None

        if self.current_func.name != "global_ctor":
            return None

        if isinstance(value, AllocaInstr):
            variable = self.gen_global(identifier, null(value.type.pointee), value.type.pointee, access_modifier,
                                       linkage, False)
        elif isinstance(value, PointerType):
            variable = self.gen_global(identifier, null(value.pointee.type), value.pointee.type, access_modifier,
                                       linkage, False)
        elif isinstance(value, FormattedConstant) or isinstance(value, AllocaInstr):
            variable = self.gen_global(identifier, null(value.type.pointee), value.type.pointee, access_modifier,
                                       linkage, False)
        elif isinstance(value, Constant):
            variable = self.gen_global(identifier, null(value.type), value.type, access_modifier, linkage, False)
        else:
            variable = self.gen_global(identifier, null(value.type), value.type, access_modifier, linkage, False)

        self.assign_non_constant_global_variable(variable, value)

        return variable
コード例 #5
0
    def constructor_call(self, tree: Tree):
        nodes = tree.children
        name = nodes[0]
        struct = ParserState.find_struct(name)

        if struct is None:
            log_fail(f"Instantiation of unknown type {name}")

        arguments = list()

        instantiated = self.llvmgen.builder.alloca(struct)
        instantiated = RIALVariable(name, name, instantiated)
        arguments.append(instantiated)

        arguments.extend(self.transform_helper(nodes[1]))
        llvm_args = [arg.backing_value for arg in arguments]

        constructor_name = mangle_function_name(
            "constructor", [arg.llvm_type for arg in arguments], name)

        try:
            call_instr = self.llvmgen.gen_function_call([constructor_name],
                                                        llvm_args)

            if call_instr is None:
                log_fail(
                    f"Failed to generate call to function {constructor_name}")
                return NULL

            return instantiated
        except IndexError:
            log_fail("Missing argument in function call")

        return NULL
コード例 #6
0
 def raw_backing_value(self):
     from rial.ParserState import ParserState
     return (self._is_loaded or
             (self.rial_type == "CString"
              and self.backing_value.type == ir.IntType(8).as_pointer())
             ) and self.backing_value or ParserState.llvmgen().builder.load(
                 self.backing_value)
コード例 #7
0
    def llvm_type(self):
        from rial.ParserState import ParserState

        if isinstance(self.backing_value, ir.CallInstr):
            return self.backing_value.type

        return ParserState.map_type_to_llvm(self.rial_type)
コード例 #8
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()
コード例 #9
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
 def check_function_call_allowed(self, func: RIALFunction):
     # Unsafe in safe context is big no-no
     if func.definition.unsafe and not self.currently_unsafe:
         return False
     # Public is always okay
     if func.definition.access_modifier == RIALAccessModifier.PUBLIC:
         return True
     # Internal only when it's the same TLM
     if func.definition.access_modifier == RIALAccessModifier.INTERNAL:
         return func.module.name.split(':')[0] == ParserState.module().name.split(':')[0]
     # Private is harder
     if func.definition.access_modifier == RIALAccessModifier.PRIVATE:
         # Allowed if not in struct and in current module
         if func.definition.struct == "" and func.module.name == ParserState.module().name:
             return True
         # Allowed if in same struct irregardless of module
         if self.current_struct is not None and self.current_struct.name == func.definition.struct:
             return True
     return False
コード例 #10
0
    def sizeof(self, tree: Tree):
        nodes = tree.children
        variable: Optional[RIALVariable] = self.transform_helper(nodes[0])
        name = ""

        # If it's not a variable, extract the name manually since it's the name of a type to get the size of
        if variable is None:
            name = nodes[0].children[0].value
            ty = ParserState.map_type_to_llvm_no_pointer(name)

            size = Int32(get_size(ty))
        elif isinstance(variable.backing_value,
                        ir.GEPInstr) or (variable.is_array and isinstance(
                            variable.raw_llvm_type, ir.PointerType)):
            # This is worst case as it cannot be optimized away.
            base = self.llvmgen.builder.ptrtoint(
                self.llvmgen.builder.gep(variable.backing_value,
                                         [ir.Constant(ir.IntType(32), 0)]),
                ir.IntType(32))
            val = self.llvmgen.builder.ptrtoint(
                self.llvmgen.builder.gep(variable.backing_value,
                                         [ir.Constant(ir.IntType(32), 1)]),
                ir.IntType(32))
            size = self.llvmgen.builder.sub(val, base)
            name = "unknown"
        elif variable.is_array:
            if variable.is_constant_sized_array:
                ty = variable.raw_llvm_type
                size = get_size(ty.element) * ty.count
                size = Int32(size)
                name = f"{ty.element}[{ty.count}]"
            else:
                value = variable.raw_backing_value
                size = get_size(value.type.element)
                size = self.llvmgen.gen_multiplication(
                    Int32(size),
                    self.llvmgen.gen_load_if_necessary(value.type.count))
                name = f"{value.type.element}[{value.type.count}]"
        elif variable.raw_llvm_type == variable.raw_backing_value.type:
            size = Int32(get_size(variable.raw_llvm_type))
            name = f"{variable.rial_type}"
        else:
            # This is worst case as it cannot be optimized away.
            base = self.llvmgen.builder.ptrtoint(
                self.llvmgen.builder.gep(variable.backing_value,
                                         [ir.Constant(ir.IntType(32), 0)]),
                ir.IntType(32))
            val = self.llvmgen.builder.ptrtoint(
                self.llvmgen.builder.gep(variable.backing_value,
                                         [ir.Constant(ir.IntType(32), 1)]),
                ir.IntType(32))
            size = self.llvmgen.builder.sub(val, base)
            name = "unknown"

        return RIALVariable(f"sizeof_{name}", "Int32", size)
コード例 #11
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
    def gen_global(self, name: str, value: Optional[ir.Constant], ty: Type, access_modifier: RIALAccessModifier,
                   linkage: str,
                   constant: bool):
        rial_variable = ParserState.module().get_rial_variable(name)

        if rial_variable is not None:
            return rial_variable.backing_value

        glob = ir.GlobalVariable(ParserState.module(), ty, name=name)
        glob.linkage = linkage
        glob.global_constant = constant

        if value is not None:
            glob.initializer = value

        rial_variable = RIALVariable(name, map_llvm_to_type(ty), glob,
                                     access_modifier)
        ParserState.module().global_variables.append(rial_variable)

        return glob
コード例 #12
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
    def declare_variable(self, identifier: str, value) -> Optional[AllocaInstr]:
        variable = self.current_block.get_named_value(identifier)
        if variable is not None:
            return None

        if isinstance(value, AllocaInstr) or isinstance(value, PointerType):
            variable = value
            variable.name = identifier
        elif isinstance(value, CastInstr) and value.opname == "inttoptr":
            variable = self.builder.alloca(value.type.pointee)
            variable.name = identifier
            rial_type = f"{map_llvm_to_type(value.type)}"
            variable.set_metadata('type',
                                  ParserState.module().add_metadata((rial_type,)))
            self.builder.store(self.builder.load(value), variable)
        elif isinstance(value, FormattedConstant):
            variable = self.builder.alloca(value.type.pointee)
            variable.name = identifier
            rial_type = f"{map_llvm_to_type(value.type)}"
            variable.set_metadata('type',
                                  ParserState.module().add_metadata((rial_type,)))
            self.builder.store(self.builder.load(value), variable)
        elif isinstance(value, Constant):
            variable = self.builder.alloca(value.type)
            variable.name = identifier
            rial_type = f"{map_llvm_to_type(value.type)}"
            variable.set_metadata('type',
                                  ParserState.module().add_metadata((rial_type,)))
            self.builder.store(value, variable)
        else:
            variable = self.builder.alloca(value.type)
            variable.name = identifier
            rial_type = f"{map_llvm_to_type(value.type)}"
            variable.set_metadata('type', ParserState.module().add_metadata((rial_type,)))
            self.builder.store(value, variable)

        self.current_block.add_named_value(identifier, variable)

        return variable
コード例 #13
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
    def get_definition(self, identifier: str):
        variable = self.get_exact_definition(identifier)

        # Search with module specifier
        if variable is None:
            if ':' in identifier:
                parts = identifier.split(':')
                module_name = ':'.join(parts[0:-1])

                if CompilationManager.check_module_already_compiled(module_name):
                    return None

                if ParserState.add_dependency_and_wait(module_name):
                    return self.get_definition(identifier)

                return None

        return variable
コード例 #14
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
    def create_in_global_ctor(self):
        current_block = self.current_block
        current_func = self.current_func
        current_struct = self.current_struct
        conditional_block = self.conditional_block
        end_block = self.end_block
        pos = self.builder is not None and self.builder._anchor or 0

        func = ParserState.module().get_global_safe('global_ctor')

        if func is None:
            func_type = self.create_function_type(ir.VoidType(), [], False)
            func = self.create_function_with_type('global_ctor', 'global_ctor', func_type, "internal", "ccc",
                                                  FunctionDefinition('void'))
            self.create_function_body(func, [])
            struct_type = ir.LiteralStructType([ir.IntType(32), func_type.as_pointer(), ir.IntType(8).as_pointer()])
            glob_value = ir.Constant(ir.ArrayType(struct_type, 1), [ir.Constant.literal_struct(
                [ir.Constant(ir.IntType(32), 65535), func, NULL])])
            glob_type = ir.ArrayType(struct_type, 1)

            self.gen_global("llvm.global_ctors", glob_value, glob_type, RIALAccessModifier.PRIVATE, "appending", False)
        else:
            self.builder.position_before(func.entry_basic_block.terminator)
            self.current_func = func
            self.current_block = create_llvm_block(func.entry_basic_block)

        self.current_struct = None
        self.conditional_block = None
        self.end_block = None

        yield

        self.finish_current_block()
        self.finish_current_func()

        self.current_block = current_block
        self.current_func = current_func
        self.current_struct = current_struct
        self.conditional_block = conditional_block
        self.end_block = end_block
        self.builder._anchor = pos
        self.builder._block = self.current_block is not None and self.current_block.block or None

        return
コード例 #15
0
    def array_constructor(self, tree: Tree):
        nodes = tree.children
        name = nodes[0].value
        number: RIALVariable = self.transform_helper(nodes[1])

        if isinstance(number.raw_backing_value, ir.Constant):
            number = number.raw_backing_value.constant
        else:
            number = number.raw_backing_value

        ty = ParserState.map_type_to_llvm_no_pointer(name)
        arr_type = ir.ArrayType(ty, number)

        allocated = self.llvmgen.builder.alloca(arr_type)

        return RIALVariable(
            f"array_{name}[{number}]",
            f"{name}[{isinstance(number, int) and f'{number}' or ''}]",
            allocated)
コード例 #16
0
    def struct_decl(self, tree: Tree):
        nodes = tree.children
        node = nodes[0]
        full_name = node.metadata['struct_name']
        function_decls = node.metadata['functions']

        struct = ParserState.search_structs(full_name)

        if struct is None:
            raise KeyError(
                f"Expected a struct {full_name} but couldn't find it!")

        self.llvmgen.current_struct = struct

        # Create functions
        for function_decl in function_decls:
            self.visit(function_decl)

        self.llvmgen.finish_struct()
コード例 #17
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
    def create_identified_struct(self, name: str, linkage: str,
                                 rial_access_modifier: RIALAccessModifier,
                                 base_llvm_structs: List[RIALIdentifiedStructType],
                                 body: List[RIALVariable]) -> RIALIdentifiedStructType:
        # Build normal struct and switch out with RIALStruct
        struct = ParserState.module().context.get_identified_type(name)
        rial_struct = RIALIdentifiedStructType(struct.context, struct.name, struct.packed)
        ParserState.module().context.identified_types[struct.name] = rial_struct
        struct = rial_struct
        ParserState.module().structs.append(struct)

        # Create metadata definition
        struct_def = StructDefinition(rial_access_modifier)

        # Build body and body definition
        props_def = dict()
        props = list()
        prop_offset = 0
        for deriv in base_llvm_structs:
            for prop in deriv.definition.properties.values():
                props.append(ParserState.map_type_to_llvm(prop[1].rial_type))
                props_def[prop[1].name] = (prop_offset, prop[1])
                prop_offset += 1

            struct_def.base_structs.append(deriv.name)
        for bod in body:
            props.append(ParserState.map_type_to_llvm(bod.rial_type))
            props_def[bod.name] = (prop_offset, bod)
            prop_offset += 1

        struct.set_body(*tuple(props))
        struct.module_name = ParserState.module().name
        self.current_struct = struct

        struct_def.properties = props_def

        # Store def in metadata
        struct.definition = struct_def

        return struct
コード例 #18
0
    def cast(self, tree: Tree):
        nodes = tree.children
        ty = ParserState.map_type_to_llvm_no_pointer(nodes[0])
        value: RIALVariable = self.transform_helper(nodes[1])

        if is_builtin_type(nodes[0]):
            # Simple cast for primitive to primitive
            if value.is_primitive:
                cast_function = get_casting_function(value.raw_llvm_type, ty)

                if hasattr(self.llvmgen.builder, cast_function):
                    casted = getattr(self.llvmgen.builder,
                                     cast_function)(value.raw_backing_value,
                                                    ty)
                else:
                    raise TypeError(
                        f"No casting function found for casting {value.rial_type} to {nodes[0]}"
                    )
            else:
                # Casting type to integer ("pointer") (unsafe!)
                with only_allowed_in_unsafe():
                    casted = self.llvmgen.builder.ptrtoint(
                        value.backing_value, ty)
        else:
            # Casting integer to type (unsafe!)
            if value.is_primitive:
                with only_allowed_in_unsafe():
                    casted = self.llvmgen.builder.inttoptr(
                        value.raw_backing_value, ty.as_pointer())
            else:
                # Simple type cast
                casted = self.llvmgen.builder.bitcast(value.backing_value,
                                                      ty.as_pointer())

        return RIALVariable(f"cast_{value.rial_type}_to_{nodes[0]}", nodes[0],
                            casted)
コード例 #19
0
def main(options):
    start = timer()

    # Monkey patch functions in
    monkey_patch()

    init()
    ParserState.init()

    if options.profile_mem:
        import tracemalloc
        tracemalloc.start()
        start_snapshot = tracemalloc.take_snapshot()

    set_profiling(options.profile)

    self_dir = __file__.replace("main.py", "")
    project_path = str(os.path.abspath(options.workdir))
    project_name = project_path.split('/')[-1]

    source_path = Path(os.path.join(project_path, "src"))
    cache_path = Path(os.path.join(project_path, "cache"))
    output_path = Path(os.path.join(project_path, "output"))
    bin_path = Path(os.path.join(project_path, "bin"))

    cache_path.mkdir(parents=False, exist_ok=True)

    if output_path.exists():
        shutil.rmtree(output_path)

    output_path.mkdir(parents=False, exist_ok=False)

    if bin_path.exists():
        shutil.rmtree(bin_path)

    bin_path.mkdir(parents=False, exist_ok=False)

    if not source_path.exists():
        raise FileNotFoundError(str(source_path))

    config = Configuration(project_name, source_path, cache_path, output_path,
                           bin_path, Path(self_dir), options)
    CompilationManager.init(config)

    compiler()

    end = timer()

    if options.profile:
        print("----- PROFILING -----")
        total = 0
        for event in execution_events:
            print(event)
            total += event.time_taken_seconds
        print(f"TOTAL : {(end - start).__round__(3)}s")
        print("")

    if options.profile_mem:
        import tracemalloc
        end_snapshot = tracemalloc.take_snapshot()
        display_top(end_snapshot)
コード例 #20
0
 def raw_llvm_type(self):
     from rial.ParserState import ParserState
     return ParserState.map_type_to_llvm_no_pointer(self.rial_type)
コード例 #21
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)
コード例 #22
0
    def nested_function_call(self, tree: Tree):
        nodes = tree.children
        i = 0
        full_name = ""
        arguments = list()
        while i < len(nodes):
            if not isinstance(nodes[i], Token):
                break

            full_name += f".{nodes[i].value}"
            i += 1

        implicit_parameter_name = '.'.join(full_name.split('.')[0:-1])
        function_name = full_name.split('.')[-1]
        implicit_parameter: RIALVariable = self.llvmgen.get_definition(
            implicit_parameter_name)

        if implicit_parameter is None:
            log_fail(
                f"Could not find implicit parameter {implicit_parameter_name} in function call {full_name}"
            )
            return NULL

        arguments.append(implicit_parameter)
        arguments.extend(self.transform_helper(nodes[i]))

        arg_types = [arg.llvm_type for arg in arguments]
        mangled_names = list()

        # Generate mangled names for implicit parameter and derived
        if implicit_parameter is not None:
            ty = implicit_parameter.rial_type

            # Check if it's a builtin type
            if ty in ParserState.builtin_types:
                mangled_names.append(
                    mangle_function_name(function_name, arg_types, ty))
            else:
                mangled_names.append(
                    mangle_function_name(function_name, arg_types, ty))

                struct = ParserState.find_struct(ty)

                # Also mangle base structs to see if it's a derived function
                for base_struct in struct.definition.base_structs:
                    arg_tys = arg_types
                    arg_tys.pop(0)
                    arg_tys.insert(0, base_struct)
                    mangled_names.append(
                        mangle_function_name(function_name, arg_types,
                                             base_struct))
        else:
            mangled_names.append(mangle_function_name(function_name,
                                                      arg_types))

        try:
            call_instr = self.llvmgen.gen_function_call(
                [*mangled_names, function_name],
                [arg.backing_value for arg in arguments])

            if call_instr is None:
                log_fail(
                    f"Failed to generate call to function {function_name}")
                return NULL

            rial_func = call_instr.callee

            if isinstance(rial_func, RIALFunction):
                return RIALVariable(f"{rial_func.name}_call",
                                    rial_func.definition.rial_return_type,
                                    call_instr)
            return RIALVariable(f"{rial_func.name}_call", "Unknown",
                                call_instr)
        except IndexError:
            log_fail(
                f"Missing argument in function call to function {function_name}"
            )

        return NULL
コード例 #23
0
def only_allowed_in_unsafe():
    if not ParserState.llvmgen().currently_unsafe:
        raise PermissionError()
コード例 #24
0
ファイル: compiler.py プロジェクト: mingtaoy/RIAL
def compile_file(path: str):
    global exceptions
    try:
        last_modified = os.path.getmtime(path)
        filename = CompilationManager.filename_from_path(path)

        if check_cache(path):
            CompilationManager.finish_file(path)
            CompilationManager.files_to_compile.task_done()
            return

        module_name = CompilationManager.mod_name_from_path(filename)
        module = CompilationManager.codegen.get_module(
            module_name, filename, str(CompilationManager.config.source_path))
        ParserState.set_module(module)
        ParserState.set_llvmgen(LLVMGen())

        if not ParserState.module().name.startswith(
                "rial:builtin:always_imported"):
            ParserState.module().dependencies.extend(
                CompilationManager.always_imported)

        # Remove the current module in case it's in the always imported list
        if module_name in ParserState.module().dependencies:
            ParserState.module().dependencies.remove(module_name)

        with run_with_profiling(filename, ExecutionStep.READ_FILE):
            with open(path, "r") as file:
                contents = file.read()

        desugar_transformer = DesugarTransformer()
        primitive_transformer = PrimitiveASTTransformer()
        parser = Lark_StandAlone(postlex=Postlexer())

        # Parse the file
        with run_with_profiling(filename, ExecutionStep.PARSE_FILE):
            try:
                ast = parser.parse(contents)
            except Exception as e:
                log_fail(f"Exception when parsing {filename}")
                log_fail(e)
                exceptions = True
                CompilationManager.finish_file(path)
                CompilationManager.files_to_compile.task_done()
                return

        if CompilationManager.config.raw_opts.print_tokens:
            print(ast.pretty())

        # Generate primitive IR (things we don't need other modules for)
        with run_with_profiling(filename, ExecutionStep.GEN_IR):
            ast = desugar_transformer.transform(ast)
            ast = primitive_transformer.transform(ast)

        struct_declaration_transformer = StructDeclarationTransformer()
        function_declaration_transformer = FunctionDeclarationTransformer()
        global_declaration_transformer = GlobalDeclarationTransformer()
        transformer = ASTVisitor()

        with run_with_profiling(filename, ExecutionStep.GEN_IR):
            ast = struct_declaration_transformer.visit(ast)

            if ast is not None:
                ast = function_declaration_transformer.visit(ast)

            if ast is not None:
                ast = global_declaration_transformer.visit(ast)

            # Declarations are all already collected so we can move on.
            CompilationManager.modules[str(path)] = ParserState.module()
            CompilationManager.finish_file(path)

            if ast is not None:
                transformer.visit(ast)

        cache_path = str(CompilationManager.get_cache_path_str(path)).replace(
            ".rial", ".cache")
        if Path(cache_path).exists(
        ) and CompilationManager.config.raw_opts.disable_cache:
            os.remove(cache_path)
        elif not CompilationManager.config.raw_opts.disable_cache:
            Cache.cache_module(ParserState.module(), path, cache_path,
                               last_modified)

        CompilationManager.files_to_compile.task_done()
    except Exception as e:
        log_fail("Internal Compiler Error: ")
        log_fail(traceback.format_exc())
        exceptions = True
        CompilationManager.finish_file(path)
        CompilationManager.files_to_compile.task_done()
コード例 #25
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
    def gen_function_call(self, possible_function_names: List[str],
                          llvm_args: List) -> Optional[CallInstr]:
        func = None
        # Check if it's actually a local variable
        for function_name in possible_function_names:
            var = self.get_definition(function_name)

            if var is not None:
                func = var

        # Try to find by function name
        if func is None:
            for function_name in possible_function_names:
                func = ParserState.find_function(function_name)

                if func is not None:
                    break

        # Try to find by function name but enable canonical name
        if func is None:
            rial_arg_types = [map_llvm_to_type(arg.type) for arg in llvm_args]

            for function_name in possible_function_names:
                func = ParserState.find_function(function_name, rial_arg_types)

                if func is not None:
                    break

        if func is None:
            return None

        if isinstance(func, RIALVariable):
            func = func.backing_value

        if isinstance(func, ir.PointerType) and isinstance(func.pointee, RIALFunction):
            func = func.pointee
        elif isinstance(func, GlobalVariable) or isinstance(func, AllocaInstr):
            loaded_func = self.builder.load(func)
            call = self.builder.call(loaded_func, llvm_args)
            return call

        # Check if call is allowed
        if not self.check_function_call_allowed(func):
            raise PermissionError(f"Tried calling function {func.name} from {self.current_func.name}")

        # Check if function is declared in current module
        if ParserState.module().get_global_safe(func.name) is None:
            func = self.create_function_with_type(func.name, func.canonical_name, func.function_type, func.linkage,
                                                  func.calling_convention, func.definition)

        args = list()

        # Gen a load if necessary
        for i, arg in enumerate(llvm_args):
            llvm_arg = func.definition.rial_args[i].llvm_type

            if llvm_arg == arg.type:
                args.append(arg)
                continue

            args.append(self.builder.load(arg))

        # Check type matching
        for i, arg in enumerate(args):
            if len(func.args) > i and arg.type != func.args[i].type:
                # Check for base types
                ty = isinstance(arg.type, PointerType) and arg.type.pointee or arg.type
                func_arg_type = isinstance(func.args[i].type, PointerType) and func.args[i].type.pointee or func.args[
                    i].type

                if isinstance(ty, RIALIdentifiedStructType):
                    struct = ParserState.find_struct(ty.name)

                    if struct is not None:
                        found = False

                        # Check if a base struct matches the type expected
                        # TODO: Recursive check
                        for base_struct in struct.definition.base_structs:
                            if base_struct == func_arg_type.name:
                                args.remove(arg)
                                args.insert(i, self.builder.bitcast(arg, ir.PointerType(base_struct)))
                                found = True
                                break
                        if found:
                            continue

                    # TODO: SLOC information
                raise TypeError(
                    f"Function {func.name} expects a {func.args[i].type} but got a {arg.type}")

        # Gen call
        return self.builder.call(func, args)
コード例 #26
0
 def __init__(self):
     super().__init__()
     self.llvmgen = ParserState.llvmgen()
コード例 #27
0
ファイル: LLVMGen.py プロジェクト: mingtaoy/RIAL
    def _get_by_identifier(self, identifier: str, variable: Optional = None) -> Optional:
        if isinstance(variable, RIALVariable):
            variable = variable.backing_value

        if not variable is None and hasattr(variable, 'type') and isinstance(variable.type, PointerType):
            if isinstance(variable.type.pointee, RIALIdentifiedStructType):
                struct = ParserState.find_struct(variable.type.pointee.name)

                if struct is None:
                    return None

                if not self.check_struct_access_allowed(struct):
                    raise PermissionError(f"Tried accesssing struct {struct.name}")

                prop = struct.definition.properties[identifier]

                if prop is None:
                    return None

                # Check property access
                if not self.check_property_access_allowed(struct, prop[1]):
                    raise PermissionError(f"Tried to access property {prop[1].name} but it was not allowed!")

                variable = self.builder.gep(variable, [ir.Constant(ir.IntType(32), 0),
                                                       ir.Constant(ir.IntType(32), prop[0])])
        else:
            # Search local variables
            variable = self.current_block.get_named_value(identifier)

            # Search for a global variable
            if variable is None:
                glob = ParserState.find_global(identifier)

                # Check if in same module
                if glob is not None:
                    if glob.backing_value.parent.name != ParserState.module().name:
                        glob_current_module = ParserState.module().get_global_safe(glob.name)

                        if glob_current_module is not None:
                            variable = glob_current_module
                        else:
                            # TODO: Check if global access is allowed
                            variable = self.gen_global(glob.name, None, glob.backing_value.type.pointee,
                                                       glob.access_modifier, "external",
                                                       glob.backing_value.global_constant)
                    else:
                        variable = glob.backing_value

        # If variable is none, just do a full function search
        if variable is None:
            variable = ParserState.find_function(identifier)

            if variable is None:
                variable = ParserState.find_function(mangle_function_name(identifier, []))

            # Check if in same module
            if variable is not None:
                if variable.module.name != ParserState.module().name:
                    variable_current_module = ParserState.module().get_global_safe(variable.name)

                    if variable_current_module is not None:
                        variable = variable_current_module
                    else:
                        variable = self.create_function_with_type(variable.name, variable.name, variable.function_type,
                                                                  variable.linkage,
                                                                  variable.calling_convention,
                                                                  variable.definition)

        return variable
コード例 #28
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)
コード例 #29
0
 def __init__(self):
     super().__init__()
     self.llvmgen = ParserState.llvmgen()
     self.fdt = FunctionDeclarationTransformer()
コード例 #30
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)