From a195e2b7cfb88cac7a0c6b48353ec4e1054f2004 Mon Sep 17 00:00:00 2001 From: IgorCielniak Date: Mon, 12 Jan 2026 19:51:52 +0100 Subject: [PATCH] added elif --- SPEC.md | 2 +- main.py | 27 +++++++++++++++++++++++---- tests/else_if_shorthand.expected | 1 + tests/else_if_shorthand.sl | 11 +++++++++++ tests/else_if_shorthand.test | 1 + 5 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 tests/else_if_shorthand.expected create mode 100644 tests/else_if_shorthand.sl create mode 100644 tests/else_if_shorthand.test diff --git a/SPEC.md b/SPEC.md index a211158..78ac540 100644 --- a/SPEC.md +++ b/SPEC.md @@ -32,7 +32,7 @@ This document reflects the implementation that ships in this repository today (` ## 5. Definitions, Control Flow, and Syntax Sugar - **Word definitions** – Always `word name ... end`. Redefinitions overwrite the previous entry (a warning prints to stderr). `inline word name ... end` marks the definition for inline expansion; recursive inline calls are rejected. `immediate` and `compile-only` apply to the most recently defined word. - **Control forms** – Built-in tokens drive code emission: - - `if ... end` and `if ... else ... end` (conditions consume the flag on top of the stack). + - `if ... end` and `if ... else ... end`. To express additional branches, place `if` on the same line as the preceding `else` (e.g., `else if ...`); the reader treats that form as an implicit chained clause, so each inline `if` consumes one flag and jumps past later clauses on success. - `while do end`; the conditional block lives between `while` and `do` and re-runs every iteration. - `n for ... end`; the loop count is popped, stored on the return stack, and decremented each pass. The compile-time word `i` exposes the loop index inside macros. - `label name` / `goto name` perform local jumps within a definition. diff --git a/main.py b/main.py index 9c663bf..8559872 100644 --- a/main.py +++ b/main.py @@ -419,10 +419,12 @@ class Parser: entry = self.control_stack.pop() - if entry["type"] == "if": - # For if without else + if entry["type"] in ("if", "elif"): + # For if/elif without a trailing else if "false" in entry: self._append_op(Op(op="label", data=entry["false"])) + if "end" in entry: + self._append_op(Op(op="label", data=entry["end"])) elif entry["type"] == "else": self._append_op(Op(op="label", data=entry["end"])) elif entry["type"] == "while": @@ -777,13 +779,30 @@ class Parser: return bool(handled) def _handle_if_control(self) -> None: + token = self._last_token + if ( + self.control_stack + and self.control_stack[-1]["type"] == "else" + and token is not None + and self.control_stack[-1].get("line") == token.line + ): + entry = self.control_stack.pop() + end_label = entry.get("end") + if end_label is None: + end_label = self._new_label("if_end") + false_label = self._new_label("if_false") + self._append_op(Op(op="branch_zero", data=false_label)) + self._push_control({"type": "elif", "false": false_label, "end": end_label}) + return false_label = self._new_label("if_false") 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") + entry = self._pop_control(("if", "elif")) + end_label = entry.get("end") + if end_label is None: + end_label = self._new_label("if_end") 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}) diff --git a/tests/else_if_shorthand.expected b/tests/else_if_shorthand.expected new file mode 100644 index 0000000..e019be0 --- /dev/null +++ b/tests/else_if_shorthand.expected @@ -0,0 +1 @@ +second diff --git a/tests/else_if_shorthand.sl b/tests/else_if_shorthand.sl new file mode 100644 index 0000000..a770303 --- /dev/null +++ b/tests/else_if_shorthand.sl @@ -0,0 +1,11 @@ +import stdlib/stdlib.sl + +word main + 10 1 < if + "first" puts + else 1 2 < if + "second" puts + else + "third" puts + end +end diff --git a/tests/else_if_shorthand.test b/tests/else_if_shorthand.test new file mode 100644 index 0000000..9e78b4f --- /dev/null +++ b/tests/else_if_shorthand.test @@ -0,0 +1 @@ +python main.py tests/else_if_shorthand.sl -o /tmp/else_if_shorthand > /dev/null && /tmp/else_if_shorthand