🐐 Step in for loop

This commit is contained in:
2026-04-24 18:33:48 +02:00
parent dbaf01b6a3
commit f197c2c3d5
12 changed files with 167 additions and 14 deletions
+33 -6
View File
@@ -369,19 +369,28 @@ class DataArray(Node):
class DataRangeArray(Node):
def __init__(self, from_value, to_value) -> None:
def __init__(self, from_value, to_value, step=None) -> None:
self.from_value = from_value
self.to_value = to_value
self.step = step
def __eq__(self, other):
return type(self) == type(other) and self.from_value == other.from_value and self.to_value == other.to_value
return (type(self) == type(other)
and self.from_value == other.from_value
and self.to_value == other.to_value
and self.step == other.step)
def __repr__(self) -> str:
content_string = rep_join([self.from_value, self.to_value])
return f"RangeArray([{content_string}])"
parts = [self.from_value, self.to_value]
if self.step is not None:
parts.append(self.step)
return f"RangeArray([{rep_join(parts)}])"
def print(self):
return f"[{self.from_value.print()} VSQVE {self.to_value.print()}]"
base = f"[{self.from_value.print()} VSQVE {self.to_value.print()}"
if self.step is not None:
base += f" GRADV {self.step.print()}"
return base + "]"
def _eval(self, vtable):
vtable, from_val = self.from_value.eval(vtable)
@@ -390,7 +399,25 @@ class DataRangeArray(Node):
raise CentvrionError("Range bounds must be numbers")
from_int = from_val.value() or 0
to_int = to_val.value() or 0
return vtable, ValList([ValInt(i) for i in range(from_int, to_int + 1)])
if self.step is None:
return vtable, ValList([ValInt(i) for i in range(from_int, to_int + 1)])
vtable, step_val = self.step.eval(vtable)
if not isinstance(step_val, ValInt):
raise CentvrionError("Range step must be a number")
step_int = step_val.value()
if step_int == 0:
raise CentvrionError("Range step cannot be zero")
items = []
i = from_int
if step_int > 0:
while i <= to_int:
items.append(ValInt(i))
i += step_int
else:
while i >= to_int:
items.append(ValInt(i))
i += step_int
return vtable, ValList(items)
class DataDict(Node):
+15 -4
View File
@@ -166,10 +166,21 @@ def emit_expr(node, ctx):
hi_lines, hi_var = emit_expr(node.to_value, ctx)
tmp = ctx.fresh_tmp()
i_var = ctx.fresh_tmp()
cap = f"({hi_var}.ival >= {lo_var}.ival ? (int)({hi_var}.ival - {lo_var}.ival + 1) : 0)"
lines = lo_lines + hi_lines + [
f"CentValue {tmp} = cent_list_new({cap});",
f"for (long {i_var} = {lo_var}.ival; {i_var} <= {hi_var}.ival; {i_var}++) {{",
if node.step is None:
cap = f"({hi_var}.ival >= {lo_var}.ival ? (int)({hi_var}.ival - {lo_var}.ival + 1) : 0)"
lines = lo_lines + hi_lines + [
f"CentValue {tmp} = cent_list_new({cap});",
f"for (long {i_var} = {lo_var}.ival; {i_var} <= {hi_var}.ival; {i_var}++) {{",
f" cent_list_push(&{tmp}, cent_int({i_var}));",
"}",
]
return lines, tmp
step_lines, step_var = emit_expr(node.step, ctx)
lines = lo_lines + hi_lines + step_lines + [
f'if ({step_var}.type != CENT_INT) cent_type_error("Range step must be a number");',
f'if ({step_var}.ival == 0) cent_runtime_error("Range step cannot be zero");',
f"CentValue {tmp} = cent_list_new(0);",
f"for (long {i_var} = {lo_var}.ival; ({step_var}.ival > 0 ? {i_var} <= {hi_var}.ival : {i_var} >= {hi_var}.ival); {i_var} += {step_var}.ival) {{",
f" cent_list_push(&{tmp}, cent_int({i_var}));",
"}",
]
+1
View File
@@ -21,6 +21,7 @@ keyword_tokens = [("KEYWORD_"+i, i) for i in [
"FAC",
"FALSITAS",
"FVNCTIO",
"GRADV",
"HAVD_MINVS",
"HAVD_PLVS",
"INVOCA",
+9
View File
@@ -276,6 +276,11 @@ class Parser():
range_array = ast_nodes.DataRangeArray(tokens[3], tokens[5])
return ast_nodes.PerStatement(range_array, tokens[1], tokens[8])
@self.pg.production('donicum_statement : KEYWORD_DONICVM id KEYWORD_VT expression KEYWORD_VSQVE expression KEYWORD_GRADV expression KEYWORD_FAC SYMBOL_LCURL statements SYMBOL_RCURL')
def donicum_step(tokens):
range_array = ast_nodes.DataRangeArray(tokens[3], tokens[5], tokens[7])
return ast_nodes.PerStatement(range_array, tokens[1], tokens[10])
# expressions
@self.pg.production('expressions : SYMBOL_LPARENS expression_list')
def expressions(tokens):
@@ -394,6 +399,10 @@ class Parser():
def range_array(tokens):
return ast_nodes.DataRangeArray(tokens[1], tokens[3])
@self.pg.production('expression : SYMBOL_LBRACKET expression KEYWORD_VSQVE expression KEYWORD_GRADV expression SYMBOL_RBRACKET')
def range_array_step(tokens):
return ast_nodes.DataRangeArray(tokens[1], tokens[3], tokens[5])
@self.pg.production('expression : expression SYMBOL_LBRACKET expression SYMBOL_RBRACKET', precedence='INDEX')
def array_index(tokens):
return ast_nodes.ArrayIndex(tokens[0], tokens[2])