slowly fixing bugs and writing a math library

This commit is contained in:
SpookyDervish
2025-10-19 10:32:33 +11:00
parent 4bd698e330
commit 4370dc4407
5 changed files with 154 additions and 79 deletions

View File

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

27
ir.ll
View File

@@ -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"

View File

@@ -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)
print(f"\n\nProgram returned: {result}\n=== Executed in {round((et - st) * 1000, 6)} ms. ===")
#exit(result)

View File

@@ -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);
}

View File

@@ -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;
}
}