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
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)