Add for to the interpreter:
if (streq(word, "for")) {
if (cur() == '(') { pos += 1; skip(); }
const start_val: i64 = expression();
if (cur() == '.') { pos += 1; }
if (cur() == '.') { pos += 1; }
skip();
const end_val: i64 = expression();
if (cur() == ')') { pos += 1; skip(); }
if (cur() == '|') { pos += 1; skip(); }
const loop_var: []const u8 = read_name();
if (cur() == '|') { pos += 1; skip(); }
const body_pos: usize = pos;
var i: i64 = start_val;
while (i < end_val) {
pos = body_pos;
setVar(loop_var, i);
_ = exec_block();
if (return_flag or break_flag) { break; }
i += 1;
}
if (break_flag) { break_flag = false; }
if (pos <= body_pos) { pos = body_pos; skip_block(); }
return 0;
}
The two dots are parsed as two separate . characters. The |name| capture is the pipe characters with a variable name between them. Inside the loop, name is set as a local variable for each iteration.