blob: ca8cbb9029c5b0f6f930453efcf6ac0827152aad [file] [log] [blame]
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
danno@chromium.orgc612e022011-11-10 11:38:15 +000031#include "ast.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "bootstrapper.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000033#include "char-predicates-inl.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000034#include "codegen.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000035#include "compiler.h"
ricow@chromium.org65fae842010-08-25 15:26:24 +000036#include "func-name-inferrer.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000037#include "messages.h"
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +000038#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include "platform.h"
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000040#include "preparser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "runtime.h"
ricow@chromium.org55ee8072011-09-08 16:33:10 +000042#include "scanner-character-streams.h"
ager@chromium.orgb5737492010-07-15 09:29:43 +000043#include "scopeinfo.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000044#include "string-stream.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
kasperl@chromium.org71affb52009-05-26 05:44:31 +000046namespace v8 {
47namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000049// PositionStack is used for on-stack allocation of token positions for
50// new expressions. Please look at ParseNewExpression.
51
52class PositionStack {
53 public:
54 explicit PositionStack(bool* ok) : top_(NULL), ok_(ok) {}
55 ~PositionStack() { ASSERT(!*ok_ || is_empty()); }
56
57 class Element {
58 public:
59 Element(PositionStack* stack, int value) {
60 previous_ = stack->top();
61 value_ = value;
62 stack->set_top(this);
63 }
64
65 private:
66 Element* previous() { return previous_; }
67 int value() { return value_; }
68 friend class PositionStack;
69 Element* previous_;
70 int value_;
71 };
72
73 bool is_empty() { return top_ == NULL; }
74 int pop() {
75 ASSERT(!is_empty());
76 int result = top_->value();
77 top_ = top_->previous();
78 return result;
79 }
80
81 private:
82 Element* top() { return top_; }
83 void set_top(Element* value) { top_ = value; }
84 Element* top_;
85 bool* ok_;
86};
87
88
ager@chromium.orga74f0da2008-12-03 16:05:52 +000089RegExpBuilder::RegExpBuilder()
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000090 : zone_(Isolate::Current()->zone()),
91 pending_empty_(false),
92 characters_(NULL),
93 terms_(),
94 alternatives_()
ager@chromium.orga74f0da2008-12-03 16:05:52 +000095#ifdef DEBUG
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000096 , last_added_(ADD_NONE)
ager@chromium.orga74f0da2008-12-03 16:05:52 +000097#endif
98 {}
99
100
101void RegExpBuilder::FlushCharacters() {
102 pending_empty_ = false;
103 if (characters_ != NULL) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000104 RegExpTree* atom = new(zone()) RegExpAtom(characters_->ToConstVector());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000105 characters_ = NULL;
106 text_.Add(atom);
107 LAST(ADD_ATOM);
108 }
109}
110
111
112void RegExpBuilder::FlushText() {
113 FlushCharacters();
114 int num_text = text_.length();
115 if (num_text == 0) {
116 return;
117 } else if (num_text == 1) {
118 terms_.Add(text_.last());
119 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000120 RegExpText* text = new(zone()) RegExpText();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000121 for (int i = 0; i < num_text; i++)
122 text_.Get(i)->AppendToText(text);
123 terms_.Add(text);
124 }
125 text_.Clear();
126}
127
128
129void RegExpBuilder::AddCharacter(uc16 c) {
130 pending_empty_ = false;
131 if (characters_ == NULL) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000132 characters_ = new(zone()) ZoneList<uc16>(4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000133 }
134 characters_->Add(c);
135 LAST(ADD_CHAR);
136}
137
138
139void RegExpBuilder::AddEmpty() {
140 pending_empty_ = true;
141}
142
143
144void RegExpBuilder::AddAtom(RegExpTree* term) {
145 if (term->IsEmpty()) {
146 AddEmpty();
147 return;
148 }
149 if (term->IsTextElement()) {
150 FlushCharacters();
151 text_.Add(term);
152 } else {
153 FlushText();
154 terms_.Add(term);
155 }
156 LAST(ADD_ATOM);
157}
158
159
160void RegExpBuilder::AddAssertion(RegExpTree* assert) {
161 FlushText();
162 terms_.Add(assert);
163 LAST(ADD_ASSERT);
164}
165
166
167void RegExpBuilder::NewAlternative() {
168 FlushTerms();
169}
170
171
172void RegExpBuilder::FlushTerms() {
173 FlushText();
174 int num_terms = terms_.length();
175 RegExpTree* alternative;
176 if (num_terms == 0) {
177 alternative = RegExpEmpty::GetInstance();
178 } else if (num_terms == 1) {
179 alternative = terms_.last();
180 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000181 alternative = new(zone()) RegExpAlternative(terms_.GetList());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000182 }
183 alternatives_.Add(alternative);
184 terms_.Clear();
185 LAST(ADD_NONE);
186}
187
188
189RegExpTree* RegExpBuilder::ToRegExp() {
190 FlushTerms();
191 int num_alternatives = alternatives_.length();
192 if (num_alternatives == 0) {
193 return RegExpEmpty::GetInstance();
194 }
195 if (num_alternatives == 1) {
196 return alternatives_.last();
197 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000198 return new(zone()) RegExpDisjunction(alternatives_.GetList());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000199}
200
201
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000202void RegExpBuilder::AddQuantifierToAtom(int min,
203 int max,
204 RegExpQuantifier::Type type) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000205 if (pending_empty_) {
206 pending_empty_ = false;
207 return;
208 }
209 RegExpTree* atom;
210 if (characters_ != NULL) {
211 ASSERT(last_added_ == ADD_CHAR);
212 // Last atom was character.
213 Vector<const uc16> char_vector = characters_->ToConstVector();
214 int num_chars = char_vector.length();
215 if (num_chars > 1) {
216 Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000217 text_.Add(new(zone()) RegExpAtom(prefix));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000218 char_vector = char_vector.SubVector(num_chars - 1, num_chars);
219 }
220 characters_ = NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000221 atom = new(zone()) RegExpAtom(char_vector);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000222 FlushText();
223 } else if (text_.length() > 0) {
224 ASSERT(last_added_ == ADD_ATOM);
225 atom = text_.RemoveLast();
226 FlushText();
227 } else if (terms_.length() > 0) {
228 ASSERT(last_added_ == ADD_ATOM);
229 atom = terms_.RemoveLast();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000230 if (atom->max_match() == 0) {
231 // Guaranteed to only match an empty string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000232 LAST(ADD_TERM);
233 if (min == 0) {
234 return;
235 }
236 terms_.Add(atom);
237 return;
238 }
239 } else {
240 // Only call immediately after adding an atom or character!
241 UNREACHABLE();
242 return;
243 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000244 terms_.Add(new(zone()) RegExpQuantifier(min, max, type, atom));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000245 LAST(ADD_TERM);
246}
247
248
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000249Handle<String> Parser::LookupSymbol(int symbol_id) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000250 // Length of symbol cache is the number of identified symbols.
251 // If we are larger than that, or negative, it's not a cached symbol.
252 // This might also happen if there is no preparser symbol data, even
253 // if there is some preparser data.
254 if (static_cast<unsigned>(symbol_id)
255 >= static_cast<unsigned>(symbol_cache_.length())) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000256 if (scanner().is_literal_ascii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000257 return isolate()->factory()->LookupAsciiSymbol(
258 scanner().literal_ascii_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000259 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000260 return isolate()->factory()->LookupTwoByteSymbol(
261 scanner().literal_uc16_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000262 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000263 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000264 return LookupCachedSymbol(symbol_id);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000265}
266
267
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000268Handle<String> Parser::LookupCachedSymbol(int symbol_id) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000269 // Make sure the cache is large enough to hold the symbol identifier.
270 if (symbol_cache_.length() <= symbol_id) {
271 // Increase length to index + 1.
272 symbol_cache_.AddBlock(Handle<String>::null(),
273 symbol_id + 1 - symbol_cache_.length());
274 }
275 Handle<String> result = symbol_cache_.at(symbol_id);
276 if (result.is_null()) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000277 if (scanner().is_literal_ascii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000278 result = isolate()->factory()->LookupAsciiSymbol(
279 scanner().literal_ascii_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000280 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 result = isolate()->factory()->LookupTwoByteSymbol(
282 scanner().literal_uc16_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000283 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000284 symbol_cache_.at(symbol_id) = result;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000285 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000286 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000287 isolate()->counters()->total_preparse_symbols_skipped()->Increment();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000288 return result;
289}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000290
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000291
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000292FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) {
293 // The current pre-data entry must be a FunctionEntry with the given
294 // start position.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000295 if ((function_index_ + FunctionEntry::kSize <= store_.length())
296 && (static_cast<int>(store_[function_index_]) == start)) {
297 int index = function_index_;
298 function_index_ += FunctionEntry::kSize;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000299 return FunctionEntry(store_.SubVector(index,
300 index + FunctionEntry::kSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000301 }
302 return FunctionEntry();
303}
304
305
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000306int ScriptDataImpl::GetSymbolIdentifier() {
307 return ReadNumber(&symbol_data_);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000308}
309
310
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000311bool ScriptDataImpl::SanityCheck() {
312 // Check that the header data is valid and doesn't specify
313 // point to positions outside the store.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000314 if (store_.length() < PreparseDataConstants::kHeaderSize) return false;
315 if (magic() != PreparseDataConstants::kMagicNumber) return false;
316 if (version() != PreparseDataConstants::kCurrentVersion) return false;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000317 if (has_error()) {
318 // Extra sane sanity check for error message encoding.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000319 if (store_.length() <= PreparseDataConstants::kHeaderSize
320 + PreparseDataConstants::kMessageTextPos) {
321 return false;
322 }
323 if (Read(PreparseDataConstants::kMessageStartPos) >
324 Read(PreparseDataConstants::kMessageEndPos)) {
325 return false;
326 }
327 unsigned arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
328 int pos = PreparseDataConstants::kMessageTextPos;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000329 for (unsigned int i = 0; i <= arg_count; i++) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000330 if (store_.length() <= PreparseDataConstants::kHeaderSize + pos) {
331 return false;
332 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000333 int length = static_cast<int>(Read(pos));
334 if (length < 0) return false;
335 pos += 1 + length;
336 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000337 if (store_.length() < PreparseDataConstants::kHeaderSize + pos) {
338 return false;
339 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000340 return true;
341 }
342 // Check that the space allocated for function entries is sane.
343 int functions_size =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000344 static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000345 if (functions_size < 0) return false;
346 if (functions_size % FunctionEntry::kSize != 0) return false;
347 // Check that the count of symbols is non-negative.
348 int symbol_count =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000349 static_cast<int>(store_[PreparseDataConstants::kSymbolCountOffset]);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000350 if (symbol_count < 0) return false;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000351 // Check that the total size has room for header and function entries.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000352 int minimum_size =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000353 PreparseDataConstants::kHeaderSize + functions_size;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000354 if (store_.length() < minimum_size) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 return true;
356}
357
358
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000359
ricow@chromium.org65fae842010-08-25 15:26:24 +0000360const char* ScriptDataImpl::ReadString(unsigned* start, int* chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 int length = start[0];
362 char* result = NewArray<char>(length + 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000363 for (int i = 0; i < length; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 result[i] = start[i + 1];
ricow@chromium.org65fae842010-08-25 15:26:24 +0000365 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366 result[length] = '\0';
367 if (chars != NULL) *chars = length;
368 return result;
369}
370
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000371Scanner::Location ScriptDataImpl::MessageLocation() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000372 int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
373 int end_pos = Read(PreparseDataConstants::kMessageEndPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374 return Scanner::Location(beg_pos, end_pos);
375}
376
377
378const char* ScriptDataImpl::BuildMessage() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000379 unsigned* start = ReadAddress(PreparseDataConstants::kMessageTextPos);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000380 return ReadString(start, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381}
382
383
384Vector<const char*> ScriptDataImpl::BuildArgs() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000385 int arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 const char** array = NewArray<const char*>(arg_count);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000387 // Position after text found by skipping past length field and
388 // length field content words.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000389 int pos = PreparseDataConstants::kMessageTextPos + 1
390 + Read(PreparseDataConstants::kMessageTextPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 for (int i = 0; i < arg_count; i++) {
392 int count = 0;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000393 array[i] = ReadString(ReadAddress(pos), &count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 pos += count + 1;
395 }
396 return Vector<const char*>(array, arg_count);
397}
398
399
400unsigned ScriptDataImpl::Read(int position) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000401 return store_[PreparseDataConstants::kHeaderSize + position];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402}
403
404
405unsigned* ScriptDataImpl::ReadAddress(int position) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000406 return &store_[PreparseDataConstants::kHeaderSize + position];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407}
408
409
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000410Scope* Parser::NewScope(Scope* parent, ScopeType type) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000411 Scope* result = new(zone()) Scope(parent, type);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000412 result->Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 return result;
414}
415
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000416
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417// ----------------------------------------------------------------------------
418// Target is a support class to facilitate manipulation of the
419// Parser's target_stack_ (the stack of potential 'break' and
420// 'continue' statement targets). Upon construction, a new target is
421// added; it is removed upon destruction.
422
423class Target BASE_EMBEDDED {
424 public:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000425 Target(Target** variable, AstNode* node)
426 : variable_(variable), node_(node), previous_(*variable) {
427 *variable = this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 }
429
430 ~Target() {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000431 *variable_ = previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000434 Target* previous() { return previous_; }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000435 AstNode* node() { return node_; }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437 private:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000438 Target** variable_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000439 AstNode* node_;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000440 Target* previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000441};
442
443
444class TargetScope BASE_EMBEDDED {
445 public:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000446 explicit TargetScope(Target** variable)
447 : variable_(variable), previous_(*variable) {
448 *variable = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449 }
450
451 ~TargetScope() {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000452 *variable_ = previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453 }
454
455 private:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000456 Target** variable_;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000457 Target* previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000458};
459
460
461// ----------------------------------------------------------------------------
danno@chromium.orgc612e022011-11-10 11:38:15 +0000462// FunctionState and BlockState together implement the parser's scope stack.
463// The parser's current scope is in top_scope_. The BlockState and
464// FunctionState constructors push on the scope stack and the destructors
465// pop. They are also used to hold the parser's per-function and per-block
466// state.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000467
danno@chromium.orgc612e022011-11-10 11:38:15 +0000468class Parser::BlockState BASE_EMBEDDED {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000469 public:
danno@chromium.orgc612e022011-11-10 11:38:15 +0000470 BlockState(Parser* parser, Scope* scope)
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000471 : parser_(parser),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000472 outer_scope_(parser->top_scope_) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000473 parser->top_scope_ = scope;
474 }
475
danno@chromium.orgc612e022011-11-10 11:38:15 +0000476 ~BlockState() { parser_->top_scope_ = outer_scope_; }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000477
478 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000479 Parser* parser_;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000480 Scope* outer_scope_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000481};
482
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000483
danno@chromium.orgc612e022011-11-10 11:38:15 +0000484Parser::FunctionState::FunctionState(Parser* parser,
485 Scope* scope,
486 Isolate* isolate)
487 : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000488 next_handler_index_(0),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000489 expected_property_count_(0),
490 only_simple_this_property_assignments_(false),
491 this_property_assignments_(isolate->factory()->empty_fixed_array()),
492 parser_(parser),
493 outer_function_state_(parser->current_function_state_),
494 outer_scope_(parser->top_scope_),
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000495 saved_ast_node_id_(isolate->ast_node_id()),
496 factory_(isolate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000497 parser->top_scope_ = scope;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000498 parser->current_function_state_ = this;
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000499 isolate->set_ast_node_id(AstNode::kDeclarationsId + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000500}
501
502
danno@chromium.orgc612e022011-11-10 11:38:15 +0000503Parser::FunctionState::~FunctionState() {
504 parser_->top_scope_ = outer_scope_;
505 parser_->current_function_state_ = outer_function_state_;
yangguo@chromium.org56454712012-02-16 15:33:53 +0000506 if (outer_function_state_ != NULL) {
507 parser_->isolate()->set_ast_node_id(saved_ast_node_id_);
508 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509}
510
511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512// ----------------------------------------------------------------------------
513// The CHECK_OK macro is a convenient macro to enforce error
514// handling for functions that may fail (by returning !*ok).
515//
516// CAUTION: This macro appends extra statements after a call,
517// thus it must never be used where only a single statement
518// is correct (e.g. an if statement branch w/o braces)!
519
520#define CHECK_OK ok); \
521 if (!*ok) return NULL; \
522 ((void)0
523#define DUMMY ) // to make indentation work
524#undef DUMMY
525
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000526#define CHECK_FAILED /**/); \
527 if (failed_) return NULL; \
528 ((void)0
529#define DUMMY ) // to make indentation work
530#undef DUMMY
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531
532// ----------------------------------------------------------------------------
533// Implementation of Parser
534
535Parser::Parser(Handle<Script> script,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000536 int parser_flags,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537 v8::Extension* extension,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000538 ScriptDataImpl* pre_data)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 : isolate_(script->GetIsolate()),
540 symbol_cache_(pre_data ? pre_data->symbol_count() : 0),
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000541 script_(script),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000542 scanner_(isolate_->unicode_cache()),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000543 reusable_preparser_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544 top_scope_(NULL),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000545 current_function_state_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546 target_stack_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547 extension_(extension),
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000548 pre_data_(pre_data),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000549 fni_(NULL),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000550 allow_natives_syntax_((parser_flags & kAllowNativesSyntax) != 0),
551 allow_lazy_((parser_flags & kAllowLazy) != 0),
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000552 allow_modules_((parser_flags & kAllowModules) != 0),
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000553 stack_overflow_(false),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000554 parenthesized_function_(false) {
yangguo@chromium.org56454712012-02-16 15:33:53 +0000555 isolate_->set_ast_node_id(0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000556 if ((parser_flags & kLanguageModeMask) == EXTENDED_MODE) {
557 scanner().SetHarmonyScoping(true);
558 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000559 if ((parser_flags & kAllowModules) != 0) {
560 scanner().SetHarmonyModules(true);
561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000562}
563
564
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000565FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000566 ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000567
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000568 HistogramTimerScope timer(isolate()->counters()->parse());
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000569 Handle<String> source(String::cast(script_->source()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000570 isolate()->counters()->total_parse_size()->Increment(source->length());
ager@chromium.org04921a82011-06-27 13:21:41 +0000571 fni_ = new(zone()) FuncNameInferrer(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572
573 // Initialize parser state.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000574 source->TryFlatten();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000575 if (source->IsExternalTwoByteString()) {
576 // Notice that the stream is destroyed at the end of the branch block.
577 // The last line of the blocks can't be moved outside, even though they're
578 // identical calls.
579 ExternalTwoByteStringUC16CharacterStream stream(
580 Handle<ExternalTwoByteString>::cast(source), 0, source->length());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000581 scanner_.Initialize(&stream);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000582 return DoParseProgram(info, source, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000583 } else {
584 GenericStringUC16CharacterStream stream(source, 0, source->length());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000585 scanner_.Initialize(&stream);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000586 return DoParseProgram(info, source, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000587 }
588}
589
590
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000591FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
592 Handle<String> source,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000593 ZoneScope* zone_scope) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000594 ASSERT(top_scope_ == NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000595 ASSERT(target_stack_ == NULL);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000596 if (pre_data_ != NULL) pre_data_->Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597
598 // Compute the parsing mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000599 mode_ = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600 if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;
601
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 Handle<String> no_name = isolate()->factory()->empty_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603
604 FunctionLiteral* result = NULL;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000605 { Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
606 info->SetGlobalScope(scope);
yangguo@chromium.org56454712012-02-16 15:33:53 +0000607 if (!info->is_global() &&
608 (info->shared_info().is_null() || info->shared_info()->is_function())) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000609 scope = Scope::DeserializeScopeChain(*info->calling_context(), scope);
610 scope = NewScope(scope, EVAL_SCOPE);
611 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000612 scope->set_start_position(0);
613 scope->set_end_position(source->length());
danno@chromium.orgc612e022011-11-10 11:38:15 +0000614 FunctionState function_state(this, scope, isolate());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000615 top_scope_->SetLanguageMode(info->language_mode());
danno@chromium.org40cb8782011-05-25 07:58:50 +0000616 ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617 bool ok = true;
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000618 int beg_loc = scanner().location().beg_pos;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000619 ParseSourceElements(body, Token::EOS, &ok);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000620 if (ok && !top_scope_->is_classic_mode()) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000621 CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok);
622 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000623
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000624 if (ok && is_extended_mode()) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000625 CheckConflictingVarDeclarations(scope, &ok);
626 }
627
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000628 if (ok) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000629 result = factory()->NewFunctionLiteral(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000630 no_name,
631 top_scope_,
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000632 body,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000633 function_state.materialized_literal_count(),
634 function_state.expected_property_count(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000635 function_state.handler_count(),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000636 function_state.only_simple_this_property_assignments(),
637 function_state.this_property_assignments(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000638 0,
yangguo@chromium.org56454712012-02-16 15:33:53 +0000639 FunctionLiteral::kNoDuplicateParameters,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000640 FunctionLiteral::ANONYMOUS_EXPRESSION,
yangguo@chromium.org56454712012-02-16 15:33:53 +0000641 FunctionLiteral::kGlobalOrEval);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000642 result->set_ast_properties(factory()->visitor()->ast_properties());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000643 } else if (stack_overflow_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000644 isolate()->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645 }
646 }
647
648 // Make sure the target stack is empty.
649 ASSERT(target_stack_ == NULL);
650
651 // If there was a syntax error we have to get rid of the AST
652 // and it is not safe to do so before the scope has been deleted.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000653 if (result == NULL) zone_scope->DeleteOnExit();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000654 return result;
655}
656
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000657
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000658FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000659 ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000660 HistogramTimerScope timer(isolate()->counters()->parse_lazy());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000661 Handle<String> source(String::cast(script_->source()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000662 isolate()->counters()->total_parse_size()->Increment(source->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000663
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000664 Handle<SharedFunctionInfo> shared_info = info->shared_info();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000665 // Initialize parser state.
666 source->TryFlatten();
667 if (source->IsExternalTwoByteString()) {
668 ExternalTwoByteStringUC16CharacterStream stream(
669 Handle<ExternalTwoByteString>::cast(source),
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000670 shared_info->start_position(),
671 shared_info->end_position());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000672 FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
673 return result;
674 } else {
675 GenericStringUC16CharacterStream stream(source,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000676 shared_info->start_position(),
677 shared_info->end_position());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000678 FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
679 return result;
680 }
681}
682
683
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000684FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000685 UC16CharacterStream* source,
686 ZoneScope* zone_scope) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000687 Handle<SharedFunctionInfo> shared_info = info->shared_info();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000688 scanner_.Initialize(source);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000689 ASSERT(top_scope_ == NULL);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000690 ASSERT(target_stack_ == NULL);
691
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000692 Handle<String> name(String::cast(shared_info->name()));
ager@chromium.org04921a82011-06-27 13:21:41 +0000693 fni_ = new(zone()) FuncNameInferrer(isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000694 fni_->PushEnclosingName(name);
695
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 mode_ = PARSE_EAGERLY;
697
698 // Place holder for the result.
699 FunctionLiteral* result = NULL;
700
701 {
702 // Parse the function literal.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000703 Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000704 info->SetGlobalScope(scope);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000705 if (!info->closure().is_null()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000706 scope = Scope::DeserializeScopeChain(info->closure()->context(), scope);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000707 }
danno@chromium.orgc612e022011-11-10 11:38:15 +0000708 FunctionState function_state(this, scope, isolate());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000709 ASSERT(scope->language_mode() != STRICT_MODE || !info->is_classic_mode());
710 ASSERT(scope->language_mode() != EXTENDED_MODE ||
711 info->is_extended_mode());
712 ASSERT(info->language_mode() == shared_info->language_mode());
713 scope->SetLanguageMode(shared_info->language_mode());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000714 FunctionLiteral::Type type = shared_info->is_expression()
715 ? (shared_info->is_anonymous()
716 ? FunctionLiteral::ANONYMOUS_EXPRESSION
717 : FunctionLiteral::NAMED_EXPRESSION)
718 : FunctionLiteral::DECLARATION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719 bool ok = true;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000720 result = ParseFunctionLiteral(name,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000721 false, // Strict mode name already checked.
722 RelocInfo::kNoPosition,
723 type,
724 &ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000725 // Make sure the results agree.
726 ASSERT(ok == (result != NULL));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000727 }
728
729 // Make sure the target stack is empty.
730 ASSERT(target_stack_ == NULL);
731
732 // If there was a stack overflow we have to get rid of AST and it is
733 // not safe to do before scope has been deleted.
734 if (result == NULL) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000735 zone_scope->DeleteOnExit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000736 if (stack_overflow_) isolate()->StackOverflow();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000737 } else {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000738 Handle<String> inferred_name(shared_info->inferred_name());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000739 result->set_inferred_name(inferred_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000740 }
741 return result;
742}
743
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000744
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000745Handle<String> Parser::GetSymbol(bool* ok) {
746 int symbol_id = -1;
747 if (pre_data() != NULL) {
748 symbol_id = pre_data()->GetSymbolIdentifier();
749 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000750 return LookupSymbol(symbol_id);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000751}
752
753
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754void Parser::ReportMessage(const char* type, Vector<const char*> args) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000755 Scanner::Location source_location = scanner().location();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000756 ReportMessageAt(source_location, type, args);
757}
758
759
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000760void Parser::ReportMessage(const char* type, Vector<Handle<String> > args) {
761 Scanner::Location source_location = scanner().location();
762 ReportMessageAt(source_location, type, args);
763}
764
765
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000766void Parser::ReportMessageAt(Scanner::Location source_location,
767 const char* type,
768 Vector<const char*> args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769 MessageLocation location(script_,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000770 source_location.beg_pos,
771 source_location.end_pos);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000772 Factory* factory = isolate()->factory();
773 Handle<FixedArray> elements = factory->NewFixedArray(args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000774 for (int i = 0; i < args.length(); i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000775 Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000776 elements->set(i, *arg_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000778 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
779 Handle<Object> result = factory->NewSyntaxError(type, array);
780 isolate()->Throw(*result, &location);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000781}
782
783
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000784void Parser::ReportMessageAt(Scanner::Location source_location,
785 const char* type,
786 Vector<Handle<String> > args) {
787 MessageLocation location(script_,
788 source_location.beg_pos,
789 source_location.end_pos);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000790 Factory* factory = isolate()->factory();
791 Handle<FixedArray> elements = factory->NewFixedArray(args.length());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000792 for (int i = 0; i < args.length(); i++) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000793 elements->set(i, *args[i]);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000794 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000795 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
796 Handle<Object> result = factory->NewSyntaxError(type, array);
797 isolate()->Throw(*result, &location);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000798}
799
800
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000801// Base class containing common code for the different finder classes used by
802// the parser.
803class ParserFinder {
804 protected:
805 ParserFinder() {}
806 static Assignment* AsAssignment(Statement* stat) {
807 if (stat == NULL) return NULL;
808 ExpressionStatement* exp_stat = stat->AsExpressionStatement();
809 if (exp_stat == NULL) return NULL;
810 return exp_stat->expression()->AsAssignment();
811 }
812};
813
814
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000815// An InitializationBlockFinder finds and marks sequences of statements of the
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000816// form expr.a = ...; expr.b = ...; etc.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000817class InitializationBlockFinder : public ParserFinder {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000818 public:
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000819 // We find and mark the initialization blocks in top level
820 // non-looping code only. This is because the optimization prevents
821 // reuse of the map transitions, so it should be used only for code
822 // that will only be run once.
823 InitializationBlockFinder(Scope* top_scope, Target* target)
824 : enabled_(top_scope->DeclarationScope()->is_global_scope() &&
825 !IsLoopTarget(target)),
826 first_in_block_(NULL),
827 last_in_block_(NULL),
828 block_size_(0) {}
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000829
830 ~InitializationBlockFinder() {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000831 if (!enabled_) return;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000832 if (InBlock()) EndBlock();
833 }
834
835 void Update(Statement* stat) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000836 if (!enabled_) return;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000837 Assignment* assignment = AsAssignment(stat);
838 if (InBlock()) {
839 if (BlockContinues(assignment)) {
840 UpdateBlock(assignment);
841 } else {
842 EndBlock();
843 }
844 }
845 if (!InBlock() && (assignment != NULL) &&
846 (assignment->op() == Token::ASSIGN)) {
847 StartBlock(assignment);
848 }
849 }
850
851 private:
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000852 // The minimum number of contiguous assignment that will
853 // be treated as an initialization block. Benchmarks show that
854 // the overhead exceeds the savings below this limit.
855 static const int kMinInitializationBlock = 3;
856
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000857 static bool IsLoopTarget(Target* target) {
858 while (target != NULL) {
859 if (target->node()->AsIterationStatement() != NULL) return true;
860 target = target->previous();
861 }
862 return false;
863 }
864
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000865 // Returns true if the expressions appear to denote the same object.
866 // In the context of initialization blocks, we only consider expressions
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000867 // of the form 'expr.x' or expr["x"].
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000868 static bool SameObject(Expression* e1, Expression* e2) {
869 VariableProxy* v1 = e1->AsVariableProxy();
870 VariableProxy* v2 = e2->AsVariableProxy();
871 if (v1 != NULL && v2 != NULL) {
872 return v1->name()->Equals(*v2->name());
873 }
874 Property* p1 = e1->AsProperty();
875 Property* p2 = e2->AsProperty();
876 if ((p1 == NULL) || (p2 == NULL)) return false;
877 Literal* key1 = p1->key()->AsLiteral();
878 Literal* key2 = p2->key()->AsLiteral();
879 if ((key1 == NULL) || (key2 == NULL)) return false;
880 if (!key1->handle()->IsString() || !key2->handle()->IsString()) {
881 return false;
882 }
883 String* name1 = String::cast(*key1->handle());
884 String* name2 = String::cast(*key2->handle());
885 if (!name1->Equals(name2)) return false;
886 return SameObject(p1->obj(), p2->obj());
887 }
888
889 // Returns true if the expressions appear to denote different properties
890 // of the same object.
891 static bool PropertyOfSameObject(Expression* e1, Expression* e2) {
892 Property* p1 = e1->AsProperty();
893 Property* p2 = e2->AsProperty();
894 if ((p1 == NULL) || (p2 == NULL)) return false;
895 return SameObject(p1->obj(), p2->obj());
896 }
897
898 bool BlockContinues(Assignment* assignment) {
899 if ((assignment == NULL) || (first_in_block_ == NULL)) return false;
900 if (assignment->op() != Token::ASSIGN) return false;
901 return PropertyOfSameObject(first_in_block_->target(),
902 assignment->target());
903 }
904
905 void StartBlock(Assignment* assignment) {
906 first_in_block_ = assignment;
907 last_in_block_ = assignment;
908 block_size_ = 1;
909 }
910
911 void UpdateBlock(Assignment* assignment) {
912 last_in_block_ = assignment;
913 ++block_size_;
914 }
915
916 void EndBlock() {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000917 if (block_size_ >= kMinInitializationBlock) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000918 first_in_block_->mark_block_start();
919 last_in_block_->mark_block_end();
920 }
921 last_in_block_ = first_in_block_ = NULL;
922 block_size_ = 0;
923 }
924
925 bool InBlock() { return first_in_block_ != NULL; }
926
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000927 const bool enabled_;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000928 Assignment* first_in_block_;
929 Assignment* last_in_block_;
930 int block_size_;
931
932 DISALLOW_COPY_AND_ASSIGN(InitializationBlockFinder);
933};
934
935
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000936// A ThisNamedPropertyAssignmentFinder finds and marks statements of the form
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000937// this.x = ...;, where x is a named property. It also determines whether a
938// function contains only assignments of this type.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000939class ThisNamedPropertyAssignmentFinder : public ParserFinder {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000940 public:
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000941 explicit ThisNamedPropertyAssignmentFinder(Isolate* isolate)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 : isolate_(isolate),
943 only_simple_this_property_assignments_(true),
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000944 names_(0),
945 assigned_arguments_(0),
946 assigned_constants_(0) {
947 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000948
949 void Update(Scope* scope, Statement* stat) {
ager@chromium.orgb9a15452009-11-11 09:55:05 +0000950 // Bail out if function already has property assignment that are
951 // not simple this property assignments.
952 if (!only_simple_this_property_assignments_) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000953 return;
954 }
955
956 // Check whether this statement is of the form this.x = ...;
957 Assignment* assignment = AsAssignment(stat);
958 if (IsThisPropertyAssignment(assignment)) {
959 HandleThisPropertyAssignment(scope, assignment);
960 } else {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000961 only_simple_this_property_assignments_ = false;
962 }
963 }
964
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000965 // Returns whether only statements of the form this.x = y; where y is either a
966 // constant or a function argument was encountered.
967 bool only_simple_this_property_assignments() {
968 return only_simple_this_property_assignments_;
969 }
970
971 // Returns a fixed array containing three elements for each assignment of the
972 // form this.x = y;
973 Handle<FixedArray> GetThisPropertyAssignments() {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000974 if (names_.is_empty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000975 return isolate_->factory()->empty_fixed_array();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000976 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000977 ASSERT_EQ(names_.length(), assigned_arguments_.length());
978 ASSERT_EQ(names_.length(), assigned_constants_.length());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000979 Handle<FixedArray> assignments =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000980 isolate_->factory()->NewFixedArray(names_.length() * 3);
981 for (int i = 0; i < names_.length(); ++i) {
982 assignments->set(i * 3, *names_[i]);
983 assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_[i]));
984 assignments->set(i * 3 + 2, *assigned_constants_[i]);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000985 }
986 return assignments;
987 }
988
989 private:
990 bool IsThisPropertyAssignment(Assignment* assignment) {
991 if (assignment != NULL) {
992 Property* property = assignment->target()->AsProperty();
993 return assignment->op() == Token::ASSIGN
994 && property != NULL
995 && property->obj()->AsVariableProxy() != NULL
996 && property->obj()->AsVariableProxy()->is_this();
997 }
998 return false;
999 }
1000
1001 void HandleThisPropertyAssignment(Scope* scope, Assignment* assignment) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001002 // Check that the property assigned to is a named property, which is not
1003 // __proto__.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001004 Property* property = assignment->target()->AsProperty();
1005 ASSERT(property != NULL);
1006 Literal* literal = property->key()->AsLiteral();
1007 uint32_t dummy;
1008 if (literal != NULL &&
1009 literal->handle()->IsString() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001010 !String::cast(*(literal->handle()))->Equals(
1011 isolate_->heap()->Proto_symbol()) &&
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001012 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
1013 Handle<String> key = Handle<String>::cast(literal->handle());
1014
1015 // Check whether the value assigned is either a constant or matches the
1016 // name of one of the arguments to the function.
1017 if (assignment->value()->AsLiteral() != NULL) {
1018 // Constant assigned.
1019 Literal* literal = assignment->value()->AsLiteral();
1020 AssignmentFromConstant(key, literal->handle());
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001021 return;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001022 } else if (assignment->value()->AsVariableProxy() != NULL) {
1023 // Variable assigned.
1024 Handle<String> name =
1025 assignment->value()->AsVariableProxy()->name();
1026 // Check whether the variable assigned matches an argument name.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001027 for (int i = 0; i < scope->num_parameters(); i++) {
1028 if (*scope->parameter(i)->name() == *name) {
1029 // Assigned from function argument.
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001030 AssignmentFromParameter(key, i);
1031 return;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001032 }
1033 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001034 }
1035 }
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001036 // It is not a simple "this.x = value;" assignment with a constant
1037 // or parameter value.
1038 AssignmentFromSomethingElse();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001039 }
1040
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001041
1042
1043
1044 // We will potentially reorder the property assignments, so they must be
1045 // simple enough that the ordering does not matter.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001046 void AssignmentFromParameter(Handle<String> name, int index) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001047 EnsureInitialized();
1048 for (int i = 0; i < names_.length(); ++i) {
1049 if (name->Equals(*names_[i])) {
1050 assigned_arguments_[i] = index;
1051 assigned_constants_[i] = isolate_->factory()->undefined_value();
1052 return;
1053 }
1054 }
1055 names_.Add(name);
1056 assigned_arguments_.Add(index);
1057 assigned_constants_.Add(isolate_->factory()->undefined_value());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001058 }
1059
1060 void AssignmentFromConstant(Handle<String> name, Handle<Object> value) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001061 EnsureInitialized();
1062 for (int i = 0; i < names_.length(); ++i) {
1063 if (name->Equals(*names_[i])) {
1064 assigned_arguments_[i] = -1;
1065 assigned_constants_[i] = value;
1066 return;
1067 }
1068 }
1069 names_.Add(name);
1070 assigned_arguments_.Add(-1);
1071 assigned_constants_.Add(value);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001072 }
1073
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001074 void AssignmentFromSomethingElse() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001075 // The this assignment is not a simple one.
1076 only_simple_this_property_assignments_ = false;
1077 }
1078
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001079 void EnsureInitialized() {
1080 if (names_.capacity() == 0) {
1081 ASSERT(assigned_arguments_.capacity() == 0);
1082 ASSERT(assigned_constants_.capacity() == 0);
1083 names_.Initialize(4);
1084 assigned_arguments_.Initialize(4);
1085 assigned_constants_.Initialize(4);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001086 }
1087 }
1088
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 Isolate* isolate_;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001090 bool only_simple_this_property_assignments_;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001091 ZoneStringList names_;
1092 ZoneList<int> assigned_arguments_;
1093 ZoneObjectList assigned_constants_;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001094};
1095
1096
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001097void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098 int end_token,
1099 bool* ok) {
1100 // SourceElements ::
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001101 // (ModuleElement)* <end_token>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102
1103 // Allocate a target stack to use for this set of source
1104 // elements. This way, all scripts and functions get their own
1105 // target stack thus avoiding illegal breaks and continues across
1106 // functions.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001107 TargetScope scope(&this->target_stack_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001108
1109 ASSERT(processor != NULL);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001110 InitializationBlockFinder block_finder(top_scope_, target_stack_);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001111 ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001112 bool directive_prologue = true; // Parsing directive prologue.
1113
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001114 while (peek() != end_token) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001115 if (directive_prologue && peek() != Token::STRING) {
1116 directive_prologue = false;
1117 }
1118
1119 Scanner::Location token_loc = scanner().peek_location();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001120 Statement* stat = ParseModuleElement(NULL, CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001121 if (stat == NULL || stat->IsEmpty()) {
1122 directive_prologue = false; // End of directive prologue.
1123 continue;
1124 }
1125
1126 if (directive_prologue) {
1127 // A shot at a directive.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001128 ExpressionStatement* e_stat;
1129 Literal* literal;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001130 // Still processing directive prologue?
1131 if ((e_stat = stat->AsExpressionStatement()) != NULL &&
1132 (literal = e_stat->expression()->AsLiteral()) != NULL &&
1133 literal->handle()->IsString()) {
1134 Handle<String> directive = Handle<String>::cast(literal->handle());
1135
1136 // Check "use strict" directive (ES5 14.1).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001137 if (top_scope_->is_classic_mode() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001138 directive->Equals(isolate()->heap()->use_strict()) &&
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001139 token_loc.end_pos - token_loc.beg_pos ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001140 isolate()->heap()->use_strict()->length() + 2) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001141 // TODO(ES6): Fix entering extended mode, once it is specified.
1142 top_scope_->SetLanguageMode(FLAG_harmony_scoping
1143 ? EXTENDED_MODE : STRICT_MODE);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001144 // "use strict" is the only directive for now.
1145 directive_prologue = false;
1146 }
1147 } else {
1148 // End of the directive prologue.
1149 directive_prologue = false;
1150 }
1151 }
1152
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001153 block_finder.Update(stat);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001154 // Find and mark all assignments to named properties in this (this.x =)
1155 if (top_scope_->is_function_scope()) {
1156 this_property_assignment_finder.Update(top_scope_, stat);
1157 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001158 processor->Add(stat);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001159 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001160
1161 // Propagate the collected information on this property assignments.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001162 if (top_scope_->is_function_scope()) {
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001163 bool only_simple_this_property_assignments =
ager@chromium.org5c838252010-02-19 08:53:10 +00001164 this_property_assignment_finder.only_simple_this_property_assignments()
1165 && top_scope_->declarations()->length() == 0;
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001166 if (only_simple_this_property_assignments) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001167 current_function_state_->SetThisPropertyAssignmentInfo(
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001168 only_simple_this_property_assignments,
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001169 this_property_assignment_finder.GetThisPropertyAssignments());
1170 }
1171 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001172
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173 return 0;
1174}
1175
1176
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001177Statement* Parser::ParseModuleElement(ZoneStringList* labels,
1178 bool* ok) {
1179 // (Ecma 262 5th Edition, clause 14):
1180 // SourceElement:
1181 // Statement
1182 // FunctionDeclaration
1183 //
1184 // In harmony mode we allow additionally the following productions
1185 // ModuleElement:
1186 // LetDeclaration
1187 // ConstDeclaration
1188 // ModuleDeclaration
1189 // ImportDeclaration
1190 // ExportDeclaration
1191
1192 switch (peek()) {
1193 case Token::FUNCTION:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001194 return ParseFunctionDeclaration(NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001195 case Token::LET:
1196 case Token::CONST:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001197 return ParseVariableStatement(kModuleElement, NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001198 case Token::IMPORT:
1199 return ParseImportDeclaration(ok);
1200 case Token::EXPORT:
1201 return ParseExportDeclaration(ok);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00001202 default: {
1203 Statement* stmt = ParseStatement(labels, CHECK_OK);
1204 // Handle 'module' as a context-sensitive keyword.
1205 if (FLAG_harmony_modules &&
1206 peek() == Token::IDENTIFIER &&
1207 !scanner().HasAnyLineTerminatorBeforeNext() &&
1208 stmt != NULL) {
1209 ExpressionStatement* estmt = stmt->AsExpressionStatement();
1210 if (estmt != NULL &&
1211 estmt->expression()->AsVariableProxy() != NULL &&
1212 estmt->expression()->AsVariableProxy()->name()->Equals(
1213 isolate()->heap()->module_symbol()) &&
1214 !scanner().literal_contains_escapes()) {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001215 return ParseModuleDeclaration(NULL, ok);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00001216 }
1217 }
1218 return stmt;
1219 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001220 }
1221}
1222
1223
ulan@chromium.org812308e2012-02-29 15:58:45 +00001224Block* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001225 // ModuleDeclaration:
1226 // 'module' Identifier Module
1227
1228 // Create new block with one expected declaration.
1229 Block* block = factory()->NewBlock(NULL, 1, true);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001230 Handle<String> name = ParseIdentifier(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001231
1232#ifdef DEBUG
1233 if (FLAG_print_interface_details)
1234 PrintF("# Module %s...\n", name->ToAsciiArray());
1235#endif
1236
ulan@chromium.org812308e2012-02-29 15:58:45 +00001237 Module* module = ParseModule(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001238 VariableProxy* proxy = NewUnresolved(name, LET, module->interface());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001239 Declaration* declaration =
1240 factory()->NewModuleDeclaration(proxy, module, top_scope_);
1241 Declare(declaration, true, CHECK_OK);
1242
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001243#ifdef DEBUG
1244 if (FLAG_print_interface_details)
1245 PrintF("# Module %s.\n", name->ToAsciiArray());
1246
1247 if (FLAG_print_interfaces) {
1248 PrintF("module %s : ", name->ToAsciiArray());
1249 module->interface()->Print();
1250 }
1251#endif
1252
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001253 // TODO(rossberg): Add initialization statement to block.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001254
1255 if (names) names->Add(name);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001256 return block;
1257}
1258
1259
1260Module* Parser::ParseModule(bool* ok) {
1261 // Module:
1262 // '{' ModuleElement '}'
ulan@chromium.org812308e2012-02-29 15:58:45 +00001263 // '=' ModulePath ';'
1264 // 'at' String ';'
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001265
1266 switch (peek()) {
1267 case Token::LBRACE:
1268 return ParseModuleLiteral(ok);
1269
ulan@chromium.org812308e2012-02-29 15:58:45 +00001270 case Token::ASSIGN: {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001271 Expect(Token::ASSIGN, CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001272 Module* result = ParseModulePath(CHECK_OK);
1273 ExpectSemicolon(CHECK_OK);
1274 return result;
1275 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001276
ulan@chromium.org812308e2012-02-29 15:58:45 +00001277 default: {
1278 ExpectContextualKeyword("at", CHECK_OK);
1279 Module* result = ParseModuleUrl(CHECK_OK);
1280 ExpectSemicolon(CHECK_OK);
1281 return result;
1282 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001283 }
1284}
1285
1286
1287Module* Parser::ParseModuleLiteral(bool* ok) {
1288 // Module:
1289 // '{' ModuleElement '}'
1290
1291 // Construct block expecting 16 statements.
1292 Block* body = factory()->NewBlock(NULL, 16, false);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001293#ifdef DEBUG
1294 if (FLAG_print_interface_details) PrintF("# Literal ");
1295#endif
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001296 Scope* scope = NewScope(top_scope_, MODULE_SCOPE);
1297
1298 Expect(Token::LBRACE, CHECK_OK);
1299 scope->set_start_position(scanner().location().beg_pos);
1300 scope->SetLanguageMode(EXTENDED_MODE);
1301
1302 {
1303 BlockState block_state(this, scope);
1304 TargetCollector collector;
1305 Target target(&this->target_stack_, &collector);
1306 Target target_body(&this->target_stack_, body);
1307 InitializationBlockFinder block_finder(top_scope_, target_stack_);
1308
1309 while (peek() != Token::RBRACE) {
1310 Statement* stat = ParseModuleElement(NULL, CHECK_OK);
1311 if (stat && !stat->IsEmpty()) {
1312 body->AddStatement(stat);
1313 block_finder.Update(stat);
1314 }
1315 }
1316 }
1317
1318 Expect(Token::RBRACE, CHECK_OK);
1319 scope->set_end_position(scanner().location().end_pos);
1320 body->set_block_scope(scope);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001321
1322 scope->interface()->Freeze(ok);
1323 ASSERT(ok);
1324 return factory()->NewModuleLiteral(body, scope->interface());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001325}
1326
1327
1328Module* Parser::ParseModulePath(bool* ok) {
1329 // ModulePath:
1330 // Identifier
1331 // ModulePath '.' Identifier
1332
1333 Module* result = ParseModuleVariable(CHECK_OK);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001334 while (Check(Token::PERIOD)) {
1335 Handle<String> name = ParseIdentifierName(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001336#ifdef DEBUG
1337 if (FLAG_print_interface_details)
1338 PrintF("# Path .%s ", name->ToAsciiArray());
1339#endif
1340 Module* member = factory()->NewModulePath(result, name);
1341 result->interface()->Add(name, member->interface(), ok);
1342 if (!*ok) {
1343#ifdef DEBUG
1344 if (FLAG_print_interfaces) {
1345 PrintF("PATH TYPE ERROR at '%s'\n", name->ToAsciiArray());
1346 PrintF("result: ");
1347 result->interface()->Print();
1348 PrintF("member: ");
1349 member->interface()->Print();
1350 }
1351#endif
1352 ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
1353 return NULL;
1354 }
1355 result = member;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001356 }
1357
1358 return result;
1359}
1360
1361
1362Module* Parser::ParseModuleVariable(bool* ok) {
1363 // ModulePath:
1364 // Identifier
1365
1366 Handle<String> name = ParseIdentifier(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001367#ifdef DEBUG
1368 if (FLAG_print_interface_details)
1369 PrintF("# Module variable %s ", name->ToAsciiArray());
1370#endif
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001371 VariableProxy* proxy = top_scope_->NewUnresolved(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001372 factory(), name, scanner().location().beg_pos, Interface::NewModule());
1373
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001374 return factory()->NewModuleVariable(proxy);
1375}
1376
1377
1378Module* Parser::ParseModuleUrl(bool* ok) {
1379 // Module:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001380 // String
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001381
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001382 Expect(Token::STRING, CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001383 Handle<String> symbol = GetSymbol(CHECK_OK);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001384
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001385 // TODO(ES6): Request JS resource from environment...
1386
1387#ifdef DEBUG
1388 if (FLAG_print_interface_details) PrintF("# Url ");
1389#endif
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001390 return factory()->NewModuleUrl(symbol);
1391}
1392
1393
ulan@chromium.org812308e2012-02-29 15:58:45 +00001394Module* Parser::ParseModuleSpecifier(bool* ok) {
1395 // ModuleSpecifier:
1396 // String
1397 // ModulePath
1398
1399 if (peek() == Token::STRING) {
1400 return ParseModuleUrl(ok);
1401 } else {
1402 return ParseModulePath(ok);
1403 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001404}
1405
1406
ulan@chromium.org812308e2012-02-29 15:58:45 +00001407Block* Parser::ParseImportDeclaration(bool* ok) {
1408 // ImportDeclaration:
1409 // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleSpecifier ';'
1410 //
1411 // TODO(ES6): implement destructuring ImportSpecifiers
1412
1413 Expect(Token::IMPORT, CHECK_OK);
1414 ZoneStringList names(1);
1415
1416 Handle<String> name = ParseIdentifierName(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001417 names.Add(name);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001418 while (peek() == Token::COMMA) {
1419 Consume(Token::COMMA);
1420 name = ParseIdentifierName(CHECK_OK);
1421 names.Add(name);
1422 }
1423
1424 ExpectContextualKeyword("from", CHECK_OK);
1425 Module* module = ParseModuleSpecifier(CHECK_OK);
1426 ExpectSemicolon(CHECK_OK);
1427
1428 // Generate a separate declaration for each identifier.
1429 // TODO(ES6): once we implement destructuring, make that one declaration.
1430 Block* block = factory()->NewBlock(NULL, 1, true);
1431 for (int i = 0; i < names.length(); ++i) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001432#ifdef DEBUG
1433 if (FLAG_print_interface_details)
1434 PrintF("# Import %s ", names[i]->ToAsciiArray());
1435#endif
1436 Interface* interface = Interface::NewUnknown();
1437 module->interface()->Add(names[i], interface, ok);
1438 if (!*ok) {
1439#ifdef DEBUG
1440 if (FLAG_print_interfaces) {
1441 PrintF("IMPORT TYPE ERROR at '%s'\n", names[i]->ToAsciiArray());
1442 PrintF("module: ");
1443 module->interface()->Print();
1444 }
1445#endif
1446 ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
1447 return NULL;
1448 }
1449 VariableProxy* proxy = NewUnresolved(names[i], LET, interface);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001450 Declaration* declaration =
1451 factory()->NewImportDeclaration(proxy, module, top_scope_);
1452 Declare(declaration, true, CHECK_OK);
1453 // TODO(rossberg): Add initialization statement to block.
1454 }
1455
ulan@chromium.org812308e2012-02-29 15:58:45 +00001456 return block;
1457}
1458
1459
1460Statement* Parser::ParseExportDeclaration(bool* ok) {
1461 // ExportDeclaration:
1462 // 'export' Identifier (',' Identifier)* ';'
1463 // 'export' VariableDeclaration
1464 // 'export' FunctionDeclaration
1465 // 'export' ModuleDeclaration
1466 //
1467 // TODO(ES6): implement structuring ExportSpecifiers
1468
1469 Expect(Token::EXPORT, CHECK_OK);
1470
1471 Statement* result = NULL;
1472 ZoneStringList names(1);
1473 switch (peek()) {
1474 case Token::IDENTIFIER: {
1475 Handle<String> name = ParseIdentifier(CHECK_OK);
1476 // Handle 'module' as a context-sensitive keyword.
1477 if (!name->IsEqualTo(CStrVector("module"))) {
1478 names.Add(name);
1479 while (peek() == Token::COMMA) {
1480 Consume(Token::COMMA);
1481 name = ParseIdentifier(CHECK_OK);
1482 names.Add(name);
1483 }
1484 ExpectSemicolon(CHECK_OK);
1485 result = factory()->NewEmptyStatement();
1486 } else {
1487 result = ParseModuleDeclaration(&names, CHECK_OK);
1488 }
1489 break;
1490 }
1491
1492 case Token::FUNCTION:
1493 result = ParseFunctionDeclaration(&names, CHECK_OK);
1494 break;
1495
1496 case Token::VAR:
1497 case Token::LET:
1498 case Token::CONST:
1499 result = ParseVariableStatement(kModuleElement, &names, CHECK_OK);
1500 break;
1501
1502 default:
1503 *ok = false;
1504 ReportUnexpectedToken(scanner().current_token());
1505 return NULL;
1506 }
1507
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001508 // Extract declared names into export declarations and interface.
1509 Interface* interface = top_scope_->interface();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001510 for (int i = 0; i < names.length(); ++i) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001511#ifdef DEBUG
1512 if (FLAG_print_interface_details)
1513 PrintF("# Export %s ", names[i]->ToAsciiArray());
1514#endif
1515 Interface* inner = Interface::NewUnknown();
1516 interface->Add(names[i], inner, CHECK_OK);
1517 VariableProxy* proxy = NewUnresolved(names[i], LET, inner);
1518 USE(proxy);
1519 // TODO(rossberg): Rethink whether we actually need to store export
1520 // declarations (for compilation?).
1521 // ExportDeclaration* declaration =
1522 // factory()->NewExportDeclaration(proxy, top_scope_);
1523 // top_scope_->AddDeclaration(declaration);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001524 }
1525
1526 ASSERT(result != NULL);
1527 return result;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001528}
1529
1530
1531Statement* Parser::ParseBlockElement(ZoneStringList* labels,
1532 bool* ok) {
1533 // (Ecma 262 5th Edition, clause 14):
1534 // SourceElement:
1535 // Statement
1536 // FunctionDeclaration
1537 //
1538 // In harmony mode we allow additionally the following productions
1539 // BlockElement (aka SourceElement):
1540 // LetDeclaration
1541 // ConstDeclaration
1542
1543 switch (peek()) {
1544 case Token::FUNCTION:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001545 return ParseFunctionDeclaration(NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001546 case Token::LET:
1547 case Token::CONST:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001548 return ParseVariableStatement(kModuleElement, NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001549 default:
1550 return ParseStatement(labels, ok);
1551 }
1552}
1553
1554
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
1556 // Statement ::
1557 // Block
1558 // VariableStatement
1559 // EmptyStatement
1560 // ExpressionStatement
1561 // IfStatement
1562 // IterationStatement
1563 // ContinueStatement
1564 // BreakStatement
1565 // ReturnStatement
1566 // WithStatement
1567 // LabelledStatement
1568 // SwitchStatement
1569 // ThrowStatement
1570 // TryStatement
1571 // DebuggerStatement
1572
1573 // Note: Since labels can only be used by 'break' and 'continue'
1574 // statements, which themselves are only valid within blocks,
1575 // iterations or 'switch' statements (i.e., BreakableStatements),
1576 // labels can be simply ignored in all other cases; except for
ager@chromium.org32912102009-01-16 10:38:43 +00001577 // trivial labeled break statements 'label: break label' which is
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578 // parsed into an empty statement.
1579
1580 // Keep the source position of the statement
1581 int statement_pos = scanner().peek_location().beg_pos;
1582 Statement* stmt = NULL;
1583 switch (peek()) {
1584 case Token::LBRACE:
1585 return ParseBlock(labels, ok);
1586
1587 case Token::CONST: // fall through
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001588 case Token::LET:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589 case Token::VAR:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001590 stmt = ParseVariableStatement(kStatement, NULL, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 break;
1592
1593 case Token::SEMICOLON:
1594 Next();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001595 return factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001596
1597 case Token::IF:
1598 stmt = ParseIfStatement(labels, ok);
1599 break;
1600
1601 case Token::DO:
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001602 stmt = ParseDoWhileStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 break;
1604
1605 case Token::WHILE:
1606 stmt = ParseWhileStatement(labels, ok);
1607 break;
1608
1609 case Token::FOR:
1610 stmt = ParseForStatement(labels, ok);
1611 break;
1612
1613 case Token::CONTINUE:
1614 stmt = ParseContinueStatement(ok);
1615 break;
1616
1617 case Token::BREAK:
1618 stmt = ParseBreakStatement(labels, ok);
1619 break;
1620
1621 case Token::RETURN:
1622 stmt = ParseReturnStatement(ok);
1623 break;
1624
1625 case Token::WITH:
1626 stmt = ParseWithStatement(labels, ok);
1627 break;
1628
1629 case Token::SWITCH:
1630 stmt = ParseSwitchStatement(labels, ok);
1631 break;
1632
1633 case Token::THROW:
1634 stmt = ParseThrowStatement(ok);
1635 break;
1636
1637 case Token::TRY: {
1638 // NOTE: It is somewhat complicated to have labels on
1639 // try-statements. When breaking out of a try-finally statement,
1640 // one must take great care not to treat it as a
1641 // fall-through. It is much easier just to wrap the entire
1642 // try-statement in a statement block and put the labels there
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001643 Block* result = factory()->NewBlock(labels, 1, false);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001644 Target target(&this->target_stack_, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645 TryStatement* statement = ParseTryStatement(CHECK_OK);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001646 if (statement) {
1647 statement->set_statement_pos(statement_pos);
1648 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649 if (result) result->AddStatement(statement);
1650 return result;
1651 }
1652
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001653 case Token::FUNCTION: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001654 // FunctionDeclaration is only allowed in the context of SourceElements
1655 // (Ecma 262 5th Edition, clause 14):
1656 // SourceElement:
1657 // Statement
1658 // FunctionDeclaration
1659 // Common language extension is to allow function declaration in place
1660 // of any statement. This language extension is disabled in strict mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001661 if (!top_scope_->is_classic_mode()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001662 ReportMessageAt(scanner().peek_location(), "strict_function",
1663 Vector<const char*>::empty());
1664 *ok = false;
1665 return NULL;
1666 }
ulan@chromium.org812308e2012-02-29 15:58:45 +00001667 return ParseFunctionDeclaration(NULL, ok);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001668 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001670 case Token::DEBUGGER:
1671 stmt = ParseDebuggerStatement(ok);
1672 break;
1673
1674 default:
1675 stmt = ParseExpressionOrLabelledStatement(labels, ok);
1676 }
1677
1678 // Store the source position of the statement
1679 if (stmt != NULL) stmt->set_statement_pos(statement_pos);
1680 return stmt;
1681}
1682
1683
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001684VariableProxy* Parser::NewUnresolved(
1685 Handle<String> name, VariableMode mode, Interface* interface) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00001686 // If we are inside a function, a declaration of a var/const variable is a
1687 // truly local variable, and the scope of the variable is always the function
1688 // scope.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001689 // Let/const variables in harmony mode are always added to the immediately
1690 // enclosing scope.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001691 return DeclarationScope(mode)->NewUnresolved(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001692 factory(), name, scanner().location().beg_pos, interface);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001693}
1694
1695
1696void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001697 VariableProxy* proxy = declaration->proxy();
1698 Handle<String> name = proxy->name();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001699 VariableMode mode = declaration->mode();
1700 Scope* declaration_scope = DeclarationScope(mode);
1701 Variable* var = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702
1703 // If a function scope exists, then we can statically declare this
1704 // variable and also set its mode. In any case, a Declaration node
1705 // will be added to the scope so that the declaration can be added
1706 // to the corresponding activation frame at runtime if necessary.
1707 // For instance declarations inside an eval scope need to be added
1708 // to the calling function context.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001709 // Similarly, strict mode eval scope does not leak variable declarations to
1710 // the caller's scope so we declare all locals, too.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001711 // Also for block scoped let/const bindings the variable can be
1712 // statically declared.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001713 if (declaration_scope->is_function_scope() ||
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001714 declaration_scope->is_strict_or_extended_eval_scope() ||
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001715 declaration_scope->is_block_scope() ||
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001716 declaration_scope->is_module_scope() ||
1717 declaration->AsModuleDeclaration() != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001718 // Declare the variable in the function scope.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001719 var = declaration_scope->LocalLookup(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001720 if (var == NULL) {
1721 // Declare the name.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001722 var = declaration_scope->DeclareLocal(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001723 name, mode, declaration->initialization(), proxy->interface());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001724 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001725 // The name was declared in this scope before; check for conflicting
1726 // re-declarations. We have a conflict if either of the declarations is
1727 // not a var. There is similar code in runtime.cc in the Declare
1728 // functions. The function CheckNonConflictingScope checks for conflicting
1729 // var and let bindings from different scopes whereas this is a check for
1730 // conflicting declarations within the same scope. This check also covers
1731 //
1732 // function () { let x; { var x; } }
1733 //
1734 // because the var declaration is hoisted to the function scope where 'x'
1735 // is already bound.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001736 if ((mode != VAR) || (var->mode() != VAR)) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00001737 // We only have vars, consts and lets in declarations.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001738 ASSERT(var->mode() == VAR ||
1739 var->mode() == CONST ||
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001740 var->mode() == CONST_HARMONY ||
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001741 var->mode() == LET);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001742 if (is_extended_mode()) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001743 // In harmony mode we treat re-declarations as early errors. See
1744 // ES5 16 for a definition of early errors.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001745 SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001746 const char* elms[2] = { "Variable", *c_string };
1747 Vector<const char*> args(elms, 2);
1748 ReportMessage("redeclaration", args);
1749 *ok = false;
ulan@chromium.org812308e2012-02-29 15:58:45 +00001750 return;
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001751 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001752 const char* type = (var->mode() == VAR)
1753 ? "var" : var->is_const_mode() ? "const" : "let";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001754 Handle<String> type_string =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001756 Expression* expression =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001757 NewThrowTypeError(isolate()->factory()->redeclaration_symbol(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001758 type_string, name);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001759 declaration_scope->SetIllegalRedeclaration(expression);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001760 }
1761 }
1762 }
1763
1764 // We add a declaration node for every declaration. The compiler
1765 // will only generate code if necessary. In particular, declarations
1766 // for inner local variables that do not represent functions won't
1767 // result in any generated code.
1768 //
1769 // Note that we always add an unresolved proxy even if it's not
1770 // used, simply because we don't know in this method (w/o extra
1771 // parameters) if the proxy is needed or not. The proxy will be
1772 // bound during variable resolution time unless it was pre-bound
1773 // below.
1774 //
1775 // WARNING: This will lead to multiple declaration nodes for the
1776 // same variable if it is declared several times. This is not a
1777 // semantic issue as long as we keep the source order, but it may be
1778 // a performance issue since it may lead to repeated
1779 // Runtime::DeclareContextSlot() calls.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001780 declaration_scope->AddDeclaration(declaration);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001781
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001782 if ((mode == CONST || mode == CONST_HARMONY) &&
1783 declaration_scope->is_global_scope()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001784 // For global const variables we bind the proxy to a variable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001785 ASSERT(resolve); // should be set by all callers
ager@chromium.org3e875802009-06-29 08:26:34 +00001786 Variable::Kind kind = Variable::NORMAL;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001787 var = new(zone()) Variable(declaration_scope,
1788 name,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001789 mode,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001790 true,
1791 kind,
1792 kNeedsInitialization);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001793 } else if (declaration_scope->is_eval_scope() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001794 declaration_scope->is_classic_mode()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001795 // For variable declarations in a non-strict eval scope the proxy is bound
1796 // to a lookup variable to force a dynamic declaration using the
1797 // DeclareContextSlot runtime function.
1798 Variable::Kind kind = Variable::NORMAL;
1799 var = new(zone()) Variable(declaration_scope,
1800 name,
1801 mode,
1802 true,
1803 kind,
ulan@chromium.org812308e2012-02-29 15:58:45 +00001804 declaration->initialization());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001805 var->AllocateTo(Variable::LOOKUP, -1);
1806 resolve = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001807 }
1808
1809 // If requested and we have a local variable, bind the proxy to the variable
1810 // at parse-time. This is used for functions (and consts) declared inside
1811 // statements: the corresponding function (or const) variable must be in the
1812 // function scope and not a statement-local scope, e.g. as provided with a
1813 // 'with' statement:
1814 //
1815 // with (obj) {
1816 // function f() {}
1817 // }
1818 //
1819 // which is translated into:
1820 //
1821 // with (obj) {
1822 // // in this case this is not: 'var f; f = function () {};'
1823 // var f = function () {};
1824 // }
1825 //
1826 // Note that if 'f' is accessed from inside the 'with' statement, it
1827 // will be allocated in the context (because we must be able to look
1828 // it up dynamically) but it will also be accessed statically, i.e.,
1829 // with a context slot index and a context chain length for this
1830 // initialization code. Thus, inside the 'with' statement, we need
1831 // both access to the static and the dynamic context chain; the
1832 // runtime needs to provide both.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001833 if (resolve && var != NULL) {
1834 proxy->BindTo(var);
1835
1836 if (FLAG_harmony_modules) {
1837 bool ok;
1838#ifdef DEBUG
1839 if (FLAG_print_interface_details)
1840 PrintF("# Declare %s\n", var->name()->ToAsciiArray());
1841#endif
1842 proxy->interface()->Unify(var->interface(), &ok);
1843 if (!ok) {
1844#ifdef DEBUG
1845 if (FLAG_print_interfaces) {
1846 PrintF("DECLARE TYPE ERROR\n");
1847 PrintF("proxy: ");
1848 proxy->interface()->Print();
1849 PrintF("var: ");
1850 var->interface()->Print();
1851 }
1852#endif
1853 ReportMessage("module_type_error", Vector<Handle<String> >(&name, 1));
1854 }
1855 }
1856 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001857}
1858
1859
1860// Language extension which is only enabled for source files loaded
1861// through the API's extension mechanism. A native function
1862// declaration is resolved by looking up the function through a
1863// callback provided by the extension.
1864Statement* Parser::ParseNativeDeclaration(bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001865 Expect(Token::FUNCTION, CHECK_OK);
1866 Handle<String> name = ParseIdentifier(CHECK_OK);
1867 Expect(Token::LPAREN, CHECK_OK);
1868 bool done = (peek() == Token::RPAREN);
1869 while (!done) {
1870 ParseIdentifier(CHECK_OK);
1871 done = (peek() == Token::RPAREN);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001872 if (!done) {
1873 Expect(Token::COMMA, CHECK_OK);
1874 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001875 }
1876 Expect(Token::RPAREN, CHECK_OK);
1877 Expect(Token::SEMICOLON, CHECK_OK);
1878
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001879 // Make sure that the function containing the native declaration
1880 // isn't lazily compiled. The extension structures are only
1881 // accessible while parsing the first time not when reparsing
1882 // because of lazy compilation.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001883 DeclarationScope(VAR)->ForceEagerCompilation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884
1885 // Compute the function template for the native function.
1886 v8::Handle<v8::FunctionTemplate> fun_template =
1887 extension_->GetNativeFunction(v8::Utils::ToLocal(name));
1888 ASSERT(!fun_template.IsEmpty());
1889
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001890 // Instantiate the function and create a shared function info from it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001891 Handle<JSFunction> fun = Utils::OpenHandle(*fun_template->GetFunction());
1892 const int literals = fun->NumberOfLiterals();
1893 Handle<Code> code = Handle<Code>(fun->shared()->code());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001894 Handle<Code> construct_stub = Handle<Code>(fun->shared()->construct_stub());
ager@chromium.orgb5737492010-07-15 09:29:43 +00001895 Handle<SharedFunctionInfo> shared =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001896 isolate()->factory()->NewSharedFunctionInfo(name, literals, code,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001897 Handle<ScopeInfo>(fun->shared()->scope_info()));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001898 shared->set_construct_stub(*construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001899
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001900 // Copy the function data to the shared function info.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001901 shared->set_function_data(fun->shared()->function_data());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001902 int parameters = fun->shared()->formal_parameter_count();
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001903 shared->set_formal_parameter_count(parameters);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904
1905 // TODO(1240846): It's weird that native function declarations are
1906 // introduced dynamically when we meet their declarations, whereas
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001907 // other functions are set up when entering the surrounding scope.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001908 VariableProxy* proxy = NewUnresolved(name, VAR);
1909 Declaration* declaration =
1910 factory()->NewVariableDeclaration(proxy, VAR, top_scope_);
1911 Declare(declaration, true, CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001912 SharedFunctionInfoLiteral* lit =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001913 factory()->NewSharedFunctionInfoLiteral(shared);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001914 return factory()->NewExpressionStatement(
1915 factory()->NewAssignment(
ulan@chromium.org812308e2012-02-29 15:58:45 +00001916 Token::INIT_VAR, proxy, lit, RelocInfo::kNoPosition));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001917}
1918
1919
ulan@chromium.org812308e2012-02-29 15:58:45 +00001920Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001921 // FunctionDeclaration ::
1922 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001923 Expect(Token::FUNCTION, CHECK_OK);
1924 int function_token_position = scanner().location().beg_pos;
ager@chromium.org04921a82011-06-27 13:21:41 +00001925 bool is_strict_reserved = false;
1926 Handle<String> name = ParseIdentifierOrStrictReservedWord(
1927 &is_strict_reserved, CHECK_OK);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001928 FunctionLiteral* fun = ParseFunctionLiteral(name,
ager@chromium.org04921a82011-06-27 13:21:41 +00001929 is_strict_reserved,
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001930 function_token_position,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001931 FunctionLiteral::DECLARATION,
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001932 CHECK_OK);
1933 // Even if we're not at the top-level of the global or a function
1934 // scope, we treat is as such and introduce the function with it's
1935 // initial value upon entering the corresponding scope.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001936 VariableMode mode = is_extended_mode() ? LET : VAR;
ulan@chromium.org812308e2012-02-29 15:58:45 +00001937 VariableProxy* proxy = NewUnresolved(name, mode);
1938 Declaration* declaration =
1939 factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_);
1940 Declare(declaration, true, CHECK_OK);
1941 if (names) names->Add(name);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001942 return factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001943}
1944
1945
1946Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001947 if (top_scope_->is_extended_mode()) return ParseScopedBlock(labels, ok);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001948
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 // Block ::
1950 // '{' Statement* '}'
1951
1952 // Note that a Block does not introduce a new execution scope!
1953 // (ECMA-262, 3rd, 12.2)
1954 //
1955 // Construct block expecting 16 statements.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001956 Block* result = factory()->NewBlock(labels, 16, false);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001957 Target target(&this->target_stack_, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 Expect(Token::LBRACE, CHECK_OK);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001959 InitializationBlockFinder block_finder(top_scope_, target_stack_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 while (peek() != Token::RBRACE) {
1961 Statement* stat = ParseStatement(NULL, CHECK_OK);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001962 if (stat && !stat->IsEmpty()) {
1963 result->AddStatement(stat);
1964 block_finder.Update(stat);
1965 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001966 }
1967 Expect(Token::RBRACE, CHECK_OK);
1968 return result;
1969}
1970
1971
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001972Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001973 // The harmony mode uses block elements instead of statements.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001974 //
1975 // Block ::
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001976 // '{' BlockElement* '}'
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001977
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001978 // Construct block expecting 16 statements.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001979 Block* body = factory()->NewBlock(labels, 16, false);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001980 Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001981
1982 // Parse the statements and collect escaping labels.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001983 Expect(Token::LBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001984 block_scope->set_start_position(scanner().location().beg_pos);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001985 { BlockState block_state(this, block_scope);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001986 TargetCollector collector;
1987 Target target(&this->target_stack_, &collector);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001988 Target target_body(&this->target_stack_, body);
1989 InitializationBlockFinder block_finder(top_scope_, target_stack_);
1990
1991 while (peek() != Token::RBRACE) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001992 Statement* stat = ParseBlockElement(NULL, CHECK_OK);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001993 if (stat && !stat->IsEmpty()) {
1994 body->AddStatement(stat);
1995 block_finder.Update(stat);
1996 }
1997 }
1998 }
1999 Expect(Token::RBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002000 block_scope->set_end_position(scanner().location().end_pos);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002001 block_scope = block_scope->FinalizeBlockScope();
2002 body->set_block_scope(block_scope);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002003 return body;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002004}
2005
2006
danno@chromium.orgb6451162011-08-17 14:33:23 +00002007Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
ulan@chromium.org812308e2012-02-29 15:58:45 +00002008 ZoneStringList* names,
danno@chromium.orgb6451162011-08-17 14:33:23 +00002009 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002010 // VariableStatement ::
2011 // VariableDeclarations ';'
2012
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002013 Handle<String> ignore;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002014 Block* result =
ulan@chromium.org812308e2012-02-29 15:58:45 +00002015 ParseVariableDeclarations(var_context, NULL, names, &ignore, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016 ExpectSemicolon(CHECK_OK);
2017 return result;
2018}
2019
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002020
2021bool Parser::IsEvalOrArguments(Handle<String> string) {
2022 return string.is_identical_to(isolate()->factory()->eval_symbol()) ||
2023 string.is_identical_to(isolate()->factory()->arguments_symbol());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002024}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002025
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002026
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002027// If the variable declaration declares exactly one non-const
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002028// variable, then *out is set to that variable. In all other cases,
2029// *out is untouched; in particular, it is the caller's responsibility
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030// to initialize it properly. This mechanism is used for the parsing
2031// of 'for-in' loops.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002032Block* Parser::ParseVariableDeclarations(
2033 VariableDeclarationContext var_context,
2034 VariableDeclarationProperties* decl_props,
ulan@chromium.org812308e2012-02-29 15:58:45 +00002035 ZoneStringList* names,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002036 Handle<String>* out,
2037 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002038 // VariableDeclarations ::
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002039 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
2040 //
2041 // The ES6 Draft Rev3 specifies the following grammar for const declarations
2042 //
2043 // ConstDeclaration ::
2044 // const ConstBinding (',' ConstBinding)* ';'
2045 // ConstBinding ::
2046 // Identifier '=' AssignmentExpression
2047 //
2048 // TODO(ES6):
2049 // ConstBinding ::
2050 // BindingPattern '=' AssignmentExpression
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002051 VariableMode mode = VAR;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002052 // True if the binding needs initialization. 'let' and 'const' declared
2053 // bindings are created uninitialized by their declaration nodes and
2054 // need initialization. 'var' declared bindings are always initialized
2055 // immediately by their declaration nodes.
2056 bool needs_init = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002057 bool is_const = false;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002058 Token::Value init_op = Token::INIT_VAR;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002059 if (peek() == Token::VAR) {
2060 Consume(Token::VAR);
2061 } else if (peek() == Token::CONST) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002062 // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
2063 //
2064 // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
2065 //
2066 // * It is a Syntax Error if the code that matches this production is not
2067 // contained in extended code.
2068 //
2069 // However disallowing const in classic mode will break compatibility with
2070 // existing pages. Therefore we keep allowing const with the old
2071 // non-harmony semantics in classic mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002072 Consume(Token::CONST);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002073 switch (top_scope_->language_mode()) {
2074 case CLASSIC_MODE:
2075 mode = CONST;
2076 init_op = Token::INIT_CONST;
2077 break;
2078 case STRICT_MODE:
2079 ReportMessage("strict_const", Vector<const char*>::empty());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002080 *ok = false;
2081 return NULL;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002082 case EXTENDED_MODE:
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002083 if (var_context == kStatement) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002084 // In extended mode 'const' declarations are only allowed in source
2085 // element positions.
2086 ReportMessage("unprotected_const", Vector<const char*>::empty());
2087 *ok = false;
2088 return NULL;
2089 }
2090 mode = CONST_HARMONY;
2091 init_op = Token::INIT_CONST_HARMONY;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002092 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002093 is_const = true;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002094 needs_init = true;
danno@chromium.orgb6451162011-08-17 14:33:23 +00002095 } else if (peek() == Token::LET) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002096 // ES6 Draft Rev4 section 12.2.1:
2097 //
2098 // LetDeclaration : let LetBindingList ;
2099 //
2100 // * It is a Syntax Error if the code that matches this production is not
2101 // contained in extended code.
2102 if (!is_extended_mode()) {
2103 ReportMessage("illegal_let", Vector<const char*>::empty());
2104 *ok = false;
2105 return NULL;
2106 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00002107 Consume(Token::LET);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002108 if (var_context == kStatement) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002109 // Let declarations are only allowed in source element positions.
danno@chromium.orgb6451162011-08-17 14:33:23 +00002110 ReportMessage("unprotected_let", Vector<const char*>::empty());
2111 *ok = false;
2112 return NULL;
2113 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002114 mode = LET;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002115 needs_init = true;
2116 init_op = Token::INIT_LET;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002117 } else {
2118 UNREACHABLE(); // by current callers
2119 }
2120
ulan@chromium.org812308e2012-02-29 15:58:45 +00002121 Scope* declaration_scope = DeclarationScope(mode);
2122
danno@chromium.orgb6451162011-08-17 14:33:23 +00002123 // The scope of a var/const declared variable anywhere inside a function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002124 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
danno@chromium.orgb6451162011-08-17 14:33:23 +00002125 // transform a source-level var/const declaration into a (Function)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002126 // Scope declaration, and rewrite the source-level initialization into an
2127 // assignment statement. We use a block to collect multiple assignments.
2128 //
2129 // We mark the block as initializer block because we don't want the
2130 // rewriter to add a '.result' assignment to such a block (to get compliant
2131 // behavior for code such as print(eval('var x = 7')), and for cosmetic
2132 // reasons when pretty-printing. Also, unless an assignment (initialization)
2133 // is inside an initializer block, it is ignored.
2134 //
2135 // Create new block with one expected declaration.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002136 Block* block = factory()->NewBlock(NULL, 1, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002137 int nvars = 0; // the number of variables declared
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002138 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002139 do {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002140 if (fni_ != NULL) fni_->Enter();
2141
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002142 // Parse variable name.
2143 if (nvars > 0) Consume(Token::COMMA);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002144 name = ParseIdentifier(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002145 if (fni_ != NULL) fni_->PushVariableName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002146
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002147 // Strict mode variables may not be named eval or arguments
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002148 if (!declaration_scope->is_classic_mode() && IsEvalOrArguments(name)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002149 ReportMessage("strict_var_name", Vector<const char*>::empty());
2150 *ok = false;
2151 return NULL;
2152 }
2153
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154 // Declare variable.
2155 // Note that we *always* must treat the initial value via a separate init
2156 // assignment for variables and constants because the value must be assigned
2157 // when the variable is encountered in the source. But the variable/constant
2158 // is declared (and set to 'undefined') upon entering the function within
2159 // which the variable or constant is declared. Only function variables have
2160 // an initial value in the declaration (because they are initialized upon
2161 // entering the function).
2162 //
2163 // If we have a const declaration, in an inner scope, the proxy is always
2164 // bound to the declared variable (independent of possibly surrounding with
2165 // statements).
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002166 // For let/const declarations in harmony mode, we can also immediately
2167 // pre-resolve the proxy because it resides in the same scope as the
2168 // declaration.
ulan@chromium.org812308e2012-02-29 15:58:45 +00002169 VariableProxy* proxy = NewUnresolved(name, mode);
2170 Declaration* declaration =
2171 factory()->NewVariableDeclaration(proxy, mode, top_scope_);
2172 Declare(declaration, mode != VAR, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 nvars++;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002174 if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002175 ReportMessageAt(scanner().location(), "too_many_variables",
2176 Vector<const char*>::empty());
2177 *ok = false;
2178 return NULL;
2179 }
ulan@chromium.org812308e2012-02-29 15:58:45 +00002180 if (names) names->Add(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002181
2182 // Parse initialization expression if present and/or needed. A
2183 // declaration of the form:
2184 //
2185 // var v = x;
2186 //
2187 // is syntactic sugar for:
2188 //
2189 // var v; v = x;
2190 //
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002191 // In particular, we need to re-lookup 'v' (in top_scope_, not
2192 // declaration_scope) as it may be a different 'v' than the 'v' in the
2193 // declaration (e.g., if we are inside a 'with' statement or 'catch'
2194 // block).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195 //
2196 // However, note that const declarations are different! A const
2197 // declaration of the form:
2198 //
2199 // const c = x;
2200 //
2201 // is *not* syntactic sugar for:
2202 //
2203 // const c; c = x;
2204 //
2205 // The "variable" c initialized to x is the same as the declared
2206 // one - there is no re-lookup (see the last parameter of the
2207 // Declare() call above).
2208
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002209 Scope* initialization_scope = is_const ? declaration_scope : top_scope_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002210 Expression* value = NULL;
2211 int position = -1;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002212 // Harmony consts have non-optional initializers.
2213 if (peek() == Token::ASSIGN || mode == CONST_HARMONY) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002214 Expect(Token::ASSIGN, CHECK_OK);
2215 position = scanner().location().beg_pos;
danno@chromium.orgb6451162011-08-17 14:33:23 +00002216 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002217 // Don't infer if it is "a = function(){...}();"-like expression.
ager@chromium.org04921a82011-06-27 13:21:41 +00002218 if (fni_ != NULL &&
2219 value->AsCall() == NULL &&
2220 value->AsCallNew() == NULL) {
2221 fni_->Infer();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002222 } else {
2223 fni_->RemoveLastFunction();
ager@chromium.org04921a82011-06-27 13:21:41 +00002224 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002225 if (decl_props != NULL) *decl_props = kHasInitializers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002226 }
2227
danno@chromium.orgc612e022011-11-10 11:38:15 +00002228 // Record the end position of the initializer.
2229 if (proxy->var() != NULL) {
2230 proxy->var()->set_initializer_position(scanner().location().end_pos);
2231 }
2232
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002233 // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
2234 if (value == NULL && needs_init) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002235 value = GetLiteralUndefined();
2236 }
2237
2238 // Global variable declarations must be compiled in a specific
2239 // way. When the script containing the global variable declaration
2240 // is entered, the global variable must be declared, so that if it
2241 // doesn't exist (not even in a prototype of the global object) it
2242 // gets created with an initial undefined value. This is handled
2243 // by the declarations part of the function representing the
2244 // top-level global code; see Runtime::DeclareGlobalVariable. If
2245 // it already exists (in the object or in a prototype), it is
2246 // *not* touched until the variable declaration statement is
2247 // executed.
2248 //
2249 // Executing the variable declaration statement will always
2250 // guarantee to give the global object a "local" variable; a
2251 // variable defined in the global object and not in any
2252 // prototype. This way, global variable declarations can shadow
2253 // properties in the prototype chain, but only after the variable
2254 // declaration statement has been executed. This is important in
2255 // browsers where the global object (window) has lots of
2256 // properties defined in prototype objects.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002257 if (initialization_scope->is_global_scope()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002258 // Compute the arguments for the runtime call.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002259 ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002260 // We have at least 1 parameter.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002261 arguments->Add(factory()->NewLiteral(name));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002262 CallRuntime* initialize;
2263
2264 if (is_const) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002265 arguments->Add(value);
2266 value = NULL; // zap the value to avoid the unnecessary assignment
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002267
2268 // Construct the call to Runtime_InitializeConstGlobal
2269 // and add it to the initialization statement block.
2270 // Note that the function does different things depending on
2271 // the number of arguments (1 or 2).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002272 initialize = factory()->NewCallRuntime(
2273 isolate()->factory()->InitializeConstGlobal_symbol(),
2274 Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
2275 arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002276 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002277 // Add strict mode.
2278 // We may want to pass singleton to avoid Literal allocations.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002279 LanguageMode language_mode = initialization_scope->language_mode();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002280 arguments->Add(factory()->NewNumberLiteral(language_mode));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002281
2282 // Be careful not to assign a value to the global variable if
2283 // we're in a with. The initialization value should not
2284 // necessarily be stored in the global object in that case,
2285 // which is why we need to generate a separate assignment node.
2286 if (value != NULL && !inside_with()) {
2287 arguments->Add(value);
2288 value = NULL; // zap the value to avoid the unnecessary assignment
2289 }
2290
2291 // Construct the call to Runtime_InitializeVarGlobal
2292 // and add it to the initialization statement block.
2293 // Note that the function does different things depending on
2294 // the number of arguments (2 or 3).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002295 initialize = factory()->NewCallRuntime(
2296 isolate()->factory()->InitializeVarGlobal_symbol(),
2297 Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
2298 arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002299 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002300
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002301 block->AddStatement(factory()->NewExpressionStatement(initialize));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002302 } else if (needs_init) {
2303 // Constant initializations always assign to the declared constant which
2304 // is always at the function scope level. This is only relevant for
2305 // dynamically looked-up variables and constants (the start context for
2306 // constant lookups is always the function context, while it is the top
2307 // context for var declared variables). Sigh...
2308 // For 'let' and 'const' declared variables in harmony mode the
2309 // initialization also always assigns to the declared variable.
2310 ASSERT(proxy != NULL);
2311 ASSERT(proxy->var() != NULL);
2312 ASSERT(value != NULL);
2313 Assignment* assignment =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002314 factory()->NewAssignment(init_op, proxy, value, position);
2315 block->AddStatement(factory()->NewExpressionStatement(assignment));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002316 value = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002317 }
2318
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002319 // Add an assignment node to the initialization statement block if we still
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002320 // have a pending initialization value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002321 if (value != NULL) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002322 ASSERT(mode == VAR);
2323 // 'var' initializations are simply assignments (with all the consequences
2324 // if they are inside a 'with' statement - they may change a 'with' object
2325 // property).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002326 VariableProxy* proxy =
2327 initialization_scope->NewUnresolved(factory(), name);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002328 Assignment* assignment =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002329 factory()->NewAssignment(init_op, proxy, value, position);
2330 block->AddStatement(factory()->NewExpressionStatement(assignment));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002331 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002332
2333 if (fni_ != NULL) fni_->Leave();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002334 } while (peek() == Token::COMMA);
2335
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002336 // If there was a single non-const declaration, return it in the output
2337 // parameter for possible use by for/in.
2338 if (nvars == 1 && !is_const) {
2339 *out = name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002340 }
2341
2342 return block;
2343}
2344
2345
2346static bool ContainsLabel(ZoneStringList* labels, Handle<String> label) {
2347 ASSERT(!label.is_null());
2348 if (labels != NULL)
2349 for (int i = labels->length(); i-- > 0; )
2350 if (labels->at(i).is_identical_to(label))
2351 return true;
2352
2353 return false;
2354}
2355
2356
2357Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
2358 bool* ok) {
2359 // ExpressionStatement | LabelledStatement ::
2360 // Expression ';'
2361 // Identifier ':' Statement
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002362 bool starts_with_idenfifier = peek_any_identifier();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002363 Expression* expr = ParseExpression(true, CHECK_OK);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002364 if (peek() == Token::COLON && starts_with_idenfifier && expr != NULL &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002365 expr->AsVariableProxy() != NULL &&
2366 !expr->AsVariableProxy()->is_this()) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002367 // Expression is a single identifier, and not, e.g., a parenthesized
2368 // identifier.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002369 VariableProxy* var = expr->AsVariableProxy();
2370 Handle<String> label = var->name();
2371 // TODO(1240780): We don't check for redeclaration of labels
2372 // during preparsing since keeping track of the set of active
2373 // labels requires nontrivial changes to the way scopes are
2374 // structured. However, these are probably changes we want to
2375 // make later anyway so we should go back and fix this then.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002376 if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002377 SmartArrayPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002378 const char* elms[2] = { "Label", *c_string };
2379 Vector<const char*> args(elms, 2);
2380 ReportMessage("redeclaration", args);
2381 *ok = false;
2382 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002383 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002384 if (labels == NULL) labels = new(zone()) ZoneStringList(4);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002385 labels->Add(label);
2386 // Remove the "ghost" variable that turned out to be a label
2387 // from the top scope. This way, we don't try to resolve it
2388 // during the scope processing.
2389 top_scope_->RemoveUnresolved(var);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002390 Expect(Token::COLON, CHECK_OK);
2391 return ParseStatement(labels, ok);
2392 }
2393
whesse@chromium.org7b260152011-06-20 15:33:18 +00002394 // If we have an extension, we allow a native function declaration.
2395 // A native function declaration starts with "native function" with
2396 // no line-terminator between the two words.
2397 if (extension_ != NULL &&
2398 peek() == Token::FUNCTION &&
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002399 !scanner().HasAnyLineTerminatorBeforeNext() &&
whesse@chromium.org7b260152011-06-20 15:33:18 +00002400 expr != NULL &&
2401 expr->AsVariableProxy() != NULL &&
2402 expr->AsVariableProxy()->name()->Equals(
2403 isolate()->heap()->native_symbol()) &&
2404 !scanner().literal_contains_escapes()) {
2405 return ParseNativeDeclaration(ok);
2406 }
2407
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00002408 // Parsed expression statement, or the context-sensitive 'module' keyword.
2409 // Only expect semicolon in the former case.
2410 if (!FLAG_harmony_modules ||
2411 peek() != Token::IDENTIFIER ||
2412 scanner().HasAnyLineTerminatorBeforeNext() ||
2413 expr->AsVariableProxy() == NULL ||
2414 !expr->AsVariableProxy()->name()->Equals(
2415 isolate()->heap()->module_symbol()) ||
2416 scanner().literal_contains_escapes()) {
2417 ExpectSemicolon(CHECK_OK);
2418 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002419 return factory()->NewExpressionStatement(expr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002420}
2421
2422
2423IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) {
2424 // IfStatement ::
2425 // 'if' '(' Expression ')' Statement ('else' Statement)?
2426
2427 Expect(Token::IF, CHECK_OK);
2428 Expect(Token::LPAREN, CHECK_OK);
2429 Expression* condition = ParseExpression(true, CHECK_OK);
2430 Expect(Token::RPAREN, CHECK_OK);
2431 Statement* then_statement = ParseStatement(labels, CHECK_OK);
2432 Statement* else_statement = NULL;
2433 if (peek() == Token::ELSE) {
2434 Next();
2435 else_statement = ParseStatement(labels, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002436 } else {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002437 else_statement = factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002438 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002439 return factory()->NewIfStatement(condition, then_statement, else_statement);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002440}
2441
2442
2443Statement* Parser::ParseContinueStatement(bool* ok) {
2444 // ContinueStatement ::
2445 // 'continue' Identifier? ';'
2446
2447 Expect(Token::CONTINUE, CHECK_OK);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002448 Handle<String> label = Handle<String>::null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002449 Token::Value tok = peek();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002450 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002451 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002452 label = ParseIdentifier(CHECK_OK);
2453 }
2454 IterationStatement* target = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002455 target = LookupContinueTarget(label, CHECK_OK);
2456 if (target == NULL) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002457 // Illegal continue statement.
2458 const char* message = "illegal_continue";
2459 Vector<Handle<String> > args;
2460 if (!label.is_null()) {
2461 message = "unknown_label";
2462 args = Vector<Handle<String> >(&label, 1);
2463 }
2464 ReportMessageAt(scanner().location(), message, args);
2465 *ok = false;
2466 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002467 }
2468 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002469 return factory()->NewContinueStatement(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002470}
2471
2472
2473Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
2474 // BreakStatement ::
2475 // 'break' Identifier? ';'
2476
2477 Expect(Token::BREAK, CHECK_OK);
2478 Handle<String> label;
2479 Token::Value tok = peek();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002480 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002481 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002482 label = ParseIdentifier(CHECK_OK);
2483 }
ager@chromium.org32912102009-01-16 10:38:43 +00002484 // Parse labeled break statements that target themselves into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002485 // empty statements, e.g. 'l1: l2: l3: break l2;'
2486 if (!label.is_null() && ContainsLabel(labels, label)) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002487 ExpectSemicolon(CHECK_OK);
2488 return factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002489 }
2490 BreakableStatement* target = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002491 target = LookupBreakTarget(label, CHECK_OK);
2492 if (target == NULL) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002493 // Illegal break statement.
2494 const char* message = "illegal_break";
2495 Vector<Handle<String> > args;
2496 if (!label.is_null()) {
2497 message = "unknown_label";
2498 args = Vector<Handle<String> >(&label, 1);
2499 }
2500 ReportMessageAt(scanner().location(), message, args);
2501 *ok = false;
2502 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002503 }
2504 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002505 return factory()->NewBreakStatement(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002506}
2507
2508
2509Statement* Parser::ParseReturnStatement(bool* ok) {
2510 // ReturnStatement ::
2511 // 'return' Expression? ';'
2512
2513 // Consume the return token. It is necessary to do the before
2514 // reporting any errors on it, because of the way errors are
2515 // reported (underlining).
2516 Expect(Token::RETURN, CHECK_OK);
2517
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002518 Token::Value tok = peek();
2519 Statement* result;
2520 if (scanner().HasAnyLineTerminatorBeforeNext() ||
2521 tok == Token::SEMICOLON ||
2522 tok == Token::RBRACE ||
2523 tok == Token::EOS) {
2524 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002525 result = factory()->NewReturnStatement(GetLiteralUndefined());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002526 } else {
2527 Expression* expr = ParseExpression(true, CHECK_OK);
2528 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002529 result = factory()->NewReturnStatement(expr);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002530 }
2531
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002532 // An ECMAScript program is considered syntactically incorrect if it
2533 // contains a return statement that is not within the body of a
2534 // function. See ECMA-262, section 12.9, page 67.
2535 //
2536 // To be consistent with KJS we report the syntax error at runtime.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002537 Scope* declaration_scope = top_scope_->DeclarationScope();
2538 if (declaration_scope->is_global_scope() ||
2539 declaration_scope->is_eval_scope()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002540 Handle<String> type = isolate()->factory()->illegal_return_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002541 Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002542 return factory()->NewExpressionStatement(throw_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002543 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002544 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002545}
2546
2547
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002548Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
2549 // WithStatement ::
2550 // 'with' '(' Expression ')' Statement
2551
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002552 Expect(Token::WITH, CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002553
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002554 if (!top_scope_->is_classic_mode()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002555 ReportMessage("strict_mode_with", Vector<const char*>::empty());
2556 *ok = false;
2557 return NULL;
2558 }
2559
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002560 Expect(Token::LPAREN, CHECK_OK);
2561 Expression* expr = ParseExpression(true, CHECK_OK);
2562 Expect(Token::RPAREN, CHECK_OK);
2563
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002564 top_scope_->DeclarationScope()->RecordWithStatement();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002565 Scope* with_scope = NewScope(top_scope_, WITH_SCOPE);
2566 Statement* stmt;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002567 { BlockState block_state(this, with_scope);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002568 with_scope->set_start_position(scanner().peek_location().beg_pos);
2569 stmt = ParseStatement(labels, CHECK_OK);
2570 with_scope->set_end_position(scanner().location().end_pos);
2571 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002572 return factory()->NewWithStatement(expr, stmt);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002573}
2574
2575
2576CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
2577 // CaseClause ::
2578 // 'case' Expression ':' Statement*
2579 // 'default' ':' Statement*
2580
2581 Expression* label = NULL; // NULL expression indicates default case
2582 if (peek() == Token::CASE) {
2583 Expect(Token::CASE, CHECK_OK);
2584 label = ParseExpression(true, CHECK_OK);
2585 } else {
2586 Expect(Token::DEFAULT, CHECK_OK);
2587 if (*default_seen_ptr) {
2588 ReportMessage("multiple_defaults_in_switch",
2589 Vector<const char*>::empty());
2590 *ok = false;
2591 return NULL;
2592 }
2593 *default_seen_ptr = true;
2594 }
2595 Expect(Token::COLON, CHECK_OK);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002596 int pos = scanner().location().beg_pos;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002597 ZoneList<Statement*>* statements = new(zone()) ZoneList<Statement*>(5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002598 while (peek() != Token::CASE &&
2599 peek() != Token::DEFAULT &&
2600 peek() != Token::RBRACE) {
2601 Statement* stat = ParseStatement(NULL, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002602 statements->Add(stat);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002603 }
2604
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002605 return new(zone()) CaseClause(isolate(), label, statements, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002606}
2607
2608
2609SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels,
2610 bool* ok) {
2611 // SwitchStatement ::
2612 // 'switch' '(' Expression ')' '{' CaseClause* '}'
2613
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002614 SwitchStatement* statement = factory()->NewSwitchStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002615 Target target(&this->target_stack_, statement);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002616
2617 Expect(Token::SWITCH, CHECK_OK);
2618 Expect(Token::LPAREN, CHECK_OK);
2619 Expression* tag = ParseExpression(true, CHECK_OK);
2620 Expect(Token::RPAREN, CHECK_OK);
2621
2622 bool default_seen = false;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002623 ZoneList<CaseClause*>* cases = new(zone()) ZoneList<CaseClause*>(4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002624 Expect(Token::LBRACE, CHECK_OK);
2625 while (peek() != Token::RBRACE) {
2626 CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002627 cases->Add(clause);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002628 }
2629 Expect(Token::RBRACE, CHECK_OK);
2630
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002631 if (statement) statement->Initialize(tag, cases);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002632 return statement;
2633}
2634
2635
2636Statement* Parser::ParseThrowStatement(bool* ok) {
2637 // ThrowStatement ::
2638 // 'throw' Expression ';'
2639
2640 Expect(Token::THROW, CHECK_OK);
2641 int pos = scanner().location().beg_pos;
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002642 if (scanner().HasAnyLineTerminatorBeforeNext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002643 ReportMessage("newline_after_throw", Vector<const char*>::empty());
2644 *ok = false;
2645 return NULL;
2646 }
2647 Expression* exception = ParseExpression(true, CHECK_OK);
2648 ExpectSemicolon(CHECK_OK);
2649
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002650 return factory()->NewExpressionStatement(factory()->NewThrow(exception, pos));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002651}
2652
2653
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002654TryStatement* Parser::ParseTryStatement(bool* ok) {
2655 // TryStatement ::
2656 // 'try' Block Catch
2657 // 'try' Block Finally
2658 // 'try' Block Catch Finally
2659 //
2660 // Catch ::
2661 // 'catch' '(' Identifier ')' Block
2662 //
2663 // Finally ::
2664 // 'finally' Block
2665
2666 Expect(Token::TRY, CHECK_OK);
2667
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002668 TargetCollector try_collector;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002669 Block* try_block;
2670
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002671 { Target target(&this->target_stack_, &try_collector);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002672 try_block = ParseBlock(NULL, CHECK_OK);
2673 }
2674
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002675 Token::Value tok = peek();
2676 if (tok != Token::CATCH && tok != Token::FINALLY) {
2677 ReportMessage("no_catch_or_finally", Vector<const char*>::empty());
2678 *ok = false;
2679 return NULL;
2680 }
2681
2682 // If we can break out from the catch block and there is a finally block,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002683 // then we will need to collect escaping targets from the catch
2684 // block. Since we don't know yet if there will be a finally block, we
2685 // always collect the targets.
2686 TargetCollector catch_collector;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002687 Scope* catch_scope = NULL;
2688 Variable* catch_variable = NULL;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002689 Block* catch_block = NULL;
2690 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002691 if (tok == Token::CATCH) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002692 Consume(Token::CATCH);
2693
2694 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002695 catch_scope = NewScope(top_scope_, CATCH_SCOPE);
2696 catch_scope->set_start_position(scanner().location().beg_pos);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002697 name = ParseIdentifier(CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002698
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002699 if (!top_scope_->is_classic_mode() && IsEvalOrArguments(name)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002700 ReportMessage("strict_catch_variable", Vector<const char*>::empty());
2701 *ok = false;
2702 return NULL;
2703 }
2704
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002705 Expect(Token::RPAREN, CHECK_OK);
2706
2707 if (peek() == Token::LBRACE) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002708 Target target(&this->target_stack_, &catch_collector);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002709 VariableMode mode = is_extended_mode() ? LET : VAR;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002710 catch_variable =
2711 catch_scope->DeclareLocal(name, mode, kCreatedInitialized);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002712
danno@chromium.orgc612e022011-11-10 11:38:15 +00002713 BlockState block_state(this, catch_scope);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002714 catch_block = ParseBlock(NULL, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002715 } else {
2716 Expect(Token::LBRACE, CHECK_OK);
2717 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002718 catch_scope->set_end_position(scanner().location().end_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002719 tok = peek();
2720 }
2721
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002722 Block* finally_block = NULL;
2723 if (tok == Token::FINALLY || catch_block == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002724 Consume(Token::FINALLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002725 finally_block = ParseBlock(NULL, CHECK_OK);
2726 }
2727
2728 // Simplify the AST nodes by converting:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002729 // 'try B0 catch B1 finally B2'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002730 // to:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002731 // 'try { try B0 catch B1 } finally B2'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002732
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002733 if (catch_block != NULL && finally_block != NULL) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002734 // If we have both, create an inner try/catch.
2735 ASSERT(catch_scope != NULL && catch_variable != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002736 int index = current_function_state_->NextHandlerIndex();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002737 TryCatchStatement* statement = factory()->NewTryCatchStatement(
2738 index, try_block, catch_scope, catch_variable, catch_block);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002739 statement->set_escaping_targets(try_collector.targets());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002740 try_block = factory()->NewBlock(NULL, 1, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002741 try_block->AddStatement(statement);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002742 catch_block = NULL; // Clear to indicate it's been handled.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002743 }
2744
2745 TryStatement* result = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002746 if (catch_block != NULL) {
2747 ASSERT(finally_block == NULL);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002748 ASSERT(catch_scope != NULL && catch_variable != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002749 int index = current_function_state_->NextHandlerIndex();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002750 result = factory()->NewTryCatchStatement(
2751 index, try_block, catch_scope, catch_variable, catch_block);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002752 } else {
2753 ASSERT(finally_block != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002754 int index = current_function_state_->NextHandlerIndex();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002755 result = factory()->NewTryFinallyStatement(index, try_block, finally_block);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002756 // Combine the jump targets of the try block and the possible catch block.
2757 try_collector.targets()->AddAll(*catch_collector.targets());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002758 }
2759
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002760 result->set_escaping_targets(try_collector.targets());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002761 return result;
2762}
2763
2764
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002765DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels,
2766 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002767 // DoStatement ::
2768 // 'do' Statement 'while' '(' Expression ')' ';'
2769
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002770 DoWhileStatement* loop = factory()->NewDoWhileStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002771 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772
2773 Expect(Token::DO, CHECK_OK);
2774 Statement* body = ParseStatement(NULL, CHECK_OK);
2775 Expect(Token::WHILE, CHECK_OK);
2776 Expect(Token::LPAREN, CHECK_OK);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002777
2778 if (loop != NULL) {
2779 int position = scanner().location().beg_pos;
2780 loop->set_condition_position(position);
2781 }
2782
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002783 Expression* cond = ParseExpression(true, CHECK_OK);
2784 Expect(Token::RPAREN, CHECK_OK);
2785
2786 // Allow do-statements to be terminated with and without
2787 // semi-colons. This allows code such as 'do;while(0)return' to
2788 // parse, which would not be the case if we had used the
2789 // ExpectSemicolon() functionality here.
2790 if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
2791
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002792 if (loop != NULL) loop->Initialize(cond, body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002793 return loop;
2794}
2795
2796
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002797WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002798 // WhileStatement ::
2799 // 'while' '(' Expression ')' Statement
2800
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002801 WhileStatement* loop = factory()->NewWhileStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002802 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002803
2804 Expect(Token::WHILE, CHECK_OK);
2805 Expect(Token::LPAREN, CHECK_OK);
2806 Expression* cond = ParseExpression(true, CHECK_OK);
2807 Expect(Token::RPAREN, CHECK_OK);
2808 Statement* body = ParseStatement(NULL, CHECK_OK);
2809
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002810 if (loop != NULL) loop->Initialize(cond, body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002811 return loop;
2812}
2813
2814
2815Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
2816 // ForStatement ::
2817 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
2818
2819 Statement* init = NULL;
2820
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002821 // Create an in-between scope for let-bound iteration variables.
2822 Scope* saved_scope = top_scope_;
2823 Scope* for_scope = NewScope(top_scope_, BLOCK_SCOPE);
2824 top_scope_ = for_scope;
2825
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002826 Expect(Token::FOR, CHECK_OK);
2827 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002828 for_scope->set_start_position(scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002829 if (peek() != Token::SEMICOLON) {
2830 if (peek() == Token::VAR || peek() == Token::CONST) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002831 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002832 Block* variable_statement =
ulan@chromium.org812308e2012-02-29 15:58:45 +00002833 ParseVariableDeclarations(kForStatement, NULL, NULL, &name, CHECK_OK);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002834
2835 if (peek() == Token::IN && !name.is_null()) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002836 VariableProxy* each = top_scope_->NewUnresolved(factory(), name);
2837 ForInStatement* loop = factory()->NewForInStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002838 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002839
2840 Expect(Token::IN, CHECK_OK);
2841 Expression* enumerable = ParseExpression(true, CHECK_OK);
2842 Expect(Token::RPAREN, CHECK_OK);
2843
2844 Statement* body = ParseStatement(NULL, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002845 loop->Initialize(each, enumerable, body);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002846 Block* result = factory()->NewBlock(NULL, 2, false);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002847 result->AddStatement(variable_statement);
2848 result->AddStatement(loop);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002849 top_scope_ = saved_scope;
2850 for_scope->set_end_position(scanner().location().end_pos);
2851 for_scope = for_scope->FinalizeBlockScope();
2852 ASSERT(for_scope == NULL);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002853 // Parsed for-in loop w/ variable/const declaration.
2854 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002855 } else {
2856 init = variable_statement;
2857 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002858 } else if (peek() == Token::LET) {
2859 Handle<String> name;
2860 VariableDeclarationProperties decl_props = kHasNoInitializers;
2861 Block* variable_statement =
ulan@chromium.org812308e2012-02-29 15:58:45 +00002862 ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name,
2863 CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002864 bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
2865 if (peek() == Token::IN && accept_IN) {
2866 // Rewrite a for-in statement of the form
2867 //
2868 // for (let x in e) b
2869 //
2870 // into
2871 //
2872 // <let x' be a temporary variable>
2873 // for (x' in e) {
2874 // let x;
2875 // x = x';
2876 // b;
2877 // }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002878
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002879 // TODO(keuchel): Move the temporary variable to the block scope, after
2880 // implementing stack allocated block scoped variables.
2881 Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002882 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
2883 VariableProxy* each = top_scope_->NewUnresolved(factory(), name);
2884 ForInStatement* loop = factory()->NewForInStatement(labels);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002885 Target target(&this->target_stack_, loop);
2886
2887 Expect(Token::IN, CHECK_OK);
2888 Expression* enumerable = ParseExpression(true, CHECK_OK);
2889 Expect(Token::RPAREN, CHECK_OK);
2890
2891 Statement* body = ParseStatement(NULL, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002892 Block* body_block = factory()->NewBlock(NULL, 3, false);
2893 Assignment* assignment = factory()->NewAssignment(
2894 Token::ASSIGN, each, temp_proxy, RelocInfo::kNoPosition);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002895 Statement* assignment_statement =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002896 factory()->NewExpressionStatement(assignment);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002897 body_block->AddStatement(variable_statement);
2898 body_block->AddStatement(assignment_statement);
2899 body_block->AddStatement(body);
2900 loop->Initialize(temp_proxy, enumerable, body_block);
2901 top_scope_ = saved_scope;
2902 for_scope->set_end_position(scanner().location().end_pos);
2903 for_scope = for_scope->FinalizeBlockScope();
2904 body_block->set_block_scope(for_scope);
2905 // Parsed for-in loop w/ let declaration.
2906 return loop;
2907
2908 } else {
2909 init = variable_statement;
2910 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002911 } else {
2912 Expression* expression = ParseExpression(false, CHECK_OK);
2913 if (peek() == Token::IN) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002914 // Signal a reference error if the expression is an invalid
2915 // left-hand side expression. We could report this as a syntax
2916 // error here but for compatibility with JSC we choose to report
2917 // the error at runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002918 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002919 Handle<String> type =
2920 isolate()->factory()->invalid_lhs_in_for_in_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002921 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002922 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002923 ForInStatement* loop = factory()->NewForInStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002924 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002925
2926 Expect(Token::IN, CHECK_OK);
2927 Expression* enumerable = ParseExpression(true, CHECK_OK);
2928 Expect(Token::RPAREN, CHECK_OK);
2929
2930 Statement* body = ParseStatement(NULL, CHECK_OK);
2931 if (loop) loop->Initialize(expression, enumerable, body);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002932 top_scope_ = saved_scope;
2933 for_scope->set_end_position(scanner().location().end_pos);
2934 for_scope = for_scope->FinalizeBlockScope();
2935 ASSERT(for_scope == NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002936 // Parsed for-in loop.
2937 return loop;
2938
2939 } else {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002940 init = factory()->NewExpressionStatement(expression);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002941 }
2942 }
2943 }
2944
2945 // Standard 'for' loop
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002946 ForStatement* loop = factory()->NewForStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002947 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002948
2949 // Parsed initializer at this point.
2950 Expect(Token::SEMICOLON, CHECK_OK);
2951
2952 Expression* cond = NULL;
2953 if (peek() != Token::SEMICOLON) {
2954 cond = ParseExpression(true, CHECK_OK);
2955 }
2956 Expect(Token::SEMICOLON, CHECK_OK);
2957
2958 Statement* next = NULL;
2959 if (peek() != Token::RPAREN) {
2960 Expression* exp = ParseExpression(true, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002961 next = factory()->NewExpressionStatement(exp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002962 }
2963 Expect(Token::RPAREN, CHECK_OK);
2964
2965 Statement* body = ParseStatement(NULL, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002966 top_scope_ = saved_scope;
2967 for_scope->set_end_position(scanner().location().end_pos);
2968 for_scope = for_scope->FinalizeBlockScope();
2969 if (for_scope != NULL) {
2970 // Rewrite a for statement of the form
2971 //
2972 // for (let x = i; c; n) b
2973 //
2974 // into
2975 //
2976 // {
2977 // let x = i;
2978 // for (; c; n) b
2979 // }
2980 ASSERT(init != NULL);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002981 Block* result = factory()->NewBlock(NULL, 2, false);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002982 result->AddStatement(init);
2983 result->AddStatement(loop);
2984 result->set_block_scope(for_scope);
2985 if (loop) loop->Initialize(NULL, cond, next, body);
2986 return result;
2987 } else {
2988 if (loop) loop->Initialize(init, cond, next, body);
2989 return loop;
2990 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002991}
2992
2993
2994// Precedence = 1
2995Expression* Parser::ParseExpression(bool accept_IN, bool* ok) {
2996 // Expression ::
2997 // AssignmentExpression
2998 // Expression ',' AssignmentExpression
2999
3000 Expression* result = ParseAssignmentExpression(accept_IN, CHECK_OK);
3001 while (peek() == Token::COMMA) {
3002 Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003003 int position = scanner().location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003004 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003005 result =
3006 factory()->NewBinaryOperation(Token::COMMA, result, right, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003007 }
3008 return result;
3009}
3010
3011
3012// Precedence = 2
3013Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
3014 // AssignmentExpression ::
3015 // ConditionalExpression
3016 // LeftHandSideExpression AssignmentOperator AssignmentExpression
3017
ricow@chromium.org65fae842010-08-25 15:26:24 +00003018 if (fni_ != NULL) fni_->Enter();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003019 Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
3020
3021 if (!Token::IsAssignmentOp(peek())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003022 if (fni_ != NULL) fni_->Leave();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003023 // Parsed conditional expression only (no assignment).
3024 return expression;
3025 }
3026
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003027 // Signal a reference error if the expression is an invalid left-hand
3028 // side expression. We could report this as a syntax error here but
3029 // for compatibility with JSC we choose to report the error at
3030 // runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003031 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003032 Handle<String> type =
3033 isolate()->factory()->invalid_lhs_in_assignment_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003034 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003035 }
3036
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003037 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003038 // Assignment to eval or arguments is disallowed in strict mode.
3039 CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK);
3040 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003041 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003042
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003043 Token::Value op = Next(); // Get assignment operator.
3044 int pos = scanner().location().beg_pos;
3045 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
3046
3047 // TODO(1231235): We try to estimate the set of properties set by
3048 // constructors. We define a new property whenever there is an
3049 // assignment to a property of 'this'. We should probably only add
3050 // properties if we haven't seen them before. Otherwise we'll
3051 // probably overestimate the number of properties.
3052 Property* property = expression ? expression->AsProperty() : NULL;
3053 if (op == Token::ASSIGN &&
3054 property != NULL &&
3055 property->obj()->AsVariableProxy() != NULL &&
3056 property->obj()->AsVariableProxy()->is_this()) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003057 current_function_state_->AddProperty();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058 }
3059
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003060 // If we assign a function literal to a property we pretenure the
3061 // literal so it can be added as a constant function property.
3062 if (property != NULL && right->AsFunctionLiteral() != NULL) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003063 right->AsFunctionLiteral()->set_pretenure();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003064 }
3065
ricow@chromium.org65fae842010-08-25 15:26:24 +00003066 if (fni_ != NULL) {
3067 // Check if the right hand side is a call to avoid inferring a
3068 // name if we're dealing with "a = function(){...}();"-like
3069 // expression.
3070 if ((op == Token::INIT_VAR
3071 || op == Token::INIT_CONST
3072 || op == Token::ASSIGN)
ager@chromium.org04921a82011-06-27 13:21:41 +00003073 && (right->AsCall() == NULL && right->AsCallNew() == NULL)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003074 fni_->Infer();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003075 } else {
3076 fni_->RemoveLastFunction();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003077 }
3078 fni_->Leave();
3079 }
3080
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003081 return factory()->NewAssignment(op, expression, right, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003082}
3083
3084
3085// Precedence = 3
3086Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
3087 // ConditionalExpression ::
3088 // LogicalOrExpression
3089 // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
3090
3091 // We start using the binary expression parser for prec >= 4 only!
3092 Expression* expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
3093 if (peek() != Token::CONDITIONAL) return expression;
3094 Consume(Token::CONDITIONAL);
3095 // In parsing the first assignment expression in conditional
3096 // expressions we always accept the 'in' keyword; see ECMA-262,
3097 // section 11.12, page 58.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003098 int left_position = scanner().peek_location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003099 Expression* left = ParseAssignmentExpression(true, CHECK_OK);
3100 Expect(Token::COLON, CHECK_OK);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003101 int right_position = scanner().peek_location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003102 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003103 return factory()->NewConditional(
3104 expression, left, right, left_position, right_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003105}
3106
3107
3108static int Precedence(Token::Value tok, bool accept_IN) {
3109 if (tok == Token::IN && !accept_IN)
3110 return 0; // 0 precedence will terminate binary expression parsing
3111
3112 return Token::Precedence(tok);
3113}
3114
3115
3116// Precedence >= 4
3117Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
3118 ASSERT(prec >= 4);
3119 Expression* x = ParseUnaryExpression(CHECK_OK);
3120 for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
3121 // prec1 >= 4
3122 while (Precedence(peek(), accept_IN) == prec1) {
3123 Token::Value op = Next();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003124 int position = scanner().location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003125 Expression* y = ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
3126
3127 // Compute some expressions involving only number literals.
3128 if (x && x->AsLiteral() && x->AsLiteral()->handle()->IsNumber() &&
3129 y && y->AsLiteral() && y->AsLiteral()->handle()->IsNumber()) {
3130 double x_val = x->AsLiteral()->handle()->Number();
3131 double y_val = y->AsLiteral()->handle()->Number();
3132
3133 switch (op) {
3134 case Token::ADD:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003135 x = factory()->NewNumberLiteral(x_val + y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003136 continue;
3137 case Token::SUB:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003138 x = factory()->NewNumberLiteral(x_val - y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003139 continue;
3140 case Token::MUL:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003141 x = factory()->NewNumberLiteral(x_val * y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003142 continue;
3143 case Token::DIV:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003144 x = factory()->NewNumberLiteral(x_val / y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003145 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003146 case Token::BIT_OR: {
3147 int value = DoubleToInt32(x_val) | DoubleToInt32(y_val);
3148 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003149 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003150 }
3151 case Token::BIT_AND: {
3152 int value = DoubleToInt32(x_val) & DoubleToInt32(y_val);
3153 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003154 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003155 }
3156 case Token::BIT_XOR: {
3157 int value = DoubleToInt32(x_val) ^ DoubleToInt32(y_val);
3158 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003159 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003160 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003161 case Token::SHL: {
3162 int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003163 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003164 continue;
3165 }
3166 case Token::SHR: {
3167 uint32_t shift = DoubleToInt32(y_val) & 0x1f;
3168 uint32_t value = DoubleToUint32(x_val) >> shift;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003169 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003170 continue;
3171 }
3172 case Token::SAR: {
3173 uint32_t shift = DoubleToInt32(y_val) & 0x1f;
3174 int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003175 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003176 continue;
3177 }
3178 default:
3179 break;
3180 }
3181 }
3182
3183 // For now we distinguish between comparisons and other binary
3184 // operations. (We could combine the two and get rid of this
ricow@chromium.org65fae842010-08-25 15:26:24 +00003185 // code and AST node eventually.)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003186 if (Token::IsCompareOp(op)) {
3187 // We have a comparison.
3188 Token::Value cmp = op;
3189 switch (op) {
3190 case Token::NE: cmp = Token::EQ; break;
3191 case Token::NE_STRICT: cmp = Token::EQ_STRICT; break;
3192 default: break;
3193 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003194 x = factory()->NewCompareOperation(cmp, x, y, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003195 if (cmp != op) {
3196 // The comparison was negated - add a NOT.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003197 x = factory()->NewUnaryOperation(Token::NOT, x, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003198 }
3199
3200 } else {
3201 // We have a "normal" binary operation.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003202 x = factory()->NewBinaryOperation(op, x, y, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003203 }
3204 }
3205 }
3206 return x;
3207}
3208
3209
3210Expression* Parser::ParseUnaryExpression(bool* ok) {
3211 // UnaryExpression ::
3212 // PostfixExpression
3213 // 'delete' UnaryExpression
3214 // 'void' UnaryExpression
3215 // 'typeof' UnaryExpression
3216 // '++' UnaryExpression
3217 // '--' UnaryExpression
3218 // '+' UnaryExpression
3219 // '-' UnaryExpression
3220 // '~' UnaryExpression
3221 // '!' UnaryExpression
3222
3223 Token::Value op = peek();
3224 if (Token::IsUnaryOp(op)) {
3225 op = Next();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003226 int position = scanner().location().beg_pos;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003227 Expression* expression = ParseUnaryExpression(CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003228
whesse@chromium.org7b260152011-06-20 15:33:18 +00003229 if (expression != NULL && (expression->AsLiteral() != NULL)) {
3230 Handle<Object> literal = expression->AsLiteral()->handle();
3231 if (op == Token::NOT) {
3232 // Convert the literal to a boolean condition and negate it.
3233 bool condition = literal->ToBoolean()->IsTrue();
3234 Handle<Object> result(isolate()->heap()->ToBoolean(!condition));
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003235 return factory()->NewLiteral(result);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003236 } else if (literal->IsNumber()) {
3237 // Compute some expressions involving only number literals.
3238 double value = literal->Number();
3239 switch (op) {
3240 case Token::ADD:
3241 return expression;
3242 case Token::SUB:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003243 return factory()->NewNumberLiteral(-value);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003244 case Token::BIT_NOT:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003245 return factory()->NewNumberLiteral(~DoubleToInt32(value));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003246 default:
3247 break;
3248 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003249 }
3250 }
3251
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003252 // "delete identifier" is a syntax error in strict mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003253 if (op == Token::DELETE && !top_scope_->is_classic_mode()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003254 VariableProxy* operand = expression->AsVariableProxy();
3255 if (operand != NULL && !operand->is_this()) {
3256 ReportMessage("strict_delete", Vector<const char*>::empty());
3257 *ok = false;
3258 return NULL;
3259 }
3260 }
3261
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003262 return factory()->NewUnaryOperation(op, expression, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003263
3264 } else if (Token::IsCountOp(op)) {
3265 op = Next();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003266 Expression* expression = ParseUnaryExpression(CHECK_OK);
3267 // Signal a reference error if the expression is an invalid
3268 // left-hand side expression. We could report this as a syntax
3269 // error here but for compatibility with JSC we choose to report the
3270 // error at runtime.
3271 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003272 Handle<String> type =
3273 isolate()->factory()->invalid_lhs_in_prefix_op_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003274 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003275 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003276
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003277 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003278 // Prefix expression operand in strict mode may not be eval or arguments.
3279 CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
3280 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003281 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003282
ricow@chromium.org65fae842010-08-25 15:26:24 +00003283 int position = scanner().location().beg_pos;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003284 return factory()->NewCountOperation(op,
3285 true /* prefix */,
3286 expression,
3287 position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003288
3289 } else {
3290 return ParsePostfixExpression(ok);
3291 }
3292}
3293
3294
3295Expression* Parser::ParsePostfixExpression(bool* ok) {
3296 // PostfixExpression ::
3297 // LeftHandSideExpression ('++' | '--')?
3298
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003299 Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00003300 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003301 Token::IsCountOp(peek())) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003302 // Signal a reference error if the expression is an invalid
3303 // left-hand side expression. We could report this as a syntax
3304 // error here but for compatibility with JSC we choose to report the
3305 // error at runtime.
3306 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003307 Handle<String> type =
3308 isolate()->factory()->invalid_lhs_in_postfix_op_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003309 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003310 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003311
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003312 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003313 // Postfix expression operand in strict mode may not be eval or arguments.
3314 CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
3315 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003316 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003317
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003318 Token::Value next = Next();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003319 int position = scanner().location().beg_pos;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003320 expression =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003321 factory()->NewCountOperation(next,
3322 false /* postfix */,
3323 expression,
3324 position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003325 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003326 return expression;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003327}
3328
3329
3330Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
3331 // LeftHandSideExpression ::
3332 // (NewExpression | MemberExpression) ...
3333
3334 Expression* result;
3335 if (peek() == Token::NEW) {
3336 result = ParseNewExpression(CHECK_OK);
3337 } else {
3338 result = ParseMemberExpression(CHECK_OK);
3339 }
3340
3341 while (true) {
3342 switch (peek()) {
3343 case Token::LBRACK: {
3344 Consume(Token::LBRACK);
3345 int pos = scanner().location().beg_pos;
3346 Expression* index = ParseExpression(true, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003347 result = factory()->NewProperty(result, index, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 Expect(Token::RBRACK, CHECK_OK);
3349 break;
3350 }
3351
3352 case Token::LPAREN: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003353 int pos;
3354 if (scanner().current_token() == Token::IDENTIFIER) {
3355 // For call of an identifier we want to report position of
3356 // the identifier as position of the call in the stack trace.
3357 pos = scanner().location().beg_pos;
3358 } else {
3359 // For other kinds of calls we record position of the parenthesis as
3360 // position of the call. Note that this is extremely important for
3361 // expressions of the form function(){...}() for which call position
3362 // should not point to the closing brace otherwise it will intersect
3363 // with positions recorded for function literal and confuse debugger.
3364 pos = scanner().peek_location().beg_pos;
3365 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003366 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
3367
3368 // Keep track of eval() calls since they disable all local variable
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003369 // optimizations.
3370 // The calls that need special treatment are the
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003371 // direct eval calls. These calls are all of the form eval(...), with
3372 // no explicit receiver.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003373 // These calls are marked as potentially direct eval calls. Whether
3374 // they are actually direct calls to eval is determined at run time.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003375 VariableProxy* callee = result->AsVariableProxy();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003376 if (callee != NULL &&
3377 callee->IsVariable(isolate()->factory()->eval_symbol())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003378 top_scope_->DeclarationScope()->RecordEvalCall();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003379 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003380 result = factory()->NewCall(result, args, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003381 break;
3382 }
3383
3384 case Token::PERIOD: {
3385 Consume(Token::PERIOD);
3386 int pos = scanner().location().beg_pos;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003387 Handle<String> name = ParseIdentifierName(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003388 result =
3389 factory()->NewProperty(result, factory()->NewLiteral(name), pos);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003390 if (fni_ != NULL) fni_->PushLiteralName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003391 break;
3392 }
3393
3394 default:
3395 return result;
3396 }
3397 }
3398}
3399
3400
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003401Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402 // NewExpression ::
3403 // ('new')+ MemberExpression
3404
3405 // The grammar for new expressions is pretty warped. The keyword
3406 // 'new' can either be a part of the new expression (where it isn't
3407 // followed by an argument list) or a part of the member expression,
3408 // where it must be followed by an argument list. To accommodate
3409 // this, we parse the 'new' keywords greedily and keep track of how
3410 // many we have parsed. This information is then passed on to the
3411 // member expression parser, which is only allowed to match argument
3412 // lists as long as it has 'new' prefixes left
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003413 Expect(Token::NEW, CHECK_OK);
3414 PositionStack::Element pos(stack, scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003416 Expression* result;
3417 if (peek() == Token::NEW) {
3418 result = ParseNewPrefix(stack, CHECK_OK);
3419 } else {
3420 result = ParseMemberWithNewPrefixesExpression(stack, CHECK_OK);
3421 }
3422
3423 if (!stack->is_empty()) {
3424 int last = stack->pop();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003425 result = factory()->NewCallNew(
3426 result, new(zone()) ZoneList<Expression*>(0), last);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003427 }
3428 return result;
3429}
3430
3431
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003432Expression* Parser::ParseNewExpression(bool* ok) {
3433 PositionStack stack(ok);
3434 return ParseNewPrefix(&stack, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003435}
3436
3437
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003438Expression* Parser::ParseMemberExpression(bool* ok) {
3439 return ParseMemberWithNewPrefixesExpression(NULL, ok);
3440}
3441
3442
3443Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
3444 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003445 // MemberExpression ::
3446 // (PrimaryExpression | FunctionLiteral)
3447 // ('[' Expression ']' | '.' Identifier | Arguments)*
3448
3449 // Parse the initial primary or function expression.
3450 Expression* result = NULL;
3451 if (peek() == Token::FUNCTION) {
3452 Expect(Token::FUNCTION, CHECK_OK);
3453 int function_token_position = scanner().location().beg_pos;
3454 Handle<String> name;
ager@chromium.org04921a82011-06-27 13:21:41 +00003455 bool is_strict_reserved_name = false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003456 if (peek_any_identifier()) {
ager@chromium.org04921a82011-06-27 13:21:41 +00003457 name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
3458 CHECK_OK);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003459 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003460 FunctionLiteral::Type type = name.is_null()
3461 ? FunctionLiteral::ANONYMOUS_EXPRESSION
3462 : FunctionLiteral::NAMED_EXPRESSION;
3463 result = ParseFunctionLiteral(name,
3464 is_strict_reserved_name,
3465 function_token_position,
3466 type,
3467 CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003468 } else {
3469 result = ParsePrimaryExpression(CHECK_OK);
3470 }
3471
3472 while (true) {
3473 switch (peek()) {
3474 case Token::LBRACK: {
3475 Consume(Token::LBRACK);
3476 int pos = scanner().location().beg_pos;
3477 Expression* index = ParseExpression(true, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003478 result = factory()->NewProperty(result, index, pos);
ager@chromium.org04921a82011-06-27 13:21:41 +00003479 if (fni_ != NULL) {
3480 if (index->IsPropertyName()) {
3481 fni_->PushLiteralName(index->AsLiteral()->AsPropertyName());
3482 } else {
3483 fni_->PushLiteralName(
3484 isolate()->factory()->anonymous_function_symbol());
3485 }
3486 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003487 Expect(Token::RBRACK, CHECK_OK);
3488 break;
3489 }
3490 case Token::PERIOD: {
3491 Consume(Token::PERIOD);
3492 int pos = scanner().location().beg_pos;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003493 Handle<String> name = ParseIdentifierName(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003494 result =
3495 factory()->NewProperty(result, factory()->NewLiteral(name), pos);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003496 if (fni_ != NULL) fni_->PushLiteralName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003497 break;
3498 }
3499 case Token::LPAREN: {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003500 if ((stack == NULL) || stack->is_empty()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003501 // Consume one of the new prefixes (already parsed).
3502 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003503 int last = stack->pop();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003504 result = factory()->NewCallNew(result, args, last);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003505 break;
3506 }
3507 default:
3508 return result;
3509 }
3510 }
3511}
3512
3513
3514DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
3515 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
3516 // contexts this is used as a statement which invokes the debugger as i a
3517 // break point is present.
3518 // DebuggerStatement ::
3519 // 'debugger' ';'
3520
3521 Expect(Token::DEBUGGER, CHECK_OK);
3522 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003523 return factory()->NewDebuggerStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003524}
3525
3526
3527void Parser::ReportUnexpectedToken(Token::Value token) {
3528 // We don't report stack overflows here, to avoid increasing the
3529 // stack depth even further. Instead we report it after parsing is
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003530 // over, in ParseProgram/ParseJson.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003531 if (token == Token::ILLEGAL && stack_overflow_) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003532 // Four of the tokens are treated specially
3533 switch (token) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003534 case Token::EOS:
3535 return ReportMessage("unexpected_eos", Vector<const char*>::empty());
3536 case Token::NUMBER:
3537 return ReportMessage("unexpected_token_number",
3538 Vector<const char*>::empty());
3539 case Token::STRING:
3540 return ReportMessage("unexpected_token_string",
3541 Vector<const char*>::empty());
3542 case Token::IDENTIFIER:
3543 return ReportMessage("unexpected_token_identifier",
3544 Vector<const char*>::empty());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003545 case Token::FUTURE_RESERVED_WORD:
ager@chromium.org04921a82011-06-27 13:21:41 +00003546 return ReportMessage("unexpected_reserved",
3547 Vector<const char*>::empty());
3548 case Token::FUTURE_STRICT_RESERVED_WORD:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003549 return ReportMessage(top_scope_->is_classic_mode() ?
3550 "unexpected_token_identifier" :
3551 "unexpected_strict_reserved",
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003552 Vector<const char*>::empty());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003553 default:
3554 const char* name = Token::String(token);
3555 ASSERT(name != NULL);
3556 ReportMessage("unexpected_token", Vector<const char*>(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003557 }
3558}
3559
3560
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003561void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003562 SmartArrayPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003563 const char* element[1] = { *name_string };
3564 ReportMessage("invalid_preparser_data",
3565 Vector<const char*>(element, 1));
3566 *ok = false;
3567}
3568
3569
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003570Expression* Parser::ParsePrimaryExpression(bool* ok) {
3571 // PrimaryExpression ::
3572 // 'this'
3573 // 'null'
3574 // 'true'
3575 // 'false'
3576 // Identifier
3577 // Number
3578 // String
3579 // ArrayLiteral
3580 // ObjectLiteral
3581 // RegExpLiteral
3582 // '(' Expression ')'
3583
3584 Expression* result = NULL;
3585 switch (peek()) {
3586 case Token::THIS: {
3587 Consume(Token::THIS);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003588 result = factory()->NewVariableProxy(top_scope_->receiver());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003589 break;
3590 }
3591
3592 case Token::NULL_LITERAL:
3593 Consume(Token::NULL_LITERAL);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003594 result = factory()->NewLiteral(isolate()->factory()->null_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 break;
3596
3597 case Token::TRUE_LITERAL:
3598 Consume(Token::TRUE_LITERAL);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003599 result = factory()->NewLiteral(isolate()->factory()->true_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003600 break;
3601
3602 case Token::FALSE_LITERAL:
3603 Consume(Token::FALSE_LITERAL);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003604 result = factory()->NewLiteral(isolate()->factory()->false_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 break;
3606
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003607 case Token::IDENTIFIER:
ager@chromium.org04921a82011-06-27 13:21:41 +00003608 case Token::FUTURE_STRICT_RESERVED_WORD: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003609 Handle<String> name = ParseIdentifier(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003610 if (fni_ != NULL) fni_->PushVariableName(name);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003611 // The name may refer to a module instance object, so its type is unknown.
3612#ifdef DEBUG
3613 if (FLAG_print_interface_details)
3614 PrintF("# Variable %s ", name->ToAsciiArray());
3615#endif
3616 Interface* interface = Interface::NewUnknown();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003617 result = top_scope_->NewUnresolved(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003618 factory(), name, scanner().location().beg_pos, interface);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003619 break;
3620 }
3621
3622 case Token::NUMBER: {
3623 Consume(Token::NUMBER);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003624 ASSERT(scanner().is_literal_ascii());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003625 double value = StringToDouble(isolate()->unicode_cache(),
3626 scanner().literal_ascii_string(),
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003627 ALLOW_HEX | ALLOW_OCTALS);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003628 result = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 break;
3630 }
3631
3632 case Token::STRING: {
3633 Consume(Token::STRING);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003634 Handle<String> symbol = GetSymbol(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003635 result = factory()->NewLiteral(symbol);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003636 if (fni_ != NULL) fni_->PushLiteralName(symbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003637 break;
3638 }
3639
3640 case Token::ASSIGN_DIV:
3641 result = ParseRegExpLiteral(true, CHECK_OK);
3642 break;
3643
3644 case Token::DIV:
3645 result = ParseRegExpLiteral(false, CHECK_OK);
3646 break;
3647
3648 case Token::LBRACK:
3649 result = ParseArrayLiteral(CHECK_OK);
3650 break;
3651
3652 case Token::LBRACE:
3653 result = ParseObjectLiteral(CHECK_OK);
3654 break;
3655
3656 case Token::LPAREN:
3657 Consume(Token::LPAREN);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003658 // Heuristically try to detect immediately called functions before
3659 // seeing the call parentheses.
3660 parenthesized_function_ = (peek() == Token::FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 result = ParseExpression(true, CHECK_OK);
3662 Expect(Token::RPAREN, CHECK_OK);
3663 break;
3664
3665 case Token::MOD:
3666 if (allow_natives_syntax_ || extension_ != NULL) {
3667 result = ParseV8Intrinsic(CHECK_OK);
3668 break;
3669 }
3670 // If we're not allowing special syntax we fall-through to the
3671 // default case.
3672
3673 default: {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003674 Token::Value tok = Next();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003675 ReportUnexpectedToken(tok);
3676 *ok = false;
3677 return NULL;
3678 }
3679 }
3680
3681 return result;
3682}
3683
3684
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003685void Parser::BuildArrayLiteralBoilerplateLiterals(ZoneList<Expression*>* values,
3686 Handle<FixedArray> literals,
3687 bool* is_simple,
3688 int* depth) {
3689 // Fill in the literals.
3690 // Accumulate output values in local variables.
3691 bool is_simple_acc = true;
3692 int depth_acc = 1;
3693 for (int i = 0; i < values->length(); i++) {
3694 MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
3695 if (m_literal != NULL && m_literal->depth() >= depth_acc) {
3696 depth_acc = m_literal->depth() + 1;
3697 }
3698 Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
3699 if (boilerplate_value->IsUndefined()) {
3700 literals->set_the_hole(i);
3701 is_simple_acc = false;
3702 } else {
3703 literals->set(i, *boilerplate_value);
3704 }
3705 }
3706
3707 *is_simple = is_simple_acc;
3708 *depth = depth_acc;
3709}
3710
3711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712Expression* Parser::ParseArrayLiteral(bool* ok) {
3713 // ArrayLiteral ::
3714 // '[' Expression? (',' Expression?)* ']'
3715
danno@chromium.org40cb8782011-05-25 07:58:50 +00003716 ZoneList<Expression*>* values = new(zone()) ZoneList<Expression*>(4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003717 Expect(Token::LBRACK, CHECK_OK);
3718 while (peek() != Token::RBRACK) {
3719 Expression* elem;
3720 if (peek() == Token::COMMA) {
3721 elem = GetLiteralTheHole();
3722 } else {
3723 elem = ParseAssignmentExpression(true, CHECK_OK);
3724 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003725 values->Add(elem);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726 if (peek() != Token::RBRACK) {
3727 Expect(Token::COMMA, CHECK_OK);
3728 }
3729 }
3730 Expect(Token::RBRACK, CHECK_OK);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003731
3732 // Update the scope information before the pre-parsing bailout.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003733 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003734
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003735 // Allocate a fixed array to hold all the object literals.
3736 Handle<FixedArray> object_literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003737 isolate()->factory()->NewFixedArray(values->length(), TENURED);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003738 Handle<FixedDoubleArray> double_literals;
3739 ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003740 bool has_only_undefined_values = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003741
3742 // Fill in the literals.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003743 bool is_simple = true;
3744 int depth = 1;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003745 for (int i = 0, n = values->length(); i < n; i++) {
3746 MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003747 if (m_literal != NULL && m_literal->depth() + 1 > depth) {
3748 depth = m_literal->depth() + 1;
3749 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003750 Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003751 if (boilerplate_value->IsUndefined()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003752 object_literals->set_the_hole(i);
3753 if (elements_kind == FAST_DOUBLE_ELEMENTS) {
3754 double_literals->set_the_hole(i);
3755 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003756 is_simple = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003757 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003758 // Examine each literal element, and adjust the ElementsKind if the
3759 // literal element is not of a type that can be stored in the current
3760 // ElementsKind. Start with FAST_SMI_ONLY_ELEMENTS, and transition to
3761 // FAST_DOUBLE_ELEMENTS and FAST_ELEMENTS as necessary. Always remember
3762 // the tagged value, no matter what the ElementsKind is in case we
3763 // ultimately end up in FAST_ELEMENTS.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003764 has_only_undefined_values = false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003765 object_literals->set(i, *boilerplate_value);
3766 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
3767 // Smi only elements. Notice if a transition to FAST_DOUBLE_ELEMENTS or
3768 // FAST_ELEMENTS is required.
3769 if (!boilerplate_value->IsSmi()) {
3770 if (boilerplate_value->IsNumber() && FLAG_smi_only_arrays) {
3771 // Allocate a double array on the FAST_DOUBLE_ELEMENTS transition to
3772 // avoid over-allocating in TENURED space.
3773 double_literals = isolate()->factory()->NewFixedDoubleArray(
3774 values->length(), TENURED);
3775 // Copy the contents of the FAST_SMI_ONLY_ELEMENT array to the
3776 // FAST_DOUBLE_ELEMENTS array so that they are in sync.
3777 for (int j = 0; j < i; ++j) {
3778 Object* smi_value = object_literals->get(j);
3779 if (smi_value->IsTheHole()) {
3780 double_literals->set_the_hole(j);
3781 } else {
3782 double_literals->set(j, Smi::cast(smi_value)->value());
3783 }
3784 }
3785 double_literals->set(i, boilerplate_value->Number());
3786 elements_kind = FAST_DOUBLE_ELEMENTS;
3787 } else {
3788 elements_kind = FAST_ELEMENTS;
3789 }
3790 }
3791 } else if (elements_kind == FAST_DOUBLE_ELEMENTS) {
3792 // Continue to store double values in to FAST_DOUBLE_ELEMENTS arrays
3793 // until the first value is seen that can't be stored as a double.
3794 if (boilerplate_value->IsNumber()) {
3795 double_literals->set(i, boilerplate_value->Number());
3796 } else {
3797 elements_kind = FAST_ELEMENTS;
3798 }
3799 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003800 }
3801 }
3802
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003803 // Very small array literals that don't have a concrete hint about their type
3804 // from a constant value should default to the slow case to avoid lots of
3805 // elements transitions on really small objects.
3806 if (has_only_undefined_values && values->length() <= 2) {
3807 elements_kind = FAST_ELEMENTS;
3808 }
3809
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003810 // Simple and shallow arrays can be lazily copied, we transform the
3811 // elements array to a copy-on-write array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003812 if (is_simple && depth == 1 && values->length() > 0 &&
3813 elements_kind != FAST_DOUBLE_ELEMENTS) {
3814 object_literals->set_map(isolate()->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003815 }
3816
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003817 Handle<FixedArrayBase> element_values = elements_kind == FAST_DOUBLE_ELEMENTS
3818 ? Handle<FixedArrayBase>(double_literals)
3819 : Handle<FixedArrayBase>(object_literals);
3820
3821 // Remember both the literal's constant values as well as the ElementsKind
3822 // in a 2-element FixedArray.
3823 Handle<FixedArray> literals =
3824 isolate()->factory()->NewFixedArray(2, TENURED);
3825
3826 literals->set(0, Smi::FromInt(elements_kind));
3827 literals->set(1, *element_values);
3828
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003829 return factory()->NewArrayLiteral(
3830 literals, values, literal_index, is_simple, depth);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003831}
3832
3833
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003834bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) {
3835 return property != NULL &&
3836 property->kind() != ObjectLiteral::Property::PROTOTYPE;
3837}
3838
3839
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003840bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003841 if (expression->AsLiteral() != NULL) return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003842 MaterializedLiteral* lit = expression->AsMaterializedLiteral();
3843 return lit != NULL && lit->is_simple();
3844}
3845
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003846
3847bool CompileTimeValue::ArrayLiteralElementNeedsInitialization(
3848 Expression* value) {
3849 // If value is a literal the property value is already set in the
3850 // boilerplate object.
3851 if (value->AsLiteral() != NULL) return false;
3852 // If value is a materialized literal the property value is already set
3853 // in the boilerplate object if it is simple.
3854 if (CompileTimeValue::IsCompileTimeValue(value)) return false;
3855 return true;
3856}
3857
3858
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003859Handle<FixedArray> CompileTimeValue::GetValue(Expression* expression) {
3860 ASSERT(IsCompileTimeValue(expression));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003861 Handle<FixedArray> result = FACTORY->NewFixedArray(2, TENURED);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003862 ObjectLiteral* object_literal = expression->AsObjectLiteral();
3863 if (object_literal != NULL) {
3864 ASSERT(object_literal->is_simple());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003865 if (object_literal->fast_elements()) {
3866 result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS));
3867 } else {
3868 result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS));
3869 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003870 result->set(kElementsSlot, *object_literal->constant_properties());
3871 } else {
3872 ArrayLiteral* array_literal = expression->AsArrayLiteral();
3873 ASSERT(array_literal != NULL && array_literal->is_simple());
3874 result->set(kTypeSlot, Smi::FromInt(ARRAY_LITERAL));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003875 result->set(kElementsSlot, *array_literal->constant_elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003876 }
3877 return result;
3878}
3879
3880
3881CompileTimeValue::Type CompileTimeValue::GetType(Handle<FixedArray> value) {
3882 Smi* type_value = Smi::cast(value->get(kTypeSlot));
3883 return static_cast<Type>(type_value->value());
3884}
3885
3886
3887Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
3888 return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot)));
3889}
3890
3891
3892Handle<Object> Parser::GetBoilerplateValue(Expression* expression) {
3893 if (expression->AsLiteral() != NULL) {
3894 return expression->AsLiteral()->handle();
3895 }
3896 if (CompileTimeValue::IsCompileTimeValue(expression)) {
3897 return CompileTimeValue::GetValue(expression);
3898 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003899 return isolate()->factory()->undefined_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003900}
3901
ager@chromium.org378b34e2011-01-28 08:04:38 +00003902// Validation per 11.1.5 Object Initialiser
3903class ObjectLiteralPropertyChecker {
3904 public:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003905 ObjectLiteralPropertyChecker(Parser* parser, LanguageMode language_mode) :
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003906 props_(Literal::Match),
ager@chromium.org378b34e2011-01-28 08:04:38 +00003907 parser_(parser),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003908 language_mode_(language_mode) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003909 }
3910
3911 void CheckProperty(
3912 ObjectLiteral::Property* property,
3913 Scanner::Location loc,
3914 bool* ok);
3915
3916 private:
3917 enum PropertyKind {
3918 kGetAccessor = 0x01,
3919 kSetAccessor = 0x02,
3920 kAccessor = kGetAccessor | kSetAccessor,
3921 kData = 0x04
3922 };
3923
3924 static intptr_t GetPropertyKind(ObjectLiteral::Property* property) {
3925 switch (property->kind()) {
3926 case ObjectLiteral::Property::GETTER:
3927 return kGetAccessor;
3928 case ObjectLiteral::Property::SETTER:
3929 return kSetAccessor;
3930 default:
3931 return kData;
3932 }
3933 }
3934
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003935 HashMap props_;
ager@chromium.org378b34e2011-01-28 08:04:38 +00003936 Parser* parser_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003937 LanguageMode language_mode_;
ager@chromium.org378b34e2011-01-28 08:04:38 +00003938};
3939
3940
3941void ObjectLiteralPropertyChecker::CheckProperty(
3942 ObjectLiteral::Property* property,
3943 Scanner::Location loc,
3944 bool* ok) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003945 ASSERT(property != NULL);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003946 Literal* literal = property->key();
3947 HashMap::Entry* entry = props_.Lookup(literal, literal->Hash(), true);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003948 intptr_t prev = reinterpret_cast<intptr_t> (entry->value);
3949 intptr_t curr = GetPropertyKind(property);
3950
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003951 // Duplicate data properties are illegal in strict or extended mode.
3952 if (language_mode_ != CLASSIC_MODE && (curr & prev & kData) != 0) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003953 parser_->ReportMessageAt(loc, "strict_duplicate_property",
3954 Vector<const char*>::empty());
3955 *ok = false;
3956 return;
3957 }
3958 // Data property conflicting with an accessor.
3959 if (((curr & kData) && (prev & kAccessor)) ||
3960 ((prev & kData) && (curr & kAccessor))) {
3961 parser_->ReportMessageAt(loc, "accessor_data_property",
3962 Vector<const char*>::empty());
3963 *ok = false;
3964 return;
3965 }
3966 // Two accessors of the same type conflicting
3967 if ((curr & prev & kAccessor) != 0) {
3968 parser_->ReportMessageAt(loc, "accessor_get_set",
3969 Vector<const char*>::empty());
3970 *ok = false;
3971 return;
3972 }
3973
3974 // Update map
3975 entry->value = reinterpret_cast<void*> (prev | curr);
3976 *ok = true;
3977}
3978
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003979
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003980void Parser::BuildObjectLiteralConstantProperties(
3981 ZoneList<ObjectLiteral::Property*>* properties,
3982 Handle<FixedArray> constant_properties,
3983 bool* is_simple,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003984 bool* fast_elements,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003985 int* depth) {
3986 int position = 0;
3987 // Accumulate the value in local variables and store it at the end.
3988 bool is_simple_acc = true;
3989 int depth_acc = 1;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003990 uint32_t max_element_index = 0;
3991 uint32_t elements = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003992 for (int i = 0; i < properties->length(); i++) {
3993 ObjectLiteral::Property* property = properties->at(i);
3994 if (!IsBoilerplateProperty(property)) {
3995 is_simple_acc = false;
3996 continue;
3997 }
3998 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
3999 if (m_literal != NULL && m_literal->depth() >= depth_acc) {
4000 depth_acc = m_literal->depth() + 1;
4001 }
4002
4003 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
4004 // value for COMPUTED properties, the real value is filled in at
4005 // runtime. The enumeration order is maintained.
4006 Handle<Object> key = property->key()->handle();
4007 Handle<Object> value = GetBoilerplateValue(property->value());
4008 is_simple_acc = is_simple_acc && !value->IsUndefined();
4009
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004010 // Keep track of the number of elements in the object literal and
4011 // the largest element index. If the largest element index is
4012 // much larger than the number of elements, creating an object
4013 // literal with fast elements will be a waste of space.
4014 uint32_t element_index = 0;
4015 if (key->IsString()
4016 && Handle<String>::cast(key)->AsArrayIndex(&element_index)
4017 && element_index > max_element_index) {
4018 max_element_index = element_index;
4019 elements++;
4020 } else if (key->IsSmi()) {
4021 int key_value = Smi::cast(*key)->value();
4022 if (key_value > 0
4023 && static_cast<uint32_t>(key_value) > max_element_index) {
4024 max_element_index = key_value;
4025 }
4026 elements++;
4027 }
4028
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004029 // Add name, value pair to the fixed array.
4030 constant_properties->set(position++, *key);
4031 constant_properties->set(position++, *value);
4032 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004033 *fast_elements =
4034 (max_element_index <= 32) || ((2 * elements) >= max_element_index);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004035 *is_simple = is_simple_acc;
4036 *depth = depth_acc;
4037}
4038
4039
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004040ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter,
4041 bool* ok) {
4042 // Special handling of getter and setter syntax:
4043 // { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... }
4044 // We have already read the "get" or "set" keyword.
4045 Token::Value next = Next();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004046 bool is_keyword = Token::IsKeyword(next);
4047 if (next == Token::IDENTIFIER || next == Token::NUMBER ||
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004048 next == Token::FUTURE_RESERVED_WORD ||
ager@chromium.org04921a82011-06-27 13:21:41 +00004049 next == Token::FUTURE_STRICT_RESERVED_WORD ||
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004050 next == Token::STRING || is_keyword) {
4051 Handle<String> name;
4052 if (is_keyword) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004053 name = isolate_->factory()->LookupAsciiSymbol(Token::String(next));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004054 } else {
4055 name = GetSymbol(CHECK_OK);
4056 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004057 FunctionLiteral* value =
4058 ParseFunctionLiteral(name,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004059 false, // reserved words are allowed here
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004060 RelocInfo::kNoPosition,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004061 FunctionLiteral::ANONYMOUS_EXPRESSION,
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004062 CHECK_OK);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004063 // Allow any number of parameters for compatibilty with JSC.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004064 // Specification only allows zero parameters for get and one for set.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004065 return factory()->NewObjectLiteralProperty(is_getter, value);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004066 } else {
4067 ReportUnexpectedToken(next);
4068 *ok = false;
4069 return NULL;
4070 }
4071}
4072
4073
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074Expression* Parser::ParseObjectLiteral(bool* ok) {
4075 // ObjectLiteral ::
4076 // '{' (
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004077 // ((IdentifierName | String | Number) ':' AssignmentExpression)
4078 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 // )*[','] '}'
4080
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004081 ZoneList<ObjectLiteral::Property*>* properties =
danno@chromium.org40cb8782011-05-25 07:58:50 +00004082 new(zone()) ZoneList<ObjectLiteral::Property*>(4);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004083 int number_of_boilerplate_properties = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004084 bool has_function = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004085
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004086 ObjectLiteralPropertyChecker checker(this, top_scope_->language_mode());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004087
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 Expect(Token::LBRACE, CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004089
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090 while (peek() != Token::RBRACE) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004091 if (fni_ != NULL) fni_->Enter();
4092
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093 Literal* key = NULL;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004094 Token::Value next = peek();
ager@chromium.org378b34e2011-01-28 08:04:38 +00004095
4096 // Location of the property name token
4097 Scanner::Location loc = scanner().peek_location();
4098
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004099 switch (next) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004100 case Token::FUTURE_RESERVED_WORD:
ager@chromium.org04921a82011-06-27 13:21:41 +00004101 case Token::FUTURE_STRICT_RESERVED_WORD:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 case Token::IDENTIFIER: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103 bool is_getter = false;
4104 bool is_setter = false;
4105 Handle<String> id =
ager@chromium.org04921a82011-06-27 13:21:41 +00004106 ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004107 if (fni_ != NULL) fni_->PushLiteralName(id);
4108
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004109 if ((is_getter || is_setter) && peek() != Token::COLON) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00004110 // Update loc to point to the identifier
4111 loc = scanner().peek_location();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 ObjectLiteral::Property* property =
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004113 ParseObjectLiteralGetSet(is_getter, CHECK_OK);
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004114 if (IsBoilerplateProperty(property)) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004115 number_of_boilerplate_properties++;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004116 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004117 // Validate the property.
4118 checker.CheckProperty(property, loc, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004119 properties->Add(property);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120 if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004121
4122 if (fni_ != NULL) {
4123 fni_->Infer();
4124 fni_->Leave();
4125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126 continue; // restart the while
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004128 // Failed to parse as get/set property, so it's just a property
4129 // called "get" or "set".
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004130 key = factory()->NewLiteral(id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004131 break;
4132 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133 case Token::STRING: {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004134 Consume(Token::STRING);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004135 Handle<String> string = GetSymbol(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004136 if (fni_ != NULL) fni_->PushLiteralName(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004137 uint32_t index;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00004138 if (!string.is_null() && string->AsArrayIndex(&index)) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004139 key = factory()->NewNumberLiteral(index);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004140 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004142 key = factory()->NewLiteral(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143 break;
4144 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004145 case Token::NUMBER: {
4146 Consume(Token::NUMBER);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004147 ASSERT(scanner().is_literal_ascii());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004148 double value = StringToDouble(isolate()->unicode_cache(),
4149 scanner().literal_ascii_string(),
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004150 ALLOW_HEX | ALLOW_OCTALS);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004151 key = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 break;
4153 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004154 default:
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004155 if (Token::IsKeyword(next)) {
4156 Consume(next);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004157 Handle<String> string = GetSymbol(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004158 key = factory()->NewLiteral(string);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004159 } else {
4160 // Unexpected token.
4161 Token::Value next = Next();
4162 ReportUnexpectedToken(next);
4163 *ok = false;
4164 return NULL;
4165 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166 }
4167
4168 Expect(Token::COLON, CHECK_OK);
4169 Expression* value = ParseAssignmentExpression(true, CHECK_OK);
4170
4171 ObjectLiteral::Property* property =
ulan@chromium.org812308e2012-02-29 15:58:45 +00004172 new(zone()) ObjectLiteral::Property(key, value, isolate());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004173
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00004174 // Mark top-level object literals that contain function literals and
4175 // pretenure the literal so it can be added as a constant function
4176 // property.
4177 if (top_scope_->DeclarationScope()->is_global_scope() &&
4178 value->AsFunctionLiteral() != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004179 has_function = true;
danno@chromium.orgc612e022011-11-10 11:38:15 +00004180 value->AsFunctionLiteral()->set_pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004181 }
4182
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004183 // Count CONSTANT or COMPUTED properties to maintain the enumeration order.
ager@chromium.org236ad962008-09-25 09:45:57 +00004184 if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++;
ager@chromium.org378b34e2011-01-28 08:04:38 +00004185 // Validate the property
4186 checker.CheckProperty(property, loc, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004187 properties->Add(property);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188
4189 // TODO(1240767): Consider allowing trailing comma.
4190 if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004191
4192 if (fni_ != NULL) {
4193 fni_->Infer();
4194 fni_->Leave();
4195 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004196 }
4197 Expect(Token::RBRACE, CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004198
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004199 // Computation of literal_index must happen before pre parse bailout.
danno@chromium.orgc612e022011-11-10 11:38:15 +00004200 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004202 Handle<FixedArray> constant_properties = isolate()->factory()->NewFixedArray(
4203 number_of_boilerplate_properties * 2, TENURED);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004204
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004205 bool is_simple = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004206 bool fast_elements = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004207 int depth = 1;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004208 BuildObjectLiteralConstantProperties(properties,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004209 constant_properties,
4210 &is_simple,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004211 &fast_elements,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004212 &depth);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004213 return factory()->NewObjectLiteral(constant_properties,
4214 properties,
4215 literal_index,
4216 is_simple,
4217 fast_elements,
4218 depth,
4219 has_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220}
4221
4222
4223Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004224 if (!scanner().ScanRegExpPattern(seen_equal)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225 Next();
4226 ReportMessage("unterminated_regexp", Vector<const char*>::empty());
4227 *ok = false;
4228 return NULL;
4229 }
4230
danno@chromium.orgc612e022011-11-10 11:38:15 +00004231 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004233 Handle<String> js_pattern = NextLiteralString(TENURED);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004234 scanner().ScanRegExpFlags();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004235 Handle<String> js_flags = NextLiteralString(TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004236 Next();
4237
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004238 return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004239}
4240
4241
4242ZoneList<Expression*>* Parser::ParseArguments(bool* ok) {
4243 // Arguments ::
4244 // '(' (AssignmentExpression)*[','] ')'
4245
danno@chromium.org40cb8782011-05-25 07:58:50 +00004246 ZoneList<Expression*>* result = new(zone()) ZoneList<Expression*>(4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004247 Expect(Token::LPAREN, CHECK_OK);
4248 bool done = (peek() == Token::RPAREN);
4249 while (!done) {
4250 Expression* argument = ParseAssignmentExpression(true, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004251 result->Add(argument);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004252 if (result->length() > kMaxNumFunctionParameters) {
4253 ReportMessageAt(scanner().location(), "too_many_arguments",
4254 Vector<const char*>::empty());
4255 *ok = false;
4256 return NULL;
4257 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004258 done = (peek() == Token::RPAREN);
4259 if (!done) Expect(Token::COMMA, CHECK_OK);
4260 }
4261 Expect(Token::RPAREN, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004262 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004263}
4264
4265
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004266class SingletonLogger : public ParserRecorder {
4267 public:
4268 SingletonLogger() : has_error_(false), start_(-1), end_(-1) { }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004269 virtual ~SingletonLogger() { }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004270
4271 void Reset() { has_error_ = false; }
4272
4273 virtual void LogFunction(int start,
4274 int end,
4275 int literals,
4276 int properties,
4277 LanguageMode mode) {
4278 ASSERT(!has_error_);
4279 start_ = start;
4280 end_ = end;
4281 literals_ = literals;
4282 properties_ = properties;
4283 mode_ = mode;
4284 };
4285
4286 // Logs a symbol creation of a literal or identifier.
4287 virtual void LogAsciiSymbol(int start, Vector<const char> literal) { }
4288 virtual void LogUC16Symbol(int start, Vector<const uc16> literal) { }
4289
4290 // Logs an error message and marks the log as containing an error.
4291 // Further logging will be ignored, and ExtractData will return a vector
4292 // representing the error only.
4293 virtual void LogMessage(int start,
4294 int end,
4295 const char* message,
4296 const char* argument_opt) {
4297 has_error_ = true;
4298 start_ = start;
4299 end_ = end;
4300 message_ = message;
4301 argument_opt_ = argument_opt;
4302 }
4303
4304 virtual int function_position() { return 0; }
4305
4306 virtual int symbol_position() { return 0; }
4307
4308 virtual int symbol_ids() { return -1; }
4309
4310 virtual Vector<unsigned> ExtractData() {
4311 UNREACHABLE();
4312 return Vector<unsigned>();
4313 }
4314
4315 virtual void PauseRecording() { }
4316
4317 virtual void ResumeRecording() { }
4318
4319 bool has_error() { return has_error_; }
4320
4321 int start() { return start_; }
4322 int end() { return end_; }
4323 int literals() {
4324 ASSERT(!has_error_);
4325 return literals_;
4326 }
4327 int properties() {
4328 ASSERT(!has_error_);
4329 return properties_;
4330 }
4331 LanguageMode language_mode() {
4332 ASSERT(!has_error_);
4333 return mode_;
4334 }
4335 const char* message() {
4336 ASSERT(has_error_);
4337 return message_;
4338 }
4339 const char* argument_opt() {
4340 ASSERT(has_error_);
4341 return argument_opt_;
4342 }
4343
4344 private:
4345 bool has_error_;
4346 int start_;
4347 int end_;
4348 // For function entries.
4349 int literals_;
4350 int properties_;
4351 LanguageMode mode_;
4352 // For error messages.
4353 const char* message_;
4354 const char* argument_opt_;
4355};
4356
4357
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004358FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
ager@chromium.org04921a82011-06-27 13:21:41 +00004359 bool name_is_strict_reserved,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004360 int function_token_position,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004361 FunctionLiteral::Type type,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004362 bool* ok) {
4363 // Function ::
4364 // '(' FormalParameterList? ')' '{' FunctionBody '}'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004365
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004366 // Anonymous functions were passed either the empty symbol or a null
4367 // handle as the function name. Remember if we were passed a non-empty
4368 // handle to decide whether to invoke function name inference.
4369 bool should_infer_name = function_name.is_null();
4370
4371 // We want a non-null handle as the function name.
4372 if (should_infer_name) {
4373 function_name = isolate()->factory()->empty_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004374 }
4375
4376 int num_parameters = 0;
danno@chromium.orgb6451162011-08-17 14:33:23 +00004377 // Function declarations are function scoped in normal mode, so they are
4378 // hoisted. In harmony block scoping mode they are block scoped, so they
4379 // are not hoisted.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004380 Scope* scope = (type == FunctionLiteral::DECLARATION && !is_extended_mode())
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004381 ? NewScope(top_scope_->DeclarationScope(), FUNCTION_SCOPE)
4382 : NewScope(top_scope_, FUNCTION_SCOPE);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004383 ZoneList<Statement*>* body = NULL;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004384 int materialized_literal_count = -1;
4385 int expected_property_count = -1;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004386 int handler_count = 0;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004387 bool only_simple_this_property_assignments;
4388 Handle<FixedArray> this_property_assignments;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004389 FunctionLiteral::ParameterFlag duplicate_parameters =
4390 FunctionLiteral::kNoDuplicateParameters;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004391 AstProperties ast_properties;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004392 // Parse function body.
danno@chromium.orgc612e022011-11-10 11:38:15 +00004393 { FunctionState function_state(this, scope, isolate());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004394 top_scope_->SetScopeName(function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004395
4396 // FormalParameterList ::
4397 // '(' (Identifier)*[','] ')'
4398 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004399 scope->set_start_position(scanner().location().beg_pos);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004400 Scanner::Location name_loc = Scanner::Location::invalid();
4401 Scanner::Location dupe_loc = Scanner::Location::invalid();
4402 Scanner::Location reserved_loc = Scanner::Location::invalid();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004403
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004404 bool done = (peek() == Token::RPAREN);
4405 while (!done) {
ager@chromium.org04921a82011-06-27 13:21:41 +00004406 bool is_strict_reserved = false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004407 Handle<String> param_name =
ager@chromium.org04921a82011-06-27 13:21:41 +00004408 ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
4409 CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004410
4411 // Store locations for possible future error reports.
4412 if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) {
4413 name_loc = scanner().location();
4414 }
4415 if (!dupe_loc.IsValid() && top_scope_->IsDeclared(param_name)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004416 duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
ager@chromium.org378b34e2011-01-28 08:04:38 +00004417 dupe_loc = scanner().location();
4418 }
ager@chromium.org04921a82011-06-27 13:21:41 +00004419 if (!reserved_loc.IsValid() && is_strict_reserved) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004420 reserved_loc = scanner().location();
4421 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004422
yangguo@chromium.org56454712012-02-16 15:33:53 +00004423 top_scope_->DeclareParameter(param_name, VAR);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004424 num_parameters++;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004425 if (num_parameters > kMaxNumFunctionParameters) {
4426 ReportMessageAt(scanner().location(), "too_many_parameters",
4427 Vector<const char*>::empty());
4428 *ok = false;
4429 return NULL;
4430 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431 done = (peek() == Token::RPAREN);
4432 if (!done) Expect(Token::COMMA, CHECK_OK);
4433 }
4434 Expect(Token::RPAREN, CHECK_OK);
4435
4436 Expect(Token::LBRACE, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004437
4438 // If we have a named function expression, we add a local variable
4439 // declaration to the body of the function with the name of the
4440 // function and let it refer to the function itself (closure).
4441 // NOTE: We create a proxy and resolve it here so that in the
4442 // future we can change the AST to only refer to VariableProxies
4443 // instead of Variables and Proxis as is the case now.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004444 Variable* fvar = NULL;
4445 Token::Value fvar_init_op = Token::INIT_CONST;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004446 if (type == FunctionLiteral::NAMED_EXPRESSION) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004447 VariableMode fvar_mode;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004448 if (is_extended_mode()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004449 fvar_mode = CONST_HARMONY;
4450 fvar_init_op = Token::INIT_CONST_HARMONY;
4451 } else {
4452 fvar_mode = CONST;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004453 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004454 fvar =
4455 top_scope_->DeclareFunctionVar(function_name, fvar_mode, factory());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004456 }
4457
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004458 // Determine whether the function will be lazily compiled.
4459 // The heuristics are:
4460 // - It must not have been prohibited by the caller to Parse (some callers
4461 // need a full AST).
4462 // - The outer scope must be trivial (only global variables in scope).
4463 // - The function mustn't be a function expression with an open parenthesis
4464 // before; we consider that a hint that the function will be called
4465 // immediately, and it would be a waste of time to make it lazily
4466 // compiled.
4467 // These are all things we can know at this point, without looking at the
4468 // function itself.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004469 bool is_lazily_compiled = (mode() == PARSE_LAZILY &&
4470 top_scope_->outer_scope()->is_global_scope() &&
4471 top_scope_->HasTrivialOuterContext() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004472 !parenthesized_function_);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004473 parenthesized_function_ = false; // The bit was set for this function only.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004474
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004475 if (is_lazily_compiled) {
4476 int function_block_pos = scanner().location().beg_pos;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004477 FunctionEntry entry;
4478 if (pre_data_ != NULL) {
4479 // If we have pre_data_, we use it to skip parsing the function body.
4480 // the preparser data contains the information we need to construct the
4481 // lazy function.
4482 entry = pre_data()->GetFunctionEntry(function_block_pos);
4483 if (entry.is_valid()) {
4484 if (entry.end_pos() <= function_block_pos) {
4485 // End position greater than end of stream is safe, and hard
4486 // to check.
4487 ReportInvalidPreparseData(function_name, CHECK_OK);
4488 }
4489 scanner().SeekForward(entry.end_pos() - 1);
4490
4491 scope->set_end_position(entry.end_pos());
4492 Expect(Token::RBRACE, CHECK_OK);
4493 isolate()->counters()->total_preparse_skipped()->Increment(
4494 scope->end_position() - function_block_pos);
4495 materialized_literal_count = entry.literal_count();
4496 expected_property_count = entry.property_count();
4497 top_scope_->SetLanguageMode(entry.language_mode());
4498 only_simple_this_property_assignments = false;
4499 this_property_assignments = isolate()->factory()->empty_fixed_array();
4500 } else {
4501 is_lazily_compiled = false;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004502 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004503 } else {
4504 // With no preparser data, we partially parse the function, without
4505 // building an AST. This gathers the data needed to build a lazy
4506 // function.
4507 SingletonLogger logger;
4508 preparser::PreParser::PreParseResult result =
4509 LazyParseFunctionLiteral(&logger);
4510 if (result == preparser::PreParser::kPreParseStackOverflow) {
4511 // Propagate stack overflow.
4512 stack_overflow_ = true;
4513 *ok = false;
4514 return NULL;
4515 }
4516 if (logger.has_error()) {
4517 const char* arg = logger.argument_opt();
4518 Vector<const char*> args;
4519 if (arg != NULL) {
4520 args = Vector<const char*>(&arg, 1);
4521 }
4522 ReportMessageAt(Scanner::Location(logger.start(), logger.end()),
4523 logger.message(), args);
4524 *ok = false;
4525 return NULL;
4526 }
4527 scope->set_end_position(logger.end());
4528 Expect(Token::RBRACE, CHECK_OK);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004529 isolate()->counters()->total_preparse_skipped()->Increment(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004530 scope->end_position() - function_block_pos);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004531 materialized_literal_count = logger.literals();
4532 expected_property_count = logger.properties();
4533 top_scope_->SetLanguageMode(logger.language_mode());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004534 only_simple_this_property_assignments = false;
4535 this_property_assignments = isolate()->factory()->empty_fixed_array();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004536 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004537 }
4538
4539 if (!is_lazily_compiled) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004540 body = new(zone()) ZoneList<Statement*>(8);
4541 if (fvar != NULL) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004542 VariableProxy* fproxy =
4543 top_scope_->NewUnresolved(factory(), function_name);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004544 fproxy->BindTo(fvar);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004545 body->Add(factory()->NewExpressionStatement(
4546 factory()->NewAssignment(fvar_init_op,
4547 fproxy,
4548 factory()->NewThisFunction(),
4549 RelocInfo::kNoPosition)));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004550 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004551 ParseSourceElements(body, Token::RBRACE, CHECK_OK);
4552
danno@chromium.orgc612e022011-11-10 11:38:15 +00004553 materialized_literal_count = function_state.materialized_literal_count();
4554 expected_property_count = function_state.expected_property_count();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004555 handler_count = function_state.handler_count();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004556 only_simple_this_property_assignments =
danno@chromium.orgc612e022011-11-10 11:38:15 +00004557 function_state.only_simple_this_property_assignments();
4558 this_property_assignments = function_state.this_property_assignments();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004559
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004560 Expect(Token::RBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004561 scope->set_end_position(scanner().location().end_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 }
4563
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004564 // Validate strict mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004565 if (!top_scope_->is_classic_mode()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004566 if (IsEvalOrArguments(function_name)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004567 int start_pos = scope->start_position();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004568 int position = function_token_position != RelocInfo::kNoPosition
ager@chromium.org378b34e2011-01-28 08:04:38 +00004569 ? function_token_position
4570 : (start_pos > 0 ? start_pos - 1 : start_pos);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004571 Scanner::Location location = Scanner::Location(position, start_pos);
4572 ReportMessageAt(location,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004573 "strict_function_name", Vector<const char*>::empty());
4574 *ok = false;
4575 return NULL;
4576 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004577 if (name_loc.IsValid()) {
4578 ReportMessageAt(name_loc, "strict_param_name",
4579 Vector<const char*>::empty());
4580 *ok = false;
4581 return NULL;
4582 }
4583 if (dupe_loc.IsValid()) {
4584 ReportMessageAt(dupe_loc, "strict_param_dupe",
4585 Vector<const char*>::empty());
4586 *ok = false;
4587 return NULL;
4588 }
ager@chromium.org04921a82011-06-27 13:21:41 +00004589 if (name_is_strict_reserved) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004590 int start_pos = scope->start_position();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004591 int position = function_token_position != RelocInfo::kNoPosition
4592 ? function_token_position
4593 : (start_pos > 0 ? start_pos - 1 : start_pos);
4594 Scanner::Location location = Scanner::Location(position, start_pos);
4595 ReportMessageAt(location, "strict_reserved_word",
4596 Vector<const char*>::empty());
4597 *ok = false;
4598 return NULL;
4599 }
4600 if (reserved_loc.IsValid()) {
4601 ReportMessageAt(reserved_loc, "strict_reserved_word",
4602 Vector<const char*>::empty());
4603 *ok = false;
4604 return NULL;
4605 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004606 CheckOctalLiteral(scope->start_position(),
4607 scope->end_position(),
4608 CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004609 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004610 ast_properties = *factory()->visitor()->ast_properties();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004611 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004612
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004613 if (is_extended_mode()) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004614 CheckConflictingVarDeclarations(scope, CHECK_OK);
4615 }
4616
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004617 FunctionLiteral* function_literal =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004618 factory()->NewFunctionLiteral(function_name,
4619 scope,
4620 body,
4621 materialized_literal_count,
4622 expected_property_count,
4623 handler_count,
4624 only_simple_this_property_assignments,
4625 this_property_assignments,
4626 num_parameters,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004627 duplicate_parameters,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004628 type,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004629 FunctionLiteral::kIsFunction);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004630 function_literal->set_function_token_position(function_token_position);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004631 function_literal->set_ast_properties(&ast_properties);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004632
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004633 if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004634 return function_literal;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004635}
4636
4637
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004638preparser::PreParser::PreParseResult Parser::LazyParseFunctionLiteral(
4639 SingletonLogger* logger) {
4640 HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse());
4641 ASSERT_EQ(Token::LBRACE, scanner().current_token());
4642
4643 if (reusable_preparser_ == NULL) {
4644 intptr_t stack_limit = isolate()->stack_guard()->real_climit();
4645 bool do_allow_lazy = true;
4646 reusable_preparser_ = new preparser::PreParser(&scanner_,
4647 NULL,
4648 stack_limit,
4649 do_allow_lazy,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00004650 allow_natives_syntax_,
4651 allow_modules_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004652 }
4653 preparser::PreParser::PreParseResult result =
4654 reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(),
4655 logger);
4656 return result;
4657}
4658
4659
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004660Expression* Parser::ParseV8Intrinsic(bool* ok) {
4661 // CallRuntime ::
4662 // '%' Identifier Arguments
4663
4664 Expect(Token::MOD, CHECK_OK);
4665 Handle<String> name = ParseIdentifier(CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004666 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004667
4668 if (extension_ != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669 // The extension structures are only accessible while parsing the
4670 // very first time not when reparsing because of lazy compilation.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004671 top_scope_->DeclarationScope()->ForceEagerCompilation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004672 }
4673
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004674 const Runtime::Function* function = Runtime::FunctionForSymbol(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004675
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004676 // Check for built-in IS_VAR macro.
4677 if (function != NULL &&
4678 function->intrinsic_type == Runtime::RUNTIME &&
4679 function->function_id == Runtime::kIS_VAR) {
4680 // %IS_VAR(x) evaluates to x if x is a variable,
4681 // leads to a parse error otherwise. Could be implemented as an
4682 // inline function %_IS_VAR(x) to eliminate this special case.
4683 if (args->length() == 1 && args->at(0)->AsVariableProxy() != NULL) {
4684 return args->at(0);
4685 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004686 ReportMessage("unable_to_parse", Vector<const char*>::empty());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004687 *ok = false;
4688 return NULL;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004689 }
4690 }
4691
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004692 // Check that the expected number of arguments are being passed.
4693 if (function != NULL &&
4694 function->nargs != -1 &&
4695 function->nargs != args->length()) {
4696 ReportMessage("illegal_access", Vector<const char*>::empty());
4697 *ok = false;
4698 return NULL;
4699 }
4700
4701 // We have a valid intrinsics call or a call to a builtin.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004702 return factory()->NewCallRuntime(name, function, args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703}
4704
4705
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004706bool Parser::peek_any_identifier() {
4707 Token::Value next = peek();
4708 return next == Token::IDENTIFIER ||
ager@chromium.org04921a82011-06-27 13:21:41 +00004709 next == Token::FUTURE_RESERVED_WORD ||
4710 next == Token::FUTURE_STRICT_RESERVED_WORD;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004711}
4712
4713
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714void Parser::Consume(Token::Value token) {
4715 Token::Value next = Next();
4716 USE(next);
4717 USE(token);
4718 ASSERT(next == token);
4719}
4720
4721
4722void Parser::Expect(Token::Value token, bool* ok) {
4723 Token::Value next = Next();
4724 if (next == token) return;
4725 ReportUnexpectedToken(next);
4726 *ok = false;
4727}
4728
4729
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004730bool Parser::Check(Token::Value token) {
4731 Token::Value next = peek();
4732 if (next == token) {
4733 Consume(next);
4734 return true;
4735 }
4736 return false;
4737}
4738
4739
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004740void Parser::ExpectSemicolon(bool* ok) {
4741 // Check for automatic semicolon insertion according to
4742 // the rules given in ECMA-262, section 7.9, page 21.
4743 Token::Value tok = peek();
4744 if (tok == Token::SEMICOLON) {
4745 Next();
4746 return;
4747 }
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00004748 if (scanner().HasAnyLineTerminatorBeforeNext() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004749 tok == Token::RBRACE ||
4750 tok == Token::EOS) {
4751 return;
4752 }
4753 Expect(Token::SEMICOLON, ok);
4754}
4755
4756
ulan@chromium.org812308e2012-02-29 15:58:45 +00004757void Parser::ExpectContextualKeyword(const char* keyword, bool* ok) {
4758 Expect(Token::IDENTIFIER, ok);
4759 if (!*ok) return;
4760 Handle<String> symbol = GetSymbol(ok);
4761 if (!*ok) return;
4762 if (!symbol->IsEqualTo(CStrVector(keyword))) {
4763 *ok = false;
4764 ReportUnexpectedToken(scanner().current_token());
4765 }
4766}
4767
4768
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769Literal* Parser::GetLiteralUndefined() {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004770 return factory()->NewLiteral(isolate()->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004771}
4772
4773
4774Literal* Parser::GetLiteralTheHole() {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004775 return factory()->NewLiteral(isolate()->factory()->the_hole_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776}
4777
4778
danno@chromium.orgb6451162011-08-17 14:33:23 +00004779// Parses an identifier that is valid for the current scope, in particular it
ager@chromium.org04921a82011-06-27 13:21:41 +00004780// fails on strict mode future reserved keywords in a strict scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781Handle<String> Parser::ParseIdentifier(bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004782 if (!top_scope_->is_classic_mode()) {
ager@chromium.org04921a82011-06-27 13:21:41 +00004783 Expect(Token::IDENTIFIER, ok);
4784 } else if (!Check(Token::IDENTIFIER)) {
4785 Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
4786 }
4787 if (!*ok) return Handle<String>();
4788 return GetSymbol(ok);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004789}
4790
4791
ager@chromium.org04921a82011-06-27 13:21:41 +00004792// Parses and identifier or a strict mode future reserved word, and indicate
4793// whether it is strict mode future reserved.
4794Handle<String> Parser::ParseIdentifierOrStrictReservedWord(
4795 bool* is_strict_reserved, bool* ok) {
4796 *is_strict_reserved = false;
4797 if (!Check(Token::IDENTIFIER)) {
4798 Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
4799 *is_strict_reserved = true;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004800 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004801 if (!*ok) return Handle<String>();
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004802 return GetSymbol(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004803}
4804
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004805
4806Handle<String> Parser::ParseIdentifierName(bool* ok) {
4807 Token::Value next = Next();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004808 if (next != Token::IDENTIFIER &&
ager@chromium.org04921a82011-06-27 13:21:41 +00004809 next != Token::FUTURE_RESERVED_WORD &&
4810 next != Token::FUTURE_STRICT_RESERVED_WORD &&
4811 !Token::IsKeyword(next)) {
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004812 ReportUnexpectedToken(next);
4813 *ok = false;
4814 return Handle<String>();
4815 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004816 return GetSymbol(ok);
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004817}
4818
ager@chromium.org378b34e2011-01-28 08:04:38 +00004819
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004820void Parser::MarkAsLValue(Expression* expression) {
4821 VariableProxy* proxy = expression != NULL
4822 ? expression->AsVariableProxy()
4823 : NULL;
4824
4825 if (proxy != NULL) proxy->MarkAsLValue();
4826}
4827
4828
ager@chromium.org378b34e2011-01-28 08:04:38 +00004829// Checks LHS expression for assignment and prefix/postfix increment/decrement
4830// in strict mode.
4831void Parser::CheckStrictModeLValue(Expression* expression,
4832 const char* error,
4833 bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004834 ASSERT(!top_scope_->is_classic_mode());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004835 VariableProxy* lhs = expression != NULL
4836 ? expression->AsVariableProxy()
4837 : NULL;
4838
4839 if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
4840 ReportMessage(error, Vector<const char*>::empty());
4841 *ok = false;
4842 }
4843}
4844
4845
lrn@chromium.org1c092762011-05-09 09:42:16 +00004846// Checks whether an octal literal was last seen between beg_pos and end_pos.
4847// If so, reports an error. Only called for strict mode.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004848void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00004849 Scanner::Location octal = scanner().octal_position();
4850 if (octal.IsValid() &&
4851 beg_pos <= octal.beg_pos &&
4852 octal.end_pos <= end_pos) {
4853 ReportMessageAt(octal, "strict_octal_literal",
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004854 Vector<const char*>::empty());
4855 scanner().clear_octal_position();
4856 *ok = false;
4857 }
4858}
4859
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004860
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004861void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
4862 Declaration* decl = scope->CheckConflictingVarDeclarations();
4863 if (decl != NULL) {
4864 // In harmony mode we treat conflicting variable bindinds as early
4865 // errors. See ES5 16 for a definition of early errors.
4866 Handle<String> name = decl->proxy()->name();
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004867 SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004868 const char* elms[2] = { "Variable", *c_string };
4869 Vector<const char*> args(elms, 2);
4870 int position = decl->proxy()->position();
4871 Scanner::Location location = position == RelocInfo::kNoPosition
4872 ? Scanner::Location::invalid()
4873 : Scanner::Location(position, position + 1);
4874 ReportMessageAt(location, "redeclaration", args);
4875 *ok = false;
4876 }
4877}
4878
4879
ager@chromium.org04921a82011-06-27 13:21:41 +00004880// This function reads an identifier name and determines whether or not it
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004881// is 'get' or 'set'.
ager@chromium.org04921a82011-06-27 13:21:41 +00004882Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get,
4883 bool* is_set,
4884 bool* ok) {
4885 Handle<String> result = ParseIdentifierName(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004886 if (!*ok) return Handle<String>();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004887 if (scanner().is_literal_ascii() && scanner().literal_length() == 3) {
4888 const char* token = scanner().literal_ascii_string().start();
4889 *is_get = strncmp(token, "get", 3) == 0;
4890 *is_set = !*is_get && strncmp(token, "set", 3) == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004891 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004892 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893}
4894
4895
4896// ----------------------------------------------------------------------------
4897// Parser support
4898
4899
4900bool Parser::TargetStackContainsLabel(Handle<String> label) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004901 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
4902 BreakableStatement* stat = t->node()->AsBreakableStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004903 if (stat != NULL && ContainsLabel(stat->labels(), label))
4904 return true;
4905 }
4906 return false;
4907}
4908
4909
4910BreakableStatement* Parser::LookupBreakTarget(Handle<String> label, bool* ok) {
4911 bool anonymous = label.is_null();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004912 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
4913 BreakableStatement* stat = t->node()->AsBreakableStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004914 if (stat == NULL) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004915 if ((anonymous && stat->is_target_for_anonymous()) ||
4916 (!anonymous && ContainsLabel(stat->labels(), label))) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004917 RegisterTargetUse(stat->break_target(), t->previous());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004918 return stat;
4919 }
4920 }
4921 return NULL;
4922}
4923
4924
4925IterationStatement* Parser::LookupContinueTarget(Handle<String> label,
4926 bool* ok) {
4927 bool anonymous = label.is_null();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004928 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
4929 IterationStatement* stat = t->node()->AsIterationStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004930 if (stat == NULL) continue;
4931
4932 ASSERT(stat->is_target_for_anonymous());
4933 if (anonymous || ContainsLabel(stat->labels(), label)) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004934 RegisterTargetUse(stat->continue_target(), t->previous());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004935 return stat;
4936 }
4937 }
4938 return NULL;
4939}
4940
4941
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004942void Parser::RegisterTargetUse(Label* target, Target* stop) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004943 // Register that a break target found at the given stop in the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004944 // target stack has been used from the top of the target stack. Add
4945 // the break target to any TargetCollectors passed on the stack.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004946 for (Target* t = target_stack_; t != stop; t = t->previous()) {
4947 TargetCollector* collector = t->node()->AsTargetCollector();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004948 if (collector != NULL) collector->AddTarget(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004949 }
4950}
4951
4952
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004953Expression* Parser::NewThrowReferenceError(Handle<String> type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004954 return NewThrowError(isolate()->factory()->MakeReferenceError_symbol(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004955 type, HandleVector<Object>(NULL, 0));
4956}
4957
4958
4959Expression* Parser::NewThrowSyntaxError(Handle<String> type,
4960 Handle<Object> first) {
4961 int argc = first.is_null() ? 0 : 1;
4962 Vector< Handle<Object> > arguments = HandleVector<Object>(&first, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004963 return NewThrowError(
4964 isolate()->factory()->MakeSyntaxError_symbol(), type, arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004965}
4966
4967
4968Expression* Parser::NewThrowTypeError(Handle<String> type,
4969 Handle<Object> first,
4970 Handle<Object> second) {
4971 ASSERT(!first.is_null() && !second.is_null());
4972 Handle<Object> elements[] = { first, second };
4973 Vector< Handle<Object> > arguments =
4974 HandleVector<Object>(elements, ARRAY_SIZE(elements));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004975 return NewThrowError(
4976 isolate()->factory()->MakeTypeError_symbol(), type, arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004977}
4978
4979
4980Expression* Parser::NewThrowError(Handle<String> constructor,
4981 Handle<String> type,
4982 Vector< Handle<Object> > arguments) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004983 int argc = arguments.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004984 Handle<FixedArray> elements = isolate()->factory()->NewFixedArray(argc,
4985 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004986 for (int i = 0; i < argc; i++) {
4987 Handle<Object> element = arguments[i];
4988 if (!element.is_null()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004989 elements->set(i, *element);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990 }
4991 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004992 Handle<JSArray> array = isolate()->factory()->NewJSArrayWithElements(
4993 elements, FAST_ELEMENTS, TENURED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004994
danno@chromium.org40cb8782011-05-25 07:58:50 +00004995 ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004996 args->Add(factory()->NewLiteral(type));
4997 args->Add(factory()->NewLiteral(array));
4998 CallRuntime* call_constructor =
4999 factory()->NewCallRuntime(constructor, NULL, args);
5000 return factory()->NewThrow(call_constructor, scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001}
5002
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005003// ----------------------------------------------------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005004// Regular expressions
5005
5006
5007RegExpParser::RegExpParser(FlatStringReader* in,
5008 Handle<String>* error,
5009 bool multiline)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005010 : isolate_(Isolate::Current()),
5011 error_(error),
5012 captures_(NULL),
5013 in_(in),
5014 current_(kEndMarker),
5015 next_pos_(0),
5016 capture_count_(0),
5017 has_more_(true),
5018 multiline_(multiline),
5019 simple_(false),
5020 contains_anchor_(false),
5021 is_scanned_for_captures_(false),
5022 failed_(false) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00005023 Advance();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005024}
5025
5026
5027uc32 RegExpParser::Next() {
5028 if (has_next()) {
5029 return in()->Get(next_pos_);
5030 } else {
5031 return kEndMarker;
5032 }
5033}
5034
5035
5036void RegExpParser::Advance() {
5037 if (next_pos_ < in()->length()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005038 StackLimitCheck check(isolate());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005039 if (check.HasOverflowed()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005040 ReportError(CStrVector(Isolate::kStackOverflowMessage));
5041 } else if (isolate()->zone()->excess_allocation()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005042 ReportError(CStrVector("Regular expression too large"));
5043 } else {
5044 current_ = in()->Get(next_pos_);
5045 next_pos_++;
5046 }
5047 } else {
5048 current_ = kEndMarker;
5049 has_more_ = false;
5050 }
5051}
5052
5053
5054void RegExpParser::Reset(int pos) {
5055 next_pos_ = pos;
5056 Advance();
5057}
5058
5059
5060void RegExpParser::Advance(int dist) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00005061 next_pos_ += dist - 1;
5062 Advance();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005063}
5064
5065
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005066bool RegExpParser::simple() {
5067 return simple_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005068}
5069
5070RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
5071 failed_ = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 *error_ = isolate()->factory()->NewStringFromAscii(message, NOT_TENURED);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005073 // Zip to the end to make sure the no more input is read.
5074 current_ = kEndMarker;
5075 next_pos_ = in()->length();
5076 return NULL;
5077}
5078
5079
5080// Pattern ::
5081// Disjunction
5082RegExpTree* RegExpParser::ParsePattern() {
5083 RegExpTree* result = ParseDisjunction(CHECK_FAILED);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005084 ASSERT(!has_more());
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005085 // If the result of parsing is a literal string atom, and it has the
5086 // same length as the input, then the atom is identical to the input.
5087 if (result->IsAtom() && result->AsAtom()->length() == in()->length()) {
5088 simple_ = true;
5089 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005090 return result;
5091}
5092
5093
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005094// Disjunction ::
5095// Alternative
5096// Alternative | Disjunction
5097// Alternative ::
5098// [empty]
5099// Term Alternative
5100// Term ::
5101// Assertion
5102// Atom
5103// Atom Quantifier
5104RegExpTree* RegExpParser::ParseDisjunction() {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005105 // Used to store current state while parsing subexpressions.
5106 RegExpParserState initial_state(NULL, INITIAL, 0);
5107 RegExpParserState* stored_state = &initial_state;
5108 // Cache the builder in a local variable for quick access.
5109 RegExpBuilder* builder = initial_state.builder();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005110 while (true) {
5111 switch (current()) {
5112 case kEndMarker:
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005113 if (stored_state->IsSubexpression()) {
5114 // Inside a parenthesized group when hitting end of input.
5115 ReportError(CStrVector("Unterminated group") CHECK_FAILED);
5116 }
5117 ASSERT_EQ(INITIAL, stored_state->group_type());
5118 // Parsing completed successfully.
5119 return builder->ToRegExp();
5120 case ')': {
5121 if (!stored_state->IsSubexpression()) {
5122 ReportError(CStrVector("Unmatched ')'") CHECK_FAILED);
5123 }
5124 ASSERT_NE(INITIAL, stored_state->group_type());
5125
5126 Advance();
5127 // End disjunction parsing and convert builder content to new single
5128 // regexp atom.
5129 RegExpTree* body = builder->ToRegExp();
5130
5131 int end_capture_index = captures_started();
5132
5133 int capture_index = stored_state->capture_index();
5134 SubexpressionType type = stored_state->group_type();
5135
5136 // Restore previous state.
5137 stored_state = stored_state->previous_state();
5138 builder = stored_state->builder();
5139
5140 // Build result of subexpression.
5141 if (type == CAPTURE) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005142 RegExpCapture* capture = new(zone()) RegExpCapture(body, capture_index);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005143 captures_->at(capture_index - 1) = capture;
5144 body = capture;
5145 } else if (type != GROUPING) {
5146 ASSERT(type == POSITIVE_LOOKAHEAD || type == NEGATIVE_LOOKAHEAD);
5147 bool is_positive = (type == POSITIVE_LOOKAHEAD);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005148 body = new(zone()) RegExpLookahead(body,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005149 is_positive,
5150 end_capture_index - capture_index,
5151 capture_index);
5152 }
5153 builder->AddAtom(body);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005154 // For compatability with JSC and ES3, we allow quantifiers after
5155 // lookaheads, and break in all cases.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005156 break;
5157 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005158 case '|': {
5159 Advance();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005160 builder->NewAlternative();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005161 continue;
5162 }
5163 case '*':
5164 case '+':
5165 case '?':
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005166 return ReportError(CStrVector("Nothing to repeat"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005167 case '^': {
5168 Advance();
iposva@chromium.org245aa852009-02-10 00:49:54 +00005169 if (multiline_) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005170 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005171 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_LINE));
iposva@chromium.org245aa852009-02-10 00:49:54 +00005172 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005173 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005174 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_INPUT));
iposva@chromium.org245aa852009-02-10 00:49:54 +00005175 set_contains_anchor();
5176 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005177 continue;
5178 }
5179 case '$': {
5180 Advance();
5181 RegExpAssertion::Type type =
5182 multiline_ ? RegExpAssertion::END_OF_LINE :
5183 RegExpAssertion::END_OF_INPUT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005184 builder->AddAssertion(new(zone()) RegExpAssertion(type));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005185 continue;
5186 }
5187 case '.': {
5188 Advance();
5189 // everything except \x0a, \x0d, \u2028 and \u2029
danno@chromium.org40cb8782011-05-25 07:58:50 +00005190 ZoneList<CharacterRange>* ranges =
5191 new(zone()) ZoneList<CharacterRange>(2);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005192 CharacterRange::AddClassEscape('.', ranges);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005193 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005194 builder->AddAtom(atom);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005195 break;
5196 }
5197 case '(': {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005198 SubexpressionType type = CAPTURE;
5199 Advance();
5200 if (current() == '?') {
5201 switch (Next()) {
5202 case ':':
5203 type = GROUPING;
5204 break;
5205 case '=':
5206 type = POSITIVE_LOOKAHEAD;
5207 break;
5208 case '!':
5209 type = NEGATIVE_LOOKAHEAD;
5210 break;
5211 default:
5212 ReportError(CStrVector("Invalid group") CHECK_FAILED);
5213 break;
5214 }
5215 Advance(2);
5216 } else {
5217 if (captures_ == NULL) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00005218 captures_ = new(zone()) ZoneList<RegExpCapture*>(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005219 }
5220 if (captures_started() >= kMaxCaptures) {
5221 ReportError(CStrVector("Too many captures") CHECK_FAILED);
5222 }
5223 captures_->Add(NULL);
5224 }
5225 // Store current state and begin new disjunction parsing.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005226 stored_state = new(zone()) RegExpParserState(stored_state,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005227 type,
5228 captures_started());
5229 builder = stored_state->builder();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005230 continue;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005231 }
5232 case '[': {
5233 RegExpTree* atom = ParseCharacterClass(CHECK_FAILED);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005234 builder->AddAtom(atom);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005235 break;
5236 }
5237 // Atom ::
5238 // \ AtomEscape
5239 case '\\':
5240 switch (Next()) {
5241 case kEndMarker:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005242 return ReportError(CStrVector("\\ at end of pattern"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005243 case 'b':
5244 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005245 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005246 new(zone()) RegExpAssertion(RegExpAssertion::BOUNDARY));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005247 continue;
5248 case 'B':
5249 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005250 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005251 new(zone()) RegExpAssertion(RegExpAssertion::NON_BOUNDARY));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005252 continue;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005253 // AtomEscape ::
5254 // CharacterClassEscape
5255 //
5256 // CharacterClassEscape :: one of
5257 // d D s S w W
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005258 case 'd': case 'D': case 's': case 'S': case 'w': case 'W': {
5259 uc32 c = Next();
5260 Advance(2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00005261 ZoneList<CharacterRange>* ranges =
5262 new(zone()) ZoneList<CharacterRange>(2);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005263 CharacterRange::AddClassEscape(c, ranges);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005264 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005265 builder->AddAtom(atom);
5266 break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005267 }
5268 case '1': case '2': case '3': case '4': case '5': case '6':
5269 case '7': case '8': case '9': {
5270 int index = 0;
5271 if (ParseBackReferenceIndex(&index)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005272 RegExpCapture* capture = NULL;
5273 if (captures_ != NULL && index <= captures_->length()) {
5274 capture = captures_->at(index - 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005275 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005276 if (capture == NULL) {
5277 builder->AddEmpty();
5278 break;
5279 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005280 RegExpTree* atom = new(zone()) RegExpBackReference(capture);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005281 builder->AddAtom(atom);
5282 break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005283 }
5284 uc32 first_digit = Next();
5285 if (first_digit == '8' || first_digit == '9') {
5286 // Treat as identity escape
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005287 builder->AddCharacter(first_digit);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005288 Advance(2);
5289 break;
5290 }
5291 }
5292 // FALLTHROUGH
5293 case '0': {
5294 Advance();
5295 uc32 octal = ParseOctalLiteral();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005296 builder->AddCharacter(octal);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005297 break;
5298 }
5299 // ControlEscape :: one of
5300 // f n r t v
5301 case 'f':
5302 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005303 builder->AddCharacter('\f');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005304 break;
5305 case 'n':
5306 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005307 builder->AddCharacter('\n');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005308 break;
5309 case 'r':
5310 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005311 builder->AddCharacter('\r');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005312 break;
5313 case 't':
5314 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005315 builder->AddCharacter('\t');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005316 break;
5317 case 'v':
5318 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005319 builder->AddCharacter('\v');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005320 break;
5321 case 'c': {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00005322 Advance();
5323 uc32 controlLetter = Next();
5324 // Special case if it is an ASCII letter.
5325 // Convert lower case letters to uppercase.
5326 uc32 letter = controlLetter & ~('a' ^ 'A');
5327 if (letter < 'A' || 'Z' < letter) {
5328 // controlLetter is not in range 'A'-'Z' or 'a'-'z'.
5329 // This is outside the specification. We match JSC in
5330 // reading the backslash as a literal character instead
5331 // of as starting an escape.
5332 builder->AddCharacter('\\');
5333 } else {
5334 Advance(2);
5335 builder->AddCharacter(controlLetter & 0x1f);
5336 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005337 break;
5338 }
5339 case 'x': {
5340 Advance(2);
5341 uc32 value;
5342 if (ParseHexEscape(2, &value)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005343 builder->AddCharacter(value);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005344 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005345 builder->AddCharacter('x');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005346 }
5347 break;
5348 }
5349 case 'u': {
5350 Advance(2);
5351 uc32 value;
5352 if (ParseHexEscape(4, &value)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005353 builder->AddCharacter(value);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005354 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005355 builder->AddCharacter('u');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005356 }
5357 break;
5358 }
5359 default:
5360 // Identity escape.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005361 builder->AddCharacter(Next());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005362 Advance(2);
5363 break;
5364 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005365 break;
5366 case '{': {
5367 int dummy;
5368 if (ParseIntervalQuantifier(&dummy, &dummy)) {
5369 ReportError(CStrVector("Nothing to repeat") CHECK_FAILED);
5370 }
5371 // fallthrough
5372 }
5373 default:
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005374 builder->AddCharacter(current());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005375 Advance();
5376 break;
5377 } // end switch(current())
5378
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005379 int min;
5380 int max;
5381 switch (current()) {
5382 // QuantifierPrefix ::
5383 // *
5384 // +
5385 // ?
5386 // {
5387 case '*':
5388 min = 0;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005389 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005390 Advance();
5391 break;
5392 case '+':
5393 min = 1;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005394 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005395 Advance();
5396 break;
5397 case '?':
5398 min = 0;
5399 max = 1;
5400 Advance();
5401 break;
5402 case '{':
5403 if (ParseIntervalQuantifier(&min, &max)) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005404 if (max < min) {
5405 ReportError(CStrVector("numbers out of order in {} quantifier.")
5406 CHECK_FAILED);
5407 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005408 break;
5409 } else {
5410 continue;
5411 }
5412 default:
5413 continue;
5414 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005415 RegExpQuantifier::Type type = RegExpQuantifier::GREEDY;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005416 if (current() == '?') {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005417 type = RegExpQuantifier::NON_GREEDY;
5418 Advance();
5419 } else if (FLAG_regexp_possessive_quantifier && current() == '+') {
5420 // FLAG_regexp_possessive_quantifier is a debug-only flag.
5421 type = RegExpQuantifier::POSSESSIVE;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005422 Advance();
5423 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005424 builder->AddQuantifierToAtom(min, max, type);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005425 }
5426}
5427
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005428
5429#ifdef DEBUG
5430// Currently only used in an ASSERT.
5431static bool IsSpecialClassEscape(uc32 c) {
5432 switch (c) {
5433 case 'd': case 'D':
5434 case 's': case 'S':
5435 case 'w': case 'W':
5436 return true;
5437 default:
5438 return false;
5439 }
5440}
5441#endif
5442
5443
5444// In order to know whether an escape is a backreference or not we have to scan
5445// the entire regexp and find the number of capturing parentheses. However we
5446// don't want to scan the regexp twice unless it is necessary. This mini-parser
5447// is called when needed. It can see the difference between capturing and
5448// noncapturing parentheses and can skip character classes and backslash-escaped
5449// characters.
5450void RegExpParser::ScanForCaptures() {
5451 // Start with captures started previous to current position
5452 int capture_count = captures_started();
5453 // Add count of captures after this position.
5454 int n;
5455 while ((n = current()) != kEndMarker) {
5456 Advance();
5457 switch (n) {
5458 case '\\':
5459 Advance();
5460 break;
5461 case '[': {
5462 int c;
5463 while ((c = current()) != kEndMarker) {
5464 Advance();
5465 if (c == '\\') {
5466 Advance();
5467 } else {
5468 if (c == ']') break;
5469 }
5470 }
5471 break;
5472 }
5473 case '(':
5474 if (current() != '?') capture_count++;
5475 break;
5476 }
5477 }
5478 capture_count_ = capture_count;
5479 is_scanned_for_captures_ = true;
5480}
5481
5482
5483bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
5484 ASSERT_EQ('\\', current());
5485 ASSERT('1' <= Next() && Next() <= '9');
iposva@chromium.org245aa852009-02-10 00:49:54 +00005486 // Try to parse a decimal literal that is no greater than the total number
5487 // of left capturing parentheses in the input.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005488 int start = position();
5489 int value = Next() - '0';
5490 Advance(2);
5491 while (true) {
5492 uc32 c = current();
5493 if (IsDecimalDigit(c)) {
5494 value = 10 * value + (c - '0');
iposva@chromium.org245aa852009-02-10 00:49:54 +00005495 if (value > kMaxCaptures) {
5496 Reset(start);
5497 return false;
5498 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005499 Advance();
5500 } else {
5501 break;
5502 }
5503 }
5504 if (value > captures_started()) {
5505 if (!is_scanned_for_captures_) {
5506 int saved_position = position();
5507 ScanForCaptures();
5508 Reset(saved_position);
5509 }
5510 if (value > capture_count_) {
5511 Reset(start);
5512 return false;
5513 }
5514 }
5515 *index_out = value;
5516 return true;
5517}
5518
5519
5520// QuantifierPrefix ::
5521// { DecimalDigits }
5522// { DecimalDigits , }
5523// { DecimalDigits , DecimalDigits }
iposva@chromium.org245aa852009-02-10 00:49:54 +00005524//
5525// Returns true if parsing succeeds, and set the min_out and max_out
5526// values. Values are truncated to RegExpTree::kInfinity if they overflow.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005527bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) {
5528 ASSERT_EQ(current(), '{');
5529 int start = position();
5530 Advance();
5531 int min = 0;
5532 if (!IsDecimalDigit(current())) {
5533 Reset(start);
5534 return false;
5535 }
5536 while (IsDecimalDigit(current())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005537 int next = current() - '0';
5538 if (min > (RegExpTree::kInfinity - next) / 10) {
5539 // Overflow. Skip past remaining decimal digits and return -1.
5540 do {
5541 Advance();
5542 } while (IsDecimalDigit(current()));
5543 min = RegExpTree::kInfinity;
5544 break;
5545 }
5546 min = 10 * min + next;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005547 Advance();
5548 }
5549 int max = 0;
5550 if (current() == '}') {
5551 max = min;
5552 Advance();
5553 } else if (current() == ',') {
5554 Advance();
5555 if (current() == '}') {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005556 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005557 Advance();
5558 } else {
5559 while (IsDecimalDigit(current())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005560 int next = current() - '0';
5561 if (max > (RegExpTree::kInfinity - next) / 10) {
5562 do {
5563 Advance();
5564 } while (IsDecimalDigit(current()));
5565 max = RegExpTree::kInfinity;
5566 break;
5567 }
5568 max = 10 * max + next;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005569 Advance();
5570 }
5571 if (current() != '}') {
5572 Reset(start);
5573 return false;
5574 }
5575 Advance();
5576 }
5577 } else {
5578 Reset(start);
5579 return false;
5580 }
5581 *min_out = min;
5582 *max_out = max;
5583 return true;
5584}
5585
5586
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005587uc32 RegExpParser::ParseOctalLiteral() {
5588 ASSERT('0' <= current() && current() <= '7');
5589 // For compatibility with some other browsers (not all), we parse
5590 // up to three octal digits with a value below 256.
5591 uc32 value = current() - '0';
5592 Advance();
5593 if ('0' <= current() && current() <= '7') {
5594 value = value * 8 + current() - '0';
5595 Advance();
5596 if (value < 32 && '0' <= current() && current() <= '7') {
5597 value = value * 8 + current() - '0';
5598 Advance();
5599 }
5600 }
5601 return value;
5602}
5603
5604
5605bool RegExpParser::ParseHexEscape(int length, uc32 *value) {
5606 int start = position();
5607 uc32 val = 0;
5608 bool done = false;
5609 for (int i = 0; !done; i++) {
5610 uc32 c = current();
5611 int d = HexValue(c);
5612 if (d < 0) {
5613 Reset(start);
5614 return false;
5615 }
5616 val = val * 16 + d;
5617 Advance();
5618 if (i == length - 1) {
5619 done = true;
5620 }
5621 }
5622 *value = val;
5623 return true;
5624}
5625
5626
5627uc32 RegExpParser::ParseClassCharacterEscape() {
5628 ASSERT(current() == '\\');
5629 ASSERT(has_next() && !IsSpecialClassEscape(Next()));
5630 Advance();
5631 switch (current()) {
5632 case 'b':
5633 Advance();
5634 return '\b';
5635 // ControlEscape :: one of
5636 // f n r t v
5637 case 'f':
5638 Advance();
5639 return '\f';
5640 case 'n':
5641 Advance();
5642 return '\n';
5643 case 'r':
5644 Advance();
5645 return '\r';
5646 case 't':
5647 Advance();
5648 return '\t';
5649 case 'v':
5650 Advance();
5651 return '\v';
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00005652 case 'c': {
5653 uc32 controlLetter = Next();
5654 uc32 letter = controlLetter & ~('A' ^ 'a');
5655 // For compatibility with JSC, inside a character class
5656 // we also accept digits and underscore as control characters.
5657 if ((controlLetter >= '0' && controlLetter <= '9') ||
5658 controlLetter == '_' ||
5659 (letter >= 'A' && letter <= 'Z')) {
5660 Advance(2);
5661 // Control letters mapped to ASCII control characters in the range
5662 // 0x00-0x1f.
5663 return controlLetter & 0x1f;
5664 }
5665 // We match JSC in reading the backslash as a literal
5666 // character instead of as starting an escape.
5667 return '\\';
5668 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005669 case '0': case '1': case '2': case '3': case '4': case '5':
5670 case '6': case '7':
5671 // For compatibility, we interpret a decimal escape that isn't
5672 // a back reference (and therefore either \0 or not valid according
5673 // to the specification) as a 1..3 digit octal character code.
5674 return ParseOctalLiteral();
5675 case 'x': {
5676 Advance();
5677 uc32 value;
5678 if (ParseHexEscape(2, &value)) {
5679 return value;
5680 }
5681 // If \x is not followed by a two-digit hexadecimal, treat it
5682 // as an identity escape.
5683 return 'x';
5684 }
5685 case 'u': {
5686 Advance();
5687 uc32 value;
5688 if (ParseHexEscape(4, &value)) {
5689 return value;
5690 }
5691 // If \u is not followed by a four-digit hexadecimal, treat it
5692 // as an identity escape.
5693 return 'u';
5694 }
5695 default: {
5696 // Extended identity escape. We accept any character that hasn't
5697 // been matched by a more specific case, not just the subset required
5698 // by the ECMAScript specification.
5699 uc32 result = current();
5700 Advance();
5701 return result;
5702 }
5703 }
5704 return 0;
5705}
5706
5707
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005708CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) {
5709 ASSERT_EQ(0, *char_class);
5710 uc32 first = current();
5711 if (first == '\\') {
5712 switch (Next()) {
5713 case 'w': case 'W': case 'd': case 'D': case 's': case 'S': {
5714 *char_class = Next();
5715 Advance(2);
5716 return CharacterRange::Singleton(0); // Return dummy value.
5717 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005718 case kEndMarker:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005719 return ReportError(CStrVector("\\ at end of pattern"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005720 default:
5721 uc32 c = ParseClassCharacterEscape(CHECK_FAILED);
5722 return CharacterRange::Singleton(c);
5723 }
5724 } else {
5725 Advance();
5726 return CharacterRange::Singleton(first);
5727 }
5728}
5729
5730
lrn@chromium.org14a70352010-12-15 12:43:21 +00005731static const uc16 kNoCharClass = 0;
5732
5733// Adds range or pre-defined character class to character ranges.
5734// If char_class is not kInvalidClass, it's interpreted as a class
5735// escape (i.e., 's' means whitespace, from '\s').
5736static inline void AddRangeOrEscape(ZoneList<CharacterRange>* ranges,
5737 uc16 char_class,
5738 CharacterRange range) {
5739 if (char_class != kNoCharClass) {
5740 CharacterRange::AddClassEscape(char_class, ranges);
5741 } else {
5742 ranges->Add(range);
5743 }
5744}
5745
5746
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005747RegExpTree* RegExpParser::ParseCharacterClass() {
5748 static const char* kUnterminated = "Unterminated character class";
5749 static const char* kRangeOutOfOrder = "Range out of order in character class";
5750
5751 ASSERT_EQ(current(), '[');
5752 Advance();
5753 bool is_negated = false;
5754 if (current() == '^') {
5755 is_negated = true;
5756 Advance();
5757 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00005758 ZoneList<CharacterRange>* ranges = new(zone()) ZoneList<CharacterRange>(2);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005759 while (has_more() && current() != ']') {
lrn@chromium.org14a70352010-12-15 12:43:21 +00005760 uc16 char_class = kNoCharClass;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005761 CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005762 if (current() == '-') {
5763 Advance();
5764 if (current() == kEndMarker) {
5765 // If we reach the end we break out of the loop and let the
5766 // following code report an error.
5767 break;
5768 } else if (current() == ']') {
lrn@chromium.org14a70352010-12-15 12:43:21 +00005769 AddRangeOrEscape(ranges, char_class, first);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005770 ranges->Add(CharacterRange::Singleton('-'));
5771 break;
5772 }
lrn@chromium.org14a70352010-12-15 12:43:21 +00005773 uc16 char_class_2 = kNoCharClass;
5774 CharacterRange next = ParseClassAtom(&char_class_2 CHECK_FAILED);
5775 if (char_class != kNoCharClass || char_class_2 != kNoCharClass) {
5776 // Either end is an escaped character class. Treat the '-' verbatim.
5777 AddRangeOrEscape(ranges, char_class, first);
5778 ranges->Add(CharacterRange::Singleton('-'));
5779 AddRangeOrEscape(ranges, char_class_2, next);
5780 continue;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005781 }
5782 if (first.from() > next.to()) {
5783 return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED);
5784 }
5785 ranges->Add(CharacterRange::Range(first.from(), next.to()));
5786 } else {
lrn@chromium.org14a70352010-12-15 12:43:21 +00005787 AddRangeOrEscape(ranges, char_class, first);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005788 }
5789 }
5790 if (!has_more()) {
5791 return ReportError(CStrVector(kUnterminated) CHECK_FAILED);
5792 }
5793 Advance();
5794 if (ranges->length() == 0) {
5795 ranges->Add(CharacterRange::Everything());
5796 is_negated = !is_negated;
5797 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005798 return new(zone()) RegExpCharacterClass(ranges, is_negated);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005799}
5800
5801
5802// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005803// The Parser interface.
5804
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005805ParserMessage::~ParserMessage() {
5806 for (int i = 0; i < args().length(); i++)
5807 DeleteArray(args()[i]);
5808 DeleteArray(args().start());
5809}
5810
5811
5812ScriptDataImpl::~ScriptDataImpl() {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005813 if (owns_store_) store_.Dispose();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005814}
5815
5816
5817int ScriptDataImpl::Length() {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005818 return store_.length() * sizeof(unsigned);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005819}
5820
5821
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005822const char* ScriptDataImpl::Data() {
5823 return reinterpret_cast<const char*>(store_.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005824}
5825
5826
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005827bool ScriptDataImpl::HasError() {
5828 return has_error();
5829}
5830
5831
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005832void ScriptDataImpl::Initialize() {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00005833 // Prepares state for use.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005834 if (store_.length() >= PreparseDataConstants::kHeaderSize) {
5835 function_index_ = PreparseDataConstants::kHeaderSize;
5836 int symbol_data_offset = PreparseDataConstants::kHeaderSize
5837 + store_[PreparseDataConstants::kFunctionsSizeOffset];
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005838 if (store_.length() > symbol_data_offset) {
5839 symbol_data_ = reinterpret_cast<byte*>(&store_[symbol_data_offset]);
5840 } else {
5841 // Partial preparse causes no symbol information.
5842 symbol_data_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
5843 }
5844 symbol_data_end_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
5845 }
5846}
5847
5848
5849int ScriptDataImpl::ReadNumber(byte** source) {
5850 // Reads a number from symbol_data_ in base 128. The most significant
5851 // bit marks that there are more digits.
5852 // If the first byte is 0x80 (kNumberTerminator), it would normally
5853 // represent a leading zero. Since that is useless, and therefore won't
5854 // appear as the first digit of any actual value, it is used to
5855 // mark the end of the input stream.
5856 byte* data = *source;
5857 if (data >= symbol_data_end_) return -1;
5858 byte input = *data;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005859 if (input == PreparseDataConstants::kNumberTerminator) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005860 // End of stream marker.
5861 return -1;
5862 }
5863 int result = input & 0x7f;
5864 data++;
5865 while ((input & 0x80u) != 0) {
5866 if (data >= symbol_data_end_) return -1;
5867 input = *data;
5868 result = (result << 7) | (input & 0x7f);
5869 data++;
5870 }
5871 *source = data;
5872 return result;
5873}
5874
5875
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00005876// Create a Scanner for the preparser to use as input, and preparse the source.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005877static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005878 int flags,
5879 ParserRecorder* recorder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005880 Isolate* isolate = Isolate::Current();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005881 HistogramTimerScope timer(isolate->counters()->pre_parse());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005882 Scanner scanner(isolate->unicode_cache());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005883 scanner.SetHarmonyScoping(FLAG_harmony_scoping);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005884 scanner.Initialize(source);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005885 intptr_t stack_limit = isolate->stack_guard()->real_climit();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005886 preparser::PreParser::PreParseResult result =
5887 preparser::PreParser::PreParseProgram(&scanner,
5888 recorder,
5889 flags,
5890 stack_limit);
5891 if (result == preparser::PreParser::kPreParseStackOverflow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005892 isolate->StackOverflow();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00005893 return NULL;
5894 }
5895
5896 // Extract the accumulated data from the recorder as a single
5897 // contiguous vector that we are responsible for disposing.
5898 Vector<unsigned> store = recorder->ExtractData();
5899 return new ScriptDataImpl(store);
5900}
5901
5902
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00005903// Preparse, but only collect data that is immediately useful,
5904// even if the preparser data is only used once.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005905ScriptDataImpl* ParserApi::PartialPreParse(Handle<String> source,
danno@chromium.orgb6451162011-08-17 14:33:23 +00005906 v8::Extension* extension,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005907 int flags) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00005908 bool allow_lazy = FLAG_lazy && (extension == NULL);
5909 if (!allow_lazy) {
5910 // Partial preparsing is only about lazily compiled functions.
5911 // If we don't allow lazy compilation, the log data will be empty.
5912 return NULL;
5913 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005914 flags |= kAllowLazy;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00005915 PartialParserRecorder recorder;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005916 int source_length = source->length();
5917 if (source->IsExternalTwoByteString()) {
5918 ExternalTwoByteStringUC16CharacterStream stream(
5919 Handle<ExternalTwoByteString>::cast(source), 0, source_length);
5920 return DoPreParse(&stream, flags, &recorder);
5921 } else {
5922 GenericStringUC16CharacterStream stream(source, 0, source_length);
5923 return DoPreParse(&stream, flags, &recorder);
5924 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00005925}
5926
5927
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005928ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source,
danno@chromium.orgb6451162011-08-17 14:33:23 +00005929 v8::Extension* extension,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005930 int flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931 Handle<Script> no_script;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005932 if (FLAG_lazy && (extension == NULL)) {
5933 flags |= kAllowLazy;
5934 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00005935 CompleteParserRecorder recorder;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005936 return DoPreParse(source, flags, &recorder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005937}
5938
5939
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00005940bool RegExpParser::ParseRegExp(FlatStringReader* input,
5941 bool multiline,
5942 RegExpCompileData* result) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005943 ASSERT(result != NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005944 RegExpParser parser(input, &result->error, multiline);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005945 RegExpTree* tree = parser.ParsePattern();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005946 if (parser.failed()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005947 ASSERT(tree == NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005948 ASSERT(!result->error.is_null());
5949 } else {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005950 ASSERT(tree != NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005951 ASSERT(result->error.is_null());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005952 result->tree = tree;
5953 int capture_count = parser.captures_started();
5954 result->simple = tree->IsAtom() && parser.simple() && capture_count == 0;
iposva@chromium.org245aa852009-02-10 00:49:54 +00005955 result->contains_anchor = parser.contains_anchor();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005956 result->capture_count = capture_count;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005957 }
5958 return !parser.failed();
5959}
5960
5961
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005962bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005963 ASSERT(info->function() == NULL);
5964 FunctionLiteral* result = NULL;
5965 Handle<Script> script = info->script();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005966 ASSERT((parsing_flags & kLanguageModeMask) == CLASSIC_MODE);
5967 if (!info->is_native() && FLAG_harmony_scoping) {
5968 // Harmony scoping is requested.
5969 parsing_flags |= EXTENDED_MODE;
5970 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00005971 if (!info->is_native() && FLAG_harmony_modules) {
5972 parsing_flags |= kAllowModules;
5973 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005974 if (FLAG_allow_natives_syntax || info->is_native()) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00005975 // We require %identifier(..) syntax.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005976 parsing_flags |= kAllowNativesSyntax;
5977 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005978 if (info->is_lazy()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005979 ASSERT(!info->is_eval());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005980 Parser parser(script, parsing_flags, NULL, NULL);
yangguo@chromium.org56454712012-02-16 15:33:53 +00005981 if (info->shared_info()->is_function()) {
5982 result = parser.ParseLazy(info);
5983 } else {
5984 result = parser.ParseProgram(info);
5985 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005986 } else {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005987 ScriptDataImpl* pre_data = info->pre_parse_data();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005988 Parser parser(script, parsing_flags, info->extension(), pre_data);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005989 if (pre_data != NULL && pre_data->has_error()) {
5990 Scanner::Location loc = pre_data->MessageLocation();
5991 const char* message = pre_data->BuildMessage();
5992 Vector<const char*> args = pre_data->BuildArgs();
5993 parser.ReportMessageAt(loc, message, args);
5994 DeleteArray(message);
5995 for (int i = 0; i < args.length(); i++) {
5996 DeleteArray(args[i]);
5997 }
5998 DeleteArray(args.start());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005999 ASSERT(info->isolate()->has_pending_exception());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006000 } else {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006001 result = parser.ParseProgram(info);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006002 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006003 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006004 info->SetFunction(result);
6005 return (result != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006006}
6007
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008} } // namespace v8::internal