slight fixes to cte
This commit is contained in:
158
main.py
158
main.py
@@ -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] = {}
|
||||||
|
|||||||
Reference in New Issue
Block a user