Skip to content

Commit

Permalink
Merge pull request #49 from GlowingScrewdriver/enhancements
Browse files Browse the repository at this point in the history
Explicit return generation and error handling
  • Loading branch information
chsasank authored Jun 28, 2024
2 parents 7f05b7e + 856ec94 commit 1e6d6ac
Show file tree
Hide file tree
Showing 45 changed files with 268 additions and 23 deletions.
89 changes: 66 additions & 23 deletions src/backend/c-lisp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
import sys
from utils.random import random_label
from utils.shape import verify_shape

CLISP_PREFIX = "tmp_clisp"

Expand Down Expand Up @@ -87,10 +88,53 @@ def gen_function(self, func):
parm_types.append(parm[1])
self.symbol_types[parm[0]] = parm[1]
self.function_types[name] = [ret_type, parm_types]

# If the function has a body, we need to codegen for it
if len(func) > 2:
# Set up a return label and a return variable, if needed
self.ret_ptr_sym, ret_label, ret_alloc_size_sym, ret_val_sym = [
random_label(CLISP_PREFIX, [extra])
for extra in ("ret_ptr", "ret_lbl", "ret_alloc", "ret_val")
]
self.ret_jmp_instr = ["jmp", ret_label]
if ret_type != "void":
# Function returns something, so we have to maintain a return variable
ret_alloc_instrs = [
# Allocate space for the return variable
["set", [ret_alloc_size_sym, "int"], ["const", 1]],
[
"set",
[self.ret_ptr_sym, ["ptr", ret_type]],
["alloc", ret_alloc_size_sym],
],
]
ret_label_instrs = [
# Load the return variable and return it.
# Control jumps here for function return.
["label", ret_label],
["set", [ret_val_sym, ret_type], ["load", self.ret_ptr_sym]],
["ret", ret_val_sym],
]
else:
# No return value, so no need to maintain a return variable
ret_alloc_instrs = []
ret_label_instrs = [["label", ret_label], ["ret"]]

body_instrs = [
*ret_alloc_instrs,
*self.gen_compound_stmt(
func[2:], new_scope=False
), # C-Lisp function body
*ret_label_instrs,
]
else:
# This is a declaration without a body
body_instrs = []

return [
"define",
func[1],
*self.gen_compound_stmt(func[2:], new_scope=False),
*body_instrs,
]

def gen_stmt(self, stmt):
Expand All @@ -115,7 +159,7 @@ def gen_stmt(self, stmt):
else:
return self.gen_expr(stmt)
except Exception as e:
print(f"Error in statement: {stmt}")
print(f"Error in statement: {stmt}", file=sys.stderr)
raise e

def is_while_stmt(self, stmt):
Expand Down Expand Up @@ -219,7 +263,7 @@ def is_decl_stmt(self, stmt):

def gen_decl_stmt(self, stmt):
if not len(stmt) == 3:
raise CodegenError(f"bad declare statement: {stmt}")
raise CodegenError(f"Bad declare statement: {stmt}")

name, typ = stmt[1], stmt[2]
scoped_name = self.construct_scoped_name(name, self.scopes)
Expand All @@ -233,11 +277,14 @@ def is_ret_stmt(self, stmt):

def gen_ret_stmt(self, stmt):
if len(stmt) == 1:
return [["ret"]]
return [self.ret_jmp_instr]
elif len(stmt) == 2:
res_sym = random_label(CLISP_PREFIX)
instr_list = self.gen_expr(stmt[1], res_sym=res_sym)
instr_list.append(["ret", res_sym])
instr_list = [
*self.gen_expr(stmt[1], res_sym=res_sym),
["store", self.ret_ptr_sym, res_sym],
self.ret_jmp_instr,
]
return instr_list
else:
raise CodegenError(
Expand All @@ -262,11 +309,11 @@ def is_set_expr(self, expr):
return expr[0] == "set"

def gen_set_expr(self, expr, res_sym):
if not verify_shape(expr, [str, str, None]):
raise CodegenError(f"Bad set expression: {expr}")

name = expr[1]
scoped_name = self.scoped_lookup(name)
if not scoped_name in self.symbol_types:
raise CodegenError(f"Cannot set undeclared variable: {name}")

instr_list = self.gen_expr(expr[2], res_sym=res_sym)
instr_list.append(
["set", [scoped_name, self.symbol_types[scoped_name]], ["id", res_sym]]
Expand Down Expand Up @@ -300,6 +347,8 @@ def gen_call_expr(self, expr, res_sym):
arg_syms.append(arg_sym)
instr_list += self.gen_expr(arg, res_sym=arg_sym)
name = expr[1]
if name not in self.function_types:
raise CodegenError(f"Call to undeclared function: {name}")
instr_list.append(
["set", [res_sym, self.function_types[name][0]], ["call", name, *arg_syms]]
)
Expand All @@ -310,14 +359,11 @@ def is_var_expr(self, expr):

def gen_var_expr(self, expr, res_sym):
scoped_name = self.scoped_lookup(expr)
if scoped_name in self.symbol_types:
typ = self.symbol_types[scoped_name]
instr_list = [["set", [res_sym, typ], ["id", scoped_name]]]
if typ[0] == "ptr":
self.pointer_types[res_sym] = typ
return instr_list
else:
raise CodegenError(f"Reference to undeclared variable: {expr}")
typ = self.symbol_types[scoped_name]
instr_list = [["set", [res_sym, typ], ["id", scoped_name]]]
if typ[0] == "ptr":
self.pointer_types[res_sym] = typ
return instr_list

def is_fixed_type_expr(self, expr):
return expr[0] in self.fixed_op_types
Expand All @@ -327,10 +373,8 @@ def gen_fixed_type_expr(self, expr, res_sym):
opcode = expr[0]
typ, n_ops = self.fixed_op_types[opcode]
if not (len(expr) == n_ops + 1):
raise CodegenError(f"`{opcode}` takes only 2 operands: {expr}")
in_syms = [
random_label(CLISP_PREFIX, [f"inp_{n}"]) for n in range(n_ops)
]
raise CodegenError(f"`{opcode}` takes only {n_ops} operands: {expr}")
in_syms = [random_label(CLISP_PREFIX, [f"inp_{n}"]) for n in range(n_ops)]
input_instrs = []
for n in range(n_ops):
input_instrs += [*self.gen_expr(expr[n + 1], in_syms[n])]
Expand Down Expand Up @@ -376,8 +420,7 @@ def gen_store_expr(self, expr, res_sym):
raise CodegenError(f"Bad store expression: {expr}")

val_sym, ptr_sym = [
random_label(CLISP_PREFIX, [extra])
for extra in ("val", "ptr")
random_label(CLISP_PREFIX, [extra]) for extra in ("val", "ptr")
]
return [
*self.gen_expr(expr[1], res_sym=ptr_sym),
Expand Down
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/alloc-bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['set', 'arr', ['alloc', 3]]
CodegenError: Bad alloc expression: ['alloc', 3]
4 changes: 4 additions & 0 deletions src/backend/tests/c-lisp/errors/alloc-bad.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(c-lisp
(define ((main void))
(declare arr (ptr float))
(set arr (alloc 3))))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/bad-expression.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['while', [True], ['call', 'print', 4]]
CodegenError: Bad expression: [True]
4 changes: 4 additions & 0 deletions src/backend/tests/c-lisp/errors/bad-expression.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(c-lisp
(define ((main int))
(while (#t)
(call print 4))))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/declare-bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['declare', 'a']
CodegenError: Bad declare statement: ['declare', 'a']
4 changes: 4 additions & 0 deletions src/backend/tests/c-lisp/errors/declare-bad.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(c-lisp
(define ((main void))
(declare a)
(call print a)))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/fixed-op-count-1.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['ret', ['not', True, False]]
CodegenError: `not` takes only 1 operands: ['not', True, False]
3 changes: 3 additions & 0 deletions src/backend/tests/c-lisp/errors/fixed-op-count-1.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(c-lisp
(define ((main bool))
(ret (not #t #f))))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/fixed-op-count-2.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['ret', ['add', 3, 4, 5]]
CodegenError: `add` takes only 2 operands: ['add', 3, 4, 5]
3 changes: 3 additions & 0 deletions src/backend/tests/c-lisp/errors/fixed-op-count-2.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(c-lisp
(define ((main int))
(ret (add 3 4 5))))
1 change: 1 addition & 0 deletions src/backend/tests/c-lisp/errors/fn-proto-bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CodegenError: Bad function prototype: ['main', 'int']
3 changes: 3 additions & 0 deletions src/backend/tests/c-lisp/errors/fn-proto-bad.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(c-lisp
(define (main int)
(ret 0)))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/for-bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['for', [['lt', 'i', 10], ['set', ['add', 'i', 1]], ['call', 'print', 'i']]]
CodegenError: Bad for statement: ['for', [['lt', 'i', 10], ['set', ['add', 'i', 1]], ['call', 'print', 'i']]]
6 changes: 6 additions & 0 deletions src/backend/tests/c-lisp/errors/for-bad.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
(c-lisp
(define ((main void))
(declare i int)
(set i 0)
(for ((lt i 10) (set (add i 1))
(call print i)))))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/if-bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['if', True, ['call', 'print', 5], ['call', 'print', 4], ['call', 'print', 3]]
CodegenError: Bad if statement: ['if', True, ['call', 'print', 5], ['call', 'print', 4], ['call', 'print', 3]]
8 changes: 8 additions & 0 deletions src/backend/tests/c-lisp/errors/if-bad.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
(c-lisp
(define ((print int) (n int)))

(define ((main void))
(if #t
(call print 5)
(call print 4)
(call print 3))))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/load-bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['load', 'argv', 'a']
CodegenError: Bad load expression: ['load', 'argv', 'a']
4 changes: 4 additions & 0 deletions src/backend/tests/c-lisp/errors/load-bad.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(c-lisp
(define ((main void) (argc int) (argv (ptr (ptr int))))
(declare a (ptr int))
(load argv a)))
1 change: 1 addition & 0 deletions src/backend/tests/c-lisp/errors/not-clisp.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CodegenError: Input not a C-Lisp program
3 changes: 3 additions & 0 deletions src/backend/tests/c-lisp/errors/not-clisp.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(brilisp
(define ((main int))
(ret 0)))
1 change: 1 addition & 0 deletions src/backend/tests/c-lisp/errors/not-function.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CodegenError: Not a function: ['declare', 'a', 'int']
4 changes: 4 additions & 0 deletions src/backend/tests/c-lisp/errors/not-function.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(c-lisp
(declare a int)
(set a 5)
(return a))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/ptradd-bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['call', 'print', ['ptradd', 'arr', 4, 3]]
CodegenError: Bad ptradd expression: ['ptradd', 'arr', 4, 3]
5 changes: 5 additions & 0 deletions src/backend/tests/c-lisp/errors/ptradd-bad.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(c-lisp
(define ((main int))
(declare arr (ptr int))
(set arr (alloc int 20))
(call print (ptradd arr 4 3))))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/redeclare.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['declare', 'var', 'bool']
CodegenError: Re-declaration of variable var
9 changes: 9 additions & 0 deletions src/backend/tests/c-lisp/errors/redeclare.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
(c-lisp
(define ((main void))
(declare var int)

(if #t
((declare var float)
(set var 0.5)))

(declare var bool)))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/ret-bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['ret', 0, 1]
CodegenError: Return statement can contain only 1 optional return value: ['ret', 0, 1]
3 changes: 3 additions & 0 deletions src/backend/tests/c-lisp/errors/ret-bad.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(c-lisp
(define ((main int))
(ret 0 1)))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/scope.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['call', 'print', 'val']
CodegenError: Undeclared symbol: val
15 changes: 15 additions & 0 deletions src/backend/tests/c-lisp/errors/scope.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
(c-lisp
(define ((print int) (n int)))

(define ((main void))
(declare i int)

(for ((set i 0)
(lt i 100)
(set i (add i 1)))
(declare val int)
(if (eq
i
(mul (div i 7) 7))
(set val i)))
(call print val)))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/set-bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['set', ['declare', 'var', 'int'], 4]
CodegenError: Bad set expression: ['set', ['declare', 'var', 'int'], 4]
3 changes: 3 additions & 0 deletions src/backend/tests/c-lisp/errors/set-bad.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(c-lisp
(define ((main int))
(set (declare var int) 4)))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/store-bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['store', 'a', 5, 6, 7]
CodegenError: Bad store expression: ['store', 'a', 5, 6, 7]
5 changes: 5 additions & 0 deletions src/backend/tests/c-lisp/errors/store-bad.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(c-lisp
(define ((main void))
(declare a (ptr int))
(set a (alloc int 3))
(store a 5 6 7)))
1 change: 1 addition & 0 deletions src/backend/tests/c-lisp/errors/turnt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
command = "guile ../../../utils/sexp-json.scm < {filename} | python ../../../c-lisp.py 2>&1 | sed -e '/^[ (Traceback)]/d'"
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/undeclared-fn.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['call', 'print', 4]
CodegenError: Call to undeclared function: print
3 changes: 3 additions & 0 deletions src/backend/tests/c-lisp/errors/undeclared-fn.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(c-lisp
(define ((main int))
(call print 4)))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/undeclared-var.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['set', 'var', 5]
CodegenError: Undeclared symbol: var
4 changes: 4 additions & 0 deletions src/backend/tests/c-lisp/errors/undeclared-var.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(c-lisp
(define ((main int))
(set var 5)
(ret var)))
2 changes: 2 additions & 0 deletions src/backend/tests/c-lisp/errors/while-bad.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error in statement: ['while', ['call', 'print', 5]]
CodegenError: Bad while statement: ['while', ['call', 'print', 5]]
4 changes: 4 additions & 0 deletions src/backend/tests/c-lisp/errors/while-bad.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(c-lisp
(define ((main int))
(while
(call print 5))))
3 changes: 3 additions & 0 deletions src/backend/tests/c-lisp/for-return.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
12
-2
-1
47 changes: 47 additions & 0 deletions src/backend/tests/c-lisp/for-return.sexp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
(c-lisp
(define ((print int) (n int)))

(define ((cons void) (arr (ptr int)) (n int))
(declare i int)
(for ((set i 0)
(lt i n)
(set i (add i 1)))
(store
(ptradd arr i)
(mul i 3))))

(define ((find int) (arr (ptr int)) (key int) (n int))
(declare i int)
(for ((set i 0)
(lt i n)
(set i (add i 1)))
(if (eq key
(load (ptradd arr i)))
(ret i))))

(define ((verify int) (arr (ptr int)) (key int) (idx int) (len int))
(declare val int)
(if (lt idx len)
((set val (load (ptradd arr idx)))
(if (eq val key)
(ret val)
(ret -1)))
(ret -2)))

(define ((main void))
(declare input (ptr int))
(declare i int)

(set input (alloc int 10))
(call cons input 10)

(declare 12-idx int)
(declare 13-idx int)

(set 12-idx (call find input 12 10))
(set 13-idx (call find input 13 10))

(call print (call verify input 12 12-idx 10))
(call print (call verify input 13 13-idx 10))
(call print (call verify input 12 2 10))
(ret)))
Loading

0 comments on commit 1e6d6ac

Please sign in to comment.