forLoopStmt method
Implementation
Stmt forLoopStmt() {
final token = consume(TokenType.kFor, 'Expected "for" keyword.');
// Look-ahead to determine for-loop type.
final next = peek(offset: 1);
if (next.type == TokenType.kComma) {
// This is an iterator for-loop.
final key = consume(TokenType.kRaw, 'Expected name for key term.');
consume(TokenType.kComma, 'Expected "," between key and value terms.');
final value = consume(TokenType.kRaw, 'Expected name for value term.');
consume(TokenType.kIn, 'Expected "in" before for-in loop iterator.');
final iterExpr = math();
consume(TokenType.kDo, 'Expected "do" before for-in loop body.');
final body = bodyStmt(terminal: TokenType.kEnd);
consume(
TokenType.kEnd,
'Expected "end" keyword to terminate for-in loop.',
);
return ForIterLoopStmt(
token,
key: key,
value: value,
iterExpr: iterExpr,
body: body,
);
} else if (next.type == TokenType.kAssign) {
// This is a ranged for-loop.
final control = assignExpr();
consume(TokenType.kComma, 'Expected "," before for-loop end term.');
final endExpr = math();
final MathExpr stepExpr;
final pk = peek();
if (pk.type == TokenType.kDo) {
// This is a ranged for-loop with implied step of 1.
stepExpr = NumberLiteral(
Token(TokenType.kNumber, "1", pk.pos),
value: 1.0,
);
} else {
consume(TokenType.kComma, 'Expected "," before for-loop step term.');
stepExpr = math();
}
consume(TokenType.kDo, 'Expected "do" before for-loop body.');
final body = bodyStmt(terminal: TokenType.kEnd);
consume(TokenType.kEnd, 'Expected for-loop to terminate with "end".');
return ForLoopStmt(
token,
control: control,
endExpr: endExpr,
stepExpr: stepExpr,
body: body,
);
} else {
// There is a problem.
throw '${next.pos} Unexpected $next in for-loop statement.';
}
}