🐐 PER deconstructing
This commit is contained in:
+22
-3
@@ -1140,6 +1140,10 @@ class PerStatement(Node):
|
||||
def __eq__(self, other):
|
||||
return type(self) == type(other) and self.data_list == other.data_list and self.variable_name == other.variable_name and self.statements == other.statements
|
||||
|
||||
@property
|
||||
def destructure(self):
|
||||
return isinstance(self.variable_name, list)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
test = repr(self.data_list)
|
||||
variable_name = repr(self.variable_name)
|
||||
@@ -1149,7 +1153,23 @@ class PerStatement(Node):
|
||||
|
||||
def print(self):
|
||||
body = "\n".join(s.print() for s in self.statements)
|
||||
return f"PER {self.variable_name.print()} IN {self.data_list.print()} FAC {{\n{body}\n}}"
|
||||
if self.destructure:
|
||||
var_str = ", ".join(v.print() for v in self.variable_name)
|
||||
else:
|
||||
var_str = self.variable_name.print()
|
||||
return f"PER {var_str} IN {self.data_list.print()} FAC {{\n{body}\n}}"
|
||||
|
||||
def _assign_loop_var(self, vtable, item):
|
||||
if self.destructure:
|
||||
if not isinstance(item, ValList):
|
||||
raise CentvrionError("Cannot destructure non-array value in PER loop")
|
||||
if len(item.value()) != len(self.variable_name):
|
||||
raise CentvrionError(
|
||||
f"Destructuring mismatch: {len(self.variable_name)} targets, {len(item.value())} values")
|
||||
for id_node, val in zip(self.variable_name, item.value()):
|
||||
vtable[id_node.name] = val
|
||||
else:
|
||||
vtable[self.variable_name.name] = item
|
||||
|
||||
def _eval(self, vtable):
|
||||
vtable, array = self.data_list.eval(vtable)
|
||||
@@ -1158,10 +1178,9 @@ class PerStatement(Node):
|
||||
array = ValList(keys)
|
||||
if not isinstance(array, ValList):
|
||||
raise CentvrionError("PER requires an array or dict")
|
||||
variable_name = self.variable_name.name
|
||||
last_val = ValNul()
|
||||
for item in array:
|
||||
vtable[variable_name] = item
|
||||
self._assign_loop_var(vtable, item)
|
||||
for statement in self.statements:
|
||||
vtable, val = statement.eval(vtable)
|
||||
if vtable["#break"] or vtable["#continue"] or vtable["#return"] is not None:
|
||||
|
||||
@@ -65,23 +65,44 @@ def emit_stmt(node, ctx):
|
||||
if isinstance(node, PerStatement):
|
||||
arr_lines, arr_var = emit_expr(node.data_list, ctx)
|
||||
i_var = ctx.fresh_tmp()
|
||||
var_name = node.variable_name.name
|
||||
body_lines = _emit_body(node.statements, ctx)
|
||||
lines = arr_lines + [
|
||||
f"if ({arr_var}.type == CENT_DICT) {{",
|
||||
f" for (int {i_var} = 0; {i_var} < {arr_var}.dval.len; {i_var}++) {{",
|
||||
f' cent_scope_set(&_scope, "{var_name}", {arr_var}.dval.keys[{i_var}]);',
|
||||
]
|
||||
lines += [f" {l}" for l in body_lines]
|
||||
lines += [
|
||||
" }",
|
||||
"} else {",
|
||||
f' if ({arr_var}.type != CENT_LIST) cent_type_error("PER requires an array or dict");',
|
||||
f" for (int {i_var} = 0; {i_var} < {arr_var}.lval.len; {i_var}++) {{",
|
||||
f' cent_scope_set(&_scope, "{var_name}", {arr_var}.lval.items[{i_var}]);',
|
||||
]
|
||||
lines += [f" {l}" for l in body_lines]
|
||||
lines += [" }", "}"]
|
||||
|
||||
if node.destructure:
|
||||
# Destructuring PER — each element must be a list
|
||||
elem_var = ctx.fresh_tmp()
|
||||
assign_lines = [
|
||||
f"CentValue {elem_var} = {arr_var}.lval.items[{i_var}];",
|
||||
f'if ({elem_var}.type != CENT_LIST) cent_type_error("Cannot destructure non-array value in PER loop");',
|
||||
f'if ({elem_var}.lval.len != {len(node.variable_name)}) cent_runtime_error("Destructuring mismatch");',
|
||||
]
|
||||
for j, id_node in enumerate(node.variable_name):
|
||||
tmp = ctx.fresh_tmp()
|
||||
assign_lines.append(f"CentValue {tmp} = cent_list_index({elem_var}, cent_int({j + 1}));")
|
||||
assign_lines.append(f'cent_scope_set(&_scope, "{id_node.name}", {tmp});')
|
||||
lines = arr_lines + [
|
||||
f'if ({arr_var}.type != CENT_LIST) cent_type_error("PER requires an array");',
|
||||
f"for (int {i_var} = 0; {i_var} < {arr_var}.lval.len; {i_var}++) {{",
|
||||
]
|
||||
lines += [f" {l}" for l in assign_lines]
|
||||
lines += [f" {l}" for l in body_lines]
|
||||
lines += ["}"]
|
||||
else:
|
||||
var_name = node.variable_name.name
|
||||
lines = arr_lines + [
|
||||
f"if ({arr_var}.type == CENT_DICT) {{",
|
||||
f" for (int {i_var} = 0; {i_var} < {arr_var}.dval.len; {i_var}++) {{",
|
||||
f' cent_scope_set(&_scope, "{var_name}", {arr_var}.dval.keys[{i_var}]);',
|
||||
]
|
||||
lines += [f" {l}" for l in body_lines]
|
||||
lines += [
|
||||
" }",
|
||||
"} else {",
|
||||
f' if ({arr_var}.type != CENT_LIST) cent_type_error("PER requires an array or dict");',
|
||||
f" for (int {i_var} = 0; {i_var} < {arr_var}.lval.len; {i_var}++) {{",
|
||||
f' cent_scope_set(&_scope, "{var_name}", {arr_var}.lval.items[{i_var}]);',
|
||||
]
|
||||
lines += [f" {l}" for l in body_lines]
|
||||
lines += [" }", "}"]
|
||||
return lines
|
||||
|
||||
if isinstance(node, Defini):
|
||||
|
||||
@@ -242,6 +242,10 @@ class Parser():
|
||||
def aeternvm(tokens):
|
||||
return ast_nodes.DumStatement(ast_nodes.Bool(False), tokens[3])
|
||||
|
||||
@self.pg.production('per_statement : KEYWORD_PER id SYMBOL_COMMA id_list_rest KEYWORD_IN expression KEYWORD_FAC SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def per_destructure(tokens):
|
||||
return ast_nodes.PerStatement(tokens[5], [tokens[1]] + tokens[3], tokens[8])
|
||||
|
||||
@self.pg.production('per_statement : KEYWORD_PER id KEYWORD_IN expression KEYWORD_FAC SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def per(tokens):
|
||||
return ast_nodes.PerStatement(tokens[3], tokens[1], tokens[6])
|
||||
|
||||
Reference in New Issue
Block a user