src/vm/oba_compiler.c
static void nextToken(Compiler* compiler) {
  compiler->parser->previous = compiler->parser->current;

  if (compiler->parser->current.type == TOK_EOF) return;

#define IF_MATCH_NEXT(next, matched, unmatched)                                \
  do {                                                                         \
    if (matchChar(compiler, next))                                             \
      makeToken(compiler, matched);                                            \
    else                                                                       \
      makeToken(compiler, unmatched);                                          \
  } while (0)

  while (peekChar(compiler) != '\0') {
    compiler->parser->tokenStart = compiler->parser->currentChar;
    char c = nextChar(compiler);
    switch (c) {
    case ' ':
    case '\r':
    case '\t':
      break;
    case '\n':
      makeToken(compiler, TOK_NEWLINE);
      return;
    case ',':
      makeToken(compiler, TOK_COMMA);
      return;
    case ';':
      makeToken(compiler, TOK_SEMICOLON);
      return;
    case '|':
      makeToken(compiler, TOK_GUARD);
      return;
    case '(':
      if (compiler->parser->interpolation > 0) {
        compiler->parser->interpolation++;
      }
      makeToken(compiler, TOK_LPAREN);
      return;
    case ')': {
      if (compiler->parser->interpolation > 0 &&
          --compiler->parser->interpolation == 0) {
        // This is the end of an interpolated expression.
        readString(compiler);
        return;
      }
      makeToken(compiler, TOK_RPAREN);
      return;
    }
    case '{':
      makeToken(compiler, TOK_LBRACK);
      return;
    case '}':
      makeToken(compiler, TOK_RBRACK);
      return;
    case '+':
      makeToken(compiler, TOK_PLUS);
      return;
    case '-':
      makeToken(compiler, TOK_MINUS);
      return;
    case '*':
      makeToken(compiler, TOK_MULTIPLY);
      return;
    case '!':
      IF_MATCH_NEXT('=', TOK_NEQ, TOK_NOT);
      return;
    case '>':
      IF_MATCH_NEXT('=', TOK_GTE, TOK_GT);
      return;
    case '<':
      IF_MATCH_NEXT('=', TOK_LTE, TOK_LT);
      return;
    case '=':
      IF_MATCH_NEXT('=', TOK_EQ, TOK_ASSIGN);
      return;
    case '/':
      if (matchChar(compiler, '/')) {
        skipLineComment(compiler);
        break;
      }
      makeToken(compiler, TOK_DIVIDE);
      return;
    case '%':
      makeToken(compiler, TOK_MODULO);
      return;
    case '"':
      readString(compiler);
      return;
    case ':':
      if (matchChar(compiler, ':')) {
        makeToken(compiler, TOK_MEMBER);
        return;
      }
      // Fallthrough to error handler.
    default:
      if (isName(c)) {
        readName(compiler);
        return;
      }
      if (isNumber(c)) {
        readNumber(compiler);
        return;
      }
      lexError(compiler, "Invalid character '%c'.", c);
      compiler->parser->current.type = TOK_ERROR;
      compiler->parser->current.length = 0;
      return;
    }
  }

#undef IF_MATCH_NEXT

  // No more source left.
  compiler->parser->tokenStart = compiler->parser->currentChar;
  makeToken(compiler, TOK_EOF);
}
// Lexes the next token and stores it in [parser.current].
Lexes the next token and stores it in [parser.current].
Lexes the next token and stores it in [ parser . current ] .
static void nextToken(Compiler* compiler) {
  compiler->parser->previous = compiler->parser->current;
  if (compiler->parser->current.type == TOK_EOF) return;
#define IF_MATCH_NEXT(next, matched, unmatched)                                \
  do {                                                                         \
    if (matchChar(compiler, next))                                             \
      makeToken(compiler, matched);                                            \
    else                                                                       \
      makeToken(compiler, unmatched);                                          \
  } while (0)
  while (peekChar(compiler) != '\0') {
    compiler->parser->tokenStart = compiler->parser->currentChar;
    char c = nextChar(compiler);
    switch (c) {
    case ' ':
    case '\r':
    case '\t':
      break;
    case '\n':
      makeToken(compiler, TOK_NEWLINE);
      return;
    case ',':
      makeToken(compiler, TOK_COMMA);
      return;
    case ';':
      makeToken(compiler, TOK_SEMICOLON);
      return;
    case '|':
      makeToken(compiler, TOK_GUARD);
      return;
    case '(':
      if (compiler->parser->interpolation > 0) {
        compiler->parser->interpolation++;
      }
      makeToken(compiler, TOK_LPAREN);
      return;
    case ')': {
      if (compiler->parser->interpolation > 0 &&
          --compiler->parser->interpolation == 0) {
        readString(compiler);
        return;
      }
      makeToken(compiler, TOK_RPAREN);
      return;
    }
    case '{':
      makeToken(compiler, TOK_LBRACK);
      return;
    case '}':
      makeToken(compiler, TOK_RBRACK);
      return;
    case '+':
      makeToken(compiler, TOK_PLUS);
      return;
    case '-':
      makeToken(compiler, TOK_MINUS);
      return;
    case '*':
      makeToken(compiler, TOK_MULTIPLY);
      return;
    case '!':
      IF_MATCH_NEXT('=', TOK_NEQ, TOK_NOT);
      return;
    case '>':
      IF_MATCH_NEXT('=', TOK_GTE, TOK_GT);
      return;
    case '<':
      IF_MATCH_NEXT('=', TOK_LTE, TOK_LT);
      return;
    case '=':
      IF_MATCH_NEXT('=', TOK_EQ, TOK_ASSIGN);
      return;
    case '/':
      if (matchChar(compiler, '/')) {
        skipLineComment(compiler);
        break;
      }
      makeToken(compiler, TOK_DIVIDE);
      return;
    case '%':
      makeToken(compiler, TOK_MODULO);
      return;
    case '"':
      readString(compiler);
      return;
    case ':':
      if (matchChar(compiler, ':')) {
        makeToken(compiler, TOK_MEMBER);
        return;
      }
    default:
      if (isName(c)) {
        readName(compiler);
        return;
      }
      if (isNumber(c)) {
        readNumber(compiler);
        return;
      }
      lexError(compiler, "Invalid character '%c'.", c);
      compiler->parser->current.type = TOK_ERROR;
      compiler->parser->current.length = 0;
      return;
    }
  }
#undef IF_MATCH_NEXT
  compiler->parser->tokenStart = compiler->parser->currentChar;
  makeToken(compiler, TOK_EOF);
}
static void nextToken ( Compiler * compiler ) { compiler -> parser -> previous = compiler -> parser -> current ; if ( compiler -> parser -> current . type == TOK_EOF ) return ; #define IF_MATCH_NEXT ( next , matched , unmatched )                                 \
  do {                                                                         \
    if (matchChar(compiler, next))                                             \
      makeToken(compiler, matched);                                            \
    else                                                                       \
      makeToken(compiler, unmatched);                                          \
  } while (0) while ( peekChar ( compiler ) != ' \0 ' ) { compiler -> parser -> tokenStart = compiler -> parser -> currentChar ; char c = nextChar ( compiler ) ; switch ( c ) { case ' ' : case ' \r ' : case ' \t ' : break ; case ' \n ' : makeToken ( compiler , TOK_NEWLINE ) ; return ; case ' ' : makeToken ( compiler , TOK_COMMA ) ; return ; case ' ' : makeToken ( compiler , TOK_SEMICOLON ) ; return ; case ' ' : makeToken ( compiler , TOK_GUARD ) ; return ; case ' ' : if ( compiler -> parser -> interpolation > 0 ) { compiler -> parser -> interpolation ++ ; } makeToken ( compiler , TOK_LPAREN ) ; return ; case ' ' : { if ( compiler -> parser -> interpolation > 0 && -- compiler -> parser -> interpolation == 0 ) { readString ( compiler ) ; return ; } makeToken ( compiler , TOK_RPAREN ) ; return ; } case ' ' : makeToken ( compiler , TOK_LBRACK ) ; return ; case ' ' : makeToken ( compiler , TOK_RBRACK ) ; return ; case ' ' : makeToken ( compiler , TOK_PLUS ) ; return ; case ' ' : makeToken ( compiler , TOK_MINUS ) ; return ; case ' ' : makeToken ( compiler , TOK_MULTIPLY ) ; return ; case ' ' : IF_MATCH_NEXT ( ' ' , TOK_NEQ , TOK_NOT ) ; return ; case ' ' : IF_MATCH_NEXT ( ' ' , TOK_GTE , TOK_GT ) ; return ; case ' ' : IF_MATCH_NEXT ( ' ' , TOK_LTE , TOK_LT ) ; return ; case ' ' : IF_MATCH_NEXT ( ' ' , TOK_EQ , TOK_ASSIGN ) ; return ; case ' ' : if ( matchChar ( compiler , ' ' ) ) { skipLineComment ( compiler ) ; break ; } makeToken ( compiler , TOK_DIVIDE ) ; return ; case ' ' : makeToken ( compiler , TOK_MODULO ) ; return ; case ' ' : readString ( compiler ) ; return ; case ' ' : if ( matchChar ( compiler , ' ' ) ) { makeToken ( compiler , TOK_MEMBER ) ; return ; } default : if ( isName ( c ) ) { readName ( compiler ) ; return ; } if ( isNumber ( c ) ) { readNumber ( compiler ) ; return ; } lexError ( compiler , " " , c ) ; compiler -> parser -> current . type = TOK_ERROR ; compiler -> parser -> current . length = 0 ; return ; } } #undef  IF_MATCH_NEXT compiler -> parser -> tokenStart = compiler -> parser -> currentChar ; makeToken ( compiler , TOK_EOF ) ; }
Lexes the next token and stores it in [parser.current].
Lexes the next token and stores it in [ parser . current ] .
// This is the end of an interpolated expression. // Fallthrough to error handler. // No more source left.