Il preprocessore del motore JavaScript V8 di Chrome

Il preprocessore del motore JavaScript V8 di Chrome

La fase di preprocessamento del motore V8 di Chrome viene gestita dalla classe PreParser. Uno dei file principali di questo componente si trova nella directory /v8/src/ del codice sorgente di Chromium ed è chiamato preparser.cc. Questa classe ha il compito di riconoscere e separare i token di input che saranno gestiti successivamente dal processore JavaScript. Per esempio un compito del preprocessore JavaScript è quello di riconoscere le asserzioni JavaScript. V8 lo fa nel modo seguente:


PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
                                                         bool* ok) {
  // SourceElements ::
  //   (Statement)* <end_token>

  while (peek() != end_token) {
    ParseStatement(CHECK_OK);
  }
  return kUnknownSourceElements;
}

Il metodo PreParser::ParseStatement(), che esegue il preprocessamento delle asserzioni JavaScript, viene definito come segue:


PreParser::Statement PreParser::ParseStatement(bool* ok) {
  // Statement ::
  //   Block
  //   VariableStatement
  //   EmptyStatement
  //   ExpressionStatement
  //   IfStatement
  //   IterationStatement
  //   ContinueStatement
  //   BreakStatement
  //   ReturnStatement
  //   WithStatement
  //   LabelledStatement
  //   SwitchStatement
  //   ThrowStatement
  //   TryStatement
  //   DebuggerStatement

  // Note: Since labels can only be used by 'break' and 'continue'
  // statements, which themselves are only valid within blocks,
  // iterations or 'switch' statements (i.e., BreakableStatements),
  // labels can be simply ignored in all other cases; except for
  // trivial labeled break statements 'label: break label' which is
  // parsed into an empty statement.

  // Keep the source position of the statement
  switch (peek()) {
    case i::Token::LBRACE:
      return ParseBlock(ok);

    case i::Token::CONST:
    case i::Token::VAR:
      return ParseVariableStatement(ok);

    case i::Token::SEMICOLON:
      Next();
      return kUnknownStatement;

    case i::Token::IF:
      return  ParseIfStatement(ok);

    case i::Token::DO:
      return ParseDoWhileStatement(ok);

    case i::Token::WHILE:
      return ParseWhileStatement(ok);

    case i::Token::FOR:
      return ParseForStatement(ok);

    case i::Token::CONTINUE:
      return ParseContinueStatement(ok);

    case i::Token::BREAK:
      return ParseBreakStatement(ok);

    case i::Token::RETURN:
      return ParseReturnStatement(ok);

    case i::Token::WITH:
      return ParseWithStatement(ok);

    case i::Token::SWITCH:
      return ParseSwitchStatement(ok);

    case i::Token::THROW:
      return ParseThrowStatement(ok);

    case i::Token::TRY:
      return ParseTryStatement(ok);

    case i::Token::FUNCTION:
      return ParseFunctionDeclaration(ok);

    case i::Token::NATIVE:
      return ParseNativeDeclaration(ok);

    case i::Token::DEBUGGER:
      return ParseDebuggerStatement(ok);

    default:
      return ParseExpressionOrLabelledStatement(ok);
  }
}

Come si può notare, questo metodo esegue una verifica sequenziale usando un costrutto switch. Per ciascun valore, che corrisponde ad un differente token di input, viene chiamato un metodo corrispondente per ogni token a seconda del tipo di asserzione JavaScript incontrato. Si noti come il costrutto switch utilizzi un'istruzione return per ciascun blocco case cosicchè l'istruzione break non è necessaria.

Torna su