struct Function { ~uint8 name, utils.Vector inputs, outputs, ~parse.Node _up, int call_padding, bool m } /; method Function /; init (~parse.Node n) self.name = utils.strcpy(n`.data) self._up = n self.m = false self.call_padding = 0 Var v self.inputs.init(len v) self.outputs.init(len v) ;/ /; _resolve_dlist (~Module parent, ~parse.Node dl) ~parse.Node tn = NULL ~parse.Node n int reg = 1 int stack_up = 8 /; loop (int i = 0; i < dl`.sub.count) [i++] n = dl`.sub.get(i) /; if (n`._type == parse.NTYPE_TYPE) tn = n ;; else if (n`._type == parse.NTYPE_ID) /; if (tn == NULL) _printf("Identifier declared in parameter list before any type was found!\n\0") return ;/ Var p p.init(tn, n) p._resolve_type(parent) # TODO: This is wrong /; if (p.regable() == true && reg < 7) p.loc = reg reg++ ;; else p.loc = 0 - 1 p.offset = stack_up stack_up = stack_up + p.actual_size() ;/ self.inputs.push(~p) ;/ ;/ ;/ /; _resolve_tlist (~Module parent, ~parse.Node tl) ~parse.Node n parse.Node dummy dummy.data = "### OUTPUT ###\0" int reg = 1 int stack = 0 /; loop (int i = 0; i < tl`.sub.count) [i++] n = tl`.sub.get(i) /; if (n`._type == parse.NTYPE_TYPE) # TODO: also wrong Var r r.init(n, ~dummy) r._resolve_type(parent) /; if (r.regable() == true && reg < 7) r.loc = reg /; if (reg > 4) r.loc = r.loc + 4 ;/ reg++ ;; else r.loc = 0 - 1 r.offset = stack stack = stack + r.actual_size() ;/ self.outputs.push(~r) ;/ ;/ ;/ /; _resolve_type (~Module parent) ~parse.Node _up = self._up /; if (_up`.sub.count < 1) return ;/ ~parse.Node lst = _up`.sub.get(0) /; if (lst`._type == parse.NTYPE_DLIST) self._resolve_dlist(parent, lst) /; if (_up`.sub.count > 1) lst = _up`.sub.get(1) ;/ ;/ /; if (lst`._type == parse.NTYPE_TLIST) self._resolve_tlist(parent, lst) ;/ int i_size = 0 int o_size = 0 ~Var v /; loop (int i = 0; i < self.inputs.count) [i++] v = self.inputs.get(i) /; if (v`.loc < 0) int vsz = v`.actual_size() i_size = i_size + vsz ;/ ;/ /; loop (int i = 0; i < self.outputs.count) [i++] v = self.outputs.get(i) /; if (v`.loc < 0) int vsz = v`.actual_size() o_size = o_size + vsz ;/ ;/ /; if (o_size > i_size) int padding = o_size - i_size /; loop (int i = 0; i < self.inputs.count) [i++] v = self.inputs.get(i) int off = v`.offset v`.offset = off + padding ;/ self.call_padding = padding ;/ ;/ /; _compute_scope_vars(~Scope s) ~Var in /; loop (int i = 0; i < self.inputs.count) [i++] in = self.inputs.get(i) s`.mk_aware(in) ;/ int i = self._first_stmt_off() /; if (i < 0) return ;/ ~parse.Node _up = self._up ~parse.Node n /; loop (i < _up`.sub.count) [i++] n = _up`.sub.get(i) /; if (n`._type == parse.NTYPE_DECL) s`.mk_aware_node(n) ;; else s`.precheck_stmt(n) ;/ ;/ ;/ /; _build_func(~Module parent, ~CompBuf cb) [Scope] Scope out out.init(parent, cb, self.name) out.parent = NULL /; if (parent`.e == true) # Add to the global exports if the parent is exported ~uint8 bl = out.base_label() cb`.add_h("global \0") cb`.add_h(bl) cb`.add_h("\n\0") _delete(bl) ;/ # Write label and opening # Nieve implementation: r10-r15 are callee saved registers # in the TNSL style ABI out.place_base_label() cb`.add_c(" push rbp\n\0") cb`.add_c(" lea rbp, [rsp + 8]\n\0") cb`.add_c(" push r10\n\0") cb`.add_c(" push r11\n\0") cb`.add_c(" push r12\n\0") cb`.add_c(" push r13\n\0") cb`.add_c(" push r14\n\0") cb`.add_c(" push r15 ; scope init\n\n\0") self._compute_scope_vars(~out) # Add all params to the scope ~Var in /; loop (int i = 0; i < self.inputs.count) [i++] in = self.inputs.get(i) out.mk_set_var(in) ;/ return out ;/ /; _end_func(~Scope scope, ~CompBuf cb) cb`.add_c("\n\0") scope`.place_end_label() cb`.add_c(" lea rsp, [rbp - 56]\n\0") cb`.add_c(" pop r15\n\0") cb`.add_c(" pop r14\n\0") cb`.add_c(" pop r13\n\0") cb`.add_c(" pop r12\n\0") cb`.add_c(" pop r11\n\0") cb`.add_c(" pop r10\n\0") cb`.add_c(" pop rbp\n\0") cb`.add_c(" ret ; scope end\n\n\n\0") scope`.end() ;/ /; _first_stmt_off [int] int i = 0 ~parse.Node _up = self._up /; if (_up`.sub.count < 1) return i - 1 ;/ ~parse.Node n = _up`.sub.get(i) /; if (n`._type == parse.NTYPE_DLIST) i++ /; if (_up`.sub.count > 1) n = _up`.sub.get(1) ;/ ;/ /; if (n`._type == parse.NTYPE_TLIST) i++ ;/ return i ;/ /; _compile (~Module parent, ~CompBuf cb) # Sanity check int i = self._first_stmt_off() # Create scope Scope fscope = self._build_func(parent, cb) /; if (i !< 0) self._compile_statements(~fscope, i) ;/ # Compile and then end scope self._end_func(~fscope, cb) ;/ # # Compiling individual statements # /; _compile_statements (~Scope s, int off) ~parse.Node _up = self._up ~parse.Node n = NULL /; loop (off < _up`.sub.count) [off++] n = _up`.sub.get(off) /; if (n`._type == parse.NTYPE_FLOW_CONTROL) self._compile_flow_control(s, n) ;; else if (n`._type == parse.NTYPE_ASM) s`.cb`.add_c(" \0") s`.cb`.add_c(n`.data) s`.cb`.add_c(" ; User defined asm\n\0") ;; else if (n`._type == parse.NTYPE_DECL) self._compile_decl(s, n) ;; else if (n`._type == parse.NTYPE_VALUE) Var v = self._compile_value(s, n) v.end() ;/ ;/ ;/ /; _check_return (~parse.Node n) [bool] int expected = self.outputs.count int have = 0 ~parse.Node val /; if (n`.sub.count > 0) val = n`.sub.get(0) val = val`.sub.get(0) /; if (expected > 1 && val`._type == parse.NTYPE_VLIST) have = val`.sub.count ;; else have = 1 ;/ ;/ /; if (have == expected) return true ;/ _print_num("ERROR: Number of return values (%d) does not match expected (\0", have) _print_num("%d)\n\0", expected) _printf("ERROR: To return multiple values enclose them in {}\n\0") _printf("ERROR: To add more return values, add them (comma separated) between [] at the end of the function definition\n\0") return false ;/ /; _compile_return_vals (~Scope s, ~parse.Node n) _printf("Compiling return vals!\n\0") /; if (self.outputs.count == 0) return ;/ n = n`.sub.get(0) /; if (self.outputs.count > 1) n = n`.sub.get(0) ;/ s`.cb`.add_c("\n ; STARTING RETURN\n\0") ~Var out Var cmp /; if (self.outputs.count > 1) ~parse.Node val_node Var tmp utils.Vector tmps tmps.init(len cmp) # Compile all values /; loop (int i = 0; i < self.outputs.count) [i++] val_node = n`.sub.get(i) out = self.outputs.get(i) tmp = s`.mk_tmp(out) cmp = self._compile_value(s, val_node, out) tmp.set(s`.cb, ~cmp) cmp.end() tmps.push(~tmp) ;/ # Set all outputs ~Var tt /; loop (int i = 0; i < self.outputs.count) [i++] out = self.outputs.get(i) tt = tmps.get(i) out`.set(s`.cb, tt) tt`.end() ;/ s`.free_tmp(tmps.count, false) tmps.end() ;; else out = self.outputs.get(0) cmp = self._compile_value(s, n, out) out`.set(s`.cb, ~cmp) cmp.end() ;/ ;/ /; _return (~Scope s, ~parse.Node n) /; if (self._check_return(n) !== true) return ;/ # Compute all return values and set the output variables properly self._compile_return_vals(s, n) # Find root scope of function /; loop (s`.parent !== NULL) s = s`.parent ;/ # Generate jump instruction ~uint8 lab = s`.end_label() s`.cb`.add_c(" jmp \0") s`.cb`.add_c(lab) s`.cb`.add_c("\n\0") _delete(lab) ;/ # Should handle break, continue, and return /; _compile_flow_control (~Scope s, ~parse.Node n) /; if (utils.strcmp(n`.data, "return\0") == true) # Compute value and return self._return(s, n) ;; else if (utils.strcmp(n`.data, "continue\0") == true) ~Scope lp = s`.closest_loop() /; if (lp == NULL) return ;/ ~uint8 lab = lp`.rep_label() s`.cb`.add_c(" jmp \0") s`.cb`.add_c(lab) s`.cb`.add_c("\n\0") _delete(lab) ;; else if (utils.strcmp(n`.data, "break\0") == true) ~Scope br = s`.closest_break() /; if (br == NULL) return ;/ ~uint8 lab = br`.rep_label() s`.cb`.add_c(" jmp \0") s`.cb`.add_c(lab) s`.cb`.add_c("\n\0") _delete(lab) ;; else _printf("COMPILER ERROR: The following was detected as flow control, but we do not handle it: '\0") _printf(n`.data) _printf("'\n\0") _printf("COMPILER ERROR: this is likely a bug with the compiler, please report it along with the\n\0") _printf("COMPILER ERROR: code snippit which caused the bug!\n\0") ;/ ;/ # Should handle variable declarations /; _compile_decl(~Scope s, ~parse.Node n) ~parse.Node sub /; loop (int i = 0; i < n`.sub.count) [i++] sub = n`.sub.get(i) /; if (sub`._type == parse.NTYPE_ID) ~Var v = s`._find_var(sub`.data) /; if (v == NULL) _printf("Failed to find variable '\0") _printf(sub`.data) _printf("'\n\0") return ;/ /; if (sub`.sub.count > 0) sub = sub`.sub.get(0) Var val = self._compile_value(s, sub, v) s`.mk_set_var(~val) val.end() ;; else s`.mk_var(v) ;/ ;/ ;/ ;/ /; _compile_call(~Scope s, ~parse.Node n, ~Function f) [Var] Var out return out ;/ /; _compile_base_id (~Scope s, ~parse.Node n) [Var] # First, check scope ~Var found = s`.find_var(n`.data) # If that fails, do a search in the module /; if (found == NULL) utils.Vector v v.init(8) ~uint8 str = n`.data v.push(~str) found = s`.mod`.find(SEARCH_VAR, ~v) v.end() ;/ /; if (found !== NULL) return found`.as_global() ;/ ~Function f utils.Vector v v.init(8) ~uint8 str = n`.data v.push(~str) /; if (s`.mod`.is_method() == true) ~Module search_mod = s`.mod`.parent f = search_mod`.find(SEARCH_FUNC, ~v) ;; else f = s`.mod`.find(SEARCH_FUNC, ~v) ;/ v.end() /; if (f !== NULL) _printf("TODO: Function call\n\0") Var out return out ;/ _printf("Could not find variable/function with identifier \"\0") _printf(n`.data) _printf("\" in scope \0") ~uint8 bl = s`.base_label() _printf(bl) _delete(bl) _printf("\n\0") Var out return out ;/ /; _compile_set (~Scope s, ~parse.Node n) [Var] # TODO Var out return out ;/ /; _compile_chain(~Scope s, ~parse.Node n) [Var] Var out return out ;/ /; _compile_bin (~Scope s, ~parse.Node n) [Var] # TODO /; if (utils.strcmp(n`.data, ".\0") == true) return self._compile_chain(s, n) ;/ ~parse.Node lhn = n`.sub.get(0) ~parse.Node rhn = n`.sub.get(1) # If we are setting /; if (utils.strcmp(n`.data, "=\0") == true) Var rhs = self._compile_value(s, rhn) # TODO: move rhs maybe if it is in rdi Var lhs = self._compile_value(s, lhn) lhs.set(s`.cb, ~rhs) rhs.end() return lhs ;/ # Otherwise Var lhs = self._compile_value(s, lhn) /; if (s`.is_tmp(~lhs) == false) Var tmp = s`.mk_tmp(~lhs) tmp.set(s`.cb, ~lhs) lhs.end() lhs = tmp ;/ Var rhs = self._compile_value(s, rhn) /; if (utils.strcmp(n`.data, "*\0") == true) lhs.mul(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "/\0") == true) lhs.div(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "%\0") == true) lhs.mod(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "+\0") == true) lhs.add(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "-\0") == true) lhs.sub(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "&\0") == true) lhs.and(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "|\0") == true) lhs.or(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "^\0") == true) lhs.xor(s`.cb, ~rhs) ;/ rhs.end() return lhs ;/ /; _compile_pre (~Scope s, ~parse.Node n, ~Var type_hint) [Var] Var out /; if (utils.strcmp(n`.data, "-\0") == true) ~parse.Node sub = n`.sub.get(0) out = self._compile_value(s, sub) out.neg(s`.cb) ;; else if (utils.strcmp(n`.data, "!\0") == true) ~parse.Node sub = n`.sub.get(0) out = self._compile_value(s, sub) out.not(s`.cb) ;; else if (utils.strcmp(n`.data, "~\0") == true) _printf("~ not impl\n\0") ;; else if (utils.strcmp(n`.data, "--\0") == true) _printf("-- not impl\n\0") ;; else if (utils.strcmp(n`.data, "++\0") == true) _printf("++ not impl\n\0") ;; else if (utils.strcmp(n`.data, "len\0") == true) _printf("len not impl\n\0") ;; else _printf("COMPILER ERROR: \"\0") _printf(n`.data) _printf("\" NOT RECOGNIZED AS A VALID PREOP\n\0") out = type_hint`.copy() ;/ return out ;/ /; _find_literal_type (~Scope s, ~uint8 name) [~Struct] utils.Vector vec vec.init(8) vec.push(~name) ~Struct out s`.mod`.find(SEARCH_STRUCT, ~vec) vec.end() return out ;/ /; _compile_literal (~Scope s, ~parse.Node n) [Var] Var out /; if (utils.strcmp(n`.data, "true\0") == true) ~Struct t = self._find_literal_type(s, "bool\0") out._init(t) out.offset = 1 ;; else if (utils.strcmp(n`.data, "false\0") == true) ~Struct t = self._find_literal_type(s, "bool\0") out._init(t) out.offset = 0 ;; else if (utils.strcmp(n`.data, "null\0") == true) ~Struct t = self._find_literal_type(s, "void\0") out._init(t) out.offset = 0 ;; else ~Struct t = self._find_literal_type(s, "int\0") out._init(t) out.offset = utils.cstr_to_int(n`.data) ;/ return out ;/ # Should handle computing a value, delegate to other funcs when needed /; _compile_value (~Scope s, ~parse.Node n) [Var] /; if (n`._type == parse.NTYPE_VALUE) ~parse.Node v = n`.sub.get(0) return self._compile_value(s, v) ;; else if (n`._type == parse.NTYPE_LITERAL) return self._compile_literal(s, n) ;; else if (n`._type == parse.NTYPE_ID) return self._compile_base_id(s, n) ;; else if (n`._type == parse.NTYPE_PRE_OP) return self._compile_pre(s, n) ;; else if (n`._type == parse.NTYPE_BIN_OP) return self._compile_bin(s, n) ;/ _printf("COMPILER ERROR: NOT IMPL NODE TYPE \"\0") parse.print_node_type(n) _printf("\" IN ROOT VAL COMPUTATION\n\0") Var out out._init(NULL) return out ;/ /; _print (int idt) _indent(idt) _printf("{ Function : \0") _printf(self.name) _printf("\n\0") _indent(idt + 1) _printf("inputs:\n\0") ~Var prtv /; loop (int i = 0; i < self.inputs.count) [i++] prtv = self.inputs.get(i) prtv`._print(idt + 2) ;/ _indent(idt + 1) _printf("outputs:\n\0") /; loop (int i = 0; i < self.outputs.count) [i++] prtv = self.outputs.get(i) prtv`._print(idt + 2) ;/ _indent(idt) _printf("}\n\0") ;/ /; end _delete(self.name) ~Var v /; loop (int i = 0; i < self.inputs.count) [i++] v = self.inputs.get(i) v`.end() ;/ self.inputs.end() /; loop (int i = 0; i < self.outputs.count) [i++] v = self.outputs.get(i) v`.end() ;/ self.outputs.end() ;/ ;/