1// Copyright 2011 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <cmath>
6
7#include "src/allocation.h"
8#include "src/base/logging.h"
9#include "src/conversions-inl.h"
10#include "src/conversions.h"
11#include "src/globals.h"
12#include "src/list.h"
13#include "src/parsing/duplicate-finder.h"
14#include "src/parsing/parser-base.h"
15#include "src/parsing/preparse-data-format.h"
16#include "src/parsing/preparse-data.h"
17#include "src/parsing/preparser.h"
18#include "src/unicode.h"
19#include "src/utils.h"
20
21namespace v8 {
22namespace internal {
23
24// ----------------------------------------------------------------------------
25// The CHECK_OK macro is a convenient macro to enforce error
26// handling for functions that may fail (by returning !*ok).
27//
28// CAUTION: This macro appends extra statements after a call,
29// thus it must never be used where only a single statement
30// is correct (e.g. an if statement branch w/o braces)!
31
32#define CHECK_OK_VALUE(x) ok); \
33  if (!*ok) return x;          \
34  ((void)0
35#define DUMMY )  // to make indentation work
36#undef DUMMY
37
38#define CHECK_OK CHECK_OK_VALUE(Expression::Default())
39#define CHECK_OK_VOID CHECK_OK_VALUE(this->Void())
40
41namespace {
42
43PreParserIdentifier GetSymbolHelper(Scanner* scanner) {
44  switch (scanner->current_token()) {
45    case Token::ENUM:
46      return PreParserIdentifier::Enum();
47    case Token::AWAIT:
48      return PreParserIdentifier::Await();
49    case Token::FUTURE_STRICT_RESERVED_WORD:
50      return PreParserIdentifier::FutureStrictReserved();
51    case Token::LET:
52      return PreParserIdentifier::Let();
53    case Token::STATIC:
54      return PreParserIdentifier::Static();
55    case Token::YIELD:
56      return PreParserIdentifier::Yield();
57    case Token::ASYNC:
58      return PreParserIdentifier::Async();
59    default:
60      if (scanner->UnescapedLiteralMatches("eval", 4))
61        return PreParserIdentifier::Eval();
62      if (scanner->UnescapedLiteralMatches("arguments", 9))
63        return PreParserIdentifier::Arguments();
64      if (scanner->UnescapedLiteralMatches("undefined", 9))
65        return PreParserIdentifier::Undefined();
66      if (scanner->LiteralMatches("prototype", 9))
67        return PreParserIdentifier::Prototype();
68      if (scanner->LiteralMatches("constructor", 11))
69        return PreParserIdentifier::Constructor();
70      return PreParserIdentifier::Default();
71  }
72}
73
74}  // unnamed namespace
75
76PreParserIdentifier PreParser::GetSymbol() const {
77  PreParserIdentifier symbol = GetSymbolHelper(scanner());
78  if (track_unresolved_variables_) {
79    const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory());
80    DCHECK_NOT_NULL(result);
81    symbol.string_ = result;
82  }
83  return symbol;
84}
85
86PreParser::PreParseResult PreParser::PreParseFunction(
87    FunctionKind kind, DeclarationScope* function_scope, bool parsing_module,
88    bool is_inner_function, bool may_abort, int* use_counts) {
89  RuntimeCallTimerScope runtime_timer(
90      runtime_call_stats_,
91      track_unresolved_variables_
92          ? &RuntimeCallStats::PreParseWithVariableResolution
93          : &RuntimeCallStats::PreParseNoVariableResolution);
94  DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
95  parsing_module_ = parsing_module;
96  use_counts_ = use_counts;
97  DCHECK(!track_unresolved_variables_);
98  track_unresolved_variables_ = is_inner_function;
99
100  // The caller passes the function_scope which is not yet inserted into the
101  // scope_state_. All scopes above the function_scope are ignored by the
102  // PreParser.
103  DCHECK_NULL(scope_state_);
104  FunctionState function_state(&function_state_, &scope_state_, function_scope);
105  // This indirection is needed so that we can use the CHECK_OK macros.
106  bool ok_holder = true;
107  bool* ok = &ok_holder;
108
109  PreParserFormalParameters formals(function_scope);
110  bool has_duplicate_parameters = false;
111  DuplicateFinder duplicate_finder(scanner()->unicode_cache());
112  std::unique_ptr<ExpressionClassifier> formals_classifier;
113
114  // Parse non-arrow function parameters. For arrow functions, the parameters
115  // have already been parsed.
116  if (!IsArrowFunction(kind)) {
117    formals_classifier.reset(new ExpressionClassifier(this, &duplicate_finder));
118    // We return kPreParseSuccess in failure cases too - errors are retrieved
119    // separately by Parser::SkipLazyFunctionBody.
120    ParseFormalParameterList(&formals, CHECK_OK_VALUE(kPreParseSuccess));
121    Expect(Token::RPAREN, CHECK_OK_VALUE(kPreParseSuccess));
122    int formals_end_position = scanner()->location().end_pos;
123
124    CheckArityRestrictions(
125        formals.arity, kind, formals.has_rest, function_scope->start_position(),
126        formals_end_position, CHECK_OK_VALUE(kPreParseSuccess));
127    has_duplicate_parameters =
128        !classifier()->is_valid_formal_parameter_list_without_duplicates();
129  }
130
131  Expect(Token::LBRACE, CHECK_OK_VALUE(kPreParseSuccess));
132  LazyParsingResult result = ParseStatementListAndLogFunction(
133      &formals, has_duplicate_parameters, may_abort, ok);
134  use_counts_ = nullptr;
135  track_unresolved_variables_ = false;
136  if (result == kLazyParsingAborted) {
137    return kPreParseAbort;
138  } else if (stack_overflow()) {
139    return kPreParseStackOverflow;
140  } else if (!*ok) {
141    DCHECK(pending_error_handler_->has_pending_error());
142  } else {
143    DCHECK_EQ(Token::RBRACE, scanner()->peek());
144
145    if (!IsArrowFunction(kind)) {
146      // Validate parameter names. We can do this only after parsing the
147      // function, since the function can declare itself strict.
148      const bool allow_duplicate_parameters =
149          is_sloppy(function_scope->language_mode()) && formals.is_simple &&
150          !IsConciseMethod(kind);
151      ValidateFormalParameters(function_scope->language_mode(),
152                               allow_duplicate_parameters,
153                               CHECK_OK_VALUE(kPreParseSuccess));
154    }
155
156    if (is_strict(function_scope->language_mode())) {
157      int end_pos = scanner()->location().end_pos;
158      CheckStrictOctalLiteral(function_scope->start_position(), end_pos, ok);
159      CheckDecimalLiteralWithLeadingZero(function_scope->start_position(),
160                                         end_pos);
161    }
162  }
163  return kPreParseSuccess;
164}
165
166
167// Preparsing checks a JavaScript program and emits preparse-data that helps
168// a later parsing to be faster.
169// See preparser-data.h for the data.
170
171// The PreParser checks that the syntax follows the grammar for JavaScript,
172// and collects some information about the program along the way.
173// The grammar check is only performed in order to understand the program
174// sufficiently to deduce some information about it, that can be used
175// to speed up later parsing. Finding errors is not the goal of pre-parsing,
176// rather it is to speed up properly written and correct programs.
177// That means that contextual checks (like a label being declared where
178// it is used) are generally omitted.
179
180PreParser::Expression PreParser::ParseFunctionLiteral(
181    Identifier function_name, Scanner::Location function_name_location,
182    FunctionNameValidity function_name_validity, FunctionKind kind,
183    int function_token_pos, FunctionLiteral::FunctionType function_type,
184    LanguageMode language_mode, bool* ok) {
185  // Function ::
186  //   '(' FormalParameterList? ')' '{' FunctionBody '}'
187  RuntimeCallTimerScope runtime_timer(
188      runtime_call_stats_,
189      track_unresolved_variables_
190          ? &RuntimeCallStats::PreParseWithVariableResolution
191          : &RuntimeCallStats::PreParseNoVariableResolution);
192
193  // Parse function body.
194  PreParserStatementList body;
195  DeclarationScope* function_scope = NewFunctionScope(kind);
196  function_scope->SetLanguageMode(language_mode);
197  FunctionState function_state(&function_state_, &scope_state_, function_scope);
198  DuplicateFinder duplicate_finder(scanner()->unicode_cache());
199  ExpressionClassifier formals_classifier(this, &duplicate_finder);
200
201  Expect(Token::LPAREN, CHECK_OK);
202  int start_position = scanner()->location().beg_pos;
203  function_scope->set_start_position(start_position);
204  PreParserFormalParameters formals(function_scope);
205  ParseFormalParameterList(&formals, CHECK_OK);
206  Expect(Token::RPAREN, CHECK_OK);
207  int formals_end_position = scanner()->location().end_pos;
208
209  CheckArityRestrictions(formals.arity, kind, formals.has_rest, start_position,
210                         formals_end_position, CHECK_OK);
211
212  Expect(Token::LBRACE, CHECK_OK);
213  ParseStatementList(body, Token::RBRACE, CHECK_OK);
214  Expect(Token::RBRACE, CHECK_OK);
215
216  // Parsing the body may change the language mode in our scope.
217  language_mode = function_scope->language_mode();
218
219  // Validate name and parameter names. We can do this only after parsing the
220  // function, since the function can declare itself strict.
221  CheckFunctionName(language_mode, function_name, function_name_validity,
222                    function_name_location, CHECK_OK);
223  const bool allow_duplicate_parameters =
224      is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind);
225  ValidateFormalParameters(language_mode, allow_duplicate_parameters, CHECK_OK);
226
227  int end_position = scanner()->location().end_pos;
228  if (is_strict(language_mode)) {
229    CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
230    CheckDecimalLiteralWithLeadingZero(start_position, end_position);
231  }
232  function_scope->set_end_position(end_position);
233
234  if (FLAG_trace_preparse) {
235    PrintF("  [%s]: %i-%i\n",
236           track_unresolved_variables_ ? "Preparse resolution"
237                                       : "Preparse no-resolution",
238           function_scope->start_position(), function_scope->end_position());
239  }
240
241  return Expression::Default();
242}
243
244PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction(
245    PreParserFormalParameters* formals, bool has_duplicate_parameters,
246    bool may_abort, bool* ok) {
247  PreParserStatementList body;
248  LazyParsingResult result = ParseStatementList(
249      body, Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete));
250  if (result == kLazyParsingAborted) return result;
251
252  // Position right after terminal '}'.
253  DCHECK_EQ(Token::RBRACE, scanner()->peek());
254  int body_end = scanner()->peek_location().end_pos;
255  DCHECK(this->scope()->is_function_scope());
256  log_.LogFunction(body_end, formals->num_parameters(),
257                   formals->function_length, has_duplicate_parameters,
258                   function_state_->materialized_literal_count(),
259                   function_state_->expected_property_count());
260  return kLazyParsingComplete;
261}
262
263PreParserExpression PreParser::ExpressionFromIdentifier(
264    PreParserIdentifier name, int start_position, InferName infer) {
265  if (track_unresolved_variables_) {
266    AstNodeFactory factory(ast_value_factory());
267    // Setting the Zone is necessary because zone_ might be the temp Zone, and
268    // AstValueFactory doesn't know about it.
269    factory.set_zone(zone());
270    DCHECK_NOT_NULL(name.string_);
271    scope()->NewUnresolved(&factory, name.string_, start_position,
272                           NORMAL_VARIABLE);
273  }
274  return PreParserExpression::FromIdentifier(name, zone());
275}
276
277void PreParser::DeclareAndInitializeVariables(
278    PreParserStatement block,
279    const DeclarationDescriptor* declaration_descriptor,
280    const DeclarationParsingResult::Declaration* declaration,
281    ZoneList<const AstRawString*>* names, bool* ok) {
282  if (declaration->pattern.identifiers_ != nullptr) {
283    DCHECK(FLAG_lazy_inner_functions);
284    /* Mimic what Parser does when declaring variables (see
285       Parser::PatternRewriter::VisitVariableProxy).
286
287       var + no initializer -> RemoveUnresolved
288       let / const + no initializer -> RemoveUnresolved
289       var + initializer -> RemoveUnresolved followed by NewUnresolved
290       let / const + initializer -> RemoveUnresolved
291    */
292
293    if (declaration->initializer.IsEmpty() ||
294        (declaration_descriptor->mode == VariableMode::LET ||
295         declaration_descriptor->mode == VariableMode::CONST)) {
296      for (auto identifier : *(declaration->pattern.identifiers_)) {
297        declaration_descriptor->scope->RemoveUnresolved(identifier);
298      }
299    }
300  }
301}
302
303#undef CHECK_OK
304#undef CHECK_OK_CUSTOM
305
306
307}  // namespace internal
308}  // namespace v8
309