added elif
This commit is contained in:
2
SPEC.md
2
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 <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.
|
||||
- `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.
|
||||
|
||||
27
main.py
27
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})
|
||||
|
||||
1
tests/else_if_shorthand.expected
Normal file
1
tests/else_if_shorthand.expected
Normal file
@@ -0,0 +1 @@
|
||||
second
|
||||
11
tests/else_if_shorthand.sl
Normal file
11
tests/else_if_shorthand.sl
Normal 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
|
||||
1
tests/else_if_shorthand.test
Normal file
1
tests/else_if_shorthand.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/else_if_shorthand.sl -o /tmp/else_if_shorthand > /dev/null && /tmp/else_if_shorthand
|
||||
Reference in New Issue
Block a user