summaryrefslogtreecommitdiff
path: root/tnslc/compile
diff options
context:
space:
mode:
Diffstat (limited to 'tnslc/compile')
-rw-r--r--tnslc/compile/codegen.tnsl122
-rw-r--r--tnslc/compile/compbuf.tnsl45
-rw-r--r--tnslc/compile/compile.tnsl11
-rw-r--r--tnslc/compile/function.tnsl1918
-rw-r--r--tnslc/compile/generate.tnsl6
-rw-r--r--tnslc/compile/module.tnsl504
-rw-r--r--tnslc/compile/scope.tnsl752
-rw-r--r--tnslc/compile/struct.tnsl282
-rw-r--r--tnslc/compile/tests_var.tnsl248
-rw-r--r--tnslc/compile/type.tnsl360
-rw-r--r--tnslc/compile/var.tnsl1822
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")
+ ;/
+;/
+
+