added elif

This commit is contained in:
IgorCielniak
2026-01-12 19:51:52 +01:00
parent ce7944916a
commit a195e2b7cf
5 changed files with 37 additions and 5 deletions

View File

@@ -32,7 +32,7 @@ This document reflects the implementation that ships in this repository today (`
## 5. Definitions, Control Flow, and Syntax Sugar ## 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. - **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: - **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 <condition> 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 <condition> do <body> end`; the conditional block lives between `while` and `do` and re-runs every iteration. - `while <condition> do <body> 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. - `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. - `label name` / `goto name` perform local jumps within a definition.

25
main.py
View File

@@ -419,10 +419,12 @@ class Parser:
entry = self.control_stack.pop() entry = self.control_stack.pop()
if entry["type"] == "if": if entry["type"] in ("if", "elif"):
# For if without else # For if/elif without a trailing else
if "false" in entry: if "false" in entry:
self._append_op(Op(op="label", data=entry["false"])) 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": elif entry["type"] == "else":
self._append_op(Op(op="label", data=entry["end"])) self._append_op(Op(op="label", data=entry["end"]))
elif entry["type"] == "while": elif entry["type"] == "while":
@@ -777,12 +779,29 @@ class Parser:
return bool(handled) return bool(handled)
def _handle_if_control(self) -> None: 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") false_label = self._new_label("if_false")
self._append_op(Op(op="branch_zero", data=false_label)) self._append_op(Op(op="branch_zero", data=false_label))
self._push_control({"type": "if", "false": false_label}) self._push_control({"type": "if", "false": false_label})
def _handle_else_control(self) -> None: def _handle_else_control(self) -> None:
entry = self._pop_control(("if",)) entry = self._pop_control(("if", "elif"))
end_label = entry.get("end")
if end_label is None:
end_label = self._new_label("if_end") end_label = self._new_label("if_end")
self._append_op(Op(op="jump", data=end_label)) self._append_op(Op(op="jump", data=end_label))
self._append_op(Op(op="label", data=entry["false"])) self._append_op(Op(op="label", data=entry["false"]))

View File

@@ -0,0 +1 @@
second

View File

@@ -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

View File

@@ -0,0 +1 @@
python main.py tests/else_if_shorthand.sl -o /tmp/else_if_shorthand > /dev/null && /tmp/else_if_shorthand