diff --git a/src/backend/c-lisp.py b/src/backend/c-lisp.py index ba5c708..6b00556 100755 --- a/src/backend/c-lisp.py +++ b/src/backend/c-lisp.py @@ -2,6 +2,7 @@ import json import sys from utils.random import random_label +from utils.shape import verify_shape CLISP_PREFIX = "tmp_clisp" @@ -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): @@ -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): @@ -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) @@ -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( @@ -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]] @@ -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]] ) @@ -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 @@ -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])] @@ -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), diff --git a/src/backend/tests/c-lisp/errors/alloc-bad.out b/src/backend/tests/c-lisp/errors/alloc-bad.out new file mode 100644 index 0000000..b9e99d8 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/alloc-bad.out @@ -0,0 +1,2 @@ +Error in statement: ['set', 'arr', ['alloc', 3]] +CodegenError: Bad alloc expression: ['alloc', 3] diff --git a/src/backend/tests/c-lisp/errors/alloc-bad.sexp b/src/backend/tests/c-lisp/errors/alloc-bad.sexp new file mode 100644 index 0000000..33adc4a --- /dev/null +++ b/src/backend/tests/c-lisp/errors/alloc-bad.sexp @@ -0,0 +1,4 @@ +(c-lisp + (define ((main void)) + (declare arr (ptr float)) + (set arr (alloc 3)))) diff --git a/src/backend/tests/c-lisp/errors/bad-expression.out b/src/backend/tests/c-lisp/errors/bad-expression.out new file mode 100644 index 0000000..07c8b50 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/bad-expression.out @@ -0,0 +1,2 @@ +Error in statement: ['while', [True], ['call', 'print', 4]] +CodegenError: Bad expression: [True] diff --git a/src/backend/tests/c-lisp/errors/bad-expression.sexp b/src/backend/tests/c-lisp/errors/bad-expression.sexp new file mode 100644 index 0000000..a0a6e04 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/bad-expression.sexp @@ -0,0 +1,4 @@ +(c-lisp + (define ((main int)) + (while (#t) + (call print 4)))) diff --git a/src/backend/tests/c-lisp/errors/declare-bad.out b/src/backend/tests/c-lisp/errors/declare-bad.out new file mode 100644 index 0000000..c1aba82 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/declare-bad.out @@ -0,0 +1,2 @@ +Error in statement: ['declare', 'a'] +CodegenError: Bad declare statement: ['declare', 'a'] diff --git a/src/backend/tests/c-lisp/errors/declare-bad.sexp b/src/backend/tests/c-lisp/errors/declare-bad.sexp new file mode 100644 index 0000000..361879e --- /dev/null +++ b/src/backend/tests/c-lisp/errors/declare-bad.sexp @@ -0,0 +1,4 @@ +(c-lisp + (define ((main void)) + (declare a) + (call print a))) diff --git a/src/backend/tests/c-lisp/errors/fixed-op-count-1.out b/src/backend/tests/c-lisp/errors/fixed-op-count-1.out new file mode 100644 index 0000000..4cef219 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/fixed-op-count-1.out @@ -0,0 +1,2 @@ +Error in statement: ['ret', ['not', True, False]] +CodegenError: `not` takes only 1 operands: ['not', True, False] diff --git a/src/backend/tests/c-lisp/errors/fixed-op-count-1.sexp b/src/backend/tests/c-lisp/errors/fixed-op-count-1.sexp new file mode 100644 index 0000000..bc9e359 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/fixed-op-count-1.sexp @@ -0,0 +1,3 @@ +(c-lisp + (define ((main bool)) + (ret (not #t #f)))) diff --git a/src/backend/tests/c-lisp/errors/fixed-op-count-2.out b/src/backend/tests/c-lisp/errors/fixed-op-count-2.out new file mode 100644 index 0000000..ee48f23 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/fixed-op-count-2.out @@ -0,0 +1,2 @@ +Error in statement: ['ret', ['add', 3, 4, 5]] +CodegenError: `add` takes only 2 operands: ['add', 3, 4, 5] diff --git a/src/backend/tests/c-lisp/errors/fixed-op-count-2.sexp b/src/backend/tests/c-lisp/errors/fixed-op-count-2.sexp new file mode 100644 index 0000000..41334c0 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/fixed-op-count-2.sexp @@ -0,0 +1,3 @@ +(c-lisp + (define ((main int)) + (ret (add 3 4 5)))) diff --git a/src/backend/tests/c-lisp/errors/fn-proto-bad.out b/src/backend/tests/c-lisp/errors/fn-proto-bad.out new file mode 100644 index 0000000..7dabea7 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/fn-proto-bad.out @@ -0,0 +1 @@ +CodegenError: Bad function prototype: ['main', 'int'] diff --git a/src/backend/tests/c-lisp/errors/fn-proto-bad.sexp b/src/backend/tests/c-lisp/errors/fn-proto-bad.sexp new file mode 100644 index 0000000..e5019ad --- /dev/null +++ b/src/backend/tests/c-lisp/errors/fn-proto-bad.sexp @@ -0,0 +1,3 @@ +(c-lisp + (define (main int) + (ret 0))) diff --git a/src/backend/tests/c-lisp/errors/for-bad.out b/src/backend/tests/c-lisp/errors/for-bad.out new file mode 100644 index 0000000..6824c13 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/for-bad.out @@ -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']]] diff --git a/src/backend/tests/c-lisp/errors/for-bad.sexp b/src/backend/tests/c-lisp/errors/for-bad.sexp new file mode 100644 index 0000000..f1f1d34 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/for-bad.sexp @@ -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))))) diff --git a/src/backend/tests/c-lisp/errors/if-bad.out b/src/backend/tests/c-lisp/errors/if-bad.out new file mode 100644 index 0000000..e2e33f0 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/if-bad.out @@ -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]] diff --git a/src/backend/tests/c-lisp/errors/if-bad.sexp b/src/backend/tests/c-lisp/errors/if-bad.sexp new file mode 100644 index 0000000..6021cd0 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/if-bad.sexp @@ -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)))) diff --git a/src/backend/tests/c-lisp/errors/load-bad.out b/src/backend/tests/c-lisp/errors/load-bad.out new file mode 100644 index 0000000..963ebb9 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/load-bad.out @@ -0,0 +1,2 @@ +Error in statement: ['load', 'argv', 'a'] +CodegenError: Bad load expression: ['load', 'argv', 'a'] diff --git a/src/backend/tests/c-lisp/errors/load-bad.sexp b/src/backend/tests/c-lisp/errors/load-bad.sexp new file mode 100644 index 0000000..76c394e --- /dev/null +++ b/src/backend/tests/c-lisp/errors/load-bad.sexp @@ -0,0 +1,4 @@ +(c-lisp + (define ((main void) (argc int) (argv (ptr (ptr int)))) + (declare a (ptr int)) + (load argv a))) diff --git a/src/backend/tests/c-lisp/errors/not-clisp.out b/src/backend/tests/c-lisp/errors/not-clisp.out new file mode 100644 index 0000000..c5cd791 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/not-clisp.out @@ -0,0 +1 @@ +CodegenError: Input not a C-Lisp program diff --git a/src/backend/tests/c-lisp/errors/not-clisp.sexp b/src/backend/tests/c-lisp/errors/not-clisp.sexp new file mode 100644 index 0000000..d38802c --- /dev/null +++ b/src/backend/tests/c-lisp/errors/not-clisp.sexp @@ -0,0 +1,3 @@ +(brilisp + (define ((main int)) + (ret 0))) diff --git a/src/backend/tests/c-lisp/errors/not-function.out b/src/backend/tests/c-lisp/errors/not-function.out new file mode 100644 index 0000000..e5695c3 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/not-function.out @@ -0,0 +1 @@ +CodegenError: Not a function: ['declare', 'a', 'int'] diff --git a/src/backend/tests/c-lisp/errors/not-function.sexp b/src/backend/tests/c-lisp/errors/not-function.sexp new file mode 100644 index 0000000..0c65d85 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/not-function.sexp @@ -0,0 +1,4 @@ +(c-lisp + (declare a int) + (set a 5) + (return a)) diff --git a/src/backend/tests/c-lisp/errors/ptradd-bad.out b/src/backend/tests/c-lisp/errors/ptradd-bad.out new file mode 100644 index 0000000..3dcf006 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/ptradd-bad.out @@ -0,0 +1,2 @@ +Error in statement: ['call', 'print', ['ptradd', 'arr', 4, 3]] +CodegenError: Bad ptradd expression: ['ptradd', 'arr', 4, 3] diff --git a/src/backend/tests/c-lisp/errors/ptradd-bad.sexp b/src/backend/tests/c-lisp/errors/ptradd-bad.sexp new file mode 100644 index 0000000..066a1df --- /dev/null +++ b/src/backend/tests/c-lisp/errors/ptradd-bad.sexp @@ -0,0 +1,5 @@ +(c-lisp + (define ((main int)) + (declare arr (ptr int)) + (set arr (alloc int 20)) + (call print (ptradd arr 4 3)))) diff --git a/src/backend/tests/c-lisp/errors/redeclare.out b/src/backend/tests/c-lisp/errors/redeclare.out new file mode 100644 index 0000000..6814420 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/redeclare.out @@ -0,0 +1,2 @@ +Error in statement: ['declare', 'var', 'bool'] +CodegenError: Re-declaration of variable var diff --git a/src/backend/tests/c-lisp/errors/redeclare.sexp b/src/backend/tests/c-lisp/errors/redeclare.sexp new file mode 100644 index 0000000..9d1dac6 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/redeclare.sexp @@ -0,0 +1,9 @@ +(c-lisp + (define ((main void)) + (declare var int) + + (if #t + ((declare var float) + (set var 0.5))) + + (declare var bool))) diff --git a/src/backend/tests/c-lisp/errors/ret-bad.out b/src/backend/tests/c-lisp/errors/ret-bad.out new file mode 100644 index 0000000..74c3607 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/ret-bad.out @@ -0,0 +1,2 @@ +Error in statement: ['ret', 0, 1] +CodegenError: Return statement can contain only 1 optional return value: ['ret', 0, 1] diff --git a/src/backend/tests/c-lisp/errors/ret-bad.sexp b/src/backend/tests/c-lisp/errors/ret-bad.sexp new file mode 100644 index 0000000..b0687ee --- /dev/null +++ b/src/backend/tests/c-lisp/errors/ret-bad.sexp @@ -0,0 +1,3 @@ +(c-lisp + (define ((main int)) + (ret 0 1))) diff --git a/src/backend/tests/c-lisp/errors/scope.out b/src/backend/tests/c-lisp/errors/scope.out new file mode 100644 index 0000000..ff124d4 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/scope.out @@ -0,0 +1,2 @@ +Error in statement: ['call', 'print', 'val'] +CodegenError: Undeclared symbol: val diff --git a/src/backend/tests/c-lisp/errors/scope.sexp b/src/backend/tests/c-lisp/errors/scope.sexp new file mode 100644 index 0000000..a42ed8f --- /dev/null +++ b/src/backend/tests/c-lisp/errors/scope.sexp @@ -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))) diff --git a/src/backend/tests/c-lisp/errors/set-bad.out b/src/backend/tests/c-lisp/errors/set-bad.out new file mode 100644 index 0000000..d8a3ca3 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/set-bad.out @@ -0,0 +1,2 @@ +Error in statement: ['set', ['declare', 'var', 'int'], 4] +CodegenError: Bad set expression: ['set', ['declare', 'var', 'int'], 4] diff --git a/src/backend/tests/c-lisp/errors/set-bad.sexp b/src/backend/tests/c-lisp/errors/set-bad.sexp new file mode 100644 index 0000000..876d9e3 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/set-bad.sexp @@ -0,0 +1,3 @@ +(c-lisp + (define ((main int)) + (set (declare var int) 4))) diff --git a/src/backend/tests/c-lisp/errors/store-bad.out b/src/backend/tests/c-lisp/errors/store-bad.out new file mode 100644 index 0000000..eeb1d1c --- /dev/null +++ b/src/backend/tests/c-lisp/errors/store-bad.out @@ -0,0 +1,2 @@ +Error in statement: ['store', 'a', 5, 6, 7] +CodegenError: Bad store expression: ['store', 'a', 5, 6, 7] diff --git a/src/backend/tests/c-lisp/errors/store-bad.sexp b/src/backend/tests/c-lisp/errors/store-bad.sexp new file mode 100644 index 0000000..30e268b --- /dev/null +++ b/src/backend/tests/c-lisp/errors/store-bad.sexp @@ -0,0 +1,5 @@ +(c-lisp + (define ((main void)) + (declare a (ptr int)) + (set a (alloc int 3)) + (store a 5 6 7))) diff --git a/src/backend/tests/c-lisp/errors/turnt.toml b/src/backend/tests/c-lisp/errors/turnt.toml new file mode 100644 index 0000000..0a7454e --- /dev/null +++ b/src/backend/tests/c-lisp/errors/turnt.toml @@ -0,0 +1 @@ +command = "guile ../../../utils/sexp-json.scm < {filename} | python ../../../c-lisp.py 2>&1 | sed -e '/^[ (Traceback)]/d'" diff --git a/src/backend/tests/c-lisp/errors/undeclared-fn.out b/src/backend/tests/c-lisp/errors/undeclared-fn.out new file mode 100644 index 0000000..1f38ce8 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/undeclared-fn.out @@ -0,0 +1,2 @@ +Error in statement: ['call', 'print', 4] +CodegenError: Call to undeclared function: print diff --git a/src/backend/tests/c-lisp/errors/undeclared-fn.sexp b/src/backend/tests/c-lisp/errors/undeclared-fn.sexp new file mode 100644 index 0000000..eeac15a --- /dev/null +++ b/src/backend/tests/c-lisp/errors/undeclared-fn.sexp @@ -0,0 +1,3 @@ +(c-lisp + (define ((main int)) + (call print 4))) diff --git a/src/backend/tests/c-lisp/errors/undeclared-var.out b/src/backend/tests/c-lisp/errors/undeclared-var.out new file mode 100644 index 0000000..29c1e34 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/undeclared-var.out @@ -0,0 +1,2 @@ +Error in statement: ['set', 'var', 5] +CodegenError: Undeclared symbol: var diff --git a/src/backend/tests/c-lisp/errors/undeclared-var.sexp b/src/backend/tests/c-lisp/errors/undeclared-var.sexp new file mode 100644 index 0000000..e6d7e80 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/undeclared-var.sexp @@ -0,0 +1,4 @@ +(c-lisp + (define ((main int)) + (set var 5) + (ret var))) diff --git a/src/backend/tests/c-lisp/errors/while-bad.out b/src/backend/tests/c-lisp/errors/while-bad.out new file mode 100644 index 0000000..3d9e5ce --- /dev/null +++ b/src/backend/tests/c-lisp/errors/while-bad.out @@ -0,0 +1,2 @@ +Error in statement: ['while', ['call', 'print', 5]] +CodegenError: Bad while statement: ['while', ['call', 'print', 5]] diff --git a/src/backend/tests/c-lisp/errors/while-bad.sexp b/src/backend/tests/c-lisp/errors/while-bad.sexp new file mode 100644 index 0000000..c768f34 --- /dev/null +++ b/src/backend/tests/c-lisp/errors/while-bad.sexp @@ -0,0 +1,4 @@ +(c-lisp + (define ((main int)) + (while + (call print 5)))) diff --git a/src/backend/tests/c-lisp/for-return.out b/src/backend/tests/c-lisp/for-return.out new file mode 100644 index 0000000..de2df04 --- /dev/null +++ b/src/backend/tests/c-lisp/for-return.out @@ -0,0 +1,3 @@ +12 +-2 +-1 diff --git a/src/backend/tests/c-lisp/for-return.sexp b/src/backend/tests/c-lisp/for-return.sexp new file mode 100644 index 0000000..43e35d3 --- /dev/null +++ b/src/backend/tests/c-lisp/for-return.sexp @@ -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))) diff --git a/src/backend/utils/shape.py b/src/backend/utils/shape.py new file mode 100644 index 0000000..d8590bd --- /dev/null +++ b/src/backend/utils/shape.py @@ -0,0 +1,17 @@ +def verify_shape(obj, template): + """ + Verify the shape of `lst` with `template`. + For example, ["set", "a", 5] has shape [str, str, int]. + `None` can be used as a wildcard; so ["set", "a", ["add", 5, 1]] matches [str, str, None] + """ + if template is None: + return True + elif not isinstance(template, list): + return isinstance(obj, template) + else: + if not isinstance(obj, list): + return False + for c in range(len(obj)): + if not verify_shape(obj[c], template[c]): + return False + return True