functions basically work now, but they're extremely inneficient

This commit is contained in:
SpookyDervish
2025-09-13 06:26:15 +10:00
parent 865a31827a
commit 170272353c
6 changed files with 74 additions and 66 deletions

View File

@@ -22,4 +22,23 @@ def traceback(code: str, error_type: str, error_message: str, line: Union[int, N
console.print(f"[bold red]{error_type}: {error_message}")
exit(1)
def warning(code: str, warning_msg: str, note: str = None, line: Union[int, None] = None, start_column: Union[int, None] = None, end_column: Union[int, None] = None):
if line != None:
console.print(f"[bold cyan]warning:[/] {warning_msg}\n")
lines = code.split("\n")[line-1:line+2]
console.print(f"{line } > " + lines[0], highlight=False)
if start_column != None and end_column != None:
console.print(" " + (" " * start_column) + "[bold red]" + ("^" * (end_column-start_column+1)))
try:
console.print(f"{line+1} " + lines[1], highlight=False)
console.print(f"{line+2} " + lines[2], highlight=False)
console.print(" ...", highlight=False)
except IndexError: # the file is less than 3 lines i guess
pass
else:
console.print(f"[bold cyan]warning:[/] {warning_msg}")
if note != None:
console.print(f"[bold]note:[/] {note}")

View File

@@ -1,6 +1,7 @@
from ground_ast import RootNode
from typing import Any
from ground_ast import *
from error import warning
class SymbolTable:
@@ -74,7 +75,7 @@ class Generator:
pass
def generate_node(self, node):
self.lines.append(f"; {node}\n\t")
#self.lines.append(f"; {node}\n\t")
node_type = str(type(node))[19:-2]
if not hasattr(self, f"generate_{node_type}"):
raise NotImplementedError(f"Generator has no generate method for {node_type}.")
@@ -83,6 +84,9 @@ class Generator:
def generate(self):
for statement in self.ast.statements:
self.generate_node(statement)
for name, var in self.global_scope.table.items():
if not var["used"]:
warning(self.code, f"warning: \"{name}\" was defined but never used.")
def write(self):
with open(self.output_path + ".asm", "w") as f:

View File

@@ -1,6 +1,6 @@
from generators.generator import Generator, SymbolTable
from ground_ast import *
from error import traceback
from error import traceback, warning
from optimizers.x86_64 import X86_64Optimizer
class X86_64Generator(Generator):
@@ -74,6 +74,8 @@ class X86_64Generator(Generator):
except TypeError as e: # variable doesnt exist
traceback(self.code, "NameError", f"\"{var_name}\" is not defined.")
scope.table[var_name]["used"] = True
return var["type"]
def get_var_pos(self, var_name: str, scope: SymbolTable = None):
@@ -131,12 +133,14 @@ class X86_64Generator(Generator):
self.stack_size += 1
else:
self.push(starting_value, lines)
scope.define(var_name, {"stack_loc": stack_location, "type": var_type})
scope.define(var_name, {"stack_loc": stack_location, "type": var_type, "used": False})
def change_variable(self, lines, var_name: str, new_value, scope: SymbolTable = None):
scope = scope or self.current_var_scope
var_pos = self.get_var_pos(var_name, scope)
old_var_type = scope.table[var_name]["type"]
if isinstance(var_pos, str):
if type(new_value) == IntNode: # we're changing a variable to a number
#lines.append(f"mov QWORD [rsp + {var_pos}], {new_value.value}\n\t")
@@ -213,6 +217,8 @@ class X86_64Generator(Generator):
elif type(new_value) == str: # we're changing a variable to the value of a register
lines.append(f"mov QWORD [rsp + {var_pos}], {new_value}\n\t")
scope.table[var_name]["type"] = IntNode
if scope.table[var_name]["type"] != old_var_type:
warning(self.code, f"Changing the type of \"{var_name}\" at runtime is considered bad practice.")
def generate_LabelDecNode(self, node: LabelDecNode, lines):
self.labels.append(node.name)
@@ -238,10 +244,10 @@ class X86_64Generator(Generator):
except IndexError:
traceback(self.code, "CallError", "Functions with more than 6 args aren't supported yet, sorry...")
self.current_var_scope.define(arg.name, {"stack_loc": stack_loc, "type": self.ground_type_to_node(arg.arg_type)})
self.current_var_scope.define(arg.name, {"stack_loc": stack_loc, "type": self.ground_type_to_node(arg.arg_type), "used": False})
for inst in node.statements:
self.function_lines.append(f"; {inst}\n\t")
#self.function_lines.append(f"; {inst}\n\t")
self.generate_InstructionNode(inst, self.function_lines)
def generate_InstructionNode(self, node: InstructionNode, lines = None):
@@ -253,7 +259,6 @@ class X86_64Generator(Generator):
if not type(node.arguments[0]) in [IntNode, VarRefNode]: # example: "end true"
traceback(self.code, "TypeError", f"end expects an integer, not {node.arguments[0]}")
lines.append("mov rax, 60\n\t")
if type(node.arguments[0]) in [IntNode,BoolNode]:
lines.append("mov rdi, " + str(node.arguments[0].value) + "\n\t")
elif isinstance(node.arguments[0], VarRefNode):
@@ -263,7 +268,8 @@ class X86_64Generator(Generator):
else:
if var_type not in [IntNode,BoolNode]:
traceback(self.code, "TypeError", f"end expects an integer, not \"{var_type}\"")
#lines.append("mov rdi, " + str(self.get_variable(lines, node.arguments[0].var_name)) + "\n\t")
lines.append("mov rax, 60\n\t")
lines.append("syscall\n\t")
### VARIABLE INSTRUCTIONS ###
@@ -516,7 +522,7 @@ class X86_64Generator(Generator):
length = self.add_constant(f"equ $ - {string_pointer[1:-1]}", no_string=True)
lines.append(f"lea rax, [rel {string_pointer[1:-1]}]\n\t")
lines.append(f"lea rdx, {length}\n\t")
lines.append(f"mov rdx, {length[1:-1]}\n\t")
#self.push("rax", lines)
elif isinstance(node.arguments[0], VarRefNode):
var = func_scope.lookup(node.arguments[0].var_name)
@@ -529,9 +535,26 @@ class X86_64Generator(Generator):
else:
lines.append("mov rax, 0\n\t")
for _ in range(self.stack_size): # TODO: THIS IS THE WORST FUCKING BULLSHIT EVER, KILL IT NOW!!!!
self.pop("rbp", lines)
size = 0
for name, var in self.current_var_scope.table.items():
if type(var["stack_loc"]) == str:
continue # its in a register, we dont need to free up the stack
if var["type"] == StringNode:
size += 2
else:
size += 1
lines.append(f"add rsp, {8 * (size)}\n\t")
self.stack_size -= size - 1
lines.append("pop rbp")
lines.append("ret\n\t")
# warn about unused variables
for name, var in self.current_var_scope.table.items():
if not var["used"]:
warning(self.code, f"\"{name}\" was defined but never used.")
old_scope = self.current_var_scope
self.current_var_scope = self.current_var_scope.parent
del old_scope
@@ -549,7 +572,7 @@ class X86_64Generator(Generator):
traceback(self.code, "TypeError", f"Function \"{node.arguments[0].func_name}\" takes {len(func.args)} arguments, but got {len(self.arg_list)}")
# stack alignment
if self.stack_size % 2 == 0:
if self.stack_size % 2 != 0:
lines.append("sub rsp, 8\n\t") # align the stack to 16 bytes
self.stack_size -= 1
@@ -587,8 +610,8 @@ class X86_64Generator(Generator):
traceback(self.code, "CallError", "Functions with more than 6 args aren't supported yet, sorry...")
lines.append(f"call {node.arguments[0].func_name}\n\t")
if len(self.arg_list) > 0:
self.lines.append(f"add rsp, {len(self.arg_list) * 8}")
#if len(self.arg_list) > 0:
# lines.append(f"add rsp, {len(self.arg_list) * 8}")
self.stack_size += len(self.arg_list)
self.arg_list.clear()
@@ -599,7 +622,7 @@ class X86_64Generator(Generator):
if self.current_var_scope.lookup(node.arguments[1].var_name):
self.change_variable(lines, node.arguments[1].var_name, "rax")
else:
self.current_var_scope.define(node.arguments[1].var_name, {"stack_loc": "rax", "type": self.ground_type_to_node(func.return_type)})
self.current_var_scope.define(node.arguments[1].var_name, {"stack_loc": "rax", "type": self.ground_type_to_node(func.return_type), "used": False})
#self.create_variable(lines, node.arguments[1].var_name, "rax", self.ground_type_to_node(self.functions.get(node.arguments[0].func_name)["func"].return_type))
elif node.instruction == "pusharg":
self.clamp_instruction_args(node, 1, 1)

BIN
out Normal file

Binary file not shown.

45
out.asm
View File

@@ -1,52 +1,19 @@
; ~~~ Auto generated by the GroundPY compiler for Linux x86_64 targets. ~~~
section .data
.LC0: db "test of returning strings INSIDE a variable!", 10, 0
.LC1: equ $ - .LC0
section .text
global _start
_start:
; FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, String]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=RootNode(statements=[..., InstructionNode(instruction='endfun', parent=..., arguments=[]), FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Int]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='int', name='function2'), InstructionNode(instruction='endfun', parent=..., arguments=[]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='stdout', parent=..., arguments=[VariableReference]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), return_type='string', name='idk')
; InstructionNode(instruction='endfun', parent=RootNode(statements=[FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, String]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='string', name='idk'), ..., FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Int]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='int', name='function2'), InstructionNode(instruction='endfun', parent=..., arguments=[]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='stdout', parent=..., arguments=[VariableReference]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), arguments=[])
; FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Int]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=RootNode(statements=[FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, String]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='string', name='idk'), InstructionNode(instruction='endfun', parent=..., arguments=[]), ..., InstructionNode(instruction='endfun', parent=..., arguments=[]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='stdout', parent=..., arguments=[VariableReference]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), return_type='int', name='function2')
; InstructionNode(instruction='endfun', parent=RootNode(statements=[FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, String]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='string', name='idk'), InstructionNode(instruction='endfun', parent=..., arguments=[]), FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Int]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='int', name='function2'), ..., InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='stdout', parent=..., arguments=[VariableReference]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), arguments=[])
; InstructionNode(instruction='call', parent=RootNode(statements=[FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, String]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='string', name='idk'), InstructionNode(instruction='endfun', parent=..., arguments=[]), FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Int]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='int', name='function2'), InstructionNode(instruction='endfun', parent=..., arguments=[]), ..., InstructionNode(instruction='stdout', parent=..., arguments=[VariableReference]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), arguments=[FunctionCall, VariablePointer])
sub rsp, 8
call idk
; InstructionNode(instruction='stdout', parent=RootNode(statements=[FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, String]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='string', name='idk'), InstructionNode(instruction='endfun', parent=..., arguments=[]), FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Int]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='int', name='function2'), InstructionNode(instruction='endfun', parent=..., arguments=[]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), ..., InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), arguments=[VariableReference])
mov rsi, rax
push rdi
mov rax, 1
mov rdi, 1
syscall
pop rdi
; InstructionNode(instruction='call', parent=RootNode(statements=[FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, String]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='string', name='idk'), InstructionNode(instruction='endfun', parent=..., arguments=[]), FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Int]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='int', name='function2'), InstructionNode(instruction='endfun', parent=..., arguments=[]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='stdout', parent=..., arguments=[VariableReference]), ..., InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), arguments=[FunctionCall, VariablePointer])
call function2
; InstructionNode(instruction='end', parent=RootNode(statements=[FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, String]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='string', name='idk'), InstructionNode(instruction='endfun', parent=..., arguments=[]), FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Int]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='int', name='function2'), InstructionNode(instruction='endfun', parent=..., arguments=[]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='stdout', parent=..., arguments=[VariableReference]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), ...]), arguments=[VariableReference])
mov rax, 60
mov rsi, 4
call add
mov rdi, rax
mov rax, 60
syscall
idk:
add:
push rbp
mov rbp, rsp
; InstructionNode(instruction='set', parent=FunctionNode(args=[], statements=[..., InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=RootNode(statements=[..., InstructionNode(instruction='endfun', parent=..., arguments=[]), FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Int]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='int', name='function2'), InstructionNode(instruction='endfun', parent=..., arguments=[]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='stdout', parent=..., arguments=[VariableReference]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), return_type='string', name='idk'), arguments=[VariablePointer, String])
lea rax, [.LC0]
push rax
push .LC1
; InstructionNode(instruction='return', parent=FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, String]), ...], parent=RootNode(statements=[..., InstructionNode(instruction='endfun', parent=..., arguments=[]), FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Int]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='int', name='function2'), InstructionNode(instruction='endfun', parent=..., arguments=[]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='stdout', parent=..., arguments=[VariableReference]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), return_type='string', name='idk'), arguments=[VariableReference])
mov rax, [rsp + 8]
mov rdx, [rsp + 0]
pop rbp
pop rbp
pop rbp
ret
function2:
push rbp
mov rbp, rsp
; InstructionNode(instruction='set', parent=FunctionNode(args=[], statements=[..., InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=RootNode(statements=[FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, String]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='string', name='idk'), InstructionNode(instruction='endfun', parent=..., arguments=[]), ..., InstructionNode(instruction='endfun', parent=..., arguments=[]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='stdout', parent=..., arguments=[VariableReference]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), return_type='int', name='function2'), arguments=[VariablePointer, Int])
push 123
; InstructionNode(instruction='return', parent=FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, Int]), ...], parent=RootNode(statements=[FunctionNode(args=[], statements=[InstructionNode(instruction='set', parent=..., arguments=[VariablePointer, String]), InstructionNode(instruction='return', parent=..., arguments=[VariableReference])], parent=..., return_type='string', name='idk'), InstructionNode(instruction='endfun', parent=..., arguments=[]), ..., InstructionNode(instruction='endfun', parent=..., arguments=[]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='stdout', parent=..., arguments=[VariableReference]), InstructionNode(instruction='call', parent=..., arguments=[FunctionCall, VariablePointer]), InstructionNode(instruction='end', parent=..., arguments=[VariableReference])]), return_type='int', name='function2'), arguments=[VariableReference])
mov rax, [rsp + 0]
pop rbp
mov rax, rdi
add rax, rsi
pop rbp
ret

View File

@@ -1,14 +1,9 @@
fun -string !idk
set &var "test of returning strings INSIDE a variable!\n"
return $var
fun -int !add -int &a -int &b
add $a $b &a
return $a
endfun
fun -int !function2
set &intvar 123
return $intvar
endfun
call !idk &var
stdout $var
call !function2 &lol
end $lol
pusharg 1
pusharg 4
call !add &result
end $result