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
|
## 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
25
main.py
@@ -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"]))
|
||||||
|
|||||||
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