slight fixes to cte

This commit is contained in:
IgorCielniak
2026-02-04 08:52:14 +01:00
parent ac4c55cb8e
commit 1652692176

158
main.py
View File

@@ -1454,95 +1454,99 @@ class CompileTimeVM:
label_positions = self._label_positions(nodes) label_positions = self._label_positions(nodes)
loop_pairs = self._for_pairs(nodes) loop_pairs = self._for_pairs(nodes)
begin_pairs = self._begin_pairs(nodes) begin_pairs = self._begin_pairs(nodes)
prev_loop_stack = self.loop_stack
self.loop_stack = [] self.loop_stack = []
begin_stack: List[Dict[str, int]] = [] begin_stack: List[Dict[str, int]] = []
ip = 0 ip = 0
while ip < len(nodes): try:
node = nodes[ip] while ip < len(nodes):
kind = node.op node = nodes[ip]
data = node.data kind = node.op
data = node.data
if kind == "literal": if kind == "literal":
self.push(data) self.push(data)
ip += 1
continue
if kind == "word":
name = str(data)
if name == "begin":
end_idx = begin_pairs.get(ip)
if end_idx is None:
raise ParseError("'begin' without matching 'again'")
begin_stack.append({"begin": ip, "end": end_idx})
ip += 1 ip += 1
continue continue
if name == "again":
if not begin_stack or begin_stack[-1]["end"] != ip: if kind == "word":
raise ParseError("'again' without matching 'begin'") name = str(data)
ip = begin_stack[-1]["begin"] + 1 if name == "begin":
continue end_idx = begin_pairs.get(ip)
if name == "continue": if end_idx is None:
if not begin_stack: raise ParseError("'begin' without matching 'again'")
raise ParseError("'continue' outside begin/again loop") begin_stack.append({"begin": ip, "end": end_idx})
ip = begin_stack[-1]["begin"] + 1 ip += 1
continue
if name == "exit":
if begin_stack:
frame = begin_stack.pop()
ip = frame["end"] + 1
continue continue
return if name == "again":
self._call_word_by_name(name) if not begin_stack or begin_stack[-1]["end"] != ip:
ip += 1 raise ParseError("'again' without matching 'begin'")
continue ip = begin_stack[-1]["begin"] + 1
continue
if kind == "branch_zero": if name == "continue":
condition = self.pop() if not begin_stack:
if isinstance(condition, bool): raise ParseError("'continue' outside begin/again loop")
flag = condition ip = begin_stack[-1]["begin"] + 1
elif isinstance(condition, int): continue
flag = condition != 0 if name == "exit":
else: if begin_stack:
raise ParseError("branch expects integer or boolean condition") frame = begin_stack.pop()
if not flag: ip = frame["end"] + 1
ip = self._jump_to_label(label_positions, str(data)) continue
else: return
self._call_word_by_name(name)
ip += 1 ip += 1
continue
if kind == "jump":
ip = self._jump_to_label(label_positions, str(data))
continue
if kind == "label":
ip += 1
continue
if kind == "for_begin":
count = self.pop_int()
if count <= 0:
match = loop_pairs.get(ip)
if match is None:
raise ParseError("internal loop bookkeeping error")
ip = match + 1
continue continue
self.loop_stack.append({"remaining": count, "begin": ip, "initial": count})
ip += 1
continue
if kind == "for_end": if kind == "branch_zero":
if not self.loop_stack: condition = self.pop()
raise ParseError("'next' without matching 'for'") if isinstance(condition, bool):
frame = self.loop_stack[-1] flag = condition
frame["remaining"] -= 1 elif isinstance(condition, int):
if frame["remaining"] > 0: flag = condition != 0
ip = frame["begin"] + 1 else:
raise ParseError("branch expects integer or boolean condition")
if not flag:
ip = self._jump_to_label(label_positions, str(data))
else:
ip += 1
continue continue
self.loop_stack.pop()
ip += 1
continue
raise ParseError(f"unsupported compile-time op {node!r}") if kind == "jump":
ip = self._jump_to_label(label_positions, str(data))
continue
if kind == "label":
ip += 1
continue
if kind == "for_begin":
count = self.pop_int()
if count <= 0:
match = loop_pairs.get(ip)
if match is None:
raise ParseError("internal loop bookkeeping error")
ip = match + 1
continue
self.loop_stack.append({"remaining": count, "begin": ip, "initial": count})
ip += 1
continue
if kind == "for_end":
if not self.loop_stack:
raise ParseError("'next' without matching 'for'")
frame = self.loop_stack[-1]
frame["remaining"] -= 1
if frame["remaining"] > 0:
ip = frame["begin"] + 1
continue
self.loop_stack.pop()
ip += 1
continue
raise ParseError(f"unsupported compile-time op {node!r}")
finally:
self.loop_stack = prev_loop_stack
def _label_positions(self, nodes: Sequence[Op]) -> Dict[str, int]: def _label_positions(self, nodes: Sequence[Op]) -> Dict[str, int]:
positions: Dict[str, int] = {} positions: Dict[str, int] = {}