From 9038ecd9423e6181063ae5a9846c617a92e6ceaf Mon Sep 17 00:00:00 2001 From: Kai Gunger Date: Sat, 9 May 2026 13:55:09 -0400 Subject: [tnslc] loops --- tnslc/compile/function.tnsl | 203 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 198 insertions(+), 5 deletions(-) diff --git a/tnslc/compile/function.tnsl b/tnslc/compile/function.tnsl index 98b3b19..eac1732 100644 --- a/tnslc/compile/function.tnsl +++ b/tnslc/compile/function.tnsl @@ -395,7 +395,99 @@ struct Function { return last_var ;/ - /; _compile_cf_post(~Scope s, ~parse.Node pre, post) + /; _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) @@ -411,15 +503,15 @@ struct Function { # 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._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) + self._compute_scope_vars_loop(~s, n, 0) ;/ - # Actually compile all the functions + # 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 @@ -489,6 +581,107 @@ struct Function { /; _compile_loop (~Scope s, ~parse.Node n) # TODO _printf("Loops not impl, sorry :(\n\0") + + # 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] -- cgit v1.2.3