diff --git a/main.py b/main.py index 7a2c030..e1a91f1 100644 --- a/main.py +++ b/main.py @@ -344,6 +344,7 @@ OP_LIST_BEGIN = 8 OP_LIST_END = 9 OP_LIST_LITERAL = 10 OP_OTHER = 11 +OP_RET = 12 _OP_STR_TO_INT = { "word": OP_WORD, @@ -357,6 +358,7 @@ _OP_STR_TO_INT = { "list_begin": OP_LIST_BEGIN, "list_end": OP_LIST_END, "list_literal": OP_LIST_LITERAL, + "ret": OP_RET, } @@ -1012,13 +1014,13 @@ class Parser: _KW_PY = 6 _KW_EXTERN = 7 _KW_PRIORITY = 8 + _KW_RET = 9 _keyword_dispatch = { "[": _KW_LIST_BEGIN, "]": _KW_LIST_END, "word": _KW_WORD, "end": _KW_END, ":asm": _KW_ASM, ":py": _KW_PY, - "extern": _KW_EXTERN, "priority": _KW_PRIORITY, + "extern": _KW_EXTERN, "priority": _KW_PRIORITY, "ret": _KW_RET, } _kw_get = _keyword_dispatch.get - _tokens = self.tokens try: while self.pos < len(_tokens): @@ -1065,6 +1067,8 @@ class Parser: self._parse_extern(token) elif kw == _KW_PRIORITY: self._parse_priority_directive(token) + elif kw == _KW_RET: + self._handle_ret(token) continue if self._try_handle_builtin_control(token): continue @@ -1297,6 +1301,9 @@ class Parser: self._pending_priority = None return value + def _handle_ret(self, token: Token) -> None: + self._append_op(_make_op("ret", loc=token)) + # Internal helpers --------------------------------------------------------- def _parse_extern(self, token: Token) -> None: @@ -3998,6 +4005,7 @@ class CompileTimeVM: _OP_JUMP = OP_JUMP _OP_LABEL = OP_LABEL _OP_LIST_BEGIN = OP_LIST_BEGIN + _OP_RET = OP_RET _OP_LIST_END = OP_LIST_END _OP_LIST_LITERAL = OP_LIST_LITERAL try: @@ -4301,6 +4309,9 @@ class CompileTimeVM: ip += 1 continue + if kind == _OP_RET: + return + self.current_location = _node.loc raise ParseError(f"unsupported compile-time op (opcode={kind})") finally: @@ -4474,6 +4485,9 @@ class FunctionEmitter: _a(f" mov {register}, [r12]") _a(" add r12, 8") + def ret(self) -> None: + self.text.append(" ret") + def _int_trunc_div(lhs: int, rhs: int) -> int: if rhs == 0: @@ -6554,6 +6568,10 @@ class Assembler: builder.emit(" mov [r12], rax") return + if kind == OP_RET: + builder.ret() + return + raise CompileError(f"unsupported op {node!r} while emitting '{self._emit_stack[-1]}'" if self._emit_stack else f"unsupported op {node!r}") def _emit_mmap_alloc(self, builder: FunctionEmitter, size: int, target_reg: str = "rax") -> None: @@ -10476,6 +10494,26 @@ def _run_docs_tui( " 3 1 syscall # 3 args, nr=1 (write)" ), }, + { + "name": "ret", + "category": "Control Flow", + "syntax": "ret", + "summary": "Return from a word", + "detail": ( + "Returns from a word.\n\n" + "Example:\n" + " word a\n" + " \"g\" puts\n" + " ret\n" + " \"g\" puts\n" + " end\n\n" + " word main\n" + " a\n" + " end\n" + "Output:\n" + " g\n" + ), + }, { "name": "exit", "category": "System", diff --git a/stdlib/utils.sl b/stdlib/utils.sl index a87f509..f1ef28f 100644 --- a/stdlib/utils.sl +++ b/stdlib/utils.sl @@ -1,7 +1,11 @@ -#strcmp [*, addr, len, addr | len] -> [*, addr, len, addr, len | bool] +#strcmp [*, addr, len, addr | len] -> [* | bool] word strcmp - 3 pick 2 pick @ swap @ == + >r nip r> for + 2dup c@ swap c@ != if drop drop 0 ret end + 1 + swap 1 + + end + drop drop 1 end #strconcat [*, addr, len, addr | len] -> [*, addr | len] diff --git a/tests/ret_test.expected b/tests/ret_test.expected new file mode 100644 index 0000000..01058d8 --- /dev/null +++ b/tests/ret_test.expected @@ -0,0 +1 @@ +g diff --git a/tests/ret_test.sl b/tests/ret_test.sl new file mode 100644 index 0000000..6465412 --- /dev/null +++ b/tests/ret_test.sl @@ -0,0 +1,11 @@ +import stdlib.sl + +word g + "g" puts + ret + "g" puts +end + +word main + g +end diff --git a/tests/str.expected b/tests/str.expected index 2c9891f..c02ff56 100644 --- a/tests/str.expected +++ b/tests/str.expected @@ -1,4 +1,3 @@ 1 -g -g +0 hello world hello world hello world hello world hello world diff --git a/tests/str.sl b/tests/str.sl index 4d2483a..90cb504 100644 --- a/tests/str.sl +++ b/tests/str.sl @@ -1,11 +1,13 @@ import stdlib.sl word main - "g" "g" + "ggggggggh" "ggggggggh" + strcmp + puti cr + + "ggggggggh" "ggggggggd" strcmp puti cr - puts - puts "hello world hello world hello " "world hello world hello world" strconcat