forLoopStmt method

Stmt forLoopStmt()

Implementation

Stmt forLoopStmt() {
  final token = consume(TokenType.kFor, 'Expected "for" keyword.');
  loopDepth++;

  // Look-ahead to determine for-loop type.
  final next = peek(offset: 1);
  if (next.type != TokenType.kAssign) {
    // This is an iterator for-loop.
    final key = consume(TokenType.kRaw, 'Expected name for key term.');

    Token? value;
    if (peek().type == TokenType.kComma) {
      consume(TokenType.kComma, 'Expected "," between key and value terms.');
      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);
    loopDepth--;
    consume(
      TokenType.kEnd,
      'Expected "end" keyword to terminate for-in loop.',
    );
    return ForIterLoopStmt(
      token,
      key: key,
      value: value,
      iterExpr: iterExpr,
      body: body,
    );
  }

  /* else next.type == TokenType.kAssign*/

  // This is a ranged for-loop.
  final control = assignStmt(
    RawExpr(
      consume(TokenType.kRaw, 'Expected a variable name in assignment.'),
    ),
  );
  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);
  loopDepth--;

  consume(TokenType.kEnd, 'Expected for-loop to terminate with "end".');

  return ForLoopStmt(
    token,
    control: control,
    endExpr: endExpr,
    stepExpr: stepExpr,
    body: body,
  );
}