diff --git a/aa.sl b/aa.sl new file mode 100644 index 0000000..a6e7c1e --- /dev/null +++ b/aa.sl @@ -0,0 +1,9 @@ +import stdlib/stdlib.sl +import stdlib/io.sl + +: main + mem 5 swap ! + mem 8 + 6 swap ! + mem @ puti cr + mem 8 + @ puti cr +; diff --git a/fib.sl b/fib.sl index a6f637e..8b174ed 100644 --- a/fib.sl +++ b/fib.sl @@ -9,7 +9,7 @@ import stdlib/io.sl 22 dup >r for 2dup + dup puti cr rot - next + end "-------" puts r> 3 + puti " numbers printed from the fibonaci sequence" puts @@ -19,6 +19,6 @@ import stdlib/io.sl 1 2 while over 100 < do over puti cr swap over + - repeat + end ; diff --git a/fn.sl b/fn.sl index 9c011a3..5047e2e 100644 --- a/fn.sl +++ b/fn.sl @@ -1,14 +1,14 @@ : call-syntax-rewrite # ( fnameToken -- handled ) - dup token-lexeme identifier? 0 == if drop 0 exit then - peek-token dup nil? if drop drop 0 exit then - dup token-lexeme "(" string= 0 == if drop drop 0 exit then + dup token-lexeme identifier? 0 == if drop 0 exit end + peek-token dup nil? if drop drop 0 exit end + dup token-lexeme "(" string= 0 == if drop drop 0 exit end swap >r # stash fnameTok drop # discard peeked '(' next-token drop # consume '(' list-new # out list-new # out cur begin - next-token dup nil? if "unterminated call expression" parse-error then + next-token dup nil? if "unterminated call expression" parse-error end dup token-lexeme ")" string= if drop # flush current arg @@ -16,13 +16,13 @@ begin r> list-append # out'' inject-tokens 1 exit - then + end dup token-lexeme "," string= if drop list-extend # out' list-new # out' cur continue - then + end # default: append tok to cur list-append again @@ -39,11 +39,11 @@ compile-only : fn-op-prec - dup "+" string= if drop 1 exit then - dup "-" string= if drop 1 exit then - dup "*" string= if drop 2 exit then - dup "/" string= if drop 2 exit then - dup "%" string= if drop 2 exit then + dup "+" string= if drop 1 exit end + dup "-" string= if drop 1 exit end + dup "*" string= if drop 2 exit end + dup "/" string= if drop 2 exit end + dup "%" string= if drop 2 exit end drop 0 ; compile-only @@ -59,10 +59,10 @@ compile-only begin over list-length swap >= if # params flag r> exit - then + end dup >r # params idx (r: idx name) over swap list-get # params elem - 1 rpick string= if "duplicate parameter names in fn definition" parse-error then + 1 rpick string= if "duplicate parameter names in fn definition" parse-error end drop # drop comparison flag when no error r> 1 + # params idx+1 again @@ -76,18 +76,18 @@ compile-only begin 0 rpick lexer-pop token-lexeme # params lex swap drop # params lex (drop returned lexer) - dup ")" string= if drop r> exit then - dup "int" string= 0 == if "only 'int' parameters are supported in fn definitions" parse-error then + dup ")" string= if drop r> exit end + dup "int" string= 0 == if "only 'int' parameters are supported in fn definitions" parse-error end drop # params 0 rpick lexer-pop token-lexeme # params lexer pname swap drop # params pname - dup identifier? 0 == if "invalid parameter name in fn definition" parse-error then + dup identifier? 0 == if "invalid parameter name in fn definition" parse-error end fn-check-dup # params pname list-append # params 0 rpick lexer-pop token-lexeme # params lexer sep swap drop # params sep - dup "," string= if drop continue then - dup ")" string= if drop r> exit then + dup "," string= if drop continue end + dup ")" string= if drop r> exit end "expected ',' or ')' in parameter list" parse-error again ; @@ -106,7 +106,7 @@ compile-only begin 0 rpick list-empty? if rdrop exit - then + end 0 rpick list-pop-front # acc tokens' first rdrop # acc tokens' swap # acc first tokens' @@ -118,13 +118,13 @@ again compile-only : fn-validate-body - dup list-length 0 == if "empty function body" parse-error then - dup 0 list-get token-lexeme "return" string= 0 == if "function body must start with 'return'" parse-error then - dup list-last ";" string= 0 == if "function body must terminate with ';'" parse-error then + dup list-length 0 == if "empty function body" parse-error end + dup 0 list-get token-lexeme "return" string= 0 == if "function body must start with 'return'" parse-error end + dup list-last ";" string= 0 == if "function body must terminate with ';'" parse-error end list-clone # body body' list-pop drop # body expr' (trim trailing ';') list-pop-front drop # body expr (trim leading 'return') - dup list-length 0 == if "missing return expression" parse-error then + dup list-length 0 == if "missing return expression" parse-error end ; compile-only @@ -135,19 +135,19 @@ begin dup list-empty? if drop # out exit - then + end list-pop-front # out body' tok swap >r # out tok (r: body') dup "return" string= if drop r> continue - then + end dup ";" string= if drop r> continue - then + end list-append # out' r> # out' body' continue @@ -157,14 +157,14 @@ compile-only : fn-body->tokens # bodyLexemes -- tokens - dup list-length 0 == if "empty function body" parse-error then + dup list-length 0 == if "empty function body" parse-error end dup 0 list-get token-lexeme "return" string= if fn-validate-body # expr shunt # postfix exit - then + end fn-filter-raw-body - dup list-length 0 == if "empty function body" parse-error then + dup list-length 0 == if "empty function body" parse-error end ; compile-only @@ -177,7 +177,7 @@ begin ">r" list-append # params out' r> # params out' n-1 continue - then + end drop # params out exit again @@ -191,7 +191,7 @@ begin 1 - >r "rdrop" list-append continue - then + end drop # drop counter swap drop # out exit @@ -204,7 +204,7 @@ compile-only 1 - 0 rpick ">r" list-append drop fn-translate-prologue-loop - then + end drop ; compile-only @@ -214,7 +214,7 @@ compile-only 1 - 0 rpick "rdrop" list-append drop fn-translate-epilogue-loop - then + end drop ; compile-only @@ -228,13 +228,13 @@ begin drop # params r> drop # drop name -1 0 exit # params -1 0 - then # params idx + end # params idx over over list-get # params idx elem 0 rpick string= # params idx flag if r> drop # drop name 1 exit # params idx 1 - then + end drop # params idx 1 + # params idx+1 again @@ -250,7 +250,7 @@ compile-only over swap >= if # params map idx flag drop # params map exit - then # params map idx + end # params map idx 2 pick over list-get # params map idx name swap # params map name idx dup >r # params map name idx (r: idx) @@ -274,7 +274,7 @@ compile-only list-append # out' r> # out' map exit - then + end drop # out map tok # param? @@ -292,7 +292,7 @@ compile-only # drop saved tok r> drop # out'' map exit - then + end # not a param: drop idx|nil, append original tok drop # out map r> # out map tok @@ -308,7 +308,7 @@ compile-only dup list-empty? if drop exit - then + end list-pop-front # map out postfix' tok swap >r # map out tok (r: postfix') >r swap r> # out map tok (r: postfix') @@ -354,7 +354,7 @@ compile-only dup lexer-pop # lexer nameTok dup >r # save nameTok token-lexeme # lexer name - dup identifier? 0 == if "invalid function name for 'fn'" parse-error then + dup identifier? 0 == if "invalid function name for 'fn'" parse-error end >r # save name string drop # leave lexer only for params "(" lexer-expect drop # consume '(' keep lexer diff --git a/main.py b/main.py index ccbde5d..bf46120 100644 --- a/main.py +++ b/main.py @@ -258,7 +258,7 @@ class ForBegin(ASTNode): @dataclass -class ForNext(ASTNode): +class ForEnd(ASTNode): loop_label: str end_label: str @@ -396,6 +396,29 @@ class Parser: def most_recent_definition(self) -> Optional[Word]: return self.last_defined + def _handle_end_control(self) -> None: + """Handle unified 'end' for all block types""" + if not self.control_stack: + raise ParseError("unexpected 'end' without matching block") + + entry = self.control_stack.pop() + + if entry["type"] == "if": + # For if without else + if "false" in entry: + self._append_node(Label(name=entry["false"])) + elif entry["type"] == "else": + self._append_node(Label(name=entry["end"])) + elif entry["type"] == "while": + self._append_node(Jump(target=entry["begin"])) + self._append_node(Label(name=entry["end"])) + elif entry["type"] == "for": + # Emit ForEnd node for loop decrement + self._append_node(ForEnd(loop_label=entry["loop"], end_label=entry["end"])) + elif entry["type"] == "begin": + self._append_node(Jump(target=entry["begin"])) + self._append_node(Label(name=entry["end"])) + # Parsing ------------------------------------------------------------------ def parse(self, tokens: Iterable[Token], source: str) -> Module: self.tokens = [] @@ -440,23 +463,17 @@ class Parser: if lexeme == "else": self._handle_else_control() continue - if lexeme == "then": - self._handle_then_control() - continue if lexeme == "for": self._handle_for_control() continue - if lexeme == "next": - self._handle_next_control() - continue if lexeme == "while": self._handle_while_control() continue if lexeme == "do": self._handle_do_control() continue - if lexeme == "repeat": - self._handle_repeat_control() + if lexeme == "end": + self._handle_end_control() continue if self._maybe_expand_macro(token): continue @@ -714,23 +731,12 @@ class Parser: self._append_node(Label(name=entry["false"])) self._push_control({"type": "else", "end": end_label}) - def _handle_then_control(self) -> None: - entry = self._pop_control(("if", "else")) - if entry["type"] == "if": - self._append_node(Label(name=entry["false"])) - else: - self._append_node(Label(name=entry["end"])) - 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._push_control({"type": "for", "loop": loop_label, "end": end_label}) - def _handle_next_control(self) -> None: - entry = self._pop_control(("for",)) - self._append_node(ForNext(loop_label=entry["loop"], end_label=entry["end"])) - def _handle_while_control(self) -> None: begin_label = self._new_label("begin") end_label = self._new_label("end") @@ -742,11 +748,6 @@ class Parser: self._append_node(BranchZero(target=entry["end"])) self._push_control(entry) - def _handle_repeat_control(self) -> None: - entry = self._pop_control(("begin",)) - self._append_node(Jump(target=entry["begin"])) - self._append_node(Label(name=entry["end"])) - def _begin_definition(self, token: Token) -> None: if self._eof(): raise ParseError(f"definition name missing after ':' at {token.line}:{token.column}") @@ -1300,7 +1301,7 @@ class CompileTimeVM: self.loop_stack.append({"remaining": count, "begin": ip, "initial": count}) ip += 1 continue - if isinstance(node, ForNext): + if isinstance(node, ForEnd): if not self.loop_stack: raise ParseError("'next' without matching 'for'") frame = self.loop_stack[-1] @@ -1326,7 +1327,7 @@ class CompileTimeVM: for idx, node in enumerate(nodes): if isinstance(node, ForBegin): stack.append(idx) - elif isinstance(node, ForNext): + elif isinstance(node, ForEnd): if not stack: raise ParseError("'next' without matching 'for'") begin_idx = stack.pop() @@ -1641,7 +1642,7 @@ class Assembler: if isinstance(node, ForBegin): self._emit_for_begin(node, builder) return - if isinstance(node, ForNext): + if isinstance(node, ForEnd): self._emit_for_next(node, builder) return raise CompileError(f"unsupported AST node {node!r}") @@ -1737,7 +1738,7 @@ class Assembler: builder.emit(" mov [r13], rax") builder.emit(f"{node.loop_label}:") - def _emit_for_next(self, node: ForNext, builder: FunctionEmitter) -> None: + def _emit_for_next(self, node: ForEnd, builder: FunctionEmitter) -> None: builder.emit(" mov rax, [r13]") builder.emit(" dec rax") builder.emit(" mov [r13], rax") @@ -2463,7 +2464,7 @@ PY_EXEC_GLOBALS: Dict[str, Any] = { "Jump": Jump, "Label": Label, "ForBegin": ForBegin, - "ForNext": ForNext, + "ForEnd": ForEnd, "StructField": StructField, "Definition": Definition, "Module": Module, diff --git a/stdlib/debug.sl b/stdlib/debug.sl index 8429b5c..ff70a45 100644 --- a/stdlib/debug.sl +++ b/stdlib/debug.sl @@ -10,7 +10,7 @@ dup pick puti cr 1 + - next + end drop ; diff --git a/strconcat.sl b/strconcat.sl index b0d0c9b..4799087 100644 --- a/strconcat.sl +++ b/strconcat.sl @@ -62,7 +62,7 @@ import stdlib/io.sl c! drop swap - next + end swap nip r> dup -rot - swap @@ -72,4 +72,4 @@ import stdlib/io.sl "hello world hello world hello " "world hello world hello world" strconcat puts -; \ No newline at end of file +; diff --git a/test.sl b/test.sl index bfcb0d7..3ce255f 100644 --- a/test.sl +++ b/test.sl @@ -104,7 +104,7 @@ fn fancy_add(int a, int b){ 111 puti cr else 222 puti cr - then + end ; : test-else-if @@ -116,8 +116,8 @@ fn fancy_add(int a, int b){ 60 puti cr else 70 puti cr - then - then + end + end drop ; @@ -125,7 +125,7 @@ fn fancy_add(int a, int b){ 0 5 for 1 + - next + end puti cr ; @@ -133,7 +133,7 @@ fn fancy_add(int a, int b){ 123 0 for drop - next + end puti cr ; diff --git a/test_read_file.sl b/test_read_file.sl index 261c820..bac2e2e 100644 --- a/test_read_file.sl +++ b/test_read_file.sl @@ -8,24 +8,24 @@ import stdlib/io.sl write_buf # print file contents (file_len file_addr) 0 exit - then + end dup -2 == if # open() failed drop "open() failed: errno=" puts swap puti cr exit - then + end dup -1 == if # fstat() failed drop "fstat() failed: errno=" puts swap puti cr exit - then + end dup -3 == if # mmap() failed drop "mmap() failed" puts exit - then + end "unknown read_file failure" puts dup # file_len file_len file_addr exit # Exit with returned file_len as the program exit code (debug) diff --git a/test_read_stdin.sl b/test_read_stdin.sl index 4496017..7c07b2d 100644 --- a/test_read_stdin.sl +++ b/test_read_stdin.sl @@ -7,7 +7,7 @@ import stdlib/io.sl dup 0 > if write_buf 0 exit - then + end "read_stdin failed" puts exit ; diff --git a/test_write_file.sl b/test_write_file.sl index fa3db19..de74b64 100644 --- a/test_write_file.sl +++ b/test_write_file.sl @@ -10,8 +10,8 @@ import stdlib/io.sl puti cr 0 exit - then + end "write failed errno=" puts puti cr exit -; \ No newline at end of file +; diff --git a/tests/run_tests.py b/tests/run_tests.py index 452ddbb..d70befe 100644 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -59,7 +59,7 @@ import {ROOT / 'stdlib/io.sl'} 0 5 for 1 + - next + end puti cr 5 5 == puti cr 5 4 == puti cr diff --git a/while_test.sl b/while_test.sl index fd7df04..bdf4051 100644 --- a/while_test.sl +++ b/while_test.sl @@ -8,6 +8,6 @@ import stdlib/io.sl do dup puti cr 1 - - repeat + end drop ;