From 06c25eef96d43f478fd28b44e0e9dfeae91d07cb Mon Sep 17 00:00:00 2001 From: Kai Gunger Date: Mon, 4 May 2026 02:10:38 -0400 Subject: [tnslc] better dot chain, begin on function call (not done) --- tnslc/compile/function.tnsl | 397 ++++++++++++++++++++++++++++++++------------ tnslc/compile/module.tnsl | 6 + tnslc/compile/scope.tnsl | 104 +++++++++++- tnslc/compile/var.tnsl | 3 +- 4 files changed, 394 insertions(+), 116 deletions(-) (limited to 'tnslc/compile') diff --git a/tnslc/compile/function.tnsl b/tnslc/compile/function.tnsl index f945479..6f6388e 100644 --- a/tnslc/compile/function.tnsl +++ b/tnslc/compile/function.tnsl @@ -6,7 +6,8 @@ struct Function { outputs, ~parse.Node _up, int call_padding, - bool m + bool m, + ~Module mod } /; method Function @@ -187,6 +188,15 @@ struct Function { ;/ ;/ + + /; _call_label [~uint8] + Scope tmp + 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) @@ -478,9 +488,172 @@ struct Function { ;/ ;/ - /; _compile_call(~Scope s, ~parse.Node params, ~Function f, ~Var self, bool mth) [Var] - Var out - return out + /; _compile_call(~Scope s, ~parse.Node params, ~Function f, ~Var _self, bool mth) [Var] + # Generate result tmp if required + Var result + ~Var out + /; if (f`.outputs.count > 0) + out = f`.outputs.get(0) + result = s`.mk_tmp(out) + ;; 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 (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) + + # 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) + ;/ + + ~Var tmp = tmps.get(pidx) + tmp` = 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) + ;/ + + ~Var tmp = tmps.get(i) + tmp` = to_set + last_reg = to_set + ;/ + ;/ + + # Set 'self' if required + int use_self = 0 + /; if (mth == true) + inp = tmps.get(0) + inp`.set(s`.cb, _self) + 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) + inp`.set(s`.cb, ptmp) + ;/ + ;/ + 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) + Var out_pos = out`.copy() + 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 + ;/ + result.set(s`.cb, ~out_pos) + out_pos.end() + ;/ + + # 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) + handle.end() + + s`.free_after(~result, true) + return result ;/ # Chain compilation functions get pretty long. Read at your own risk @@ -665,14 +838,7 @@ struct Function { # 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 - working.loc = 0 - - /; if (utils.strcmp(lhn`.data, ".\0") == true) - working = self._compile_chain_r(s, lhn, v) - ;; else - working = self._compile_chain_r_base(s, lhn, v) - ;/ + Var working = self._compile_chain_r_base(s, lhn, v) /; if (v`.count == 0) /; if (working.loc == 0) @@ -681,51 +847,79 @@ struct Function { ;/ ;/ + # 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 + ;/ - ~parse.Node rhn = n`.sub.get(1) - # 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() + # 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 ;/ - # 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 - ;/ + /; 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) - # Try to find function. Does not matter if we are a module since this is multi-part search - ~Module mod = s`.mod + ~Module mod = s`.mod + ~Var find = mod`.find(SEARCH_VAR, v) - # Already tried to find in module so can just use v for search. - ~Function to_call = mod`.find(SEARCH_FUNC, v) + /; if (find !== NULL) + working = find`.as_global() + v`.end() + v`.count = 0 + ;/ - /; if (to_call == NULL) - _printf("ERROR: Unable to find function or variable with name \"\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() @@ -735,80 +929,67 @@ struct Function { 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 - # 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) + # 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 + ;/ ;/ - ;/ - ;; 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) + + /; 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) - # 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 - ;/ - - working.end() - working = mbr + 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) + /; 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) + # 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 diff --git a/tnslc/compile/module.tnsl b/tnslc/compile/module.tnsl index d3deb2f..9de8041 100644 --- a/tnslc/compile/module.tnsl +++ b/tnslc/compile/module.tnsl @@ -73,6 +73,12 @@ struct Module { 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] diff --git a/tnslc/compile/scope.tnsl b/tnslc/compile/scope.tnsl index ebfc671..2461abb 100644 --- a/tnslc/compile/scope.tnsl +++ b/tnslc/compile/scope.tnsl @@ -369,6 +369,9 @@ struct Scope { 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 @@ -388,6 +391,58 @@ struct Scope { 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() + ;/ + + /; _save_caller_tmp (~utils.Vector vec) + # TODO + ;/ + + /; save_caller_tmp [Var] + Var tmp + utils.Vector tmps + tmps.init(len tmp) + + self._save_caller_tmp(~tmps) + + ~Var to_save + /; loop (int i = 0; i < tmps.count) [i++] + to_save = tmps.get(i) + tmp = self.mk_tmp_stack(to_save) + tmp.set(self.cb, to_save) + /; if (i < tmps.count - 1) + tmp.end() + ;/ + ;/ + tmps.end() + + return tmp + ;/ + + /; restore_caller_tmp (~Var handle) + # TODO + ;/ + # 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 @@ -419,33 +474,68 @@ struct Scope { # 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++] + /; loop (int i = 1; i !> self.tmps.count) [i++] v = self.tmps.get(self.tmps.count - i) /; if (v`.offset == tmp`.offset) - tmps = self.tmps.count - tmps = tmps - i - tmps = tmps + 1 + tmps = i + i = self.tmps.count + 1 ;/ ;/ - /; if (tmps !== 0) - self.free_tmp(tmps, code) - ;; else + /; 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) + ;/ ;/ # diff --git a/tnslc/compile/var.tnsl b/tnslc/compile/var.tnsl index f41d233..477a4fb 100644 --- a/tnslc/compile/var.tnsl +++ b/tnslc/compile/var.tnsl @@ -920,7 +920,7 @@ struct Var { buf`.add_c(" ; putting struct address into register\n\0") # Initial deref or move - /; if (self.ptrc.count > 0) + /; if (self.ptrc.count > 1) buf`.add_c(" mov \0") ;; else buf`.add_c(" lea \0") @@ -1670,6 +1670,7 @@ struct Var { /; 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 -- cgit v1.2.3