struct Function { ~uint8 name, utils.Vector inputs, outputs, ~parse.Node _up, int call_padding, bool m } /; method Function /; init (~parse.Node n) self.name = utils.strcpy(n`.data) self._up = n self.m = false self.call_padding = 0 Var v self.inputs.init(len v) self.outputs.init(len v) ;/ /; _resolve_dlist (~Module parent, ~parse.Node dl) ~parse.Node tn = NULL ~parse.Node n int reg = 1 int stack_up = 8 /; loop (int i = 0; i < dl`.sub.count) [i++] n = dl`.sub.get(i) /; if (n`._type == parse.NTYPE_TYPE) tn = n ;; else if (n`._type == parse.NTYPE_ID) /; if (tn == NULL) _printf("Identifier declared in parameter list before any type was found!\n\0") return ;/ Var p p.init(tn, n) p._resolve_type(parent) # TODO: This is wrong /; if (p.regable() == true && reg < 7) p.loc = reg reg++ ;; else p.loc = 0 - 1 p.offset = stack_up stack_up = stack_up + p.actual_size() ;/ self.inputs.push(~p) ;/ ;/ ;/ /; _resolve_tlist (~Module parent, ~parse.Node tl) ~parse.Node n parse.Node dummy dummy.data = "### OUTPUT ###\0" int reg = 1 int stack = 0 /; loop (int i = 0; i < tl`.sub.count) [i++] n = tl`.sub.get(i) /; if (n`._type == parse.NTYPE_TYPE) # TODO: also wrong Var r r.init(n, ~dummy) r._resolve_type(parent) /; if (r.regable() == true && reg < 7) r.loc = reg /; if (reg > 4) r.loc = r.loc + 4 ;/ reg++ ;; else r.loc = 0 - 1 r.offset = stack stack = stack + r.actual_size() ;/ self.outputs.push(~r) ;/ ;/ ;/ /; _resolve_type (~Module parent) ~parse.Node _up = self._up /; if (_up`.sub.count < 1) return ;/ ~parse.Node lst = _up`.sub.get(0) /; if (lst`._type == parse.NTYPE_DLIST) self._resolve_dlist(parent, lst) /; if (_up`.sub.count > 1) lst = _up`.sub.get(1) ;/ ;/ /; if (lst`._type == parse.NTYPE_TLIST) self._resolve_tlist(parent, lst) ;/ int i_size = 0 int o_size = 0 ~Var v /; loop (int i = 0; i < self.inputs.count) [i++] v = self.inputs.get(i) /; if (v`.loc < 0) int vsz = v`.actual_size() i_size = i_size + vsz ;/ ;/ /; loop (int i = 0; i < self.outputs.count) [i++] v = self.outputs.get(i) /; if (v`.loc < 0) int vsz = v`.actual_size() o_size = o_size + vsz ;/ ;/ /; if (o_size > i_size) int padding = o_size - i_size /; loop (int i = 0; i < self.inputs.count) [i++] v = self.inputs.get(i) int off = v`.offset v`.offset = off + padding ;/ self.call_padding = padding ;/ ;/ /; _compute_scope_vars(~Scope s) ~Var in /; loop (int i = 0; i < self.inputs.count) [i++] in = self.inputs.get(i) s`.mk_aware(in) ;/ int i = self._first_stmt_off() /; if (i < 0) return ;/ ~parse.Node _up = self._up ~parse.Node n /; loop (i < _up`.sub.count) [i++] n = _up`.sub.get(i) /; if (n`._type == parse.NTYPE_DECL) s`.mk_aware_node(n) ;; else s`.precheck_stmt(n) ;/ ;/ ;/ /; _build_func(~Module parent, ~CompBuf cb) [Scope] Scope out out.init(parent, cb, self.name) out.parent = NULL /; if (parent`.e == true) # Add to the global exports if the parent is exported ~uint8 bl = out.base_label() cb`.add_h("global \0") cb`.add_h(bl) cb`.add_h("\n\0") _delete(bl) ;/ # Write label and opening # Nieve implementation: r10-r15 are callee saved registers # in the TNSL style ABI out.place_base_label() cb`.add_c(" push rbp\n\0") cb`.add_c(" lea rbp, [rsp + 8]\n\0") cb`.add_c(" push r10\n\0") cb`.add_c(" push r11\n\0") cb`.add_c(" push r12\n\0") cb`.add_c(" push r13\n\0") cb`.add_c(" push r14\n\0") cb`.add_c(" push r15 ; scope init\n\n\0") self._compute_scope_vars(~out) # Add all params to the scope ~Var in /; loop (int i = 0; i < self.inputs.count) [i++] in = self.inputs.get(i) out.mk_set_var(in) ;/ return out ;/ /; _end_func(~Scope scope, ~CompBuf cb) cb`.add_c("\n\0") scope`.place_end_label() cb`.add_c(" lea rsp, [rbp - 56]\n\0") cb`.add_c(" pop r15\n\0") cb`.add_c(" pop r14\n\0") cb`.add_c(" pop r13\n\0") cb`.add_c(" pop r12\n\0") cb`.add_c(" pop r11\n\0") cb`.add_c(" pop r10\n\0") cb`.add_c(" pop rbp\n\0") cb`.add_c(" ret ; scope end\n\n\n\0") scope`.end() ;/ /; _first_stmt_off [int] int i = 0 ~parse.Node _up = self._up /; if (_up`.sub.count < 1) return i - 1 ;/ ~parse.Node n = _up`.sub.get(i) /; if (n`._type == parse.NTYPE_DLIST) i++ /; if (_up`.sub.count > 1) n = _up`.sub.get(1) ;/ ;/ /; if (n`._type == parse.NTYPE_TLIST) i++ ;/ return i ;/ /; _compile (~Module parent, ~CompBuf cb) # Sanity check int i = self._first_stmt_off() # Create scope Scope fscope = self._build_func(parent, cb) /; if (i !< 0) self._compile_statements(~fscope, i) ;/ # Compile and then end scope self._end_func(~fscope, cb) ;/ # # Compiling individual statements # /; _compile_statements (~Scope s, int off) ~parse.Node _up = self._up ~parse.Node n = NULL /; loop (off < _up`.sub.count) [off++] n = _up`.sub.get(off) /; if (n`._type == parse.NTYPE_FLOW_CONTROL) self._compile_flow_control(s, n) ;; else if (n`._type == parse.NTYPE_ASM) s`.cb`.add_c(" \0") s`.cb`.add_c(n`.data) s`.cb`.add_c(" ; User defined asm\n\0") ;; else if (n`._type == parse.NTYPE_DECL) self._compile_decl(s, n) ;; else if (n`._type == parse.NTYPE_VALUE) Var v = self._compile_value(s, n) v.end() ;/ ;/ ;/ /; _check_return (~parse.Node n) [bool] int expected = self.outputs.count int have = 0 ~parse.Node val /; if (n`.sub.count > 0) val = n`.sub.get(0) val = val`.sub.get(0) /; if (expected > 1 && val`._type == parse.NTYPE_VLIST) have = val`.sub.count ;; else have = 1 ;/ ;/ /; if (have == expected) return true ;/ _print_num("ERROR: Number of return values (%d) does not match expected (\0", have) _print_num("%d)\n\0", expected) _printf("ERROR: To return multiple values enclose them in {}\n\0") _printf("ERROR: To add more return values, add them (comma separated) between [] at the end of the function definition\n\0") return false ;/ /; _compile_return_vals (~Scope s, ~parse.Node n) _printf("Compiling return vals!\n\0") /; if (self.outputs.count == 0) return ;/ n = n`.sub.get(0) /; if (self.outputs.count > 1) n = n`.sub.get(0) ;/ s`.cb`.add_c("\n ; STARTING RETURN\n\0") ~Var out Var cmp /; if (self.outputs.count > 1) ~parse.Node val_node Var tmp utils.Vector tmps tmps.init(len cmp) # Compile all values /; loop (int i = 0; i < self.outputs.count) [i++] val_node = n`.sub.get(i) out = self.outputs.get(i) tmp = s`.mk_tmp(out) cmp = self._compile_value(s, val_node) 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 out return out ;/ # 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() 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) Var tmp = s`.mk_tmp(v) tmp.set(s`.cb, v) v`.end() 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() v` = tmp ;; else if (utils.strcmp(post`.data, "++\0") == true) # Generate copy (make sure no refs) Var copy = v`.copy() /; loop (copy.is_ptr(0, 0) == true) copy.ptr_pop() ;/ # 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() v` = tmp ;; else if (utils.strcmp(post`.data, "--\0") == true) # Generate copy (make sure no refs) Var copy = v`.copy() /; loop (copy.is_ptr(0, 0) == true) copy.ptr_pop() ;/ # 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() 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) vv = s`.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) ;; 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 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) ;/ /; 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 ;/ ;/ # 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. ~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() 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 ;/ 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_set (~Scope s, ~parse.Node n) [Var] Var out return out ;/ /; _compile_bin (~Scope s, ~parse.Node n) [Var] # TODO /; if (utils.strcmp(n`.data, ".\0") == true) return self._compile_chain(s, n) ;/ ~parse.Node lhn = n`.sub.get(0) ~parse.Node rhn = n`.sub.get(1) # If we are setting /; if (utils.strcmp(n`.data, "=\0") == true) Var rhs = self._compile_value(s, rhn) # TODO: move rhs maybe if it is in rdi Var lhs = self._compile_set(s, lhn) lhs.set(s`.cb, ~rhs) rhs.end() return lhs ;/ # Otherwise Var lhs = self._compile_value(s, lhn) /; if (s`.is_tmp(~lhs) == false) Var tmp = s`.mk_tmp(~lhs) tmp.set(s`.cb, ~lhs) lhs.end() lhs = tmp ;/ Var rhs = self._compile_value(s, rhn) /; if (utils.strcmp(n`.data, "*\0") == true) lhs.mul(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "/\0") == true) lhs.div(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "%\0") == true) lhs.mod(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "+\0") == true) lhs.add(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "-\0") == true) lhs.sub(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "&\0") == true) lhs.and(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "|\0") == true) lhs.or(s`.cb, ~rhs) ;; else if (utils.strcmp(n`.data, "^\0") == true) lhs.xor(s`.cb, ~rhs) ;/ /; if (s`.is_tmp(~rhs) == true) s`.free_to(~rhs, 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 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 if (out.loc !== 0) 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() ;/ ;/