From d4dc6ceef5e57fb8f687463d8e627b1287b1f023 Mon Sep 17 00:00:00 2001 From: IgorCielniak Date: Thu, 8 Jan 2026 13:15:27 +0100 Subject: [PATCH] small refactor and cleanup --- __pycache__/main.cpython-314.pyc | Bin 146914 -> 0 bytes main | Bin 6832 -> 0 bytes main.bin | Bin 6928 -> 0 bytes main.py | 295 +++++++++---------- mem.sl | 8 - readstdin | Bin 11648 -> 0 bytes stdlib/mem.sl | 15 + test.bin | Bin 10224 -> 0 bytes test_read_file.out | Bin 11696 -> 0 bytes tests/alloc.expected | 2 + alloc.sl => tests/alloc.sl | 21 +- tests/alloc.test | 1 + tests/call_syntax_parens.expected | 2 + tests/call_syntax_parens.sl | 16 + tests/call_syntax_parens.test | 1 + tests/fib.expected | 27 ++ fib.sl => tests/fib.sl | 6 +- tests/fib.test | 1 + tests/integration_core.expected | 33 +++ test.sl => tests/integration_core.sl | 6 +- tests/integration_core.test | 1 + tests/io_read_file.expected | 1 + test_read_file.sl => tests/io_read_file.sl | 10 +- tests/io_read_file.test | 1 + tests/io_read_stdin.expected | 1 + test_read_stdin.sl => tests/io_read_stdin.sl | 4 +- tests/io_read_stdin.test | 1 + tests/io_write_buf.expected | 1 + test_write_buf.sl => tests/io_write_buf.sl | 4 +- tests/io_write_buf.test | 1 + tests/io_write_file.expected | 2 + test_write_file.sl => tests/io_write_file.sl | 8 +- tests/io_write_file.test | 1 + tests/loop_while.expected | 10 + while_test.sl => tests/loop_while.sl | 4 +- tests/loop_while.test | 1 + tests/loops_and_cmp.expected | 3 + tests/loops_and_cmp.sl | 13 + tests/loops_and_cmp.test | 1 + tests/mem.expected | 2 + aa.sl => tests/mem.sl | 4 +- tests/mem.test | 1 + tests/override_dup_compile_time.expected | 1 + tests/override_dup_compile_time.sl | 28 ++ tests/override_dup_compile_time.test | 1 + tests/run_tests.py | 171 ----------- tests/string_puts.expected | 4 + tests/string_puts.sl | 9 + tests/string_puts.test | 1 + tests/test.py | 66 +++++ write | Bin 11648 -> 0 bytes write_buf_test | Bin 11360 -> 0 bytes 52 files changed, 418 insertions(+), 372 deletions(-) delete mode 100644 __pycache__/main.cpython-314.pyc delete mode 100755 main delete mode 100755 main.bin delete mode 100644 mem.sl delete mode 100755 readstdin create mode 100644 stdlib/mem.sl delete mode 100755 test.bin delete mode 100755 test_read_file.out create mode 100644 tests/alloc.expected rename alloc.sl => tests/alloc.sl (63%) create mode 100644 tests/alloc.test create mode 100644 tests/call_syntax_parens.expected create mode 100644 tests/call_syntax_parens.sl create mode 100644 tests/call_syntax_parens.test create mode 100644 tests/fib.expected rename fib.sl => tests/fib.sl (79%) create mode 100644 tests/fib.test create mode 100644 tests/integration_core.expected rename test.sl => tests/integration_core.sl (97%) create mode 100644 tests/integration_core.test create mode 100644 tests/io_read_file.expected rename test_read_file.sl => tests/io_read_file.sl (82%) create mode 100644 tests/io_read_file.test create mode 100644 tests/io_read_stdin.expected rename test_read_stdin.sl => tests/io_read_stdin.sl (75%) create mode 100644 tests/io_read_stdin.test create mode 100644 tests/io_write_buf.expected rename test_write_buf.sl => tests/io_write_buf.sl (56%) create mode 100644 tests/io_write_buf.test create mode 100644 tests/io_write_file.expected rename test_write_file.sl => tests/io_write_file.sl (52%) create mode 100644 tests/io_write_file.test create mode 100644 tests/loop_while.expected rename while_test.sl => tests/loop_while.sl (66%) create mode 100644 tests/loop_while.test create mode 100644 tests/loops_and_cmp.expected create mode 100644 tests/loops_and_cmp.sl create mode 100644 tests/loops_and_cmp.test create mode 100644 tests/mem.expected rename aa.sl => tests/mem.sl (63%) create mode 100644 tests/mem.test create mode 100644 tests/override_dup_compile_time.expected create mode 100644 tests/override_dup_compile_time.sl create mode 100644 tests/override_dup_compile_time.test delete mode 100644 tests/run_tests.py create mode 100644 tests/string_puts.expected create mode 100644 tests/string_puts.sl create mode 100644 tests/string_puts.test create mode 100644 tests/test.py delete mode 100755 write delete mode 100755 write_buf_test diff --git a/__pycache__/main.cpython-314.pyc b/__pycache__/main.cpython-314.pyc deleted file mode 100644 index a3aa38d1d044b23ae348481d1cfc96f884077925..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146914 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 GK>RWjjtYOU`Z*E+D za4Q6%*U*Q-d{EpJeGox>8&pMPi``(b3O-{HpteoxtX~=& z)jAih4{KxJY3>ht`}d`b2-cVHMXI???agboU-bGP;0$r`0mPTW_iRPOGk?v~yH|Ag z=B&FOi!{Zp{1(;SaI(qnQjo?=Nkqd*-JMPn!k8XnB3h2V-`{CJhFT7A5R;-xdq->E z>PL6^GBt*i+C=k9w%pj6CY!fAi$C`ECb9Q6iM_u`?A#`?v)!2109uK7m^!;JcQ>zC zrg0ZvbA~FDY3!mJNPCF-lgZT~w#W$O^6_ncKFRg8Te`KV-@u150|;h7udhY*y7%DL z*i#a>p*NQd#OtRJ?33@eNU(?75R5DQAn|7v zeuQ{U;nRKi)5K3J`WJ|Qpz!0wzf!nE{EEU)68~1=%fx?H_-W!B3V)aQZH0eC{O;{( z?#bp;;twnQJn;#IUm*Ux!mkp4RpH+gUs3pv#6MB^b>eFZZxjDX;o{|L2yQ5Rh;1MY zhIXX+NZITpKB4dji9e(8{lra$r-<7Mf1G$-;TrK}g+E99oWfrwzM=3u=lF?C^scMu z@hQ1fZWsITQyzb^NB>qIeunr`qF4Vh@;G}4%6|Kh^E>bJvp)PRaWy|=YlQ{tV9_j; zM$BpvjH+YW&Pb_j;S zf(~<-Vc)cDE_Uq}2H1Z9-rU5PIeMSyoM(&kT}l_WW9;9?N9cU%5#Lzms^k9w3MUi- diff --git a/main.bin b/main.bin deleted file mode 100755 index 9a54c1f663bd689403674acbda0efa18814cd1ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6928 zcmeI1UuauZ7{I?|Nl7~~Svz#H3KcTl#CB`5!3I@QY3;qx%rRf~Fu2?_X?I!k$K+<4 zf?FjByTpR?AINm>!3SaN!I#-NWNeumPOYF13PbQgFrqRiNR>L{ch31v?#t#&#{TAr-Fe1$R`L-0Pn?;9Eld-l?S8;KoWMs8f?2D%zZew zuU?60&b7r+gwe1|>SNqbtFFKc-P-bvu|@XpTwB=jNGu5FS&FfbdKf{6%37_tbhT@n z*1Ys{zc&1p=6tI!|2}^i!P4>jkZMj{d+A2y2fg|y*xlTD5b@Q}y*(&+=8HVNb6t0C zO*u=^a9vF0mx%6!;&nDlB;)ajUX_SVzP2BU(;wFzG*QTvh#p`ev^af>x3l~h`f`9l zn3Q>GZ)wXbo#=W`rdoeo+f~2779V}R&c<~|@!H;4#rF0pws%*tom$2Aj%(9uKr0bj ztFw7I8+iRvwR`xQQ&gE$Z9UaM%I(x2jW2eyMTRMthp+YWQSMJ?$E`*6SKO2dKrjJ% z^%KvYVF#(02A2MF&u&UM{sqR!J!ZKUZH2!_yk}jKYqB{@e51n85g%6gMdFhR|BU#w!oMMYOyS=XKdJDah<~W?KZt*= zaPcZO05=uh!wwL>ZCz1#AMt2!l4q37gTyBlzJ<7<@C5OK!XGC-ukcCYCltPy_?rsf zPyCF+XNg}@__M@&``Xv_Jm>iJ9cbq-w)mJV0hcd#;IFm#lWqQ|I`H?2&kwZwUqBvX zZ^4!Gd5-ft=XtpU|A4rfAJP?TF0(afTKOTfoCBk5n%?!%8D%DOrZc7tTZ|aVc1xWk|08GQY=|{+elYtprskvd None: - self._parser.emit_node(Literal(value=value)) + self._parser.emit_node(Op(op="literal", data=value)) def emit_word(self, name: str) -> None: - self._parser.emit_node(WordRef(name=name)) + self._parser.emit_node(Op(op="word", data=name)) - def emit_node(self, node: ASTNode) -> None: + def emit_node(self, node: Op) -> None: self._parser.emit_node(node) def inject_tokens(self, tokens: Sequence[str], template: Optional[Token] = None) -> None: @@ -316,7 +283,7 @@ class MacroContext: return self._parser.most_recent_definition() -MacroHandler = Callable[[MacroContext], Optional[List[ASTNode]]] +MacroHandler = Callable[[MacroContext], Optional[List[Op]]] IntrinsicEmitter = Callable[["FunctionEmitter"], None] @@ -390,8 +357,8 @@ class Parser: self._ensure_tokens(self.pos) return None if self._eof() else self.tokens[self.pos] - def emit_node(self, node: ASTNode) -> None: - self._append_node(node) + def emit_node(self, node: Op) -> None: + self._append_op(node) def most_recent_definition(self) -> Optional[Word]: return self.last_defined @@ -406,18 +373,18 @@ class Parser: if entry["type"] == "if": # For if without else if "false" in entry: - self._append_node(Label(name=entry["false"])) + self._append_op(Op(op="label", data=entry["false"])) elif entry["type"] == "else": - self._append_node(Label(name=entry["end"])) + self._append_op(Op(op="label", data=entry["end"])) elif entry["type"] == "while": - self._append_node(Jump(target=entry["begin"])) - self._append_node(Label(name=entry["end"])) + self._append_op(Op(op="jump", data=entry["begin"])) + self._append_op(Op(op="label", data=entry["end"])) elif entry["type"] == "for": # Emit ForEnd node for loop decrement - self._append_node(ForEnd(loop_label=entry["loop"], end_label=entry["end"])) + self._append_op(Op(op="for_end", data={"loop": entry["loop"], "end": entry["end"]})) elif entry["type"] == "begin": - self._append_node(Jump(target=entry["begin"])) - self._append_node(Label(name=entry["end"])) + self._append_op(Op(op="jump", data=entry["begin"])) + self._append_op(Op(op="label", data=entry["end"])) # Parsing ------------------------------------------------------------------ def parse(self, tokens: Iterable[Token], source: str) -> Module: @@ -608,12 +575,12 @@ class Parser: produced = word.macro(MacroContext(self)) if produced: for node in produced: - self._append_node(node) + self._append_op(node) else: self._execute_immediate_word(word) return - self._append_node(WordRef(name=token.lexeme)) + self._append_op(Op(op="word", data=token.lexeme)) def _execute_immediate_word(self, word: Word) -> None: try: @@ -721,31 +688,31 @@ class Parser: def _handle_if_control(self) -> None: false_label = self._new_label("if_false") - self._append_node(BranchZero(target=false_label)) + self._append_op(Op(op="branch_zero", data=false_label)) self._push_control({"type": "if", "false": false_label}) def _handle_else_control(self) -> None: entry = self._pop_control(("if",)) end_label = self._new_label("if_end") - self._append_node(Jump(target=end_label)) - self._append_node(Label(name=entry["false"])) + self._append_op(Op(op="jump", data=end_label)) + self._append_op(Op(op="label", data=entry["false"])) self._push_control({"type": "else", "end": end_label}) def _handle_for_control(self) -> None: loop_label = self._new_label("for_loop") end_label = self._new_label("for_end") - self._append_node(ForBegin(loop_label=loop_label, end_label=end_label)) + self._append_op(Op(op="for_begin", data={"loop": loop_label, "end": end_label})) self._push_control({"type": "for", "loop": loop_label, "end": end_label}) def _handle_while_control(self) -> None: begin_label = self._new_label("begin") end_label = self._new_label("end") - self._append_node(Label(name=begin_label)) + self._append_op(Op(op="label", data=begin_label)) self._push_control({"type": "begin", "begin": begin_label, "end": end_label}) def _handle_do_control(self) -> None: entry = self._pop_control(("begin",)) - self._append_node(BranchZero(target=entry["end"])) + self._append_op(Op(op="branch_zero", data=entry["end"])) self._push_control(entry) def _begin_definition(self, token: Token) -> None: @@ -859,7 +826,7 @@ class Parser: def _py_exec_namespace(self) -> Dict[str, Any]: return dict(PY_EXEC_GLOBALS) - def _append_node(self, node: ASTNode) -> None: + def _append_op(self, node: Op) -> None: target = self.context_stack[-1] if isinstance(target, Module): target.forms.append(node) @@ -868,10 +835,10 @@ class Parser: else: # pragma: no cover - defensive raise ParseError("unknown parse context") - def _try_literal(self, token: Token) -> None: + def _try_literal(self, token: Token) -> bool: try: value = int(token.lexeme, 0) - self._append_node(Literal(value=value)) + self._append_op(Op(op="literal", data=value)) return True except ValueError: pass @@ -880,14 +847,14 @@ class Parser: try: if "." in token.lexeme or "e" in token.lexeme.lower(): value = float(token.lexeme) - self._append_node(Literal(value=value)) + self._append_op(Op(op="literal", data=value)) return True except ValueError: pass string_value = _parse_string_literal(token) if string_value is not None: - self._append_node(Literal(value=string_value)) + self._append_op(Op(op="literal", data=string_value)) return True return False @@ -1229,7 +1196,7 @@ class CompileTimeVM: raise ParseError(f"unknown word '{name}' during compile-time execution") self._call_word(word) - def _execute_nodes(self, nodes: Sequence[ASTNode]) -> None: + def _execute_nodes(self, nodes: Sequence[Op]) -> None: label_positions = self._label_positions(nodes) loop_pairs = self._for_pairs(nodes) begin_pairs = self._begin_pairs(nodes) @@ -1238,12 +1205,16 @@ class CompileTimeVM: ip = 0 while ip < len(nodes): node = nodes[ip] - if isinstance(node, Literal): - self.push(node.value) + kind = node.op + data = node.data + + if kind == "literal": + self.push(data) ip += 1 continue - if isinstance(node, WordRef): - name = node.name + + if kind == "word": + name = str(data) if name == "begin": end_idx = begin_pairs.get(ip) if end_idx is None: @@ -1270,9 +1241,9 @@ class CompileTimeVM: self._call_word_by_name(name) ip += 1 continue - if isinstance(node, BranchZero): + + if kind == "branch_zero": condition = self.pop() - flag: bool if isinstance(condition, bool): flag = condition elif isinstance(condition, int): @@ -1280,17 +1251,20 @@ class CompileTimeVM: else: raise ParseError("branch expects integer or boolean condition") if not flag: - ip = self._jump_to_label(label_positions, node.target) + ip = self._jump_to_label(label_positions, str(data)) else: ip += 1 continue - if isinstance(node, Jump): - ip = self._jump_to_label(label_positions, node.target) + + if kind == "jump": + ip = self._jump_to_label(label_positions, str(data)) continue - if isinstance(node, Label): + + if kind == "label": ip += 1 continue - if isinstance(node, ForBegin): + + if kind == "for_begin": count = self.pop_int() if count <= 0: match = loop_pairs.get(ip) @@ -1301,7 +1275,8 @@ class CompileTimeVM: self.loop_stack.append({"remaining": count, "begin": ip, "initial": count}) ip += 1 continue - if isinstance(node, ForEnd): + + if kind == "for_end": if not self.loop_stack: raise ParseError("'next' without matching 'for'") frame = self.loop_stack[-1] @@ -1312,22 +1287,23 @@ class CompileTimeVM: self.loop_stack.pop() ip += 1 continue - raise ParseError(f"unsupported compile-time AST node {node!r}") - def _label_positions(self, nodes: Sequence[ASTNode]) -> Dict[str, int]: + raise ParseError(f"unsupported compile-time op {node!r}") + + def _label_positions(self, nodes: Sequence[Op]) -> Dict[str, int]: positions: Dict[str, int] = {} for idx, node in enumerate(nodes): - if isinstance(node, Label): - positions[node.name] = idx + if node.op == "label": + positions[str(node.data)] = idx return positions - def _for_pairs(self, nodes: Sequence[ASTNode]) -> Dict[int, int]: + def _for_pairs(self, nodes: Sequence[Op]) -> Dict[int, int]: stack: List[int] = [] pairs: Dict[int, int] = {} for idx, node in enumerate(nodes): - if isinstance(node, ForBegin): + if node.op == "for_begin": stack.append(idx) - elif isinstance(node, ForEnd): + elif node.op == "for_end": if not stack: raise ParseError("'next' without matching 'for'") begin_idx = stack.pop() @@ -1337,13 +1313,13 @@ class CompileTimeVM: raise ParseError("'for' without matching 'next'") return pairs - def _begin_pairs(self, nodes: Sequence[ASTNode]) -> Dict[int, int]: + def _begin_pairs(self, nodes: Sequence[Op]) -> Dict[int, int]: stack: List[int] = [] pairs: Dict[int, int] = {} for idx, node in enumerate(nodes): - if isinstance(node, WordRef) and node.name == "begin": + if node.op == "word" and node.data == "begin": stack.append(idx) - elif isinstance(node, WordRef) and node.name == "again": + elif node.op == "word" and node.data == "again": if not stack: raise ParseError("'again' without matching 'begin'") begin_idx = stack.pop() @@ -1611,48 +1587,57 @@ class Assembler: else: builder.emit("") - def _emit_node(self, node: ASTNode, builder: FunctionEmitter) -> None: - if isinstance(node, Literal): - if isinstance(node.value, int): - builder.push_literal(node.value) + def _emit_node(self, node: Op, builder: FunctionEmitter) -> None: + kind = node.op + data = node.data + + if kind == "literal": + if isinstance(data, int): + builder.push_literal(data) return - if isinstance(node.value, float): - label = self._intern_float_literal(node.value) + if isinstance(data, float): + label = self._intern_float_literal(data) builder.push_float(label) return - if isinstance(node.value, str): - label, length = self._intern_string_literal(node.value) + if isinstance(data, str): + label, length = self._intern_string_literal(data) builder.push_label(label) builder.push_literal(length) return - raise CompileError(f"unsupported literal type {type(node.value)!r}") - return - if isinstance(node, WordRef): - self._emit_wordref(node, builder) - return - if isinstance(node, BranchZero): - self._emit_branch_zero(node, builder) - return - if isinstance(node, Jump): - builder.emit(f" jmp {node.target}") - return - if isinstance(node, Label): - builder.emit(f"{node.name}:") - return - if isinstance(node, ForBegin): - self._emit_for_begin(node, builder) - return - if isinstance(node, ForEnd): - self._emit_for_next(node, builder) - return - raise CompileError(f"unsupported AST node {node!r}") + raise CompileError(f"unsupported literal type {type(data)!r}") - def _emit_wordref(self, ref: WordRef, builder: FunctionEmitter) -> None: - word = self.dictionary.lookup(ref.name) + if kind == "word": + self._emit_wordref(str(data), builder) + return + + if kind == "branch_zero": + self._emit_branch_zero(str(data), builder) + return + + if kind == "jump": + builder.emit(f" jmp {data}") + return + + if kind == "label": + builder.emit(f"{data}:") + return + + if kind == "for_begin": + self._emit_for_begin(data, builder) + return + + if kind == "for_end": + self._emit_for_next(data, builder) + return + + raise CompileError(f"unsupported op {node!r}") + + def _emit_wordref(self, name: str, builder: FunctionEmitter) -> None: + word = self.dictionary.lookup(name) if word is None: - raise CompileError(f"unknown word '{ref.name}'") + raise CompileError(f"unknown word '{name}'") if word.compile_only: - raise CompileError(f"word '{ref.name}' is compile-time only") + raise CompileError(f"word '{name}' is compile-time only") if word.intrinsic: word.intrinsic(builder) return @@ -1669,7 +1654,7 @@ class Assembler: ret_type = signature[1] if signature else None if len(arg_types) != inputs and signature: - raise CompileError(f"extern '{ref.name}' mismatch: {inputs} inputs vs {len(arg_types)} types") + raise CompileError(f"extern '{name}' mismatch: {inputs} inputs vs {len(arg_types)} types") int_idx = 0 xmm_idx = 0 @@ -1679,19 +1664,19 @@ class Assembler: if not arg_types: # Legacy/Raw mode: assume all ints if inputs > 6: - raise CompileError(f"extern '{ref.name}' has too many inputs ({inputs} > 6)") + raise CompileError(f"extern '{name}' has too many inputs ({inputs} > 6)") for i in range(inputs): mapping.append(("int", regs[i])) else: for type_name in arg_types: if type_name in ("float", "double"): if xmm_idx >= 8: - raise CompileError(f"extern '{ref.name}' has too many float inputs") + raise CompileError(f"extern '{name}' has too many float inputs") mapping.append(("float", xmm_regs[xmm_idx])) xmm_idx += 1 else: if int_idx >= 6: - raise CompileError(f"extern '{ref.name}' has too many int inputs") + raise CompileError(f"extern '{name}' has too many int inputs") mapping.append(("int", regs[int_idx])) int_idx += 1 @@ -1706,7 +1691,7 @@ class Assembler: builder.emit(" mov rbp, rsp") builder.emit(" and rsp, -16") builder.emit(f" mov al, {xmm_idx}") - builder.emit(f" call {ref.name}") + builder.emit(f" call {name}") builder.emit(" leave") # Handle Return Value @@ -1721,30 +1706,34 @@ class Assembler: raise CompileError("extern only supports 0 or 1 output") else: # Emit call to unresolved symbol (let linker resolve it) - builder.emit(f" call {ref.name}") + builder.emit(f" call {name}") else: - builder.emit(f" call {sanitize_label(ref.name)}") + builder.emit(f" call {sanitize_label(name)}") - def _emit_branch_zero(self, node: BranchZero, builder: FunctionEmitter) -> None: + def _emit_branch_zero(self, target: str, builder: FunctionEmitter) -> None: builder.pop_to("rax") builder.emit(" test rax, rax") - builder.emit(f" jz {node.target}") + builder.emit(f" jz {target}") - def _emit_for_begin(self, node: ForBegin, builder: FunctionEmitter) -> None: + def _emit_for_begin(self, data: Dict[str, str], builder: FunctionEmitter) -> None: + loop_label = data["loop"] + end_label = data["end"] builder.pop_to("rax") builder.emit(" cmp rax, 0") - builder.emit(f" jle {node.end_label}") + builder.emit(f" jle {end_label}") builder.emit(" sub r13, 8") builder.emit(" mov [r13], rax") - builder.emit(f"{node.loop_label}:") + builder.emit(f"{loop_label}:") - def _emit_for_next(self, node: ForEnd, builder: FunctionEmitter) -> None: + def _emit_for_next(self, data: Dict[str, str], builder: FunctionEmitter) -> None: + loop_label = data["loop"] + end_label = data["end"] builder.emit(" mov rax, [r13]") builder.emit(" dec rax") builder.emit(" mov [r13], rax") - builder.emit(f" jg {node.loop_label}") + builder.emit(f" jg {loop_label}") builder.emit(" add r13, 8") - builder.emit(f"{node.end_label}:") + builder.emit(f"{end_label}:") def _runtime_prelude(self) -> List[str]: return [ @@ -1804,7 +1793,7 @@ class Assembler: # --------------------------------------------------------------------------- -def macro_immediate(ctx: MacroContext) -> Optional[List[ASTNode]]: +def macro_immediate(ctx: MacroContext) -> Optional[List[Op]]: parser = ctx.parser word = parser.most_recent_definition() if word is None: @@ -1815,7 +1804,7 @@ def macro_immediate(ctx: MacroContext) -> Optional[List[ASTNode]]: return None -def macro_compile_only(ctx: MacroContext) -> Optional[List[ASTNode]]: +def macro_compile_only(ctx: MacroContext) -> Optional[List[Op]]: parser = ctx.parser word = parser.most_recent_definition() if word is None: @@ -1826,7 +1815,7 @@ def macro_compile_only(ctx: MacroContext) -> Optional[List[ASTNode]]: return None -def macro_compile_time(ctx: MacroContext) -> Optional[List[ASTNode]]: +def macro_compile_time(ctx: MacroContext) -> Optional[List[Op]]: """Run the next word at compile time and still emit it for runtime.""" parser = ctx.parser if parser._eof(): @@ -1840,11 +1829,11 @@ def macro_compile_time(ctx: MacroContext) -> Optional[List[ASTNode]]: raise ParseError(f"word '{name}' is compile-time only") parser.compile_time_vm.invoke(word) if isinstance(parser.context_stack[-1], Definition): - parser.emit_node(WordRef(name=name)) + parser.emit_node(Op(op="word", data=name)) return None -def macro_begin_text_macro(ctx: MacroContext) -> Optional[List[ASTNode]]: +def macro_begin_text_macro(ctx: MacroContext) -> Optional[List[Op]]: parser = ctx.parser if parser._eof(): raise ParseError("macro name missing after 'macro:'") @@ -1861,7 +1850,7 @@ def macro_begin_text_macro(ctx: MacroContext) -> Optional[List[ASTNode]]: return None -def macro_end_text_macro(ctx: MacroContext) -> Optional[List[ASTNode]]: +def macro_end_text_macro(ctx: MacroContext) -> Optional[List[Op]]: parser = ctx.parser if parser.macro_recording is None: raise ParseError("';macro' without matching 'macro:'") @@ -2458,13 +2447,7 @@ def _register_compile_time_primitives(dictionary: Dictionary) -> None: PY_EXEC_GLOBALS: Dict[str, Any] = { "MacroContext": MacroContext, "Token": Token, - "Literal": Literal, - "WordRef": WordRef, - "BranchZero": BranchZero, - "Jump": Jump, - "Label": Label, - "ForBegin": ForBegin, - "ForEnd": ForEnd, + "Op": Op, "StructField": StructField, "Definition": Definition, "Module": Module, @@ -2474,7 +2457,7 @@ PY_EXEC_GLOBALS: Dict[str, Any] = { } -def macro_struct_begin(ctx: MacroContext) -> Optional[List[ASTNode]]: +def macro_struct_begin(ctx: MacroContext) -> Optional[List[Op]]: parser = ctx.parser if parser._eof(): raise ParseError("struct name missing after 'struct:'") @@ -2529,7 +2512,7 @@ def macro_struct_begin(ctx: MacroContext) -> Optional[List[ASTNode]]: return None -def macro_struct_end(ctx: MacroContext) -> Optional[List[ASTNode]]: +def macro_struct_end(ctx: MacroContext) -> Optional[List[Op]]: raise ParseError("';struct' must follow a 'struct:' block") diff --git a/mem.sl b/mem.sl deleted file mode 100644 index 7f58d6f..0000000 --- a/mem.sl +++ /dev/null @@ -1,8 +0,0 @@ -import stdlib/stdlib.sl -import stdlib/io.sl -import stdlib/debug.sl - -: main - mem dup 5 swap ! - @ puti cr -; diff --git a/readstdin b/readstdin deleted file mode 100755 index 5f6fb0700da3d45394c4c7f01e4c3123584f170d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11648 zcmeI2e{5S<6~}LWwQ0M}Zd$4Uo$w|Dow|km=(J@k$O#R4Z+o6Lwfy*F+rx>S^-;%; zo}ZTvWuwDX^kJfDq8lKwU+@R~QEd}{j1a_{)FElN(XmcKg$jhU01*tS9jpP$X3n|y zTtEASbbs*Yo~8KS`#I;Hd+zt1_w2gwD?`?2nwy%0el?3v2|0=;BvS7}%&rt0$*>o$S3g8-T*rlll2o$}MI_QQG76jOE)OQ;UD9fY42 z&8ny46AznEflz@^flz@^flz@^flz@^flz@^flz@^f%l^V*3?Ho7;O?s|IgOc4UuTG zST4XnucuLpWdDD>cC*|XH%s&FhQBzy8(^dji4l20n0{-#Qqgv^ygh!T1;<0eEWO!Y zZ>1520sEeKd(A=4F5eBr-yS!8FsXnNm92Qx^si9d^zV*GR~d1Vg|qi)Bdj5p4kA-B z7@*!!E+K6YL?;X>u3DtLFW#xr*hc{{RHxiY)PyjdYI=Pb63uJ^iDV|2)^+uRmFppO z32+`*QPuAnE0@-yTk9f$)<%EjXLv}FqZQOHSf$?f*kx?ryNvCr%h;a0jO~fQW|UQd z)OL?~`5+b4fZ_kaC@q~g%aidPX4#9!Ow>3DZ_y-{N3sluUYhTo-XIIk@aJm>1pC}Y zdhL!+Z&C%RblfdD6=|a$hi4;4=ZwSWB1ca^<(`7SGsZQq;i0~_--f`?z&Nuodp0OB zJi5}~ps7OF<&94GC{n_buXf1yc>@(2BbsMpH23hinJMi zCFw6sx2Wkbe)v+;`D(Q=2-(2}2l_&Nw^srO%Rj43a4T4Z^QpqCV)?&nfbSwS7H84e zV0Z@&paR6jttH{q;h3{{+04gae=iO|_A@U)o^r>K5AI>m^yj8Acgug(^53=mzeokl z(!a&z7E0|^Kyc+IeYiIM2SS@Xs7jKGMvG$k7iVz$12fmcyQz{^+I&(UfbY8>n1$KXj0y;P`w5TFoGhBt#K(3 z$|$KSK)e~rZSS?F+MJEB>!~X}Z2Bvc39J9*2X8gt^!?vsT^NVYcvnbij-x)2wuQFO zZEO}B17u9yI0Qr4U{!$*#Z5-_ z^uoGsqdNE3?NERQ6v4_{hfV-EePkO@2nUx`amj?^@-|548vrk~UbPXLx@`QHO#g!A zpO&d?g(~o`ytI>xji#Jz zCjA~d;CHrGaiPlHJ}g0#*rER)pB%c0_cDG9@dV?0h~LTh9mMZt{PV;QFrFel&iDc1 z4>4XO{wU)Q5r3BPZxDZ(@oy17%lH$-|H1eViC?ujA$$7m$HccV{&V8DFn*HwXBmHu z_%P$YC7x&e4dRCwf0Ov*jK59%7~|@Zk|uGI@hh=_;Hi-%#zst+L-^Ji1#yIC4L9vo%j<4ocn&pcMw0x_@{}VWBeZC ze`I`&_|+e1%=7ES6O2DY{5Hm4B>n})e?$CBjQ^eZ!;HT}yu$bv{M`X`c!Tk4iMMQP z%zr2Gk1>AJ8hn8GAoIVS_+5Y~68N^9`B8Xs)%e`O8+YvNDG8vTy|kHR_X=hbwuCCOLk zd0z5n!T0q8^5^lzaM8)8KjCExo*jHfccltr0zR%&uGf{z+nIxoXWyU77BgZZ@22e$ zdsnya_4cTqTVv_sxI$?+Prdy88CS8wM2eW3_Y|^w!IAnohpb+4*BRzL2r;dzPIoWHKbA zJYIC~l9v2{N`7;njCk@jIw!ssCD(1&gU|+ z9#_qg7O2TwF`Hdwlo2wntL3eW$hJ0K^a=vspvql4mzl^quwp)!eL&H1*U5P{{HbAT zn7q@@eU6?fGgmR3`*O;0)X6!8{WiJDt3^pOT%-aVOF21V+0G~&5S)(PEz&73r7kvs z$#koCI}7I{O&O?~G+c~O0;;h+kjzy?HIk^DaiLnz#<{jVT)=(8)hz4`h7_W!@W7at z8iv+$Rl8sJyv#vQbV;`^n5geK|6hyW+wmit9=8qdXHgZm_WUg^LzqTFTmwCv54SP( z()Z_>8g>xYP2;n|LVO$y_)EB+ukY_2F*W0mevVfS^<%&^QfoKYMnR`Druv80s}`R% xw%||x>JDwE!UF$`Nv};vHs8U-;I+bxxYzm@ett0*X?}#Bm%hH<8Tx$we*vcSeZv3% diff --git a/stdlib/mem.sl b/stdlib/mem.sl new file mode 100644 index 0000000..b161ed8 --- /dev/null +++ b/stdlib/mem.sl @@ -0,0 +1,15 @@ +import stdlib.sl + +: alloc + 0 # addr hint (NULL) + swap # size + 3 # prot (PROT_READ | PROT_WRITE) + 34 # flags (MAP_PRIVATE | MAP_ANON) + -1 # fd + 0 # offset + mmap +; + +: free + munmap drop +; \ No newline at end of file diff --git a/test.bin b/test.bin deleted file mode 100755 index 792e00c324aee10fee36391d3c75537ed8273c47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10224 zcmeI2e{38_701Vpoj3`t9h|y}>b5R*1EIu;?-H=36xq!W-${0rMx+IjYIVLJ&QYJw zy4$nkLgP@YQckW_8WE(@(f~s6M?gqar3sZO?Uke|sS5?vK$NsXq+QfBAr-9~>~g&C z?3=yWiS2**lUpgXZ$9&VZ)V=i&N+KGx~+SAWkrQhSEcx(khQuFiQH0%!8J-DM2Bb- zi>O>Is-?E7)I^r@aPJPcsk^9i0s5$h$#uc~sr%GYSEueu2fxK`lUp`*`0w0yKvcSx ziqE`!D`%jbfpP}Q87OC2^7Uk~L^ho|2^@FIb!gAGJO`9kR7Gr7Nq z$37DFQYl_X_(avU%jhN}KQF`QUkT?gcju>Ss|)T>F4TncRm}yAlE~KPn(&xH82tDi zBKgMVaGsjj<)xZ%1zdP?;k9~Y`g5d}fSf2ORH4U1(=+qYm0G0n#^z9a;WY731Eo{77(VT>!kO6IR;{1bA{J)D`I@s*qdb>GPK z&CSQ~iiY-sn=6ek*ZF3t=e<+P#n^kaDBA>qZ6ZAOTW!s#Lew1wrT&z*nhI`xm3(-O zLlf0)*Ho73vf*S^bCd=_dxBI{!J8&!*O2Xe@Nu!|wc-_#S3$E^AzKuji^XEmDUgRV z`5$s~&Y}J^>c>&n1N$qkXCBJ2lIIBOqq6=Um5xJ&ih&NDdWx?Aw!Bk`4(}v4AH4wQ z?FjZVtO6BY_xgmFAVd{(owJ$*Po|2u2$GA`>fEGD@S;sgWR%m8%*<#}zGO;HKyq4_ z>@p?CA$dlZ=wn%lv8;#WkS@Wda+U+PqZrcL@TyOZ6Ek-fL4v6`cR}a8f!R-ysZ?Kw z>MQ~0L#WQ9xK$5H?OsT{dsL3dl(Iji*|b7laQHgEK*-%%m+dq%=WFP43{4%dQm~Hx zTXUtZoS%cP(?^3R&AApH_n;Ud52qe;O2cY^6(?)X<(CQBLvHG{3qAZByI##9jmT@s z_uUl=odasn!y&)UqePTM?#i0^Vg?}p^A(EO<$Oi+l3`v4;M2u75`4NiN8sg+WINC! zgq)l8;SlxKKyGvujy^i}e>TiVi*Kyeve#`QRD2o7&gkE8<~Xes+RGWXgz}L+=uvM{ zQJur&gF{P2x+o*P^AWb$AQq<&0zP+Sc84&5lW6MJnq-!Dqv>rlVJLFLJ5N$5=S8qX zuUsD=?rTMy%#x-H=)?2DfDwpDkh-_YKp63JPXAN zO`+#Q#yAYcr4O}*(T6IJ%SPID&M8QoD9mr7ID%pl#TgV=P+X5iZb5N3ieVH2r@-wf zawv)@cHl|>7m9D87&8u?0`~3P7oONEak*%=x?hh}h|j3+Us!OPyjO^T!Phh2Y4A4Y zIfHMVhu_8gF+=}l=HEB?{mdr~ZZm(y;QN`sX7Gc|&l>y?^M4xr3FaRg{71}}t>}=J zDt^ZN27~{Sd8@&nXWnJ--!YFG{0-)#27inB69)eW^JfkI0rNi^-2E!BLR>QVGHf9F zwr|GZ^~`HO*&!pU;zs6O24BnEGI)@A+TeFEKVa}K=8qYCC-d(Zd=K-Z2Jd73g29KG z|H0r7F+XSU3Ffl~Kf-)zy+1$CFmEvUtITgT_?ygw2EWXFi@}%R!7k4eh>4*29GiSvB3xD z;oo5XQ$zm<^S>JWyUb?|{uAbv*Zb%DYvvmaev0{aga3tjx4|zkKWgw<=37_$`>n<2 zHLXjZ!BJ3TFoJLchC%nvmA^ zBlGYb%+2_sH<#>>t+(S@yCsrM2`g(yGIq;A+KTT>+SX8{KNlCn=}gQT%-LCi!iw~= z5li+Z73@!^2i@juvTwk(63KyNcCW=U86}n*bi>6mq?af?6wkO;b~wV!3iP_j3dEEV zQAR=;o7f1(te_`rE!n}S67U?XU{q_3m+XxjRLoY_NTt+JQn>-oMozqtJm`!Slcs!wk<6^KMLXiYd^7u6v+U346a to%D~ZVih1=c$4GxEs0yag@Mtv7mnJ6x$4&ns?6mdTH~tt=DC>u{{?!^ry2kN diff --git a/test_read_file.out b/test_read_file.out deleted file mode 100755 index dbf7c098d39d2f9c4ab2c4a4170696a0a40ccf48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11696 zcmeI2e{2-T701WFh#@3*Nr>eZSGrV}0*YgNXK3n#wl;xiSGnsCg+_^#WOKe-;}hq- zV{b2p0t&4IWqWa}M)Z#;CH<#u`bYmLY81J&Y79qkX%Z_1RYD?4Dh1J#N-I+&oB-|h zy_q+=dqeF%`fqk6@63GOn>RDx`EhsaeST}|k=B+LCa+fZ6~;@^A&$hIvHAO?2V+C* zORNp7O0$IL zS*ys&_{75`R3KC!R3KC!R3KC!R3KC!R3KC!R3KC!RN&L7Kx*pVe6)q7-M^)#?l+>X ztUeAu%coI_^xzGrQ?Iti^~sZ+nmaqa31FlHi57W->27O)+kYmE^bxCt;!+apxXvRzIwcp{~ zMh@3dJHM5n?Z->lezJt^r%TvgUBY(6w`o8NoUZqYO@k8~B(o;=wqzw zaRmin!v*9&q7r>KcKzSRex1=>40YIdjb@@Q9pa5xniQeKj3nEpbK|nJ72p7b#{VB zeGBG}LbLTXfeH|^QGfoXn7sj)cpzpM#=Q0k)cG97oX6bL81pPdmjgsq>h~!z*VNAi zTpkL<scfC@gapjO#B-PPZNJe;ZG9Zsc`XL zK@0nh!grJZS%n`WensIwBHne!5YNfmkwy4x#FL8uQR2f2KS}%P!YS!mx#2--j zuZcgV@ZS?JD*P?tdlWuL{D%rZNBnJtUm*UG!v9J9iozF&uU^$Wt_Jak72es3E2D)y zuJAjFZ&!E^@m&gELwujY6U1Lq_$K1NRQRLBH{RXc{~g4)Df|WEd4(S#KB@56h<~8) z*NG>)n%g~2{Gh_;h`*=s^PIyi)*R>JBK#8PmmB!2Ja}Cte|*9ayl#*`K5YnI%kUWt zyu*c04}#Z9&M!B*f)Mgu#gutNr-``Qvkf;MGh1_{<=9eUbdLivL$RZ(}8e zKjQJ>U>NqzMfejQ-`wP%U4)MlpN}>Bf7ptz)WPOZK6mzje-z%@Q~UWn&Rdx}t_R6q zjn76Z`9f~JW0oDm`>5~Bl*gF?-x6%6&ng<`uDoMBmnl?CHc_;5M%LKSFLTL+$k`q% zJ9fde1T9sZGQ%4Lvkl9fDC8~EC|ZTxf|l&OJiagu&;BRS%Ql$ngoP^XOKMj`__V<0E32|quOl@27jF^~;dO+PQ^!jMye z-{VB(@rvc;aS{d1Skz#VgyMG0~aTj z6XNcblf0bt$^*PS;FUM<@&;b!p-s>+2b%;$5sBfz%CH3y2`6HaW&~2l7U`JGIp!{h^>Md8sMvI>{Qrg3P!&IV>GfRyoQaB<-ut@L z1Ys&Mb`RvRK0m&Y%5yV@1;(->@$Sv<7BjX6EckR^)|cm5HYTd /dev/null && /tmp/alloc \ No newline at end of file diff --git a/tests/call_syntax_parens.expected b/tests/call_syntax_parens.expected new file mode 100644 index 0000000..72350c3 --- /dev/null +++ b/tests/call_syntax_parens.expected @@ -0,0 +1,2 @@ +42 +3 diff --git a/tests/call_syntax_parens.sl b/tests/call_syntax_parens.sl new file mode 100644 index 0000000..229b874 --- /dev/null +++ b/tests/call_syntax_parens.sl @@ -0,0 +1,16 @@ +import ../stdlib/stdlib.sl +import ../stdlib/io.sl +import ../fn.sl + +: main + 2 40 + + puti cr + extend-syntax + foo(1, 2) + puti cr + 0 +; + +fn foo(int a, int b){ + return a + b; +} diff --git a/tests/call_syntax_parens.test b/tests/call_syntax_parens.test new file mode 100644 index 0000000..d5cb6e7 --- /dev/null +++ b/tests/call_syntax_parens.test @@ -0,0 +1 @@ +python main.py tests/call_syntax_parens.sl -o /tmp/call_syntax_parens > /dev/null && /tmp/call_syntax_parens diff --git a/tests/fib.expected b/tests/fib.expected new file mode 100644 index 0000000..7afbcfe --- /dev/null +++ b/tests/fib.expected @@ -0,0 +1,27 @@ +1 +1 +2 +3 +5 +8 +13 +21 +34 +55 +89 +144 +233 +377 +610 +987 +1597 +2584 +4181 +6765 +10946 +17711 +28657 +46368 +75025 +------- +25 numbers printed from the fibonaci sequence diff --git a/fib.sl b/tests/fib.sl similarity index 79% rename from fib.sl rename to tests/fib.sl index 8b174ed..237cea1 100644 --- a/fib.sl +++ b/tests/fib.sl @@ -1,5 +1,6 @@ -import stdlib/stdlib.sl -import stdlib/io.sl +import ../stdlib/stdlib.sl +import ../stdlib/io.sl +import ../stdlib/debug.sl : main 1 1 2dup 2dup puti cr puti cr @@ -13,6 +14,7 @@ import stdlib/io.sl "-------" puts r> 3 + puti " numbers printed from the fibonaci sequence" puts + 0 ; : main2 diff --git a/tests/fib.test b/tests/fib.test new file mode 100644 index 0000000..3be9ca5 --- /dev/null +++ b/tests/fib.test @@ -0,0 +1 @@ +python main.py tests/fib.sl -o /tmp/fib > /dev/null && /tmp/fib \ No newline at end of file diff --git a/tests/integration_core.expected b/tests/integration_core.expected new file mode 100644 index 0000000..430631c --- /dev/null +++ b/tests/integration_core.expected @@ -0,0 +1,33 @@ +12 +7 +42 +12 +1 +10 +22 +3 +123 +1337 +81 +99 +13 +111 +60 +5 +123 +1 +0 +1 +0 +1 +0 +1 +0 +1 +0 +1 +0 +111 +222 +16 +70 diff --git a/test.sl b/tests/integration_core.sl similarity index 97% rename from test.sl rename to tests/integration_core.sl index 3ce255f..37c3cc2 100644 --- a/test.sl +++ b/tests/integration_core.sl @@ -1,6 +1,6 @@ -import stdlib/stdlib.sl -import stdlib/io.sl -import fn.sl +import ../stdlib/stdlib.sl +import ../stdlib/io.sl +import ../fn.sl :asm mem-slot { lea rax, [rel print_buf] diff --git a/tests/integration_core.test b/tests/integration_core.test new file mode 100644 index 0000000..acda8b4 --- /dev/null +++ b/tests/integration_core.test @@ -0,0 +1 @@ +python main.py tests/integration_core.sl -o /tmp/integration_core > /dev/null && /tmp/integration_core diff --git a/tests/io_read_file.expected b/tests/io_read_file.expected new file mode 100644 index 0000000..f4b3548 --- /dev/null +++ b/tests/io_read_file.expected @@ -0,0 +1 @@ +read_file works diff --git a/test_read_file.sl b/tests/io_read_file.sl similarity index 82% rename from test_read_file.sl rename to tests/io_read_file.sl index bac2e2e..e058829 100644 --- a/test_read_file.sl +++ b/tests/io_read_file.sl @@ -1,8 +1,12 @@ -import stdlib/stdlib.sl -import stdlib/io.sl +import ../stdlib/stdlib.sl +import ../stdlib/io.sl : main - "/etc/hostname" # (addr len) + "/tmp/l2_read_file_test.txt" + "read_file works\n" + write_file drop + + "/tmp/l2_read_file_test.txt" # (addr len) read_file # (file_addr file_len) dup 0 > if # if file_len > 0, success write_buf # print file contents (file_len file_addr) diff --git a/tests/io_read_file.test b/tests/io_read_file.test new file mode 100644 index 0000000..958face --- /dev/null +++ b/tests/io_read_file.test @@ -0,0 +1 @@ +python main.py tests/io_read_file.sl -o /tmp/io_read_file > /dev/null && /tmp/io_read_file diff --git a/tests/io_read_stdin.expected b/tests/io_read_stdin.expected new file mode 100644 index 0000000..4d19008 --- /dev/null +++ b/tests/io_read_stdin.expected @@ -0,0 +1 @@ +stdin via test diff --git a/test_read_stdin.sl b/tests/io_read_stdin.sl similarity index 75% rename from test_read_stdin.sl rename to tests/io_read_stdin.sl index 7c07b2d..7d68b70 100644 --- a/test_read_stdin.sl +++ b/tests/io_read_stdin.sl @@ -1,5 +1,5 @@ -import stdlib/stdlib.sl -import stdlib/io.sl +import ../stdlib/stdlib.sl +import ../stdlib/io.sl : main 1024 diff --git a/tests/io_read_stdin.test b/tests/io_read_stdin.test new file mode 100644 index 0000000..97244eb --- /dev/null +++ b/tests/io_read_stdin.test @@ -0,0 +1 @@ +python main.py tests/io_read_stdin.sl -o /tmp/io_read_stdin > /dev/null && printf 'stdin via test\n' | /tmp/io_read_stdin diff --git a/tests/io_write_buf.expected b/tests/io_write_buf.expected new file mode 100644 index 0000000..3d6db8b --- /dev/null +++ b/tests/io_write_buf.expected @@ -0,0 +1 @@ +hello from write_buf test diff --git a/test_write_buf.sl b/tests/io_write_buf.sl similarity index 56% rename from test_write_buf.sl rename to tests/io_write_buf.sl index 72720b1..bcb91e0 100644 --- a/test_write_buf.sl +++ b/tests/io_write_buf.sl @@ -1,5 +1,5 @@ -import stdlib/stdlib.sl -import stdlib/io.sl +import ../stdlib/stdlib.sl +import ../stdlib/io.sl : main "hello from write_buf test\n" diff --git a/tests/io_write_buf.test b/tests/io_write_buf.test new file mode 100644 index 0000000..f656e52 --- /dev/null +++ b/tests/io_write_buf.test @@ -0,0 +1 @@ +python main.py tests/io_write_buf.sl -o /tmp/io_write_buf > /dev/null && /tmp/io_write_buf diff --git a/tests/io_write_file.expected b/tests/io_write_file.expected new file mode 100644 index 0000000..30fcc89 --- /dev/null +++ b/tests/io_write_file.expected @@ -0,0 +1,2 @@ +wrote bytes: +27 diff --git a/test_write_file.sl b/tests/io_write_file.sl similarity index 52% rename from test_write_file.sl rename to tests/io_write_file.sl index de74b64..2b2f8b8 100644 --- a/test_write_file.sl +++ b/tests/io_write_file.sl @@ -1,9 +1,9 @@ -import stdlib/stdlib.sl -import stdlib/io.sl +import ../stdlib/stdlib.sl +import ../stdlib/io.sl : main - "/tmp/l2_test_write.txt" # push path (addr len) - "hello from write_file test\n" # push buf (addr len) + "/tmp/l2_write_file_test.txt" # path + "hello from write_file test\n" # buffer write_file dup 0 > if "wrote bytes: " puts diff --git a/tests/io_write_file.test b/tests/io_write_file.test new file mode 100644 index 0000000..9ed47bf --- /dev/null +++ b/tests/io_write_file.test @@ -0,0 +1 @@ +python main.py tests/io_write_file.sl -o /tmp/io_write_file > /dev/null && /tmp/io_write_file diff --git a/tests/loop_while.expected b/tests/loop_while.expected new file mode 100644 index 0000000..f4c0c86 --- /dev/null +++ b/tests/loop_while.expected @@ -0,0 +1,10 @@ +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 diff --git a/while_test.sl b/tests/loop_while.sl similarity index 66% rename from while_test.sl rename to tests/loop_while.sl index bdf4051..f0000bb 100644 --- a/while_test.sl +++ b/tests/loop_while.sl @@ -1,5 +1,5 @@ -import stdlib/stdlib.sl -import stdlib/io.sl +import ../stdlib/stdlib.sl +import ../stdlib/io.sl : main 10 diff --git a/tests/loop_while.test b/tests/loop_while.test new file mode 100644 index 0000000..885a048 --- /dev/null +++ b/tests/loop_while.test @@ -0,0 +1 @@ +python main.py tests/loop_while.sl -o /tmp/loop_while > /dev/null && /tmp/loop_while diff --git a/tests/loops_and_cmp.expected b/tests/loops_and_cmp.expected new file mode 100644 index 0000000..54d9c92 --- /dev/null +++ b/tests/loops_and_cmp.expected @@ -0,0 +1,3 @@ +5 +1 +0 diff --git a/tests/loops_and_cmp.sl b/tests/loops_and_cmp.sl new file mode 100644 index 0000000..6397221 --- /dev/null +++ b/tests/loops_and_cmp.sl @@ -0,0 +1,13 @@ +import ../stdlib/stdlib.sl +import ../stdlib/io.sl + +: main + 0 + 5 for + 1 + + end + puti cr + 5 5 == puti cr + 5 4 == puti cr + 0 +; diff --git a/tests/loops_and_cmp.test b/tests/loops_and_cmp.test new file mode 100644 index 0000000..6b1583f --- /dev/null +++ b/tests/loops_and_cmp.test @@ -0,0 +1 @@ +python main.py tests/loops_and_cmp.sl -o /tmp/loops_and_cmp > /dev/null && /tmp/loops_and_cmp diff --git a/tests/mem.expected b/tests/mem.expected new file mode 100644 index 0000000..1f7a723 --- /dev/null +++ b/tests/mem.expected @@ -0,0 +1,2 @@ +5 +6 \ No newline at end of file diff --git a/aa.sl b/tests/mem.sl similarity index 63% rename from aa.sl rename to tests/mem.sl index a6e7c1e..4e6de88 100644 --- a/aa.sl +++ b/tests/mem.sl @@ -1,5 +1,5 @@ -import stdlib/stdlib.sl -import stdlib/io.sl +import ../stdlib/stdlib.sl +import ../stdlib/io.sl : main mem 5 swap ! diff --git a/tests/mem.test b/tests/mem.test new file mode 100644 index 0000000..fc410e8 --- /dev/null +++ b/tests/mem.test @@ -0,0 +1 @@ +python main.py tests/mem.sl -o /tmp/mem > /dev/null && /tmp/mem diff --git a/tests/override_dup_compile_time.expected b/tests/override_dup_compile_time.expected new file mode 100644 index 0000000..1e8b314 --- /dev/null +++ b/tests/override_dup_compile_time.expected @@ -0,0 +1 @@ +6 diff --git a/tests/override_dup_compile_time.sl b/tests/override_dup_compile_time.sl new file mode 100644 index 0000000..29b3534 --- /dev/null +++ b/tests/override_dup_compile_time.sl @@ -0,0 +1,28 @@ +import ../stdlib/stdlib.sl +import ../stdlib/io.sl + +: dup + 6 +; +compile-only + +: emit-overridden + "dup" use-l2-ct + 42 + dup + int>string + nil + token-from-lexeme + list-new + swap + list-append + inject-tokens +; +immediate +compile-only + +: main + emit-overridden + puti cr + 0 +; diff --git a/tests/override_dup_compile_time.test b/tests/override_dup_compile_time.test new file mode 100644 index 0000000..13bd19b --- /dev/null +++ b/tests/override_dup_compile_time.test @@ -0,0 +1 @@ +python main.py tests/override_dup_compile_time.sl -o /tmp/override_dup_compile_time > /dev/null && /tmp/override_dup_compile_time diff --git a/tests/run_tests.py b/tests/run_tests.py deleted file mode 100644 index d70befe..0000000 --- a/tests/run_tests.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python3 -"""Simple end-to-end test runner for L2. - -Each test case provides an L2 program source and an expected stdout. The runner -invokes the bootstrap compiler on the fly and executes the produced binary. -""" - -from __future__ import annotations - -import subprocess -import sys -import tempfile -from dataclasses import dataclass -from pathlib import Path -from typing import List - -ROOT = Path(__file__).resolve().parents[1] -COMPILER = ROOT / "main.py" -PYTHON = Path(sys.executable) - - -@dataclass -class TestCase: - name: str - source: str - expected_stdout: str - - -CASES: List[TestCase] = [ - TestCase( - name="call_syntax_parens", - source=f""" -import {ROOT / 'stdlib/stdlib.sl'} -import {ROOT / 'stdlib/io.sl'} -import {ROOT / 'fn.sl'} - -: main - 2 40 + - puti cr - extend-syntax - foo(1, 2) - puti cr - 0 -; - -fn foo(int a, int b){{ - return a + b; -}} -""", - expected_stdout="42\n3\n", - ), - TestCase( - name="loops_and_cmp", - source=f""" -import {ROOT / 'stdlib/stdlib.sl'} -import {ROOT / 'stdlib/io.sl'} - -: main - 0 - 5 for - 1 + - end - puti cr - 5 5 == puti cr - 5 4 == puti cr - 0 -; -""", - expected_stdout="5\n1\n0\n", - ), - TestCase( - name="override_dup_compile_time", - source=f""" -import {ROOT / 'stdlib/stdlib.sl'} -import {ROOT / 'stdlib/io.sl'} - -: dup - 6 -; -compile-only - -: emit-overridden - "dup" use-l2-ct - 42 - dup - int>string - nil - token-from-lexeme - list-new - swap - list-append - inject-tokens -; -immediate -compile-only - -: main - emit-overridden - puti cr - 0 -; -""", - expected_stdout="6\n", - ), - TestCase( - name="string_puts", - source=f""" -import {ROOT / 'stdlib/stdlib.sl'} -import {ROOT / 'stdlib/io.sl'} - -: main - \"hello world\" puts - \"line1\\nline2\" puts - \"\" puts - 0 -; -""", - expected_stdout="hello world\nline1\nline2\n\n", - ), -] - - -def run_case(case: TestCase) -> None: - print(f"[run] {case.name}") - with tempfile.TemporaryDirectory() as tmp: - src_path = Path(tmp) / f"{case.name}.sl" - exe_path = Path(tmp) / f"{case.name}.out" - src_path.write_text(case.source.strip() + "\n", encoding="utf-8") - - compile_cmd = [str(PYTHON), str(COMPILER), str(src_path), "-o", str(exe_path)] - compile_result = subprocess.run( - compile_cmd, - capture_output=True, - text=True, - cwd=ROOT, - ) - if compile_result.returncode != 0: - sys.stderr.write("[fail] compile error\n") - sys.stderr.write(compile_result.stdout) - sys.stderr.write(compile_result.stderr) - raise SystemExit(compile_result.returncode) - - run_result = subprocess.run( - [str(exe_path)], - capture_output=True, - text=True, - cwd=ROOT, - ) - if run_result.returncode != 0: - sys.stderr.write("[fail] execution error\n") - sys.stderr.write(run_result.stdout) - sys.stderr.write(run_result.stderr) - raise SystemExit(run_result.returncode) - - if run_result.stdout != case.expected_stdout: - sys.stderr.write(f"[fail] output mismatch for {case.name}\n") - sys.stderr.write("expected:\n" + case.expected_stdout) - sys.stderr.write("got:\n" + run_result.stdout) - raise SystemExit(1) - - print(f"[ok] {case.name}") - - -def main() -> None: - for case in CASES: - run_case(case) - print("[all tests passed]") - - -if __name__ == "__main__": - main() diff --git a/tests/string_puts.expected b/tests/string_puts.expected new file mode 100644 index 0000000..78e9c9f --- /dev/null +++ b/tests/string_puts.expected @@ -0,0 +1,4 @@ +hello world +line1 +line2 + diff --git a/tests/string_puts.sl b/tests/string_puts.sl new file mode 100644 index 0000000..1c87ef7 --- /dev/null +++ b/tests/string_puts.sl @@ -0,0 +1,9 @@ +import ../stdlib/stdlib.sl +import ../stdlib/io.sl + +: main + "hello world" puts + "line1\nline2" puts + "" puts + 0 +; diff --git a/tests/string_puts.test b/tests/string_puts.test new file mode 100644 index 0000000..493f022 --- /dev/null +++ b/tests/string_puts.test @@ -0,0 +1 @@ +python main.py tests/string_puts.sl -o /tmp/string_puts > /dev/null && /tmp/string_puts diff --git a/tests/test.py b/tests/test.py new file mode 100644 index 0000000..f41fc4f --- /dev/null +++ b/tests/test.py @@ -0,0 +1,66 @@ +#!/usr/bin/python +import sys +import os +import subprocess + +COLORS = { + "red": "\033[91m", + "green": "\033[92m", + "yellow": "\033[93m", + "blue": "\033[94m", + "reset": "\033[0m" +} + +def print_colored(text, color): + print(COLORS.get(color, "") + text + COLORS["reset"], end="") + +def run_tests(): + test_dir = "tests" + any_failed = False + + if not os.path.isdir(test_dir): + print("No 'tests' directory found.") + return 1 + + for file in sorted(os.listdir(test_dir)): + if file.endswith(".test"): + test_path = os.path.join(test_dir, file) + expected_path = test_path.replace(".test", ".expected") + + if not os.path.isfile(expected_path): + print(f"Missing expected output file for {file}") + any_failed = True + continue + + with open(test_path, "r") as test_file: + command = test_file.read().strip() + + with open(expected_path, "r") as expected_file: + expected_output = expected_file.read().strip() + + try: + result = subprocess.run(command, shell=True, text=True, capture_output=True) + actual_output = result.stdout.strip() + stderr_output = result.stderr.strip() + + if result.returncode == 0 and actual_output == expected_output: + print_colored("[OK] ", "green") + print(f"{file} passed") + else: + print_colored("[ERR] ", "red") + print(f"{file} failed (exit {result.returncode})") + print(f"Expected:\n{expected_output}") + print(f"Got:\n{actual_output}") + if stderr_output: + print(f"Stderr:\n{stderr_output}") + any_failed = True + + except Exception as e: + print_colored(f"Error running {file}: {e}", "red") + any_failed = True + + return 1 if any_failed else 0 + +if __name__ == "__main__": + sys.exit(run_tests()) + diff --git a/write b/write deleted file mode 100755 index ec3c6047fa1f371fd7a3c02d6e53b40f438f5b03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11648 zcmeI2ZEPIH8Gy%*o!ANVE;v|elS+p;L=fa+-w~BSsO%6|yV6~Xl$b9eHfP^DS>=4^ z?(N~EI4bQaEz8xaL=yxe3BOwLqe22CWQ+nP7i@)(1i~LG)GAU^umTYYkuYGI>-)~U zv%5DWma6{jj+FU$-jA7i=i}C!{Y_u`7tKvgOr~b`bH-cI9*#uL*wn33gRvfV2U`UB z61JG@w)i5bNefZVl1!E?DggG;idAYe>Q9zO77IODN zpLke=5eOp?Mj(tp7=bVXVFbbmgb@fM5Jn)3Kp27l#|WgyZ+bA=#4_$@>G8F{j5f2` zbMR;R1coBB;d`e|ueQYX%CR=hotfAOFw%-di@eHowb~`Jyc# zt)}B`;3BHK*GPlv!|^t)@(ml?njUZ66Jabpe(ekv8){=c=?(Ahy-RbCYVJSLOxt(L zxn=_Y?tc@rNb7X#Un9+IsgJbr^#_1V3b8jN&8_wFiD;F1wzplI`=poKfcmGP{u(%A zy^~8JM}_h-t$t#9ahFzq>+{uG_bJW&SfBgq@uL7vJkbdh+-dthDWBD0+)g`JUJH1- z?&;H$!yjJu(}&_Phqmw^*+Jg^jMC)I87mAI<9yNw*6 ztCf5vQ5^hAVIFit`$=zt-NQ$M!@4Edn7a)ea)5Rq#SQnYHaCAYx+35SwxPD6_ByU@ zWPc4~=l2qn9auniZ~@u#3&;*HAUovCw5m8e-t2K)E`$p9faadoDrYa~)v@>*+$%91 zW1N93n!)XnsY0|X$GRrkae}Ryd(2xPnCI;juZ{7EWn4}X+sHYc-^O_Cn~Lmz3-)zn z|4}&9$Kl^8?S>EeQEeFCmGs(uJq_hkU_Iq;FIj#F^IH_RIk z_>5sZcxP_XU2)x{-IHnea@sw|BcNBlV`CjOw3C3~pywXUFFGV7YL0K-h^w1BA1iVf3><38;aD%}#$0c67*LS2!u@H5G7jEoy%CE!dxj zOlolZEf5q5dIKgMX!0hSOk#F3sMXLQOko7V2!s&`BM?R)j6fKHFarNo1a_MFd@(j; z7l&h`w&j?{kd-%Mj#+Y+vUSez$hv&ez?Q+K31_#%M(v_w#s>BPzB2|bu!;?3!7LXu zZM#ssd!Yf~-{>vuVqMk2XHEuR6ReTn0gyr$@ub4)Xf(s1mcwFJ|j*0V675-!5mlS>@@yK;OXy~Q2#BWjf9mEp~zlV6g z!nY6~QTYAD_bPll@h25-5r0nMHu0Af{uuEYh5v#08HN9ucwONKiLdJD@nVCOzYzbK z!e1i3RpCd77ZpBD{4s@}B>pFb|DE`|3jY`JGYbEb_$7sZLwwbW#(9a)d79Wg3U6=5 zSvRr!6y8C6hr)kKe7C~a5Z|ltB=M&demC(K6rLu&{`$u8=ZSAq_&(y6!VeR#DEvj@ zXB2*%_}2nh;%*a>Lz;d~L>uJC@3_cnOieigpM z=?$mKU&3Q9Z=cSXr>Yojit$c2s|C7#t z@Dth6Ff&R{)^-wwqG9f~9OKb!zHGA5qMb7ajoZ6qE!iz)p9kH!~W57Sr%np!t&e~x~%Y3moLO!e=1yLKa3RY>SL27(Zx$=nU zQ#`i}l!rt!XM;J{C_ZZ1qE;Hs5`$+Kfs7<5QoUf2)F}_{65^!i9`#6^^!+4#=SFhC zb15rXS)oB0$@N51IU|*m(r&+=8k7nYbR#twkeYs7u7x3&Vt822Zn#|V>bQu)Wwt;a z7AYJBIdLN;BV^;j@2Zx*3}IwqDxH`>j7F^d1*K{GtK5+CTOUSLP4W12KV~St3gO w);I(IurEw2MZxg@QDonQcyR#-2I-I@#QuV5IW!a%E*_`vrEd!=LtVB14}}+LJOBUy diff --git a/write_buf_test b/write_buf_test deleted file mode 100755 index 3f474ae540bb074e500ff9eacae45543b2fb45c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11360 zcmeI2e`p*<6vrpOYSLEkY-^1sf1Glnl^XM-MT4OvX;XIb4g_0K5SL4C(;mIt#l1b# zXoA(VrRy2QQvWEm+CN17LqQQrjH0m@8*4Sy`j6lbM1$6!q!x@A^?YyU&FNX#$&5J z7g(}|D9@5lmMka$_ECc-)fx3C%jRVwPL?tb+i_P&_*tk^7*sY8KFTVECG!*a3ts_W z0bc=M0bc=M0bc=M0bc=M0bc=M0bhatqXLn!Ypw`Zu&DEGWbB4Ou#%mfgRkY|C`GjW z54%>+SBLf7RITPrk9PnJ)F9CU$C&O^hYJPi*Yl0x{Z&}+VS4Vz+7fR*60U_5LETv? z8|3c}*J`=n*vRdXv6|rkW0A3o$FOKGjC4lYPmSK9Imb2U3v8zCJ!7vN$M5}b;Vn>e zqNYDk$(DOa8{4=Y$b@jaL(-f=7oUihTVSJg+WeM<6MelXKm{REa7{43EvUVr{%@7Z2u&)CLkHbTK56X9@c4CpCVj^ zi1T3?{0pHrJ&DdT$DimB>xNT{!h*}kW-1hQ=5^I7&?A9G| z=tP{;5$CUn^F7x=&;8CuR?`4a1A^x_>cA874+wpHx#0W(Yq~m&e@&J4l_0`dZGjJ2 zH~|#k<6pi4z5>1iz5>1iz5>1iz5@SY1$LUrWIEJur3XSoR>C%o-fVx!HZwMUFJ9up z@7mSuTu}|d-x?Xb6>y#We?A4=NW4|y?Zi73zM1%K3Xc-MN8xu7zgOXX#9vkTF!7HS zzMuGcg+D=j?WLXElD8v^@aKuQD)Fxn?^5^_@p}~h0r6c5|BU!Pg?~dlukbnIhZO!h z@fQ_dg$oSpcv9g3;@>E|p7?o%Urju)s+0F5Z|jM#Q}|89n-tzne7nM<#0M3A2k}vb z8^j+~_)g-76@D-AR}_9f@o9zcBmT9*4-hXZ{4nu`)#ds;OZ+B@e2SCRN;h1cTubl7iqD0~(19SUzGzFXnf z5+7A~3-JRA?;!qy!fz$M@v`#q?;^fU;g1kcDEtWVoWfrs{++_#CH{xPzaqYDZTWb9 zjEO{AR95r_}MTWRVz@8tZ#d99#$H9zakCX(?R@h70+{y=PsWd@j$ zv169qlu8@s?u2dJ7fWVMHk7vFMxU{vSz4_v!m?bJv8|+;5_B+YXBgffnPsHRp=2Uu z8tGJWSkOT$k+Kc=h-$2tqT`7j3E484P7hL!#Ez7(`V*-{W~V`6d{FW1py<<`g{a0Y zXwDtIC8god0M^XMr*H|QW`O7^h;wS z8EtW+EiPe;XSemq021A3>nrh^o-NnHkV`QzAZIs_O}REMqDUD_QHN=gBPAzpv`K|5 zFh#WG&37;%<*-UjGZr`c6G<5^t4)2$bjCFLV~M1Z%$Oz#X}NyxNe{}cqBy)si1qY( z@aj!G1+R;-sxB}4KrE4B@t7SGyPDy4Y!-I|cPn?9AWR%~J2)bo Slo0Mt)BC{dOM}5y+y4#Y_2@$Y