visitForIterLoopStmt method
Implementation
@override
Object? visitForIterLoopStmt(ForIterLoopStmt forIterLoopStmt) {
final prevScope = scope;
pushScope();
final String lineInfo = this.lineInfo(forIterLoopStmt.token);
try {
final List<String> vars = forIterLoopStmt.vars.map((e) => e.lexeme).toList(growable: false);
final List<LuaObject> exprs = [];
final int len = forIterLoopStmt.exprs.length;
for(int i = 0; i < len; i++) {
final expr = forIterLoopStmt.exprs[i];
if(i == len-1) {
final List<LuaObject> ls = switch(expr.accept(this)) {
final LuaArgPack ls => ls,
final List<Object> ls => ls.map((e) => e.toLuaRet()).toList(growable: false),
final Object o => [o.toLuaRet()],
_ => [LuaObject.nil('expr$i')],
};
exprs.addAll(ls);
} else {
exprs.add(expr.accept(this)?.unpack() ?? LuaObject.nil('expr$i'));
}
}
// Read only the first 3 evaluated expression result values.
// See: https://www.lua.org/pil/7.2.html
LuaObject f = exprs.elementAt(0);
if(f.isCallable) {
f = f.readMetatable('__call')?.unpack() ?? LuaObject.nil('iter');
} else if(f.isNotFunc) {
throw '$lineInfo Expected an iterator found ${f.luaTypeInfo}.';
}
final LuaObject s = exprs.elementAtOrNull(1) ?? LuaObject.nil('state');
LuaObject v = exprs.elementAtOrNull(2) ?? LuaObject.nil('value');
for(final String v in vars) {
defLocal(LuaObject.nil(v));
}
bool loop = true;
while(loop) {
final args = callLuaFunction(f, args: [s, v]);
for(int i = 0; i < vars.length; i++) {
LuaObject vs = findVar(vars[i])!;
if(i >= args.length) {
vs.value = null;
continue;
}
vs.value = args[i];
if(i == 0) {
v = vs;
}
}
if(v.isNil) {
loop = false;
break;
}
for (Stmt stmt in forIterLoopStmt.body) {
try {
stmt.accept(this);
} on LuaBreakStmtException {
loop = false;
break;
} catch (e) {
loop = false;
addError(e.toString());
}
}
}
} catch (e) {
rethrow;
} finally {
restoreScope(prevScope);
}
return null;
}