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