functions basically work now, but they're extremely inneficient
This commit is contained in:
21
error.py
21
error.py
@@ -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}")
|
@@ -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:
|
||||
|
@@ -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)
|
||||
|
45
out.asm
45
out.asm
@@ -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
|
||||
|
19
test2.grnd
19
test2.grnd
@@ -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
|
Reference in New Issue
Block a user