def type(self, params): if len(params) == 1: return VariableType(VariableTypeEnum.UNKNOWN, params[0].value) elif len(params) == 3: assert params[0].value == "[" and params[2].value == "]" return VariableType( VariableTypeEnum.ARRAY, array_type=VariableType(VariableTypeEnum.UNKNOWN, type_name=params[1].value), )
def get_type_from_string(global_scope: GlobalScope, type_name: str) -> VariableType: # int is just an alias for i64 if type_name == "int": type_name = "i64" if type_name == "i64": return primitive(PrimitiveType.I64) elif type_name == "i32": return primitive(PrimitiveType.I32) elif type_name == "i16": return primitive(PrimitiveType.I16) elif type_name == "i8": return primitive(PrimitiveType.I8) elif type_name == "u64": return primitive(PrimitiveType.U64) elif type_name == "u32": return primitive(PrimitiveType.U32) elif type_name == "u16": return primitive(PrimitiveType.U16) elif type_name == "u8": return primitive(PrimitiveType.U8) elif type_name == "float": return primitive(PrimitiveType.FLOAT) elif type_name == "string": return primitive(PrimitiveType.STRING) elif type_name == "bool": return primitive(PrimitiveType.BOOL) elif type_name in global_scope.structs: return VariableType(VariableTypeEnum.STRUCT, type_name=type_name) else: raise Exception(f"Unknown type: {type_name}")
def boolean_literal(self, value): return Constant( VariableType(VariableTypeEnum.UNKNOWN), ParseContext(value), ConstantType.BOOL, value.value == "true", )
def string_literal(self, value): return Constant( VariableType(VariableTypeEnum.UNKNOWN), ParseContext(value), ConstantType.STRING, value.value[1:-1], )
def integer_constant(self, value): return Constant( VariableType(VariableTypeEnum.UNKNOWN), ParseContext(value), ConstantType.INTEGER, int(value.value), )
def mul_div_expr(self, op1, operator, op2): return MathOperation( VariableType(VariableTypeEnum.UNKNOWN), op1.context, op1, op2, operator.value, )
def compare_expr(self, op1, operator, op2): return CompareOperation( VariableType(VariableTypeEnum.UNKNOWN), op1.context, op1, op2, operator.value, )
def typeify(base_type: VariableType, global_scope: GlobalScope): if base_type.variable_type == VariableTypeEnum.ARRAY: assert base_type.array_type assert base_type.array_type.type_name assert base_type.array_type.variable_type == VariableTypeEnum.UNKNOWN base_type.array_type = get_type_from_string( global_scope, base_type.array_type.type_name) elif base_type.variable_type == VariableTypeEnum.UNKNOWN: assert base_type.type_name base_type = get_type_from_string(global_scope, base_type.type_name) else: raise InternalCompilerError("Unhandled type in struct validation pass") return base_type
def var_access(self, variable, *args): assert len(args) in range(0, 3) if len(args) == 2: array_access, variable_access = args[0].expression, args[1] elif len(args) == 0: array_access, variable_access = None, None elif isinstance(args[0], VariableAccess): array_access, variable_access = None, args[0] else: array_access, variable_access = args[0].expression, None return VariableAccess( VariableType(VariableTypeEnum.UNKNOWN), ParseContext(variable), variable.value, array_access, variable_access, )
def primitive(primitive_type: PrimitiveType) -> VariableType: return VariableType(VariableTypeEnum.PRIMITIVE, primitive_type=primitive_type)
def expression(self, expression: BaseExpression): if isinstance(expression, FunctionCall): expression.type = self.function_call(expression) elif isinstance(expression, VariableAccess): variable_type = self.scope_stack.get_variable_type( expression.variable_name) if not variable_type: raise ContextException( f"Unknown variable: {expression.variable_name}", expression.context) # handle array access if expression.array_access is not None: expression_type = self.array_access(variable_type, expression.array_access) else: expression_type = variable_type # handle struct access if expression.variable_access is not None: expression_type = self.struct_access( expression_type, expression.variable_access) expression.type = expression_type elif isinstance(expression, Constant): if expression.constant_type == ConstantType.STRING: expression.type = VariableType( VariableTypeEnum.PRIMITIVE, primitive_type=PrimitiveType.STRING) elif expression.constant_type == ConstantType.FLOAT: expression.type = VariableType( VariableTypeEnum.PRIMITIVE, primitive_type=PrimitiveType.FLOAT) elif expression.constant_type == ConstantType.BOOL: expression.type = VariableType( VariableTypeEnum.PRIMITIVE, primitive_type=PrimitiveType.BOOL) elif expression.constant_type == ConstantType.INTEGER: expression.type = primitive_type_from_constant( expression.value) else: raise InternalCompilerError("Unknown constant type") elif isinstance(expression, MathOperation): operand1_type = self.expression(expression.operand1) operand2_type = self.expression(expression.operand2) if is_type_compatible(operand1_type, operand2_type): expression.type = operand1_type elif is_type_compatible(operand2_type, operand1_type): expression.type = operand2_type else: raise Exception("Incompatible type in operator expressions") elif isinstance(expression, CompareOperation): operand1_type = self.expression(expression.operand1) operand2_type = self.expression(expression.operand2) if not is_type_compatible(operand1_type, operand2_type) or not is_type_compatible( operand2_type, operand1_type): raise TypeMismatchException("Operands cannot be compared", expression.context) expression.type = VariableType(VariableTypeEnum.PRIMITIVE, primitive_type=PrimitiveType.BOOL) else: raise InternalCompilerError("Unknown expression") return expression.type