diff options
Diffstat (limited to 'tnslc/compile')
| -rw-r--r-- | tnslc/compile/codegen.tnsl | 122 | ||||
| -rw-r--r-- | tnslc/compile/compbuf.tnsl | 45 | ||||
| -rw-r--r-- | tnslc/compile/compile.tnsl | 11 | ||||
| -rw-r--r-- | tnslc/compile/function.tnsl | 1918 | ||||
| -rw-r--r-- | tnslc/compile/generate.tnsl | 6 | ||||
| -rw-r--r-- | tnslc/compile/module.tnsl | 504 | ||||
| -rw-r--r-- | tnslc/compile/scope.tnsl | 752 | ||||
| -rw-r--r-- | tnslc/compile/struct.tnsl | 282 | ||||
| -rw-r--r-- | tnslc/compile/tests_var.tnsl | 248 | ||||
| -rw-r--r-- | tnslc/compile/type.tnsl | 360 | ||||
| -rw-r--r-- | tnslc/compile/var.tnsl | 1822 |
11 files changed, 5702 insertions, 368 deletions
diff --git a/tnslc/compile/codegen.tnsl b/tnslc/compile/codegen.tnsl new file mode 100644 index 0000000..636f16b --- /dev/null +++ b/tnslc/compile/codegen.tnsl @@ -0,0 +1,122 @@ +/; _indent (int idt) + /; loop (int i = 0; i < idt) [i++] + _printf(" \0") + ;/ +;/ + +/; parse_tree(~utils.File fin) + # Parse files into AST + parse.Node ast = parse.generate_ast(fin) + ast.update_children() + + # Print parse tree + parse.print_ast(~ast) + + ast.end() +;/ + +/; mod_tree(~utils.File fin) + # Parse files into AST + parse.Node ast = parse.generate_ast(fin) + ast.update_children() + + # Create output buffer + CompBuf buffer + buffer.init() + + Module mod + mod.init(~ast, ~buffer) + _gen_prims(~mod) + mod.update_children() + mod.collect_methods(~ast) + + # Compile code + mod.compile(~buffer) + + mod.print() + + # Free all structs + mod.end() + buffer.end() + ast.end() +;/ + + +/; generate (~utils.File fin, fout) + # Parse files into AST + parse.Node ast = parse.generate_ast(fin) + ast.update_children() + + # Create output buffer + CompBuf buffer + buffer.init() + + # Transform into a module tree + Module mod + mod.init(~ast, ~buffer) + _gen_prims(~mod) + mod.update_children() + mod.collect_methods(~ast) + + # Compile code + mod.compile(~buffer) + + # Tests + # var_tests(~buffer) + + # Write assembly to output file + fout.create() + buffer.write_to(fout) + fout.close() + + # Free all structs + mod.end() + buffer.end() + ast.end() +;/ + +# Generate a primitive type with the specified size and specified name +/; _gen_prim(~Module m, int size, ~uint8 id) + ~Module mds = m`._create_methods(id) + + Var t + + Struct s + s.size = size + s.methods = NULL + s.members.init(len t) + s.name = utils.strcpy(id) + s._up = NULL + + m`.structs.push(~s) +;/ + +# This function generates the generic language primitives on +# the root module so that resolution will work when creating +# a variable or struct +/; _gen_prims (~Module m) + + # One byte prims + _gen_prim(m, 1, "bool\0") + _gen_prim(m, 1, "uint8\0") + _gen_prim(m, 1, "int8\0") + + # Two byte prims + _gen_prim(m, 2, "uint16\0") + _gen_prim(m, 2, "int16\0") + + # Four byte prims + _gen_prim(m, 4, "uint32\0") + _gen_prim(m, 4, "int32\0") + _gen_prim(m, 4, "float32\0") + + # Eight byte prims + _gen_prim(m, 8, "uint64\0") + _gen_prim(m, 8, "int64\0") + _gen_prim(m, 8, "float64\0") + _gen_prim(m, 8, "uint\0") + _gen_prim(m, 8, "int\0") + _gen_prim(m, 8, "float\0") + _gen_prim(m, 8, "void\0") +;/ + diff --git a/tnslc/compile/compbuf.tnsl b/tnslc/compile/compbuf.tnsl new file mode 100644 index 0000000..d4bc640 --- /dev/null +++ b/tnslc/compile/compbuf.tnsl @@ -0,0 +1,45 @@ + +struct CompBuf { + utils.Vector + sec_head, + sec_data, + sec_code +} + +/; method CompBuf + /; init + self.sec_head.init(1) + self.sec_data.init(1) + self.sec_code.init(1) + ;/ + + /; add_h(~uint8 text) + self.sec_head.push_cstr(text) + ;/ + + /; add_d(~uint8 text) + self.sec_data.push_cstr(text) + ;/ + + /; add_c(~uint8 text) + self.sec_code.push_cstr(text) + ;/ + + /; write_to(~utils.File fout) + fout`.write_cstr("BITS 64\n\0") + fout`.write_cstr(self.sec_head.as_cstr()) + + fout`.write_cstr("\nsection .data\n\n\0") + fout`.write_cstr(self.sec_data.as_cstr()) + + fout`.write_cstr("\nsection .text\n\n\0") + fout`.write_cstr(self.sec_code.as_cstr()) + ;/ + + /; end + self.sec_head.end() + self.sec_data.end() + self.sec_code.end() + ;/ +;/ + diff --git a/tnslc/compile/compile.tnsl b/tnslc/compile/compile.tnsl index 3560f48..709dbce 100644 --- a/tnslc/compile/compile.tnsl +++ b/tnslc/compile/compile.tnsl @@ -1,4 +1,11 @@ /; module compile - :import "type.tnsl" - :import "generate.tnsl" + :import "compbuf.tnsl" + :import "struct.tnsl" + :import "var.tnsl" + :import "function.tnsl" + :import "module.tnsl" + :import "tests_var.tnsl" + :import "codegen.tnsl" + :import "scope.tnsl" ;/ + diff --git a/tnslc/compile/function.tnsl b/tnslc/compile/function.tnsl new file mode 100644 index 0000000..9188ca3 --- /dev/null +++ b/tnslc/compile/function.tnsl @@ -0,0 +1,1918 @@ + +struct Function { + ~uint8 name, + utils.Vector + inputs, + outputs, + ~parse.Node _up, + int call_padding, + bool m, + ~Module mod +} + +~uint8 BOOL_OPS = "&&,||,^^,!&&,!||,!^^\0" +~uint8 CMP_OPS = "==,<,>,!==,!<,!>,<==,>==\0" + +/; 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 + + /; if (self.m == true) + ~Struct s = parent`.related_type() + Var p + p._init(s) + _delete(p.name) + p.name = utils.strcpy("self\0") + p.ptr_push(0) + p.loc = reg + reg++ + self.inputs.push(~p) + ;/ + + /; if (dl == NULL) + return + ;/ + + /; 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 out_id + out_id.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, ~out_id) + r._resolve_type(parent) + r._id = NULL + r._tn = NULL + + /; 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) + /; if (self.m == true) + self._resolve_dlist(parent, NULL) + ;/ + 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) + ;/ + ;; else if (self.m == true) + self._resolve_dlist(parent, NULL) + ;/ + + /; 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_loop(~Scope s, ~parse.Node upper, int i) + ~parse.Node n + /; loop (i < upper`.sub.count) [i++] + n = upper`.sub.get(i) + /; if (n`._type == parse.NTYPE_DECL) + s`.mk_aware_node(n) + ;; else + s`.precheck_stmt(n) + ;/ + ;/ + ;/ + + /; _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 + self._compute_scope_vars_loop(s, _up, i) + ;/ + + + /; _call_label [~uint8] + Scope tmp + self.mod`._print(0) + tmp.init(self.mod, NULL, self.name) + ~uint8 out = tmp.base_label() + tmp.end() + return out + ;/ + + /; _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) + /; if (in.is_ref()) + ~int32 ptc = in.top_ptrc() + int32 set = 0 + set = set - 1 + ptc` = set + ;/ + 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) + ~parse.Node _up = self._up + self._compile_statements(~fscope, _up, i) + ;/ + + # Compile and then end scope + self._end_func(~fscope, cb) + ;/ + + # + # Compiling individual statements + # + + /; _compile_statements (~Scope s, ~parse.Node _up, int off) + ~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) + /; if (s`.is_tmp(~v)) + s`.free_to(~v, true) + ;/ + v.end() + ;; else if (n`._type == parse.NTYPE_IF_BLOCK) + off = self._compile_if(s, _up, off) + ;; else if (n`._type == parse.NTYPE_LOOP_BLOCK) + self._compile_loop(s, n) + ;/ + ;/ + ;/ + + /; _compile_cf_pre(~Scope s, ~parse.Node _up) [bool] + ~parse.Node n = NULL + + bool last_var = false + Var v + + /; loop (int off = 0; 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) + + v = self._compile_value(s, n) + + int count = _up`.sub.count + /; if (off + 1 == count) + last_var = true + ;; else + /; if (s`.is_tmp(~v)) + s`.free_to(~v, true) + ;/ + v.end() + ;/ + ;; else if (n`._type == parse.NTYPE_IF_BLOCK) + off = self._compile_if(s, _up, off) + ;; else if (n`._type == parse.NTYPE_LOOP_BLOCK) + self._compile_loop(s, n) + ;/ + ;/ + + /; if (last_var == true) + last_var = false + /; if (v.is_struct() == false) + # Do cond jmp + ~CompBuf buf = s`.cb + ~uint8 lab = s`.end_label() + /; if (v.loc == 0 && v.offset == 0) + # False was passed, always jump to end + buf`.add_c(" jmp \0") + buf`.add_c(lab) + buf`.add_c("\n\0") + ;; else if (v.loc !== 0) + v.test(s`.cb) + buf`.add_c(" je \0") + buf`.add_c(lab) + buf`.add_c("\n\0") + ;/ + _delete(lab) + last_var = true + ;/ + + /; if (s`.is_tmp(~v) == true) + s`.free_to(~v, true) + ;/ + v.end() + ;/ + + return last_var + ;/ + + /; _compile_cf_post(~Scope s, ~parse.Node pre, post, bool has_pre) + ~parse.Node n = NULL + + bool last_var = false + Var v + + /; loop (int i = 0; i < post`.sub.count) [i++] + n = post`.sub.get(i) + /; 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) + + v = self._compile_value(s, n) + + int count = post`.sub.count + /; if (i + 1 == count) + last_var = true + ;; else + /; if (s`.is_tmp(~v)) + s`.free_to(~v, true) + ;/ + v.end() + ;/ + ;; else if (n`._type == parse.NTYPE_IF_BLOCK) + i = self._compile_if(s, post, i) + ;; else if (n`._type == parse.NTYPE_LOOP_BLOCK) + self._compile_loop(s, n) + ;/ + ;/ + + /; if (last_var == true) + last_var = false + /; if (v.is_struct() == false) + # Do cond jmp + ~CompBuf buf = s`.cb + ~uint8 lab = s`.end_label() + /; if (v.loc == 0 && v.offset == 0) + # False was passed, always jump to end + buf`.add_c(" jmp \0") + buf`.add_c(lab) + buf`.add_c("\n\0") + ;; else if (v.loc !== 0) + v.test(s`.cb) + buf`.add_c(" je \0") + buf`.add_c(lab) + buf`.add_c("\n\0") + ;/ + _delete(lab) + last_var = true + ;/ + + /; if (s`.is_tmp(~v) == true) + s`.free_to(~v, true) + ;/ + v.end() + ;/ + + /; if (last_var == false) + /; if (has_pre == true) + # Grab last item from pre block and compile as value. Then do similar to above + # as if it was the last statement + int off = pre`.sub.count - 1 + n = pre`.sub.get(off) + v = self._compile_value(s, n) + + # Do cond jmp + ~CompBuf buf = s`.cb + ~uint8 lab = s`.end_label() + /; if (v.loc == 0 && v.offset == 0) + # False was passed, always jump to end + buf`.add_c(" jmp \0") + buf`.add_c(lab) + buf`.add_c("\n\0") + ;; else if (v.loc !== 0) + v.test(s`.cb) + buf`.add_c(" je \0") + buf`.add_c(lab) + buf`.add_c("\n\0") + ;/ + _delete(lab) + + /; if (s`.is_tmp(~v) == true) + s`.free_to(~v, true) + ;/ + v.end() + ;/ + ;/ + ;/ + + /; _compile_if_if(~Scope wrap, ~parse.Node n) + /; if (n`.sub.count < 1) + # Sanity + return + ;/ + + # Generate and pre-compute scope + Scope s = wrap`.gen_sub("if\0") + ~parse.Node first = n`.sub.get(0) + int off = 0 + + # Compile pre statements if applicable and do conditional jmp + /; if (first`._type == parse.NTYPE_SLIST) + self._compute_scope_vars_loop(~s, first, 0) + self._compute_scope_vars_loop(~s, n, 1) + self._compile_cf_pre(~s, first) + off = off + 1 + ;; else + self._compute_scope_vars_loop(~s, n, 0) + ;/ + + # Actually compile all the statements + self._compile_statements(~s, n, off) + + # If we did execute the if branch then we are jumping to the end of the wrapper + ~CompBuf cb = wrap`.cb + cb`.add_c(" jmp \0") + ~uint8 lab = wrap`.end_label() + cb`.add_c(lab) + cb`.add_c("\n\0") + _delete(lab) + + # Place an anchor for the negative case to latch on to and clean up the scope + s.place_end_label() + s.end() + ;/ + + /; _compile_if_elif(~Scope wrap, ~parse.Node n) [bool] + /; if (n`._type !== parse.NTYPE_ELIF_BLOCK) + return false + ;/ + + self._compile_if_if(wrap, n) + return true + ;/ + + /; _compile_if_else(~Scope wrap, ~parse.Node n) [bool] + /; if (n`._type !== parse.NTYPE_ELSE_BLOCK) + return false + ;/ + + self._compile_if_if(wrap, n) + return true + ;/ + + /; _compile_if (~Scope s, ~parse.Node n, int off) [int] + Scope wrap = s`.gen_sub("wrap\0") + + ~parse.Node block = n`.sub.get(off) + self._compile_if_if(~wrap, block) + + bool run = true + /; loop (run == true) + off = off + 1 + /; if (off !< n`.sub.count) + run = false + ;; else + block = n`.sub.get(off) + /; if (self._compile_if_elif(~wrap, block) == false) + run = false + ;/ + ;/ + ;/ + + /; if (off < n`.sub.count) + /; if (self._compile_if_else(~wrap, block) == true) + off = off + 1 + ;/ + ;/ + + wrap.place_end_label() + wrap.end() + + off = off - 1 + return off + ;/ + + + /; _compile_loop (~Scope s, ~parse.Node n) + # Generate scope + Scope ls = s`.gen_sub("loop\0") + + # Grab pre-statements, post-statements, and offset + ~parse.Node pre = NULL + ~parse.Node post = NULL + int off = 0 + + /; if (n`.sub.count > 0) + ~parse.Node first = n`.sub.get(0) + /; if (first`._type == parse.NTYPE_SLIST) + /; if (utils.strcmp(first`.data, "(\0") == true) + pre = first + off++ + ;; else if (utils.strcmp(first`.data, "[\0") == true) + post = first + off++ + ;/ + ;/ + ;/ + + /; if (n`.sub.count > 1) + ~parse.Node second = n`.sub.get(1) + /; if (second`._type == parse.NTYPE_SLIST) + /; if (utils.strcmp(second`.data, "[\0") == true) + post = second + off++ + ;/ + ;/ + ;/ + + # Scope pre-check + /; if (pre !== NULL) + self._compute_scope_vars_loop(~ls, pre, 0) + ;/ + + /; if (post !== NULL) + self._compute_scope_vars_loop(~ls, post, 0) + ;/ + + self._compute_scope_vars_loop(~ls, n, off) + + # Compile pre statements if applicable and do conditional jmp + bool has_pre = false + /; if (pre !== NULL) + has_pre = self._compile_cf_pre(~ls, pre) + ;/ + + # Place an anchor for repeating the loop to latch on to + ls.place_start_label() + + # Actually compile all the statements + self._compile_statements(~ls, n, off) + + # Place an anchor for continue statements to latch on to + ls.place_rep_label() + + # Compile post-statements if applicable + /; if (post !== NULL) + self._compile_cf_post(~ls, pre, post, has_pre) + ;; else if (has_pre == true) + # In this case no post but we have a valid condition in the pre-statements + # so we should use that as the rep condition + int idx = pre`.sub.count - 1 + ~parse.Node last = pre`.sub.get(idx) + Var v = self._compile_value(~ls, last) + + # Do cond jmp + ~CompBuf buf = ls.cb + ~uint8 lab = ls.end_label() + /; if (v.loc == 0 && v.offset == 0) + # False was passed, always jump to end + buf`.add_c(" jmp \0") + buf`.add_c(lab) + buf`.add_c("\n\0") + ;; else if (v.loc !== 0) + v.test(s`.cb) + buf`.add_c(" je \0") + buf`.add_c(lab) + buf`.add_c("\n\0") + ;/ + _delete(lab) + + /; if (ls.is_tmp(~v) == true) + ls.free_to(~v, true) + ;/ + v.end() + ;/ + + # Default to repeating the loop + ~CompBuf cb = ls.cb + cb`.add_c(" jmp \0") + ~uint8 lab = ls.start_label() + cb`.add_c(lab) + cb`.add_c("\n\0") + _delete(lab) + + # Place an anchor for breaks to latch on to and clean up the scope + ls.place_end_label() + ls.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) + /; if (tmp.is_ref() == true) + int32 pp = 0 + pp = pp - 1 + tmp.ptr_pop() + tmp.ptr_push(pp) + ;; else + 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`.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) + # Need var name correct + _delete(val.name) + ~uint8 name = utils.strcpy(v`.name) + val.name = name + s`.mk_set_var(~val) + val.end() + ;; else + s`.mk_var(v) + ;/ + ;/ + ;/ + ;/ + + /; _compile_call(~Scope s, ~parse.Node params, ~Function f, ~Var _self, bool mth) [Var] + Var result + ~Var out + /; if (f`.outputs.count > 0) + # Generate result tmp if required + out = f`.outputs.get(0) + /; if (out`.loc < 0) + result = s`.mk_tmp_stack(out) + ;; else + result = out`.copy() + ;/ + ;; else + ~Struct t = self._find_literal_type(s, "void\0") + result._init(t) + ;/ + + # Save caller saved tmp variables + Var handle = s`.save_caller_tmp() + + # Check that parameter count matches + int param_count = params`.sub.count + /; if (mth == true) + param_count++ + ;/ + + /; if (params`.sub.count == 1) + ~parse.Node nn + nn = params`.sub.get(0) + /; if (nn`._type == parse.NTYPE_VALUE && nn`.sub.count == 0) + param_count = param_count - 1 + ;/ + ;/ + + /; if (param_count !== f`.inputs.count) + ~uint8 blab = s`.base_label() + _printf("ERROR: Failed to call function \"\0") + _printf(f`.name) + _printf("\" from scope \"\0") + _printf(blab) + _printf("\"\n\0") + _print_num(" Number of arguments (%d) did not match number of provided parameters \0", f`.inputs.count) + _print_num("(%d)\n\0", param_count) + _delete(blab) + result.loc = 0 + return result + ;/ + + # Then generate a vector to store all the tmp variables which will store the + # params as intermediaries + utils.Vector tmps + tmps.init(len result) + tmps._grow(param_count) + tmps.count = param_count + + # Create all stack based tmps + ~Var inp + Var last_stack + last_stack.loc = 0 + /; loop (int i = 1; i !> f`.inputs.count) [i++] + int pidx = f`.inputs.count - i + inp = f`.inputs.get(pidx) + /; if (inp`.loc < 0) + # Make tmp on stack and compute + Var to_set = s`.mk_tmp_stack(inp) + + /; if (to_set.is_ref() == true) + # Correct for ref + int32 ptrc = 0 + ptrc = ptrc - 1 + to_set.ptr_pop() + to_set.ptr_push(ptrc) + ;/ + + tmps.replace(pidx, ~to_set) + last_stack = to_set + ;/ + ;/ + + # Create all register based tmps + Var last_reg + last_reg.loc = 0 + /; loop (int i = 0; i < f`.inputs.count) [i++] + inp = f`.inputs.get(i) + /; if (inp`.loc > 0) + # Make tmp on stack and compute + Var to_set = s`.mk_tmp_stack(inp) + + /; if (to_set.is_ref() == true) + # Correct for ref + int32 ptrc = 0 + ptrc = ptrc - 1 + to_set.ptr_pop() + to_set.ptr_push(ptrc) + ;/ + + tmps.replace(i, ~to_set) + last_reg = to_set + ;/ + ;/ + + # Set 'self' if required + int use_self = 0 + /; if (mth == true) + inp = tmps.get(0) + + Var _sptr = _self`.take_ptr(s`.cb, 1) + inp`.set(s`.cb, ~_sptr) + _sptr.end() + use_self++ + ;/ + + # compile all parameters and put them into tmp vars + ~parse.Node pnode + /; loop (int i = use_self; i < f`.inputs.count) [i++] + pnode = params`.sub.get(i) + inp = tmps.get(i) + + Var param = self._compile_value(s, pnode) + inp`.set(s`.cb, ~param) + /; if (s`.is_tmp(~param)) + s`.free_to(~param, true) + ;/ + param.end() + ;/ + + # Move all register parameters into registers and free the stack space + ~Var ptmp + /; loop (int i = 0; i < f`.inputs.count) [i++] + inp = f`.inputs.get(i) + /; if (inp`.loc > 0) + ptmp = tmps.get(i) + /; if (inp`.is_ref() == true) + Var to_set = inp`.take_ptr(s`.cb, 1) + to_set.set(s`.cb, ptmp) + to_set.end() + ;; else + inp`.set(s`.cb, ptmp) + ;/ + ;/ + ;/ + + /; if (last_stack.loc !== 0) + s`.free_after(~last_stack, true) + ;/ + + # Pad out the stack for return if required + ~CompBuf buf = s`.cb + /; if (f`.call_padding > 0) + ~uint8 pad_num = utils.int_to_str(f`.call_padding) + buf`.add_c(" sub rsp, \0") + buf`.add_c(pad_num) + buf`.add_c("\n\0") + _delete(pad_num) + ;/ + + # Do call + ~uint8 call = f`._call_label() + buf`.add_c(" call \0") + buf`.add_c(call) + buf`.add_c("\n\0") + _delete(call) + + # Generate result variable and move into the result if required + /; if (f`.outputs.count > 0) + /; if (out`.loc < 0) + Var out_pos = out`.copy() + + /; if (out_pos.is_ref() == true) + int32 pp = 0 + pp = pp - 1 + out_pos.ptr_pop() + out_pos.ptr_push(pp) + ;/ + + out_pos.loc = last_stack.loc + out_pos.offset = last_stack.offset + + /; if (f`.call_padding > 0) + int offset = out_pos.offset + offset = offset - f`.call_padding + out_pos.offset = offset + ;/ + + bool is_ref = false + /; if (result.is_ref() == true) + is_ref = true + int32 pp = 0 + pp = pp - 1 + result.ptr_pop() + result.ptr_push(pp) + ;/ + + result.set(s`.cb, ~out_pos) + out_pos.end() + + /; if (is_ref == true) + result.ptr_pop() + result.ptr_push(0) + ;/ + ;/ + ;/ + + # Free all in tmp vector + /; loop (int i = 0; i < tmps.count) [i++] + inp = tmps.get(i) + inp`.end() + ;/ + tmps.end() + + # Restore tmps in regs + s`.restore_caller_tmp(~handle) + + /; if (result.loc < 0) + s`.free_after(~result, true) + ;/ + + return result + ;/ + + /; _set_var_ptr(~void v, ~void new_val) + Var v + int sz = len v + /; loop (int i = 0; i < sz) [i++] + ~uint8 out = v + i + ~uint8 in = new_val + i + out` = in` + ;/ + ;/ + + # Chain compilation functions get pretty long. Read at your own risk + + /; _compile_chain_r_post(~Scope s, ~parse.Node post, ~Var v) + # Post op type + /; if (utils.strcmp(post`.data, "(\0") == true) + _printf("TODO: tnslc does not yet support calling variables\n\0") + ;; else if (utils.strcmp(post`.data, "`\0") == true) + Var tmp = v`.de_ref() + v`.end() + self._set_var_ptr(v, ~tmp) + ;; else if (utils.strcmp(post`.data, "{\0") == true) + post = post`.sub.get(0) + + # make sure we store variable if it's in a register which may be overwritten + /; if (v`.loc > 0) + /; if (s`.is_tmp(v) == false) + bool is_ref = false + /; if (v`.is_ref() == true) + is_ref = true + int32 pp = 0 + pp = pp - 1 + v`.ptr_pop() + v`.ptr_push(pp) + ;/ + + Var tmp = s`.mk_tmp(v) + tmp.set(s`.cb, v) + v`.end() + /; if (is_ref == true) + tmp.ptr_pop() + tmp.ptr_push(0) + ;/ + self._set_var_ptr(v, ~tmp) + ;/ + ;/ + + # Compute index + Var idx = self._compile_value(s, post) + /; if (idx.loc == 6 || idx.loc == 5) + ~CompBuf buf = s`.cb + buf`.add_c(" mov rax, rdi\n\0") + idx.loc = 1 + ;/ + + # Take index and set result + Var tmp = v`.index(s`.cb, ~idx, 6) + + # Clear tmp + /; if (s`.is_tmp(v) == true) + s`.free_to(v, true) + ;/ + + v`.end() + idx.end() + self._set_var_ptr(v, ~tmp) + ;; else if (utils.strcmp(post`.data, "++\0") == true) + # Generate copy (make sure no refs) + Var copy = v`.copy() + copy.strip_refs() + # Make tmp var + Var tmp = s`.mk_tmp(~copy) + copy.end() + # Set the new tmp to the value of the old + tmp.set(s`.cb, v) + # Increment the old + v`.inc(s`.cb) + v`.end() + self._set_var_ptr(v, ~tmp) + ;; else if (utils.strcmp(post`.data, "--\0") == true) + # Generate copy (make sure no refs) + Var copy = v`.copy() + copy.strip_refs() + # Make tmp var + Var tmp = s`.mk_tmp(~copy) + copy.end() + # Set the new tmp to the value of the old + tmp.set(s`.cb, v) + # Decrement the old + v`.dec(s`.cb) + v`.end() + self._set_var_ptr(v, ~tmp) + ;/ + ;/ + + /; _compile_chain_r_base (~Scope s, ~parse.Node base, ~utils.Vector v) [Var] + # Base case for dot chains + Var result + result.loc = 0 + + # Sanity + /; if (base`._type !== parse.NTYPE_ID) + _printf("TODO: tnslc does not currently support dot-chains with literals or non-identifiers as primary\n\0") + _printf(" will look into either intuiting the type from context or requiring a cast in the future\n\0") + v`.end() + v`.count = 0 + return result + ;/ + + # Check for var + ~Var vv = s`.find_var(base`.data) + /; if (vv == NULL) + # If could not find in scope then try to find in module + ~uint8 name = base`.data + v`.push(~name) + ~Module mod = s`.mod + vv = mod`.find(SEARCH_VAR, v) + /; if (vv !== NULL) + result = vv`.as_global() + v`.end() + v`.count = 0 + ;/ + ;; else + result = vv`.copy() + v`.end() + v`.count = 0 + ;/ + + # If has a post op + /; if (base`.sub.count > 0) + ~parse.Node sub = base`.sub.get(0) + /; if (utils.strcmp(sub`.data, "(\0") == true) + /; if (vv !== NULL) + result.end() + result.loc = 0 + _printf("TODO: tnslc does not yet support calling variables\n\0") + return result + ;/ + + # Try to find function. Make sure scope not in method module first. + ~Module mod = s`.mod + /; if (mod`.is_method() == true) + mod = mod`.parent + ;/ + + # Already tried to find in module so can just use v for search. + ~Function to_call = mod`.find(SEARCH_FUNC, v) + + /; if (to_call == NULL) + _printf("ERROR: Unable to find function or variable with name \"\0") + _printf(base`.data) + _printf("\" in scope \"\0") + ~uint8 blab = s`.base_label() + _printf(blab) + _printf("\"\n\0") + _delete(blab) + v`.end() + v`.count = 0 + return result + ;/ + + # Do call + result = self._compile_call(s, sub, to_call, NULL, false) + v`.end() + v`.count = 0 + + ;; else if (result.loc == 0) + # Exit + _printf("ERROR: Unable to find variable \"\0") + _printf(base`.data) + _printf("\" in scope \"\0") + ~uint8 blab = s`.base_label() + _printf(blab) + _printf("\"\n\0") + _delete(blab) + v`.end() + v`.count = 0 + return result + ;; else + self._compile_chain_r_post(s, sub, ~result) + ;/ + ;/ + + # Loop over all post-ops past the first + ~parse.Node post + /; loop (int i = 1; i < base`.sub.count) [i++] + post = base`.sub.get(i) + /; if (utils.strcmp(post`.data, "(\0") == true) + result.end() + result.loc = 0 + _printf("TODO: tnslc does not yet support calling variables\n\0") + v`.end() + v`.count = 0 + return result + ;/ + self._compile_chain_r_post(s, post, ~result) + ;/ + + return result + ;/ + + # Function: the very long one. + /; _compile_chain_r (~Scope s, ~parse.Node n, ~utils.Vector v) [Var] + ~parse.Node lhn = n`.sub.get(0) + Var working = self._compile_chain_r_base(s, lhn, v) + + /; if (v`.count == 0) + /; if (working.loc == 0) + # If we have encountered an error or determined we could not find the variable for certain. + return working + ;/ + ;/ + + # The way in which chains are parsed puts all dots in the second sub-node + + # Several points here: if have not found var or func yet need to try + # if we can't and there is a post-op, then we need to stop. + bool run = true + ~parse.Node rhn + /; loop (run == true) + rhn = n`.sub.get(1) + + /; if (utils.strcmp(rhn`.data, ".\0") == true) + n = rhn + rhn = n`.sub.get(0) + ;; else + run = false + ;/ + + # Sanity + /; if (rhn`._type !== parse.NTYPE_ID) + _printf("TODO: tnslc does not currently support dot-chains with literals or non-identifiers in the middle\n\0") + v`.end() + v`.count = 0 + working.loc = 0 + return working + ;/ + + /; if (v`.count !== 0) + # If we haven't yet found the var add to the vec and search the module + ~uint8 dat = rhn`.data + v`.push(~dat) + + ~Module mod = s`.mod + ~Var find = mod`.find(SEARCH_VAR, v) + + /; if (find !== NULL) + working = find`.as_global() + v`.end() + v`.count = 0 + ;/ + + # Then check for post-op. + /; if (rhn`.sub.count > 0) + ~parse.Node post_op = rhn`.sub.get(0) + /; if (utils.strcmp(post_op`.data, "(\0") == true) + # Try a call + /; if (find !== NULL) + _printf("TODO: TNSL doesn't currently have good support for function calling by value\n\0") + return working + ;/ + + # Try to find function. Does not matter if we are a module since this is multi-part search + ~Module mod = s`.mod + + # Already tried to find in module so can just use v for search. + ~Function to_call = mod`.find(SEARCH_FUNC, v) + + /; if (to_call == NULL) + _printf("ERROR: Unable to find function or variable with name \"\0") + _printf(rhn`.data) + _printf("\" in scope \"\0") + ~uint8 blab = s`.base_label() + _printf(blab) + _printf("\"\n\0") + _delete(blab) + v`.end() + v`.count = 0 + return working + ;/ + + # Do call + working = self._compile_call(s, post_op, to_call, NULL, false) + ;; else if (working.loc == 0) + # Didn't find a variable but there was a post op + _printf("ERROR: Failed to find variable (dot chain ends in \"\0") + _printf(rhn`.data) + _printf("\" in scope \"\0") + ~uint8 blab = s`.base_label() + _printf(blab) + _printf("\"\n\0") + _delete(blab) + v`.end() + v`.count = 0 + return working + ;; else + # Do the post op on the found variable + self._compile_chain_r_post(s, post_op, ~working) + ;/ + ;/ + ;; else + # We already have a var, not doing anything with the vector any more + + # Check method call + int post_idx = 0 + /; if (rhn`.sub.count > 0) + ~parse.Node post = rhn`.sub.get(0) + /; if (utils.strcmp(post`.data, "(\0") == true) + # Try method + post_idx++ + ~Function to_call = working.find_method(rhn`.data) + + /; if (to_call == NULL) + working.end() + working.loc = 0 + return working + ;/ + + # Create space for the variable in a tmp + Var result = self._compile_call(s, post, to_call, ~working, true) + working.end() + working = result + ;/ + ;/ + + /; if (post_idx == 0) + # Normal member + Var mbr = working.member(s`.cb, rhn`.data) + + /; if (mbr.loc == 0) + # If the member didn't exist we end here + # The member function already prints some info + working.end() + working.loc = 0 + return working + ;/ + _printf("Member:\n\0") + mbr._print(0) + + working.end() + working = mbr + + /; if (rhn`.sub.count > 0) + # Do first post-op after the member + ~parse.Node post = rhn`.sub.get(0) + self._compile_chain_r_post(s, post, ~working) + ;/ + ;/ + ;/ + + # Loop over rest of post ops + ~parse.Node post + /; loop (int i = 1; i < rhn`.sub.count) [i++] + post = rhn`.sub.get(i) + self._compile_chain_r_post(s, post, ~working) + ;/ + ;/ + + return working + ;/ + + /; _compile_chain (~Scope s, ~parse.Node n) [Var] + # FIND_VAR!!!!! + utils.Vector chain + chain.init(8) + return self._compile_chain_r(s, n, ~chain) + ;/ + + /; _compile_bool_op (~Scope s, ~parse.Node n) [Var] + Scope bs = s`.gen_sub("bool\0") + ~parse.Node lhn = n`.sub.get(0) + ~parse.Node rhn = n`.sub.get(1) + + ~uint8 op = n`.data + + ~Struct t = self._find_literal_type(s, "bool\0") + Var dummy + dummy._init(t) + Var out = s`.mk_tmp(~dummy) + dummy.end() + + # Compute left hand side + Var lhs = self._compile_value(s, lhn) + /; if (s`.is_tmp(~lhs) == true) + s`.free_after(~lhs, true) + ;/ + + /; if (lhs.is_struct() == true) + _printf("Can not use struct as boolean value\n\0") + lhs.end() + bs.end() + return out + ;/ + + ~CompBuf buf = s`.cb + + # Pre-operation (jmp or mov) for this bool operator + /; if (op{1} == '&') + lhs.test(buf) + ~uint8 lab = bs.end_label() + buf`.add_c(" je \0") + buf`.add_c(lab) + buf`.add_c("\n\0") + ;; else if (op{1} == '|') + lhs.test(buf) + ~uint8 lab = bs.end_label() + buf`.add_c(" jne \0") + buf`.add_c(lab) + buf`.add_c("\n\0") + ;; else if (op{1} == '^') + /; if (lhs.loc > 0 && lhs.loc < 11) + /; if (s`.is_tmp(~lhs) == false) + bool was_ref = false + /; if (lhs.is_ref() == true) + was_ref = true + int32 ptr = 0 + ptr = ptr - 1 + lhs.ptr_pop() + lhs.ptr_push(ptr) + ;/ + + Var tmp = s`.mk_tmp(~lhs) + + tmp.set(s`.cb, ~lhs) + lhs.end() + lhs = tmp + + /; if (was_ref == true) + lhs.ptr_pop() + lhs.ptr_push(0) + ;/ + ;/ + ;/ + ;/ + + # Compute right hand side + Var rhs = self._compile_value(s, rhn) + + /; if (rhs.is_struct() == true) + _printf("Can not use struct as boolean value\n\0") + lhs.end() + rhs.end() + bs.end() + return out + ;/ + + # Post compare or test for this particular bool op + /; if (op{1} == '^') + # Mov lhs to a register + bool is_ref = lhs.is_ref() + /; if (lhs.loc < 1 || is_ref == true) + Var tmp = lhs.copy() + tmp.strip_refs() + tmp.loc = 3 + tmp.offset = 0 + tmp.set(s`.cb, ~lhs) + lhs.end() + lhs = tmp + ;/ + + /; if (op{0} == '!') + out.cmov(s`.cb, ~lhs, ~rhs, "e\0") + ;; else + out.cmov(s`.cb, ~lhs, ~rhs, "e\0") + ;/ + ;; else + rhs.test(buf) + bs.place_end_label() + /; if (op{0} == '!') + out.cset(buf, "e\0") + ;; else + out.cset(buf, "ne\0") + ;/ + ;/ + + lhs.end() + rhs.end() + s`.free_after(~out, true) + bs.end() + return out + ;/ + + /; _compile_cmp_op (~Scope s, ~parse.Node n) [Var] + ~parse.Node lhn = n`.sub.get(0) + ~parse.Node rhn = n`.sub.get(1) + + # Setup output + ~Struct t = self._find_literal_type(s, "bool\0") + Var dummy + dummy._init(t) + Var out = s`.mk_tmp(~dummy) + dummy.end() + + # Compute left hand side + Var lhs = self._compile_value(s, lhn) + /; if (s`.is_tmp(~lhs) == true) + s`.free_after(~lhs, true) + ;/ + + # TODO: move lhs maybe if it is in rdi + /; if (lhs.loc > 0 && lhs.loc < 11) + /; if (s`.is_tmp(~lhs) == false) + bool was_ref = false + /; if (lhs.is_ref() == true) + was_ref = true + int32 ptr = 0 + ptr = ptr - 1 + lhs.ptr_pop() + lhs.ptr_push(ptr) + ;/ + + Var tmp = s`.mk_tmp(~lhs) + + tmp.set(s`.cb, ~lhs) + lhs.end() + lhs = tmp + + /; if (was_ref == true) + lhs.ptr_pop() + lhs.ptr_push(0) + ;/ + ;/ + ;/ + + # Compute right hand side + Var rhs = self._compile_value(s, rhn) + + # Check not structs + /; if (lhs.is_struct() == true || rhs.is_struct() == true) + _printf("Can not compare structs in this version of tnsl\n\0") + lhs.end() + rhs.end() + s`.free_after(~out, true) + return out + ;/ + + # Mov lhs to a register + bool is_ref = lhs.is_ref() + /; if (lhs.loc < 1 || is_ref == true) + Var tmp = lhs.copy() + tmp.strip_refs() + tmp.loc = 3 + tmp.offset = 0 + tmp.set(s`.cb, ~lhs) + lhs.end() + lhs = tmp + ;/ + + # Do comparitive move + /; if (utils.strcmp(n`.data, "==\0") == true) + out.cmov(s`.cb, ~lhs, ~rhs, "e\0") + ;; else if (utils.strcmp(n`.data, "<\0") == true) + out.cmov(s`.cb, ~lhs, ~rhs, "l\0") + ;; else if (utils.strcmp(n`.data, ">\0") == true) + out.cmov(s`.cb, ~lhs, ~rhs, "g\0") + ;; else if (utils.strcmp(n`.data, "!==\0") == true) + out.cmov(s`.cb, ~lhs, ~rhs, "ne\0") + ;; else if (utils.strcmp(n`.data, "!<\0") == true) + out.cmov(s`.cb, ~lhs, ~rhs, "nl\0") + ;; else if (utils.strcmp(n`.data, "!>\0") == true) + out.cmov(s`.cb, ~lhs, ~rhs, "ng\0") + ;; else if (utils.strcmp(n`.data, "<==\0") == true) + out.cmov(s`.cb, ~lhs, ~rhs, "le\0") + ;; else if (utils.strcmp(n`.data, ">==\0") == true) + out.cmov(s`.cb, ~lhs, ~rhs, "ge\0") + ;/ + + lhs.end() + rhs.end() + s`.free_after(~out, true) + return out + ;/ + + /; _compile_bin (~Scope s, ~parse.Node n) [Var] + # TODO + /; if (utils.strcmp(n`.data, ".\0") == true) + return self._compile_chain(s, n) + ;; else if (parse._in_csv(BOOL_OPS, n`.data) == true) + return self._compile_bool_op(s, n) + ;; else if (parse._in_csv(CMP_OPS, n`.data) == true) + return self._compile_cmp_op(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 lhs = self._compile_value(s, lhn) + + /; if (s`.is_tmp(~lhs) == true) + s`.free_after(~lhs, true) + ;/ + + # TODO: move lhs maybe if it is in rdi + /; if (lhs.loc > 0 && lhs.loc < 11) + /; if (s`.is_tmp(~lhs) == false) + bool was_ref = false + /; if (lhs.is_ref() == true) + was_ref = true + int32 ptr = 0 + ptr = ptr - 1 + lhs.ptr_pop() + lhs.ptr_push(ptr) + ;/ + + Var tmp = s`.mk_tmp(~lhs) + + tmp.set(s`.cb, ~lhs) + lhs.end() + lhs = tmp + + /; if (was_ref == true) + lhs.ptr_pop() + lhs.ptr_push(0) + ;/ + ;/ + ;/ + + Var rhs = self._compile_value(s, rhn) + lhs.set(s`.cb, ~rhs) + + # Cleanup rhs + /; if (s`.is_tmp(~rhs) == true) + s`.free_to(~rhs, true) + ;/ + rhs.end() + + return lhs + ;/ + + # Otherwise + Var lhs = self._compile_value(s, lhn) + /; if (s`.is_tmp(~lhs) == false) + Var copy = lhs.copy() + copy.strip_refs() + Var tmp = s`.mk_tmp(~copy) + copy.end() + + tmp.set(s`.cb, ~lhs) + lhs.end() + lhs = tmp + ;/ + + /; if (lhs.is_ref() == true) + Var copy = lhs.copy() + copy.strip_refs() + Var tmp = s`.mk_tmp(~copy) + copy.end() + + 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) + ;/ + + s`.free_after(~lhs, true) + rhs.end() + + return lhs + ;/ + + /; _compile_pre (~Scope s, ~parse.Node n) [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) + ~parse.Node sub = n`.sub.get(0) + Var tmp = self._compile_value(s, sub) + out = tmp.take_ptr(s`.cb, 5) + tmp.end() + ;; else if (utils.strcmp(n`.data, "--\0") == true) + ~parse.Node sub = n`.sub.get(0) + out = self._compile_value(s, sub) + out.dec(s`.cb) + ;; else if (utils.strcmp(n`.data, "++\0") == true) + ~parse.Node sub = n`.sub.get(0) + out = self._compile_value(s, sub) + out.inc(s`.cb) + ;; 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") + ;/ + + return out + ;/ + + /; _find_literal_type (~Scope s, ~uint8 name) [~Struct] + utils.Vector vec + vec.init(8) + vec.push(~name) + + ~Struct out + 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 + out.ptr_push(1) + ;; else if (n`.data{0} == '\'') + ~Struct t = self._find_literal_type(s, "uint8\0") + out._init(t) + ~uint8 dat = n`.data + dat++ + uint8 val = utils.unquote_cha(dat) + out.offset = val + ;; else if (n`.data{0} == '\"') + _printf("TODO: in-function strings\n\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) + utils.Vector tmp + tmp.init(8) + Var out = self._compile_chain_r_base(s, n, ~tmp) + /; if (tmp.count !== 0) + tmp.end() + ;; else + return out + ;/ + + ;; 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() + ;/ +;/ + diff --git a/tnslc/compile/generate.tnsl b/tnslc/compile/generate.tnsl deleted file mode 100644 index ef6a76c..0000000 --- a/tnslc/compile/generate.tnsl +++ /dev/null @@ -1,6 +0,0 @@ -/; generate (~utils.File fin, fout) - parse.Node n = parse.generate_ast(fin) - n.update_children() - parse.print_ast(~n) - n.end() -;/ diff --git a/tnslc/compile/module.tnsl b/tnslc/compile/module.tnsl new file mode 100644 index 0000000..86ede96 --- /dev/null +++ b/tnslc/compile/module.tnsl @@ -0,0 +1,504 @@ + +int SEARCH_VAR = 0 +int SEARCH_STRUCT = 1 +int SEARCH_FUNC = 2 +int SEARCH_SUB = 3 + +struct Module { + # Text name of module + ~uint8 name, + + # Various contained elements + utils.Vector + vars, + structs, + funcs, + subs, + + # Whether we export or not + bool e, + + # Parent module + ~Module parent +} + +/; method Module + + /; _init + Var v + Struct s + Function f + Module m + + self.parent = NULL + + self.vars.init(len v) + self.structs.init(len s) + self.funcs.init(len f) + self.subs.init(len m) + ;/ + + /; init (~parse.Node mod, ~CompBuf buf) + self._init() + self.name = utils.strcpy(mod`.data) + self.e = mod`._type == parse.NTYPE_EXPORT + + self._from_tree(mod, buf) + ;/ + + /; update_children + ~Module sub + /; loop (int i = 0; i < self.subs.count) [i++] + sub = self.subs.get(i) + sub`.update_children() + sub`.parent = ~self + ;/ + + ~Struct str + utils.Vector n + /; loop (int i = 0; i < self.structs.count) [i++] + str = self.structs.get(i) + + n.from_cstr("_#\0") + n.push_cstr(str`.name) + + sub = self._find_sub(n.as_cstr()) + str`.methods = sub + + n.end() + ;/ + + ~Var var + /; loop (int i = 0; i < self.vars.count) [i++] + var = self.vars.get(i) + var`.parent = ~self + ;/ + + ~Function func + /; loop (int i = 0; i < self.funcs.count) [i++] + func = self.funcs.get(i) + func`.mod = ~self + ;/ + ;/ + + /; _create_methods (~uint8 name) [~Module] + utils.Vector n + n.from_cstr("_#\0") + n.push_cstr(name) + + Module m + m._init() + m.name = n.as_cstr() + m.e = self.e + self.subs.push(~m) + + int i = self.subs.count - 1 + ~Module out = self.subs.get(i) + return out + ;/ + + /; is_method [bool] + /; if (utils.strlen(self.name) < 3) + return false + ;/ + + ~uint8 name = self.name + + /; if (name{0} !== '_') + return false + ;; else if (name{1} !== '#') + return false + ;; else if (name{2} == '#') + return false + ;/ + + return true + ;/ + + /; related_type [~Struct] + /; if (self.is_method() == false) + return NULL + ;/ + + ~Module m = self.parent + ~Module match = ~self + ~Struct s + /; loop (int i = 0; i < m`.structs.count) [i++] + s = m`.structs.get(i) + /; if (s`.methods == match) + return s + ;/ + ;/ + + _printf("COMPILER ERROR: UNABLE to find a sutable struct for module \"\0") + _printf(self.name) + _printf("\"\n\0") + return NULL + ;/ + + /; _from_tree (~parse.Node mod, ~CompBuf buf) + ~parse.Node sub + /; loop (int i = 0; i < mod`.sub.count) [i++] + sub = mod`.sub.get(i) + + # TODO: Enums + + /; if (sub`._type == parse.NTYPE_MODULE) + Module m + m.init(sub, buf) + self.subs.push(~m) + ;; else if (sub`._type == parse.NTYPE_EXPORT) + Module m + m.init(sub, buf) + self.subs.push(~m) + ;; else if (sub`._type == parse.NTYPE_STRUCT) + ~Module m = self._create_methods(sub`.data) + Struct s + s.init(sub) + self.structs.push(~s) + ;; else if (sub`._type == parse.NTYPE_FUNCTION) + Function f + f.init(sub) + self.funcs.push(~f) + ;; else if (sub`._type == parse.NTYPE_DECL) + self._decl(sub) + ;; else if (sub`._type == parse.NTYPE_ASM) + buf`.add_h(sub`.data) + buf`.add_h("\n\0") + ;/ + ;/ + ;/ + + /; _method_id (~uint8 id) [utils.Vector] + utils.Vector tmp + tmp.init(1) + utils.Vector out + out.init(8) + + ~uint8 str + + /; loop (id` !== 0) [id++] + /; if (id` == '.') + str = tmp.as_cstr() + out.push(~str) + tmp.init(1) + ;; else + tmp.push(id) + ;/ + ;/ + + str = tmp.as_cstr() + ~uint8 last = utils.stradd("_#\0", str) + _delete(str) + out.push(~last) + + return out + ;/ + + /; _method_id_end(~utils.Vector v) + ~~uint8 str + /; loop (int i = 0; i < v`.count) [i++] + str = v`.get(i) + _delete(str`) + ;/ + v`.end() + ;/ + + /; _collect_methods(~parse.Node m) + ~parse.Node sub + /; loop (int i = 0; i < m`.sub.count) [i++] + sub = m`.sub.get(i) + + /; if (sub`._type == parse.NTYPE_FUNCTION) + Function f + f.init(sub) + # Make function aware that it is in a method block + f.m = true + f.mod = ~self + self.funcs.push(~f) + ;/ + ;/ + ;/ + + /; collect_methods (~parse.Node mod) + ~parse.Node sub + /; loop (int i = 0; i < mod`.sub.count) [i++] + sub = mod`.sub.get(i) + /; if (sub`._type == parse.NTYPE_METHOD) + utils.Vector id = self._method_id(sub`.data) + ~Module m = self.find(SEARCH_SUB, ~id) + /; if (m !== NULL) + _printf("Found module for method\n\0") + m`._collect_methods(sub) + ;; else + _printf("Failed to find module for method\n\0") + ;/ + _method_id_end(~id) + ;; else if (sub`._type == parse.NTYPE_MODULE) + ~Module m = self._find_sub(sub`.data) + /; if (m !== NULL) + m`.collect_methods(sub) + ;; else + _printf("Failed to find module for method\n\0") + ;/ + ;; else if (sub`._type == parse.NTYPE_EXPORT) + ~Module m = self._find_sub(sub`.data) + /; if (m !== NULL) + m`.collect_methods(sub) + ;; else + _printf("Failed to find module for method\n\0") + ;/ + ;/ + ;/ + ;/ + + /; _decl (~parse.Node decl) + /; if (decl`.sub.count < 1) + return + ;/ + + ~parse.Node tn = decl`.sub.get(0) + /; if (tn`._type !== parse.NTYPE_TYPE) + # Type must be first + return + ;/ + + ~parse.Node id + /; loop (int i = 1; i < decl`.sub.count) [i++] + id = decl`.sub.get(i) + /; if (id`._type == parse.NTYPE_ID) + # Add a new variable to the list + Var v + v.init(tn, id) + self.vars.push(~v) + ;/ + ;/ + ;/ + + /; compile (~CompBuf cb) + # First, since all the types are in place, we need to size all of them. + self._size_structs() + + # Finally, write all functions to the code section and globals to the data section + self._compile(cb) + ;/ + + /; _size_structs + ~Struct s + /; loop (int i = 0; i < self.structs.count) [i++] + s = self.structs.get(i) + /; if (s`.size == 0) + s`._compute_size() + ;/ + ;/ + + ~Var v + /; loop (int i = 0; i < self.vars.count) [i++] + v = self.vars.get(i) + v`._resolve_type(~self) + ;/ + + ~Function f + /; loop (int i = 0; i < self.funcs.count) [i++] + f = self.funcs.get(i) + f`._resolve_type(~self) + ;/ + + ~Module m + /; loop (int i = 0; i < self.subs.count) [i++] + m = self.subs.get(i) + m`._size_structs() + ;/ + ;/ + + /; _compile (~CompBuf cb) + # Static compile all global variables + ~Var v + /; loop (int i = 0; i < self.vars.count) [i++] + v = self.vars.get(i) + v`._static_compile(cb) + ;/ + + # Write function to code section + ~Function f + /; loop (int i = 0; i < self.funcs.count) [i++] + f = self.funcs.get(i) + f`._compile(~self, cb) + ;/ + + # Recurse + ~Module m + /; loop (int i = 0; i < self.subs.count) [i++] + m = self.subs.get(i) + m`._compile(cb) + ;/ + ;/ + + # + # Functions to search sub-modules + # + + /; find (int stype, ~utils.Vector key) [~void] + /; if (key`.count < 1) + return NULL + ;/ + return self._find(stype, key, 0) + ;/ + + /; _find (int stype, ~utils.Vector key, int lvl) [~void] + + /; if ((lvl + 1) < key`.count) + ~Module m + ~~uint8 str = key`.get(lvl) + + /; loop (int i = 0; i < self.subs.count) [i++] + m = self.subs.get(i) + /; if (utils.strcmp(str`, m`.name) == true) + ~void v = m._find(stype, key, lvl + 1) + /; if (v !== NULL) + return v + ;/ + ;/ + ;/ + ;; else + ~~uint8 str = key`.get(key`.count - 1) + ~void out = NULL + /; if (stype == SEARCH_VAR) + out = self._find_var(str`) + ;; else if (stype == SEARCH_STRUCT) + out = self._find_struct(str`) + ;; else if (stype == SEARCH_FUNC) + out = self._find_func(str`) + ;; else if (stype == SEARCH_SUB) + out = self._find_sub(str`) + ;/ + + /; if (out !== NULL) + return out + ;/ + ;/ + + /; if (lvl == 0 && self.parent !== NULL) + return self.parent`._find(stype, key, 0) + ;/ + + return NULL + ;/ + + /; _find_var (~uint8 name) [~void] + ~Var v + /; loop (int i = 0; i < self.vars.count) [i++] + v = self.vars.get(i) + /; if (utils.strcmp(name, v`.name) == true) + return v + ;/ + ;/ + return NULL + ;/ + + /; _find_struct (~uint8 name) [~void] + ~Struct s + /; loop (int i = 0; i < self.structs.count) [i++] + s = self.structs.get(i) + /; if (utils.strcmp(name, s`.name) == true) + return s + ;/ + ;/ + return NULL + ;/ + + /; _find_func (~uint8 name) [~void] + ~Function f + /; loop (int i = 0; i < self.funcs.count) [i++] + f = self.funcs.get(i) + /; if (utils.strcmp(name, f`.name) == true) + return f + ;/ + ;/ + return NULL + ;/ + + /; _find_sub (~uint8 name) [~void] + ~Module m + /; loop (int i = 0; i < self.subs.count) [i++] + m = self.subs.get(i) + /; if (utils.strcmp(name, m`.name) == true) + return m + ;/ + ;/ + return NULL + ;/ + + /; print + self._print(0) + ;/ + + /; _print (int indent) + + _indent(indent) + _printf("{ Module : \0") + _printf(self.name) + _printf("\n\0") + + ~Var v + /; loop (int i = 0; i < self.vars.count) [i++] + v = self.vars.get(i) + v`._print(indent + 1) + ;/ + + ~Struct s + /; loop (int i = 0; i < self.structs.count) [i++] + s = self.structs.get(i) + s`._print(indent + 1) + ;/ + + ~Function f + /; loop (int i = 0; i < self.funcs.count) [i++] + f = self.funcs.get(i) + f`._print(indent + 1) + ;/ + + ~Module m + /; loop (int i = 0; i < self.subs.count) [i++] + m = self.subs.get(i) + m`._print(indent + 1) + ;/ + + _indent(indent) + _printf("}\n\0") + ;/ + + /; end + _delete(self.name) + + ~Var v + /; loop (int i = 0; i < self.vars.count) [i++] + v = self.vars.get(i) + v`.end() + ;/ + self.vars.end() + + ~Struct s + /; loop (int i = 0; i < self.structs.count) [i++] + s = self.structs.get(i) + s`.end() + ;/ + self.structs.end() + + ~Function f + /; loop (int i = 0; i < self.funcs.count) [i++] + f = self.funcs.get(i) + f`.end() + ;/ + self.funcs.end() + + ~Module m + /; loop (int i = 0; i < self.subs.count) [i++] + m = self.subs.get(i) + m`.end() + ;/ + self.subs.end() + ;/ + +;/ + diff --git a/tnslc/compile/scope.tnsl b/tnslc/compile/scope.tnsl new file mode 100644 index 0000000..569c48a --- /dev/null +++ b/tnslc/compile/scope.tnsl @@ -0,0 +1,752 @@ +struct Scope { + ~uint8 name, + ~Module mod, + ~CompBuf cb, + + ~Scope parent, + + utils.Vector vars, tmps, + + # Used for generating unique sub-scope labels + int unique +} + +/; _recursive_mod_name(~Module mod, ~utils.Vector vec) + ~Module p = mod`.parent + /; if (p !== NULL) + _recursive_mod_name(p, vec) + /; if (vec`.count !== 0) + vec`.push_char('.') + ;/ + ;/ + vec`.push_cstr(mod`.name) +;/ + +/; _recursive_scope_name(~Scope s, ~utils.Vector vec) + ~void p = s`.parent + /; if (p == NULL) + ~void m = s`.mod + /; if (m !== NULL) + _recursive_mod_name(m, vec) + /; if (vec`.count > 0) + vec`.push_char('.') + ;/ + ;/ + ;; else + _recursive_scope_name(p, vec) + ;/ + vec`.push_cstr(s`.name) +;/ + +/; method Scope + /; init (~Module mod, ~CompBuf cb, ~uint8 name) + self.name = utils.strcpy(name) + self.mod = mod + self.cb = cb + self.parent = NULL + self.unique = 0 + + Var v + self.vars.init(len v) + self.tmps.init(len v) + ;/ + + /; print + _printf("==== SCOPE DATA ====\n\0") + + _printf("Scope label: \0") + ~uint8 lab = self.base_label() + _printf(lab) + _printf("\n\n\0") + _delete(lab) + + _printf("Pre-tracked vars:\n\0") + ~Var v + /; loop (int i = 0; i < self.vars.count) [i++] + v = self.vars.get(i) + v`._print(0) + ;/ + + _printf("====================\n\0") + ;/ + + /; end + _delete(self.name) + + ~Var v + /; loop (int i = 0; i < self.vars.count) [i++] + v = self.vars.get(i) + v`.end() + ;/ + self.vars.end() + + /; loop (int i = 0; i < self.tmps.count) [i++] + v = self.tmps.get(i) + v`.end() + ;/ + self.tmps.end() + ;/ + + # + # Make variables + # + + /; _next_reg_slot [int] + int out = 11 + /; if (self.parent !== NULL) + out = self.parent`._next_reg_slot() + ;/ + + /; if (out < 0) + return out + ;/ + + ~Var v + /; loop (int i = 0; i < self.vars.count) [i++] + v = self.vars.get(i) + /; if (v`.loc > 1) + out++ + /; if (out > 16) + out = 0 + out = out - 1 + return out + ;/ + ;/ + ;/ + + return out + ;/ + + /; _next_tmp_slot [int] + int out = 2 + /; if (self.parent !== NULL) + out = self.parent`._next_tmp_slot() + ;/ + + /; if (out < 0) + return out + ;/ + + ~Var v + /; loop (int i = 0; i < self.tmps.count) [i++] + v = self.tmps.get(i) + /; if (v`.loc > 1) + out++ + /; if (out > 4) + out = 0 + out = out - 1 + return out + ;/ + ;/ + ;/ + + return out + ;/ + + /; _next_stack_slot [int] + int out = 0 + out = out - 56 + /; if (self.parent !== NULL) + out = self.parent`._next_stack_slot() + ;/ + + ~Var v + /; loop (int i = 0; i < self.vars.count) [i++] + v = self.vars.get(i) + /; if (v`.loc < 0 && v`.offset !== 0) + int off = v`.offset + /; if (off < out) + out = off + ;/ + ;/ + ;/ + + /; loop (int i = 0; i < self.tmps.count) [i++] + v = self.tmps.get(i) + /; if (v`.loc < 0 && v`.offset !== 0) + int off = v`.offset + /; if (off < out) + out = off + ;/ + ;/ + ;/ + + return out + ;/ + + /; mk_aware (~Var v) + Var mk = v`.copy() + mk.offset = 0 + + /; if (mk.loc > 0) + mk.loc = 1 + ;/ + + self.vars.push(~mk) + ;/ + + /; mk_aware_node (~parse.Node n) + ~parse.Node sub + ~parse.Node tp = NULL + /; loop (int i = 0; i < n`.sub.count) [i++] + sub = n`.sub.get(i) + /; if (sub`._type == parse.NTYPE_TYPE) + tp = sub + ;; else if (sub`._type == parse.NTYPE_ID) + /; if (tp == NULL) + _printf("COMPILER ERROR: Should have type node before first id in decl/dlist node\n\0") + return + ;/ + + # Part 1: Add var + Var v + v.init(tp, sub) + v._resolve_type(self.mod) + + # Compute weather we can put it in a register + /; if (v.regable() == true) + v.loc = 1 + ;; else + v.loc = 0 + v.loc = v.loc - 1 + ;/ + v.offset = 0 + + self.vars.push(~v) + + # Part 2: Compute via value (if exists) + /; if (sub`.sub.count > 0) + sub = sub`.sub.get(0) + /; if (sub`._type == parse.NTYPE_VALUE) + self.precheck_stmt(sub) + ;/ + ;/ + ;/ + ;/ + ;/ + + /; try_move (~parse.Node n) + /; loop (n`._type == parse.NTYPE_PRE_OP) + /; if (n`.sub.count < 1) + return + ;/ + n = n`.sub.get(0) + ;/ + + /; if (n`._type == parse.NTYPE_ID) + ~Var to_move = self._find_var(n`.data) + /; if (to_move == NULL) + return + ;/ + + /; if (to_move`.loc > 0) + int negative = 0 + to_move`.loc = negative - 1 + ;/ + ;/ + ;/ + + /; precheck_stmt (~parse.Node n) + /; if (n`._type == parse.NTYPE_PRE_OP) + /; if (utils.strcmp(n`.data, "~\0") == true) + self.try_move(n) + return + ;/ + ;/ + + ~parse.Node sub + /; loop (int i = 0; i < n`.sub.count) [i++] + sub = n`.sub.get(i) + self.precheck_stmt(sub) + ;/ + ;/ + + /; _find_var (~uint8 name) [~Var] + ~Var v + /; loop (int i = 0; i < self.vars.count) [i++] + v = self.vars.get(i) + /; if (utils.strcmp(v`.name, name) == true) + return v + ;/ + ;/ + + /; if (self.parent !== NULL) + return self.parent`.find_var(name) + ;/ + + return NULL + ;/ + + /; find_var (~uint8 name) [~Var] + ~Var out = self._find_var(name) + + /; if (out == NULL) + return NULL + ;/ + + /; if (out`.loc > 1 || out`.offset !== 0) + return out + ;/ + + _printf("ERROR: Found variable \"\0") + _printf(name) + _printf("\" but it doesn't look like it's been initialized yet!\n\0") + _print_num(" Loc: %d\n\0", out`.loc) + _print_num(" Offset: %d\n\0", out`.offset) + return NULL + ;/ + + /; mk_var (~Var src) [~Var] + ~Var v = self._find_var(src`.name) + + /; if (v == NULL) + return NULL + ;/ + + int tmp = 0 + /; if (v`.loc == 1) + int tmp = self._next_reg_slot() + v`.loc = tmp + /; if (v`.loc + 1 == 0) + tmp = self._next_stack_slot() + int sz = v`.actual_size() + v`.offset = tmp - sz + ;/ + ;; else if (v`.loc + 1 == 0) + /; if (v`.offset == 0) + tmp = self._next_stack_slot() + int sz = v`.actual_size() + v`.offset = tmp - sz + ;/ + ;/ + + /; if (v`.loc < 0) + int stk = v`.actual_size() + ~uint8 stk_str = utils.int_to_str(stk) + self.cb`.add_c(" sub rsp, \0") + self.cb`.add_c(stk_str) + self.cb`.add_c(" ; Create stack space for local variable \0") + self.cb`.add_c(v`.name) + self.cb`.add_c("\n\0") + _delete(stk_str) + ;/ + + return v + ;/ + + /; mk_set_var (~Var src) [~Var] + ~Var v = self.mk_var(src) + + /; if (v == NULL) + return NULL + ;/ + + /; if (v`.is_ref() == true) + int rc = v`.max_ref() + rc = rc - 1 + v`.set_ref(self.cb, src, rc) + ;; else + v`.set(self.cb, src) + ;/ + + return v + ;/ + + # Make a temp variable in register or stack for use in computations + /; mk_tmp (~Var base) [Var] + Var v = base`.copy() + v.offset = 0 + + int tmp = 0 + /; if (v.regable() == true) + int tmp = self._next_tmp_slot() + v.loc = tmp + /; if (v.loc + 1 == 0) + tmp = self._next_stack_slot() + int sz = v.actual_size() + v.offset = tmp - sz + ;; else if (v.loc > 2) + v.loc = v.loc + 6 + ;/ + ;; else + int loc = 0 + loc = loc - 1 + v.loc = loc + tmp = self._next_stack_slot() + int sz = v.actual_size() + v.offset = tmp - sz + ;/ + + /; if (v.loc < 0) + int stk = v.actual_size() + ~uint8 stk_str = utils.int_to_str(stk) + self.cb`.add_c(" sub rsp, \0") + self.cb`.add_c(stk_str) + self.cb`.add_c(" ; Create stack space for tmp variable\n\0") + _delete(stk_str) + ;/ + + self.tmps.push(~v) + + return v.copy() + ;/ + + # Make a temp variable on the stack for use in computations + /; mk_tmp_stack (~Var base) [Var] + Var v = base`.copy() + v.offset = 0 + + int loc = 0 + loc = loc - 1 + v.loc = loc + int tmp = self._next_stack_slot() + int sz = v.actual_size() + v.offset = tmp - sz + + ~uint8 stk_str = utils.int_to_str(sz) + self.cb`.add_c(" sub rsp, \0") + self.cb`.add_c(stk_str) + self.cb`.add_c(" ; Create stack space for tmp variable\n\0") + _delete(stk_str) + + self.tmps.push(~v) + + return v.copy() + ;/ + + /; _get_reg_tmp (~utils.Vector vec) + /; if (self.parent !== NULL) + ~Scope p = self.parent + p`._get_reg_tmp(vec) + ;/ + + ~Var tmp + /; loop (int i = 0; i < self.tmps.count) [i++] + tmp = self.tmps.get(i) + /; if (tmp`.loc > 0) + vec`.push(tmp) + ;/ + ;/ + ;/ + + /; save_caller_tmp [Var] + Var tmp + utils.Vector tmps + tmps.init(len tmp) + + self._get_reg_tmp(~tmps) + + /; if (tmps.count == 0) + tmps.end() + return tmp + ;/ + + ~Var to_save + /; loop (int i = 0; i < tmps.count) [i++] + to_save = tmps.get(i) + tmp = self.mk_tmp_stack(to_save) + + /; if (tmp.is_ref() == true) + # Handle ref + Var ref_val = to_save`.take_ptr(self.cb, 1) + Var ref_set = tmp.take_ptr(self.cb, 2) + ref_set.set(self.cb, ~ref_val) + ref_val.end() + ref_set.end() + ;; else + tmp.set(self.cb, to_save) + ;/ + + /; if (i < tmps.count - 1) + tmp.end() + ;/ + ;/ + tmps.end() + + return tmp + ;/ + + /; restore_caller_tmp (~Var handle) + Var tmp + utils.Vector tmps + tmps.init(len tmp) + + self._get_reg_tmp(~tmps) + + /; if (tmps.count == 0) + return + ;/ + + int end_idx = 0 + ~Var tmp + /; loop (int i = 0; i < self.tmps.count) [i++] + tmp = self.tmps.get(i) + /; if (tmp`.offset == handle`.offset) + /; if (tmp`.loc == handle`.loc) + end_idx = i + 1 + i = self.tmps.count + ;/ + ;/ + ;/ + + ~Var to_set + /; loop (int i = 0; i < tmps.count) [i++] + int idx = i + end_idx - tmps.count + to_set = tmps.get(i) + tmp = self.tmps.get(idx) + + /; if (to_set`.is_ref() == true) + # Handle ref + Var ref_val = tmp`.take_ptr(self.cb, 1) + Var ref_set = to_set`.take_ptr(self.cb, 2) + ref_set.set(self.cb, ~ref_val) + ref_val.end() + ref_set.end() + ;; else + to_set`.set(self.cb, tmp) + ;/ + ;/ + + handle`.end() + ;/ + + # Free n tmp variables (starts from most recently created) + # If you want to generate code to set the stack pointer then + # set code to true + /; free_tmp (int tmps, bool code) + /; if (self.tmps.count < tmps) + tmps = self.tmps.count + ;/ + + int stk_mv = 0 + + ~Var tmp + /; loop (int i = 1; i !> tmps) [i++] + tmp = self.tmps.get(self.tmps.count - i) + /; if (tmp`.loc < 0) + stk_mv = stk_mv + tmp`.actual_size() + ;/ + tmp`.end() + self.tmps.pop() + ;/ + + /; if (stk_mv > 0) + ~uint8 stk_mv_str = utils.int_to_str(stk_mv) + self.cb`.add_c(" add rsp, \0") + self.cb`.add_c(stk_mv_str) + self.cb`.add_c(" ; Free stack space (freeing tmp variables)\n\0") + _delete(stk_mv_str) + ;/ + ;/ + + # Returns true if the variable is in a temp spot + /; is_tmp (~Var v) [bool] + ~Var tmp + /; loop (int i = 0; i < self.tmps.count) [i++] + tmp = self.tmps.get(i) + /; if (tmp`.loc == v`.loc) + /; if (tmp`.offset == v`.offset) + return true + ;/ + ;/ + ;/ + return false + ;/ + + # Free all tmp variables created after and including the one provided + /; free_to (~Var tmp, bool code) + # TODO:DETERMINE HOW MANY TMPS + int tmps = 0 + tmps = tmps - 1 + ~Var v + /; loop (int i = 1; i !> self.tmps.count) [i++] + v = self.tmps.get(self.tmps.count - i) + /; if (v`.offset == tmp`.offset) + tmps = i + i = self.tmps.count + 1 + ;/ + ;/ + + /; if (tmps < 0) + ~uint8 scope_name = self.base_label() + int off = tmp`.offset + _printf("COMPILER ERROR: Unable to find temp to free to in scope \"\0") + _printf(scope_name) + _printf("\"\n\0") + _print_num(" Was looking for tmp with offset %d but could not find one.\n\0", off) + ;; else if (tmps > 0) + self.free_tmp(tmps, code) + ;/ + ;/ + + # Free all tmp variables created after the one provided + /; free_after (~Var tmp, bool code) + # TODO:DETERMINE HOW MANY TMPS + int tmps = 0 + tmps = tmps - 1 + ~Var v + /; loop (int i = 1; i !> self.tmps.count) [i++] + v = self.tmps.get(self.tmps.count - i) + /; if (v`.offset == tmp`.offset) + tmps = i - 1 + i = self.tmps.count + 1 + ;/ + ;/ + + /; if (tmps < 0) + ~uint8 scope_name = self.base_label() + int off = tmp`.offset + _printf("COMPILER ERROR: Unable to find temp to free to in scope \"\0") + _printf(scope_name) + _printf("\"\n\0") + _print_num(" Was looking for tmp with offset %d but could not find one.\n\0", off) + ;; else if (tmps > 0) + self.free_tmp(tmps, code) + ;/ + ;/ + + # + # Sub scope + # + + /; mk_sub (~uint8 name) [Scope] + Scope out + out.init(self.mod, self.cb, name) + out.parent = ~self + return out + ;/ + + # Generate a garantueed unique name for the sub scope, using + # the provided name as a base + /; gen_sub(~uint8 name) [Scope] + utils.Vector true_name + true_name.init(1) + + # Append a 'unique' number + ~uint8 u = utils.int_to_str(self.unique) + true_name.push_char('#') + true_name.push_cstr(u) + true_name.push_char('#') + true_name.push_cstr(name) + _delete(u) + + Scope out = self.mk_sub(true_name.as_cstr()) + true_name.end() + + # Inc for subsequent names + self.unique++ + + return out + ;/ + + # Get closest breakable scope + /; _closest_break [~Scope] + /; if (utils.ends_with(self.name, "#wrap\0")) + return ~self + ;; else if (utils.ends_with(self.name, "#loop\0")) + return ~self + ;/ + + /; if (self.parent == NULL) + return NULL + ;/ + + return self.parent`.closest_loop() + ;/ + + /; closest_break [~Scope] + /; if (self.parent == NULL) + return NULL + ;/ + + ~uint8 pname = self.parent`.name + /; if (utils.ends_with(pname, "#wrap\0")) + ~Scope par2 = self.parent`.parent + /; if (par2 !== NULL) + return par2`._closest_break() + ;/ + ;/ + + return self._closest_break() + ;/ + + # Get closest loop + /; closest_loop [~Scope] + /; if (utils.ends_with(self.name, "#loop\0")) + return ~self + ;/ + + /; if (self.parent == NULL) + return NULL + ;/ + + return self.parent`.closest_loop() + ;/ + + + # + # Label generation + # + + + /; _base_label [utils.Vector] + utils.Vector out + out.init(1) + + _recursive_scope_name(~self, ~out) + + return out + ;/ + + /; base_label [~uint8] + utils.Vector v = self._base_label() + return v.as_cstr() + ;/ + + /; place_base_label + ~uint8 bl = self.base_label() + self.cb`.add_c(bl) + self.cb`.add_c(":\n\0") + _delete(bl) + ;/ + + /; start_label [~uint8] + utils.Vector v = self._base_label() + v.push_cstr("#start\0") + return v.as_cstr() + ;/ + + /; place_start_label + ~uint8 sl = self.start_label() + self.cb`.add_c(sl) + self.cb`.add_c(":\n\0") + _delete(sl) + ;/ + + /; rep_label [~uint8] + utils.Vector v = self._base_label() + v.push_cstr("#rep\0") + return v.as_cstr() + ;/ + + /; place_rep_label + ~uint8 rl = self.rep_label() + self.cb`.add_c(rl) + self.cb`.add_c(":\n\0") + _delete(rl) + ;/ + + /; end_label [~uint8] + utils.Vector v = self._base_label() + v.push_cstr("#end\0") + return v.as_cstr() + ;/ + + /; place_end_label + ~uint8 el = self.end_label() + self.cb`.add_c(el) + self.cb`.add_c(":\n\0") + _delete(el) + ;/ +;/ + diff --git a/tnslc/compile/struct.tnsl b/tnslc/compile/struct.tnsl new file mode 100644 index 0000000..ed0b76a --- /dev/null +++ b/tnslc/compile/struct.tnsl @@ -0,0 +1,282 @@ + +struct Struct { + ~uint8 name, + ~Module methods, + utils.Vector members, + int size, + + ~parse.Node _up +} + +~uint8 PRIMITIVE_1 = "bool,uint8,int8\0" +~uint8 PRIMITIVE_2 = "uint16,int16\0" +~uint8 PRIMITIVE_4 = "uint32,int32,float32\0" +~uint8 PRIMITIVE_8 = "uint64,int64,float64,int,uint,float,void\0" + +/; _is_primitive(~uint8 str) [int] + /; if (parse._in_csv(PRIMITIVE_1, str) == true) + return 1 + ;; else if (parse._in_csv(PRIMITIVE_2, str) == true) + return 2 + ;; else if (parse._in_csv(PRIMITIVE_4, str) == true) + return 4 + ;; else if (parse._in_csv(PRIMITIVE_8, str) == true) + return 8 + ;/ + return 0 +;/ + +/; is_primitive (~parse.Node tn) [int] + /; if (tn`.sub.count < 1) + return 0 + ;/ + + ~parse.Node n = tn`.sub.get(0) + + # Check for pointer, array + /; if (n`._type == parse.NTYPE_PRE_OP) + return 8 + ;/ + + # Check for ref + n = tn`.sub.get(tn`.sub.count - 1) + /; if (n`._type == parse.NTYPE_POST_OP) + return 8 + ;/ + + int id = 0 - 1 + /; loop (int i = 0; i < tn`.sub.count) [i++] + n = tn`.sub.get(i) + /; if (n`._type == parse.NTYPE_ID) + /; if (id < 0) + id = i + ;; else + return 0 + ;/ + ;/ + ;/ + + /; if (id < 0) + return 0 + ;/ + + n = tn`.sub.get(id) + return _is_primitive(n`.data) +;/ + +/; _print_type(~parse.Node tn) + ~parse.Node n + bool seen_id = false + /; loop (int i = 0; i < tn`.sub.count) [i++] + + n = tn`.sub.get(i) + + /; if (n`._type == parse.NTYPE_ID) + /; if (seen_id == true) + _printf(".\0") + ;/ + _printf(n`.data) + seen_id = true + ;; else + return + ;/ + ;/ +;/ + +# Might be wrong +/; _type_is_ptr (~parse.Node n) [bool] + # Sanity + /; if (n`.sub.count < 1) + return false + ;/ + + ~parse.Node op = n`.sub.get(0) + /; if (op`._type == parse.NTYPE_PRE_OP) + return true + ;/ + + op = n`.sub.get(n`.sub.count - 1) + /; if (op`._type == parse.NTYPE_POST_OP) + return true + ;/ + + return false +;/ + +/; method Struct + + /; init (~parse.Node node) + self._up = node + self.size = 0 + self.methods = NULL + self.name = utils.strcpy(node`.data) + Var v + self.members.init(len v) + ;/ + + /; _print (int idt) + _indent(idt) + _printf("{ Struct : \0") + _printf(self.name) + _printf("\n\0") + + _indent(idt + 1) + _print_num("size: %d\n\0", self.size) + + _indent(idt + 1) + _printf("members:\n\0") + + ~Var v + /; loop (int i = 0; i < self.members.count) [i++] + v = self.members.get(i) + v`._print(idt + 2) + ;/ + + _indent(idt) + _printf("}\n\0") + ;/ + + /; add_member(~parse.Node tn, ~parse.Node id, int offset) + Var v + v.init(tn, id) + v._resolve_type(self.methods) + v.offset = offset + self.members.push(~v) + ;/ + + /; get_member(~uint8 name) [~Var] + ~Var out = NULL + + ~Var v + /; loop (int i = 0; i < self.members.count) [i++] + v = self.members.get(i) + /; if (utils.strcmp(v`.name, name) == true) + return v + ;/ + ;/ + + return out + ;/ + + /; _dlist [~parse.Node] + ~parse.Node up = self._up + ~parse.Node n + /; loop (int i = 0; i < up`.sub.count) [i++] + n = up`.sub.get(i) + /; if (n`._type == parse.NTYPE_DLIST) + return n + ;/ + ;/ + return NULL + ;/ + + /; _compute_size + /; if (self.size !== 0) + return + ;/ + + self.size = self.size - 1 + + int total = 0 + ~parse.Node up = self._dlist() + ~parse.Node tn = NULL + ~parse.Node n = NULL + int add_size = 0 + /; loop (int i = 0; i < up`.sub.count) [i++] + n = up`.sub.get(i) + + /; if (n`._type == parse.NTYPE_TYPE) + # Store for generating new variables + tn = n + add_size = self._compute_type_size(n) + /; if (add_size == 0) + return + ;/ + ;; else if (n`._type == parse.NTYPE_ID) + /; if (tn == NULL) + _printf("ERROR: Unable to find type when trying to create member for struct '\0") + _printf(self.name) + _printf("\n\0") + return + ;/ + self.add_member(tn, n, total) + total = total + add_size + ;/ + ;/ + + self.size = total + ;/ + + /; _compute_type_size(~parse.Node tn) [int] + ~Struct ft = self._find_type(tn) + + /; if (ft == NULL) + # Type not found + _printf("ERROR: Unable to find type '\0") + _print_type(tn) + _printf("' for use in struct '\0") + _printf(self.name) + _printf("'\n\0") + return 0 + ;/ + + /; if (_type_is_ptr(tn) == true) + return 8 + ;/ + + /; if (ft !== NULL && ft`.size == 0) + ft`._compute_size() + ;/ + + /; if (ft`.size < 0) + # Cyclical dependency + _printf("ERROR: Cyclic struct definition: '\0") + _printf(ft`.name) + _printf("' imported from '\0") + _printf(self.name) + _printf("'\n\0") + return 0 + ;/ + + return ft`.size + ;/ + + /; _find_type (~parse.Node tn) [~Struct] + + # Init vector of strings + utils.Vector sv + sv.init(8) + + ~uint8 str + ~parse.Node n + bool seen_id = false + + /; loop (int i = 0; i < tn`.sub.count) [i++] + n = tn`.sub.get(i) + /; if (n`._type == parse.NTYPE_ID) + str = n`.data + sv.push(~str) + seen_id = true + ;; else if (seen_id == true) + i = tn`.sub.count + ;/ + ;/ + + # Find struct and compute its size + ~Struct out = self.methods`.find(SEARCH_STRUCT, ~sv) + sv.end() + return out + ;/ + + /; end + _delete(self.name) + ~Var v + /; loop (int i = 0; i < self.members.count) [i++] + v = self.members.get(i) + v`.end() + ;/ + self.members.end() + ;/ + +;/ + diff --git a/tnslc/compile/tests_var.tnsl b/tnslc/compile/tests_var.tnsl new file mode 100644 index 0000000..a8fd573 --- /dev/null +++ b/tnslc/compile/tests_var.tnsl @@ -0,0 +1,248 @@ + +/; var_test_mov (~Module root, ~CompBuf buf) + ~Struct _int = root`._find_struct("int\0") + + Var a + Var b + + a._init(_int) + b._init(_int) + + buf`.add_c("; test: register to register move, both int\n\0") + + a.loc = 1 + b.loc = 2 + b.set(buf, ~a) + + buf`.add_c("; test: register to stack move\n\0") + + b.loc = b.loc - 3 + b.offset = b.offset - 56 + b.set(buf, ~a) + + buf`.add_c("; test: stack to register move\n\0") + + a.set(buf, ~b) + + buf`.add_c("; test: stack to stack move\n\0") + + a.loc = a.loc - 2 + a.offset = 56 + b.set(buf, ~a) + + buf`.add_c("\n\0") + + a.end() + b.end() +;/ + +/; var_test_movsx (~Module root, ~CompBuf buf) + ~Struct _int = root`._find_struct("int\0") + ~Struct _int32 = root`._find_struct("int32\0") + ~Struct _int8 = root`._find_struct("int8\0") + + Var a + Var b + Var c + + a._init(_int) + b._init(_int32) + c._init(_int8) + + a.loc = 1 + b.loc = 2 + c.loc = 3 + + buf`.add_c("; test: mov with extension - int8 to int32\n\0") + b.set(buf, ~c) + buf`.add_c("; test: mov with extension - int8 to int\n\0") + a.set(buf, ~c) + buf`.add_c("; test: mov with extension - int32 to int\n\0") + a.set(buf, ~b) + + buf`.add_c("; test: mov with extension - int8 to int32 (stack to reg)\n\0") + c.loc = c.loc - 4 + c.offset = 4 + b.set(buf, ~c) + buf`.add_c("; test: mov with extension - int8 to int32 (reg to stack)\n\0") + c.loc = 3 + c.offset = 0 + b.loc = b.loc - 3 + b.offset = 5 + b.set(buf, ~c) + buf`.add_c("; test: mov with extension - int8 to int32 (stack to stack)\n\0") + c.loc = c.loc - 4 + c.offset = 4 + b.set(buf, ~c) + + b.loc = 2 + b.offset = 0 + c.loc = 3 + c.offset = 0 + + buf`.add_c("; test: mov with extension - int8 to int (stack to reg)\n\0") + c.loc = c.loc - 4 + c.offset = 4 + a.set(buf, ~c) + buf`.add_c("; test: mov with extension - int8 to int (reg to stack)\n\0") + c.loc = 3 + c.offset = 0 + a.loc = a.loc - 2 + a.offset = 5 + a.set(buf, ~c) + buf`.add_c("; test: mov with extension - int8 to int (stack to stack)\n\0") + c.loc = c.loc - 4 + c.offset = 4 + a.set(buf, ~c) + + a.loc = 1 + a.offset = 0 + c.loc = 3 + c.offset = 0 + + buf`.add_c("; test: mov with extension - int32 to int (stack to reg)\n\0") + b.loc = b.loc - 3 + b.offset = 4 + a.set(buf, ~b) + buf`.add_c("; test: mov with extension - int32 to int (reg to stack)\n\0") + b.loc = 2 + b.offset = 0 + a.loc = a.loc - 2 + a.offset = 5 + a.set(buf, ~b) + buf`.add_c("; test: mov with extension - int32 to int (stack to stack)\n\0") + b.loc = b.loc - 3 + b.offset = 4 + a.set(buf, ~b) + + + buf`.add_c("\n\0") + a.end() + b.end() + c.end() +;/ + +/; var_test_movzx (~Module root, ~CompBuf buf) + ~Struct _uint = root`._find_struct("uint\0") + ~Struct _uint32 = root`._find_struct("uint32\0") + ~Struct _uint8 = root`._find_struct("uint8\0") + + Var a + Var b + Var c + + a._init(_uint) + b._init(_uint32) + c._init(_uint8) + + a.loc = 1 + b.loc = 2 + c.loc = 3 + + buf`.add_c("; test: mov with extension - uint8 to uint32\n\0") + b.set(buf, ~c) + buf`.add_c("; test: mov with extension - uint8 to uint\n\0") + a.set(buf, ~c) + buf`.add_c("; test: mov with extension - uint32 to uint\n\0") + a.set(buf, ~b) + + buf`.add_c("; test: mov with extension - uint8 to uint32 (stack to reg)\n\0") + c.loc = c.loc - 4 + c.offset = 4 + b.set(buf, ~c) + buf`.add_c("; test: mov with extension - uint8 to uint32 (reg to stack)\n\0") + c.loc = 3 + c.offset = 0 + b.loc = b.loc - 3 + b.offset = 5 + b.set(buf, ~c) + buf`.add_c("; test: mov with extension - uint8 to uint32 (stack to stack)\n\0") + c.loc = c.loc - 4 + c.offset = 4 + b.set(buf, ~c) + + b.loc = 2 + b.offset = 0 + c.loc = 3 + c.offset = 0 + + buf`.add_c("; test: mov with extension - uint8 to uint (stack to reg)\n\0") + c.loc = c.loc - 4 + c.offset = 4 + a.set(buf, ~c) + buf`.add_c("; test: mov with extension - uint8 to uint (reg to stack)\n\0") + c.loc = 3 + c.offset = 0 + a.loc = a.loc - 2 + a.offset = 5 + a.set(buf, ~c) + buf`.add_c("; test: mov with extension - uint8 to uint (stack to stack)\n\0") + c.loc = c.loc - 4 + c.offset = 4 + a.set(buf, ~c) + + a.loc = 1 + a.offset = 0 + c.loc = 3 + c.offset = 0 + + buf`.add_c("; test: mov with extension - uint32 to uint (stack to reg)\n\0") + b.loc = b.loc - 3 + b.offset = 4 + a.set(buf, ~b) + buf`.add_c("; test: mov with extension - uint32 to uint (reg to stack)\n\0") + b.loc = 2 + b.offset = 0 + a.loc = a.loc - 2 + a.offset = 5 + a.set(buf, ~b) + buf`.add_c("; test: mov with extension - uint32 to uint (stack to stack)\n\0") + b.loc = b.loc - 3 + b.offset = 4 + a.set(buf, ~b) + + + buf`.add_c("\n\0") + a.end() + b.end() + c.end() +;/ + +# Test moving references +/; var_test_movref (~Module root, ~CompBuf buf) + ~Struct _int = root`._find_struct("int\0") + ~Struct _int32 = root`._find_struct("int32\0") +;/ + +# Generate a test_struct type for use in testing struct moves and sub-refs +/; _gen_test_struct(~Module m) + ~Module mds = m`._create_methods("test\0") + + Var t + + Struct s + s.size = 9 + s.methods = NULL + s.members.init(len t) + s.name = utils.strcpy("test\0") + s._up = NULL + + m`.structs.push(~s) +;/ + +/; var_tests (~CompBuf buf) + # Setup dummy root + Module mod + mod._init() + mod.name = utils.strcpy("\0") + mod.e = true + _gen_prims(~mod) + _gen_test_struct(~mod) + + var_test_mov(~mod, buf) + var_test_movsx(~mod, buf) + var_test_movzx(~mod, buf) + var_test_movref(~mod, buf) + + mod.end() +;/ diff --git a/tnslc/compile/type.tnsl b/tnslc/compile/type.tnsl deleted file mode 100644 index 474f705..0000000 --- a/tnslc/compile/type.tnsl +++ /dev/null @@ -1,360 +0,0 @@ -struct Variable { - ~uint8 name, - ~Type _type, - utils.Vector ptr -} - -/; method Variable - /; init (~uint8 name) - self.name = name - self.ptr.init(8) - ;/ - - /; add_ptr(uint ptp) - self.ptr.push(~ptp) - ;/ - - /; get_ptr [uint] - /; if (self.ptr.count == 0) - return 0 - ;/ - ~uint p = self.ptr.get(self.ptr.count - 1) - return p` - ;/ - - /; pop_ptr [uint] - /; if (self.ptr.count == 0) - return 0 - ;/ - ~uint p = self.ptr.get(self.ptr.count - 1) - uint out = p` - self.ptr.pop() - return out - ;/ - - /; end - _delete(self.name) - self.ptr.end() - ;/ -;/ - -struct Type { - ~uint8 name, - uint size, - utils.Vector vars, - ~Module methods, -} - -/; method Type - /; init(~uint8 name) - self.name = name - Variable tmp - self.vars.init(len tmp) - ;/ - - /; add_var (~Variable v) - self.vars.push(v) - ;/ - - /; end - _delete(self.name) - /; loop (int i = 0; i < self.vars.count) [i++] - ~Variable v = self.vars.get(i) - v`.end() - ;/ - self.vars.end() - ;/ -;/ - -struct Function { - ~uint8 - name, - ~parse.Node - body, - utils.Vector - inputs, - outputs -} - -/; method Function - /; init (~uint8 name) - self.name = name - Variable vtmp - ~uint i - self.inputs.init(len vtmp) - self.outputs.init(len i) - ;/ - - /; add_input (~Variable v) - self.inputs.push(v) - ;/ - - /; add_output (~Type t) - self.outputs.push(~t) - ;/ - - /; end - _delete(self.name) - - /; loop (int i = 0; i < self.inputs.count) [i++] - ~Variable v = self.inputs.get(i) - v`.end() - ;/ - self.inputs.end() - - self.outputs.end() - ;/ -;/ - -struct Enum { - ~uint8 name, - ~Type _type, - utils.Vector vals -} - -/; method Enum - /; init (~uint8 name) - self.name = name - Variable vtmp - self.vals.init(len vtmp) - ;/ - - /; end - _delete(self.name) - /; loop (int i = 0; i < self.vals.count) [i++] - ~Variable v = self.vals.get(i) - v`.end() - ;/ - self.vals.end() - ;/ -;/ - -struct Module { - ~uint8 name, - ~Module parent, - bool exp, - utils.Vector - sub, - vars, - types, - funcs, - enums - -} - -uint8 MOD_FIND_SUB = 0 -uint8 MOD_FIND_VAR = 1 -uint8 MOD_FIND_TYP = 2 -uint8 MOD_FIND_FUN = 3 -uint8 MOD_FIND_ENM = 4 - -/; method Module - /; init (~uint8 name) - self.name = name - Module mtmp - Variable vtmp - Type ttmp - Function ftmp - Enum etmp - self.sub.init(len mtmp) - self.vars.init(len vtmp) - self.types.init(len ttmp) - self.funcs.init(len ftmp) - self.enums.init(len etmp) - ;/ - - /; update_children - /; loop (int i = 0; i < self.sub.count) [i++] - ~Module s = self.sub.get(i) - s`.parent = ~self - ;/ - ;/ - - /; add_sub(~Module m) [~Module] - self.sub.push(m) - /; loop (int i = 0; i < self.sub.count) [i++] - ~Module s = self.sub.get(i) - s`.update_children() - ;/ - return self.sub.get(self.sub.count - 1) - ;/ - - /; add_var (~Variable v) - self.vars.push(v) - ;/ - - /; add_type (~Type t) - self.types.push(t) - ;/ - - /; add_funcs (~Function f) - self.funcs.push(f) - ;/ - - /; add_enum (~Enum e) - self.enums.push(e) - ;/ - - /; _find_rec (utils.Artifact pth, uint8 typ, int sub) [~void] - /; if (sub !< pth.count) - return NULL - ;; else if ((sub + 1) < pth.count) - /; loop (int i = 0; i < self.sub.count) [i++] - ~Module m = self.sub.get(i) - /; if (utils.strcmp(pth.get(sub), m`.name) == true) - return _find_rec(pth, typ, sub + 1) - ;/ - ;/ - ;; else - /; if (typ == MOD_FIND_SUB) - /; loop (int i = 0; i < self.sub.count) [i++] - ~Module m = self.sub.get(i) - /; if (utils.strcmp(pth.get(sub), m`.name) == true) - return self.sub.get(i) - ;/ - ;/ - ;; else if (typ == MOD_FIND_VAR) - /; loop (int i = 0; i < self.vars.count) [i++] - ~Variable v = self.vars.get(i) - /; if (utils.strcmp(pth.get(sub), v`.name) == true) - return self.vars.get(i) - ;/ - ;/ - ;; else if (typ == MOD_FIND_TYP) - /; loop (int i = 0; i < self.types.count) [i++] - ~Type t = self.types.get(i) - /; if (utils.strcmp(pth.get(sub), t`.name) == true) - return self.types.get(i) - ;/ - ;/ - ;; else if (typ == MOD_FIND_FUN) - /; loop (int i = 0; i < self.funcs.count) [i++] - ~Function f = self.funcs.get(i) - /; if (utils.strcmp(pth.get(sub), f`.name) == true) - return self.funcs.get(i) - ;/ - ;/ - ;; else if (typ == MOD_FIND_ENM) - /; loop (int i = 0; i < self.enums.count) [i++] - ~Enum e = self.enums.get(i) - /; if (utils.strcmp(pth.get(sub), e`.name) == true) - return self.enums.get(i) - ;/ - ;/ - ;/ - ;/ - - /; if (self.parent == NULL || sub !== 0) - return NULL - ;/ - - return self.parent._find_rec(pth, typ, 0) - ;/ - - /; find (utils.Artifact pth, uint8 typ) [~void] - return _find_rec(pth, typ, 0) - ;/ - - /; end - _delete(self.name) - - /; loop (int i = 0; i < self.sub.count) [i++] - ~Module m = self.sub.get(i) - m`.end() - ;/ - self.sub.end() - - /; loop (int i = 0; i < self.vars.count) [i++] - ~Variable v = self.vars.get(i) - v`.end() - ;/ - self.vars.end() - - /; loop (int i = 0; i < self.types.count) [i++] - ~Type t = self.types.get(i) - t`.end() - ;/ - self.types.end() - - /; loop (int i = 0; i < self.funcs.count) [i++] - ~Function f = self.funcs.get(i) - f`.end() - ;/ - self.funcs.end() - - /; loop (int i = 0; i < self.enums.count) [i++] - ~Enum e = self.enums.get(i) - e`.end() - ;/ - self.enums.end() - ;/ -;/ - -{}~uint8 GEN_VAR_NAMES = { "int\0", "int8\0", "int16\0", "int32\0", "int64\0", "uint\0", "uint8\0", "uint16\0", "uint32\0", "uint64\0", "float\0", "float32\0", "float64\0", "vect\0", "bool\0", "void\0" } - -{}uint GEN_VAR_SIZES = { 8, 1, 2, 4, 8, 8, 1, 2, 4, 8, 8, 4, 8, 0, 1, 8} - -/; find_type(utils.Artifact a, ~parse.Node n) [~parse.Node] - return NULL -;/ - -/; transform_struct(~parse.Node n, ~Module parent) -;/ - -/; _tfn_mod_loop (~parse.Node n, ~Module m) - /; loop (int i = 0; i < n`.sub.count) [i++] - ~parse.Node s = n`.sub.get(i) - /; if (s`._type == parse.NTYPE_MODULE || s`._type == parse.NTYPE_EXPORT) - transform_module(s, m) - ;; else if (s`._type == parse.NTYPE_STRUCT) - transform_struct(s, m) - ;/ - ;/ -;/ - -/; transform_module (~parse.Node n, ~Module parent) - ~Module s = NULL - - /; loop (int i = 0; i < parent`.sub.count) [i++] - ~Module tmp = parent`.sub.get(i) - /; if (utils.strcmp(n`.data, tmp`.name) == true) - s = tmp - ;/ - ;/ - - ~int cmp = s - /; if (cmp == NULL) - Module out - out.init(utils.strcpy(n`.data)) - - /; if (n`._type == parse.NTYPE_EXPORT) - out.exp = true - ;; else - out.exp = false - ;/ - - s = parent`.add_sub(~out) - ;/ - - _tfn_mod_loop(n, s) -;/ - -/; _tfn_gen_default_types (~Module m) - /; loop (int i = 0; i < len GEN_VAR_NAMES) [i++] - Type t - t.init(utils.strcpy(GEN_VAR_NAMES{i})) - t.size = GEN_VAR_SIZES{i} - m`.add_type(~t) - ;/ -;/ - -/; transform_tree (~parse.Node n) [Module] - Module out - out.init(utils.strcpy(n`.data)) - out.exp = true - - _tfn_gen_default_types(~out) - _tfn_mod_loop(n, ~out) - - return out -;/ diff --git a/tnslc/compile/var.tnsl b/tnslc/compile/var.tnsl new file mode 100644 index 0000000..5f87cc7 --- /dev/null +++ b/tnslc/compile/var.tnsl @@ -0,0 +1,1822 @@ + +# Location enum +int VLOC_DATA = 2 +int VLOC_STCK = 1 +int VLOC_LITL = 0 + +# Should be -2 +int32 PTYPE_NONE = 2 +# Should be -1 +int32 PTYPE_PTR = 1 +int32 PTYPE_REF = 0 +# 1 Arr is ptr to arr, larger #s are static size arrs +int32 PTYPE_ARR = 1 + +~uint8 PRIM_CSV_BOO = "bool\0" +~uint8 PRIM_CSV_INT = "int,int8,int16,int32,int64,uint,uint8,uint16,uint32,uint64\0" +~uint8 PRIM_CSV_FLT = "float,float32,float64\0" + +# Should dispose of this constructed string +# 1-8 are ax, bx, cx, dx, si, di, sp, bp +# 9-16 are r8, r9, r10, r11, r12, r13, r14, r15 +# 17-32 are xmm0, xmm1, xmm2, ..., xmm15 +/; reg_string (int r, int size) [~uint8] + utils.Vector out + out.init(1) + uint8 add + + /; if (r < 9) + /; if (size == 4) + add = 'e' + out.push(~add) + ;; else if (size == 8) + add = 'r' + out.push(~add) + ;/ + + add = 'a' + /; if (r < 5) + add = add + r - 1 + ;; else if (r == 5 || r == 7) + add = 's' + ;; else if (r == 6) + add = 'd' + ;; else if (r == 8) + add = 'b' + ;/ + out.push(~add) + + /; if (r == 5 || r == 6) + add = 'i' + out.push(~add) + ;; else if (r == 7 || r == 8) + add = 'p' + out.push(~add) + ;; else if (size !== 1) + add = 'x' + out.push(~add) + ;/ + + /; if (size == 1) + add = 'l' + out.push(~add) + ;/ + ;; else if (r < 17) + add = 'r' + out.push(~add) + + ~uint8 num = utils.int_to_str(r - 1) + out.push_cstr(num) + _delete(num) + /; if (size == 1) + add = 'b' + out.push(~add) + ;; else if (size == 2) + add = 'w' + out.push(~add) + ;; else if (size == 4) + add = 'd' + out.push(~add) + ;/ + ;; else if (r < 33) + out.push_cstr("xmm\0") + ~uint8 num = utils.int_to_str(r - 17) + out.push_cstr(num) + _delete(num) + ;/ + + return out.as_cstr() +;/ + +# Valid value states: +# When loc is DATA value is in the data section and the name is actually the label +# When loc is STCK value is offset from rbp pointer using the offset +# When loc is 0 then offset represents a numeric literal +# When loc is positive then the variable exists in that register* +# Structs and references don't exactly exist in a register and so must +# be combined with the offset to get a resonable approximation + +# So when computing the location of a standard type... +# ...just load from the register +# ...Unless it's a ref in which case take into account the offset +# ...Or it's a DATA in which case load from rel label +# ...Or it's on the stack in which case load from +# ...Or it's a literal in which case just use the literal value + +# So when computing the location of a struct... +# ...Load as an offset from a register +# ...Unless it's on the stack (offset from rbp) +# ...Or it's in DATA (offset from rel label) +# ...Or it's a ref (lea first ref and then just load direct values from there) + +struct Var { + ~uint8 name, + ~Struct _type, + utils.Vector ptrc, + int loc, offset, + + ~parse.Node _tn, _id, + + # Used for globals + ~Module parent +} + +/; method Var + + ########################### + # Init and copy functions # + ########################### + + # Dummy init + /; _init (~Struct _type) + self.name = utils.strcpy("dummy\0") + self.ptrc.init(4) + self.loc = 0 + self.offset = 0 + self._type = _type + self.parent = NULL + self._tn = NULL + self._id = NULL + ;/ + + # Initial init function, requires type node and + # identifier node + /; init (~parse.Node tn, id) + self.name = utils.strcpy(id`.data) + self.ptrc.init(4) + self.loc = 0 + self.offset = 0 + self.parent = NULL + + self._tn = tn + self._id = id + ;/ + + # Deep copy the variable + /; copy [Var] + Var out = self.shallow_copy() + + /; loop (int i = 0; i < self.ptrc.count) [i++] + ~int32 p = self.ptrc.get(i) + out.ptrc.push(p) + ;/ + + return out + ;/ + + # A copy without the pointer chain + /; shallow_copy [Var] + Var out + /; if (self._tn !== NULL) + out.init(self._tn, self._id) + out._type = self._type + ;; else + out._init(self._type) + _delete(out.name) + out.name = utils.strcpy(self.name) + ;/ + out.loc = self.loc + out.offset = self.offset + return out + ;/ + + ############################# + # Variable inspection funcs # + ############################# + + # Get a pointer to the top of the pointer chain, returns + # null if the pointer chain is empty + /; top_ptrc [~int32] + # Sanity + /; if (self.ptrc.count < 1) + return NULL + ;/ + + ~int32 out = self.ptrc.get(self.ptrc.count - 1) + return out + ;/ + + /; is_ptrc (int idx, int32 ptype) [bool] + /; if (idx !< self.ptrc.count) + return false + ;/ + + idx = self.ptrc.count - idx + idx = idx - 1 + ~int32 chk = self.ptrc.get(idx) + return chk` == ptype + ;/ + + /; strip_refs + /; loop (self.is_ptrc(0, 0) == true) + self.ptr_pop() + ;/ + ;/ + + # Returns true if the variable is a reference + /; is_ref [bool] + return self.is_ptrc(0, 0) + ;/ + + # Returns true if two or more ref layers + /; double_ref [bool] + /; if (self.is_ref() == false) + return false + ;/ + return self.is_ptrc(1, 0) + ;/ + + # Ref level + /; max_ref [int] + int out = 0 + /; loop (int i = 0; i < self.ptrc.count) [i++] + /; if (self.is_ptrc(i, 0) == true) + out++ + ;; else + i = self.ptrc.count + ;/ + ;/ + return out + ;/ + + # Returnes true if the underlying type is a signed integer + /; is_signed [bool] + /; if (_is_primitive(self._type`.name) !== 0) + return self._type`.name{0} == 'i' + ;/ + return false + ;/ + + # Returns true if the variable is a pointer + /; is_ptr [bool] + ~int32 p = self.top_ptrc() + /; if (p == NULL) + return false + ;/ + + return p` < 0 + ;/ + + # Returns true if the variable is an array + /; is_arr [bool] + ~int32 p = self.top_ptrc() + /; if (p == NULL) + return false + ;/ + + return p` > 0 + ;/ + + # Whether the variable can be stored within a register + /; regable [bool] + ~int p + /; if (self.ptrc.count > 0) + return true + ;/ + return _is_primitive(self._type`.name) !== 0 + ;/ + + /; is_struct [bool] + # Check first if we are a pointer of some sort + ~int32 p + /; loop (int i = 0; i < self.ptrc.count) [i++] + p = self.ptrc.get(i) + /; if (p` !== 0) + return false + ;/ + ;/ + + return _is_primitive(self._type`.name) == 0 + ;/ + + # Compute and add the correct pointer chain value for an array + # type prefix + /; _arr_ptr(~parse.Node a) + int32 ptr = 1 + /; if (a`.sub.count > 0) + ~parse.Node l = a`.sub.get(0) + ptr = utils.cstr_to_int(l`.data) + /; if (ptr < 2) + return + ;/ + ;/ + self.ptrc.push(~ptr) + ;/ + + # The "actual size" of the variable (if we were to do a mov on it + # how much space would we need) + /; actual_size [uint] + /; if (self.ptrc.count > 0) + return 8 + ;; else if (self._type == NULL) + return 0 + ;/ + + return self._type`.size + ;/ + + /; type_size [uint] + /; loop (int i = 0; i < self.ptrc.count) [i++] + ~int32 p = self.ptrc.get(i) + /; if (p` !== 0) + return 8 + ;/ + ;/ + + return self._type`.size + ;/ + + /; find_method (~uint8 name) [~Function] + ~int32 p + /; loop (int i = 0; i < self.ptrc.count) [i++] + p = self.ptrc.get(i) + /; if (p` !== 0) + _printf("ERROR: Tried to find method \"\0") + _printf(name) + _printf("\" on a variable but we had a pointer in the chain\n\0") + return false + ;/ + ;/ + + ~Module mod = self._type`.methods + ~Function out = mod`._find_func(name) + return out + ;/ + + ##################################### + # Variable manipulation (comp time) # + ##################################### + + # Reverse the pointer chain + /; _reverse_ptrc + int max = self.ptrc.count / 2 + ~int32 l, r + /; loop (int i = 0; i < max) [i++] + l = self.ptrc.get(i) + r = self.ptrc.get(self.ptrc.count - (i + 1)) + int32 tmp = l` + l` = r` + r` = tmp + ;/ + ;/ + + # Sets up both the ptrc and the _type members, requires + # parent module for resolution of types + /; _resolve_type (~Module parent) + int idx = 0 + bool running = true + ~parse.Node t, _tn + _tn = self._tn + + # Pre-op pointer + /; loop (running == true) + /; if (idx !< _tn`.sub.count) + running = false + ;; else + t = _tn`.sub.get(idx) + /; if (t`._type == parse.NTYPE_PRE_OP) + /; if (utils.strcmp(t`.data, "~\0") == true) + int32 ptr = 0 + ptr = ptr - PTYPE_PTR + self.ptrc.push(~ptr) + ;; else + self._arr_ptr(t) + ;/ + ;; else + running = false + ;/ + ;/ + + /; if (running == true) + idx++ + ;/ + ;/ + + self._reverse_ptrc() + + # After pre-ops comes id + utils.Vector strv + strv.init(8) + running = true + /; loop (running == true) + /; if (idx !< _tn`.sub.count) + running = false + ;; else + t = _tn`.sub.get(idx) + /; if (t`._type == parse.NTYPE_ID) + ~uint8 str = t`.data + strv.push(~str) + ;; else + running = false + ;/ + ;/ + + /; if (running == true) + idx++ + ;/ + ;/ + + # Main type resolution + # TODO: FUNCTION POINTER + self._type = parent`.find(SEARCH_STRUCT, ~strv) + strv.end() + + # Post-op pointer + running = true + /; loop (running == true) + /; if (idx !< _tn`.sub.count) + running = false + ;; else + t = _tn`.sub.get(idx) + /; if (t`._type == parse.NTYPE_POST_OP) + int32 ptr = 0 + self.ptrc.push(~ptr) + ;/ + ;/ + + /; if (running == true) + idx++ + ;/ + ;/ + ;/ + + ###################### + # Static compilation # + ###################### + + /; _static_compile_arr(~parse.Node n, ~utils.Vector out, int depth) [~uint8] + return utils.strcpy("TODO\0") + ;/ + + /; _static_compile_ptr(~parse.Node n, ~utils.Vector out, int depth) [~uint8] + + /; if (n`._type == parse.NTYPE_VALUE) + n = n`.sub.get(0) + return self._static_compile_ptr(n, out, depth) + ;/ + + /; if (n`._type == parse.NTYPE_LITERAL) + + /; if (n`.data{0} == '"') + # Generate string + ~uint8 tmp = self._global_ptr() + out`.push_cstr(tmp) + out`.push_cstr(":\n\0") + _delete(tmp) + + + utils.Vector vout = utils.unquote_str(n`.data) + tmp = utils.int_to_str(vout.count) + out`.push_cstr(" dq \0") + out`.push_cstr(tmp) + out`.push_cstr("\n\0") + _delete(tmp) + + /; if (vout.count > 0) + out`.push_cstr(" db \0") + ;/ + + /; loop (int i = 1; i < vout.count) [i++] + ~uint8 uptr = vout.get(i - 1) + uint8 utmp = uptr` + tmp = utils.int_to_str(utmp) + out`.push_cstr(tmp) + out`.push_cstr(", \0") + _delete(tmp) + ;/ + + /; if (vout.count > 0) + int i = vout.count + ~uint8 uptr = vout.get(i - 1) + uint8 utmp = uptr` + tmp = utils.int_to_str(utmp) + out`.push_cstr(tmp) + _delete(tmp) + ;/ + + out`.push_cstr("\n\0") + + # Generate response text + vout.end() + tmp = self._global_ptr() + vout.from_cstr(" dq \0") + vout.push_cstr(tmp) + _delete(tmp) + + int idx = self.ptrc.count - 1 + idx = idx - depth + ~int32 pc = self.ptrc.get(idx) + /; if (pc` < 1) + vout.push_cstr(" + 8\0") + ;/ + vout.push_cstr("\n\0") + + return vout.as_cstr() + ;/ + + # Literal not string - literal address + # TODO + ;; else if (n`._type == parse.NTYPE_VLIST) + return self._static_compile_arr(n, out, depth) + ;/ + + # Do a literal evaluation and then + return utils.strcpy("TODO\0") + ;/ + + /; _static_compile_struct(~parse.Node n, ~utils.Vector out) [~uint8] + return utils.strcpy("TODO\0") + ;/ + + /; _static_comp_prim_r_dot(~parse.Node n) [Var] + # Has to do: + # Variable dot chain mod + # Variable dot chain struct + _printf("TODO: _static_comp_prim_r_dot\n\0") + Var out + out._init(self._type) + return out + ;/ + + /; _static_comp_prim_r_bin(~parse.Node n) [Var] + /; if (n`.data{0} == '.') + return self._static_comp_prim_r_dot(n) + ;/ + + ~parse.Node na = n`.sub.get(0) + ~parse.Node nb = n`.sub.get(1) + + Var a = self._static_comp_prim_r(na) + Var b = self._static_comp_prim_r(nb) + + /; if (a.loc !== 0) + _printf("TODO: _static_comp_prim_r_bin: Pointer types not yet supported in binary ops at compile time\n\0") + b.end() + return a + ;; else if (b.loc !== 0) + _printf("TODO: _static_comp_prim_r_bin: Pointer types not yet supported in binary ops at compile time\n\0") + a.end() + return b + ;/ + + /; if (utils.strcmp(n`.data, "*\0") == true) + a.offset = a.offset * b.offset + ;; else if (utils.strcmp(n`.data, "/\0") == true) + a.offset = a.offset / b.offset + ;; else if (utils.strcmp(n`.data, "%\0") == true) + a.offset = a.offset % b.offset + ;; else if (utils.strcmp(n`.data, "+\0") == true) + a.offset = a.offset + b.offset + ;; else if (utils.strcmp(n`.data, "-\0") == true) + a.offset = a.offset - b.offset + ;; else + _printf("TODO: _static_comp_prim_r_bin: Bin op \"\0") + _printf(n`.data) + _printf("\" not yet supported at comptime\n\0") + ;/ + + b.end() + return a + ;/ + + /; _static_comp_prim_r_pre(~parse.Node n) [Var] + _printf("TODO: _static_comp_prim_r_pre\n\0") + Var out + out._init(self._type) + return out + ;/ + + /; _static_comp_prim_r_post(~parse.Node n) [Var] + # Has to do: + # deref of variables + # array index + _printf("TODO: _static_comp_prim_r_post\n\0") + Var out + out._init(self._type) + return out + ;/ + + /; _static_comp_prim_r_id(~parse.Node n) [Var] + # Has to do: + # Get variable and static comp + ~uint8 name = n`.data + utils.Vector v + v.init(8) + v.push(~name) + ~Var vid = self.parent`.find(SEARCH_VAR, ~v) + v.end() + + /; if (vid == NULL) + _printf("ERROR: Unable to find id \"\0") + _printf(name) + _printf("\" when compiling global \"\0") + _printf(self.name) + _printf(" returning dummy\n\0") + Var out + out._init(self._type) + return out + ;/ + + /; if (vid`.loc > 0) + _printf("ERROR: CIRCULAR REFERENCE DETECTED WHEN INITIALIZING GLOBAL!\n\0") + _printf(" Something in \"\0") + _printf(name) + _printf("\" depends on \"") + _printf(self.name) + _printf("\" which depends on the former.\n\0") + Var out + out._init(self._type) + return out + ;/ + + /; if (vid`.is_struct() == true) + _printf("ERROR: Attempted to set primitive global \"\0") + _printf(self.name) + _printf("\" to \"") + _printf(name) + _printf("\" which is a struct, not a primitive\n\0") + Var out + out._init(self._type) + return out + ;; else if (vid`.ptrc.count > 0) + return vid`.as_global() + ;/ + + # If this is also a primitive, we want to do a static comp and + # return whatever the variable spits out + ~parse.Node cross_n = vid`._id + + /; if (cross_n`.sub.count < 1) + cross_n = NULL + ;; else + cross_n = cross_n`.sub.get(0) + /; if (cross_n`._type !== parse.NTYPE_VALUE) + _printf("COMPILER ERROR: When static compiling var \"\0") + _printf(name) + _printf("\" the sub-node was not a value\n\0") + Var out + out._init(self._type) + return out + ;; else if (cross_n`.sub.count < 1) + cross_n = NULL + ;; else + cross_n = cross_n`.sub.get(0) + ;/ + ;/ + + /; if (cross_n !== NULL) + return vid`._static_comp_prim_r(cross_n) + ;/ + + Var out + out._init(self._type) + return out + ;/ + + /; _static_comp_prim_r(~parse.Node n) [Var] + /; if (n`._type == parse.NTYPE_VALUE) + n = n`.sub.get(0) + return self._static_comp_prim_r(n) + ;/ + + /; if (n`._type == parse.NTYPE_LITERAL) + int lval = 0 + /; if (utils.strcmp(n`.data, "true\0") == true) + lval = 1 + ;; else if (utils.strcmp(n`.data, "iota\0") == true) + _printf("COMPILER ERROR: iota not yet implemented\n\0") + ;; else if (n`.data{0} !< '0' && n`.data{0} !> '9') + lval = utils.cstr_to_int(n`.data) + ;; else if (n`.data{0} == '\'') + ~uint8 cha = n`.data + cha++ + uint8 uval = utils.unquote_cha(cha) + lval = uval + ;; else if (n`.data{0} == '"') + _printf("ERROR: Attempted to set a non-pointer or non-array to a string literal!\n\0") + _printf(" Literal: \0") + _printf(n`.data) + _printf("\n\0") + ;/ + Var out + out._init(self._type) + out.offset = lval + return out + ;; else if (n`._type == parse.NTYPE_BIN_OP) + return self._static_comp_prim_r_bin(n) + ;; else if (n`._type == parse.NTYPE_PRE_OP) + return self._static_comp_prim_r_pre(n) + ;; else if (n`._type == parse.NTYPE_POST_OP) + return self._static_comp_prim_r_post(n) + ;; else if (n`._type == parse.NTYPE_ID) + return self._static_comp_prim_r_id(n) + ;/ + + _printf("COMPILER ERROR: _static_comp_prim_r: Unable to work on node given\n\0") + Var out + out._init(self._type) + return out + ;/ + + /; _static_compile_prim(~parse.Node n) [~uint8] + Var vout = self._static_comp_prim_r(n) + + utils.Vector out + out.init(1) + + int sz = self.type_size() + /; if (sz == 1) + out.push_cstr(" db \0") + ;; else if (sz == 2) + out.push_cstr(" dw \0") + ;; else if (sz == 4) + out.push_cstr(" dd \0") + ;; else if (sz == 8) + out.push_cstr(" dq \0") + ;/ + + /; if (vout.loc == 0) + ~uint8 nstr = utils.int_to_str(vout.offset) + out.push_cstr(nstr) + out.push_cstr("\n\0") + _delete(nstr) + ;; else + _print_num("COMPILER ERROR: Type of var %d not yet supported for static comp\n\0", vout.loc) + ;/ + + vout.end() + return out.as_cstr() + ;/ + + /; _static_compile_zero [~uint8] + utils.Vector zero + zero.from_cstr(" db \0") + int sz = self.type_size() + /; loop (int i = 1; i < sz) [i++] + zero.push_cstr("0, \0") + ;/ + zero.push_cstr("0\n\0") + return zero.as_cstr() + ;/ + + # Compile the variable into the data section + /; _static_compile (~CompBuf buf) + # Mark we are in compilation stage to detect circular refs + self.loc = 1 + + # Get node which we are statically compiling + ~parse.Node n = self._id + /; if (n`.sub.count < 1) + n = NULL + ;; else + n = n`.sub.get(0) + /; if (n`._type !== parse.NTYPE_VALUE) + _printf("COMPILER ERROR: When static compiling var \"\0") + _printf(self.name) + _printf("\" the sub-node was not a value\n\0") + return + ;; else if (n`.sub.count < 1) + n = NULL + ;; else + n = n`.sub.get(0) + ;/ + ;/ + + utils.Vector out + out.init(1) + + ~uint8 after + /; if (n == NULL) + # Fallback to zero initialization if no value provided + after = self._static_compile_zero() + ;; else if (self.ptrc.count > 0) + # Pointer, reference, or array + after = self._static_compile_ptr(n, ~out, 0) + ;; else if (self.is_struct() == true) + # struct, should either be a vlist with all required parameters or a + # variable of the same type which we can static compile from + after = self._static_compile_struct(n, ~out) + ;; else + # primitive + after = self._static_compile_prim(n) + ;/ + + # Generate label and data + ~uint8 lab = self._global_base() + out.push_cstr(lab) + out.push_cstr(":\n\0") + out.push_cstr(after) + _delete(after) + _delete(lab) + + # Add to data sec + ~uint8 outs = out.as_cstr() + buf`.add_d(outs) + buf`.add_d("\n\0") + out.end() + + # No longer compiling this variable + self.loc = 0 + ;/ + + /; _global_base [~uint8] + utils.Vector name + name.init(1) + _recursive_mod_name(self.parent, ~name) + + /; if (name.count !== 0) + name.push_char('.') + ;/ + + name.push_cstr(self.name) + return name.as_cstr() + ;/ + + /; _global_ptr [~uint8] + utils.Vector name + name.init(1) + _recursive_mod_name(self.parent, ~name) + + /; if (name.count !== 0) + name.push_char('.') + ;/ + + name.push_cstr(self.name) + name.push_cstr("#ptr\0") + + return name.as_cstr() + ;/ + + # Get a proper global variable + /; as_global [Var] + Var out = self.copy() + out.name = self._global_base() + + int loc = 0 + loc = loc - 2 + out.loc = loc + + return out + ;/ + + /; ptr_push (int32 p) + self.ptrc.push(~p) + ;/ + + /; ptr_pop + self.ptrc.pop() + ;/ + + /; end + _delete(self.name) + self.ptrc.end() + ;/ + + #################################### + # Variable manipulation (run time) # + #################################### + + # Returns true if the variable is known to be stored in memory + /; in_mem [bool] + /; if (self.loc < 1) + return true + ;/ + + ~int32 ptr = self.top_ptrc() + /; if (ptr !== NULL) + /; if (ptr` == 0) + return true + ;; else if (ptr` > 1) + return true + ;/ + ;/ + + return false + ;/ + + + # Typechecking + + # Typechecking structs + /; _tc_struct (~Var other) [bool] + /; if (other`.is_struct() == false) + return false + ;/ + ~void a = self._type + ~void b = other`._type + + return a == b + ;/ + + /; _tc_prim (~Var other) [bool] + # Allow implicit ptr conversions + /; if (self.is_ptr() == true) + return other`.is_ptr() + ;/ + + return false + ;/ + + # Operations + + # Helper to gen register when setting a struct + /; _set_struct_r (~CompBuf buf, int reg) + ~uint8 r = reg_string(reg, 8) + + buf`.add_c(" ; putting struct address into register\n\0") + + # Initial deref or move + /; if (self.ptrc.count > 1) + buf`.add_c(" mov \0") + ;; else + buf`.add_c(" lea \0") + ;/ + buf`.add_c(r) + buf`.add_c(", [\0") + + # Reg, stack, or data + /; if (self.loc + VLOC_DATA == 0) + buf`.add_c("rel \0") + buf`.add_c(self.name) + ;; else if (self.loc + VLOC_STCK == 0) + ~uint8 get_reg = reg_string(8, 8) + buf`.add_c(get_reg) + _delete(get_reg) + ;; else + ~uint8 get_reg = reg_string(self.loc, 8) + buf`.add_c(get_reg) + _delete(get_reg) + ;/ + + # Deal with offset + /; if (self.offset !== 0) + int o = self.offset + /; if (o < 0) + o = 0 - o + buf`.add_c(" - \0") + ;; else + buf`.add_c(" + \0") + ;/ + ~uint8 its = utils.int_to_str(o) + buf`.add_c(its) + _delete(its) + ;/ + + buf`.add_c("] ; initial struct addr move\n\0") + + # For as many more times as there are references + /; loop (int i = 1; i < self.ptrc.count) [i++] + buf`.add_c(" mov \0") + buf`.add_c(r) + buf`.add_c(", [\0") + buf`.add_c(r) + buf`.add_c("] ; reference chain\n\0") + ;/ + + _delete(r) + ;/ + + # Helper to properly move a struct in memory + /; _set_struct(~CompBuf buf, ~Var other) + # Typecheck + /; if (self._tc_struct(other) == false) + _printf("ERROR: Types do not match when setting struct. [\0") + _printf(self._type`.name) + _printf("] !== [\0") + _printf(other`._type`.name) + _printf("]\n\0") + return + ;/ + + # Have to get struct address (to set) into rdi + self._set_struct_r(buf, 6) + # Have to get struct address (to read) into rsi + other`._set_struct_r(buf, 5) + + # Setup move size + ~uint8 str + str = utils.int_to_str(self._type`.size) + buf`.add_c(" mov rcx, \0") + buf`.add_c(str) + buf`.add_c(" ; size of struct [\0") + buf`.add_c(self._type`.name) + buf`.add_c("] in bytes\n\0") + _delete(str) + + # Move byte (rcx times) + buf`.add_c(" rep movsb ; move struct\n\0") + + ;/ + + # Helper to properly get the lhs of a set + /; _set_prim_l (~CompBuf buf) [~uint8] + /; if (self.loc == 0) + _printf("SET WAS CALLED ON A LITERAL! THIS IS A COMPILER ERROR!\0") + return utils.strcpy("ERR SHOULD NOT HAPPEN - TRIED TO SETPRIML ON A LITERAL\0") + ;/ + + # Base of address/register + ~uint8 out + /; if (self.loc > 0) + /; if (self.in_mem() == true) + out = reg_string(self.loc, 8) + /; if (self.offset !== 0) + utils.Vector vout + vout.from_cstr(out) + + int off = self.offset + /; if (off < 0) + off = 0 - off + vout.push_cstr(" - \0") + ;; else if (off > 0) + vout.push_cstr(" + \0") + ;/ + + _delete(out) + out = utils.int_to_str(off) + vout.push_cstr(out) + _delete(out) + out = vout.as_cstr() + ;/ + ;; else + uint sz = self.type_size() + out = reg_string(self.loc, sz) + ;/ + ;; else + utils.Vector vout + /; if (self.loc + 1 == 0) + # Stack + vout.from_cstr("rbp\0") + ;; else + vout.from_cstr("rel \0") + vout.push_cstr(self.name) + ;/ + + int off = self.offset + /; if (off < 0) + off = 0 - off + vout.push_cstr(" - \0") + ;; else if (off > 0) + vout.push_cstr(" + \0") + ;/ + + /; if (off !== 0) + out = utils.int_to_str(off) + vout.push_cstr(out) + _delete(out) + ;/ + + out = vout.as_cstr() + + /; if (self.is_ref() == true) + # Need to move into rdi + buf`.add_c(" mov rdi, [\0") + buf`.add_c(out) + buf`.add_c("]\n\0") + _delete(out) + out = utils.strcpy("rdi\0") + ;/ + ;/ + + # If in memory we need to wrap in [] + /; if (self.in_mem() == true) + utils.Vector vout + vout.from_cstr("[\0") + vout.push_cstr(out) + vout.push_cstr("]\0") + + _delete(out) + out = vout.as_cstr() + ;/ + + # Loop and make sure we are dereferencing properly + /; loop (int i = 1; i < self.ptrc.count) [i++] + /; if (self.is_ptrc(i, 0) == true) + buf`.add_c(" mov rdi, [rdi] ; auto deref\n\0") + ;; else + i = self.ptrc.count + ;/ + ;/ + + /; if (self.double_ref() == true) + _delete(out) + out = utils.strcpy("[rdi]\0") + ;/ + + /; if (out{0} == '[') + utils.Vector vout + uint ts = self.type_size() + /; if (ts == 1) + vout.from_cstr("byte \0") + ;; else if (ts == 2) + vout.from_cstr("word \0") + ;; else if (ts == 4) + vout.from_cstr("dword \0") + ;; else if (ts == 8) + vout.from_cstr("qword \0") + ;/ + vout.push_cstr(out) + + _delete(out) + out = vout.as_cstr() + ;/ + + return out + ;/ + + # Helper to properly get the rhs of a set + /; _set_prim_r (~CompBuf buf, ~Var lhs) [~uint8] + /; if (self.loc == 0) + ~uint8 o = utils.int_to_str(self.offset) + return o + ;/ + + ~uint8 out = self._set_prim_l(buf) + + /; if (self.in_mem() == true) + utils.Vector vout + uint ts = self.type_size() + /; if (ts == 1) + vout.from_cstr("byte \0") + ;; else if (ts == 2) + vout.from_cstr("word \0") + ;; else if (ts == 4) + vout.from_cstr("dword \0") + ;; else if (ts == 8) + vout.from_cstr("qword \0") + ;/ + vout.push_cstr(out) + + _delete(out) + out = vout.as_cstr() + ;/ + + # Sign extend if required + bool ext = false + uint R = self.type_size() + uint L = lhs`.type_size() + /; if (R < L) + ext = true + ~uint8 vout = reg_string(5, L) + + /; if (lhs`.is_signed() == true && self.is_signed() == true) + /; if (R < 4) + buf`.add_c(" movsx \0") + ;; else + buf`.add_c(" movsxd \0") + ;/ + buf`.add_c(vout) + buf`.add_c(", \0") + ;; else if (R < 4) + buf`.add_c(" movzx \0") + buf`.add_c(vout) + buf`.add_c(", \0") + ;; else + buf`.add_c(" mov esi, \0") + ;/ + + buf`.add_c(out) + buf`.add_c("\n\0") + _delete(out) + out = vout + ;/ + + /; if (ext == false) + /; if (self.in_mem() == true && lhs`.in_mem() == true) + ~uint8 vout = reg_string(5, L) + buf`.add_c(" mov \0") + buf`.add_c(vout) + buf`.add_c(", \0") + buf`.add_c(out) + buf`.add_c("\n\0") + _delete(out) + out = vout + ;/ + ;/ + + return out + ;/ + + + # Set this Variable to the value of other + /; set (~CompBuf buf, ~Var other) + # Options: + # - If builtin then move based on size (byte, word, dword, qword) + # - If pointer then move qword + # - If struct then move via rep movsb + + /; if (self.is_struct() == true) + # Struct set + self._set_struct(buf, other) + return + ;/ + + # Generate lhs set and rhs set + ~uint8 sr = other`._set_prim_r(buf, ~self) + ~uint8 sl = self._set_prim_l(buf) + + buf`.add_c(" mov \0") + buf`.add_c(sl) + buf`.add_c(", \0") + buf`.add_c(sr) + buf`.add_c("\n\0") + + _delete(sl) + _delete(sr) + ;/ + + # Set the address which this reference points to + /; set_ref (~CompBuf buf, ~Var other, int depth) + # count how many refs + int max_depth = self.max_ref() + + /; if (depth !< max_depth) + _print_num("ERROR: Unable to set reference, depth %d equals or exceeds max_depth \0", depth) + _print_num("%d\n\0", max_depth) + _printf(" When taking ref of variable \"\0") + _printf(other`.name) + _printf("\" into variable \"\0") + _printf(self.name) + _printf("\"\n\0") + return + ;/ + + int32 set = 0 + set = set - 1 + + max_depth = self.ptrc.count - max_depth + max_depth = max_depth + depth + + Var copy = self.copy() + ~int32 ptr = copy.ptrc.get(max_depth) + ptr` = set + copy.set(buf, other) + copy.end() + ;/ + + # Copy the pointer to this variable into the output reg (or not if not needed) + /; take_ptr (~CompBuf buf, int reg) [Var] + Var vcpy = self.copy() + /; if (self.in_mem() == false) + _printf("ERROR: UNABLE TO GET REFERENCE OF VAR \"\0") + _printf(self.name) + _printf("\"\n\0") + return vcpy + ;/ + + int32 set = 0 + set = set - 1 + /; if (vcpy.is_ref() == true) + # If we are a ref, we want to set the first one and that's it + int idx = 0 + /; loop (int i = 0; i < vcpy.ptrc.count) [i++] + /; if (vcpy.is_ptrc(i, 0) == false) + i = vcpy.ptrc.count + ;; else + idx++ + ;/ + ;/ + + idx = vcpy.ptrc.count - idx + ~int32 p = vcpy.ptrc.get(idx) + p` = set + ;; else + /; if (self.is_struct() == true) + self._set_struct_r(buf, reg) + ;; else + ~uint8 source = self._set_prim_l(buf) + ~uint8 rstr = reg_string(reg, 8) + buf`.add_c(" lea \0") + buf`.add_c(rstr) + buf`.add_c(", \0") + buf`.add_c(source) + buf`.add_c("\n\0") + _delete(source) + _delete(rstr) + ;/ + + vcpy.loc = reg + vcpy.offset = 0 + vcpy.ptrc.end() + vcpy.ptrc.init(4) + vcpy.ptr_push(set) + ;/ + + return vcpy + ;/ + + /; _de_ref + uint idx = self.ptrc.count + ~int32 ptr + /; loop (idx > 0) + idx = idx - 1 + ptr = self.ptrc.get(idx) + /; if (ptr` !== 0) + /; if (ptr` > 0) + _printf("ERROR: Can't take direct de-ref of array variable, try an index (name: \"\0") + _printf(self.name) + _printf("\")\n\0") + ;; else + ptr` = 0 + ;/ + return + ;/ + ;/ + ;/ + + /; de_ref [Var] + Var out = self.copy() + out._de_ref() + return out + ;/ + + /; index (~CompBuf buf, ~Var idx, int reg) [Var] + buf`.add_c(" ; Gen index\n\0") + + # Create a literal with the size of the type + # Don't need to init or end this one + uint mul_sz = self.type_size() + Var oo + oo.offset = mul_sz + oo.loc = 0 + + # Generate output variable + Var out = self.copy() + out.offset = 0 + out.loc = reg + + # Strip off any refs + /; loop (out.is_ref() == true) + out.ptr_pop() + ;/ + + # Multiply index by size of type + out.set(buf, idx) + out.mul(buf, ~oo) + + # If we are an array, want to add 8 since the beginning encodes the length + /; if (out.is_arr() == true) + oo.offset = 8 + out.add(buf, ~oo) + ;/ + + # Get address in rsi + ~uint8 to_str = self._set_prim_l(buf) + + # If we are a "known length array" we need to lea instead of mov + ~int32 optrc = out.top_ptrc() + /; if (optrc !== NULL) + /; if (optrc` > 1) + buf`.add_c(" lea rsi, \0") + ;; else + buf`.add_c(" mov rsi, \0") + ;/ + ;; else + _printf("ERROR: Can't take index of non-array variable \"\0") + _printf(self.name) + _printf("\"\n\0") + _delete(to_str) + return out + ;/ + buf`.add_c(to_str) + buf`.add_c("\n\0") + _delete(to_str) + + # Add address to computed offset + to_str = out._set_prim_l(buf) + buf`.add_c(" add \0") + buf`.add_c(to_str) + buf`.add_c(", rsi\n\0") + + # deref + int32 ptr_ref = 0 + out.ptr_pop() + out.ptr_push(ptr_ref) + + return out + ;/ + + ####################### + # Standard operations # + ####################### + + /; standard_op (~CompBuf buf, ~Var other, ~uint8 op_str) + ~uint8 from_str = other`._set_prim_r(buf, ~self) + ~uint8 to_str = self._set_prim_l(buf) + + buf`.add_c(" \0") + buf`.add_c(op_str) + buf`.add_c(" \0") + buf`.add_c(to_str) + buf`.add_c(", \0") + buf`.add_c(from_str) + buf`.add_c("\n\0") + + _delete(from_str) + _delete(to_str) + ;/ + + /; add (~CompBuf buf, ~Var other) + /; if (self.loc == VLOC_LITL && other`.loc == VLOC_LITL) + self.offset = self.offset + other`.offset + return + ;/ + + self.standard_op(buf, other, "add\0") + ;/ + + /; sub (~CompBuf buf, ~Var other) + /; if (self.loc == VLOC_LITL && other`.loc == VLOC_LITL) + self.offset = self.offset - other`.offset + return + ;/ + + self.standard_op(buf, other, "sub\0") + ;/ + + /; and (~CompBuf buf, ~Var other) + /; if (self.loc == VLOC_LITL && other`.loc == VLOC_LITL) + self.offset = self.offset & other`.offset + return + ;/ + + self.standard_op(buf, other, "and\0") + ;/ + + /; or (~CompBuf buf, ~Var other) + /; if (self.loc == VLOC_LITL && other`.loc == VLOC_LITL) + self.offset = self.offset | other`.offset + return + ;/ + + self.standard_op(buf, other, "or\0") + ;/ + + /; xor (~CompBuf buf, ~Var other) + /; if (self.loc == VLOC_LITL && other`.loc == VLOC_LITL) + self.offset = self.offset ^ other`.offset + return + ;/ + + self.standard_op(buf, other, "xor\0") + ;/ + + # Product op + + /; mul (~CompBuf buf, ~Var other) + /; if (self.loc == VLOC_LITL && other`.loc == VLOC_LITL) + self.offset = self.offset * other`.offset + return + ;/ + + ~uint8 from_str = other`._set_prim_r(buf, ~self) + ~uint8 to_str = self._set_prim_l(buf) + + /; if (self.in_mem() == true) + uint sz = self.type_size() + ~uint8 ax = reg_string(1, sz) + + # Move to ax register for the mul and move back afterward + buf`.add_c(" mov \0") + buf`.add_c(ax) + buf`.add_c(", \0") + buf`.add_c(to_str) + buf`.add_c("\n\0") + + # Do actual product + buf`.add_c(" imul \0") + buf`.add_c(ax) + buf`.add_c(", \0") + buf`.add_c(from_str) + buf`.add_c("\n\0") + + # Move back + buf`.add_c(" mov \0") + buf`.add_c(to_str) + buf`.add_c(", \0") + buf`.add_c(ax) + buf`.add_c("\n\0") + + _delete(ax) + ;; else + buf`.add_c(" imul \0") + buf`.add_c(to_str) + buf`.add_c(", \0") + buf`.add_c(from_str) + buf`.add_c("\n\0") + ;/ + + _delete(from_str) + _delete(to_str) + ;/ + + # Division op + + /; _div(~CompBuf buf, ~Var other, int r) + ~uint8 from_str = other`._set_prim_r(buf, ~self) + ~uint8 to_str = self._set_prim_l(buf) + uint sz = self.type_size() + ~uint8 rstr = reg_string(1, sz) + + /; if (other`.loc == 0) + # Move literal into register + buf`.add_c(" mov rcx, \0") + buf`.add_c(from_str) + buf`.add_c("\n\0") + _delete(from_str) + from_str = reg_string(3, sz) + ;/ + + # Move dividend into rax + buf`.add_c(" mov \0") + buf`.add_c(rstr) + buf`.add_c(", \0") + buf`.add_c(to_str) + buf`.add_c("\n\0") + + /; if (self.is_signed() == true) + # Sign extend + /; if (sz == 1) + buf`.add_c(" movsx ax, al\n\0") + ;; else if (sz == 2) + buf`.add_c(" cwd\n\0") + ;; else if (sz == 4) + buf`.add_c(" cdq\n\0") + ;; else if (sz == 8) + buf`.add_c(" cqo\n\0") + ;/ + + buf`.add_c(" idiv \0") + ;; else + # Zero out + buf`.add_c(" xor ") + /; if (sz == 1) + buf`.add_c("ah, ah\n\0") + ;; else if (sz == 2) + buf`.add_c("dx, dx\n\0") + ;; else if (sz == 4) + buf`.add_c("edx, edx\n\0") + ;; else if (sz == 8) + buf`.add_c("rdx, rdx\n\0") + ;/ + + buf`.add_c(" div \0") + ;/ + buf`.add_c(from_str) + buf`.add_c("\n\0") + + # Fix for bytes + _delete(rstr) + /; if (sz == 1 && r == 4) + rstr = utils.strcpy("ah\0") + ;; else + rstr = reg_string(r, sz) + ;/ + + + buf`.add_c(" mov \0") + buf`.add_c(to_str) + buf`.add_c(", \0") + buf`.add_c(rstr) + buf`.add_c("\n\0") + + _delete(from_str) + _delete(to_str) + _delete(rstr) + ;/ + + /; div (~CompBuf buf, ~Var other) + /; if (self.loc == VLOC_LITL && other`.loc == VLOC_LITL) + self.offset = self.offset / other`.offset + return + ;/ + + self._div(buf, other, 1) + ;/ + + /; mod (~CompBuf buf, ~Var other) + /; if (self.loc == VLOC_LITL && other`.loc == VLOC_LITL) + self.offset = self.offset % other`.offset + return + ;/ + + self._div(buf, other, 4) + ;/ + + /; _unary (~CompBuf buf, ~uint8 op) + ~uint8 to_str = self._set_prim_l(buf) + buf`.add_c(" \0") + buf`.add_c(op) + buf`.add_c(" \0") + /; if (self.in_mem() == true) + uint sz = self.type_size() + /; if (sz == 1) + buf`.add_c("byte \0") + ;; else if (sz == 2) + buf`.add_c("word \0") + ;; else if (sz == 4) + buf`.add_c("dword \0") + ;; else if (sz == 8) + buf`.add_c("qword \0") + ;/ + ;/ + buf`.add_c(to_str) + buf`.add_c("\n\0") + _delete(to_str) + ;/ + + /; not (~CompBuf buf) + /; if (self.loc == VLOC_LITL) + self.offset = !self.offset + return + ;/ + + self._unary(buf, "not\0") + ;/ + + /; neg (~CompBuf buf) + /; if (self.loc == VLOC_LITL) + int off = 0 + self.offset = off - self.offset + return + ;/ + + self._unary(buf, "neg\0") + ;/ + + /; inc (~CompBuf buf) + /; if (self.loc == VLOC_LITL) + self.offset++ + return + ;/ + + self._unary(buf, "inc\0") + ;/ + + /; dec (~CompBuf buf) + /; if (self.loc == VLOC_LITL) + self.offset++ + return + ;/ + + self._unary(buf, "dec\0") + ;/ + + # Boolean related + + /; test (~CompBuf buf) + ~uint8 to_str = self._set_prim_l(buf) + buf`.add_c(" cmp \0") + /; if (self.in_mem() == true) + uint sz = self.type_size() + /; if (sz == 1) + buf`.add_c("byte \0") + ;; else if (sz == 2) + buf`.add_c("word \0") + ;; else if (sz == 4) + buf`.add_c("dword \0") + ;; else if (sz == 8) + buf`.add_c("qword \0") + ;/ + ;/ + buf`.add_c(to_str) + buf`.add_c(", 0\n\0") + _delete(to_str) + ;/ + + /; cmov (~CompBuf buf, ~Var a, ~Var b, ~uint8 cc) + + buf`.add_c(" cmp \0") + ~uint8 a_str = a`._set_prim_l(buf) + buf`.add_c(a_str) + _delete(a_str) + buf`.add_c(", \0") + ~uint8 b_str = b`._set_prim_r(buf, a) + buf`.add_c(b_str) + _delete(b_str) + buf`.add_c("\n\0") + + buf`.add_c(" mov ax, 0\n\0") + buf`.add_c(" mov cx, 1\n\0") + buf`.add_c(" cmov\0") + buf`.add_c(cc) + buf`.add_c(" ax, cx ; Compare set\n\0") + + ~uint8 to_str = self._set_prim_l(buf) + + Var ax = self.copy() + ax.loc = 1 + + buf`.add_c(" mov \0") + ~uint8 to_str = self._set_prim_l(buf) + buf`.add_c(to_str) + _delete(to_str) + buf`.add_c(", \0") + ~uint8 ax_str = ax._set_prim_r(buf, ~self) + buf`.add_c(ax_str) + _delete(ax_str) + buf`.add_c(" ; Mov after compare\n\0") + ;/ + + /; cset (~CompBuf buf, ~uint8 cc) + buf`.add_c(" mov ax, 0\n\0") + buf`.add_c(" mov cx, 1\n\0") + buf`.add_c(" cmov\0") + buf`.add_c(cc) + buf`.add_c(" ax, cx ; Compare set\n\0") + + ~uint8 to_str = self._set_prim_l(buf) + + Var ax = self.copy() + ax.loc = 1 + + buf`.add_c(" mov \0") + ~uint8 to_str = self._set_prim_l(buf) + buf`.add_c(to_str)scope + _delete(to_str) + buf`.add_c(", \0") + ~uint8 ax_str = ax._set_prim_r(buf, ~self) + buf`.add_c(ax_str) + _delete(ax_str) + buf`.add_c(" ; Mov after compare\n\0") + ;/ + + /; member (~CompBuf buf, ~uint8 name) [Var] + /; if (self.is_struct() == false) + _printf("ERROR: Attempted to get a member named \"\0") + _printf(name) + _printf("\" from a primitive type \"\0") + _printf(self._type`.name) + _printf("\"\n\0") + _printf(" (If the previous type was in fact a structure then the variable was probably a pointer)\n\0") + Var out + out.loc = 0 + return out + ;/ + + ~Var mbr = self`._type`.get_member(name) + + /; if (mbr == NULL) + _printf("ERROR: member \"\0") + _printf(name) + _printf("\" not found in struct \"\0") + _printf(self._type`.name) + _printf("\n\0") + Var out + out.loc = 0 + return out + ;/ + + Var out = mbr`.copy() + + /; if (self.is_ref() == true) + self._set_struct_r(buf, 5) + out.loc = 5 + out.ptr_push(0) + ;; else + out.loc = self.loc + out.offset = out.offset + self.offset + ;/ + + # out._print(0) + return out + ;/ + + # Printing + + /; _print (int idt) + _indent(idt) + _printf("{ Var : \0") + _printf(self.name) + _printf("\n\0") + + _indent(idt + 1) + _printf("type: \0") + /; if (self._type !== NULL) + _printf(self._type`.name) + ;; else + _printf("(nil)\0") + ;/ + _printf("\n\0") + + _indent(idt + 1) + _printf("ptrc: \0") + ~int32 istr + /; loop (int i = 0; i < self.ptrc.count) [i++] + istr = self.ptrc.get(i) + _print_num("%d \0", istr`) + ;/ + _printf("\n\0") + + _indent(idt + 1) + _print_num("loc: %d\n\0", self.loc) + + _indent(idt + 1) + _print_num("off: %d\n\0", self.offset) + + _indent(idt) + _printf("}\n\0") + ;/ +;/ + + |