// Copyright 2011 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <cmath>

#include "src/base/logging.h"
#include "src/common/globals.h"
#include "src/logging/counters.h"
#include "src/numbers/conversions-inl.h"
#include "src/numbers/conversions.h"
#include "src/parsing/parser-base.h"
#include "src/parsing/preparse-data.h"
#include "src/parsing/preparser.h"
#include "src/strings/unicode.h"
#include "src/utils/allocation.h"
#include "src/utils/utils.h"
#include "src/zone/zone-list-inl.h"

namespace v8 {
namespace internal {

namespace {

PreParserIdentifier GetIdentifierHelper(Scanner* scanner,
                                        const AstRawString* string,
                                        AstValueFactory* avf) {
  // These symbols require slightly different treatement:
  // - regular keywords (async, await, etc.; treated in 1st switch.)
  // - 'contextual' keywords (and may contain escaped; treated in 2nd switch.)
  // - 'contextual' keywords, but may not be escaped (3rd switch).
  switch (scanner->current_token()) {
    case Token::AWAIT:
      return PreParserIdentifier::Await();
    case Token::ASYNC:
      return PreParserIdentifier::Async();
    case Token::PRIVATE_NAME:
      return PreParserIdentifier::PrivateName();
    default:
      break;
  }
  if (string == avf->constructor_string()) {
    return PreParserIdentifier::Constructor();
  }
  if (string == avf->name_string()) {
    return PreParserIdentifier::Name();
  }
  if (scanner->literal_contains_escapes()) {
    return PreParserIdentifier::Default();
  }
  if (string == avf->eval_string()) {
    return PreParserIdentifier::Eval();
  }
  if (string == avf->arguments_string()) {
    return PreParserIdentifier::Arguments();
  }
  return PreParserIdentifier::Default();
}

}  // namespace

PreParserIdentifier PreParser::GetIdentifier() const {
  const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory());
  PreParserIdentifier symbol =
      GetIdentifierHelper(scanner(), result, ast_value_factory());
  DCHECK_NOT_NULL(result);
  symbol.string_ = result;
  return symbol;
}

PreParser::PreParseResult PreParser::PreParseProgram() {
  DCHECK_NULL(scope_);
  DeclarationScope* scope = NewScriptScope(REPLMode::kNo);
#ifdef DEBUG
  scope->set_is_being_lazily_parsed(true);
#endif

  // ModuleDeclarationInstantiation for Source Text Module Records creates a
  // new Module Environment Record whose outer lexical environment record is
  // the global scope.
  if (flags().is_module()) scope = NewModuleScope(scope);

  FunctionState top_scope(&function_state_, &scope_, scope);
  original_scope_ = scope_;
  int start_position = peek_position();
  PreParserScopedStatementList body(pointer_buffer());
  ParseStatementList(&body, Token::EOS);
  CheckConflictingVarDeclarations(scope);
  original_scope_ = nullptr;
  if (stack_overflow()) return kPreParseStackOverflow;
  if (is_strict(language_mode())) {
    CheckStrictOctalLiteral(start_position, scanner()->location().end_pos);
  }
  return kPreParseSuccess;
}

void PreParserFormalParameters::ValidateDuplicate(PreParser* preparser) const {
  if (has_duplicate_) preparser->ReportUnidentifiableError();
}

void PreParserFormalParameters::ValidateStrictMode(PreParser* preparser) const {
  if (strict_parameter_error_) preparser->ReportUnidentifiableError();
}

PreParser::PreParseResult PreParser::PreParseFunction(
    const AstRawString* function_name, FunctionKind kind,
    FunctionSyntaxKind function_syntax_kind, DeclarationScope* function_scope,
    int* use_counts, ProducedPreparseData** produced_preparse_data) {
  DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
  use_counts_ = use_counts;
#ifdef DEBUG
  function_scope->set_is_being_lazily_parsed(true);
#endif

  PreParserFormalParameters formals(function_scope);

  // In the preparser, we use the function literal ids to count how many
  // FunctionLiterals were encountered. The PreParser doesn't actually persist
  // FunctionLiterals, so there IDs don't matter.
  ResetFunctionLiteralId();

  // The caller passes the function_scope which is not yet inserted into the
  // scope stack. All scopes above the function_scope are ignored by the
  // PreParser.
  DCHECK_NULL(function_state_);
  DCHECK_NULL(scope_);
  FunctionState function_state(&function_state_, &scope_, function_scope);

  // Start collecting data for a new function which might contain skippable
  // functions.
  PreparseDataBuilder::DataGatheringScope preparse_data_builder_scope(this);

  if (IsArrowFunction(kind)) {
    formals.is_simple = function_scope->has_simple_parameters();
  } else {
    preparse_data_builder_scope.Start(function_scope);

    // Parse non-arrow function parameters. For arrow functions, the parameters
    // have already been parsed.
    ParameterDeclarationParsingScope formals_scope(this);
    // We return kPreParseSuccess in failure cases too - errors are retrieved
    // separately by Parser::SkipLazyFunctionBody.
    ParseFormalParameterList(&formals);
    if (formals_scope.has_duplicate()) formals.set_has_duplicate();
    if (!formals.is_simple) {
      BuildParameterInitializationBlock(formals);
    }

    Expect(Token::RPAREN);
    int formals_end_position = scanner()->location().end_pos;

    CheckArityRestrictions(formals.arity, kind, formals.has_rest,
                           function_scope->start_position(),
                           formals_end_position);
  }

  Expect(Token::LBRACE);
  DeclarationScope* inner_scope = function_scope;

  if (!formals.is_simple) {
    inner_scope = NewVarblockScope();
    inner_scope->set_start_position(position());
  }

  {
    BlockState block_state(&scope_, inner_scope);
    ParseStatementListAndLogFunction(&formals);
  }

  bool allow_duplicate_parameters = false;
  CheckConflictingVarDeclarations(inner_scope);

  if (!has_error()) {
    if (formals.is_simple) {
      if (is_sloppy(function_scope->language_mode())) {
        function_scope->HoistSloppyBlockFunctions(nullptr);
      }

      allow_duplicate_parameters =
          is_sloppy(function_scope->language_mode()) && !IsConciseMethod(kind);
    } else {
      if (is_sloppy(inner_scope->language_mode())) {
        inner_scope->HoistSloppyBlockFunctions(nullptr);
      }

      SetLanguageMode(function_scope, inner_scope->language_mode());
      inner_scope->set_end_position(scanner()->peek_location().end_pos);
      if (inner_scope->FinalizeBlockScope() != nullptr) {
        const AstRawString* conflict = inner_scope->FindVariableDeclaredIn(
            function_scope, VariableMode::kLastLexicalVariableMode);
        if (conflict != nullptr)
          ReportVarRedeclarationIn(conflict, inner_scope);
      }
    }
  }

  use_counts_ = nullptr;

  if (stack_overflow()) {
    return kPreParseStackOverflow;
  } else if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
    return kPreParseNotIdentifiableError;
  } else if (has_error()) {
    DCHECK(pending_error_handler()->has_pending_error());
  } else {
    DCHECK_EQ(Token::RBRACE, scanner()->peek());

    if (!IsArrowFunction(kind)) {
      // Validate parameter names. We can do this only after parsing the
      // function, since the function can declare itself strict.
      ValidateFormalParameters(language_mode(), formals,
                               allow_duplicate_parameters);
      if (has_error()) {
        if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
          return kPreParseNotIdentifiableError;
        } else {
          return kPreParseSuccess;
        }
      }

      // Declare arguments after parsing the function since lexical
      // 'arguments' masks the arguments object. Declare arguments before
      // declaring the function var since the arguments object masks 'function
      // arguments'.
      function_scope->DeclareArguments(ast_value_factory());

      DeclareFunctionNameVar(function_name, function_syntax_kind,
                             function_scope);

      if (preparse_data_builder_->HasData()) {
        *produced_preparse_data =
            ProducedPreparseData::For(preparse_data_builder_, main_zone());
      }
    }

    if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
      return kPreParseNotIdentifiableError;
    }

    if (is_strict(function_scope->language_mode())) {
      int end_pos = scanner()->location().end_pos;
      CheckStrictOctalLiteral(function_scope->start_position(), end_pos);
    }
  }

  DCHECK(!pending_error_handler()->has_error_unidentifiable_by_preparser());
  return kPreParseSuccess;
}

// Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster.
// See preparser-data.h for the data.

// The PreParser checks that the syntax follows the grammar for JavaScript,
// and collects some information about the program along the way.
// The grammar check is only performed in order to understand the program
// sufficiently to deduce some information about it, that can be used
// to speed up later parsing. Finding errors is not the goal of pre-parsing,
// rather it is to speed up properly written and correct programs.
// That means that contextual checks (like a label being declared where
// it is used) are generally omitted.

PreParser::Expression PreParser::ParseFunctionLiteral(
    Identifier function_name, Scanner::Location function_name_location,
    FunctionNameValidity function_name_validity, FunctionKind kind,
    int function_token_pos, FunctionSyntaxKind function_syntax_kind,
    LanguageMode language_mode,
    ZonePtrList<const AstRawString>* arguments_for_wrapped_function) {
  FunctionParsingScope function_parsing_scope(this);
  // Wrapped functions are not parsed in the preparser.
  DCHECK_NULL(arguments_for_wrapped_function);
  DCHECK_NE(FunctionSyntaxKind::kWrapped, function_syntax_kind);
  // Function ::
  //   '(' FormalParameterList? ')' '{' FunctionBody '}'
  RuntimeCallTimerScope runtime_timer(
      runtime_call_stats_,
      RuntimeCallCounterId::kPreParseWithVariableResolution,
      RuntimeCallStats::kThreadSpecific);

  base::ElapsedTimer timer;
  if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start();

  DeclarationScope* function_scope = NewFunctionScope(kind);
  function_scope->SetLanguageMode(language_mode);
  int func_id = GetNextFunctionLiteralId();
  bool skippable_function = false;

  // Start collecting data for a new function which might contain skippable
  // functions.
  {
    PreparseDataBuilder::DataGatheringScope preparse_data_builder_scope(this);
    skippable_function = !function_state_->next_function_is_likely_called() &&
                         preparse_data_builder_ != nullptr;
    if (skippable_function) {
      preparse_data_builder_scope.Start(function_scope);
    }

    FunctionState function_state(&function_state_, &scope_, function_scope);

    Expect(Token::LPAREN);
    int start_position = position();
    function_scope->set_start_position(start_position);
    PreParserFormalParameters formals(function_scope);
    {
      ParameterDeclarationParsingScope formals_scope(this);
      ParseFormalParameterList(&formals);
      if (formals_scope.has_duplicate()) formals.set_has_duplicate();
    }
    Expect(Token::RPAREN);
    int formals_end_position = scanner()->location().end_pos;

    CheckArityRestrictions(formals.arity, kind, formals.has_rest,
                           start_position, formals_end_position);

    Expect(Token::LBRACE);

    // Parse function body.
    PreParserScopedStatementList body(pointer_buffer());
    int pos = function_token_pos == kNoSourcePosition ? peek_position()
                                                      : function_token_pos;
    AcceptINScope scope(this, true);
    ParseFunctionBody(&body, function_name, pos, formals, kind,
                      function_syntax_kind, FunctionBodyType::kBlock);

    // Parsing the body may change the language mode in our scope.
    language_mode = function_scope->language_mode();

    // Validate name and parameter names. We can do this only after parsing the
    // function, since the function can declare itself strict.
    CheckFunctionName(language_mode, function_name, function_name_validity,
                      function_name_location);

    if (is_strict(language_mode)) {
      CheckStrictOctalLiteral(start_position, end_position());
    }
    if (skippable_function) {
      preparse_data_builder_scope.SetSkippableFunction(
          function_scope, formals.function_length,
          GetLastFunctionLiteralId() - func_id);
    }
  }

  if (V8_UNLIKELY(FLAG_log_function_events)) {
    double ms = timer.Elapsed().InMillisecondsF();
    const char* event_name = "preparse-resolution";
    // We might not always get a function name here. However, it can be easily
    // reconstructed from the script id and the byte range in the log processor.
    const char* name = "";
    size_t name_byte_length = 0;
    bool is_one_byte = true;
    const AstRawString* string = function_name.string_;
    if (string != nullptr) {
      name = reinterpret_cast<const char*>(string->raw_data());
      name_byte_length = string->byte_length();
      is_one_byte = string->is_one_byte();
    }
    logger_->FunctionEvent(
        event_name, flags().script_id(), ms, function_scope->start_position(),
        function_scope->end_position(), name, name_byte_length, is_one_byte);
  }

  return Expression::Default();
}

void PreParser::ParseStatementListAndLogFunction(
    PreParserFormalParameters* formals) {
  PreParserScopedStatementList body(pointer_buffer());
  ParseStatementList(&body, Token::RBRACE);

  // Position right after terminal '}'.
  DCHECK_IMPLIES(!has_error(), scanner()->peek() == Token::RBRACE);
  int body_end = scanner()->peek_location().end_pos;
  DCHECK_EQ(this->scope()->is_function_scope(), formals->is_simple);
  log_.LogFunction(body_end, formals->num_parameters(),
                   formals->function_length, GetLastFunctionLiteralId());
}

PreParserBlock PreParser::BuildParameterInitializationBlock(
    const PreParserFormalParameters& parameters) {
  DCHECK(!parameters.is_simple);
  DCHECK(scope()->is_function_scope());
  if (scope()->AsDeclarationScope()->sloppy_eval_can_extend_vars() &&
      preparse_data_builder_ != nullptr) {
    // We cannot replicate the Scope structure constructed by the Parser,
    // because we've lost information whether each individual parameter was
    // simple or not. Give up trying to produce data to skip inner functions.
    if (preparse_data_builder_->parent() != nullptr) {
      // Lazy parsing started before the current function; the function which
      // cannot contain skippable functions is the parent function. (Its inner
      // functions cannot either; they are implicitly bailed out.)
      preparse_data_builder_->parent()->Bailout();
    } else {
      // Lazy parsing started at the current function; it cannot contain
      // skippable functions.
      preparse_data_builder_->Bailout();
    }
  }

  return PreParserBlock::Default();
}

bool PreParser::IdentifierEquals(const PreParserIdentifier& identifier,
                                 const AstRawString* other) {
  return identifier.string_ == other;
}

}  // namespace internal
}  // namespace v8
