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
def not_rule(self, nodes): return Tree('equal', [ nodes[0], Token('EQUAL', '=='), RIALVariable("number", "Int1", ir.IntType(1), ir.Constant(ir.IntType(1), 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()
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)
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 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