From 4370dc44070fc47a1f36c5c73e198614be8298a5 Mon Sep 17 00:00:00 2001 From: SpookyDervish <78246495+SpookyDervish@users.noreply.github.com> Date: Sun, 19 Oct 2025 10:32:33 +1100 Subject: [PATCH] slowly fixing bugs and writing a math library --- compiler.py | 176 +++++++++++++++++++++++++++++++++++-------------- ir.ll | 27 -------- main.py | 4 +- tests/math.pla | 19 ++++++ tests/test.pla | 7 +- 5 files changed, 154 insertions(+), 79 deletions(-) delete mode 100644 ir.ll diff --git a/compiler.py b/compiler.py index 7733604..d696427 100644 --- a/compiler.py +++ b/compiler.py @@ -27,10 +27,6 @@ class Compiler: "String": ir.PointerType(ir.IntType(8)), "Nil": ir.VoidType() } - self.py_type_map: dict[str, type] = { - "Int": int, - "Float": float - } self.module: ir.Module = ir.Module("main") self.builder: ir.IRBuilder = ir.IRBuilder() @@ -55,13 +51,14 @@ class Compiler: ) return ir.Function(self.module, fnty, "printf") - def __init_sqrt() -> ir.Function: + def __init_pow() -> ir.Function: fnty: ir.FunctionType = ir.FunctionType( self.type_map["Float"], - [ir.DoubleType()], + [ir.DoubleType(), ir.DoubleType()], var_arg=False ) - return ir.Function(self.module, fnty, "sqrt") + self.environment.define("pow", ir.Function(self.module, fnty, "pow"), ir.IntType(32)) + def __init_booleans() -> tuple[ir.GlobalVariable, ir.GlobalVariable]: bool_type: ir.Type = self.type_map["Bool"] @@ -74,14 +71,12 @@ class Compiler: false_var.initializer = ir.Constant(bool_type, 0) false_var.global_constant = True - return true_var, false_var + self.environment.define("true", true_var, true_var.type) + self.environment.define("false", false_var, false_var.type) self.environment.define("print", __init_print(), ir.IntType(32)) - self.environment.define("sqrt", __init_sqrt(), ir.IntType(32)) - - true_var, false_var = __init_booleans() - self.environment.define("true", true_var, true_var.type) - self.environment.define("false", false_var, false_var.type) + __init_booleans() + __init_pow() def __increment_counter(self) -> int: self.counter += 1 @@ -138,19 +133,24 @@ class Compiler: def __visit_assignment_statement(self, node: AssignmentStatement) -> None: name: str = node.name.value value: Expression = node.value - value_type: str = node.value_type # TODO: implemented + value_type = self.type_map[node.value_type] # TODO: implemented - value, Type = self.__resolve_value(node=value) + print(value.json()) + value, Type = self.__resolve_value(value) if self.environment.lookup(name) is None: # Define and allocate the new variable - ptr = self.builder.alloca(Type) + ptr = self.builder.alloca(value_type) # Storing the value to the ptr - self.builder.store(value, ptr) + if isinstance(value_type, ir.DoubleType) and isinstance(Type, ir.IntType): + self.builder.store(self.builder.sitofp(value, value_type), ptr) + else: + print(value_type, Type, value_type) + self.builder.store(value, ptr) # Add the variable to the environment - self.environment.define(name, ptr, Type) + self.environment.define(name, ptr, value_type) else: ptr, _ = self.environment.lookup(name) self.builder.store(value, ptr) @@ -226,11 +226,11 @@ class Compiler: var_ptr, _ = self.environment.lookup(name) orig_value = self.builder.load(var_ptr) - if isinstance(orig_value.type, ir.IntType) and isinstance(right_type, ir.FloatType): - orig_value = self.builder.sitofp(orig_value, ir.FloatType()) + if isinstance(orig_value.type, ir.IntType) and isinstance(right_type, ir.DoubleType): + orig_value = self.builder.sitofp(orig_value, ir.DoubleType()) - if isinstance(orig_value.type, ir.FloatType) and isinstance(right_type, ir.IntType): - right_value = self.builder.sitofp(right_value, ir.FloatType()) + if isinstance(orig_value.type, ir.DoubleType) and isinstance(right_type, ir.IntType): + right_value = self.builder.sitofp(right_value, ir.DoubleType()) value = None Type = None @@ -396,6 +396,7 @@ class Compiler: value = None Type = None + if isinstance(right_type, ir.IntType) and isinstance(left_type, ir.IntType): Type = self.type_map["Int"] match operator: @@ -409,9 +410,6 @@ class Compiler: value = self.builder.sdiv(left_value, right_value) case "%": value = self.builder.srem(left_value, right_value) - case "^": - # TODO - pass case "<": value = self.builder.icmp_signed('<', left_value, right_value) Type = ir.IntType(1) @@ -430,7 +428,7 @@ class Compiler: case "!=": value = self.builder.icmp_signed('!=', left_value, right_value) Type = ir.IntType(1) - elif isinstance(right_type, ir.FloatType) and isinstance(left_type, ir.FloatType): + elif isinstance(right_type, ir.DoubleType) and isinstance(left_type, ir.DoubleType): Type = self.type_map["Float"] match operator: case "+": @@ -443,9 +441,6 @@ class Compiler: value = self.builder.fdiv(left_value, right_value) case "%": value = self.builder.frem(left_value, right_value) - case "^": - # TODO - pass case "<": value = self.builder.fcmp_ordered('<', left_value, right_value) Type = ir.IntType(1) @@ -464,6 +459,68 @@ class Compiler: case "!=": value = self.builder.fcmp_ordered('!=', left_value, right_value) Type = ir.IntType(1) + elif isinstance(right_type, ir.IntType) and isinstance(left_type, ir.DoubleType): + Type = self.type_map["Float"] + match operator: + case "+": + value = self.builder.fadd(left_value, self.builder.sitofp(right_value, ir.DoubleType())) + case "-": + value = self.builder.fsub(left_value, self.builder.sitofp(right_value, ir.DoubleType())) + case "*": + value = self.builder.fmul(left_value, self.builder.sitofp(right_value, ir.DoubleType())) + case "/": + value = self.builder.fdiv(left_value, self.builder.sitofp(right_value, ir.DoubleType())) + case "%": + value = self.builder.frem(left_value, self.builder.sitofp(right_value, ir.DoubleType())) + case "<": + value = self.builder.fcmp_ordered('<', left_value, self.builder.sitofp(right_value, ir.DoubleType())) + Type = ir.IntType(1) + case "<=": + value = self.builder.fcmp_ordered('<=', left_value, self.builder.sitofp(right_value, ir.DoubleType())) + Type = ir.IntType(1) + case ">": + value = self.builder.fcmp_ordered('>', left_value, self.builder.sitofp(right_value, ir.DoubleType())) + Type = ir.IntType(1) + case ">=": + value = self.builder.fcmp_ordered('>=', left_value, self.builder.sitofp(right_value, ir.DoubleType())) + Type = ir.IntType(1) + case "==": + value = self.builder.fcmp_ordered('==', left_value, self.builder.sitofp(right_value, ir.DoubleType())) + Type = ir.IntType(1) + case "!=": + value = self.builder.fcmp_ordered('!=', left_value, self.builder.sitofp(right_value, ir.DoubleType())) + Type = ir.IntType(1) + elif isinstance(right_type, ir.DoubleType) and isinstance(left_type, ir.IntType): + Type = self.type_map["Float"] + match operator: + case "+": + value = self.builder.fadd(self.builder.sitofp(left_value, ir.DoubleType()), right_value) + case "-": + value = self.builder.fsub(self.builder.sitofp(left_value, ir.DoubleType()), right_value) + case "*": + value = self.builder.fmul(self.builder.sitofp(left_value, ir.DoubleType()), right_value) + case "/": + value = self.builder.fdiv(self.builder.sitofp(left_value, ir.DoubleType()), right_value) + case "%": + value = self.builder.frem(self.builder.sitofp(left_value, ir.DoubleType()), right_value) + case "<": + value = self.builder.fcmp_ordered('<', self.builder.sitofp(left_value, ir.DoubleType()), right_value) + Type = ir.IntType(1) + case "<=": + value = self.builder.fcmp_ordered('<=', self.builder.sitofp(left_value, ir.DoubleType()), right_value) + Type = ir.IntType(1) + case ">": + value = self.builder.fcmp_ordered('>', self.builder.sitofp(left_value, ir.DoubleType()), right_value) + Type = ir.IntType(1) + case ">=": + value = self.builder.fcmp_ordered('>=', self.builder.sitofp(left_value, ir.DoubleType()), right_value) + Type = ir.IntType(1) + case "==": + value = self.builder.fcmp_ordered('==', self.builder.sitofp(left_value, ir.DoubleType()), right_value) + Type = ir.IntType(1) + case "!=": + value = self.builder.fcmp_ordered('!=', self.builder.sitofp(left_value, ir.DoubleType()), right_value) + Type = ir.IntType(1) return value, Type @@ -483,8 +540,8 @@ class Compiler: case "print": ret = self.builtin_print(params=args, return_type=types[0]) ret_type = self.type_map["Int"] - case "sqrt": - ret = self.builtin_sqrt(params=args) + case "pow": + ret = self.builtin_pow(params=args) ret_type = self.type_map["Float"] case _: if not self.environment.lookup(name): @@ -505,11 +562,11 @@ class Compiler: Type = None value = None - if isinstance(right_type, ir.FloatType): - Type = ir.FloatType + if isinstance(right_type, ir.DoubleType): + Type = ir.DoubleType match operator: case "-": - value = self.builder.fmul(right_value, ir.Constant(ir.FloatType(), -1.0)) + value = self.builder.fmul(right_value, ir.Constant(ir.DoubleType(), -1.0)) case "!": value = ir.Constant(ir.IntType(1), 0) elif isinstance(right_type, ir.IntType): @@ -538,13 +595,13 @@ class Compiler: case "++": if isinstance(orig_value.type, ir.IntType): value = self.builder.add(orig_value, ir.Constant(ir.IntType(32), 1)) - elif isinstance(orig_value.type, ir.FloatType): - value = self.builder.fadd(orig_value, ir.Constant(ir.FloatType(), 1.0)) + elif isinstance(orig_value.type, ir.DoubleType): + value = self.builder.fadd(orig_value, ir.Constant(ir.DoubleType(), 1.0)) case "--": if isinstance(orig_value.type, ir.IntType): value = self.builder.sub(orig_value, ir.Constant(ir.IntType(32), 1)) - elif isinstance(orig_value.type, ir.FloatType): - value = self.builder.fsub(orig_value, ir.Constant(ir.FloatType(), 1.0)) + elif isinstance(orig_value.type, ir.DoubleType): + value = self.builder.fsub(orig_value, ir.Constant(ir.DoubleType(), 1.0)) self.builder.store(value, var_ptr) # endregion @@ -564,7 +621,13 @@ class Compiler: return ir.Constant(Type, value), Type case NodeType.IdentifierLiteral: node: IdentifierLiteral = node - ptr, Type = self.environment.lookup(node.value) + + idk = self.environment.lookup(node.value) + if not idk: + print(f"\"{node.value}\" is not defined in the current scope.") + exit(1) + + ptr, Type = idk return self.builder.load(ptr), Type case NodeType.BooleanLiteral: node: BooleanLiteral = node @@ -616,18 +679,35 @@ class Compiler: fmt_arg = self.builder.bitcast(self.module.get_global(f"__str_{self.counter}"), ir.IntType(8).as_pointer()) return self.builder.call(func, [fmt_arg, *rest_params]) - def builtin_sqrt(self, params: list[ir.Instruction]) -> None: - func, _ = self.environment.lookup("sqrt") + def builtin_pow(self, params: list[ir.Instruction]) -> None: + func, _ = self.environment.lookup("pow") - c_float = self.builder.alloca(self.type_map["Float"]) - self.builder.store(params[0], c_float) + rest_params = params[1:] - if isinstance(params[0], ir.LoadInstr): + if isinstance(params[0], ir.LoadInstr) and not isinstance(params[1], ir.LoadInstr): + # printing from a variable load instruction c_fmt: ir.LoadInstr = params[0] g_var_ptr = c_fmt.operands[0] - float_val = self.builder.load(g_var_ptr) - return self.builder.call(func, [float_val]) - else: - return self.builder.call(func, [params[0]]) + val = self.builder.load(g_var_ptr) + return self.builder.call(func, [val, *rest_params]) + if isinstance(params[1], ir.LoadInstr) and not isinstance(params[0], ir.LoadInstr): + # printing from a variable load instruction + c_fmt: ir.LoadInstr = params[1] + g_var_ptr = c_fmt.operands[1] + val = self.builder.load(g_var_ptr) + return self.builder.call(func, [val, *rest_params]) + if isinstance(params[0], ir.LoadInstr) and isinstance(params[1], ir.LoadInstr): + # printing from a variable load instruction + c_fmt: ir.LoadInstr = params[0] + g_var_ptr = c_fmt.operands[0] + val = self.builder.load(g_var_ptr) + + c_fmt2: ir.LoadInstr = params[1] + g_var_ptr2 = c_fmt2.operands[1] + val2 = self.builder.load(g_var_ptr2) + + return self.builder.call(func, [val, val2]) + + return self.builder.call(func, params) # endregion # endregion \ No newline at end of file diff --git a/ir.ll b/ir.ll deleted file mode 100644 index 7d7c042..0000000 --- a/ir.ll +++ /dev/null @@ -1,27 +0,0 @@ -; ModuleID = "main" -target triple = "x86_64-pc-windows-msvc" -target datalayout = "" - -declare i32 @"printf"(i8* %".1", ...) - -declare double @"sqrt"(double %".1") - -@"true" = constant i1 1 -@"false" = constant i1 0 -define i32 @"main"() -{ -main_entry: - %".2" = alloca double - store double 0x4010000000000000, double* %".2" - %".4" = call double @"sqrt"(double 0x4010000000000000) - %".5" = alloca double - store double %".4", double* %".5" - %".7" = load double, double* %".5" - %".8" = alloca [5 x i8]* - store [5 x i8]* @"__str_1", [5 x i8]** %".8" - %".10" = bitcast [5 x i8]* @"__str_1" to i8* - %".11" = call i32 (i8*, ...) @"printf"(i8* %".10", double %".7") - ret i32 0 -} - -@"__str_1" = internal constant [5 x i8] c"%f\0a\00\00" \ No newline at end of file diff --git a/main.py b/main.py index 8c0f3bb..1728927 100644 --- a/main.py +++ b/main.py @@ -101,5 +101,5 @@ if __name__ == "__main__": et = time.time() - #print(f"\n\nProgram returned: {result}\n=== Executed in {round((et - st) * 1000, 6)} ms. ===") - exit(result) \ No newline at end of file + print(f"\n\nProgram returned: {result}\n=== Executed in {round((et - st) * 1000, 6)} ms. ===") + #exit(result) \ No newline at end of file diff --git a/tests/math.pla b/tests/math.pla index e69de29..22d5e3e 100644 --- a/tests/math.pla +++ b/tests/math.pla @@ -0,0 +1,19 @@ +pi = Func(): Float { + return 3.141592653589793; +} + +e = Func(): Float { + return 2.718281828459045; +} + +rad = Func(degrees: Float): Float { + return degrees * $pi() / 180; +} + +deg = Func(radians: Float): Float { + return 180 * radians / $pi(); +} + +sqrt = Func(n: Float): Float { + return $pow(n, 0.5); +} \ No newline at end of file diff --git a/tests/test.pla b/tests/test.pla index f6ffb6f..1bdf3e7 100644 --- a/tests/test.pla +++ b/tests/test.pla @@ -1,4 +1,7 @@ +depend "tests/math.pla"; + main = Func(): Int { - $print("%f\n", $sqrt(9.0)); + $print("%f\n", $sqrt(100.0)); return 0; -} \ No newline at end of file +} +