blob: a17883fd456182865a90a1b76225ff02ae826ddb [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) {}
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +000055 ~PositionStack() {
56 ASSERT(!*ok_ || is_empty());
57 USE(ok_);
58 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000059
60 class Element {
61 public:
62 Element(PositionStack* stack, int value) {
63 previous_ = stack->top();
64 value_ = value;
65 stack->set_top(this);
66 }
67
68 private:
69 Element* previous() { return previous_; }
70 int value() { return value_; }
71 friend class PositionStack;
72 Element* previous_;
73 int value_;
74 };
75
76 bool is_empty() { return top_ == NULL; }
77 int pop() {
78 ASSERT(!is_empty());
79 int result = top_->value();
80 top_ = top_->previous();
81 return result;
82 }
83
84 private:
85 Element* top() { return top_; }
86 void set_top(Element* value) { top_ = value; }
87 Element* top_;
88 bool* ok_;
89};
90
91
rossberg@chromium.org400388e2012-06-06 09:29:22 +000092RegExpBuilder::RegExpBuilder(Zone* zone)
93 : zone_(zone),
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000094 pending_empty_(false),
95 characters_(NULL),
96 terms_(),
97 alternatives_()
ager@chromium.orga74f0da2008-12-03 16:05:52 +000098#ifdef DEBUG
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000099 , last_added_(ADD_NONE)
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000100#endif
101 {}
102
103
104void RegExpBuilder::FlushCharacters() {
105 pending_empty_ = false;
106 if (characters_ != NULL) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000107 RegExpTree* atom = new(zone()) RegExpAtom(characters_->ToConstVector());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000108 characters_ = NULL;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000109 text_.Add(atom, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000110 LAST(ADD_ATOM);
111 }
112}
113
114
115void RegExpBuilder::FlushText() {
116 FlushCharacters();
117 int num_text = text_.length();
118 if (num_text == 0) {
119 return;
120 } else if (num_text == 1) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000121 terms_.Add(text_.last(), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000122 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000123 RegExpText* text = new(zone()) RegExpText(zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000124 for (int i = 0; i < num_text; i++)
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000125 text_.Get(i)->AppendToText(text, zone());
126 terms_.Add(text, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000127 }
128 text_.Clear();
129}
130
131
132void RegExpBuilder::AddCharacter(uc16 c) {
133 pending_empty_ = false;
134 if (characters_ == NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000135 characters_ = new(zone()) ZoneList<uc16>(4, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000136 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000137 characters_->Add(c, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000138 LAST(ADD_CHAR);
139}
140
141
142void RegExpBuilder::AddEmpty() {
143 pending_empty_ = true;
144}
145
146
147void RegExpBuilder::AddAtom(RegExpTree* term) {
148 if (term->IsEmpty()) {
149 AddEmpty();
150 return;
151 }
152 if (term->IsTextElement()) {
153 FlushCharacters();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000154 text_.Add(term, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000155 } else {
156 FlushText();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000157 terms_.Add(term, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000158 }
159 LAST(ADD_ATOM);
160}
161
162
163void RegExpBuilder::AddAssertion(RegExpTree* assert) {
164 FlushText();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000165 terms_.Add(assert, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000166 LAST(ADD_ASSERT);
167}
168
169
170void RegExpBuilder::NewAlternative() {
171 FlushTerms();
172}
173
174
175void RegExpBuilder::FlushTerms() {
176 FlushText();
177 int num_terms = terms_.length();
178 RegExpTree* alternative;
179 if (num_terms == 0) {
180 alternative = RegExpEmpty::GetInstance();
181 } else if (num_terms == 1) {
182 alternative = terms_.last();
183 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000184 alternative = new(zone()) RegExpAlternative(terms_.GetList(zone()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000185 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000186 alternatives_.Add(alternative, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000187 terms_.Clear();
188 LAST(ADD_NONE);
189}
190
191
192RegExpTree* RegExpBuilder::ToRegExp() {
193 FlushTerms();
194 int num_alternatives = alternatives_.length();
195 if (num_alternatives == 0) {
196 return RegExpEmpty::GetInstance();
197 }
198 if (num_alternatives == 1) {
199 return alternatives_.last();
200 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000201 return new(zone()) RegExpDisjunction(alternatives_.GetList(zone()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000202}
203
204
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000205void RegExpBuilder::AddQuantifierToAtom(
206 int min, int max, RegExpQuantifier::QuantifierType quantifier_type) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000207 if (pending_empty_) {
208 pending_empty_ = false;
209 return;
210 }
211 RegExpTree* atom;
212 if (characters_ != NULL) {
213 ASSERT(last_added_ == ADD_CHAR);
214 // Last atom was character.
215 Vector<const uc16> char_vector = characters_->ToConstVector();
216 int num_chars = char_vector.length();
217 if (num_chars > 1) {
218 Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000219 text_.Add(new(zone()) RegExpAtom(prefix), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000220 char_vector = char_vector.SubVector(num_chars - 1, num_chars);
221 }
222 characters_ = NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000223 atom = new(zone()) RegExpAtom(char_vector);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000224 FlushText();
225 } else if (text_.length() > 0) {
226 ASSERT(last_added_ == ADD_ATOM);
227 atom = text_.RemoveLast();
228 FlushText();
229 } else if (terms_.length() > 0) {
230 ASSERT(last_added_ == ADD_ATOM);
231 atom = terms_.RemoveLast();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000232 if (atom->max_match() == 0) {
233 // Guaranteed to only match an empty string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000234 LAST(ADD_TERM);
235 if (min == 0) {
236 return;
237 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000238 terms_.Add(atom, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000239 return;
240 }
241 } else {
242 // Only call immediately after adding an atom or character!
243 UNREACHABLE();
244 return;
245 }
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000246 terms_.Add(
247 new(zone()) RegExpQuantifier(min, max, quantifier_type, atom), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000248 LAST(ADD_TERM);
249}
250
251
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000252Handle<String> Parser::LookupSymbol(int symbol_id) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000253 // Length of symbol cache is the number of identified symbols.
254 // If we are larger than that, or negative, it's not a cached symbol.
255 // This might also happen if there is no preparser symbol data, even
256 // if there is some preparser data.
257 if (static_cast<unsigned>(symbol_id)
258 >= static_cast<unsigned>(symbol_cache_.length())) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000259 if (scanner().is_literal_ascii()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000260 return isolate()->factory()->InternalizeOneByteString(
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000261 Vector<const uint8_t>::cast(scanner().literal_ascii_string()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000262 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000263 return isolate()->factory()->InternalizeTwoByteString(
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000264 scanner().literal_utf16_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000265 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000266 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000267 return LookupCachedSymbol(symbol_id);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000268}
269
270
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000271Handle<String> Parser::LookupCachedSymbol(int symbol_id) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000272 // Make sure the cache is large enough to hold the symbol identifier.
273 if (symbol_cache_.length() <= symbol_id) {
274 // Increase length to index + 1.
275 symbol_cache_.AddBlock(Handle<String>::null(),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000276 symbol_id + 1 - symbol_cache_.length(), zone());
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000277 }
278 Handle<String> result = symbol_cache_.at(symbol_id);
279 if (result.is_null()) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000280 if (scanner().is_literal_ascii()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000281 result = isolate()->factory()->InternalizeOneByteString(
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000282 Vector<const uint8_t>::cast(scanner().literal_ascii_string()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000283 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000284 result = isolate()->factory()->InternalizeTwoByteString(
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000285 scanner().literal_utf16_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000286 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000287 symbol_cache_.at(symbol_id) = result;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000288 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000289 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000290 isolate()->counters()->total_preparse_symbols_skipped()->Increment();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000291 return result;
292}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000293
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000294
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000295FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) {
296 // The current pre-data entry must be a FunctionEntry with the given
297 // start position.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000298 if ((function_index_ + FunctionEntry::kSize <= store_.length())
299 && (static_cast<int>(store_[function_index_]) == start)) {
300 int index = function_index_;
301 function_index_ += FunctionEntry::kSize;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000302 return FunctionEntry(store_.SubVector(index,
303 index + FunctionEntry::kSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304 }
305 return FunctionEntry();
306}
307
308
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000309int ScriptDataImpl::GetSymbolIdentifier() {
310 return ReadNumber(&symbol_data_);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000311}
312
313
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000314bool ScriptDataImpl::SanityCheck() {
315 // Check that the header data is valid and doesn't specify
316 // point to positions outside the store.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000317 if (store_.length() < PreparseDataConstants::kHeaderSize) return false;
318 if (magic() != PreparseDataConstants::kMagicNumber) return false;
319 if (version() != PreparseDataConstants::kCurrentVersion) return false;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000320 if (has_error()) {
321 // Extra sane sanity check for error message encoding.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000322 if (store_.length() <= PreparseDataConstants::kHeaderSize
323 + PreparseDataConstants::kMessageTextPos) {
324 return false;
325 }
326 if (Read(PreparseDataConstants::kMessageStartPos) >
327 Read(PreparseDataConstants::kMessageEndPos)) {
328 return false;
329 }
330 unsigned arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
331 int pos = PreparseDataConstants::kMessageTextPos;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000332 for (unsigned int i = 0; i <= arg_count; i++) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000333 if (store_.length() <= PreparseDataConstants::kHeaderSize + pos) {
334 return false;
335 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000336 int length = static_cast<int>(Read(pos));
337 if (length < 0) return false;
338 pos += 1 + length;
339 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000340 if (store_.length() < PreparseDataConstants::kHeaderSize + pos) {
341 return false;
342 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000343 return true;
344 }
345 // Check that the space allocated for function entries is sane.
346 int functions_size =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000347 static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000348 if (functions_size < 0) return false;
349 if (functions_size % FunctionEntry::kSize != 0) return false;
350 // Check that the count of symbols is non-negative.
351 int symbol_count =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000352 static_cast<int>(store_[PreparseDataConstants::kSymbolCountOffset]);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000353 if (symbol_count < 0) return false;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000354 // Check that the total size has room for header and function entries.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000355 int minimum_size =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000356 PreparseDataConstants::kHeaderSize + functions_size;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000357 if (store_.length() < minimum_size) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358 return true;
359}
360
361
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000362
ricow@chromium.org65fae842010-08-25 15:26:24 +0000363const char* ScriptDataImpl::ReadString(unsigned* start, int* chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 int length = start[0];
365 char* result = NewArray<char>(length + 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000366 for (int i = 0; i < length; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367 result[i] = start[i + 1];
ricow@chromium.org65fae842010-08-25 15:26:24 +0000368 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000369 result[length] = '\0';
370 if (chars != NULL) *chars = length;
371 return result;
372}
373
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000374
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000375Scanner::Location ScriptDataImpl::MessageLocation() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000376 int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
377 int end_pos = Read(PreparseDataConstants::kMessageEndPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000378 return Scanner::Location(beg_pos, end_pos);
379}
380
381
382const char* ScriptDataImpl::BuildMessage() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000383 unsigned* start = ReadAddress(PreparseDataConstants::kMessageTextPos);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000384 return ReadString(start, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385}
386
387
388Vector<const char*> ScriptDataImpl::BuildArgs() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000389 int arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000390 const char** array = NewArray<const char*>(arg_count);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000391 // Position after text found by skipping past length field and
392 // length field content words.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000393 int pos = PreparseDataConstants::kMessageTextPos + 1
394 + Read(PreparseDataConstants::kMessageTextPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 for (int i = 0; i < arg_count; i++) {
396 int count = 0;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000397 array[i] = ReadString(ReadAddress(pos), &count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 pos += count + 1;
399 }
400 return Vector<const char*>(array, arg_count);
401}
402
403
404unsigned ScriptDataImpl::Read(int position) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000405 return store_[PreparseDataConstants::kHeaderSize + position];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000406}
407
408
409unsigned* ScriptDataImpl::ReadAddress(int position) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000410 return &store_[PreparseDataConstants::kHeaderSize + position];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000411}
412
413
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000414Scope* Parser::NewScope(Scope* parent, ScopeType scope_type) {
415 Scope* result = new(zone()) Scope(parent, scope_type, zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000416 result->Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 return result;
418}
419
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000420
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000421// ----------------------------------------------------------------------------
422// Target is a support class to facilitate manipulation of the
423// Parser's target_stack_ (the stack of potential 'break' and
424// 'continue' statement targets). Upon construction, a new target is
425// added; it is removed upon destruction.
426
427class Target BASE_EMBEDDED {
428 public:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000429 Target(Target** variable, AstNode* node)
430 : variable_(variable), node_(node), previous_(*variable) {
431 *variable = this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433
434 ~Target() {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000435 *variable_ = previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000436 }
437
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000438 Target* previous() { return previous_; }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000439 AstNode* node() { return node_; }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000441 private:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000442 Target** variable_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000443 AstNode* node_;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000444 Target* previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445};
446
447
448class TargetScope BASE_EMBEDDED {
449 public:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000450 explicit TargetScope(Target** variable)
451 : variable_(variable), previous_(*variable) {
452 *variable = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453 }
454
455 ~TargetScope() {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000456 *variable_ = previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000457 }
458
459 private:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000460 Target** variable_;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000461 Target* previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462};
463
464
465// ----------------------------------------------------------------------------
danno@chromium.orgc612e022011-11-10 11:38:15 +0000466// FunctionState and BlockState together implement the parser's scope stack.
467// The parser's current scope is in top_scope_. The BlockState and
468// FunctionState constructors push on the scope stack and the destructors
469// pop. They are also used to hold the parser's per-function and per-block
470// state.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000471
danno@chromium.orgc612e022011-11-10 11:38:15 +0000472class Parser::BlockState BASE_EMBEDDED {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000473 public:
danno@chromium.orgc612e022011-11-10 11:38:15 +0000474 BlockState(Parser* parser, Scope* scope)
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000475 : parser_(parser),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000476 outer_scope_(parser->top_scope_) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000477 parser->top_scope_ = scope;
478 }
479
danno@chromium.orgc612e022011-11-10 11:38:15 +0000480 ~BlockState() { parser_->top_scope_ = outer_scope_; }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000481
482 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000483 Parser* parser_;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000484 Scope* outer_scope_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000485};
486
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487
danno@chromium.orgc612e022011-11-10 11:38:15 +0000488Parser::FunctionState::FunctionState(Parser* parser,
489 Scope* scope,
490 Isolate* isolate)
491 : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000492 next_handler_index_(0),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000493 expected_property_count_(0),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000494 generator_object_variable_(NULL),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000495 parser_(parser),
496 outer_function_state_(parser->current_function_state_),
497 outer_scope_(parser->top_scope_),
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000498 saved_ast_node_id_(isolate->ast_node_id()),
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000499 factory_(isolate, parser->zone()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000500 parser->top_scope_ = scope;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000501 parser->current_function_state_ = this;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000502 isolate->set_ast_node_id(BailoutId::FirstUsable().ToInt());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000503}
504
505
danno@chromium.orgc612e022011-11-10 11:38:15 +0000506Parser::FunctionState::~FunctionState() {
507 parser_->top_scope_ = outer_scope_;
508 parser_->current_function_state_ = outer_function_state_;
yangguo@chromium.org56454712012-02-16 15:33:53 +0000509 if (outer_function_state_ != NULL) {
510 parser_->isolate()->set_ast_node_id(saved_ast_node_id_);
511 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512}
513
514
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515// ----------------------------------------------------------------------------
516// The CHECK_OK macro is a convenient macro to enforce error
517// handling for functions that may fail (by returning !*ok).
518//
519// CAUTION: This macro appends extra statements after a call,
520// thus it must never be used where only a single statement
521// is correct (e.g. an if statement branch w/o braces)!
522
523#define CHECK_OK ok); \
524 if (!*ok) return NULL; \
525 ((void)0
526#define DUMMY ) // to make indentation work
527#undef DUMMY
528
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000529#define CHECK_FAILED /**/); \
530 if (failed_) return NULL; \
531 ((void)0
532#define DUMMY ) // to make indentation work
533#undef DUMMY
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000534
535// ----------------------------------------------------------------------------
536// Implementation of Parser
537
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000538Parser::Parser(CompilationInfo* info)
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000539 : ParserBase(&scanner_, info->isolate()->stack_guard()->real_climit()),
540 isolate_(info->isolate()),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000541 symbol_cache_(0, info->zone()),
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000542 script_(info->script()),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000543 scanner_(isolate_->unicode_cache()),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000544 reusable_preparser_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545 top_scope_(NULL),
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +0000546 original_scope_(NULL),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000547 current_function_state_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 target_stack_(NULL),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000549 extension_(info->extension()),
550 pre_parse_data_(NULL),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000551 fni_(NULL),
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000552 parenthesized_function_(false),
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000553 zone_(info->zone()),
554 info_(info) {
555 ASSERT(!script_.is_null());
yangguo@chromium.org56454712012-02-16 15:33:53 +0000556 isolate_->set_ast_node_id(0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000557 set_allow_harmony_scoping(!info->is_native() && FLAG_harmony_scoping);
558 set_allow_modules(!info->is_native() && FLAG_harmony_modules);
559 set_allow_natives_syntax(FLAG_allow_natives_syntax || info->is_native());
560 set_allow_lazy(false); // Must be explicitly enabled.
561 set_allow_generators(FLAG_harmony_generators);
danno@chromium.org1fd77d52013-06-07 16:01:45 +0000562 set_allow_for_of(FLAG_harmony_iteration);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000563 set_allow_harmony_numeric_literals(FLAG_harmony_numeric_literals);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000564}
565
566
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000567FunctionLiteral* Parser::ParseProgram() {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +0000568 HistogramTimerScope timer_scope(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());
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +0000571 ElapsedTimer timer;
572 if (FLAG_trace_parse) {
573 timer.Start();
574 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000575 fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576
577 // Initialize parser state.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000578 source->TryFlatten();
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000579 FunctionLiteral* result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000580 if (source->IsExternalTwoByteString()) {
581 // Notice that the stream is destroyed at the end of the branch block.
582 // The last line of the blocks can't be moved outside, even though they're
583 // identical calls.
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000584 ExternalTwoByteStringUtf16CharacterStream stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000585 Handle<ExternalTwoByteString>::cast(source), 0, source->length());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000586 scanner_.Initialize(&stream);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000587 result = DoParseProgram(info(), source);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000588 } else {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000589 GenericStringUtf16CharacterStream stream(source, 0, source->length());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000590 scanner_.Initialize(&stream);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000591 result = DoParseProgram(info(), source);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000592 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000593
594 if (FLAG_trace_parse && result != NULL) {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +0000595 double ms = timer.Elapsed().InMillisecondsF();
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000596 if (info()->is_eval()) {
597 PrintF("[parsing eval");
598 } else if (info()->script()->name()->IsString()) {
599 String* name = String::cast(info()->script()->name());
600 SmartArrayPointer<char> name_chars = name->ToCString();
601 PrintF("[parsing script: %s", *name_chars);
602 } else {
603 PrintF("[parsing script");
604 }
605 PrintF(" - took %0.3f ms]\n", ms);
606 }
607 return result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000608}
609
610
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000611FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000612 Handle<String> source) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000613 ASSERT(top_scope_ == NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000614 ASSERT(target_stack_ == NULL);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000615 if (pre_parse_data_ != NULL) pre_parse_data_->Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000617 Handle<String> no_name = isolate()->factory()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618
619 FunctionLiteral* result = NULL;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000620 { Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
621 info->SetGlobalScope(scope);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000622 if (!info->context().is_null()) {
623 scope = Scope::DeserializeScopeChain(*info->context(), scope, zone());
624 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +0000625 original_scope_ = scope;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000626 if (info->is_eval()) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000627 if (!scope->is_global_scope() || info->language_mode() != CLASSIC_MODE) {
628 scope = NewScope(scope, EVAL_SCOPE);
629 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000630 } else if (info->is_global()) {
631 scope = NewScope(scope, GLOBAL_SCOPE);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000632 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000633 scope->set_start_position(0);
634 scope->set_end_position(source->length());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000635
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000636 // Compute the parsing mode.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000637 Mode mode = (FLAG_lazy && allow_lazy()) ? PARSE_LAZILY : PARSE_EAGERLY;
638 if (allow_natives_syntax() ||
639 extension_ != NULL ||
640 scope->is_eval_scope()) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000641 mode = PARSE_EAGERLY;
642 }
643 ParsingModeScope parsing_mode(this, mode);
644
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000645 // Enters 'scope'.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000646 FunctionState function_state(this, scope, isolate());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000647
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000648 top_scope_->SetLanguageMode(info->language_mode());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000649 ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650 bool ok = true;
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000651 int beg_pos = scanner().location().beg_pos;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000652 ParseSourceElements(body, Token::EOS, info->is_eval(), true, &ok);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000653 if (ok && !top_scope_->is_classic_mode()) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000654 CheckOctalLiteral(beg_pos, scanner().location().end_pos, &ok);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000655 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000656
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000657 if (ok && is_extended_mode()) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000658 CheckConflictingVarDeclarations(top_scope_, &ok);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000659 }
660
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000661 if (ok && info->parse_restriction() == ONLY_SINGLE_FUNCTION_LITERAL) {
662 if (body->length() != 1 ||
663 !body->at(0)->IsExpressionStatement() ||
664 !body->at(0)->AsExpressionStatement()->
665 expression()->IsFunctionLiteral()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000666 ReportMessage("single_function_literal", Vector<const char*>::empty());
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000667 ok = false;
668 }
669 }
670
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671 if (ok) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000672 result = factory()->NewFunctionLiteral(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000673 no_name,
674 top_scope_,
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000675 body,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000676 function_state.materialized_literal_count(),
677 function_state.expected_property_count(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000678 function_state.handler_count(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000679 0,
yangguo@chromium.org56454712012-02-16 15:33:53 +0000680 FunctionLiteral::kNoDuplicateParameters,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000681 FunctionLiteral::ANONYMOUS_EXPRESSION,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000682 FunctionLiteral::kGlobalOrEval,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000683 FunctionLiteral::kNotParenthesized,
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000684 FunctionLiteral::kNotGenerator,
685 0);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000686 result->set_ast_properties(factory()->visitor()->ast_properties());
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +0000687 result->set_dont_optimize_reason(
688 factory()->visitor()->dont_optimize_reason());
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000689 } else if (stack_overflow()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000690 isolate()->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691 }
692 }
693
694 // Make sure the target stack is empty.
695 ASSERT(target_stack_ == NULL);
696
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697 return result;
698}
699
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000700
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000701FunctionLiteral* Parser::ParseLazy() {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +0000702 HistogramTimerScope timer_scope(isolate()->counters()->parse_lazy());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000703 Handle<String> source(String::cast(script_->source()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000704 isolate()->counters()->total_parse_size()->Increment(source->length());
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +0000705 ElapsedTimer timer;
706 if (FLAG_trace_parse) {
707 timer.Start();
708 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000709 Handle<SharedFunctionInfo> shared_info = info()->shared_info();
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000710
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000711 // Initialize parser state.
712 source->TryFlatten();
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000713 FunctionLiteral* result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000714 if (source->IsExternalTwoByteString()) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000715 ExternalTwoByteStringUtf16CharacterStream stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000716 Handle<ExternalTwoByteString>::cast(source),
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000717 shared_info->start_position(),
718 shared_info->end_position());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000719 result = ParseLazy(&stream);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000720 } else {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000721 GenericStringUtf16CharacterStream stream(source,
722 shared_info->start_position(),
723 shared_info->end_position());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000724 result = ParseLazy(&stream);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000725 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000726
727 if (FLAG_trace_parse && result != NULL) {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +0000728 double ms = timer.Elapsed().InMillisecondsF();
verwaest@chromium.orgde64f722012-08-16 15:44:54 +0000729 SmartArrayPointer<char> name_chars = result->debug_name()->ToCString();
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000730 PrintF("[parsing function: %s - took %0.3f ms]\n", *name_chars, ms);
731 }
732 return result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000733}
734
735
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000736FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000737 Handle<SharedFunctionInfo> shared_info = info()->shared_info();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000738 scanner_.Initialize(source);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000739 ASSERT(top_scope_ == NULL);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000740 ASSERT(target_stack_ == NULL);
741
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000742 Handle<String> name(String::cast(shared_info->name()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000743 fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000744 fni_->PushEnclosingName(name);
745
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000746 ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000747
748 // Place holder for the result.
749 FunctionLiteral* result = NULL;
750
751 {
752 // Parse the function literal.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000753 Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000754 info()->SetGlobalScope(scope);
755 if (!info()->closure().is_null()) {
756 scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000757 zone());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000758 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +0000759 original_scope_ = scope;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000760 FunctionState function_state(this, scope, isolate());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000761 ASSERT(scope->language_mode() != STRICT_MODE || !info()->is_classic_mode());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000762 ASSERT(scope->language_mode() != EXTENDED_MODE ||
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000763 info()->is_extended_mode());
764 ASSERT(info()->language_mode() == shared_info->language_mode());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000765 scope->SetLanguageMode(shared_info->language_mode());
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000766 FunctionLiteral::FunctionType function_type = shared_info->is_expression()
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000767 ? (shared_info->is_anonymous()
768 ? FunctionLiteral::ANONYMOUS_EXPRESSION
769 : FunctionLiteral::NAMED_EXPRESSION)
770 : FunctionLiteral::DECLARATION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771 bool ok = true;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000772 result = ParseFunctionLiteral(name,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000773 false, // Strict mode name already checked.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000774 shared_info->is_generator(),
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000775 RelocInfo::kNoPosition,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000776 function_type,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000777 &ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778 // Make sure the results agree.
779 ASSERT(ok == (result != NULL));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000780 }
781
782 // Make sure the target stack is empty.
783 ASSERT(target_stack_ == NULL);
784
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000785 if (result == NULL) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000786 if (stack_overflow()) isolate()->StackOverflow();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000787 } else {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000788 Handle<String> inferred_name(shared_info->inferred_name());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000789 result->set_inferred_name(inferred_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000790 }
791 return result;
792}
793
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000794
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000795Handle<String> Parser::GetSymbol() {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000796 int symbol_id = -1;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000797 if (pre_parse_data() != NULL) {
798 symbol_id = pre_parse_data()->GetSymbolIdentifier();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000799 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000800 return LookupSymbol(symbol_id);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000801}
802
803
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000804void Parser::ReportMessage(const char* message, Vector<const char*> args) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000805 Scanner::Location source_location = scanner().location();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000806 ReportMessageAt(source_location, message, args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807}
808
809
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000810void Parser::ReportMessage(const char* message, Vector<Handle<String> > args) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000811 Scanner::Location source_location = scanner().location();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000812 ReportMessageAt(source_location, message, args);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000813}
814
815
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000816void Parser::ReportMessageAt(Scanner::Location source_location,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000817 const char* message,
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000818 Vector<const char*> args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819 MessageLocation location(script_,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000820 source_location.beg_pos,
821 source_location.end_pos);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000822 Factory* factory = isolate()->factory();
823 Handle<FixedArray> elements = factory->NewFixedArray(args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000824 for (int i = 0; i < args.length(); i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000825 Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000826 elements->set(i, *arg_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000828 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000829 Handle<Object> result = factory->NewSyntaxError(message, array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000830 isolate()->Throw(*result, &location);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000831}
832
833
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000834void Parser::ReportMessageAt(Scanner::Location source_location,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000835 const char* message,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000836 Vector<Handle<String> > args) {
837 MessageLocation location(script_,
838 source_location.beg_pos,
839 source_location.end_pos);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000840 Factory* factory = isolate()->factory();
841 Handle<FixedArray> elements = factory->NewFixedArray(args.length());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000842 for (int i = 0; i < args.length(); i++) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000843 elements->set(i, *args[i]);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000844 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000845 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000846 Handle<Object> result = factory->NewSyntaxError(message, array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000847 isolate()->Throw(*result, &location);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000848}
849
850
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000851void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000852 int end_token,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000853 bool is_eval,
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000854 bool is_global,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855 bool* ok) {
856 // SourceElements ::
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000857 // (ModuleElement)* <end_token>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000858
859 // Allocate a target stack to use for this set of source
860 // elements. This way, all scripts and functions get their own
861 // target stack thus avoiding illegal breaks and continues across
862 // functions.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000863 TargetScope scope(&this->target_stack_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864
865 ASSERT(processor != NULL);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000866 bool directive_prologue = true; // Parsing directive prologue.
867
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868 while (peek() != end_token) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000869 if (directive_prologue && peek() != Token::STRING) {
870 directive_prologue = false;
871 }
872
873 Scanner::Location token_loc = scanner().peek_location();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000874 Statement* stat;
875 if (is_global && !is_eval) {
876 stat = ParseModuleElement(NULL, CHECK_OK);
877 } else {
878 stat = ParseBlockElement(NULL, CHECK_OK);
879 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000880 if (stat == NULL || stat->IsEmpty()) {
881 directive_prologue = false; // End of directive prologue.
882 continue;
883 }
884
885 if (directive_prologue) {
886 // A shot at a directive.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000887 ExpressionStatement* e_stat;
888 Literal* literal;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000889 // Still processing directive prologue?
890 if ((e_stat = stat->AsExpressionStatement()) != NULL &&
891 (literal = e_stat->expression()->AsLiteral()) != NULL &&
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000892 literal->value()->IsString()) {
893 Handle<String> directive = Handle<String>::cast(literal->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000894
895 // Check "use strict" directive (ES5 14.1).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000896 if (top_scope_->is_classic_mode() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000897 directive->Equals(isolate()->heap()->use_strict_string()) &&
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000898 token_loc.end_pos - token_loc.beg_pos ==
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000899 isolate()->heap()->use_strict_string()->length() + 2) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000900 // TODO(mstarzinger): Global strict eval calls, need their own scope
901 // as specified in ES5 10.4.2(3). The correct fix would be to always
902 // add this scope in DoParseProgram(), but that requires adaptations
903 // all over the code base, so we go with a quick-fix for now.
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000904 // In the same manner, we have to patch the parsing mode.
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000905 if (is_eval && !top_scope_->is_eval_scope()) {
906 ASSERT(top_scope_->is_global_scope());
907 Scope* scope = NewScope(top_scope_, EVAL_SCOPE);
908 scope->set_start_position(top_scope_->start_position());
909 scope->set_end_position(top_scope_->end_position());
910 top_scope_ = scope;
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000911 mode_ = PARSE_EAGERLY;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000912 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000913 // TODO(ES6): Fix entering extended mode, once it is specified.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000914 top_scope_->SetLanguageMode(allow_harmony_scoping()
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000915 ? EXTENDED_MODE : STRICT_MODE);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000916 // "use strict" is the only directive for now.
917 directive_prologue = false;
918 }
919 } else {
920 // End of the directive prologue.
921 directive_prologue = false;
922 }
923 }
924
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000925 processor->Add(stat, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000927
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928 return 0;
929}
930
931
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000932Statement* Parser::ParseModuleElement(ZoneStringList* labels,
933 bool* ok) {
934 // (Ecma 262 5th Edition, clause 14):
935 // SourceElement:
936 // Statement
937 // FunctionDeclaration
938 //
939 // In harmony mode we allow additionally the following productions
940 // ModuleElement:
941 // LetDeclaration
942 // ConstDeclaration
943 // ModuleDeclaration
944 // ImportDeclaration
945 // ExportDeclaration
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000946 // GeneratorDeclaration
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000947
948 switch (peek()) {
949 case Token::FUNCTION:
ulan@chromium.org812308e2012-02-29 15:58:45 +0000950 return ParseFunctionDeclaration(NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000951 case Token::LET:
952 case Token::CONST:
ulan@chromium.org812308e2012-02-29 15:58:45 +0000953 return ParseVariableStatement(kModuleElement, NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000954 case Token::IMPORT:
955 return ParseImportDeclaration(ok);
956 case Token::EXPORT:
957 return ParseExportDeclaration(ok);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000958 default: {
959 Statement* stmt = ParseStatement(labels, CHECK_OK);
960 // Handle 'module' as a context-sensitive keyword.
961 if (FLAG_harmony_modules &&
962 peek() == Token::IDENTIFIER &&
963 !scanner().HasAnyLineTerminatorBeforeNext() &&
964 stmt != NULL) {
965 ExpressionStatement* estmt = stmt->AsExpressionStatement();
966 if (estmt != NULL &&
967 estmt->expression()->AsVariableProxy() != NULL &&
968 estmt->expression()->AsVariableProxy()->name()->Equals(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000969 isolate()->heap()->module_string()) &&
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000970 !scanner().literal_contains_escapes()) {
ulan@chromium.org812308e2012-02-29 15:58:45 +0000971 return ParseModuleDeclaration(NULL, ok);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000972 }
973 }
974 return stmt;
975 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000976 }
977}
978
979
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000980Statement* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000981 // ModuleDeclaration:
982 // 'module' Identifier Module
983
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000984 int pos = peek_position();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000985 Handle<String> name = ParseIdentifier(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000986
987#ifdef DEBUG
988 if (FLAG_print_interface_details)
989 PrintF("# Module %s...\n", name->ToAsciiArray());
990#endif
991
ulan@chromium.org812308e2012-02-29 15:58:45 +0000992 Module* module = ParseModule(CHECK_OK);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000993 VariableProxy* proxy = NewUnresolved(name, MODULE, module->interface());
ulan@chromium.org812308e2012-02-29 15:58:45 +0000994 Declaration* declaration =
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +0000995 factory()->NewModuleDeclaration(proxy, module, top_scope_, pos);
ulan@chromium.org812308e2012-02-29 15:58:45 +0000996 Declare(declaration, true, CHECK_OK);
997
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000998#ifdef DEBUG
999 if (FLAG_print_interface_details)
1000 PrintF("# Module %s.\n", name->ToAsciiArray());
1001
1002 if (FLAG_print_interfaces) {
1003 PrintF("module %s : ", name->ToAsciiArray());
1004 module->interface()->Print();
1005 }
1006#endif
1007
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001008 if (names) names->Add(name, zone());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001009 if (module->body() == NULL)
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001010 return factory()->NewEmptyStatement(pos);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001011 else
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001012 return factory()->NewModuleStatement(proxy, module->body(), pos);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001013}
1014
1015
1016Module* Parser::ParseModule(bool* ok) {
1017 // Module:
1018 // '{' ModuleElement '}'
ulan@chromium.org812308e2012-02-29 15:58:45 +00001019 // '=' ModulePath ';'
1020 // 'at' String ';'
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001021
1022 switch (peek()) {
1023 case Token::LBRACE:
1024 return ParseModuleLiteral(ok);
1025
ulan@chromium.org812308e2012-02-29 15:58:45 +00001026 case Token::ASSIGN: {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001027 Expect(Token::ASSIGN, CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001028 Module* result = ParseModulePath(CHECK_OK);
1029 ExpectSemicolon(CHECK_OK);
1030 return result;
1031 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001032
ulan@chromium.org812308e2012-02-29 15:58:45 +00001033 default: {
danno@chromium.org1fd77d52013-06-07 16:01:45 +00001034 ExpectContextualKeyword(CStrVector("at"), CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001035 Module* result = ParseModuleUrl(CHECK_OK);
1036 ExpectSemicolon(CHECK_OK);
1037 return result;
1038 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001039 }
1040}
1041
1042
1043Module* Parser::ParseModuleLiteral(bool* ok) {
1044 // Module:
1045 // '{' ModuleElement '}'
1046
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001047 int pos = peek_position();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001048 // Construct block expecting 16 statements.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001049 Block* body = factory()->NewBlock(NULL, 16, false, RelocInfo::kNoPosition);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001050#ifdef DEBUG
1051 if (FLAG_print_interface_details) PrintF("# Literal ");
1052#endif
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001053 Scope* scope = NewScope(top_scope_, MODULE_SCOPE);
1054
1055 Expect(Token::LBRACE, CHECK_OK);
1056 scope->set_start_position(scanner().location().beg_pos);
1057 scope->SetLanguageMode(EXTENDED_MODE);
1058
1059 {
1060 BlockState block_state(this, scope);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001061 TargetCollector collector(zone());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001062 Target target(&this->target_stack_, &collector);
1063 Target target_body(&this->target_stack_, body);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001064
1065 while (peek() != Token::RBRACE) {
1066 Statement* stat = ParseModuleElement(NULL, CHECK_OK);
1067 if (stat && !stat->IsEmpty()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001068 body->AddStatement(stat, zone());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001069 }
1070 }
1071 }
1072
1073 Expect(Token::RBRACE, CHECK_OK);
1074 scope->set_end_position(scanner().location().end_pos);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001075 body->set_scope(scope);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001076
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001077 // Check that all exports are bound.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001078 Interface* interface = scope->interface();
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001079 for (Interface::Iterator it = interface->iterator();
1080 !it.done(); it.Advance()) {
1081 if (scope->LocalLookup(it.name()) == NULL) {
1082 Handle<String> name(it.name());
1083 ReportMessage("module_export_undefined",
1084 Vector<Handle<String> >(&name, 1));
1085 *ok = false;
1086 return NULL;
1087 }
1088 }
1089
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001090 interface->MakeModule(ok);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001091 ASSERT(*ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001092 interface->Freeze(ok);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001093 ASSERT(*ok);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001094 return factory()->NewModuleLiteral(body, interface, pos);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001095}
1096
1097
1098Module* Parser::ParseModulePath(bool* ok) {
1099 // ModulePath:
1100 // Identifier
1101 // ModulePath '.' Identifier
1102
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001103 int pos = peek_position();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001104 Module* result = ParseModuleVariable(CHECK_OK);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001105 while (Check(Token::PERIOD)) {
1106 Handle<String> name = ParseIdentifierName(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001107#ifdef DEBUG
1108 if (FLAG_print_interface_details)
1109 PrintF("# Path .%s ", name->ToAsciiArray());
1110#endif
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001111 Module* member = factory()->NewModulePath(result, name, pos);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001112 result->interface()->Add(name, member->interface(), zone(), ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001113 if (!*ok) {
1114#ifdef DEBUG
1115 if (FLAG_print_interfaces) {
1116 PrintF("PATH TYPE ERROR at '%s'\n", name->ToAsciiArray());
1117 PrintF("result: ");
1118 result->interface()->Print();
1119 PrintF("member: ");
1120 member->interface()->Print();
1121 }
1122#endif
1123 ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
1124 return NULL;
1125 }
1126 result = member;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001127 }
1128
1129 return result;
1130}
1131
1132
1133Module* Parser::ParseModuleVariable(bool* ok) {
1134 // ModulePath:
1135 // Identifier
1136
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001137 int pos = peek_position();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001138 Handle<String> name = ParseIdentifier(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001139#ifdef DEBUG
1140 if (FLAG_print_interface_details)
1141 PrintF("# Module variable %s ", name->ToAsciiArray());
1142#endif
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001143 VariableProxy* proxy = top_scope_->NewUnresolved(
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001144 factory(), name, Interface::NewModule(zone()),
1145 scanner().location().beg_pos);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001146
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001147 return factory()->NewModuleVariable(proxy, pos);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001148}
1149
1150
1151Module* Parser::ParseModuleUrl(bool* ok) {
1152 // Module:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001153 // String
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001154
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001155 int pos = peek_position();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001156 Expect(Token::STRING, CHECK_OK);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001157 Handle<String> symbol = GetSymbol();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001158
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001159 // TODO(ES6): Request JS resource from environment...
1160
1161#ifdef DEBUG
1162 if (FLAG_print_interface_details) PrintF("# Url ");
1163#endif
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001164
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001165 // Create an empty literal as long as the feature isn't finished.
1166 USE(symbol);
1167 Scope* scope = NewScope(top_scope_, MODULE_SCOPE);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001168 Block* body = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001169 body->set_scope(scope);
1170 Interface* interface = scope->interface();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001171 Module* result = factory()->NewModuleLiteral(body, interface, pos);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001172 interface->Freeze(ok);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001173 ASSERT(*ok);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001174 interface->Unify(scope->interface(), zone(), ok);
1175 ASSERT(*ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001176 return result;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001177}
1178
1179
ulan@chromium.org812308e2012-02-29 15:58:45 +00001180Module* Parser::ParseModuleSpecifier(bool* ok) {
1181 // ModuleSpecifier:
1182 // String
1183 // ModulePath
1184
1185 if (peek() == Token::STRING) {
1186 return ParseModuleUrl(ok);
1187 } else {
1188 return ParseModulePath(ok);
1189 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001190}
1191
1192
ulan@chromium.org812308e2012-02-29 15:58:45 +00001193Block* Parser::ParseImportDeclaration(bool* ok) {
1194 // ImportDeclaration:
1195 // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleSpecifier ';'
1196 //
1197 // TODO(ES6): implement destructuring ImportSpecifiers
1198
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001199 int pos = peek_position();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001200 Expect(Token::IMPORT, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001201 ZoneStringList names(1, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001202
1203 Handle<String> name = ParseIdentifierName(CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001204 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001205 while (peek() == Token::COMMA) {
1206 Consume(Token::COMMA);
1207 name = ParseIdentifierName(CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001208 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001209 }
1210
danno@chromium.org1fd77d52013-06-07 16:01:45 +00001211 ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001212 Module* module = ParseModuleSpecifier(CHECK_OK);
1213 ExpectSemicolon(CHECK_OK);
1214
1215 // Generate a separate declaration for each identifier.
1216 // TODO(ES6): once we implement destructuring, make that one declaration.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001217 Block* block = factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001218 for (int i = 0; i < names.length(); ++i) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001219#ifdef DEBUG
1220 if (FLAG_print_interface_details)
1221 PrintF("# Import %s ", names[i]->ToAsciiArray());
1222#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001223 Interface* interface = Interface::NewUnknown(zone());
1224 module->interface()->Add(names[i], interface, zone(), ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001225 if (!*ok) {
1226#ifdef DEBUG
1227 if (FLAG_print_interfaces) {
1228 PrintF("IMPORT TYPE ERROR at '%s'\n", names[i]->ToAsciiArray());
1229 PrintF("module: ");
1230 module->interface()->Print();
1231 }
1232#endif
1233 ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
1234 return NULL;
1235 }
1236 VariableProxy* proxy = NewUnresolved(names[i], LET, interface);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001237 Declaration* declaration =
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001238 factory()->NewImportDeclaration(proxy, module, top_scope_, pos);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001239 Declare(declaration, true, CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001240 }
1241
ulan@chromium.org812308e2012-02-29 15:58:45 +00001242 return block;
1243}
1244
1245
1246Statement* Parser::ParseExportDeclaration(bool* ok) {
1247 // ExportDeclaration:
1248 // 'export' Identifier (',' Identifier)* ';'
1249 // 'export' VariableDeclaration
1250 // 'export' FunctionDeclaration
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001251 // 'export' GeneratorDeclaration
ulan@chromium.org812308e2012-02-29 15:58:45 +00001252 // 'export' ModuleDeclaration
1253 //
1254 // TODO(ES6): implement structuring ExportSpecifiers
1255
1256 Expect(Token::EXPORT, CHECK_OK);
1257
1258 Statement* result = NULL;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001259 ZoneStringList names(1, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001260 switch (peek()) {
1261 case Token::IDENTIFIER: {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001262 int pos = position();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001263 Handle<String> name = ParseIdentifier(CHECK_OK);
1264 // Handle 'module' as a context-sensitive keyword.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001265 if (!name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("module"))) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001266 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001267 while (peek() == Token::COMMA) {
1268 Consume(Token::COMMA);
1269 name = ParseIdentifier(CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001270 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001271 }
1272 ExpectSemicolon(CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001273 result = factory()->NewEmptyStatement(pos);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001274 } else {
1275 result = ParseModuleDeclaration(&names, CHECK_OK);
1276 }
1277 break;
1278 }
1279
1280 case Token::FUNCTION:
1281 result = ParseFunctionDeclaration(&names, CHECK_OK);
1282 break;
1283
1284 case Token::VAR:
1285 case Token::LET:
1286 case Token::CONST:
1287 result = ParseVariableStatement(kModuleElement, &names, CHECK_OK);
1288 break;
1289
1290 default:
1291 *ok = false;
1292 ReportUnexpectedToken(scanner().current_token());
1293 return NULL;
1294 }
1295
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001296 // Extract declared names into export declarations and interface.
1297 Interface* interface = top_scope_->interface();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001298 for (int i = 0; i < names.length(); ++i) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001299#ifdef DEBUG
1300 if (FLAG_print_interface_details)
1301 PrintF("# Export %s ", names[i]->ToAsciiArray());
1302#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001303 Interface* inner = Interface::NewUnknown(zone());
1304 interface->Add(names[i], inner, zone(), CHECK_OK);
1305 if (!*ok)
1306 return NULL;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001307 VariableProxy* proxy = NewUnresolved(names[i], LET, inner);
1308 USE(proxy);
1309 // TODO(rossberg): Rethink whether we actually need to store export
1310 // declarations (for compilation?).
1311 // ExportDeclaration* declaration =
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001312 // factory()->NewExportDeclaration(proxy, top_scope_, position);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001313 // top_scope_->AddDeclaration(declaration);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001314 }
1315
1316 ASSERT(result != NULL);
1317 return result;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001318}
1319
1320
1321Statement* Parser::ParseBlockElement(ZoneStringList* labels,
1322 bool* ok) {
1323 // (Ecma 262 5th Edition, clause 14):
1324 // SourceElement:
1325 // Statement
1326 // FunctionDeclaration
1327 //
1328 // In harmony mode we allow additionally the following productions
1329 // BlockElement (aka SourceElement):
1330 // LetDeclaration
1331 // ConstDeclaration
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001332 // GeneratorDeclaration
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001333
1334 switch (peek()) {
1335 case Token::FUNCTION:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001336 return ParseFunctionDeclaration(NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001337 case Token::LET:
1338 case Token::CONST:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001339 return ParseVariableStatement(kModuleElement, NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001340 default:
1341 return ParseStatement(labels, ok);
1342 }
1343}
1344
1345
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
1347 // Statement ::
1348 // Block
1349 // VariableStatement
1350 // EmptyStatement
1351 // ExpressionStatement
1352 // IfStatement
1353 // IterationStatement
1354 // ContinueStatement
1355 // BreakStatement
1356 // ReturnStatement
1357 // WithStatement
1358 // LabelledStatement
1359 // SwitchStatement
1360 // ThrowStatement
1361 // TryStatement
1362 // DebuggerStatement
1363
1364 // Note: Since labels can only be used by 'break' and 'continue'
1365 // statements, which themselves are only valid within blocks,
1366 // iterations or 'switch' statements (i.e., BreakableStatements),
1367 // labels can be simply ignored in all other cases; except for
ager@chromium.org32912102009-01-16 10:38:43 +00001368 // trivial labeled break statements 'label: break label' which is
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 // parsed into an empty statement.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 switch (peek()) {
1371 case Token::LBRACE:
1372 return ParseBlock(labels, ok);
1373
1374 case Token::CONST: // fall through
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001375 case Token::LET:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 case Token::VAR:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001377 return ParseVariableStatement(kStatement, NULL, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001378
1379 case Token::SEMICOLON:
1380 Next();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001381 return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382
1383 case Token::IF:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001384 return ParseIfStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385
1386 case Token::DO:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001387 return ParseDoWhileStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388
1389 case Token::WHILE:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001390 return ParseWhileStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391
1392 case Token::FOR:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001393 return ParseForStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001394
1395 case Token::CONTINUE:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001396 return ParseContinueStatement(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397
1398 case Token::BREAK:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001399 return ParseBreakStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400
1401 case Token::RETURN:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001402 return ParseReturnStatement(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403
1404 case Token::WITH:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001405 return ParseWithStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406
1407 case Token::SWITCH:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001408 return ParseSwitchStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409
1410 case Token::THROW:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001411 return ParseThrowStatement(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412
1413 case Token::TRY: {
1414 // NOTE: It is somewhat complicated to have labels on
1415 // try-statements. When breaking out of a try-finally statement,
1416 // one must take great care not to treat it as a
1417 // fall-through. It is much easier just to wrap the entire
1418 // try-statement in a statement block and put the labels there
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001419 Block* result =
1420 factory()->NewBlock(labels, 1, false, RelocInfo::kNoPosition);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001421 Target target(&this->target_stack_, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 TryStatement* statement = ParseTryStatement(CHECK_OK);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001423 if (result) result->AddStatement(statement, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424 return result;
1425 }
1426
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001427 case Token::FUNCTION: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001428 // FunctionDeclaration is only allowed in the context of SourceElements
1429 // (Ecma 262 5th Edition, clause 14):
1430 // SourceElement:
1431 // Statement
1432 // FunctionDeclaration
1433 // Common language extension is to allow function declaration in place
1434 // of any statement. This language extension is disabled in strict mode.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001435 //
1436 // In Harmony mode, this case also handles the extension:
1437 // Statement:
1438 // GeneratorDeclaration
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001439 if (!top_scope_->is_classic_mode()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001440 ReportMessageAt(scanner().peek_location(), "strict_function",
1441 Vector<const char*>::empty());
1442 *ok = false;
1443 return NULL;
1444 }
ulan@chromium.org812308e2012-02-29 15:58:45 +00001445 return ParseFunctionDeclaration(NULL, ok);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001446 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001448 case Token::DEBUGGER:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001449 return ParseDebuggerStatement(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450
1451 default:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001452 return ParseExpressionOrLabelledStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001454}
1455
1456
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001457VariableProxy* Parser::NewUnresolved(
1458 Handle<String> name, VariableMode mode, Interface* interface) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00001459 // If we are inside a function, a declaration of a var/const variable is a
1460 // truly local variable, and the scope of the variable is always the function
1461 // scope.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001462 // Let/const variables in harmony mode are always added to the immediately
1463 // enclosing scope.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001464 return DeclarationScope(mode)->NewUnresolved(
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001465 factory(), name, interface, position());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001466}
1467
1468
1469void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001470 VariableProxy* proxy = declaration->proxy();
1471 Handle<String> name = proxy->name();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001472 VariableMode mode = declaration->mode();
1473 Scope* declaration_scope = DeclarationScope(mode);
1474 Variable* var = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001476 // If a suitable scope exists, then we can statically declare this
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477 // variable and also set its mode. In any case, a Declaration node
1478 // will be added to the scope so that the declaration can be added
1479 // to the corresponding activation frame at runtime if necessary.
1480 // For instance declarations inside an eval scope need to be added
1481 // to the calling function context.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001482 // Similarly, strict mode eval scope does not leak variable declarations to
1483 // the caller's scope so we declare all locals, too.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001484 if (declaration_scope->is_function_scope() ||
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001485 declaration_scope->is_strict_or_extended_eval_scope() ||
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001486 declaration_scope->is_block_scope() ||
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001487 declaration_scope->is_module_scope() ||
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001488 declaration_scope->is_global_scope()) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001489 // Declare the variable in the declaration scope.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001490 // For the global scope, we have to check for collisions with earlier
1491 // (i.e., enclosing) global scopes, to maintain the illusion of a single
1492 // global scope.
1493 var = declaration_scope->is_global_scope()
1494 ? declaration_scope->Lookup(name)
1495 : declaration_scope->LocalLookup(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496 if (var == NULL) {
1497 // Declare the name.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001498 var = declaration_scope->DeclareLocal(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001499 name, mode, declaration->initialization(), proxy->interface());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001500 } else if ((mode != VAR || var->mode() != VAR) &&
1501 (!declaration_scope->is_global_scope() ||
1502 IsLexicalVariableMode(mode) ||
1503 IsLexicalVariableMode(var->mode()))) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001504 // The name was declared in this scope before; check for conflicting
1505 // re-declarations. We have a conflict if either of the declarations is
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001506 // not a var (in the global scope, we also have to ignore legacy const for
1507 // compatibility). There is similar code in runtime.cc in the Declare
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001508 // functions. The function CheckNonConflictingScope checks for conflicting
1509 // var and let bindings from different scopes whereas this is a check for
1510 // conflicting declarations within the same scope. This check also covers
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001511 // the special case
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001512 //
1513 // function () { let x; { var x; } }
1514 //
1515 // because the var declaration is hoisted to the function scope where 'x'
1516 // is already bound.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001517 ASSERT(IsDeclaredVariableMode(var->mode()));
1518 if (is_extended_mode()) {
1519 // In harmony mode we treat re-declarations as early errors. See
1520 // ES5 16 for a definition of early errors.
1521 SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
1522 const char* elms[2] = { "Variable", *c_string };
1523 Vector<const char*> args(elms, 2);
1524 ReportMessage("redeclaration", args);
1525 *ok = false;
1526 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 }
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00001528 Handle<String> message_string =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001529 isolate()->factory()->NewStringFromUtf8(CStrVector("Variable"),
1530 TENURED);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001531 Expression* expression =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001532 NewThrowTypeError(isolate()->factory()->redeclaration_string(),
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00001533 message_string, name);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001534 declaration_scope->SetIllegalRedeclaration(expression);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 }
1536 }
1537
1538 // We add a declaration node for every declaration. The compiler
1539 // will only generate code if necessary. In particular, declarations
1540 // for inner local variables that do not represent functions won't
1541 // result in any generated code.
1542 //
1543 // Note that we always add an unresolved proxy even if it's not
1544 // used, simply because we don't know in this method (w/o extra
1545 // parameters) if the proxy is needed or not. The proxy will be
1546 // bound during variable resolution time unless it was pre-bound
1547 // below.
1548 //
1549 // WARNING: This will lead to multiple declaration nodes for the
1550 // same variable if it is declared several times. This is not a
1551 // semantic issue as long as we keep the source order, but it may be
1552 // a performance issue since it may lead to repeated
1553 // Runtime::DeclareContextSlot() calls.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001554 declaration_scope->AddDeclaration(declaration);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001556 if (mode == CONST && declaration_scope->is_global_scope()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001557 // For global const variables we bind the proxy to a variable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001558 ASSERT(resolve); // should be set by all callers
ager@chromium.org3e875802009-06-29 08:26:34 +00001559 Variable::Kind kind = Variable::NORMAL;
jkummerow@chromium.org10480472013-07-17 08:22:15 +00001560 var = new(zone()) Variable(
1561 declaration_scope, name, mode, true, kind,
1562 kNeedsInitialization, proxy->interface());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001563 } else if (declaration_scope->is_eval_scope() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001564 declaration_scope->is_classic_mode()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001565 // For variable declarations in a non-strict eval scope the proxy is bound
1566 // to a lookup variable to force a dynamic declaration using the
1567 // DeclareContextSlot runtime function.
1568 Variable::Kind kind = Variable::NORMAL;
jkummerow@chromium.org10480472013-07-17 08:22:15 +00001569 var = new(zone()) Variable(
1570 declaration_scope, name, mode, true, kind,
1571 declaration->initialization(), proxy->interface());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001572 var->AllocateTo(Variable::LOOKUP, -1);
1573 resolve = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 }
1575
1576 // If requested and we have a local variable, bind the proxy to the variable
1577 // at parse-time. This is used for functions (and consts) declared inside
1578 // statements: the corresponding function (or const) variable must be in the
1579 // function scope and not a statement-local scope, e.g. as provided with a
1580 // 'with' statement:
1581 //
1582 // with (obj) {
1583 // function f() {}
1584 // }
1585 //
1586 // which is translated into:
1587 //
1588 // with (obj) {
1589 // // in this case this is not: 'var f; f = function () {};'
1590 // var f = function () {};
1591 // }
1592 //
1593 // Note that if 'f' is accessed from inside the 'with' statement, it
1594 // will be allocated in the context (because we must be able to look
1595 // it up dynamically) but it will also be accessed statically, i.e.,
1596 // with a context slot index and a context chain length for this
1597 // initialization code. Thus, inside the 'with' statement, we need
1598 // both access to the static and the dynamic context chain; the
1599 // runtime needs to provide both.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001600 if (resolve && var != NULL) {
1601 proxy->BindTo(var);
1602
1603 if (FLAG_harmony_modules) {
1604 bool ok;
1605#ifdef DEBUG
1606 if (FLAG_print_interface_details)
1607 PrintF("# Declare %s\n", var->name()->ToAsciiArray());
1608#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001609 proxy->interface()->Unify(var->interface(), zone(), &ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001610 if (!ok) {
1611#ifdef DEBUG
1612 if (FLAG_print_interfaces) {
1613 PrintF("DECLARE TYPE ERROR\n");
1614 PrintF("proxy: ");
1615 proxy->interface()->Print();
1616 PrintF("var: ");
1617 var->interface()->Print();
1618 }
1619#endif
1620 ReportMessage("module_type_error", Vector<Handle<String> >(&name, 1));
1621 }
1622 }
1623 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001624}
1625
1626
1627// Language extension which is only enabled for source files loaded
1628// through the API's extension mechanism. A native function
1629// declaration is resolved by looking up the function through a
1630// callback provided by the extension.
1631Statement* Parser::ParseNativeDeclaration(bool* ok) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001632 int pos = peek_position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633 Expect(Token::FUNCTION, CHECK_OK);
1634 Handle<String> name = ParseIdentifier(CHECK_OK);
1635 Expect(Token::LPAREN, CHECK_OK);
1636 bool done = (peek() == Token::RPAREN);
1637 while (!done) {
1638 ParseIdentifier(CHECK_OK);
1639 done = (peek() == Token::RPAREN);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001640 if (!done) {
1641 Expect(Token::COMMA, CHECK_OK);
1642 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643 }
1644 Expect(Token::RPAREN, CHECK_OK);
1645 Expect(Token::SEMICOLON, CHECK_OK);
1646
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001647 // Make sure that the function containing the native declaration
1648 // isn't lazily compiled. The extension structures are only
1649 // accessible while parsing the first time not when reparsing
1650 // because of lazy compilation.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001651 DeclarationScope(VAR)->ForceEagerCompilation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001653 // TODO(1240846): It's weird that native function declarations are
1654 // introduced dynamically when we meet their declarations, whereas
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001655 // other functions are set up when entering the surrounding scope.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001656 VariableProxy* proxy = NewUnresolved(name, VAR, Interface::NewValue());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001657 Declaration* declaration =
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001658 factory()->NewVariableDeclaration(proxy, VAR, top_scope_, pos);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001659 Declare(declaration, true, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001660 NativeFunctionLiteral* lit = factory()->NewNativeFunctionLiteral(
1661 name, extension_, RelocInfo::kNoPosition);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001662 return factory()->NewExpressionStatement(
1663 factory()->NewAssignment(
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001664 Token::INIT_VAR, proxy, lit, RelocInfo::kNoPosition),
1665 pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001666}
1667
1668
ulan@chromium.org812308e2012-02-29 15:58:45 +00001669Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001670 // FunctionDeclaration ::
1671 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001672 // GeneratorDeclaration ::
1673 // 'function' '*' Identifier '(' FormalParameterListopt ')'
1674 // '{' FunctionBody '}'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675 Expect(Token::FUNCTION, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001676 int pos = position();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001677 bool is_generator = allow_generators() && Check(Token::MUL);
ager@chromium.org04921a82011-06-27 13:21:41 +00001678 bool is_strict_reserved = false;
1679 Handle<String> name = ParseIdentifierOrStrictReservedWord(
1680 &is_strict_reserved, CHECK_OK);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001681 FunctionLiteral* fun = ParseFunctionLiteral(name,
ager@chromium.org04921a82011-06-27 13:21:41 +00001682 is_strict_reserved,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001683 is_generator,
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001684 pos,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001685 FunctionLiteral::DECLARATION,
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001686 CHECK_OK);
1687 // Even if we're not at the top-level of the global or a function
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001688 // scope, we treat it as such and introduce the function with its
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001689 // initial value upon entering the corresponding scope.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001690 // In extended mode, a function behaves as a lexical binding, except in the
1691 // global scope.
1692 VariableMode mode =
1693 is_extended_mode() && !top_scope_->is_global_scope() ? LET : VAR;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001694 VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001695 Declaration* declaration =
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001696 factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_, pos);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001697 Declare(declaration, true, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001698 if (names) names->Add(name, zone());
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001699 return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700}
1701
1702
1703Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001704 if (top_scope_->is_extended_mode()) return ParseScopedBlock(labels, ok);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001705
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706 // Block ::
1707 // '{' Statement* '}'
1708
1709 // Note that a Block does not introduce a new execution scope!
1710 // (ECMA-262, 3rd, 12.2)
1711 //
1712 // Construct block expecting 16 statements.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001713 Block* result =
1714 factory()->NewBlock(labels, 16, false, RelocInfo::kNoPosition);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001715 Target target(&this->target_stack_, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001716 Expect(Token::LBRACE, CHECK_OK);
1717 while (peek() != Token::RBRACE) {
1718 Statement* stat = ParseStatement(NULL, CHECK_OK);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001719 if (stat && !stat->IsEmpty()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001720 result->AddStatement(stat, zone());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001721 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001722 }
1723 Expect(Token::RBRACE, CHECK_OK);
1724 return result;
1725}
1726
1727
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001728Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001729 // The harmony mode uses block elements instead of statements.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001730 //
1731 // Block ::
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001732 // '{' BlockElement* '}'
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001733
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001734 // Construct block expecting 16 statements.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001735 Block* body =
1736 factory()->NewBlock(labels, 16, false, RelocInfo::kNoPosition);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001737 Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001738
1739 // Parse the statements and collect escaping labels.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001740 Expect(Token::LBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001741 block_scope->set_start_position(scanner().location().beg_pos);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001742 { BlockState block_state(this, block_scope);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001743 TargetCollector collector(zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001744 Target target(&this->target_stack_, &collector);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001745 Target target_body(&this->target_stack_, body);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001746
1747 while (peek() != Token::RBRACE) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001748 Statement* stat = ParseBlockElement(NULL, CHECK_OK);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001749 if (stat && !stat->IsEmpty()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001750 body->AddStatement(stat, zone());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001751 }
1752 }
1753 }
1754 Expect(Token::RBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001755 block_scope->set_end_position(scanner().location().end_pos);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001756 block_scope = block_scope->FinalizeBlockScope();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001757 body->set_scope(block_scope);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001758 return body;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001759}
1760
1761
danno@chromium.orgb6451162011-08-17 14:33:23 +00001762Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
ulan@chromium.org812308e2012-02-29 15:58:45 +00001763 ZoneStringList* names,
danno@chromium.orgb6451162011-08-17 14:33:23 +00001764 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001765 // VariableStatement ::
1766 // VariableDeclarations ';'
1767
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001768 Handle<String> ignore;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001769 Block* result =
ulan@chromium.org812308e2012-02-29 15:58:45 +00001770 ParseVariableDeclarations(var_context, NULL, names, &ignore, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001771 ExpectSemicolon(CHECK_OK);
1772 return result;
1773}
1774
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775
1776bool Parser::IsEvalOrArguments(Handle<String> string) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001777 return string.is_identical_to(isolate()->factory()->eval_string()) ||
1778 string.is_identical_to(isolate()->factory()->arguments_string());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001779}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001780
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001781
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001782// If the variable declaration declares exactly one non-const
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001783// variable, then *out is set to that variable. In all other cases,
1784// *out is untouched; in particular, it is the caller's responsibility
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001785// to initialize it properly. This mechanism is used for the parsing
1786// of 'for-in' loops.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001787Block* Parser::ParseVariableDeclarations(
1788 VariableDeclarationContext var_context,
1789 VariableDeclarationProperties* decl_props,
ulan@chromium.org812308e2012-02-29 15:58:45 +00001790 ZoneStringList* names,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001791 Handle<String>* out,
1792 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001793 // VariableDeclarations ::
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001794 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
1795 //
1796 // The ES6 Draft Rev3 specifies the following grammar for const declarations
1797 //
1798 // ConstDeclaration ::
1799 // const ConstBinding (',' ConstBinding)* ';'
1800 // ConstBinding ::
1801 // Identifier '=' AssignmentExpression
1802 //
1803 // TODO(ES6):
1804 // ConstBinding ::
1805 // BindingPattern '=' AssignmentExpression
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001806
1807 int pos = peek_position();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001808 VariableMode mode = VAR;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001809 // True if the binding needs initialization. 'let' and 'const' declared
1810 // bindings are created uninitialized by their declaration nodes and
1811 // need initialization. 'var' declared bindings are always initialized
1812 // immediately by their declaration nodes.
1813 bool needs_init = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001814 bool is_const = false;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001815 Token::Value init_op = Token::INIT_VAR;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816 if (peek() == Token::VAR) {
1817 Consume(Token::VAR);
1818 } else if (peek() == Token::CONST) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001819 // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
1820 //
1821 // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
1822 //
1823 // * It is a Syntax Error if the code that matches this production is not
1824 // contained in extended code.
1825 //
1826 // However disallowing const in classic mode will break compatibility with
1827 // existing pages. Therefore we keep allowing const with the old
1828 // non-harmony semantics in classic mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829 Consume(Token::CONST);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001830 switch (top_scope_->language_mode()) {
1831 case CLASSIC_MODE:
1832 mode = CONST;
1833 init_op = Token::INIT_CONST;
1834 break;
1835 case STRICT_MODE:
1836 ReportMessage("strict_const", Vector<const char*>::empty());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001837 *ok = false;
1838 return NULL;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001839 case EXTENDED_MODE:
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001840 if (var_context == kStatement) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001841 // In extended mode 'const' declarations are only allowed in source
1842 // element positions.
1843 ReportMessage("unprotected_const", Vector<const char*>::empty());
1844 *ok = false;
1845 return NULL;
1846 }
1847 mode = CONST_HARMONY;
1848 init_op = Token::INIT_CONST_HARMONY;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001849 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001850 is_const = true;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001851 needs_init = true;
danno@chromium.orgb6451162011-08-17 14:33:23 +00001852 } else if (peek() == Token::LET) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001853 // ES6 Draft Rev4 section 12.2.1:
1854 //
1855 // LetDeclaration : let LetBindingList ;
1856 //
1857 // * It is a Syntax Error if the code that matches this production is not
1858 // contained in extended code.
1859 if (!is_extended_mode()) {
1860 ReportMessage("illegal_let", Vector<const char*>::empty());
1861 *ok = false;
1862 return NULL;
1863 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00001864 Consume(Token::LET);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001865 if (var_context == kStatement) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001866 // Let declarations are only allowed in source element positions.
danno@chromium.orgb6451162011-08-17 14:33:23 +00001867 ReportMessage("unprotected_let", Vector<const char*>::empty());
1868 *ok = false;
1869 return NULL;
1870 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001871 mode = LET;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001872 needs_init = true;
1873 init_op = Token::INIT_LET;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001874 } else {
1875 UNREACHABLE(); // by current callers
1876 }
1877
ulan@chromium.org812308e2012-02-29 15:58:45 +00001878 Scope* declaration_scope = DeclarationScope(mode);
1879
danno@chromium.orgb6451162011-08-17 14:33:23 +00001880 // The scope of a var/const declared variable anywhere inside a function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001881 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
danno@chromium.orgb6451162011-08-17 14:33:23 +00001882 // transform a source-level var/const declaration into a (Function)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001883 // Scope declaration, and rewrite the source-level initialization into an
1884 // assignment statement. We use a block to collect multiple assignments.
1885 //
1886 // We mark the block as initializer block because we don't want the
1887 // rewriter to add a '.result' assignment to such a block (to get compliant
1888 // behavior for code such as print(eval('var x = 7')), and for cosmetic
1889 // reasons when pretty-printing. Also, unless an assignment (initialization)
1890 // is inside an initializer block, it is ignored.
1891 //
1892 // Create new block with one expected declaration.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001893 Block* block = factory()->NewBlock(NULL, 1, true, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001894 int nvars = 0; // the number of variables declared
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001895 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 do {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001897 if (fni_ != NULL) fni_->Enter();
1898
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001899 // Parse variable name.
1900 if (nvars > 0) Consume(Token::COMMA);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001901 name = ParseIdentifier(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001902 if (fni_ != NULL) fni_->PushVariableName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001903
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001904 // Strict mode variables may not be named eval or arguments
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001905 if (!declaration_scope->is_classic_mode() && IsEvalOrArguments(name)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001906 ReportMessage("strict_var_name", Vector<const char*>::empty());
1907 *ok = false;
1908 return NULL;
1909 }
1910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911 // Declare variable.
1912 // Note that we *always* must treat the initial value via a separate init
1913 // assignment for variables and constants because the value must be assigned
1914 // when the variable is encountered in the source. But the variable/constant
1915 // is declared (and set to 'undefined') upon entering the function within
1916 // which the variable or constant is declared. Only function variables have
1917 // an initial value in the declaration (because they are initialized upon
1918 // entering the function).
1919 //
1920 // If we have a const declaration, in an inner scope, the proxy is always
1921 // bound to the declared variable (independent of possibly surrounding with
1922 // statements).
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001923 // For let/const declarations in harmony mode, we can also immediately
1924 // pre-resolve the proxy because it resides in the same scope as the
1925 // declaration.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001926 Interface* interface =
1927 is_const ? Interface::NewConst() : Interface::NewValue();
1928 VariableProxy* proxy = NewUnresolved(name, mode, interface);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001929 Declaration* declaration =
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001930 factory()->NewVariableDeclaration(proxy, mode, top_scope_, pos);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001931 Declare(declaration, mode != VAR, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 nvars++;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001933 if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001934 ReportMessageAt(scanner().location(), "too_many_variables",
1935 Vector<const char*>::empty());
1936 *ok = false;
1937 return NULL;
1938 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001939 if (names) names->Add(name, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001940
1941 // Parse initialization expression if present and/or needed. A
1942 // declaration of the form:
1943 //
1944 // var v = x;
1945 //
1946 // is syntactic sugar for:
1947 //
1948 // var v; v = x;
1949 //
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001950 // In particular, we need to re-lookup 'v' (in top_scope_, not
1951 // declaration_scope) as it may be a different 'v' than the 'v' in the
1952 // declaration (e.g., if we are inside a 'with' statement or 'catch'
1953 // block).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001954 //
1955 // However, note that const declarations are different! A const
1956 // declaration of the form:
1957 //
1958 // const c = x;
1959 //
1960 // is *not* syntactic sugar for:
1961 //
1962 // const c; c = x;
1963 //
1964 // The "variable" c initialized to x is the same as the declared
1965 // one - there is no re-lookup (see the last parameter of the
1966 // Declare() call above).
1967
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001968 Scope* initialization_scope = is_const ? declaration_scope : top_scope_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001969 Expression* value = NULL;
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001970 int pos = -1;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001971 // Harmony consts have non-optional initializers.
1972 if (peek() == Token::ASSIGN || mode == CONST_HARMONY) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973 Expect(Token::ASSIGN, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001974 pos = position();
danno@chromium.orgb6451162011-08-17 14:33:23 +00001975 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001976 // Don't infer if it is "a = function(){...}();"-like expression.
ager@chromium.org04921a82011-06-27 13:21:41 +00001977 if (fni_ != NULL &&
1978 value->AsCall() == NULL &&
1979 value->AsCallNew() == NULL) {
1980 fni_->Infer();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001981 } else {
1982 fni_->RemoveLastFunction();
ager@chromium.org04921a82011-06-27 13:21:41 +00001983 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001984 if (decl_props != NULL) *decl_props = kHasInitializers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985 }
1986
danno@chromium.orgc612e022011-11-10 11:38:15 +00001987 // Record the end position of the initializer.
1988 if (proxy->var() != NULL) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001989 proxy->var()->set_initializer_position(position());
danno@chromium.orgc612e022011-11-10 11:38:15 +00001990 }
1991
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001992 // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
1993 if (value == NULL && needs_init) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001994 value = GetLiteralUndefined(position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995 }
1996
1997 // Global variable declarations must be compiled in a specific
1998 // way. When the script containing the global variable declaration
1999 // is entered, the global variable must be declared, so that if it
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002000 // doesn't exist (on the global object itself, see ES5 errata) it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001 // gets created with an initial undefined value. This is handled
2002 // by the declarations part of the function representing the
2003 // top-level global code; see Runtime::DeclareGlobalVariable. If
2004 // it already exists (in the object or in a prototype), it is
2005 // *not* touched until the variable declaration statement is
2006 // executed.
2007 //
2008 // Executing the variable declaration statement will always
2009 // guarantee to give the global object a "local" variable; a
2010 // variable defined in the global object and not in any
2011 // prototype. This way, global variable declarations can shadow
2012 // properties in the prototype chain, but only after the variable
2013 // declaration statement has been executed. This is important in
2014 // browsers where the global object (window) has lots of
2015 // properties defined in prototype objects.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002016 if (initialization_scope->is_global_scope() &&
2017 !IsLexicalVariableMode(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002018 // Compute the arguments for the runtime call.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002019 ZoneList<Expression*>* arguments =
2020 new(zone()) ZoneList<Expression*>(3, zone());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002021 // We have at least 1 parameter.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002022 arguments->Add(factory()->NewLiteral(name, pos), zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002023 CallRuntime* initialize;
2024
2025 if (is_const) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002026 arguments->Add(value, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002027 value = NULL; // zap the value to avoid the unnecessary assignment
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002028
2029 // Construct the call to Runtime_InitializeConstGlobal
2030 // and add it to the initialization statement block.
2031 // Note that the function does different things depending on
2032 // the number of arguments (1 or 2).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002033 initialize = factory()->NewCallRuntime(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002034 isolate()->factory()->InitializeConstGlobal_string(),
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002035 Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002036 arguments, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002037 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002038 // Add strict mode.
2039 // We may want to pass singleton to avoid Literal allocations.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002040 LanguageMode language_mode = initialization_scope->language_mode();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002041 arguments->Add(factory()->NewNumberLiteral(language_mode, pos), zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002042
2043 // Be careful not to assign a value to the global variable if
2044 // we're in a with. The initialization value should not
2045 // necessarily be stored in the global object in that case,
2046 // which is why we need to generate a separate assignment node.
2047 if (value != NULL && !inside_with()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002048 arguments->Add(value, zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002049 value = NULL; // zap the value to avoid the unnecessary assignment
2050 }
2051
2052 // Construct the call to Runtime_InitializeVarGlobal
2053 // and add it to the initialization statement block.
2054 // Note that the function does different things depending on
2055 // the number of arguments (2 or 3).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002056 initialize = factory()->NewCallRuntime(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002057 isolate()->factory()->InitializeVarGlobal_string(),
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002058 Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002059 arguments, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002061
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002062 block->AddStatement(
2063 factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition),
2064 zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002065 } else if (needs_init) {
2066 // Constant initializations always assign to the declared constant which
2067 // is always at the function scope level. This is only relevant for
2068 // dynamically looked-up variables and constants (the start context for
2069 // constant lookups is always the function context, while it is the top
2070 // context for var declared variables). Sigh...
2071 // For 'let' and 'const' declared variables in harmony mode the
2072 // initialization also always assigns to the declared variable.
2073 ASSERT(proxy != NULL);
2074 ASSERT(proxy->var() != NULL);
2075 ASSERT(value != NULL);
2076 Assignment* assignment =
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002077 factory()->NewAssignment(init_op, proxy, value, pos);
2078 block->AddStatement(
2079 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
2080 zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002081 value = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002082 }
2083
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002084 // Add an assignment node to the initialization statement block if we still
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002085 // have a pending initialization value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002086 if (value != NULL) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002087 ASSERT(mode == VAR);
2088 // 'var' initializations are simply assignments (with all the consequences
2089 // if they are inside a 'with' statement - they may change a 'with' object
2090 // property).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002091 VariableProxy* proxy =
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002092 initialization_scope->NewUnresolved(factory(), name, interface);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002093 Assignment* assignment =
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002094 factory()->NewAssignment(init_op, proxy, value, pos);
2095 block->AddStatement(
2096 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
2097 zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002098 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002099
2100 if (fni_ != NULL) fni_->Leave();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002101 } while (peek() == Token::COMMA);
2102
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002103 // If there was a single non-const declaration, return it in the output
2104 // parameter for possible use by for/in.
2105 if (nvars == 1 && !is_const) {
2106 *out = name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002107 }
2108
2109 return block;
2110}
2111
2112
2113static bool ContainsLabel(ZoneStringList* labels, Handle<String> label) {
2114 ASSERT(!label.is_null());
2115 if (labels != NULL)
2116 for (int i = labels->length(); i-- > 0; )
2117 if (labels->at(i).is_identical_to(label))
2118 return true;
2119
2120 return false;
2121}
2122
2123
2124Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
2125 bool* ok) {
2126 // ExpressionStatement | LabelledStatement ::
2127 // Expression ';'
2128 // Identifier ':' Statement
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002129 int pos = peek_position();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002130 bool starts_with_idenfifier = peek_any_identifier();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002131 Expression* expr = ParseExpression(true, CHECK_OK);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002132 if (peek() == Token::COLON && starts_with_idenfifier && expr != NULL &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002133 expr->AsVariableProxy() != NULL &&
2134 !expr->AsVariableProxy()->is_this()) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002135 // Expression is a single identifier, and not, e.g., a parenthesized
2136 // identifier.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002137 VariableProxy* var = expr->AsVariableProxy();
2138 Handle<String> label = var->name();
2139 // TODO(1240780): We don't check for redeclaration of labels
2140 // during preparsing since keeping track of the set of active
2141 // labels requires nontrivial changes to the way scopes are
2142 // structured. However, these are probably changes we want to
2143 // make later anyway so we should go back and fix this then.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002144 if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002145 SmartArrayPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002146 const char* elms[2] = { "Label", *c_string };
2147 Vector<const char*> args(elms, 2);
2148 ReportMessage("redeclaration", args);
2149 *ok = false;
2150 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002151 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002152 if (labels == NULL) {
2153 labels = new(zone()) ZoneStringList(4, zone());
2154 }
2155 labels->Add(label, zone());
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002156 // Remove the "ghost" variable that turned out to be a label
2157 // from the top scope. This way, we don't try to resolve it
2158 // during the scope processing.
2159 top_scope_->RemoveUnresolved(var);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002160 Expect(Token::COLON, CHECK_OK);
2161 return ParseStatement(labels, ok);
2162 }
2163
whesse@chromium.org7b260152011-06-20 15:33:18 +00002164 // If we have an extension, we allow a native function declaration.
2165 // A native function declaration starts with "native function" with
2166 // no line-terminator between the two words.
2167 if (extension_ != NULL &&
2168 peek() == Token::FUNCTION &&
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002169 !scanner().HasAnyLineTerminatorBeforeNext() &&
whesse@chromium.org7b260152011-06-20 15:33:18 +00002170 expr != NULL &&
2171 expr->AsVariableProxy() != NULL &&
2172 expr->AsVariableProxy()->name()->Equals(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002173 isolate()->heap()->native_string()) &&
whesse@chromium.org7b260152011-06-20 15:33:18 +00002174 !scanner().literal_contains_escapes()) {
2175 return ParseNativeDeclaration(ok);
2176 }
2177
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00002178 // Parsed expression statement, or the context-sensitive 'module' keyword.
2179 // Only expect semicolon in the former case.
2180 if (!FLAG_harmony_modules ||
2181 peek() != Token::IDENTIFIER ||
2182 scanner().HasAnyLineTerminatorBeforeNext() ||
2183 expr->AsVariableProxy() == NULL ||
2184 !expr->AsVariableProxy()->name()->Equals(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002185 isolate()->heap()->module_string()) ||
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00002186 scanner().literal_contains_escapes()) {
2187 ExpectSemicolon(CHECK_OK);
2188 }
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002189 return factory()->NewExpressionStatement(expr, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190}
2191
2192
2193IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) {
2194 // IfStatement ::
2195 // 'if' '(' Expression ')' Statement ('else' Statement)?
2196
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002197 int pos = peek_position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002198 Expect(Token::IF, CHECK_OK);
2199 Expect(Token::LPAREN, CHECK_OK);
2200 Expression* condition = ParseExpression(true, CHECK_OK);
2201 Expect(Token::RPAREN, CHECK_OK);
2202 Statement* then_statement = ParseStatement(labels, CHECK_OK);
2203 Statement* else_statement = NULL;
2204 if (peek() == Token::ELSE) {
2205 Next();
2206 else_statement = ParseStatement(labels, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002207 } else {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002208 else_statement = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002209 }
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002210 return factory()->NewIfStatement(
2211 condition, then_statement, else_statement, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002212}
2213
2214
2215Statement* Parser::ParseContinueStatement(bool* ok) {
2216 // ContinueStatement ::
2217 // 'continue' Identifier? ';'
2218
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002219 int pos = peek_position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002220 Expect(Token::CONTINUE, CHECK_OK);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002221 Handle<String> label = Handle<String>::null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002222 Token::Value tok = peek();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002223 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002224 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002225 label = ParseIdentifier(CHECK_OK);
2226 }
2227 IterationStatement* target = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002228 target = LookupContinueTarget(label, CHECK_OK);
2229 if (target == NULL) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002230 // Illegal continue statement.
2231 const char* message = "illegal_continue";
2232 Vector<Handle<String> > args;
2233 if (!label.is_null()) {
2234 message = "unknown_label";
2235 args = Vector<Handle<String> >(&label, 1);
2236 }
2237 ReportMessageAt(scanner().location(), message, args);
2238 *ok = false;
2239 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002240 }
2241 ExpectSemicolon(CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002242 return factory()->NewContinueStatement(target, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002243}
2244
2245
2246Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
2247 // BreakStatement ::
2248 // 'break' Identifier? ';'
2249
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002250 int pos = peek_position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251 Expect(Token::BREAK, CHECK_OK);
2252 Handle<String> label;
2253 Token::Value tok = peek();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002254 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002255 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002256 label = ParseIdentifier(CHECK_OK);
2257 }
ager@chromium.org32912102009-01-16 10:38:43 +00002258 // Parse labeled break statements that target themselves into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002259 // empty statements, e.g. 'l1: l2: l3: break l2;'
2260 if (!label.is_null() && ContainsLabel(labels, label)) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002261 ExpectSemicolon(CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002262 return factory()->NewEmptyStatement(pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002263 }
2264 BreakableStatement* target = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002265 target = LookupBreakTarget(label, CHECK_OK);
2266 if (target == NULL) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002267 // Illegal break statement.
2268 const char* message = "illegal_break";
2269 Vector<Handle<String> > args;
2270 if (!label.is_null()) {
2271 message = "unknown_label";
2272 args = Vector<Handle<String> >(&label, 1);
2273 }
2274 ReportMessageAt(scanner().location(), message, args);
2275 *ok = false;
2276 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002277 }
2278 ExpectSemicolon(CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002279 return factory()->NewBreakStatement(target, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002280}
2281
2282
2283Statement* Parser::ParseReturnStatement(bool* ok) {
2284 // ReturnStatement ::
2285 // 'return' Expression? ';'
2286
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002287 // Consume the return token. It is necessary to do that before
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002288 // reporting any errors on it, because of the way errors are
2289 // reported (underlining).
2290 Expect(Token::RETURN, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002291 int pos = position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002292
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002293 Token::Value tok = peek();
2294 Statement* result;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002295 Expression* return_value;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002296 if (scanner().HasAnyLineTerminatorBeforeNext() ||
2297 tok == Token::SEMICOLON ||
2298 tok == Token::RBRACE ||
2299 tok == Token::EOS) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002300 return_value = GetLiteralUndefined(position());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002301 } else {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002302 return_value = ParseExpression(true, CHECK_OK);
2303 }
2304 ExpectSemicolon(CHECK_OK);
2305 if (is_generator()) {
2306 Expression* generator = factory()->NewVariableProxy(
2307 current_function_state_->generator_object_variable());
2308 Expression* yield = factory()->NewYield(
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002309 generator, return_value, Yield::FINAL, pos);
2310 result = factory()->NewExpressionStatement(yield, pos);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002311 } else {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002312 result = factory()->NewReturnStatement(return_value, pos);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002313 }
2314
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002315 // An ECMAScript program is considered syntactically incorrect if it
2316 // contains a return statement that is not within the body of a
2317 // function. See ECMA-262, section 12.9, page 67.
2318 //
2319 // To be consistent with KJS we report the syntax error at runtime.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002320 Scope* declaration_scope = top_scope_->DeclarationScope();
2321 if (declaration_scope->is_global_scope() ||
2322 declaration_scope->is_eval_scope()) {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00002323 Handle<String> message = isolate()->factory()->illegal_return_string();
2324 Expression* throw_error =
2325 NewThrowSyntaxError(message, Handle<Object>::null());
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002326 return factory()->NewExpressionStatement(throw_error, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002327 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002328 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002329}
2330
2331
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002332Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
2333 // WithStatement ::
2334 // 'with' '(' Expression ')' Statement
2335
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002336 Expect(Token::WITH, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002337 int pos = position();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002338
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002339 if (!top_scope_->is_classic_mode()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002340 ReportMessage("strict_mode_with", Vector<const char*>::empty());
2341 *ok = false;
2342 return NULL;
2343 }
2344
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002345 Expect(Token::LPAREN, CHECK_OK);
2346 Expression* expr = ParseExpression(true, CHECK_OK);
2347 Expect(Token::RPAREN, CHECK_OK);
2348
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002349 top_scope_->DeclarationScope()->RecordWithStatement();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002350 Scope* with_scope = NewScope(top_scope_, WITH_SCOPE);
2351 Statement* stmt;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002352 { BlockState block_state(this, with_scope);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002353 with_scope->set_start_position(scanner().peek_location().beg_pos);
2354 stmt = ParseStatement(labels, CHECK_OK);
2355 with_scope->set_end_position(scanner().location().end_pos);
2356 }
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002357 return factory()->NewWithStatement(with_scope, expr, stmt, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002358}
2359
2360
2361CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
2362 // CaseClause ::
2363 // 'case' Expression ':' Statement*
2364 // 'default' ':' Statement*
2365
2366 Expression* label = NULL; // NULL expression indicates default case
2367 if (peek() == Token::CASE) {
2368 Expect(Token::CASE, CHECK_OK);
2369 label = ParseExpression(true, CHECK_OK);
2370 } else {
2371 Expect(Token::DEFAULT, CHECK_OK);
2372 if (*default_seen_ptr) {
2373 ReportMessage("multiple_defaults_in_switch",
2374 Vector<const char*>::empty());
2375 *ok = false;
2376 return NULL;
2377 }
2378 *default_seen_ptr = true;
2379 }
2380 Expect(Token::COLON, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002381 int pos = position();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002382 ZoneList<Statement*>* statements =
2383 new(zone()) ZoneList<Statement*>(5, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002384 while (peek() != Token::CASE &&
2385 peek() != Token::DEFAULT &&
2386 peek() != Token::RBRACE) {
2387 Statement* stat = ParseStatement(NULL, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002388 statements->Add(stat, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002389 }
2390
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002391 return factory()->NewCaseClause(label, statements, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002392}
2393
2394
2395SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels,
2396 bool* ok) {
2397 // SwitchStatement ::
2398 // 'switch' '(' Expression ')' '{' CaseClause* '}'
2399
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002400 SwitchStatement* statement =
2401 factory()->NewSwitchStatement(labels, peek_position());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002402 Target target(&this->target_stack_, statement);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002403
2404 Expect(Token::SWITCH, CHECK_OK);
2405 Expect(Token::LPAREN, CHECK_OK);
2406 Expression* tag = ParseExpression(true, CHECK_OK);
2407 Expect(Token::RPAREN, CHECK_OK);
2408
2409 bool default_seen = false;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002410 ZoneList<CaseClause*>* cases = new(zone()) ZoneList<CaseClause*>(4, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002411 Expect(Token::LBRACE, CHECK_OK);
2412 while (peek() != Token::RBRACE) {
2413 CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002414 cases->Add(clause, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002415 }
2416 Expect(Token::RBRACE, CHECK_OK);
2417
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002418 if (statement) statement->Initialize(tag, cases);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002419 return statement;
2420}
2421
2422
2423Statement* Parser::ParseThrowStatement(bool* ok) {
2424 // ThrowStatement ::
2425 // 'throw' Expression ';'
2426
2427 Expect(Token::THROW, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002428 int pos = position();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002429 if (scanner().HasAnyLineTerminatorBeforeNext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002430 ReportMessage("newline_after_throw", Vector<const char*>::empty());
2431 *ok = false;
2432 return NULL;
2433 }
2434 Expression* exception = ParseExpression(true, CHECK_OK);
2435 ExpectSemicolon(CHECK_OK);
2436
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002437 return factory()->NewExpressionStatement(
2438 factory()->NewThrow(exception, pos), pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002439}
2440
2441
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002442TryStatement* Parser::ParseTryStatement(bool* ok) {
2443 // TryStatement ::
2444 // 'try' Block Catch
2445 // 'try' Block Finally
2446 // 'try' Block Catch Finally
2447 //
2448 // Catch ::
2449 // 'catch' '(' Identifier ')' Block
2450 //
2451 // Finally ::
2452 // 'finally' Block
2453
2454 Expect(Token::TRY, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002455 int pos = position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002456
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002457 TargetCollector try_collector(zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002458 Block* try_block;
2459
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002460 { Target target(&this->target_stack_, &try_collector);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002461 try_block = ParseBlock(NULL, CHECK_OK);
2462 }
2463
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002464 Token::Value tok = peek();
2465 if (tok != Token::CATCH && tok != Token::FINALLY) {
2466 ReportMessage("no_catch_or_finally", Vector<const char*>::empty());
2467 *ok = false;
2468 return NULL;
2469 }
2470
2471 // If we can break out from the catch block and there is a finally block,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002472 // then we will need to collect escaping targets from the catch
2473 // block. Since we don't know yet if there will be a finally block, we
2474 // always collect the targets.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002475 TargetCollector catch_collector(zone());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002476 Scope* catch_scope = NULL;
2477 Variable* catch_variable = NULL;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002478 Block* catch_block = NULL;
2479 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002480 if (tok == Token::CATCH) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002481 Consume(Token::CATCH);
2482
2483 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002484 catch_scope = NewScope(top_scope_, CATCH_SCOPE);
2485 catch_scope->set_start_position(scanner().location().beg_pos);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002486 name = ParseIdentifier(CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002487
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002488 if (!top_scope_->is_classic_mode() && IsEvalOrArguments(name)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002489 ReportMessage("strict_catch_variable", Vector<const char*>::empty());
2490 *ok = false;
2491 return NULL;
2492 }
2493
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002494 Expect(Token::RPAREN, CHECK_OK);
2495
2496 if (peek() == Token::LBRACE) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002497 Target target(&this->target_stack_, &catch_collector);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002498 VariableMode mode = is_extended_mode() ? LET : VAR;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002499 catch_variable =
2500 catch_scope->DeclareLocal(name, mode, kCreatedInitialized);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002501
danno@chromium.orgc612e022011-11-10 11:38:15 +00002502 BlockState block_state(this, catch_scope);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002503 catch_block = ParseBlock(NULL, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002504 } else {
2505 Expect(Token::LBRACE, CHECK_OK);
2506 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002507 catch_scope->set_end_position(scanner().location().end_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002508 tok = peek();
2509 }
2510
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002511 Block* finally_block = NULL;
2512 if (tok == Token::FINALLY || catch_block == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002513 Consume(Token::FINALLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002514 finally_block = ParseBlock(NULL, CHECK_OK);
2515 }
2516
2517 // Simplify the AST nodes by converting:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002518 // 'try B0 catch B1 finally B2'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002519 // to:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002520 // 'try { try B0 catch B1 } finally B2'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002521
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002522 if (catch_block != NULL && finally_block != NULL) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002523 // If we have both, create an inner try/catch.
2524 ASSERT(catch_scope != NULL && catch_variable != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002525 int index = current_function_state_->NextHandlerIndex();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002526 TryCatchStatement* statement = factory()->NewTryCatchStatement(
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002527 index, try_block, catch_scope, catch_variable, catch_block,
2528 RelocInfo::kNoPosition);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002529 statement->set_escaping_targets(try_collector.targets());
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002530 try_block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002531 try_block->AddStatement(statement, zone());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002532 catch_block = NULL; // Clear to indicate it's been handled.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002533 }
2534
2535 TryStatement* result = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002536 if (catch_block != NULL) {
2537 ASSERT(finally_block == NULL);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002538 ASSERT(catch_scope != NULL && catch_variable != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002539 int index = current_function_state_->NextHandlerIndex();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002540 result = factory()->NewTryCatchStatement(
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002541 index, try_block, catch_scope, catch_variable, catch_block, pos);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002542 } else {
2543 ASSERT(finally_block != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002544 int index = current_function_state_->NextHandlerIndex();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002545 result = factory()->NewTryFinallyStatement(
2546 index, try_block, finally_block, pos);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002547 // Combine the jump targets of the try block and the possible catch block.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002548 try_collector.targets()->AddAll(*catch_collector.targets(), zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002549 }
2550
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002551 result->set_escaping_targets(try_collector.targets());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002552 return result;
2553}
2554
2555
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002556DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels,
2557 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002558 // DoStatement ::
2559 // 'do' Statement 'while' '(' Expression ')' ';'
2560
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002561 DoWhileStatement* loop =
2562 factory()->NewDoWhileStatement(labels, peek_position());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002563 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002564
2565 Expect(Token::DO, CHECK_OK);
2566 Statement* body = ParseStatement(NULL, CHECK_OK);
2567 Expect(Token::WHILE, CHECK_OK);
2568 Expect(Token::LPAREN, CHECK_OK);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002569
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002570 Expression* cond = ParseExpression(true, CHECK_OK);
2571 Expect(Token::RPAREN, CHECK_OK);
2572
2573 // Allow do-statements to be terminated with and without
2574 // semi-colons. This allows code such as 'do;while(0)return' to
2575 // parse, which would not be the case if we had used the
2576 // ExpectSemicolon() functionality here.
2577 if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
2578
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002579 if (loop != NULL) loop->Initialize(cond, body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002580 return loop;
2581}
2582
2583
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002584WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002585 // WhileStatement ::
2586 // 'while' '(' Expression ')' Statement
2587
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002588 WhileStatement* loop = factory()->NewWhileStatement(labels, peek_position());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002589 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002590
2591 Expect(Token::WHILE, CHECK_OK);
2592 Expect(Token::LPAREN, CHECK_OK);
2593 Expression* cond = ParseExpression(true, CHECK_OK);
2594 Expect(Token::RPAREN, CHECK_OK);
2595 Statement* body = ParseStatement(NULL, CHECK_OK);
2596
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002597 if (loop != NULL) loop->Initialize(cond, body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002598 return loop;
2599}
2600
2601
danno@chromium.org41728482013-06-12 22:31:22 +00002602bool Parser::CheckInOrOf(bool accept_OF,
2603 ForEachStatement::VisitMode* visit_mode) {
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002604 if (Check(Token::IN)) {
2605 *visit_mode = ForEachStatement::ENUMERATE;
2606 return true;
danno@chromium.org41728482013-06-12 22:31:22 +00002607 } else if (allow_for_of() && accept_OF &&
2608 CheckContextualKeyword(CStrVector("of"))) {
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002609 *visit_mode = ForEachStatement::ITERATE;
2610 return true;
2611 }
2612 return false;
2613}
2614
2615
2616void Parser::InitializeForEachStatement(ForEachStatement* stmt,
2617 Expression* each,
2618 Expression* subject,
2619 Statement* body) {
2620 ForOfStatement* for_of = stmt->AsForOfStatement();
2621
2622 if (for_of != NULL) {
2623 Factory* heap_factory = isolate()->factory();
2624 Handle<String> iterator_str = heap_factory->InternalizeOneByteString(
2625 STATIC_ASCII_VECTOR(".iterator"));
2626 Handle<String> result_str = heap_factory->InternalizeOneByteString(
2627 STATIC_ASCII_VECTOR(".result"));
2628 Variable* iterator =
2629 top_scope_->DeclarationScope()->NewTemporary(iterator_str);
2630 Variable* result = top_scope_->DeclarationScope()->NewTemporary(result_str);
2631
2632 Expression* assign_iterator;
2633 Expression* next_result;
2634 Expression* result_done;
2635 Expression* assign_each;
2636
2637 // var iterator = iterable;
2638 {
2639 Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
2640 assign_iterator = factory()->NewAssignment(
2641 Token::ASSIGN, iterator_proxy, subject, RelocInfo::kNoPosition);
2642 }
2643
2644 // var result = iterator.next();
2645 {
2646 Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002647 Expression* next_literal = factory()->NewLiteral(
2648 heap_factory->next_string(), RelocInfo::kNoPosition);
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002649 Expression* next_property = factory()->NewProperty(
2650 iterator_proxy, next_literal, RelocInfo::kNoPosition);
2651 ZoneList<Expression*>* next_arguments =
2652 new(zone()) ZoneList<Expression*>(0, zone());
2653 Expression* next_call = factory()->NewCall(
2654 next_property, next_arguments, RelocInfo::kNoPosition);
2655 Expression* result_proxy = factory()->NewVariableProxy(result);
2656 next_result = factory()->NewAssignment(
2657 Token::ASSIGN, result_proxy, next_call, RelocInfo::kNoPosition);
2658 }
2659
2660 // result.done
2661 {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002662 Expression* done_literal = factory()->NewLiteral(
2663 heap_factory->done_string(), RelocInfo::kNoPosition);
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002664 Expression* result_proxy = factory()->NewVariableProxy(result);
2665 result_done = factory()->NewProperty(
2666 result_proxy, done_literal, RelocInfo::kNoPosition);
2667 }
2668
2669 // each = result.value
2670 {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002671 Expression* value_literal = factory()->NewLiteral(
2672 heap_factory->value_string(), RelocInfo::kNoPosition);
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002673 Expression* result_proxy = factory()->NewVariableProxy(result);
2674 Expression* result_value = factory()->NewProperty(
2675 result_proxy, value_literal, RelocInfo::kNoPosition);
2676 assign_each = factory()->NewAssignment(
2677 Token::ASSIGN, each, result_value, RelocInfo::kNoPosition);
2678 }
2679
2680 for_of->Initialize(each, subject, body,
2681 assign_iterator, next_result, result_done, assign_each);
2682 } else {
2683 stmt->Initialize(each, subject, body);
2684 }
2685}
2686
2687
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002688Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
2689 // ForStatement ::
2690 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
2691
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002692 int pos = peek_position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002693 Statement* init = NULL;
2694
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002695 // Create an in-between scope for let-bound iteration variables.
2696 Scope* saved_scope = top_scope_;
2697 Scope* for_scope = NewScope(top_scope_, BLOCK_SCOPE);
2698 top_scope_ = for_scope;
2699
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002700 Expect(Token::FOR, CHECK_OK);
2701 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002702 for_scope->set_start_position(scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703 if (peek() != Token::SEMICOLON) {
2704 if (peek() == Token::VAR || peek() == Token::CONST) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002705 bool is_const = peek() == Token::CONST;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002706 Handle<String> name;
danno@chromium.org41728482013-06-12 22:31:22 +00002707 VariableDeclarationProperties decl_props = kHasNoInitializers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002708 Block* variable_statement =
danno@chromium.org41728482013-06-12 22:31:22 +00002709 ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name,
2710 CHECK_OK);
2711 bool accept_OF = decl_props == kHasNoInitializers;
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002712 ForEachStatement::VisitMode mode;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002713
danno@chromium.org41728482013-06-12 22:31:22 +00002714 if (!name.is_null() && CheckInOrOf(accept_OF, &mode)) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002715 Interface* interface =
2716 is_const ? Interface::NewConst() : Interface::NewValue();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002717 ForEachStatement* loop =
2718 factory()->NewForEachStatement(mode, labels, pos);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002719 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002720
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002721 Expression* enumerable = ParseExpression(true, CHECK_OK);
2722 Expect(Token::RPAREN, CHECK_OK);
2723
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002724 VariableProxy* each =
2725 top_scope_->NewUnresolved(factory(), name, interface);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002726 Statement* body = ParseStatement(NULL, CHECK_OK);
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002727 InitializeForEachStatement(loop, each, enumerable, body);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002728 Block* result =
2729 factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002730 result->AddStatement(variable_statement, zone());
2731 result->AddStatement(loop, zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002732 top_scope_ = saved_scope;
2733 for_scope->set_end_position(scanner().location().end_pos);
2734 for_scope = for_scope->FinalizeBlockScope();
2735 ASSERT(for_scope == NULL);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002736 // Parsed for-in loop w/ variable/const declaration.
2737 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002738 } else {
2739 init = variable_statement;
2740 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002741 } else if (peek() == Token::LET) {
2742 Handle<String> name;
2743 VariableDeclarationProperties decl_props = kHasNoInitializers;
2744 Block* variable_statement =
ulan@chromium.org812308e2012-02-29 15:58:45 +00002745 ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name,
2746 CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002747 bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
danno@chromium.org41728482013-06-12 22:31:22 +00002748 bool accept_OF = decl_props == kHasNoInitializers;
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002749 ForEachStatement::VisitMode mode;
2750
danno@chromium.org41728482013-06-12 22:31:22 +00002751 if (accept_IN && CheckInOrOf(accept_OF, &mode)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002752 // Rewrite a for-in statement of the form
2753 //
2754 // for (let x in e) b
2755 //
2756 // into
2757 //
2758 // <let x' be a temporary variable>
2759 // for (x' in e) {
2760 // let x;
2761 // x = x';
2762 // b;
2763 // }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002764
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002765 // TODO(keuchel): Move the temporary variable to the block scope, after
2766 // implementing stack allocated block scoped variables.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002767 Factory* heap_factory = isolate()->factory();
2768 Handle<String> tempstr =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002769 heap_factory->NewConsString(heap_factory->dot_for_string(), name);
2770 Handle<String> tempname = heap_factory->InternalizeString(tempstr);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002771 Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002772 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002773 ForEachStatement* loop =
2774 factory()->NewForEachStatement(mode, labels, pos);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002775 Target target(&this->target_stack_, loop);
2776
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002777 // The expression does not see the loop variable.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002778 top_scope_ = saved_scope;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002779 Expression* enumerable = ParseExpression(true, CHECK_OK);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002780 top_scope_ = for_scope;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002781 Expect(Token::RPAREN, CHECK_OK);
2782
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002783 VariableProxy* each =
2784 top_scope_->NewUnresolved(factory(), name, Interface::NewValue());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002785 Statement* body = ParseStatement(NULL, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002786 Block* body_block =
2787 factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002788 Assignment* assignment = factory()->NewAssignment(
2789 Token::ASSIGN, each, temp_proxy, RelocInfo::kNoPosition);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002790 Statement* assignment_statement = factory()->NewExpressionStatement(
2791 assignment, RelocInfo::kNoPosition);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002792 body_block->AddStatement(variable_statement, zone());
2793 body_block->AddStatement(assignment_statement, zone());
2794 body_block->AddStatement(body, zone());
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002795 InitializeForEachStatement(loop, temp_proxy, enumerable, body_block);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002796 top_scope_ = saved_scope;
2797 for_scope->set_end_position(scanner().location().end_pos);
2798 for_scope = for_scope->FinalizeBlockScope();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002799 body_block->set_scope(for_scope);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002800 // Parsed for-in loop w/ let declaration.
2801 return loop;
2802
2803 } else {
2804 init = variable_statement;
2805 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002806 } else {
2807 Expression* expression = ParseExpression(false, CHECK_OK);
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002808 ForEachStatement::VisitMode mode;
danno@chromium.org41728482013-06-12 22:31:22 +00002809 bool accept_OF = expression->AsVariableProxy();
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002810
danno@chromium.org41728482013-06-12 22:31:22 +00002811 if (CheckInOrOf(accept_OF, &mode)) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002812 // Signal a reference error if the expression is an invalid
2813 // left-hand side expression. We could report this as a syntax
2814 // error here but for compatibility with JSC we choose to report
2815 // the error at runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002816 if (expression == NULL || !expression->IsValidLeftHandSide()) {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00002817 Handle<String> message =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002818 isolate()->factory()->invalid_lhs_in_for_in_string();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00002819 expression = NewThrowReferenceError(message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002820 }
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002821 ForEachStatement* loop =
2822 factory()->NewForEachStatement(mode, labels, pos);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002823 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002825 Expression* enumerable = ParseExpression(true, CHECK_OK);
2826 Expect(Token::RPAREN, CHECK_OK);
2827
2828 Statement* body = ParseStatement(NULL, CHECK_OK);
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002829 InitializeForEachStatement(loop, expression, enumerable, body);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002830 top_scope_ = saved_scope;
2831 for_scope->set_end_position(scanner().location().end_pos);
2832 for_scope = for_scope->FinalizeBlockScope();
2833 ASSERT(for_scope == NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002834 // Parsed for-in loop.
2835 return loop;
2836
2837 } else {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002838 init = factory()->NewExpressionStatement(
2839 expression, RelocInfo::kNoPosition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002840 }
2841 }
2842 }
2843
2844 // Standard 'for' loop
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002845 ForStatement* loop = factory()->NewForStatement(labels, pos);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002846 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002847
2848 // Parsed initializer at this point.
2849 Expect(Token::SEMICOLON, CHECK_OK);
2850
2851 Expression* cond = NULL;
2852 if (peek() != Token::SEMICOLON) {
2853 cond = ParseExpression(true, CHECK_OK);
2854 }
2855 Expect(Token::SEMICOLON, CHECK_OK);
2856
2857 Statement* next = NULL;
2858 if (peek() != Token::RPAREN) {
2859 Expression* exp = ParseExpression(true, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002860 next = factory()->NewExpressionStatement(exp, RelocInfo::kNoPosition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002861 }
2862 Expect(Token::RPAREN, CHECK_OK);
2863
2864 Statement* body = ParseStatement(NULL, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002865 top_scope_ = saved_scope;
2866 for_scope->set_end_position(scanner().location().end_pos);
2867 for_scope = for_scope->FinalizeBlockScope();
2868 if (for_scope != NULL) {
2869 // Rewrite a for statement of the form
2870 //
2871 // for (let x = i; c; n) b
2872 //
2873 // into
2874 //
2875 // {
2876 // let x = i;
2877 // for (; c; n) b
2878 // }
2879 ASSERT(init != NULL);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002880 Block* result = factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002881 result->AddStatement(init, zone());
2882 result->AddStatement(loop, zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002883 result->set_scope(for_scope);
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002884 loop->Initialize(NULL, cond, next, body);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002885 return result;
2886 } else {
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002887 loop->Initialize(init, cond, next, body);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002888 return loop;
2889 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002890}
2891
2892
2893// Precedence = 1
2894Expression* Parser::ParseExpression(bool accept_IN, bool* ok) {
2895 // Expression ::
2896 // AssignmentExpression
2897 // Expression ',' AssignmentExpression
2898
2899 Expression* result = ParseAssignmentExpression(accept_IN, CHECK_OK);
2900 while (peek() == Token::COMMA) {
2901 Expect(Token::COMMA, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002902 int pos = position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002903 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002904 result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002905 }
2906 return result;
2907}
2908
2909
2910// Precedence = 2
2911Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
2912 // AssignmentExpression ::
2913 // ConditionalExpression
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002914 // YieldExpression
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002915 // LeftHandSideExpression AssignmentOperator AssignmentExpression
2916
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002917 if (peek() == Token::YIELD && is_generator()) {
2918 return ParseYieldExpression(ok);
2919 }
2920
ricow@chromium.org65fae842010-08-25 15:26:24 +00002921 if (fni_ != NULL) fni_->Enter();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002922 Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
2923
2924 if (!Token::IsAssignmentOp(peek())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002925 if (fni_ != NULL) fni_->Leave();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002926 // Parsed conditional expression only (no assignment).
2927 return expression;
2928 }
2929
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002930 // Signal a reference error if the expression is an invalid left-hand
2931 // side expression. We could report this as a syntax error here but
2932 // for compatibility with JSC we choose to report the error at
2933 // runtime.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002934 // TODO(ES5): Should change parsing for spec conformance.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002935 if (expression == NULL || !expression->IsValidLeftHandSide()) {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00002936 Handle<String> message =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002937 isolate()->factory()->invalid_lhs_in_assignment_string();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00002938 expression = NewThrowReferenceError(message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002939 }
2940
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002941 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002942 // Assignment to eval or arguments is disallowed in strict mode.
2943 CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK);
2944 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002945 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002946
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002947 Token::Value op = Next(); // Get assignment operator.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002948 int pos = position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002949 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
2950
2951 // TODO(1231235): We try to estimate the set of properties set by
2952 // constructors. We define a new property whenever there is an
2953 // assignment to a property of 'this'. We should probably only add
2954 // properties if we haven't seen them before. Otherwise we'll
2955 // probably overestimate the number of properties.
2956 Property* property = expression ? expression->AsProperty() : NULL;
2957 if (op == Token::ASSIGN &&
2958 property != NULL &&
2959 property->obj()->AsVariableProxy() != NULL &&
2960 property->obj()->AsVariableProxy()->is_this()) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00002961 current_function_state_->AddProperty();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002962 }
2963
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00002964 // If we assign a function literal to a property we pretenure the
2965 // literal so it can be added as a constant function property.
2966 if (property != NULL && right->AsFunctionLiteral() != NULL) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00002967 right->AsFunctionLiteral()->set_pretenure();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00002968 }
2969
ricow@chromium.org65fae842010-08-25 15:26:24 +00002970 if (fni_ != NULL) {
2971 // Check if the right hand side is a call to avoid inferring a
2972 // name if we're dealing with "a = function(){...}();"-like
2973 // expression.
2974 if ((op == Token::INIT_VAR
2975 || op == Token::INIT_CONST
2976 || op == Token::ASSIGN)
ager@chromium.org04921a82011-06-27 13:21:41 +00002977 && (right->AsCall() == NULL && right->AsCallNew() == NULL)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002978 fni_->Infer();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002979 } else {
2980 fni_->RemoveLastFunction();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002981 }
2982 fni_->Leave();
2983 }
2984
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002985 return factory()->NewAssignment(op, expression, right, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002986}
2987
2988
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002989Expression* Parser::ParseYieldExpression(bool* ok) {
2990 // YieldExpression ::
2991 // 'yield' '*'? AssignmentExpression
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002992 int pos = peek_position();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002993 Expect(Token::YIELD, CHECK_OK);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002994 Yield::Kind kind =
2995 Check(Token::MUL) ? Yield::DELEGATING : Yield::SUSPEND;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002996 Expression* generator_object = factory()->NewVariableProxy(
2997 current_function_state_->generator_object_variable());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002998 Expression* expression = ParseAssignmentExpression(false, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002999 Yield* yield = factory()->NewYield(generator_object, expression, kind, pos);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003000 if (kind == Yield::DELEGATING) {
3001 yield->set_index(current_function_state_->NextHandlerIndex());
3002 }
3003 return yield;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003004}
3005
3006
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003007// Precedence = 3
3008Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
3009 // ConditionalExpression ::
3010 // LogicalOrExpression
3011 // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
3012
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003013 int pos = peek_position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003014 // We start using the binary expression parser for prec >= 4 only!
3015 Expression* expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
3016 if (peek() != Token::CONDITIONAL) return expression;
3017 Consume(Token::CONDITIONAL);
3018 // In parsing the first assignment expression in conditional
3019 // expressions we always accept the 'in' keyword; see ECMA-262,
3020 // section 11.12, page 58.
3021 Expression* left = ParseAssignmentExpression(true, CHECK_OK);
3022 Expect(Token::COLON, CHECK_OK);
3023 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003024 return factory()->NewConditional(expression, left, right, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025}
3026
3027
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00003028int ParserBase::Precedence(Token::Value tok, bool accept_IN) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003029 if (tok == Token::IN && !accept_IN)
3030 return 0; // 0 precedence will terminate binary expression parsing
3031
3032 return Token::Precedence(tok);
3033}
3034
3035
3036// Precedence >= 4
3037Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
3038 ASSERT(prec >= 4);
3039 Expression* x = ParseUnaryExpression(CHECK_OK);
3040 for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
3041 // prec1 >= 4
3042 while (Precedence(peek(), accept_IN) == prec1) {
3043 Token::Value op = Next();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003044 int pos = position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003045 Expression* y = ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
3046
3047 // Compute some expressions involving only number literals.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003048 if (x && x->AsLiteral() && x->AsLiteral()->value()->IsNumber() &&
3049 y && y->AsLiteral() && y->AsLiteral()->value()->IsNumber()) {
3050 double x_val = x->AsLiteral()->value()->Number();
3051 double y_val = y->AsLiteral()->value()->Number();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003052
3053 switch (op) {
3054 case Token::ADD:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003055 x = factory()->NewNumberLiteral(x_val + y_val, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003056 continue;
3057 case Token::SUB:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003058 x = factory()->NewNumberLiteral(x_val - y_val, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003059 continue;
3060 case Token::MUL:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003061 x = factory()->NewNumberLiteral(x_val * y_val, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003062 continue;
3063 case Token::DIV:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003064 x = factory()->NewNumberLiteral(x_val / y_val, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003065 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003066 case Token::BIT_OR: {
3067 int value = DoubleToInt32(x_val) | DoubleToInt32(y_val);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003068 x = factory()->NewNumberLiteral(value, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003069 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003070 }
3071 case Token::BIT_AND: {
3072 int value = DoubleToInt32(x_val) & DoubleToInt32(y_val);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003073 x = factory()->NewNumberLiteral(value, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003074 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003075 }
3076 case Token::BIT_XOR: {
3077 int value = DoubleToInt32(x_val) ^ DoubleToInt32(y_val);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003078 x = factory()->NewNumberLiteral(value, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003079 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003080 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003081 case Token::SHL: {
3082 int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003083 x = factory()->NewNumberLiteral(value, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003084 continue;
3085 }
3086 case Token::SHR: {
3087 uint32_t shift = DoubleToInt32(y_val) & 0x1f;
3088 uint32_t value = DoubleToUint32(x_val) >> shift;
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003089 x = factory()->NewNumberLiteral(value, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003090 continue;
3091 }
3092 case Token::SAR: {
3093 uint32_t shift = DoubleToInt32(y_val) & 0x1f;
3094 int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003095 x = factory()->NewNumberLiteral(value, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003096 continue;
3097 }
3098 default:
3099 break;
3100 }
3101 }
3102
3103 // For now we distinguish between comparisons and other binary
3104 // operations. (We could combine the two and get rid of this
ricow@chromium.org65fae842010-08-25 15:26:24 +00003105 // code and AST node eventually.)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003106 if (Token::IsCompareOp(op)) {
3107 // We have a comparison.
3108 Token::Value cmp = op;
3109 switch (op) {
3110 case Token::NE: cmp = Token::EQ; break;
3111 case Token::NE_STRICT: cmp = Token::EQ_STRICT; break;
3112 default: break;
3113 }
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003114 x = factory()->NewCompareOperation(cmp, x, y, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003115 if (cmp != op) {
3116 // The comparison was negated - add a NOT.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003117 x = factory()->NewUnaryOperation(Token::NOT, x, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003118 }
3119
3120 } else {
3121 // We have a "normal" binary operation.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003122 x = factory()->NewBinaryOperation(op, x, y, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003123 }
3124 }
3125 }
3126 return x;
3127}
3128
3129
3130Expression* Parser::ParseUnaryExpression(bool* ok) {
3131 // UnaryExpression ::
3132 // PostfixExpression
3133 // 'delete' UnaryExpression
3134 // 'void' UnaryExpression
3135 // 'typeof' UnaryExpression
3136 // '++' UnaryExpression
3137 // '--' UnaryExpression
3138 // '+' UnaryExpression
3139 // '-' UnaryExpression
3140 // '~' UnaryExpression
3141 // '!' UnaryExpression
3142
3143 Token::Value op = peek();
3144 if (Token::IsUnaryOp(op)) {
3145 op = Next();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003146 int pos = position();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003147 Expression* expression = ParseUnaryExpression(CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003148
whesse@chromium.org7b260152011-06-20 15:33:18 +00003149 if (expression != NULL && (expression->AsLiteral() != NULL)) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003150 Handle<Object> literal = expression->AsLiteral()->value();
whesse@chromium.org7b260152011-06-20 15:33:18 +00003151 if (op == Token::NOT) {
3152 // Convert the literal to a boolean condition and negate it.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003153 bool condition = literal->BooleanValue();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003154 Handle<Object> result = isolate()->factory()->ToBoolean(!condition);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003155 return factory()->NewLiteral(result, pos);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003156 } else if (literal->IsNumber()) {
3157 // Compute some expressions involving only number literals.
3158 double value = literal->Number();
3159 switch (op) {
3160 case Token::ADD:
3161 return expression;
3162 case Token::SUB:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003163 return factory()->NewNumberLiteral(-value, pos);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003164 case Token::BIT_NOT:
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003165 return factory()->NewNumberLiteral(~DoubleToInt32(value), pos);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003166 default:
3167 break;
3168 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003169 }
3170 }
3171
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003172 // "delete identifier" is a syntax error in strict mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003173 if (op == Token::DELETE && !top_scope_->is_classic_mode()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003174 VariableProxy* operand = expression->AsVariableProxy();
3175 if (operand != NULL && !operand->is_this()) {
3176 ReportMessage("strict_delete", Vector<const char*>::empty());
3177 *ok = false;
3178 return NULL;
3179 }
3180 }
3181
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00003182 // Desugar '+foo' into 'foo*1', this enables the collection of type feedback
3183 // without any special stub and the multiplication is removed later in
3184 // Crankshaft's canonicalization pass.
3185 if (op == Token::ADD) {
3186 return factory()->NewBinaryOperation(Token::MUL,
3187 expression,
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003188 factory()->NewNumberLiteral(1, pos),
3189 pos);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00003190 }
danno@chromium.org59400602013-08-13 17:09:37 +00003191 // The same idea for '-foo' => 'foo*(-1)'.
3192 if (op == Token::SUB) {
3193 return factory()->NewBinaryOperation(Token::MUL,
3194 expression,
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003195 factory()->NewNumberLiteral(-1, pos),
3196 pos);
danno@chromium.org59400602013-08-13 17:09:37 +00003197 }
3198 // ...and one more time for '~foo' => 'foo^(~0)'.
3199 if (op == Token::BIT_NOT) {
3200 return factory()->NewBinaryOperation(Token::BIT_XOR,
3201 expression,
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003202 factory()->NewNumberLiteral(~0, pos),
3203 pos);
danno@chromium.org59400602013-08-13 17:09:37 +00003204 }
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00003205
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003206 return factory()->NewUnaryOperation(op, expression, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003207
3208 } else if (Token::IsCountOp(op)) {
3209 op = Next();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003210 Expression* expression = ParseUnaryExpression(CHECK_OK);
3211 // Signal a reference error if the expression is an invalid
3212 // left-hand side expression. We could report this as a syntax
3213 // error here but for compatibility with JSC we choose to report the
3214 // error at runtime.
3215 if (expression == NULL || !expression->IsValidLeftHandSide()) {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00003216 Handle<String> message =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003217 isolate()->factory()->invalid_lhs_in_prefix_op_string();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00003218 expression = NewThrowReferenceError(message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003219 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003220
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003221 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003222 // Prefix expression operand in strict mode may not be eval or arguments.
3223 CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
3224 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003225 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003226
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003227 return factory()->NewCountOperation(op,
3228 true /* prefix */,
3229 expression,
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003230 position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003231
3232 } else {
3233 return ParsePostfixExpression(ok);
3234 }
3235}
3236
3237
3238Expression* Parser::ParsePostfixExpression(bool* ok) {
3239 // PostfixExpression ::
3240 // LeftHandSideExpression ('++' | '--')?
3241
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003242 Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00003243 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003244 Token::IsCountOp(peek())) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003245 // Signal a reference error if the expression is an invalid
3246 // left-hand side expression. We could report this as a syntax
3247 // error here but for compatibility with JSC we choose to report the
3248 // error at runtime.
3249 if (expression == NULL || !expression->IsValidLeftHandSide()) {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00003250 Handle<String> message =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003251 isolate()->factory()->invalid_lhs_in_postfix_op_string();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00003252 expression = NewThrowReferenceError(message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003253 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003254
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003255 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003256 // Postfix expression operand in strict mode may not be eval or arguments.
3257 CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
3258 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003259 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003260
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003261 Token::Value next = Next();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003262 expression =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003263 factory()->NewCountOperation(next,
3264 false /* postfix */,
3265 expression,
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003266 position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003267 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003268 return expression;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003269}
3270
3271
3272Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
3273 // LeftHandSideExpression ::
3274 // (NewExpression | MemberExpression) ...
3275
3276 Expression* result;
3277 if (peek() == Token::NEW) {
3278 result = ParseNewExpression(CHECK_OK);
3279 } else {
3280 result = ParseMemberExpression(CHECK_OK);
3281 }
3282
3283 while (true) {
3284 switch (peek()) {
3285 case Token::LBRACK: {
3286 Consume(Token::LBRACK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003287 int pos = position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003288 Expression* index = ParseExpression(true, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003289 result = factory()->NewProperty(result, index, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003290 Expect(Token::RBRACK, CHECK_OK);
3291 break;
3292 }
3293
3294 case Token::LPAREN: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003295 int pos;
3296 if (scanner().current_token() == Token::IDENTIFIER) {
3297 // For call of an identifier we want to report position of
3298 // the identifier as position of the call in the stack trace.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003299 pos = position();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003300 } else {
3301 // For other kinds of calls we record position of the parenthesis as
3302 // position of the call. Note that this is extremely important for
3303 // expressions of the form function(){...}() for which call position
3304 // should not point to the closing brace otherwise it will intersect
3305 // with positions recorded for function literal and confuse debugger.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003306 pos = peek_position();
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003307 // Also the trailing parenthesis are a hint that the function will
3308 // be called immediately. If we happen to have parsed a preceding
3309 // function literal eagerly, we can also compile it eagerly.
3310 if (result->IsFunctionLiteral() && mode() == PARSE_EAGERLY) {
3311 result->AsFunctionLiteral()->set_parenthesized();
3312 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003313 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003314 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
3315
3316 // Keep track of eval() calls since they disable all local variable
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003317 // optimizations.
3318 // The calls that need special treatment are the
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003319 // direct eval calls. These calls are all of the form eval(...), with
3320 // no explicit receiver.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003321 // These calls are marked as potentially direct eval calls. Whether
3322 // they are actually direct calls to eval is determined at run time.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003323 VariableProxy* callee = result->AsVariableProxy();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003324 if (callee != NULL &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003325 callee->IsVariable(isolate()->factory()->eval_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003326 top_scope_->DeclarationScope()->RecordEvalCall();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003327 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003328 result = factory()->NewCall(result, args, pos);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003329 if (fni_ != NULL) fni_->RemoveLastFunction();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003330 break;
3331 }
3332
3333 case Token::PERIOD: {
3334 Consume(Token::PERIOD);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003335 int pos = position();
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003336 Handle<String> name = ParseIdentifierName(CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003337 result = factory()->NewProperty(
3338 result, factory()->NewLiteral(name, pos), pos);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003339 if (fni_ != NULL) fni_->PushLiteralName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340 break;
3341 }
3342
3343 default:
3344 return result;
3345 }
3346 }
3347}
3348
3349
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003350Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003351 // NewExpression ::
3352 // ('new')+ MemberExpression
3353
3354 // The grammar for new expressions is pretty warped. The keyword
3355 // 'new' can either be a part of the new expression (where it isn't
3356 // followed by an argument list) or a part of the member expression,
3357 // where it must be followed by an argument list. To accommodate
3358 // this, we parse the 'new' keywords greedily and keep track of how
3359 // many we have parsed. This information is then passed on to the
3360 // member expression parser, which is only allowed to match argument
3361 // lists as long as it has 'new' prefixes left
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003362 Expect(Token::NEW, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003363 PositionStack::Element pos(stack, position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003364
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003365 Expression* result;
3366 if (peek() == Token::NEW) {
3367 result = ParseNewPrefix(stack, CHECK_OK);
3368 } else {
3369 result = ParseMemberWithNewPrefixesExpression(stack, CHECK_OK);
3370 }
3371
3372 if (!stack->is_empty()) {
3373 int last = stack->pop();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003374 result = factory()->NewCallNew(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003375 result, new(zone()) ZoneList<Expression*>(0, zone()), last);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003376 }
3377 return result;
3378}
3379
3380
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003381Expression* Parser::ParseNewExpression(bool* ok) {
3382 PositionStack stack(ok);
3383 return ParseNewPrefix(&stack, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003384}
3385
3386
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003387Expression* Parser::ParseMemberExpression(bool* ok) {
3388 return ParseMemberWithNewPrefixesExpression(NULL, ok);
3389}
3390
3391
3392Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
3393 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003394 // MemberExpression ::
3395 // (PrimaryExpression | FunctionLiteral)
3396 // ('[' Expression ']' | '.' Identifier | Arguments)*
3397
3398 // Parse the initial primary or function expression.
3399 Expression* result = NULL;
3400 if (peek() == Token::FUNCTION) {
3401 Expect(Token::FUNCTION, CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003402 int function_token_position = position();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003403 bool is_generator = allow_generators() && Check(Token::MUL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003404 Handle<String> name;
ager@chromium.org04921a82011-06-27 13:21:41 +00003405 bool is_strict_reserved_name = false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003406 if (peek_any_identifier()) {
ager@chromium.org04921a82011-06-27 13:21:41 +00003407 name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
3408 CHECK_OK);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003409 }
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00003410 FunctionLiteral::FunctionType function_type = name.is_null()
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003411 ? FunctionLiteral::ANONYMOUS_EXPRESSION
3412 : FunctionLiteral::NAMED_EXPRESSION;
3413 result = ParseFunctionLiteral(name,
3414 is_strict_reserved_name,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003415 is_generator,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003416 function_token_position,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00003417 function_type,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003418 CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419 } else {
3420 result = ParsePrimaryExpression(CHECK_OK);
3421 }
3422
3423 while (true) {
3424 switch (peek()) {
3425 case Token::LBRACK: {
3426 Consume(Token::LBRACK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003427 int pos = position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003428 Expression* index = ParseExpression(true, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003429 result = factory()->NewProperty(result, index, pos);
ager@chromium.org04921a82011-06-27 13:21:41 +00003430 if (fni_ != NULL) {
3431 if (index->IsPropertyName()) {
3432 fni_->PushLiteralName(index->AsLiteral()->AsPropertyName());
3433 } else {
3434 fni_->PushLiteralName(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003435 isolate()->factory()->anonymous_function_string());
ager@chromium.org04921a82011-06-27 13:21:41 +00003436 }
3437 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003438 Expect(Token::RBRACK, CHECK_OK);
3439 break;
3440 }
3441 case Token::PERIOD: {
3442 Consume(Token::PERIOD);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003443 int pos = position();
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003444 Handle<String> name = ParseIdentifierName(CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003445 result = factory()->NewProperty(
3446 result, factory()->NewLiteral(name, pos), pos);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003447 if (fni_ != NULL) fni_->PushLiteralName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448 break;
3449 }
3450 case Token::LPAREN: {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003451 if ((stack == NULL) || stack->is_empty()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003452 // Consume one of the new prefixes (already parsed).
3453 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003454 int pos = stack->pop();
3455 result = factory()->NewCallNew(result, args, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003456 break;
3457 }
3458 default:
3459 return result;
3460 }
3461 }
3462}
3463
3464
3465DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
3466 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
3467 // contexts this is used as a statement which invokes the debugger as i a
3468 // break point is present.
3469 // DebuggerStatement ::
3470 // 'debugger' ';'
3471
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003472 int pos = peek_position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003473 Expect(Token::DEBUGGER, CHECK_OK);
3474 ExpectSemicolon(CHECK_OK);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003475 return factory()->NewDebuggerStatement(pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003476}
3477
3478
3479void Parser::ReportUnexpectedToken(Token::Value token) {
3480 // We don't report stack overflows here, to avoid increasing the
3481 // stack depth even further. Instead we report it after parsing is
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003482 // over, in ParseProgram/ParseJson.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003483 if (token == Token::ILLEGAL && stack_overflow()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003484 // Four of the tokens are treated specially
3485 switch (token) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003486 case Token::EOS:
3487 return ReportMessage("unexpected_eos", Vector<const char*>::empty());
3488 case Token::NUMBER:
3489 return ReportMessage("unexpected_token_number",
3490 Vector<const char*>::empty());
3491 case Token::STRING:
3492 return ReportMessage("unexpected_token_string",
3493 Vector<const char*>::empty());
3494 case Token::IDENTIFIER:
3495 return ReportMessage("unexpected_token_identifier",
3496 Vector<const char*>::empty());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003497 case Token::FUTURE_RESERVED_WORD:
ager@chromium.org04921a82011-06-27 13:21:41 +00003498 return ReportMessage("unexpected_reserved",
3499 Vector<const char*>::empty());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003500 case Token::YIELD:
ager@chromium.org04921a82011-06-27 13:21:41 +00003501 case Token::FUTURE_STRICT_RESERVED_WORD:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003502 return ReportMessage(top_scope_->is_classic_mode() ?
3503 "unexpected_token_identifier" :
3504 "unexpected_strict_reserved",
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003505 Vector<const char*>::empty());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003506 default:
3507 const char* name = Token::String(token);
3508 ASSERT(name != NULL);
3509 ReportMessage("unexpected_token", Vector<const char*>(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003510 }
3511}
3512
3513
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003514void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003515 SmartArrayPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003516 const char* element[1] = { *name_string };
3517 ReportMessage("invalid_preparser_data",
3518 Vector<const char*>(element, 1));
3519 *ok = false;
3520}
3521
3522
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003523Expression* Parser::ParsePrimaryExpression(bool* ok) {
3524 // PrimaryExpression ::
3525 // 'this'
3526 // 'null'
3527 // 'true'
3528 // 'false'
3529 // Identifier
3530 // Number
3531 // String
3532 // ArrayLiteral
3533 // ObjectLiteral
3534 // RegExpLiteral
3535 // '(' Expression ')'
3536
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003537 int pos = peek_position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003538 Expression* result = NULL;
3539 switch (peek()) {
3540 case Token::THIS: {
3541 Consume(Token::THIS);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003542 result = factory()->NewVariableProxy(top_scope_->receiver());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003543 break;
3544 }
3545
3546 case Token::NULL_LITERAL:
3547 Consume(Token::NULL_LITERAL);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003548 result = factory()->NewLiteral(isolate()->factory()->null_value(), pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003549 break;
3550
3551 case Token::TRUE_LITERAL:
3552 Consume(Token::TRUE_LITERAL);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003553 result = factory()->NewLiteral(isolate()->factory()->true_value(), pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554 break;
3555
3556 case Token::FALSE_LITERAL:
3557 Consume(Token::FALSE_LITERAL);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003558 result = factory()->NewLiteral(isolate()->factory()->false_value(), pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003559 break;
3560
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003561 case Token::IDENTIFIER:
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003562 case Token::YIELD:
ager@chromium.org04921a82011-06-27 13:21:41 +00003563 case Token::FUTURE_STRICT_RESERVED_WORD: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003564 Handle<String> name = ParseIdentifier(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003565 if (fni_ != NULL) fni_->PushVariableName(name);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003566 // The name may refer to a module instance object, so its type is unknown.
3567#ifdef DEBUG
3568 if (FLAG_print_interface_details)
3569 PrintF("# Variable %s ", name->ToAsciiArray());
3570#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003571 Interface* interface = Interface::NewUnknown(zone());
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003572 result = top_scope_->NewUnresolved(factory(), name, interface, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003573 break;
3574 }
3575
3576 case Token::NUMBER: {
3577 Consume(Token::NUMBER);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003578 ASSERT(scanner().is_literal_ascii());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003579 double value = StringToDouble(isolate()->unicode_cache(),
3580 scanner().literal_ascii_string(),
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003581 ALLOW_HEX | ALLOW_OCTAL |
3582 ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003583 result = factory()->NewNumberLiteral(value, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584 break;
3585 }
3586
3587 case Token::STRING: {
3588 Consume(Token::STRING);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003589 Handle<String> symbol = GetSymbol();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003590 result = factory()->NewLiteral(symbol, pos);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003591 if (fni_ != NULL) fni_->PushLiteralName(symbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 break;
3593 }
3594
3595 case Token::ASSIGN_DIV:
3596 result = ParseRegExpLiteral(true, CHECK_OK);
3597 break;
3598
3599 case Token::DIV:
3600 result = ParseRegExpLiteral(false, CHECK_OK);
3601 break;
3602
3603 case Token::LBRACK:
3604 result = ParseArrayLiteral(CHECK_OK);
3605 break;
3606
3607 case Token::LBRACE:
3608 result = ParseObjectLiteral(CHECK_OK);
3609 break;
3610
3611 case Token::LPAREN:
3612 Consume(Token::LPAREN);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003613 // Heuristically try to detect immediately called functions before
3614 // seeing the call parentheses.
3615 parenthesized_function_ = (peek() == Token::FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 result = ParseExpression(true, CHECK_OK);
3617 Expect(Token::RPAREN, CHECK_OK);
3618 break;
3619
3620 case Token::MOD:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003621 if (allow_natives_syntax() || extension_ != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 result = ParseV8Intrinsic(CHECK_OK);
3623 break;
3624 }
3625 // If we're not allowing special syntax we fall-through to the
3626 // default case.
3627
3628 default: {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003629 Token::Value tok = Next();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003630 ReportUnexpectedToken(tok);
3631 *ok = false;
3632 return NULL;
3633 }
3634 }
3635
3636 return result;
3637}
3638
3639
3640Expression* Parser::ParseArrayLiteral(bool* ok) {
3641 // ArrayLiteral ::
3642 // '[' Expression? (',' Expression?)* ']'
3643
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003644 int pos = peek_position();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003645 ZoneList<Expression*>* values = new(zone()) ZoneList<Expression*>(4, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003646 Expect(Token::LBRACK, CHECK_OK);
3647 while (peek() != Token::RBRACK) {
3648 Expression* elem;
3649 if (peek() == Token::COMMA) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003650 elem = GetLiteralTheHole(peek_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003651 } else {
3652 elem = ParseAssignmentExpression(true, CHECK_OK);
3653 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003654 values->Add(elem, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003655 if (peek() != Token::RBRACK) {
3656 Expect(Token::COMMA, CHECK_OK);
3657 }
3658 }
3659 Expect(Token::RBRACK, CHECK_OK);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003660
3661 // Update the scope information before the pre-parsing bailout.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003662 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003663
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003664 // Allocate a fixed array to hold all the object literals.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003665 Handle<JSArray> array =
3666 isolate()->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
3667 isolate()->factory()->SetElementsCapacityAndLength(
3668 array, values->length(), values->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003669
3670 // Fill in the literals.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003671 Heap* heap = isolate()->heap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003672 bool is_simple = true;
3673 int depth = 1;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003674 bool is_holey = false;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003675 for (int i = 0, n = values->length(); i < n; i++) {
3676 MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003677 if (m_literal != NULL && m_literal->depth() + 1 > depth) {
3678 depth = m_literal->depth() + 1;
3679 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003680 Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003681 if (boilerplate_value->IsTheHole()) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003682 is_holey = true;
danno@chromium.org1fd77d52013-06-07 16:01:45 +00003683 } else if (boilerplate_value->IsUninitialized()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003684 is_simple = false;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003685 JSObject::SetOwnElement(
3686 array, i, handle(Smi::FromInt(0), isolate()), kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003687 } else {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003688 JSObject::SetOwnElement(array, i, boilerplate_value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003689 }
3690 }
3691
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003692 Handle<FixedArrayBase> element_values(array->elements());
3693
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003694 // Simple and shallow arrays can be lazily copied, we transform the
3695 // elements array to a copy-on-write array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003696 if (is_simple && depth == 1 && values->length() > 0 &&
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003697 array->HasFastSmiOrObjectElements()) {
3698 element_values->set_map(heap->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003699 }
3700
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003701 // Remember both the literal's constant values as well as the ElementsKind
3702 // in a 2-element FixedArray.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003703 Handle<FixedArray> literals = isolate()->factory()->NewFixedArray(2, TENURED);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003704
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003705 ElementsKind kind = array->GetElementsKind();
3706 kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003707
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003708 literals->set(0, Smi::FromInt(kind));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003709 literals->set(1, *element_values);
3710
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003711 return factory()->NewArrayLiteral(
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003712 literals, values, literal_index, is_simple, depth, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713}
3714
3715
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003716bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) {
3717 return property != NULL &&
3718 property->kind() != ObjectLiteral::Property::PROTOTYPE;
3719}
3720
3721
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003722bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003723 if (expression->AsLiteral() != NULL) return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003724 MaterializedLiteral* lit = expression->AsMaterializedLiteral();
3725 return lit != NULL && lit->is_simple();
3726}
3727
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003728
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003729Handle<FixedArray> CompileTimeValue::GetValue(Isolate* isolate,
3730 Expression* expression) {
3731 Factory* factory = isolate->factory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003732 ASSERT(IsCompileTimeValue(expression));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003733 Handle<FixedArray> result = factory->NewFixedArray(2, TENURED);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003734 ObjectLiteral* object_literal = expression->AsObjectLiteral();
3735 if (object_literal != NULL) {
3736 ASSERT(object_literal->is_simple());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003737 if (object_literal->fast_elements()) {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00003738 result->set(kLiteralTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003739 } else {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00003740 result->set(kLiteralTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003741 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003742 result->set(kElementsSlot, *object_literal->constant_properties());
3743 } else {
3744 ArrayLiteral* array_literal = expression->AsArrayLiteral();
3745 ASSERT(array_literal != NULL && array_literal->is_simple());
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00003746 result->set(kLiteralTypeSlot, Smi::FromInt(ARRAY_LITERAL));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003747 result->set(kElementsSlot, *array_literal->constant_elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003748 }
3749 return result;
3750}
3751
3752
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00003753CompileTimeValue::LiteralType CompileTimeValue::GetLiteralType(
3754 Handle<FixedArray> value) {
3755 Smi* literal_type = Smi::cast(value->get(kLiteralTypeSlot));
3756 return static_cast<LiteralType>(literal_type->value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003757}
3758
3759
3760Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
3761 return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot)));
3762}
3763
3764
3765Handle<Object> Parser::GetBoilerplateValue(Expression* expression) {
3766 if (expression->AsLiteral() != NULL) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003767 return expression->AsLiteral()->value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003768 }
3769 if (CompileTimeValue::IsCompileTimeValue(expression)) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003770 return CompileTimeValue::GetValue(isolate(), expression);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003771 }
danno@chromium.org1fd77d52013-06-07 16:01:45 +00003772 return isolate()->factory()->uninitialized_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003773}
3774
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00003775
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003776void Parser::BuildObjectLiteralConstantProperties(
3777 ZoneList<ObjectLiteral::Property*>* properties,
3778 Handle<FixedArray> constant_properties,
3779 bool* is_simple,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003780 bool* fast_elements,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003781 int* depth,
3782 bool* may_store_doubles) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003783 int position = 0;
3784 // Accumulate the value in local variables and store it at the end.
3785 bool is_simple_acc = true;
3786 int depth_acc = 1;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003787 uint32_t max_element_index = 0;
3788 uint32_t elements = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003789 for (int i = 0; i < properties->length(); i++) {
3790 ObjectLiteral::Property* property = properties->at(i);
3791 if (!IsBoilerplateProperty(property)) {
3792 is_simple_acc = false;
3793 continue;
3794 }
3795 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
3796 if (m_literal != NULL && m_literal->depth() >= depth_acc) {
3797 depth_acc = m_literal->depth() + 1;
3798 }
3799
3800 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
3801 // value for COMPUTED properties, the real value is filled in at
3802 // runtime. The enumeration order is maintained.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003803 Handle<Object> key = property->key()->value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003804 Handle<Object> value = GetBoilerplateValue(property->value());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003805
danno@chromium.org1fd77d52013-06-07 16:01:45 +00003806 // Ensure objects that may, at any point in time, contain fields with double
3807 // representation are always treated as nested objects. This is true for
3808 // computed fields (value is undefined), and smi and double literals
3809 // (value->IsNumber()).
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003810 // TODO(verwaest): Remove once we can store them inline.
danno@chromium.org1fd77d52013-06-07 16:01:45 +00003811 if (FLAG_track_double_fields &&
3812 (value->IsNumber() || value->IsUninitialized())) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003813 *may_store_doubles = true;
3814 }
3815
danno@chromium.org1fd77d52013-06-07 16:01:45 +00003816 is_simple_acc = is_simple_acc && !value->IsUninitialized();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003817
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003818 // Keep track of the number of elements in the object literal and
3819 // the largest element index. If the largest element index is
3820 // much larger than the number of elements, creating an object
3821 // literal with fast elements will be a waste of space.
3822 uint32_t element_index = 0;
3823 if (key->IsString()
3824 && Handle<String>::cast(key)->AsArrayIndex(&element_index)
3825 && element_index > max_element_index) {
3826 max_element_index = element_index;
3827 elements++;
3828 } else if (key->IsSmi()) {
3829 int key_value = Smi::cast(*key)->value();
3830 if (key_value > 0
3831 && static_cast<uint32_t>(key_value) > max_element_index) {
3832 max_element_index = key_value;
3833 }
3834 elements++;
3835 }
3836
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003837 // Add name, value pair to the fixed array.
3838 constant_properties->set(position++, *key);
3839 constant_properties->set(position++, *value);
3840 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003841 *fast_elements =
3842 (max_element_index <= 32) || ((2 * elements) >= max_element_index);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003843 *is_simple = is_simple_acc;
3844 *depth = depth_acc;
3845}
3846
3847
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003848Expression* Parser::ParseObjectLiteral(bool* ok) {
3849 // ObjectLiteral ::
3850 // '{' (
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003851 // ((IdentifierName | String | Number) ':' AssignmentExpression)
3852 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003853 // )*[','] '}'
3854
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003855 int pos = peek_position();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003856 ZoneList<ObjectLiteral::Property*>* properties =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003857 new(zone()) ZoneList<ObjectLiteral::Property*>(4, zone());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003858 int number_of_boilerplate_properties = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003859 bool has_function = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003860
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00003861 ObjectLiteralChecker checker(this, top_scope_->language_mode());
ager@chromium.org378b34e2011-01-28 08:04:38 +00003862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003863 Expect(Token::LBRACE, CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003864
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003865 while (peek() != Token::RBRACE) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003866 if (fni_ != NULL) fni_->Enter();
3867
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003868 Literal* key = NULL;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003869 Token::Value next = peek();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003870 int next_pos = peek_position();
ager@chromium.org378b34e2011-01-28 08:04:38 +00003871
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003872 switch (next) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003873 case Token::FUTURE_RESERVED_WORD:
ager@chromium.org04921a82011-06-27 13:21:41 +00003874 case Token::FUTURE_STRICT_RESERVED_WORD:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003875 case Token::IDENTIFIER: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003876 bool is_getter = false;
3877 bool is_setter = false;
3878 Handle<String> id =
ager@chromium.org04921a82011-06-27 13:21:41 +00003879 ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003880 if (fni_ != NULL) fni_->PushLiteralName(id);
3881
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003882 if ((is_getter || is_setter) && peek() != Token::COLON) {
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +00003883 // Special handling of getter and setter syntax:
3884 // { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... }
3885 // We have already read the "get" or "set" keyword.
3886 Token::Value next = Next();
3887 bool is_keyword = Token::IsKeyword(next);
3888 if (next != i::Token::IDENTIFIER &&
3889 next != i::Token::FUTURE_RESERVED_WORD &&
3890 next != i::Token::FUTURE_STRICT_RESERVED_WORD &&
3891 next != i::Token::NUMBER &&
3892 next != i::Token::STRING &&
3893 !is_keyword) {
3894 // Unexpected token.
3895 ReportUnexpectedToken(next);
3896 *ok = false;
3897 return NULL;
3898 }
3899 // Validate the property.
3900 PropertyKind type = is_getter ? kGetterProperty : kSetterProperty;
3901 checker.CheckProperty(next, type, CHECK_OK);
3902 Handle<String> name = is_keyword
3903 ? isolate_->factory()->InternalizeUtf8String(Token::String(next))
3904 : GetSymbol();
3905 FunctionLiteral* value =
3906 ParseFunctionLiteral(name,
3907 false, // reserved words are allowed here
3908 false, // not a generator
3909 RelocInfo::kNoPosition,
3910 FunctionLiteral::ANONYMOUS_EXPRESSION,
3911 CHECK_OK);
3912 // Allow any number of parameters for compatibilty with JSC.
3913 // Specification only allows zero parameters for get and one for set.
3914 ObjectLiteral::Property* property =
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003915 factory()->NewObjectLiteralProperty(is_getter, value, next_pos);
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +00003916 if (IsBoilerplateProperty(property)) {
3917 number_of_boilerplate_properties++;
3918 }
3919 properties->Add(property, zone());
3920 if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003921
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +00003922 if (fni_ != NULL) {
3923 fni_->Infer();
3924 fni_->Leave();
3925 }
3926 continue; // restart the while
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003927 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003928 // Failed to parse as get/set property, so it's just a property
3929 // called "get" or "set".
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003930 key = factory()->NewLiteral(id, next_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003931 break;
3932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933 case Token::STRING: {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003934 Consume(Token::STRING);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003935 Handle<String> string = GetSymbol();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003936 if (fni_ != NULL) fni_->PushLiteralName(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003937 uint32_t index;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00003938 if (!string.is_null() && string->AsArrayIndex(&index)) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003939 key = factory()->NewNumberLiteral(index, next_pos);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003940 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003941 }
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003942 key = factory()->NewLiteral(string, next_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003943 break;
3944 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945 case Token::NUMBER: {
3946 Consume(Token::NUMBER);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003947 ASSERT(scanner().is_literal_ascii());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003948 double value = StringToDouble(isolate()->unicode_cache(),
3949 scanner().literal_ascii_string(),
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003950 ALLOW_HEX | ALLOW_OCTAL |
3951 ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003952 key = factory()->NewNumberLiteral(value, next_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003953 break;
3954 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003955 default:
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003956 if (Token::IsKeyword(next)) {
3957 Consume(next);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003958 Handle<String> string = GetSymbol();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00003959 key = factory()->NewLiteral(string, next_pos);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003960 } else {
3961 // Unexpected token.
3962 Token::Value next = Next();
3963 ReportUnexpectedToken(next);
3964 *ok = false;
3965 return NULL;
3966 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967 }
3968
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +00003969 // Validate the property
3970 checker.CheckProperty(next, kValueProperty, CHECK_OK);
3971
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 Expect(Token::COLON, CHECK_OK);
3973 Expression* value = ParseAssignmentExpression(true, CHECK_OK);
3974
3975 ObjectLiteral::Property* property =
ulan@chromium.org812308e2012-02-29 15:58:45 +00003976 new(zone()) ObjectLiteral::Property(key, value, isolate());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003977
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00003978 // Mark top-level object literals that contain function literals and
3979 // pretenure the literal so it can be added as a constant function
3980 // property.
3981 if (top_scope_->DeclarationScope()->is_global_scope() &&
3982 value->AsFunctionLiteral() != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003983 has_function = true;
danno@chromium.orgc612e022011-11-10 11:38:15 +00003984 value->AsFunctionLiteral()->set_pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003985 }
3986
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003987 // Count CONSTANT or COMPUTED properties to maintain the enumeration order.
ager@chromium.org236ad962008-09-25 09:45:57 +00003988 if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003989 properties->Add(property, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990
3991 // TODO(1240767): Consider allowing trailing comma.
3992 if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003993
3994 if (fni_ != NULL) {
3995 fni_->Infer();
3996 fni_->Leave();
3997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998 }
3999 Expect(Token::RBRACE, CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004000
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004001 // Computation of literal_index must happen before pre parse bailout.
danno@chromium.orgc612e022011-11-10 11:38:15 +00004002 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004004 Handle<FixedArray> constant_properties = isolate()->factory()->NewFixedArray(
4005 number_of_boilerplate_properties * 2, TENURED);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004006
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004007 bool is_simple = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004008 bool fast_elements = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004009 int depth = 1;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004010 bool may_store_doubles = false;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004011 BuildObjectLiteralConstantProperties(properties,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004012 constant_properties,
4013 &is_simple,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004014 &fast_elements,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004015 &depth,
4016 &may_store_doubles);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004017 return factory()->NewObjectLiteral(constant_properties,
4018 properties,
4019 literal_index,
4020 is_simple,
4021 fast_elements,
4022 depth,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004023 may_store_doubles,
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004024 has_function,
4025 pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026}
4027
4028
4029Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004030 int pos = peek_position();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004031 if (!scanner().ScanRegExpPattern(seen_equal)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 Next();
4033 ReportMessage("unterminated_regexp", Vector<const char*>::empty());
4034 *ok = false;
4035 return NULL;
4036 }
4037
danno@chromium.orgc612e022011-11-10 11:38:15 +00004038 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004040 Handle<String> js_pattern = NextLiteralString(TENURED);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004041 scanner().ScanRegExpFlags();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004042 Handle<String> js_flags = NextLiteralString(TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004043 Next();
4044
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004045 return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046}
4047
4048
4049ZoneList<Expression*>* Parser::ParseArguments(bool* ok) {
4050 // Arguments ::
4051 // '(' (AssignmentExpression)*[','] ')'
4052
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004053 ZoneList<Expression*>* result = new(zone()) ZoneList<Expression*>(4, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 Expect(Token::LPAREN, CHECK_OK);
4055 bool done = (peek() == Token::RPAREN);
4056 while (!done) {
4057 Expression* argument = ParseAssignmentExpression(true, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004058 result->Add(argument, zone());
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00004059 if (result->length() > Code::kMaxArguments) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004060 ReportMessageAt(scanner().location(), "too_many_arguments",
4061 Vector<const char*>::empty());
4062 *ok = false;
4063 return NULL;
4064 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 done = (peek() == Token::RPAREN);
4066 if (!done) Expect(Token::COMMA, CHECK_OK);
4067 }
4068 Expect(Token::RPAREN, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004069 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004070}
4071
4072
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004073class SingletonLogger : public ParserRecorder {
4074 public:
4075 SingletonLogger() : has_error_(false), start_(-1), end_(-1) { }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004076 virtual ~SingletonLogger() { }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004077
4078 void Reset() { has_error_ = false; }
4079
4080 virtual void LogFunction(int start,
4081 int end,
4082 int literals,
4083 int properties,
4084 LanguageMode mode) {
4085 ASSERT(!has_error_);
4086 start_ = start;
4087 end_ = end;
4088 literals_ = literals;
4089 properties_ = properties;
4090 mode_ = mode;
4091 };
4092
4093 // Logs a symbol creation of a literal or identifier.
4094 virtual void LogAsciiSymbol(int start, Vector<const char> literal) { }
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004095 virtual void LogUtf16Symbol(int start, Vector<const uc16> literal) { }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004096
4097 // Logs an error message and marks the log as containing an error.
4098 // Further logging will be ignored, and ExtractData will return a vector
4099 // representing the error only.
4100 virtual void LogMessage(int start,
4101 int end,
4102 const char* message,
4103 const char* argument_opt) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004104 if (has_error_) return;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004105 has_error_ = true;
4106 start_ = start;
4107 end_ = end;
4108 message_ = message;
4109 argument_opt_ = argument_opt;
4110 }
4111
4112 virtual int function_position() { return 0; }
4113
4114 virtual int symbol_position() { return 0; }
4115
4116 virtual int symbol_ids() { return -1; }
4117
4118 virtual Vector<unsigned> ExtractData() {
4119 UNREACHABLE();
4120 return Vector<unsigned>();
4121 }
4122
4123 virtual void PauseRecording() { }
4124
4125 virtual void ResumeRecording() { }
4126
4127 bool has_error() { return has_error_; }
4128
4129 int start() { return start_; }
4130 int end() { return end_; }
4131 int literals() {
4132 ASSERT(!has_error_);
4133 return literals_;
4134 }
4135 int properties() {
4136 ASSERT(!has_error_);
4137 return properties_;
4138 }
4139 LanguageMode language_mode() {
4140 ASSERT(!has_error_);
4141 return mode_;
4142 }
4143 const char* message() {
4144 ASSERT(has_error_);
4145 return message_;
4146 }
4147 const char* argument_opt() {
4148 ASSERT(has_error_);
4149 return argument_opt_;
4150 }
4151
4152 private:
4153 bool has_error_;
4154 int start_;
4155 int end_;
4156 // For function entries.
4157 int literals_;
4158 int properties_;
4159 LanguageMode mode_;
4160 // For error messages.
4161 const char* message_;
4162 const char* argument_opt_;
4163};
4164
4165
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004166FunctionLiteral* Parser::ParseFunctionLiteral(
4167 Handle<String> function_name,
4168 bool name_is_strict_reserved,
4169 bool is_generator,
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004170 int function_token_pos,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004171 FunctionLiteral::FunctionType function_type,
4172 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 // Function ::
4174 // '(' FormalParameterList? ')' '{' FunctionBody '}'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004176 int pos = function_token_pos == RelocInfo::kNoPosition
4177 ? peek_position() : function_token_pos;
4178
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004179 // Anonymous functions were passed either the empty symbol or a null
4180 // handle as the function name. Remember if we were passed a non-empty
4181 // handle to decide whether to invoke function name inference.
4182 bool should_infer_name = function_name.is_null();
4183
4184 // We want a non-null handle as the function name.
4185 if (should_infer_name) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004186 function_name = isolate()->factory()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 }
4188
4189 int num_parameters = 0;
danno@chromium.orgb6451162011-08-17 14:33:23 +00004190 // Function declarations are function scoped in normal mode, so they are
4191 // hoisted. In harmony block scoping mode they are block scoped, so they
4192 // are not hoisted.
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00004193 //
4194 // One tricky case are function declarations in a local sloppy-mode eval:
4195 // their declaration is hoisted, but they still see the local scope. E.g.,
4196 //
4197 // function() {
4198 // var x = 0
4199 // try { throw 1 } catch (x) { eval("function g() { return x }") }
4200 // return g()
4201 // }
4202 //
4203 // needs to return 1. To distinguish such cases, we need to detect
4204 // (1) whether a function stems from a sloppy eval, and
4205 // (2) whether it actually hoists across the eval.
4206 // Unfortunately, we do not represent sloppy eval scopes, so we do not have
4207 // either information available directly, especially not when lazily compiling
4208 // a function like 'g'. We hence rely on the following invariants:
4209 // - (1) is the case iff the innermost scope of the deserialized scope chain
4210 // under which we compile is _not_ a declaration scope. This holds because
4211 // in all normal cases, function declarations are fully hoisted to a
4212 // declaration scope and compiled relative to that.
4213 // - (2) is the case iff the current declaration scope is still the original
4214 // one relative to the deserialized scope chain. Otherwise we must be
4215 // compiling a function in an inner declaration scope in the eval, e.g. a
4216 // nested function, and hoisting works normally relative to that.
4217 Scope* declaration_scope = top_scope_->DeclarationScope();
4218 Scope* original_declaration_scope = original_scope_->DeclarationScope();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004219 Scope* scope =
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00004220 function_type == FunctionLiteral::DECLARATION && !is_extended_mode() &&
4221 (original_scope_ == original_declaration_scope ||
4222 declaration_scope != original_declaration_scope)
4223 ? NewScope(declaration_scope, FUNCTION_SCOPE)
4224 : NewScope(top_scope_, FUNCTION_SCOPE);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004225 ZoneList<Statement*>* body = NULL;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004226 int materialized_literal_count = -1;
4227 int expected_property_count = -1;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004228 int handler_count = 0;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004229 FunctionLiteral::ParameterFlag duplicate_parameters =
4230 FunctionLiteral::kNoDuplicateParameters;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004231 FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_
4232 ? FunctionLiteral::kIsParenthesized
4233 : FunctionLiteral::kNotParenthesized;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004234 FunctionLiteral::IsGeneratorFlag generator = is_generator
4235 ? FunctionLiteral::kIsGenerator
4236 : FunctionLiteral::kNotGenerator;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004237 AstProperties ast_properties;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00004238 BailoutReason dont_optimize_reason = kNoReason;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004239 // Parse function body.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004240 { FunctionState function_state(this, scope, isolate());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004241 top_scope_->SetScopeName(function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004242
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004243 if (is_generator) {
4244 // For generators, allocating variables in contexts is currently a win
4245 // because it minimizes the work needed to suspend and resume an
4246 // activation.
4247 top_scope_->ForceContextAllocation();
4248
4249 // Calling a generator returns a generator object. That object is stored
4250 // in a temporary variable, a definition that is used by "yield"
4251 // expressions. Presence of a variable for the generator object in the
4252 // FunctionState indicates that this function is a generator.
4253 Handle<String> tempname = isolate()->factory()->InternalizeOneByteString(
4254 STATIC_ASCII_VECTOR(".generator_object"));
4255 Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname);
4256 function_state.set_generator_object_variable(temp);
4257 }
4258
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004259 // FormalParameterList ::
4260 // '(' (Identifier)*[','] ')'
4261 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004262 scope->set_start_position(scanner().location().beg_pos);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004263 Scanner::Location name_loc = Scanner::Location::invalid();
4264 Scanner::Location dupe_loc = Scanner::Location::invalid();
4265 Scanner::Location reserved_loc = Scanner::Location::invalid();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004267 bool done = (peek() == Token::RPAREN);
4268 while (!done) {
ager@chromium.org04921a82011-06-27 13:21:41 +00004269 bool is_strict_reserved = false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004270 Handle<String> param_name =
ager@chromium.org04921a82011-06-27 13:21:41 +00004271 ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
4272 CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004273
4274 // Store locations for possible future error reports.
4275 if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) {
4276 name_loc = scanner().location();
4277 }
4278 if (!dupe_loc.IsValid() && top_scope_->IsDeclared(param_name)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004279 duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
ager@chromium.org378b34e2011-01-28 08:04:38 +00004280 dupe_loc = scanner().location();
4281 }
ager@chromium.org04921a82011-06-27 13:21:41 +00004282 if (!reserved_loc.IsValid() && is_strict_reserved) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004283 reserved_loc = scanner().location();
4284 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004285
yangguo@chromium.org56454712012-02-16 15:33:53 +00004286 top_scope_->DeclareParameter(param_name, VAR);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004287 num_parameters++;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00004288 if (num_parameters > Code::kMaxArguments) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004289 ReportMessageAt(scanner().location(), "too_many_parameters",
4290 Vector<const char*>::empty());
4291 *ok = false;
4292 return NULL;
4293 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004294 done = (peek() == Token::RPAREN);
4295 if (!done) Expect(Token::COMMA, CHECK_OK);
4296 }
4297 Expect(Token::RPAREN, CHECK_OK);
4298
4299 Expect(Token::LBRACE, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004300
4301 // If we have a named function expression, we add a local variable
4302 // declaration to the body of the function with the name of the
4303 // function and let it refer to the function itself (closure).
4304 // NOTE: We create a proxy and resolve it here so that in the
4305 // future we can change the AST to only refer to VariableProxies
4306 // instead of Variables and Proxis as is the case now.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004307 Variable* fvar = NULL;
4308 Token::Value fvar_init_op = Token::INIT_CONST;
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004309 if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004310 if (is_extended_mode()) fvar_init_op = Token::INIT_CONST_HARMONY;
4311 VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST;
4312 fvar = new(zone()) Variable(top_scope_,
4313 function_name, fvar_mode, true /* is valid LHS */,
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00004314 Variable::NORMAL, kCreatedInitialized, Interface::NewConst());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004315 VariableProxy* proxy = factory()->NewVariableProxy(fvar);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004316 VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(
4317 proxy, fvar_mode, top_scope_, RelocInfo::kNoPosition);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004318 top_scope_->DeclareFunctionVar(fvar_declaration);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004319 }
4320
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004321 // Determine whether the function will be lazily compiled.
4322 // The heuristics are:
4323 // - It must not have been prohibited by the caller to Parse (some callers
4324 // need a full AST).
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004325 // - The outer scope must allow lazy compilation of inner functions.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004326 // - The function mustn't be a function expression with an open parenthesis
4327 // before; we consider that a hint that the function will be called
4328 // immediately, and it would be a waste of time to make it lazily
4329 // compiled.
4330 // These are all things we can know at this point, without looking at the
4331 // function itself.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004332 bool is_lazily_compiled = (mode() == PARSE_LAZILY &&
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004333 top_scope_->AllowsLazyCompilation() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004334 !parenthesized_function_);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004335 parenthesized_function_ = false; // The bit was set for this function only.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004336
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004337 if (is_lazily_compiled) {
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004338 int function_block_pos = position();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004339 FunctionEntry entry;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004340 if (pre_parse_data_ != NULL) {
4341 // If we have pre_parse_data_, we use it to skip parsing the function
4342 // body. The preparser data contains the information we need to
4343 // construct the lazy function.
4344 entry = pre_parse_data()->GetFunctionEntry(function_block_pos);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004345 if (entry.is_valid()) {
4346 if (entry.end_pos() <= function_block_pos) {
4347 // End position greater than end of stream is safe, and hard
4348 // to check.
4349 ReportInvalidPreparseData(function_name, CHECK_OK);
4350 }
4351 scanner().SeekForward(entry.end_pos() - 1);
4352
4353 scope->set_end_position(entry.end_pos());
4354 Expect(Token::RBRACE, CHECK_OK);
4355 isolate()->counters()->total_preparse_skipped()->Increment(
4356 scope->end_position() - function_block_pos);
4357 materialized_literal_count = entry.literal_count();
4358 expected_property_count = entry.property_count();
4359 top_scope_->SetLanguageMode(entry.language_mode());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004360 } else {
4361 is_lazily_compiled = false;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004362 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004363 } else {
4364 // With no preparser data, we partially parse the function, without
4365 // building an AST. This gathers the data needed to build a lazy
4366 // function.
4367 SingletonLogger logger;
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004368 PreParser::PreParseResult result = LazyParseFunctionLiteral(&logger);
4369 if (result == PreParser::kPreParseStackOverflow) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004370 // Propagate stack overflow.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004371 set_stack_overflow();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004372 *ok = false;
4373 return NULL;
4374 }
4375 if (logger.has_error()) {
4376 const char* arg = logger.argument_opt();
4377 Vector<const char*> args;
4378 if (arg != NULL) {
4379 args = Vector<const char*>(&arg, 1);
4380 }
4381 ReportMessageAt(Scanner::Location(logger.start(), logger.end()),
4382 logger.message(), args);
4383 *ok = false;
4384 return NULL;
4385 }
4386 scope->set_end_position(logger.end());
4387 Expect(Token::RBRACE, CHECK_OK);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004388 isolate()->counters()->total_preparse_skipped()->Increment(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004389 scope->end_position() - function_block_pos);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004390 materialized_literal_count = logger.literals();
4391 expected_property_count = logger.properties();
4392 top_scope_->SetLanguageMode(logger.language_mode());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004393 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004394 }
4395
4396 if (!is_lazily_compiled) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004397 ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004398 body = new(zone()) ZoneList<Statement*>(8, zone());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004399 if (fvar != NULL) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00004400 VariableProxy* fproxy = top_scope_->NewUnresolved(
4401 factory(), function_name, Interface::NewConst());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004402 fproxy->BindTo(fvar);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004403 body->Add(factory()->NewExpressionStatement(
4404 factory()->NewAssignment(fvar_init_op,
4405 fproxy,
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004406 factory()->NewThisFunction(pos),
4407 RelocInfo::kNoPosition),
4408 RelocInfo::kNoPosition), zone());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004409 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004410
4411 // For generators, allocate and yield an iterator on function entry.
4412 if (is_generator) {
4413 ZoneList<Expression*>* arguments =
4414 new(zone()) ZoneList<Expression*>(0, zone());
4415 CallRuntime* allocation = factory()->NewCallRuntime(
4416 isolate()->factory()->empty_string(),
4417 Runtime::FunctionForId(Runtime::kCreateJSGeneratorObject),
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004418 arguments, pos);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004419 VariableProxy* init_proxy = factory()->NewVariableProxy(
4420 current_function_state_->generator_object_variable());
4421 Assignment* assignment = factory()->NewAssignment(
4422 Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition);
4423 VariableProxy* get_proxy = factory()->NewVariableProxy(
4424 current_function_state_->generator_object_variable());
4425 Yield* yield = factory()->NewYield(
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004426 get_proxy, assignment, Yield::INITIAL, RelocInfo::kNoPosition);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004427 body->Add(factory()->NewExpressionStatement(
4428 yield, RelocInfo::kNoPosition), zone());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004429 }
4430
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004431 ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004432
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004433 if (is_generator) {
4434 VariableProxy* get_proxy = factory()->NewVariableProxy(
4435 current_function_state_->generator_object_variable());
4436 Expression *undefined = factory()->NewLiteral(
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004437 isolate()->factory()->undefined_value(), RelocInfo::kNoPosition);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004438 Yield* yield = factory()->NewYield(
4439 get_proxy, undefined, Yield::FINAL, RelocInfo::kNoPosition);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004440 body->Add(factory()->NewExpressionStatement(
4441 yield, RelocInfo::kNoPosition), zone());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004442 }
4443
danno@chromium.orgc612e022011-11-10 11:38:15 +00004444 materialized_literal_count = function_state.materialized_literal_count();
4445 expected_property_count = function_state.expected_property_count();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004446 handler_count = function_state.handler_count();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004448 Expect(Token::RBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004449 scope->set_end_position(scanner().location().end_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004450 }
4451
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004452 // Validate strict mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004453 if (!top_scope_->is_classic_mode()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004454 if (IsEvalOrArguments(function_name)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004455 int start_pos = scope->start_position();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004456 int position = function_token_pos != RelocInfo::kNoPosition
4457 ? function_token_pos : (start_pos > 0 ? start_pos - 1 : start_pos);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004458 Scanner::Location location = Scanner::Location(position, start_pos);
4459 ReportMessageAt(location,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004460 "strict_function_name", Vector<const char*>::empty());
4461 *ok = false;
4462 return NULL;
4463 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004464 if (name_loc.IsValid()) {
4465 ReportMessageAt(name_loc, "strict_param_name",
4466 Vector<const char*>::empty());
4467 *ok = false;
4468 return NULL;
4469 }
4470 if (dupe_loc.IsValid()) {
4471 ReportMessageAt(dupe_loc, "strict_param_dupe",
4472 Vector<const char*>::empty());
4473 *ok = false;
4474 return NULL;
4475 }
ager@chromium.org04921a82011-06-27 13:21:41 +00004476 if (name_is_strict_reserved) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004477 int start_pos = scope->start_position();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004478 int position = function_token_pos != RelocInfo::kNoPosition
4479 ? function_token_pos : (start_pos > 0 ? start_pos - 1 : start_pos);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004480 Scanner::Location location = Scanner::Location(position, start_pos);
4481 ReportMessageAt(location, "strict_reserved_word",
4482 Vector<const char*>::empty());
4483 *ok = false;
4484 return NULL;
4485 }
4486 if (reserved_loc.IsValid()) {
4487 ReportMessageAt(reserved_loc, "strict_reserved_word",
4488 Vector<const char*>::empty());
4489 *ok = false;
4490 return NULL;
4491 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004492 CheckOctalLiteral(scope->start_position(),
4493 scope->end_position(),
4494 CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004495 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004496 ast_properties = *factory()->visitor()->ast_properties();
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00004497 dont_optimize_reason = factory()->visitor()->dont_optimize_reason();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004499
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004500 if (is_extended_mode()) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004501 CheckConflictingVarDeclarations(scope, CHECK_OK);
4502 }
4503
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004504 FunctionLiteral* function_literal =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004505 factory()->NewFunctionLiteral(function_name,
4506 scope,
4507 body,
4508 materialized_literal_count,
4509 expected_property_count,
4510 handler_count,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004511 num_parameters,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004512 duplicate_parameters,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004513 function_type,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004514 FunctionLiteral::kIsFunction,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004515 parenthesized,
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004516 generator,
4517 pos);
4518 function_literal->set_function_token_position(function_token_pos);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004519 function_literal->set_ast_properties(&ast_properties);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00004520 function_literal->set_dont_optimize_reason(dont_optimize_reason);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004521
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004522 if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004523 return function_literal;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004524}
4525
4526
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004527PreParser::PreParseResult Parser::LazyParseFunctionLiteral(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004528 SingletonLogger* logger) {
4529 HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse());
4530 ASSERT_EQ(Token::LBRACE, scanner().current_token());
4531
4532 if (reusable_preparser_ == NULL) {
4533 intptr_t stack_limit = isolate()->stack_guard()->real_climit();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004534 reusable_preparser_ = new PreParser(&scanner_, NULL, stack_limit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004535 reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping());
4536 reusable_preparser_->set_allow_modules(allow_modules());
4537 reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax());
4538 reusable_preparser_->set_allow_lazy(true);
4539 reusable_preparser_->set_allow_generators(allow_generators());
danno@chromium.org1fd77d52013-06-07 16:01:45 +00004540 reusable_preparser_->set_allow_for_of(allow_for_of());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004541 reusable_preparser_->set_allow_harmony_numeric_literals(
4542 allow_harmony_numeric_literals());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004543 }
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004544 PreParser::PreParseResult result =
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004545 reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(),
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004546 is_generator(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004547 logger);
4548 return result;
4549}
4550
4551
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552Expression* Parser::ParseV8Intrinsic(bool* ok) {
4553 // CallRuntime ::
4554 // '%' Identifier Arguments
4555
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004556 int pos = peek_position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004557 Expect(Token::MOD, CHECK_OK);
4558 Handle<String> name = ParseIdentifier(CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004559 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004560
4561 if (extension_ != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 // The extension structures are only accessible while parsing the
4563 // very first time not when reparsing because of lazy compilation.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004564 top_scope_->DeclarationScope()->ForceEagerCompilation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565 }
4566
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004567 const Runtime::Function* function = Runtime::FunctionForName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004568
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004569 // Check for built-in IS_VAR macro.
4570 if (function != NULL &&
4571 function->intrinsic_type == Runtime::RUNTIME &&
4572 function->function_id == Runtime::kIS_VAR) {
4573 // %IS_VAR(x) evaluates to x if x is a variable,
4574 // leads to a parse error otherwise. Could be implemented as an
4575 // inline function %_IS_VAR(x) to eliminate this special case.
4576 if (args->length() == 1 && args->at(0)->AsVariableProxy() != NULL) {
4577 return args->at(0);
4578 } else {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004579 ReportMessage("not_isvar", Vector<const char*>::empty());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004580 *ok = false;
4581 return NULL;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004582 }
4583 }
4584
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004585 // Check that the expected number of arguments are being passed.
4586 if (function != NULL &&
4587 function->nargs != -1 &&
4588 function->nargs != args->length()) {
4589 ReportMessage("illegal_access", Vector<const char*>::empty());
4590 *ok = false;
4591 return NULL;
4592 }
4593
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00004594 // Check that the function is defined if it's an inline runtime call.
4595 if (function == NULL && name->Get(0) == '_') {
4596 ReportMessage("not_defined", Vector<Handle<String> >(&name, 1));
4597 *ok = false;
4598 return NULL;
4599 }
4600
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004601 // We have a valid intrinsics call or a call to a builtin.
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004602 return factory()->NewCallRuntime(name, function, args, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603}
4604
4605
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004606bool ParserBase::peek_any_identifier() {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004607 Token::Value next = peek();
4608 return next == Token::IDENTIFIER ||
ager@chromium.org04921a82011-06-27 13:21:41 +00004609 next == Token::FUTURE_RESERVED_WORD ||
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004610 next == Token::FUTURE_STRICT_RESERVED_WORD ||
4611 next == Token::YIELD;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004612}
4613
4614
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004615bool ParserBase::CheckContextualKeyword(Vector<const char> keyword) {
danno@chromium.org1fd77d52013-06-07 16:01:45 +00004616 if (peek() == Token::IDENTIFIER &&
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004617 scanner()->is_next_contextual_keyword(keyword)) {
danno@chromium.org1fd77d52013-06-07 16:01:45 +00004618 Consume(Token::IDENTIFIER);
4619 return true;
4620 }
4621 return false;
4622}
4623
4624
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004625void ParserBase::ExpectSemicolon(bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626 // Check for automatic semicolon insertion according to
4627 // the rules given in ECMA-262, section 7.9, page 21.
4628 Token::Value tok = peek();
4629 if (tok == Token::SEMICOLON) {
4630 Next();
4631 return;
4632 }
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004633 if (scanner()->HasAnyLineTerminatorBeforeNext() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 tok == Token::RBRACE ||
4635 tok == Token::EOS) {
4636 return;
4637 }
4638 Expect(Token::SEMICOLON, ok);
4639}
4640
4641
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004642void ParserBase::ExpectContextualKeyword(Vector<const char> keyword, bool* ok) {
ulan@chromium.org812308e2012-02-29 15:58:45 +00004643 Expect(Token::IDENTIFIER, ok);
4644 if (!*ok) return;
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004645 if (!scanner()->is_literal_contextual_keyword(keyword)) {
4646 ReportUnexpectedToken(scanner()->current_token());
ulan@chromium.org812308e2012-02-29 15:58:45 +00004647 *ok = false;
ulan@chromium.org812308e2012-02-29 15:58:45 +00004648 }
4649}
4650
4651
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004652Literal* Parser::GetLiteralUndefined(int position) {
4653 return factory()->NewLiteral(
4654 isolate()->factory()->undefined_value(), position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004655}
4656
4657
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004658Literal* Parser::GetLiteralTheHole(int position) {
4659 return factory()->NewLiteral(
4660 isolate()->factory()->the_hole_value(), RelocInfo::kNoPosition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004661}
4662
4663
danno@chromium.orgb6451162011-08-17 14:33:23 +00004664// Parses an identifier that is valid for the current scope, in particular it
ager@chromium.org04921a82011-06-27 13:21:41 +00004665// fails on strict mode future reserved keywords in a strict scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004666Handle<String> Parser::ParseIdentifier(bool* ok) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004667 Token::Value next = Next();
4668 if (next == Token::IDENTIFIER ||
4669 (top_scope_->is_classic_mode() &&
4670 (next == Token::FUTURE_STRICT_RESERVED_WORD ||
4671 (next == Token::YIELD && !is_generator())))) {
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004672 return GetSymbol();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004673 } else {
4674 ReportUnexpectedToken(next);
4675 *ok = false;
4676 return Handle<String>();
ager@chromium.org04921a82011-06-27 13:21:41 +00004677 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004678}
4679
4680
ager@chromium.org04921a82011-06-27 13:21:41 +00004681// Parses and identifier or a strict mode future reserved word, and indicate
4682// whether it is strict mode future reserved.
4683Handle<String> Parser::ParseIdentifierOrStrictReservedWord(
4684 bool* is_strict_reserved, bool* ok) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004685 Token::Value next = Next();
4686 if (next == Token::IDENTIFIER) {
4687 *is_strict_reserved = false;
4688 } else if (next == Token::FUTURE_STRICT_RESERVED_WORD ||
4689 (next == Token::YIELD && !is_generator())) {
ager@chromium.org04921a82011-06-27 13:21:41 +00004690 *is_strict_reserved = true;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004691 } else {
4692 ReportUnexpectedToken(next);
4693 *ok = false;
4694 return Handle<String>();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004695 }
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004696 return GetSymbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004697}
4698
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004699
4700Handle<String> Parser::ParseIdentifierName(bool* ok) {
4701 Token::Value next = Next();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004702 if (next != Token::IDENTIFIER &&
ager@chromium.org04921a82011-06-27 13:21:41 +00004703 next != Token::FUTURE_RESERVED_WORD &&
4704 next != Token::FUTURE_STRICT_RESERVED_WORD &&
4705 !Token::IsKeyword(next)) {
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004706 ReportUnexpectedToken(next);
4707 *ok = false;
4708 return Handle<String>();
4709 }
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004710 return GetSymbol();
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004711}
4712
ager@chromium.org378b34e2011-01-28 08:04:38 +00004713
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004714void Parser::MarkAsLValue(Expression* expression) {
4715 VariableProxy* proxy = expression != NULL
4716 ? expression->AsVariableProxy()
4717 : NULL;
4718
4719 if (proxy != NULL) proxy->MarkAsLValue();
4720}
4721
4722
ager@chromium.org378b34e2011-01-28 08:04:38 +00004723// Checks LHS expression for assignment and prefix/postfix increment/decrement
4724// in strict mode.
4725void Parser::CheckStrictModeLValue(Expression* expression,
4726 const char* error,
4727 bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004728 ASSERT(!top_scope_->is_classic_mode());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004729 VariableProxy* lhs = expression != NULL
4730 ? expression->AsVariableProxy()
4731 : NULL;
4732
4733 if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
4734 ReportMessage(error, Vector<const char*>::empty());
4735 *ok = false;
4736 }
4737}
4738
4739
lrn@chromium.org1c092762011-05-09 09:42:16 +00004740// Checks whether an octal literal was last seen between beg_pos and end_pos.
4741// If so, reports an error. Only called for strict mode.
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004742void ParserBase::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
4743 Scanner::Location octal = scanner()->octal_position();
4744 if (octal.IsValid() && beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
4745 ReportMessageAt(octal, "strict_octal_literal");
4746 scanner()->clear_octal_position();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004747 *ok = false;
4748 }
4749}
4750
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004751
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004752void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
4753 Declaration* decl = scope->CheckConflictingVarDeclarations();
4754 if (decl != NULL) {
4755 // In harmony mode we treat conflicting variable bindinds as early
4756 // errors. See ES5 16 for a definition of early errors.
4757 Handle<String> name = decl->proxy()->name();
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004758 SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004759 const char* elms[2] = { "Variable", *c_string };
4760 Vector<const char*> args(elms, 2);
4761 int position = decl->proxy()->position();
4762 Scanner::Location location = position == RelocInfo::kNoPosition
4763 ? Scanner::Location::invalid()
4764 : Scanner::Location(position, position + 1);
4765 ReportMessageAt(location, "redeclaration", args);
4766 *ok = false;
4767 }
4768}
4769
4770
ager@chromium.org04921a82011-06-27 13:21:41 +00004771// This function reads an identifier name and determines whether or not it
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004772// is 'get' or 'set'.
ager@chromium.org04921a82011-06-27 13:21:41 +00004773Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get,
4774 bool* is_set,
4775 bool* ok) {
4776 Handle<String> result = ParseIdentifierName(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004777 if (!*ok) return Handle<String>();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004778 if (scanner().is_literal_ascii() && scanner().literal_length() == 3) {
4779 const char* token = scanner().literal_ascii_string().start();
4780 *is_get = strncmp(token, "get", 3) == 0;
4781 *is_set = !*is_get && strncmp(token, "set", 3) == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004782 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004783 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784}
4785
4786
4787// ----------------------------------------------------------------------------
4788// Parser support
4789
4790
4791bool Parser::TargetStackContainsLabel(Handle<String> label) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004792 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
4793 BreakableStatement* stat = t->node()->AsBreakableStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794 if (stat != NULL && ContainsLabel(stat->labels(), label))
4795 return true;
4796 }
4797 return false;
4798}
4799
4800
4801BreakableStatement* Parser::LookupBreakTarget(Handle<String> label, bool* ok) {
4802 bool anonymous = label.is_null();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004803 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
4804 BreakableStatement* stat = t->node()->AsBreakableStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004805 if (stat == NULL) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806 if ((anonymous && stat->is_target_for_anonymous()) ||
4807 (!anonymous && ContainsLabel(stat->labels(), label))) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004808 RegisterTargetUse(stat->break_target(), t->previous());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004809 return stat;
4810 }
4811 }
4812 return NULL;
4813}
4814
4815
4816IterationStatement* Parser::LookupContinueTarget(Handle<String> label,
4817 bool* ok) {
4818 bool anonymous = label.is_null();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004819 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
4820 IterationStatement* stat = t->node()->AsIterationStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004821 if (stat == NULL) continue;
4822
4823 ASSERT(stat->is_target_for_anonymous());
4824 if (anonymous || ContainsLabel(stat->labels(), label)) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004825 RegisterTargetUse(stat->continue_target(), t->previous());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 return stat;
4827 }
4828 }
4829 return NULL;
4830}
4831
4832
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004833void Parser::RegisterTargetUse(Label* target, Target* stop) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004834 // Register that a break target found at the given stop in the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004835 // target stack has been used from the top of the target stack. Add
4836 // the break target to any TargetCollectors passed on the stack.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004837 for (Target* t = target_stack_; t != stop; t = t->previous()) {
4838 TargetCollector* collector = t->node()->AsTargetCollector();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004839 if (collector != NULL) collector->AddTarget(target, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004840 }
4841}
4842
4843
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004844Expression* Parser::NewThrowReferenceError(Handle<String> message) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004845 return NewThrowError(isolate()->factory()->MakeReferenceError_string(),
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004846 message, HandleVector<Object>(NULL, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847}
4848
4849
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004850Expression* Parser::NewThrowSyntaxError(Handle<String> message,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004851 Handle<Object> first) {
4852 int argc = first.is_null() ? 0 : 1;
4853 Vector< Handle<Object> > arguments = HandleVector<Object>(&first, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004854 return NewThrowError(
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004855 isolate()->factory()->MakeSyntaxError_string(), message, arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856}
4857
4858
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004859Expression* Parser::NewThrowTypeError(Handle<String> message,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004860 Handle<Object> first,
4861 Handle<Object> second) {
4862 ASSERT(!first.is_null() && !second.is_null());
4863 Handle<Object> elements[] = { first, second };
4864 Vector< Handle<Object> > arguments =
4865 HandleVector<Object>(elements, ARRAY_SIZE(elements));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004866 return NewThrowError(
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004867 isolate()->factory()->MakeTypeError_string(), message, arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004868}
4869
4870
4871Expression* Parser::NewThrowError(Handle<String> constructor,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004872 Handle<String> message,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004873 Vector< Handle<Object> > arguments) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004874 int argc = arguments.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004875 Handle<FixedArray> elements = isolate()->factory()->NewFixedArray(argc,
4876 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004877 for (int i = 0; i < argc; i++) {
4878 Handle<Object> element = arguments[i];
4879 if (!element.is_null()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004880 elements->set(i, *element);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004881 }
4882 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004883 Handle<JSArray> array = isolate()->factory()->NewJSArrayWithElements(
4884 elements, FAST_ELEMENTS, TENURED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004885
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004886 int pos = position();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004887 ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2, zone());
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004888 args->Add(factory()->NewLiteral(message, pos), zone());
4889 args->Add(factory()->NewLiteral(array, pos), zone());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004890 CallRuntime* call_constructor =
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00004891 factory()->NewCallRuntime(constructor, NULL, args, pos);
4892 return factory()->NewThrow(call_constructor, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893}
4894
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00004895
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004896// ----------------------------------------------------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004897// Regular expressions
4898
4899
4900RegExpParser::RegExpParser(FlatStringReader* in,
4901 Handle<String>* error,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00004902 bool multiline,
4903 Zone* zone)
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00004904 : isolate_(zone->isolate()),
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00004905 zone_(zone),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004906 error_(error),
4907 captures_(NULL),
4908 in_(in),
4909 current_(kEndMarker),
4910 next_pos_(0),
4911 capture_count_(0),
4912 has_more_(true),
4913 multiline_(multiline),
4914 simple_(false),
4915 contains_anchor_(false),
4916 is_scanned_for_captures_(false),
4917 failed_(false) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00004918 Advance();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004919}
4920
4921
4922uc32 RegExpParser::Next() {
4923 if (has_next()) {
4924 return in()->Get(next_pos_);
4925 } else {
4926 return kEndMarker;
4927 }
4928}
4929
4930
4931void RegExpParser::Advance() {
4932 if (next_pos_ < in()->length()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004933 StackLimitCheck check(isolate());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004934 if (check.HasOverflowed()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004935 ReportError(CStrVector(Isolate::kStackOverflowMessage));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00004936 } else if (zone()->excess_allocation()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004937 ReportError(CStrVector("Regular expression too large"));
4938 } else {
4939 current_ = in()->Get(next_pos_);
4940 next_pos_++;
4941 }
4942 } else {
4943 current_ = kEndMarker;
4944 has_more_ = false;
4945 }
4946}
4947
4948
4949void RegExpParser::Reset(int pos) {
4950 next_pos_ = pos;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004951 has_more_ = (pos < in()->length());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004952 Advance();
4953}
4954
4955
4956void RegExpParser::Advance(int dist) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00004957 next_pos_ += dist - 1;
4958 Advance();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004959}
4960
4961
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004962bool RegExpParser::simple() {
4963 return simple_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004964}
4965
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00004966
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004967RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
4968 failed_ = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004969 *error_ = isolate()->factory()->NewStringFromAscii(message, NOT_TENURED);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004970 // Zip to the end to make sure the no more input is read.
4971 current_ = kEndMarker;
4972 next_pos_ = in()->length();
4973 return NULL;
4974}
4975
4976
4977// Pattern ::
4978// Disjunction
4979RegExpTree* RegExpParser::ParsePattern() {
4980 RegExpTree* result = ParseDisjunction(CHECK_FAILED);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004981 ASSERT(!has_more());
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004982 // If the result of parsing is a literal string atom, and it has the
4983 // same length as the input, then the atom is identical to the input.
4984 if (result->IsAtom() && result->AsAtom()->length() == in()->length()) {
4985 simple_ = true;
4986 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004987 return result;
4988}
4989
4990
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004991// Disjunction ::
4992// Alternative
4993// Alternative | Disjunction
4994// Alternative ::
4995// [empty]
4996// Term Alternative
4997// Term ::
4998// Assertion
4999// Atom
5000// Atom Quantifier
5001RegExpTree* RegExpParser::ParseDisjunction() {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005002 // Used to store current state while parsing subexpressions.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00005003 RegExpParserState initial_state(NULL, INITIAL, 0, zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005004 RegExpParserState* stored_state = &initial_state;
5005 // Cache the builder in a local variable for quick access.
5006 RegExpBuilder* builder = initial_state.builder();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005007 while (true) {
5008 switch (current()) {
5009 case kEndMarker:
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005010 if (stored_state->IsSubexpression()) {
5011 // Inside a parenthesized group when hitting end of input.
5012 ReportError(CStrVector("Unterminated group") CHECK_FAILED);
5013 }
5014 ASSERT_EQ(INITIAL, stored_state->group_type());
5015 // Parsing completed successfully.
5016 return builder->ToRegExp();
5017 case ')': {
5018 if (!stored_state->IsSubexpression()) {
5019 ReportError(CStrVector("Unmatched ')'") CHECK_FAILED);
5020 }
5021 ASSERT_NE(INITIAL, stored_state->group_type());
5022
5023 Advance();
5024 // End disjunction parsing and convert builder content to new single
5025 // regexp atom.
5026 RegExpTree* body = builder->ToRegExp();
5027
5028 int end_capture_index = captures_started();
5029
5030 int capture_index = stored_state->capture_index();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005031 SubexpressionType group_type = stored_state->group_type();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005032
5033 // Restore previous state.
5034 stored_state = stored_state->previous_state();
5035 builder = stored_state->builder();
5036
5037 // Build result of subexpression.
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005038 if (group_type == CAPTURE) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005039 RegExpCapture* capture = new(zone()) RegExpCapture(body, capture_index);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005040 captures_->at(capture_index - 1) = capture;
5041 body = capture;
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005042 } else if (group_type != GROUPING) {
5043 ASSERT(group_type == POSITIVE_LOOKAHEAD ||
5044 group_type == NEGATIVE_LOOKAHEAD);
5045 bool is_positive = (group_type == POSITIVE_LOOKAHEAD);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005046 body = new(zone()) RegExpLookahead(body,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005047 is_positive,
5048 end_capture_index - capture_index,
5049 capture_index);
5050 }
5051 builder->AddAtom(body);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005052 // For compatability with JSC and ES3, we allow quantifiers after
5053 // lookaheads, and break in all cases.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005054 break;
5055 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005056 case '|': {
5057 Advance();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005058 builder->NewAlternative();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005059 continue;
5060 }
5061 case '*':
5062 case '+':
5063 case '?':
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005064 return ReportError(CStrVector("Nothing to repeat"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005065 case '^': {
5066 Advance();
iposva@chromium.org245aa852009-02-10 00:49:54 +00005067 if (multiline_) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005068 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005069 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_LINE));
iposva@chromium.org245aa852009-02-10 00:49:54 +00005070 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005071 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005072 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_INPUT));
iposva@chromium.org245aa852009-02-10 00:49:54 +00005073 set_contains_anchor();
5074 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005075 continue;
5076 }
5077 case '$': {
5078 Advance();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005079 RegExpAssertion::AssertionType assertion_type =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005080 multiline_ ? RegExpAssertion::END_OF_LINE :
5081 RegExpAssertion::END_OF_INPUT;
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005082 builder->AddAssertion(new(zone()) RegExpAssertion(assertion_type));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005083 continue;
5084 }
5085 case '.': {
5086 Advance();
5087 // everything except \x0a, \x0d, \u2028 and \u2029
danno@chromium.org40cb8782011-05-25 07:58:50 +00005088 ZoneList<CharacterRange>* ranges =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005089 new(zone()) ZoneList<CharacterRange>(2, zone());
5090 CharacterRange::AddClassEscape('.', ranges, zone());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005091 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005092 builder->AddAtom(atom);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005093 break;
5094 }
5095 case '(': {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005096 SubexpressionType subexpr_type = CAPTURE;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005097 Advance();
5098 if (current() == '?') {
5099 switch (Next()) {
5100 case ':':
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005101 subexpr_type = GROUPING;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005102 break;
5103 case '=':
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005104 subexpr_type = POSITIVE_LOOKAHEAD;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005105 break;
5106 case '!':
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005107 subexpr_type = NEGATIVE_LOOKAHEAD;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005108 break;
5109 default:
5110 ReportError(CStrVector("Invalid group") CHECK_FAILED);
5111 break;
5112 }
5113 Advance(2);
5114 } else {
5115 if (captures_ == NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005116 captures_ = new(zone()) ZoneList<RegExpCapture*>(2, zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005117 }
5118 if (captures_started() >= kMaxCaptures) {
5119 ReportError(CStrVector("Too many captures") CHECK_FAILED);
5120 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005121 captures_->Add(NULL, zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005122 }
5123 // Store current state and begin new disjunction parsing.
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005124 stored_state = new(zone()) RegExpParserState(stored_state, subexpr_type,
rossberg@chromium.org400388e2012-06-06 09:29:22 +00005125 captures_started(), zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005126 builder = stored_state->builder();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005127 continue;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005128 }
5129 case '[': {
5130 RegExpTree* atom = ParseCharacterClass(CHECK_FAILED);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005131 builder->AddAtom(atom);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005132 break;
5133 }
5134 // Atom ::
5135 // \ AtomEscape
5136 case '\\':
5137 switch (Next()) {
5138 case kEndMarker:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005139 return ReportError(CStrVector("\\ at end of pattern"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005140 case 'b':
5141 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005142 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005143 new(zone()) RegExpAssertion(RegExpAssertion::BOUNDARY));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005144 continue;
5145 case 'B':
5146 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005147 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005148 new(zone()) RegExpAssertion(RegExpAssertion::NON_BOUNDARY));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005149 continue;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005150 // AtomEscape ::
5151 // CharacterClassEscape
5152 //
5153 // CharacterClassEscape :: one of
5154 // d D s S w W
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005155 case 'd': case 'D': case 's': case 'S': case 'w': case 'W': {
5156 uc32 c = Next();
5157 Advance(2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00005158 ZoneList<CharacterRange>* ranges =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005159 new(zone()) ZoneList<CharacterRange>(2, zone());
5160 CharacterRange::AddClassEscape(c, ranges, zone());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005161 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005162 builder->AddAtom(atom);
5163 break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005164 }
5165 case '1': case '2': case '3': case '4': case '5': case '6':
5166 case '7': case '8': case '9': {
5167 int index = 0;
5168 if (ParseBackReferenceIndex(&index)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005169 RegExpCapture* capture = NULL;
5170 if (captures_ != NULL && index <= captures_->length()) {
5171 capture = captures_->at(index - 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005172 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005173 if (capture == NULL) {
5174 builder->AddEmpty();
5175 break;
5176 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005177 RegExpTree* atom = new(zone()) RegExpBackReference(capture);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005178 builder->AddAtom(atom);
5179 break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005180 }
5181 uc32 first_digit = Next();
5182 if (first_digit == '8' || first_digit == '9') {
5183 // Treat as identity escape
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005184 builder->AddCharacter(first_digit);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005185 Advance(2);
5186 break;
5187 }
5188 }
5189 // FALLTHROUGH
5190 case '0': {
5191 Advance();
5192 uc32 octal = ParseOctalLiteral();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005193 builder->AddCharacter(octal);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005194 break;
5195 }
5196 // ControlEscape :: one of
5197 // f n r t v
5198 case 'f':
5199 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005200 builder->AddCharacter('\f');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005201 break;
5202 case 'n':
5203 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005204 builder->AddCharacter('\n');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005205 break;
5206 case 'r':
5207 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005208 builder->AddCharacter('\r');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005209 break;
5210 case 't':
5211 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005212 builder->AddCharacter('\t');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005213 break;
5214 case 'v':
5215 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005216 builder->AddCharacter('\v');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005217 break;
5218 case 'c': {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00005219 Advance();
5220 uc32 controlLetter = Next();
5221 // Special case if it is an ASCII letter.
5222 // Convert lower case letters to uppercase.
5223 uc32 letter = controlLetter & ~('a' ^ 'A');
5224 if (letter < 'A' || 'Z' < letter) {
5225 // controlLetter is not in range 'A'-'Z' or 'a'-'z'.
5226 // This is outside the specification. We match JSC in
5227 // reading the backslash as a literal character instead
5228 // of as starting an escape.
5229 builder->AddCharacter('\\');
5230 } else {
5231 Advance(2);
5232 builder->AddCharacter(controlLetter & 0x1f);
5233 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005234 break;
5235 }
5236 case 'x': {
5237 Advance(2);
5238 uc32 value;
5239 if (ParseHexEscape(2, &value)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005240 builder->AddCharacter(value);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005241 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005242 builder->AddCharacter('x');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005243 }
5244 break;
5245 }
5246 case 'u': {
5247 Advance(2);
5248 uc32 value;
5249 if (ParseHexEscape(4, &value)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005250 builder->AddCharacter(value);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005251 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005252 builder->AddCharacter('u');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005253 }
5254 break;
5255 }
5256 default:
5257 // Identity escape.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005258 builder->AddCharacter(Next());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005259 Advance(2);
5260 break;
5261 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005262 break;
5263 case '{': {
5264 int dummy;
5265 if (ParseIntervalQuantifier(&dummy, &dummy)) {
5266 ReportError(CStrVector("Nothing to repeat") CHECK_FAILED);
5267 }
5268 // fallthrough
5269 }
5270 default:
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005271 builder->AddCharacter(current());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005272 Advance();
5273 break;
5274 } // end switch(current())
5275
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005276 int min;
5277 int max;
5278 switch (current()) {
5279 // QuantifierPrefix ::
5280 // *
5281 // +
5282 // ?
5283 // {
5284 case '*':
5285 min = 0;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005286 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005287 Advance();
5288 break;
5289 case '+':
5290 min = 1;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005291 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005292 Advance();
5293 break;
5294 case '?':
5295 min = 0;
5296 max = 1;
5297 Advance();
5298 break;
5299 case '{':
5300 if (ParseIntervalQuantifier(&min, &max)) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005301 if (max < min) {
5302 ReportError(CStrVector("numbers out of order in {} quantifier.")
5303 CHECK_FAILED);
5304 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005305 break;
5306 } else {
5307 continue;
5308 }
5309 default:
5310 continue;
5311 }
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005312 RegExpQuantifier::QuantifierType quantifier_type = RegExpQuantifier::GREEDY;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005313 if (current() == '?') {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005314 quantifier_type = RegExpQuantifier::NON_GREEDY;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005315 Advance();
5316 } else if (FLAG_regexp_possessive_quantifier && current() == '+') {
5317 // FLAG_regexp_possessive_quantifier is a debug-only flag.
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005318 quantifier_type = RegExpQuantifier::POSSESSIVE;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005319 Advance();
5320 }
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005321 builder->AddQuantifierToAtom(min, max, quantifier_type);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005322 }
5323}
5324
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005325
5326#ifdef DEBUG
5327// Currently only used in an ASSERT.
5328static bool IsSpecialClassEscape(uc32 c) {
5329 switch (c) {
5330 case 'd': case 'D':
5331 case 's': case 'S':
5332 case 'w': case 'W':
5333 return true;
5334 default:
5335 return false;
5336 }
5337}
5338#endif
5339
5340
5341// In order to know whether an escape is a backreference or not we have to scan
5342// the entire regexp and find the number of capturing parentheses. However we
5343// don't want to scan the regexp twice unless it is necessary. This mini-parser
5344// is called when needed. It can see the difference between capturing and
5345// noncapturing parentheses and can skip character classes and backslash-escaped
5346// characters.
5347void RegExpParser::ScanForCaptures() {
5348 // Start with captures started previous to current position
5349 int capture_count = captures_started();
5350 // Add count of captures after this position.
5351 int n;
5352 while ((n = current()) != kEndMarker) {
5353 Advance();
5354 switch (n) {
5355 case '\\':
5356 Advance();
5357 break;
5358 case '[': {
5359 int c;
5360 while ((c = current()) != kEndMarker) {
5361 Advance();
5362 if (c == '\\') {
5363 Advance();
5364 } else {
5365 if (c == ']') break;
5366 }
5367 }
5368 break;
5369 }
5370 case '(':
5371 if (current() != '?') capture_count++;
5372 break;
5373 }
5374 }
5375 capture_count_ = capture_count;
5376 is_scanned_for_captures_ = true;
5377}
5378
5379
5380bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
5381 ASSERT_EQ('\\', current());
5382 ASSERT('1' <= Next() && Next() <= '9');
iposva@chromium.org245aa852009-02-10 00:49:54 +00005383 // Try to parse a decimal literal that is no greater than the total number
5384 // of left capturing parentheses in the input.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005385 int start = position();
5386 int value = Next() - '0';
5387 Advance(2);
5388 while (true) {
5389 uc32 c = current();
5390 if (IsDecimalDigit(c)) {
5391 value = 10 * value + (c - '0');
iposva@chromium.org245aa852009-02-10 00:49:54 +00005392 if (value > kMaxCaptures) {
5393 Reset(start);
5394 return false;
5395 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005396 Advance();
5397 } else {
5398 break;
5399 }
5400 }
5401 if (value > captures_started()) {
5402 if (!is_scanned_for_captures_) {
5403 int saved_position = position();
5404 ScanForCaptures();
5405 Reset(saved_position);
5406 }
5407 if (value > capture_count_) {
5408 Reset(start);
5409 return false;
5410 }
5411 }
5412 *index_out = value;
5413 return true;
5414}
5415
5416
5417// QuantifierPrefix ::
5418// { DecimalDigits }
5419// { DecimalDigits , }
5420// { DecimalDigits , DecimalDigits }
iposva@chromium.org245aa852009-02-10 00:49:54 +00005421//
5422// Returns true if parsing succeeds, and set the min_out and max_out
5423// values. Values are truncated to RegExpTree::kInfinity if they overflow.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005424bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) {
5425 ASSERT_EQ(current(), '{');
5426 int start = position();
5427 Advance();
5428 int min = 0;
5429 if (!IsDecimalDigit(current())) {
5430 Reset(start);
5431 return false;
5432 }
5433 while (IsDecimalDigit(current())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005434 int next = current() - '0';
5435 if (min > (RegExpTree::kInfinity - next) / 10) {
5436 // Overflow. Skip past remaining decimal digits and return -1.
5437 do {
5438 Advance();
5439 } while (IsDecimalDigit(current()));
5440 min = RegExpTree::kInfinity;
5441 break;
5442 }
5443 min = 10 * min + next;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005444 Advance();
5445 }
5446 int max = 0;
5447 if (current() == '}') {
5448 max = min;
5449 Advance();
5450 } else if (current() == ',') {
5451 Advance();
5452 if (current() == '}') {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005453 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005454 Advance();
5455 } else {
5456 while (IsDecimalDigit(current())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005457 int next = current() - '0';
5458 if (max > (RegExpTree::kInfinity - next) / 10) {
5459 do {
5460 Advance();
5461 } while (IsDecimalDigit(current()));
5462 max = RegExpTree::kInfinity;
5463 break;
5464 }
5465 max = 10 * max + next;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005466 Advance();
5467 }
5468 if (current() != '}') {
5469 Reset(start);
5470 return false;
5471 }
5472 Advance();
5473 }
5474 } else {
5475 Reset(start);
5476 return false;
5477 }
5478 *min_out = min;
5479 *max_out = max;
5480 return true;
5481}
5482
5483
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005484uc32 RegExpParser::ParseOctalLiteral() {
5485 ASSERT('0' <= current() && current() <= '7');
5486 // For compatibility with some other browsers (not all), we parse
5487 // up to three octal digits with a value below 256.
5488 uc32 value = current() - '0';
5489 Advance();
5490 if ('0' <= current() && current() <= '7') {
5491 value = value * 8 + current() - '0';
5492 Advance();
5493 if (value < 32 && '0' <= current() && current() <= '7') {
5494 value = value * 8 + current() - '0';
5495 Advance();
5496 }
5497 }
5498 return value;
5499}
5500
5501
5502bool RegExpParser::ParseHexEscape(int length, uc32 *value) {
5503 int start = position();
5504 uc32 val = 0;
5505 bool done = false;
5506 for (int i = 0; !done; i++) {
5507 uc32 c = current();
5508 int d = HexValue(c);
5509 if (d < 0) {
5510 Reset(start);
5511 return false;
5512 }
5513 val = val * 16 + d;
5514 Advance();
5515 if (i == length - 1) {
5516 done = true;
5517 }
5518 }
5519 *value = val;
5520 return true;
5521}
5522
5523
5524uc32 RegExpParser::ParseClassCharacterEscape() {
5525 ASSERT(current() == '\\');
5526 ASSERT(has_next() && !IsSpecialClassEscape(Next()));
5527 Advance();
5528 switch (current()) {
5529 case 'b':
5530 Advance();
5531 return '\b';
5532 // ControlEscape :: one of
5533 // f n r t v
5534 case 'f':
5535 Advance();
5536 return '\f';
5537 case 'n':
5538 Advance();
5539 return '\n';
5540 case 'r':
5541 Advance();
5542 return '\r';
5543 case 't':
5544 Advance();
5545 return '\t';
5546 case 'v':
5547 Advance();
5548 return '\v';
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00005549 case 'c': {
5550 uc32 controlLetter = Next();
5551 uc32 letter = controlLetter & ~('A' ^ 'a');
5552 // For compatibility with JSC, inside a character class
5553 // we also accept digits and underscore as control characters.
5554 if ((controlLetter >= '0' && controlLetter <= '9') ||
5555 controlLetter == '_' ||
5556 (letter >= 'A' && letter <= 'Z')) {
5557 Advance(2);
5558 // Control letters mapped to ASCII control characters in the range
5559 // 0x00-0x1f.
5560 return controlLetter & 0x1f;
5561 }
5562 // We match JSC in reading the backslash as a literal
5563 // character instead of as starting an escape.
5564 return '\\';
5565 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005566 case '0': case '1': case '2': case '3': case '4': case '5':
5567 case '6': case '7':
5568 // For compatibility, we interpret a decimal escape that isn't
5569 // a back reference (and therefore either \0 or not valid according
5570 // to the specification) as a 1..3 digit octal character code.
5571 return ParseOctalLiteral();
5572 case 'x': {
5573 Advance();
5574 uc32 value;
5575 if (ParseHexEscape(2, &value)) {
5576 return value;
5577 }
5578 // If \x is not followed by a two-digit hexadecimal, treat it
5579 // as an identity escape.
5580 return 'x';
5581 }
5582 case 'u': {
5583 Advance();
5584 uc32 value;
5585 if (ParseHexEscape(4, &value)) {
5586 return value;
5587 }
5588 // If \u is not followed by a four-digit hexadecimal, treat it
5589 // as an identity escape.
5590 return 'u';
5591 }
5592 default: {
5593 // Extended identity escape. We accept any character that hasn't
5594 // been matched by a more specific case, not just the subset required
5595 // by the ECMAScript specification.
5596 uc32 result = current();
5597 Advance();
5598 return result;
5599 }
5600 }
5601 return 0;
5602}
5603
5604
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005605CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) {
5606 ASSERT_EQ(0, *char_class);
5607 uc32 first = current();
5608 if (first == '\\') {
5609 switch (Next()) {
5610 case 'w': case 'W': case 'd': case 'D': case 's': case 'S': {
5611 *char_class = Next();
5612 Advance(2);
5613 return CharacterRange::Singleton(0); // Return dummy value.
5614 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005615 case kEndMarker:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005616 return ReportError(CStrVector("\\ at end of pattern"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005617 default:
5618 uc32 c = ParseClassCharacterEscape(CHECK_FAILED);
5619 return CharacterRange::Singleton(c);
5620 }
5621 } else {
5622 Advance();
5623 return CharacterRange::Singleton(first);
5624 }
5625}
5626
5627
lrn@chromium.org14a70352010-12-15 12:43:21 +00005628static const uc16 kNoCharClass = 0;
5629
5630// Adds range or pre-defined character class to character ranges.
5631// If char_class is not kInvalidClass, it's interpreted as a class
5632// escape (i.e., 's' means whitespace, from '\s').
5633static inline void AddRangeOrEscape(ZoneList<CharacterRange>* ranges,
5634 uc16 char_class,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005635 CharacterRange range,
5636 Zone* zone) {
lrn@chromium.org14a70352010-12-15 12:43:21 +00005637 if (char_class != kNoCharClass) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005638 CharacterRange::AddClassEscape(char_class, ranges, zone);
lrn@chromium.org14a70352010-12-15 12:43:21 +00005639 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005640 ranges->Add(range, zone);
lrn@chromium.org14a70352010-12-15 12:43:21 +00005641 }
5642}
5643
5644
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005645RegExpTree* RegExpParser::ParseCharacterClass() {
5646 static const char* kUnterminated = "Unterminated character class";
5647 static const char* kRangeOutOfOrder = "Range out of order in character class";
5648
5649 ASSERT_EQ(current(), '[');
5650 Advance();
5651 bool is_negated = false;
5652 if (current() == '^') {
5653 is_negated = true;
5654 Advance();
5655 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005656 ZoneList<CharacterRange>* ranges =
5657 new(zone()) ZoneList<CharacterRange>(2, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005658 while (has_more() && current() != ']') {
lrn@chromium.org14a70352010-12-15 12:43:21 +00005659 uc16 char_class = kNoCharClass;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005660 CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005661 if (current() == '-') {
5662 Advance();
5663 if (current() == kEndMarker) {
5664 // If we reach the end we break out of the loop and let the
5665 // following code report an error.
5666 break;
5667 } else if (current() == ']') {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005668 AddRangeOrEscape(ranges, char_class, first, zone());
5669 ranges->Add(CharacterRange::Singleton('-'), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005670 break;
5671 }
lrn@chromium.org14a70352010-12-15 12:43:21 +00005672 uc16 char_class_2 = kNoCharClass;
5673 CharacterRange next = ParseClassAtom(&char_class_2 CHECK_FAILED);
5674 if (char_class != kNoCharClass || char_class_2 != kNoCharClass) {
5675 // Either end is an escaped character class. Treat the '-' verbatim.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005676 AddRangeOrEscape(ranges, char_class, first, zone());
5677 ranges->Add(CharacterRange::Singleton('-'), zone());
5678 AddRangeOrEscape(ranges, char_class_2, next, zone());
lrn@chromium.org14a70352010-12-15 12:43:21 +00005679 continue;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005680 }
5681 if (first.from() > next.to()) {
5682 return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED);
5683 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005684 ranges->Add(CharacterRange::Range(first.from(), next.to()), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005685 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005686 AddRangeOrEscape(ranges, char_class, first, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005687 }
5688 }
5689 if (!has_more()) {
5690 return ReportError(CStrVector(kUnterminated) CHECK_FAILED);
5691 }
5692 Advance();
5693 if (ranges->length() == 0) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005694 ranges->Add(CharacterRange::Everything(), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005695 is_negated = !is_negated;
5696 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005697 return new(zone()) RegExpCharacterClass(ranges, is_negated);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005698}
5699
5700
5701// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005702// The Parser interface.
5703
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005704ParserMessage::~ParserMessage() {
5705 for (int i = 0; i < args().length(); i++)
5706 DeleteArray(args()[i]);
5707 DeleteArray(args().start());
5708}
5709
5710
5711ScriptDataImpl::~ScriptDataImpl() {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005712 if (owns_store_) store_.Dispose();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005713}
5714
5715
5716int ScriptDataImpl::Length() {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005717 return store_.length() * sizeof(unsigned);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005718}
5719
5720
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005721const char* ScriptDataImpl::Data() {
5722 return reinterpret_cast<const char*>(store_.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005723}
5724
5725
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005726bool ScriptDataImpl::HasError() {
5727 return has_error();
5728}
5729
5730
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005731void ScriptDataImpl::Initialize() {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00005732 // Prepares state for use.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005733 if (store_.length() >= PreparseDataConstants::kHeaderSize) {
5734 function_index_ = PreparseDataConstants::kHeaderSize;
5735 int symbol_data_offset = PreparseDataConstants::kHeaderSize
5736 + store_[PreparseDataConstants::kFunctionsSizeOffset];
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005737 if (store_.length() > symbol_data_offset) {
5738 symbol_data_ = reinterpret_cast<byte*>(&store_[symbol_data_offset]);
5739 } else {
5740 // Partial preparse causes no symbol information.
5741 symbol_data_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
5742 }
5743 symbol_data_end_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
5744 }
5745}
5746
5747
5748int ScriptDataImpl::ReadNumber(byte** source) {
5749 // Reads a number from symbol_data_ in base 128. The most significant
5750 // bit marks that there are more digits.
5751 // If the first byte is 0x80 (kNumberTerminator), it would normally
5752 // represent a leading zero. Since that is useless, and therefore won't
5753 // appear as the first digit of any actual value, it is used to
5754 // mark the end of the input stream.
5755 byte* data = *source;
5756 if (data >= symbol_data_end_) return -1;
5757 byte input = *data;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005758 if (input == PreparseDataConstants::kNumberTerminator) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005759 // End of stream marker.
5760 return -1;
5761 }
5762 int result = input & 0x7f;
5763 data++;
5764 while ((input & 0x80u) != 0) {
5765 if (data >= symbol_data_end_) return -1;
5766 input = *data;
5767 result = (result << 7) | (input & 0x7f);
5768 data++;
5769 }
5770 *source = data;
5771 return result;
5772}
5773
5774
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00005775// Create a Scanner for the preparser to use as input, and preparse the source.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00005776ScriptDataImpl* PreParserApi::PreParse(Isolate* isolate,
5777 Utf16CharacterStream* source) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005778 CompleteParserRecorder recorder;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005779 HistogramTimerScope timer(isolate->counters()->pre_parse());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005780 Scanner scanner(isolate->unicode_cache());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005781 intptr_t stack_limit = isolate->stack_guard()->real_climit();
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00005782 PreParser preparser(&scanner, &recorder, stack_limit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005783 preparser.set_allow_lazy(true);
5784 preparser.set_allow_generators(FLAG_harmony_generators);
danno@chromium.org1fd77d52013-06-07 16:01:45 +00005785 preparser.set_allow_for_of(FLAG_harmony_iteration);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005786 preparser.set_allow_harmony_scoping(FLAG_harmony_scoping);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005787 preparser.set_allow_harmony_numeric_literals(FLAG_harmony_numeric_literals);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005788 scanner.Initialize(source);
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00005789 PreParser::PreParseResult result = preparser.PreParseProgram();
5790 if (result == PreParser::kPreParseStackOverflow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005791 isolate->StackOverflow();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00005792 return NULL;
5793 }
5794
5795 // Extract the accumulated data from the recorder as a single
5796 // contiguous vector that we are responsible for disposing.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005797 Vector<unsigned> store = recorder.ExtractData();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00005798 return new ScriptDataImpl(store);
5799}
5800
5801
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00005802bool RegExpParser::ParseRegExp(FlatStringReader* input,
5803 bool multiline,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005804 RegExpCompileData* result,
5805 Zone* zone) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005806 ASSERT(result != NULL);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005807 RegExpParser parser(input, &result->error, multiline, zone);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005808 RegExpTree* tree = parser.ParsePattern();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005809 if (parser.failed()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005810 ASSERT(tree == NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005811 ASSERT(!result->error.is_null());
5812 } else {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005813 ASSERT(tree != NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005814 ASSERT(result->error.is_null());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005815 result->tree = tree;
5816 int capture_count = parser.captures_started();
5817 result->simple = tree->IsAtom() && parser.simple() && capture_count == 0;
iposva@chromium.org245aa852009-02-10 00:49:54 +00005818 result->contains_anchor = parser.contains_anchor();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005819 result->capture_count = capture_count;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005820 }
5821 return !parser.failed();
5822}
5823
5824
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005825bool Parser::Parse() {
5826 ASSERT(info()->function() == NULL);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005827 FunctionLiteral* result = NULL;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005828 if (info()->is_lazy()) {
5829 ASSERT(!info()->is_eval());
5830 if (info()->shared_info()->is_function()) {
5831 result = ParseLazy();
yangguo@chromium.org56454712012-02-16 15:33:53 +00005832 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005833 result = ParseProgram();
yangguo@chromium.org56454712012-02-16 15:33:53 +00005834 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005835 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005836 ScriptDataImpl* pre_parse_data = info()->pre_parse_data();
5837 set_pre_parse_data(pre_parse_data);
5838 if (pre_parse_data != NULL && pre_parse_data->has_error()) {
5839 Scanner::Location loc = pre_parse_data->MessageLocation();
5840 const char* message = pre_parse_data->BuildMessage();
5841 Vector<const char*> args = pre_parse_data->BuildArgs();
5842 ReportMessageAt(loc, message, args);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005843 DeleteArray(message);
5844 for (int i = 0; i < args.length(); i++) {
5845 DeleteArray(args[i]);
5846 }
5847 DeleteArray(args.start());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005848 ASSERT(info()->isolate()->has_pending_exception());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005849 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005850 result = ParseProgram();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005851 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005852 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005853 info()->SetFunction(result);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005854 return (result != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005855}
5856
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005857} } // namespace v8::internal