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
21 namespace v8 {
22 namespace 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
41 namespace {
42
GetSymbolHelper(Scanner * scanner)43 PreParserIdentifier 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
GetSymbol() const76 PreParserIdentifier 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
PreParseFunction(FunctionKind kind,DeclarationScope * function_scope,bool parsing_module,bool is_inner_function,bool may_abort,int * use_counts)86 PreParser::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
ParseFunctionLiteral(Identifier function_name,Scanner::Location function_name_location,FunctionNameValidity function_name_validity,FunctionKind kind,int function_token_pos,FunctionLiteral::FunctionType function_type,LanguageMode language_mode,bool * ok)180 PreParser::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
ParseStatementListAndLogFunction(PreParserFormalParameters * formals,bool has_duplicate_parameters,bool may_abort,bool * ok)244 PreParser::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
ExpressionFromIdentifier(PreParserIdentifier name,int start_position,InferName infer)263 PreParserExpression 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
DeclareAndInitializeVariables(PreParserStatement block,const DeclarationDescriptor * declaration_descriptor,const DeclarationParsingResult::Declaration * declaration,ZoneList<const AstRawString * > * names,bool * ok)277 void 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