blob: 62b633ea2807f4edbfed4d6147196058f3745ec9 [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
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000205void RegExpBuilder::AddQuantifierToAtom(int min,
206 int max,
207 RegExpQuantifier::Type type) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000208 if (pending_empty_) {
209 pending_empty_ = false;
210 return;
211 }
212 RegExpTree* atom;
213 if (characters_ != NULL) {
214 ASSERT(last_added_ == ADD_CHAR);
215 // Last atom was character.
216 Vector<const uc16> char_vector = characters_->ToConstVector();
217 int num_chars = char_vector.length();
218 if (num_chars > 1) {
219 Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000220 text_.Add(new(zone()) RegExpAtom(prefix), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000221 char_vector = char_vector.SubVector(num_chars - 1, num_chars);
222 }
223 characters_ = NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000224 atom = new(zone()) RegExpAtom(char_vector);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000225 FlushText();
226 } else if (text_.length() > 0) {
227 ASSERT(last_added_ == ADD_ATOM);
228 atom = text_.RemoveLast();
229 FlushText();
230 } else if (terms_.length() > 0) {
231 ASSERT(last_added_ == ADD_ATOM);
232 atom = terms_.RemoveLast();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000233 if (atom->max_match() == 0) {
234 // Guaranteed to only match an empty string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000235 LAST(ADD_TERM);
236 if (min == 0) {
237 return;
238 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000239 terms_.Add(atom, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000240 return;
241 }
242 } else {
243 // Only call immediately after adding an atom or character!
244 UNREACHABLE();
245 return;
246 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000247 terms_.Add(new(zone()) RegExpQuantifier(min, max, 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374Scanner::Location ScriptDataImpl::MessageLocation() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000375 int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
376 int end_pos = Read(PreparseDataConstants::kMessageEndPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377 return Scanner::Location(beg_pos, end_pos);
378}
379
380
381const char* ScriptDataImpl::BuildMessage() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000382 unsigned* start = ReadAddress(PreparseDataConstants::kMessageTextPos);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000383 return ReadString(start, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384}
385
386
387Vector<const char*> ScriptDataImpl::BuildArgs() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000388 int arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389 const char** array = NewArray<const char*>(arg_count);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000390 // Position after text found by skipping past length field and
391 // length field content words.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000392 int pos = PreparseDataConstants::kMessageTextPos + 1
393 + Read(PreparseDataConstants::kMessageTextPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 for (int i = 0; i < arg_count; i++) {
395 int count = 0;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000396 array[i] = ReadString(ReadAddress(pos), &count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000397 pos += count + 1;
398 }
399 return Vector<const char*>(array, arg_count);
400}
401
402
403unsigned ScriptDataImpl::Read(int position) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000404 return store_[PreparseDataConstants::kHeaderSize + position];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405}
406
407
408unsigned* ScriptDataImpl::ReadAddress(int position) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000409 return &store_[PreparseDataConstants::kHeaderSize + position];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410}
411
412
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000413Scope* Parser::NewScope(Scope* parent, ScopeType type) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000414 Scope* result = new(zone()) Scope(parent, type, zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000415 result->Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416 return result;
417}
418
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000419
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420// ----------------------------------------------------------------------------
421// Target is a support class to facilitate manipulation of the
422// Parser's target_stack_ (the stack of potential 'break' and
423// 'continue' statement targets). Upon construction, a new target is
424// added; it is removed upon destruction.
425
426class Target BASE_EMBEDDED {
427 public:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000428 Target(Target** variable, AstNode* node)
429 : variable_(variable), node_(node), previous_(*variable) {
430 *variable = this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431 }
432
433 ~Target() {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000434 *variable_ = previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435 }
436
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000437 Target* previous() { return previous_; }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000438 AstNode* node() { return node_; }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000439
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440 private:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000441 Target** variable_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000442 AstNode* node_;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000443 Target* previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444};
445
446
447class TargetScope BASE_EMBEDDED {
448 public:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000449 explicit TargetScope(Target** variable)
450 : variable_(variable), previous_(*variable) {
451 *variable = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000452 }
453
454 ~TargetScope() {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000455 *variable_ = previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456 }
457
458 private:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000459 Target** variable_;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000460 Target* previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461};
462
463
464// ----------------------------------------------------------------------------
danno@chromium.orgc612e022011-11-10 11:38:15 +0000465// FunctionState and BlockState together implement the parser's scope stack.
466// The parser's current scope is in top_scope_. The BlockState and
467// FunctionState constructors push on the scope stack and the destructors
468// pop. They are also used to hold the parser's per-function and per-block
469// state.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000470
danno@chromium.orgc612e022011-11-10 11:38:15 +0000471class Parser::BlockState BASE_EMBEDDED {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000472 public:
danno@chromium.orgc612e022011-11-10 11:38:15 +0000473 BlockState(Parser* parser, Scope* scope)
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000474 : parser_(parser),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000475 outer_scope_(parser->top_scope_) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000476 parser->top_scope_ = scope;
477 }
478
danno@chromium.orgc612e022011-11-10 11:38:15 +0000479 ~BlockState() { parser_->top_scope_ = outer_scope_; }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480
481 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000482 Parser* parser_;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000483 Scope* outer_scope_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000484};
485
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486
danno@chromium.orgc612e022011-11-10 11:38:15 +0000487Parser::FunctionState::FunctionState(Parser* parser,
488 Scope* scope,
489 Isolate* isolate)
490 : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000491 next_handler_index_(0),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000492 expected_property_count_(0),
493 only_simple_this_property_assignments_(false),
494 this_property_assignments_(isolate->factory()->empty_fixed_array()),
495 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
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000538Parser::Parser(CompilationInfo* info,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000539 int parser_flags,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 v8::Extension* extension,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000541 ScriptDataImpl* pre_data)
542 : isolate_(info->isolate()),
543 symbol_cache_(pre_data ? pre_data->symbol_count() : 0, info->zone()),
544 script_(info->script()),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000545 scanner_(isolate_->unicode_cache()),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000546 reusable_preparser_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547 top_scope_(NULL),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000548 current_function_state_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 target_stack_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550 extension_(extension),
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000551 pre_data_(pre_data),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000552 fni_(NULL),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000553 allow_natives_syntax_((parser_flags & kAllowNativesSyntax) != 0),
554 allow_lazy_((parser_flags & kAllowLazy) != 0),
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000555 allow_modules_((parser_flags & kAllowModules) != 0),
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000556 stack_overflow_(false),
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000557 parenthesized_function_(false),
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000558 zone_(info->zone()),
559 info_(info) {
560 ASSERT(!script_.is_null());
yangguo@chromium.org56454712012-02-16 15:33:53 +0000561 isolate_->set_ast_node_id(0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000562 if ((parser_flags & kLanguageModeMask) == EXTENDED_MODE) {
563 scanner().SetHarmonyScoping(true);
564 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000565 if ((parser_flags & kAllowModules) != 0) {
566 scanner().SetHarmonyModules(true);
567 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568}
569
570
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000571FunctionLiteral* Parser::ParseProgram() {
572 ZoneScope zone_scope(zone(), DONT_DELETE_ON_EXIT);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000573 HistogramTimerScope timer(isolate()->counters()->parse());
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000574 Handle<String> source(String::cast(script_->source()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000575 isolate()->counters()->total_parse_size()->Increment(source->length());
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000576 int64_t start = FLAG_trace_parse ? OS::Ticks() : 0;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000577 fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000578
579 // Initialize parser state.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000580 source->TryFlatten();
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000581 FunctionLiteral* result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000582 if (source->IsExternalTwoByteString()) {
583 // Notice that the stream is destroyed at the end of the branch block.
584 // The last line of the blocks can't be moved outside, even though they're
585 // identical calls.
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000586 ExternalTwoByteStringUtf16CharacterStream stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000587 Handle<ExternalTwoByteString>::cast(source), 0, source->length());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000588 scanner_.Initialize(&stream);
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000589 result = DoParseProgram(info(), source, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000590 } else {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000591 GenericStringUtf16CharacterStream stream(source, 0, source->length());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000592 scanner_.Initialize(&stream);
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000593 result = DoParseProgram(info(), source, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000594 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000595
596 if (FLAG_trace_parse && result != NULL) {
597 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
598 if (info()->is_eval()) {
599 PrintF("[parsing eval");
600 } else if (info()->script()->name()->IsString()) {
601 String* name = String::cast(info()->script()->name());
602 SmartArrayPointer<char> name_chars = name->ToCString();
603 PrintF("[parsing script: %s", *name_chars);
604 } else {
605 PrintF("[parsing script");
606 }
607 PrintF(" - took %0.3f ms]\n", ms);
608 }
609 return result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000610}
611
612
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000613FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
614 Handle<String> source,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000615 ZoneScope* zone_scope) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000616 ASSERT(top_scope_ == NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617 ASSERT(target_stack_ == NULL);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000618 if (pre_data_ != NULL) pre_data_->Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000620 Handle<String> no_name = isolate()->factory()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000621
622 FunctionLiteral* result = NULL;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000623 { Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
624 info->SetGlobalScope(scope);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000625 if (!info->context().is_null()) {
626 scope = Scope::DeserializeScopeChain(*info->context(), scope, zone());
627 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000628 if (info->is_eval()) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000629 if (!scope->is_global_scope() || info->language_mode() != CLASSIC_MODE) {
630 scope = NewScope(scope, EVAL_SCOPE);
631 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000632 } else if (info->is_global()) {
633 scope = NewScope(scope, GLOBAL_SCOPE);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000634 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000635 scope->set_start_position(0);
636 scope->set_end_position(source->length());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000637
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000638 // Compute the parsing mode.
639 Mode mode = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY;
640 if (allow_natives_syntax_ || extension_ != NULL || scope->is_eval_scope()) {
641 mode = PARSE_EAGERLY;
642 }
643 ParsingModeScope parsing_mode(this, mode);
644
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000645 FunctionState function_state(this, scope, isolate()); // Enters 'scope'.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000646 top_scope_->SetLanguageMode(info->language_mode());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000647 ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648 bool ok = true;
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000649 int beg_loc = scanner().location().beg_pos;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000650 ParseSourceElements(body, Token::EOS, info->is_eval(), true, &ok);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000651 if (ok && !top_scope_->is_classic_mode()) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000652 CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok);
653 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000654
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000655 if (ok && is_extended_mode()) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000656 CheckConflictingVarDeclarations(top_scope_, &ok);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000657 }
658
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000659 if (ok) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000660 result = factory()->NewFunctionLiteral(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000661 no_name,
662 top_scope_,
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000663 body,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000664 function_state.materialized_literal_count(),
665 function_state.expected_property_count(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000666 function_state.handler_count(),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000667 function_state.only_simple_this_property_assignments(),
668 function_state.this_property_assignments(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000669 0,
yangguo@chromium.org56454712012-02-16 15:33:53 +0000670 FunctionLiteral::kNoDuplicateParameters,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000671 FunctionLiteral::ANONYMOUS_EXPRESSION,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000672 FunctionLiteral::kGlobalOrEval,
673 FunctionLiteral::kNotParenthesized);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000674 result->set_ast_properties(factory()->visitor()->ast_properties());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000675 } else if (stack_overflow_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000676 isolate()->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000677 }
678 }
679
680 // Make sure the target stack is empty.
681 ASSERT(target_stack_ == NULL);
682
683 // If there was a syntax error we have to get rid of the AST
684 // and it is not safe to do so before the scope has been deleted.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000685 if (result == NULL) zone_scope->DeleteOnExit();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686 return result;
687}
688
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000689
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000690FunctionLiteral* Parser::ParseLazy() {
691 ZoneScope zone_scope(zone(), DONT_DELETE_ON_EXIT);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000692 HistogramTimerScope timer(isolate()->counters()->parse_lazy());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000693 Handle<String> source(String::cast(script_->source()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000694 isolate()->counters()->total_parse_size()->Increment(source->length());
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000695 int64_t start = FLAG_trace_parse ? OS::Ticks() : 0;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000696 Handle<SharedFunctionInfo> shared_info = info()->shared_info();
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000697
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000698 // Initialize parser state.
699 source->TryFlatten();
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000700 FunctionLiteral* result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000701 if (source->IsExternalTwoByteString()) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000702 ExternalTwoByteStringUtf16CharacterStream stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000703 Handle<ExternalTwoByteString>::cast(source),
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000704 shared_info->start_position(),
705 shared_info->end_position());
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000706 result = ParseLazy(&stream, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000707 } else {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000708 GenericStringUtf16CharacterStream stream(source,
709 shared_info->start_position(),
710 shared_info->end_position());
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000711 result = ParseLazy(&stream, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000712 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000713
714 if (FLAG_trace_parse && result != NULL) {
715 double ms = static_cast<double>(OS::Ticks() - start) / 1000;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +0000716 SmartArrayPointer<char> name_chars = result->debug_name()->ToCString();
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000717 PrintF("[parsing function: %s - took %0.3f ms]\n", *name_chars, ms);
718 }
719 return result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000720}
721
722
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000723FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000724 ZoneScope* zone_scope) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000725 Handle<SharedFunctionInfo> shared_info = info()->shared_info();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000726 scanner_.Initialize(source);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000727 ASSERT(top_scope_ == NULL);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000728 ASSERT(target_stack_ == NULL);
729
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000730 Handle<String> name(String::cast(shared_info->name()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000731 fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000732 fni_->PushEnclosingName(name);
733
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000734 ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735
736 // Place holder for the result.
737 FunctionLiteral* result = NULL;
738
739 {
740 // Parse the function literal.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000741 Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000742 info()->SetGlobalScope(scope);
743 if (!info()->closure().is_null()) {
744 scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000745 zone());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000746 }
danno@chromium.orgc612e022011-11-10 11:38:15 +0000747 FunctionState function_state(this, scope, isolate());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000748 ASSERT(scope->language_mode() != STRICT_MODE || !info()->is_classic_mode());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000749 ASSERT(scope->language_mode() != EXTENDED_MODE ||
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000750 info()->is_extended_mode());
751 ASSERT(info()->language_mode() == shared_info->language_mode());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000752 scope->SetLanguageMode(shared_info->language_mode());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000753 FunctionLiteral::Type type = shared_info->is_expression()
754 ? (shared_info->is_anonymous()
755 ? FunctionLiteral::ANONYMOUS_EXPRESSION
756 : FunctionLiteral::NAMED_EXPRESSION)
757 : FunctionLiteral::DECLARATION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000758 bool ok = true;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000759 result = ParseFunctionLiteral(name,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000760 false, // Strict mode name already checked.
761 RelocInfo::kNoPosition,
762 type,
763 &ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764 // Make sure the results agree.
765 ASSERT(ok == (result != NULL));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000766 }
767
768 // Make sure the target stack is empty.
769 ASSERT(target_stack_ == NULL);
770
771 // If there was a stack overflow we have to get rid of AST and it is
772 // not safe to do before scope has been deleted.
773 if (result == NULL) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000774 zone_scope->DeleteOnExit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000775 if (stack_overflow_) isolate()->StackOverflow();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000776 } else {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000777 Handle<String> inferred_name(shared_info->inferred_name());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000778 result->set_inferred_name(inferred_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000779 }
780 return result;
781}
782
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000783
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000784Handle<String> Parser::GetSymbol(bool* ok) {
785 int symbol_id = -1;
786 if (pre_data() != NULL) {
787 symbol_id = pre_data()->GetSymbolIdentifier();
788 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000789 return LookupSymbol(symbol_id);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000790}
791
792
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793void Parser::ReportMessage(const char* type, Vector<const char*> args) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000794 Scanner::Location source_location = scanner().location();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795 ReportMessageAt(source_location, type, args);
796}
797
798
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000799void Parser::ReportMessage(const char* type, Vector<Handle<String> > args) {
800 Scanner::Location source_location = scanner().location();
801 ReportMessageAt(source_location, type, args);
802}
803
804
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000805void Parser::ReportMessageAt(Scanner::Location source_location,
806 const char* type,
807 Vector<const char*> args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808 MessageLocation location(script_,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000809 source_location.beg_pos,
810 source_location.end_pos);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000811 Factory* factory = isolate()->factory();
812 Handle<FixedArray> elements = factory->NewFixedArray(args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813 for (int i = 0; i < args.length(); i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000814 Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000815 elements->set(i, *arg_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000816 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000817 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
818 Handle<Object> result = factory->NewSyntaxError(type, array);
819 isolate()->Throw(*result, &location);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000820}
821
822
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000823void Parser::ReportMessageAt(Scanner::Location source_location,
824 const char* type,
825 Vector<Handle<String> > args) {
826 MessageLocation location(script_,
827 source_location.beg_pos,
828 source_location.end_pos);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000829 Factory* factory = isolate()->factory();
830 Handle<FixedArray> elements = factory->NewFixedArray(args.length());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000831 for (int i = 0; i < args.length(); i++) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000832 elements->set(i, *args[i]);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000833 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000834 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
835 Handle<Object> result = factory->NewSyntaxError(type, array);
836 isolate()->Throw(*result, &location);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000837}
838
839
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000840// A ThisNamedPropertyAssignmentFinder finds and marks statements of the form
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000841// this.x = ...;, where x is a named property. It also determines whether a
842// function contains only assignments of this type.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000843class ThisNamedPropertyAssignmentFinder {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000844 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000845 ThisNamedPropertyAssignmentFinder(Isolate* isolate, Zone* zone)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000846 : isolate_(isolate),
847 only_simple_this_property_assignments_(true),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000848 names_(0, zone),
849 assigned_arguments_(0, zone),
850 assigned_constants_(0, zone),
851 zone_(zone) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000852 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000853
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000854 static Assignment* AsAssignment(Statement* stat) {
855 if (stat == NULL) return NULL;
856 ExpressionStatement* exp_stat = stat->AsExpressionStatement();
857 if (exp_stat == NULL) return NULL;
858 return exp_stat->expression()->AsAssignment();
859 }
860
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000861 void Update(Scope* scope, Statement* stat) {
ager@chromium.orgb9a15452009-11-11 09:55:05 +0000862 // Bail out if function already has property assignment that are
863 // not simple this property assignments.
864 if (!only_simple_this_property_assignments_) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000865 return;
866 }
867
868 // Check whether this statement is of the form this.x = ...;
869 Assignment* assignment = AsAssignment(stat);
870 if (IsThisPropertyAssignment(assignment)) {
871 HandleThisPropertyAssignment(scope, assignment);
872 } else {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000873 only_simple_this_property_assignments_ = false;
874 }
875 }
876
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000877 // Returns whether only statements of the form this.x = y; where y is either a
878 // constant or a function argument was encountered.
879 bool only_simple_this_property_assignments() {
880 return only_simple_this_property_assignments_;
881 }
882
883 // Returns a fixed array containing three elements for each assignment of the
884 // form this.x = y;
885 Handle<FixedArray> GetThisPropertyAssignments() {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000886 if (names_.is_empty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000887 return isolate_->factory()->empty_fixed_array();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000888 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000889 ASSERT_EQ(names_.length(), assigned_arguments_.length());
890 ASSERT_EQ(names_.length(), assigned_constants_.length());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000891 Handle<FixedArray> assignments =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000892 isolate_->factory()->NewFixedArray(names_.length() * 3);
893 for (int i = 0; i < names_.length(); ++i) {
894 assignments->set(i * 3, *names_[i]);
895 assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_[i]));
896 assignments->set(i * 3 + 2, *assigned_constants_[i]);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000897 }
898 return assignments;
899 }
900
901 private:
902 bool IsThisPropertyAssignment(Assignment* assignment) {
903 if (assignment != NULL) {
904 Property* property = assignment->target()->AsProperty();
905 return assignment->op() == Token::ASSIGN
906 && property != NULL
907 && property->obj()->AsVariableProxy() != NULL
908 && property->obj()->AsVariableProxy()->is_this();
909 }
910 return false;
911 }
912
913 void HandleThisPropertyAssignment(Scope* scope, Assignment* assignment) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000914 // Check that the property assigned to is a named property, which is not
915 // __proto__.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000916 Property* property = assignment->target()->AsProperty();
917 ASSERT(property != NULL);
918 Literal* literal = property->key()->AsLiteral();
919 uint32_t dummy;
920 if (literal != NULL &&
921 literal->handle()->IsString() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000922 !String::cast(*(literal->handle()))->Equals(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000923 isolate_->heap()->proto_string()) &&
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000924 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
925 Handle<String> key = Handle<String>::cast(literal->handle());
926
927 // Check whether the value assigned is either a constant or matches the
928 // name of one of the arguments to the function.
929 if (assignment->value()->AsLiteral() != NULL) {
930 // Constant assigned.
931 Literal* literal = assignment->value()->AsLiteral();
932 AssignmentFromConstant(key, literal->handle());
ager@chromium.orgb9a15452009-11-11 09:55:05 +0000933 return;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000934 } else if (assignment->value()->AsVariableProxy() != NULL) {
935 // Variable assigned.
936 Handle<String> name =
937 assignment->value()->AsVariableProxy()->name();
938 // Check whether the variable assigned matches an argument name.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000939 for (int i = 0; i < scope->num_parameters(); i++) {
940 if (*scope->parameter(i)->name() == *name) {
941 // Assigned from function argument.
ager@chromium.orgb9a15452009-11-11 09:55:05 +0000942 AssignmentFromParameter(key, i);
943 return;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000944 }
945 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000946 }
947 }
ager@chromium.orgb9a15452009-11-11 09:55:05 +0000948 // It is not a simple "this.x = value;" assignment with a constant
949 // or parameter value.
950 AssignmentFromSomethingElse();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000951 }
952
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000953
954
955
956 // We will potentially reorder the property assignments, so they must be
957 // simple enough that the ordering does not matter.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000958 void AssignmentFromParameter(Handle<String> name, int index) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000959 EnsureInitialized();
960 for (int i = 0; i < names_.length(); ++i) {
961 if (name->Equals(*names_[i])) {
962 assigned_arguments_[i] = index;
963 assigned_constants_[i] = isolate_->factory()->undefined_value();
964 return;
965 }
966 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000967 names_.Add(name, zone());
968 assigned_arguments_.Add(index, zone());
969 assigned_constants_.Add(isolate_->factory()->undefined_value(), zone());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000970 }
971
972 void AssignmentFromConstant(Handle<String> name, Handle<Object> value) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000973 EnsureInitialized();
974 for (int i = 0; i < names_.length(); ++i) {
975 if (name->Equals(*names_[i])) {
976 assigned_arguments_[i] = -1;
977 assigned_constants_[i] = value;
978 return;
979 }
980 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000981 names_.Add(name, zone());
982 assigned_arguments_.Add(-1, zone());
983 assigned_constants_.Add(value, zone());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000984 }
985
ager@chromium.orgb9a15452009-11-11 09:55:05 +0000986 void AssignmentFromSomethingElse() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000987 // The this assignment is not a simple one.
988 only_simple_this_property_assignments_ = false;
989 }
990
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000991 void EnsureInitialized() {
992 if (names_.capacity() == 0) {
993 ASSERT(assigned_arguments_.capacity() == 0);
994 ASSERT(assigned_constants_.capacity() == 0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000995 names_.Initialize(4, zone());
996 assigned_arguments_.Initialize(4, zone());
997 assigned_constants_.Initialize(4, zone());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000998 }
999 }
1000
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001001 Zone* zone() const { return zone_; }
1002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 Isolate* isolate_;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001004 bool only_simple_this_property_assignments_;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001005 ZoneStringList names_;
1006 ZoneList<int> assigned_arguments_;
1007 ZoneObjectList assigned_constants_;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001008 Zone* zone_;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001009};
1010
1011
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001012void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013 int end_token,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001014 bool is_eval,
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001015 bool is_global,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001016 bool* ok) {
1017 // SourceElements ::
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001018 // (ModuleElement)* <end_token>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019
1020 // Allocate a target stack to use for this set of source
1021 // elements. This way, all scripts and functions get their own
1022 // target stack thus avoiding illegal breaks and continues across
1023 // functions.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001024 TargetScope scope(&this->target_stack_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025
1026 ASSERT(processor != NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001027 ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate(),
1028 zone());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001029 bool directive_prologue = true; // Parsing directive prologue.
1030
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001031 while (peek() != end_token) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001032 if (directive_prologue && peek() != Token::STRING) {
1033 directive_prologue = false;
1034 }
1035
1036 Scanner::Location token_loc = scanner().peek_location();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001037 Statement* stat;
1038 if (is_global && !is_eval) {
1039 stat = ParseModuleElement(NULL, CHECK_OK);
1040 } else {
1041 stat = ParseBlockElement(NULL, CHECK_OK);
1042 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001043 if (stat == NULL || stat->IsEmpty()) {
1044 directive_prologue = false; // End of directive prologue.
1045 continue;
1046 }
1047
1048 if (directive_prologue) {
1049 // A shot at a directive.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001050 ExpressionStatement* e_stat;
1051 Literal* literal;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001052 // Still processing directive prologue?
1053 if ((e_stat = stat->AsExpressionStatement()) != NULL &&
1054 (literal = e_stat->expression()->AsLiteral()) != NULL &&
1055 literal->handle()->IsString()) {
1056 Handle<String> directive = Handle<String>::cast(literal->handle());
1057
1058 // Check "use strict" directive (ES5 14.1).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001059 if (top_scope_->is_classic_mode() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001060 directive->Equals(isolate()->heap()->use_strict_string()) &&
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001061 token_loc.end_pos - token_loc.beg_pos ==
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001062 isolate()->heap()->use_strict_string()->length() + 2) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001063 // TODO(mstarzinger): Global strict eval calls, need their own scope
1064 // as specified in ES5 10.4.2(3). The correct fix would be to always
1065 // add this scope in DoParseProgram(), but that requires adaptations
1066 // all over the code base, so we go with a quick-fix for now.
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001067 // In the same manner, we have to patch the parsing mode.
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001068 if (is_eval && !top_scope_->is_eval_scope()) {
1069 ASSERT(top_scope_->is_global_scope());
1070 Scope* scope = NewScope(top_scope_, EVAL_SCOPE);
1071 scope->set_start_position(top_scope_->start_position());
1072 scope->set_end_position(top_scope_->end_position());
1073 top_scope_ = scope;
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001074 mode_ = PARSE_EAGERLY;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001075 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001076 // TODO(ES6): Fix entering extended mode, once it is specified.
1077 top_scope_->SetLanguageMode(FLAG_harmony_scoping
1078 ? EXTENDED_MODE : STRICT_MODE);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001079 // "use strict" is the only directive for now.
1080 directive_prologue = false;
1081 }
1082 } else {
1083 // End of the directive prologue.
1084 directive_prologue = false;
1085 }
1086 }
1087
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001088 // Find and mark all assignments to named properties in this (this.x =)
1089 if (top_scope_->is_function_scope()) {
1090 this_property_assignment_finder.Update(top_scope_, stat);
1091 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001092 processor->Add(stat, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001094
1095 // Propagate the collected information on this property assignments.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001096 if (top_scope_->is_function_scope()) {
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001097 bool only_simple_this_property_assignments =
ager@chromium.org5c838252010-02-19 08:53:10 +00001098 this_property_assignment_finder.only_simple_this_property_assignments()
1099 && top_scope_->declarations()->length() == 0;
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001100 if (only_simple_this_property_assignments) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001101 current_function_state_->SetThisPropertyAssignmentInfo(
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001102 only_simple_this_property_assignments,
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001103 this_property_assignment_finder.GetThisPropertyAssignments());
1104 }
1105 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107 return 0;
1108}
1109
1110
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001111Statement* Parser::ParseModuleElement(ZoneStringList* labels,
1112 bool* ok) {
1113 // (Ecma 262 5th Edition, clause 14):
1114 // SourceElement:
1115 // Statement
1116 // FunctionDeclaration
1117 //
1118 // In harmony mode we allow additionally the following productions
1119 // ModuleElement:
1120 // LetDeclaration
1121 // ConstDeclaration
1122 // ModuleDeclaration
1123 // ImportDeclaration
1124 // ExportDeclaration
1125
1126 switch (peek()) {
1127 case Token::FUNCTION:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001128 return ParseFunctionDeclaration(NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001129 case Token::LET:
1130 case Token::CONST:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001131 return ParseVariableStatement(kModuleElement, NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001132 case Token::IMPORT:
1133 return ParseImportDeclaration(ok);
1134 case Token::EXPORT:
1135 return ParseExportDeclaration(ok);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00001136 default: {
1137 Statement* stmt = ParseStatement(labels, CHECK_OK);
1138 // Handle 'module' as a context-sensitive keyword.
1139 if (FLAG_harmony_modules &&
1140 peek() == Token::IDENTIFIER &&
1141 !scanner().HasAnyLineTerminatorBeforeNext() &&
1142 stmt != NULL) {
1143 ExpressionStatement* estmt = stmt->AsExpressionStatement();
1144 if (estmt != NULL &&
1145 estmt->expression()->AsVariableProxy() != NULL &&
1146 estmt->expression()->AsVariableProxy()->name()->Equals(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001147 isolate()->heap()->module_string()) &&
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00001148 !scanner().literal_contains_escapes()) {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001149 return ParseModuleDeclaration(NULL, ok);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00001150 }
1151 }
1152 return stmt;
1153 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001154 }
1155}
1156
1157
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001158Statement* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001159 // ModuleDeclaration:
1160 // 'module' Identifier Module
1161
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001162 Handle<String> name = ParseIdentifier(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001163
1164#ifdef DEBUG
1165 if (FLAG_print_interface_details)
1166 PrintF("# Module %s...\n", name->ToAsciiArray());
1167#endif
1168
ulan@chromium.org812308e2012-02-29 15:58:45 +00001169 Module* module = ParseModule(CHECK_OK);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001170 VariableProxy* proxy = NewUnresolved(name, MODULE, module->interface());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001171 Declaration* declaration =
1172 factory()->NewModuleDeclaration(proxy, module, top_scope_);
1173 Declare(declaration, true, CHECK_OK);
1174
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001175#ifdef DEBUG
1176 if (FLAG_print_interface_details)
1177 PrintF("# Module %s.\n", name->ToAsciiArray());
1178
1179 if (FLAG_print_interfaces) {
1180 PrintF("module %s : ", name->ToAsciiArray());
1181 module->interface()->Print();
1182 }
1183#endif
1184
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001185 if (names) names->Add(name, zone());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001186 if (module->body() == NULL)
1187 return factory()->NewEmptyStatement();
1188 else
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001189 return factory()->NewModuleStatement(proxy, module->body());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001190}
1191
1192
1193Module* Parser::ParseModule(bool* ok) {
1194 // Module:
1195 // '{' ModuleElement '}'
ulan@chromium.org812308e2012-02-29 15:58:45 +00001196 // '=' ModulePath ';'
1197 // 'at' String ';'
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001198
1199 switch (peek()) {
1200 case Token::LBRACE:
1201 return ParseModuleLiteral(ok);
1202
ulan@chromium.org812308e2012-02-29 15:58:45 +00001203 case Token::ASSIGN: {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001204 Expect(Token::ASSIGN, CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001205 Module* result = ParseModulePath(CHECK_OK);
1206 ExpectSemicolon(CHECK_OK);
1207 return result;
1208 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001209
ulan@chromium.org812308e2012-02-29 15:58:45 +00001210 default: {
1211 ExpectContextualKeyword("at", CHECK_OK);
1212 Module* result = ParseModuleUrl(CHECK_OK);
1213 ExpectSemicolon(CHECK_OK);
1214 return result;
1215 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001216 }
1217}
1218
1219
1220Module* Parser::ParseModuleLiteral(bool* ok) {
1221 // Module:
1222 // '{' ModuleElement '}'
1223
1224 // Construct block expecting 16 statements.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001225 Block* body = factory()->NewBlock(NULL, 16, false);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001226#ifdef DEBUG
1227 if (FLAG_print_interface_details) PrintF("# Literal ");
1228#endif
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001229 Scope* scope = NewScope(top_scope_, MODULE_SCOPE);
1230
1231 Expect(Token::LBRACE, CHECK_OK);
1232 scope->set_start_position(scanner().location().beg_pos);
1233 scope->SetLanguageMode(EXTENDED_MODE);
1234
1235 {
1236 BlockState block_state(this, scope);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001237 TargetCollector collector(zone());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001238 Target target(&this->target_stack_, &collector);
1239 Target target_body(&this->target_stack_, body);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001240
1241 while (peek() != Token::RBRACE) {
1242 Statement* stat = ParseModuleElement(NULL, CHECK_OK);
1243 if (stat && !stat->IsEmpty()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001244 body->AddStatement(stat, zone());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001245 }
1246 }
1247 }
1248
1249 Expect(Token::RBRACE, CHECK_OK);
1250 scope->set_end_position(scanner().location().end_pos);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001251 body->set_scope(scope);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001252
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001253 // Check that all exports are bound.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001254 Interface* interface = scope->interface();
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001255 for (Interface::Iterator it = interface->iterator();
1256 !it.done(); it.Advance()) {
1257 if (scope->LocalLookup(it.name()) == NULL) {
1258 Handle<String> name(it.name());
1259 ReportMessage("module_export_undefined",
1260 Vector<Handle<String> >(&name, 1));
1261 *ok = false;
1262 return NULL;
1263 }
1264 }
1265
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001266 interface->MakeModule(ok);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001267 ASSERT(*ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001268 interface->Freeze(ok);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001269 ASSERT(*ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001270 return factory()->NewModuleLiteral(body, interface);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001271}
1272
1273
1274Module* Parser::ParseModulePath(bool* ok) {
1275 // ModulePath:
1276 // Identifier
1277 // ModulePath '.' Identifier
1278
1279 Module* result = ParseModuleVariable(CHECK_OK);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001280 while (Check(Token::PERIOD)) {
1281 Handle<String> name = ParseIdentifierName(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001282#ifdef DEBUG
1283 if (FLAG_print_interface_details)
1284 PrintF("# Path .%s ", name->ToAsciiArray());
1285#endif
1286 Module* member = factory()->NewModulePath(result, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001287 result->interface()->Add(name, member->interface(), zone(), ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001288 if (!*ok) {
1289#ifdef DEBUG
1290 if (FLAG_print_interfaces) {
1291 PrintF("PATH TYPE ERROR at '%s'\n", name->ToAsciiArray());
1292 PrintF("result: ");
1293 result->interface()->Print();
1294 PrintF("member: ");
1295 member->interface()->Print();
1296 }
1297#endif
1298 ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
1299 return NULL;
1300 }
1301 result = member;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001302 }
1303
1304 return result;
1305}
1306
1307
1308Module* Parser::ParseModuleVariable(bool* ok) {
1309 // ModulePath:
1310 // Identifier
1311
1312 Handle<String> name = ParseIdentifier(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001313#ifdef DEBUG
1314 if (FLAG_print_interface_details)
1315 PrintF("# Module variable %s ", name->ToAsciiArray());
1316#endif
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001317 VariableProxy* proxy = top_scope_->NewUnresolved(
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001318 factory(), name, Interface::NewModule(zone()),
1319 scanner().location().beg_pos);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001320
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001321 return factory()->NewModuleVariable(proxy);
1322}
1323
1324
1325Module* Parser::ParseModuleUrl(bool* ok) {
1326 // Module:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001327 // String
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001328
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001329 Expect(Token::STRING, CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001330 Handle<String> symbol = GetSymbol(CHECK_OK);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001331
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001332 // TODO(ES6): Request JS resource from environment...
1333
1334#ifdef DEBUG
1335 if (FLAG_print_interface_details) PrintF("# Url ");
1336#endif
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001337
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001338 // Create an empty literal as long as the feature isn't finished.
1339 USE(symbol);
1340 Scope* scope = NewScope(top_scope_, MODULE_SCOPE);
1341 Block* body = factory()->NewBlock(NULL, 1, false);
1342 body->set_scope(scope);
1343 Interface* interface = scope->interface();
1344 Module* result = factory()->NewModuleLiteral(body, interface);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001345 interface->Freeze(ok);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001346 ASSERT(*ok);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001347 interface->Unify(scope->interface(), zone(), ok);
1348 ASSERT(*ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001349 return result;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001350}
1351
1352
ulan@chromium.org812308e2012-02-29 15:58:45 +00001353Module* Parser::ParseModuleSpecifier(bool* ok) {
1354 // ModuleSpecifier:
1355 // String
1356 // ModulePath
1357
1358 if (peek() == Token::STRING) {
1359 return ParseModuleUrl(ok);
1360 } else {
1361 return ParseModulePath(ok);
1362 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001363}
1364
1365
ulan@chromium.org812308e2012-02-29 15:58:45 +00001366Block* Parser::ParseImportDeclaration(bool* ok) {
1367 // ImportDeclaration:
1368 // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleSpecifier ';'
1369 //
1370 // TODO(ES6): implement destructuring ImportSpecifiers
1371
1372 Expect(Token::IMPORT, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001373 ZoneStringList names(1, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001374
1375 Handle<String> name = ParseIdentifierName(CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001376 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001377 while (peek() == Token::COMMA) {
1378 Consume(Token::COMMA);
1379 name = ParseIdentifierName(CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001380 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001381 }
1382
1383 ExpectContextualKeyword("from", CHECK_OK);
1384 Module* module = ParseModuleSpecifier(CHECK_OK);
1385 ExpectSemicolon(CHECK_OK);
1386
1387 // Generate a separate declaration for each identifier.
1388 // TODO(ES6): once we implement destructuring, make that one declaration.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001389 Block* block = factory()->NewBlock(NULL, 1, true);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001390 for (int i = 0; i < names.length(); ++i) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001391#ifdef DEBUG
1392 if (FLAG_print_interface_details)
1393 PrintF("# Import %s ", names[i]->ToAsciiArray());
1394#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001395 Interface* interface = Interface::NewUnknown(zone());
1396 module->interface()->Add(names[i], interface, zone(), ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001397 if (!*ok) {
1398#ifdef DEBUG
1399 if (FLAG_print_interfaces) {
1400 PrintF("IMPORT TYPE ERROR at '%s'\n", names[i]->ToAsciiArray());
1401 PrintF("module: ");
1402 module->interface()->Print();
1403 }
1404#endif
1405 ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
1406 return NULL;
1407 }
1408 VariableProxy* proxy = NewUnresolved(names[i], LET, interface);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001409 Declaration* declaration =
1410 factory()->NewImportDeclaration(proxy, module, top_scope_);
1411 Declare(declaration, true, CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001412 }
1413
ulan@chromium.org812308e2012-02-29 15:58:45 +00001414 return block;
1415}
1416
1417
1418Statement* Parser::ParseExportDeclaration(bool* ok) {
1419 // ExportDeclaration:
1420 // 'export' Identifier (',' Identifier)* ';'
1421 // 'export' VariableDeclaration
1422 // 'export' FunctionDeclaration
1423 // 'export' ModuleDeclaration
1424 //
1425 // TODO(ES6): implement structuring ExportSpecifiers
1426
1427 Expect(Token::EXPORT, CHECK_OK);
1428
1429 Statement* result = NULL;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001430 ZoneStringList names(1, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001431 switch (peek()) {
1432 case Token::IDENTIFIER: {
1433 Handle<String> name = ParseIdentifier(CHECK_OK);
1434 // Handle 'module' as a context-sensitive keyword.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001435 if (!name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("module"))) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001436 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001437 while (peek() == Token::COMMA) {
1438 Consume(Token::COMMA);
1439 name = ParseIdentifier(CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001440 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001441 }
1442 ExpectSemicolon(CHECK_OK);
1443 result = factory()->NewEmptyStatement();
1444 } else {
1445 result = ParseModuleDeclaration(&names, CHECK_OK);
1446 }
1447 break;
1448 }
1449
1450 case Token::FUNCTION:
1451 result = ParseFunctionDeclaration(&names, CHECK_OK);
1452 break;
1453
1454 case Token::VAR:
1455 case Token::LET:
1456 case Token::CONST:
1457 result = ParseVariableStatement(kModuleElement, &names, CHECK_OK);
1458 break;
1459
1460 default:
1461 *ok = false;
1462 ReportUnexpectedToken(scanner().current_token());
1463 return NULL;
1464 }
1465
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001466 // Extract declared names into export declarations and interface.
1467 Interface* interface = top_scope_->interface();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001468 for (int i = 0; i < names.length(); ++i) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001469#ifdef DEBUG
1470 if (FLAG_print_interface_details)
1471 PrintF("# Export %s ", names[i]->ToAsciiArray());
1472#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001473 Interface* inner = Interface::NewUnknown(zone());
1474 interface->Add(names[i], inner, zone(), CHECK_OK);
1475 if (!*ok)
1476 return NULL;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001477 VariableProxy* proxy = NewUnresolved(names[i], LET, inner);
1478 USE(proxy);
1479 // TODO(rossberg): Rethink whether we actually need to store export
1480 // declarations (for compilation?).
1481 // ExportDeclaration* declaration =
1482 // factory()->NewExportDeclaration(proxy, top_scope_);
1483 // top_scope_->AddDeclaration(declaration);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001484 }
1485
1486 ASSERT(result != NULL);
1487 return result;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001488}
1489
1490
1491Statement* Parser::ParseBlockElement(ZoneStringList* labels,
1492 bool* ok) {
1493 // (Ecma 262 5th Edition, clause 14):
1494 // SourceElement:
1495 // Statement
1496 // FunctionDeclaration
1497 //
1498 // In harmony mode we allow additionally the following productions
1499 // BlockElement (aka SourceElement):
1500 // LetDeclaration
1501 // ConstDeclaration
1502
1503 switch (peek()) {
1504 case Token::FUNCTION:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001505 return ParseFunctionDeclaration(NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001506 case Token::LET:
1507 case Token::CONST:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001508 return ParseVariableStatement(kModuleElement, NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001509 default:
1510 return ParseStatement(labels, ok);
1511 }
1512}
1513
1514
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
1516 // Statement ::
1517 // Block
1518 // VariableStatement
1519 // EmptyStatement
1520 // ExpressionStatement
1521 // IfStatement
1522 // IterationStatement
1523 // ContinueStatement
1524 // BreakStatement
1525 // ReturnStatement
1526 // WithStatement
1527 // LabelledStatement
1528 // SwitchStatement
1529 // ThrowStatement
1530 // TryStatement
1531 // DebuggerStatement
1532
1533 // Note: Since labels can only be used by 'break' and 'continue'
1534 // statements, which themselves are only valid within blocks,
1535 // iterations or 'switch' statements (i.e., BreakableStatements),
1536 // labels can be simply ignored in all other cases; except for
ager@chromium.org32912102009-01-16 10:38:43 +00001537 // trivial labeled break statements 'label: break label' which is
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001538 // parsed into an empty statement.
1539
1540 // Keep the source position of the statement
1541 int statement_pos = scanner().peek_location().beg_pos;
1542 Statement* stmt = NULL;
1543 switch (peek()) {
1544 case Token::LBRACE:
1545 return ParseBlock(labels, ok);
1546
1547 case Token::CONST: // fall through
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001548 case Token::LET:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 case Token::VAR:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001550 stmt = ParseVariableStatement(kStatement, NULL, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551 break;
1552
1553 case Token::SEMICOLON:
1554 Next();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001555 return factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556
1557 case Token::IF:
1558 stmt = ParseIfStatement(labels, ok);
1559 break;
1560
1561 case Token::DO:
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001562 stmt = ParseDoWhileStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 break;
1564
1565 case Token::WHILE:
1566 stmt = ParseWhileStatement(labels, ok);
1567 break;
1568
1569 case Token::FOR:
1570 stmt = ParseForStatement(labels, ok);
1571 break;
1572
1573 case Token::CONTINUE:
1574 stmt = ParseContinueStatement(ok);
1575 break;
1576
1577 case Token::BREAK:
1578 stmt = ParseBreakStatement(labels, ok);
1579 break;
1580
1581 case Token::RETURN:
1582 stmt = ParseReturnStatement(ok);
1583 break;
1584
1585 case Token::WITH:
1586 stmt = ParseWithStatement(labels, ok);
1587 break;
1588
1589 case Token::SWITCH:
1590 stmt = ParseSwitchStatement(labels, ok);
1591 break;
1592
1593 case Token::THROW:
1594 stmt = ParseThrowStatement(ok);
1595 break;
1596
1597 case Token::TRY: {
1598 // NOTE: It is somewhat complicated to have labels on
1599 // try-statements. When breaking out of a try-finally statement,
1600 // one must take great care not to treat it as a
1601 // fall-through. It is much easier just to wrap the entire
1602 // try-statement in a statement block and put the labels there
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001603 Block* result = factory()->NewBlock(labels, 1, false);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001604 Target target(&this->target_stack_, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605 TryStatement* statement = ParseTryStatement(CHECK_OK);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001606 if (statement) {
1607 statement->set_statement_pos(statement_pos);
1608 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001609 if (result) result->AddStatement(statement, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001610 return result;
1611 }
1612
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001613 case Token::FUNCTION: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001614 // FunctionDeclaration is only allowed in the context of SourceElements
1615 // (Ecma 262 5th Edition, clause 14):
1616 // SourceElement:
1617 // Statement
1618 // FunctionDeclaration
1619 // Common language extension is to allow function declaration in place
1620 // of any statement. This language extension is disabled in strict mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001621 if (!top_scope_->is_classic_mode()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001622 ReportMessageAt(scanner().peek_location(), "strict_function",
1623 Vector<const char*>::empty());
1624 *ok = false;
1625 return NULL;
1626 }
ulan@chromium.org812308e2012-02-29 15:58:45 +00001627 return ParseFunctionDeclaration(NULL, ok);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001628 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001629
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001630 case Token::DEBUGGER:
1631 stmt = ParseDebuggerStatement(ok);
1632 break;
1633
1634 default:
1635 stmt = ParseExpressionOrLabelledStatement(labels, ok);
1636 }
1637
1638 // Store the source position of the statement
1639 if (stmt != NULL) stmt->set_statement_pos(statement_pos);
1640 return stmt;
1641}
1642
1643
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001644VariableProxy* Parser::NewUnresolved(
1645 Handle<String> name, VariableMode mode, Interface* interface) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00001646 // If we are inside a function, a declaration of a var/const variable is a
1647 // truly local variable, and the scope of the variable is always the function
1648 // scope.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001649 // Let/const variables in harmony mode are always added to the immediately
1650 // enclosing scope.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001651 return DeclarationScope(mode)->NewUnresolved(
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001652 factory(), name, interface, scanner().location().beg_pos);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001653}
1654
1655
1656void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001657 VariableProxy* proxy = declaration->proxy();
1658 Handle<String> name = proxy->name();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001659 VariableMode mode = declaration->mode();
1660 Scope* declaration_scope = DeclarationScope(mode);
1661 Variable* var = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001662
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001663 // If a suitable scope exists, then we can statically declare this
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664 // variable and also set its mode. In any case, a Declaration node
1665 // will be added to the scope so that the declaration can be added
1666 // to the corresponding activation frame at runtime if necessary.
1667 // For instance declarations inside an eval scope need to be added
1668 // to the calling function context.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001669 // Similarly, strict mode eval scope does not leak variable declarations to
1670 // the caller's scope so we declare all locals, too.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001671 if (declaration_scope->is_function_scope() ||
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001672 declaration_scope->is_strict_or_extended_eval_scope() ||
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001673 declaration_scope->is_block_scope() ||
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001674 declaration_scope->is_module_scope() ||
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001675 declaration_scope->is_global_scope()) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001676 // Declare the variable in the declaration scope.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001677 // For the global scope, we have to check for collisions with earlier
1678 // (i.e., enclosing) global scopes, to maintain the illusion of a single
1679 // global scope.
1680 var = declaration_scope->is_global_scope()
1681 ? declaration_scope->Lookup(name)
1682 : declaration_scope->LocalLookup(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001683 if (var == NULL) {
1684 // Declare the name.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001685 var = declaration_scope->DeclareLocal(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001686 name, mode, declaration->initialization(), proxy->interface());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001687 } else if ((mode != VAR || var->mode() != VAR) &&
1688 (!declaration_scope->is_global_scope() ||
1689 IsLexicalVariableMode(mode) ||
1690 IsLexicalVariableMode(var->mode()))) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001691 // The name was declared in this scope before; check for conflicting
1692 // re-declarations. We have a conflict if either of the declarations is
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001693 // not a var (in the global scope, we also have to ignore legacy const for
1694 // compatibility). There is similar code in runtime.cc in the Declare
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001695 // functions. The function CheckNonConflictingScope checks for conflicting
1696 // var and let bindings from different scopes whereas this is a check for
1697 // conflicting declarations within the same scope. This check also covers
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001698 // the special case
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001699 //
1700 // function () { let x; { var x; } }
1701 //
1702 // because the var declaration is hoisted to the function scope where 'x'
1703 // is already bound.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001704 ASSERT(IsDeclaredVariableMode(var->mode()));
1705 if (is_extended_mode()) {
1706 // In harmony mode we treat re-declarations as early errors. See
1707 // ES5 16 for a definition of early errors.
1708 SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
1709 const char* elms[2] = { "Variable", *c_string };
1710 Vector<const char*> args(elms, 2);
1711 ReportMessage("redeclaration", args);
1712 *ok = false;
1713 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001714 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001715 Handle<String> type_string =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001716 isolate()->factory()->NewStringFromUtf8(CStrVector("Variable"),
1717 TENURED);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001718 Expression* expression =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001719 NewThrowTypeError(isolate()->factory()->redeclaration_string(),
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001720 type_string, name);
1721 declaration_scope->SetIllegalRedeclaration(expression);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001722 }
1723 }
1724
1725 // We add a declaration node for every declaration. The compiler
1726 // will only generate code if necessary. In particular, declarations
1727 // for inner local variables that do not represent functions won't
1728 // result in any generated code.
1729 //
1730 // Note that we always add an unresolved proxy even if it's not
1731 // used, simply because we don't know in this method (w/o extra
1732 // parameters) if the proxy is needed or not. The proxy will be
1733 // bound during variable resolution time unless it was pre-bound
1734 // below.
1735 //
1736 // WARNING: This will lead to multiple declaration nodes for the
1737 // same variable if it is declared several times. This is not a
1738 // semantic issue as long as we keep the source order, but it may be
1739 // a performance issue since it may lead to repeated
1740 // Runtime::DeclareContextSlot() calls.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001741 declaration_scope->AddDeclaration(declaration);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001742
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001743 if (mode == CONST && declaration_scope->is_global_scope()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001744 // For global const variables we bind the proxy to a variable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001745 ASSERT(resolve); // should be set by all callers
ager@chromium.org3e875802009-06-29 08:26:34 +00001746 Variable::Kind kind = Variable::NORMAL;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001747 var = new(zone()) Variable(declaration_scope,
1748 name,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001749 mode,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001750 true,
1751 kind,
1752 kNeedsInitialization);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001753 } else if (declaration_scope->is_eval_scope() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001754 declaration_scope->is_classic_mode()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001755 // For variable declarations in a non-strict eval scope the proxy is bound
1756 // to a lookup variable to force a dynamic declaration using the
1757 // DeclareContextSlot runtime function.
1758 Variable::Kind kind = Variable::NORMAL;
1759 var = new(zone()) Variable(declaration_scope,
1760 name,
1761 mode,
1762 true,
1763 kind,
ulan@chromium.org812308e2012-02-29 15:58:45 +00001764 declaration->initialization());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001765 var->AllocateTo(Variable::LOOKUP, -1);
1766 resolve = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001767 }
1768
1769 // If requested and we have a local variable, bind the proxy to the variable
1770 // at parse-time. This is used for functions (and consts) declared inside
1771 // statements: the corresponding function (or const) variable must be in the
1772 // function scope and not a statement-local scope, e.g. as provided with a
1773 // 'with' statement:
1774 //
1775 // with (obj) {
1776 // function f() {}
1777 // }
1778 //
1779 // which is translated into:
1780 //
1781 // with (obj) {
1782 // // in this case this is not: 'var f; f = function () {};'
1783 // var f = function () {};
1784 // }
1785 //
1786 // Note that if 'f' is accessed from inside the 'with' statement, it
1787 // will be allocated in the context (because we must be able to look
1788 // it up dynamically) but it will also be accessed statically, i.e.,
1789 // with a context slot index and a context chain length for this
1790 // initialization code. Thus, inside the 'with' statement, we need
1791 // both access to the static and the dynamic context chain; the
1792 // runtime needs to provide both.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001793 if (resolve && var != NULL) {
1794 proxy->BindTo(var);
1795
1796 if (FLAG_harmony_modules) {
1797 bool ok;
1798#ifdef DEBUG
1799 if (FLAG_print_interface_details)
1800 PrintF("# Declare %s\n", var->name()->ToAsciiArray());
1801#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001802 proxy->interface()->Unify(var->interface(), zone(), &ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001803 if (!ok) {
1804#ifdef DEBUG
1805 if (FLAG_print_interfaces) {
1806 PrintF("DECLARE TYPE ERROR\n");
1807 PrintF("proxy: ");
1808 proxy->interface()->Print();
1809 PrintF("var: ");
1810 var->interface()->Print();
1811 }
1812#endif
1813 ReportMessage("module_type_error", Vector<Handle<String> >(&name, 1));
1814 }
1815 }
1816 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817}
1818
1819
1820// Language extension which is only enabled for source files loaded
1821// through the API's extension mechanism. A native function
1822// declaration is resolved by looking up the function through a
1823// callback provided by the extension.
1824Statement* Parser::ParseNativeDeclaration(bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001825 Expect(Token::FUNCTION, CHECK_OK);
1826 Handle<String> name = ParseIdentifier(CHECK_OK);
1827 Expect(Token::LPAREN, CHECK_OK);
1828 bool done = (peek() == Token::RPAREN);
1829 while (!done) {
1830 ParseIdentifier(CHECK_OK);
1831 done = (peek() == Token::RPAREN);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001832 if (!done) {
1833 Expect(Token::COMMA, CHECK_OK);
1834 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835 }
1836 Expect(Token::RPAREN, CHECK_OK);
1837 Expect(Token::SEMICOLON, CHECK_OK);
1838
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839 // Make sure that the function containing the native declaration
1840 // isn't lazily compiled. The extension structures are only
1841 // accessible while parsing the first time not when reparsing
1842 // because of lazy compilation.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001843 DeclarationScope(VAR)->ForceEagerCompilation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001844
1845 // Compute the function template for the native function.
1846 v8::Handle<v8::FunctionTemplate> fun_template =
1847 extension_->GetNativeFunction(v8::Utils::ToLocal(name));
1848 ASSERT(!fun_template.IsEmpty());
1849
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001850 // Instantiate the function and create a shared function info from it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001851 Handle<JSFunction> fun = Utils::OpenHandle(*fun_template->GetFunction());
1852 const int literals = fun->NumberOfLiterals();
1853 Handle<Code> code = Handle<Code>(fun->shared()->code());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001854 Handle<Code> construct_stub = Handle<Code>(fun->shared()->construct_stub());
ager@chromium.orgb5737492010-07-15 09:29:43 +00001855 Handle<SharedFunctionInfo> shared =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856 isolate()->factory()->NewSharedFunctionInfo(name, literals, code,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001857 Handle<ScopeInfo>(fun->shared()->scope_info()));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001858 shared->set_construct_stub(*construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001859
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001860 // Copy the function data to the shared function info.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001861 shared->set_function_data(fun->shared()->function_data());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001862 int parameters = fun->shared()->formal_parameter_count();
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001863 shared->set_formal_parameter_count(parameters);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001864
1865 // TODO(1240846): It's weird that native function declarations are
1866 // introduced dynamically when we meet their declarations, whereas
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001867 // other functions are set up when entering the surrounding scope.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001868 VariableProxy* proxy = NewUnresolved(name, VAR, Interface::NewValue());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001869 Declaration* declaration =
1870 factory()->NewVariableDeclaration(proxy, VAR, top_scope_);
1871 Declare(declaration, true, CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001872 SharedFunctionInfoLiteral* lit =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001873 factory()->NewSharedFunctionInfoLiteral(shared);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001874 return factory()->NewExpressionStatement(
1875 factory()->NewAssignment(
ulan@chromium.org812308e2012-02-29 15:58:45 +00001876 Token::INIT_VAR, proxy, lit, RelocInfo::kNoPosition));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001877}
1878
1879
ulan@chromium.org812308e2012-02-29 15:58:45 +00001880Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001881 // FunctionDeclaration ::
1882 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001883 Expect(Token::FUNCTION, CHECK_OK);
1884 int function_token_position = scanner().location().beg_pos;
ager@chromium.org04921a82011-06-27 13:21:41 +00001885 bool is_strict_reserved = false;
1886 Handle<String> name = ParseIdentifierOrStrictReservedWord(
1887 &is_strict_reserved, CHECK_OK);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001888 FunctionLiteral* fun = ParseFunctionLiteral(name,
ager@chromium.org04921a82011-06-27 13:21:41 +00001889 is_strict_reserved,
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001890 function_token_position,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001891 FunctionLiteral::DECLARATION,
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001892 CHECK_OK);
1893 // Even if we're not at the top-level of the global or a function
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001894 // scope, we treat it as such and introduce the function with its
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001895 // initial value upon entering the corresponding scope.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001896 // In extended mode, a function behaves as a lexical binding, except in the
1897 // global scope.
1898 VariableMode mode =
1899 is_extended_mode() && !top_scope_->is_global_scope() ? LET : VAR;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001900 VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001901 Declaration* declaration =
1902 factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_);
1903 Declare(declaration, true, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001904 if (names) names->Add(name, zone());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001905 return factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001906}
1907
1908
1909Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001910 if (top_scope_->is_extended_mode()) return ParseScopedBlock(labels, ok);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001911
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 // Block ::
1913 // '{' Statement* '}'
1914
1915 // Note that a Block does not introduce a new execution scope!
1916 // (ECMA-262, 3rd, 12.2)
1917 //
1918 // Construct block expecting 16 statements.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001919 Block* result = factory()->NewBlock(labels, 16, false);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001920 Target target(&this->target_stack_, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001921 Expect(Token::LBRACE, CHECK_OK);
1922 while (peek() != Token::RBRACE) {
1923 Statement* stat = ParseStatement(NULL, CHECK_OK);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001924 if (stat && !stat->IsEmpty()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001925 result->AddStatement(stat, zone());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001926 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001927 }
1928 Expect(Token::RBRACE, CHECK_OK);
1929 return result;
1930}
1931
1932
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001933Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001934 // The harmony mode uses block elements instead of statements.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001935 //
1936 // Block ::
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001937 // '{' BlockElement* '}'
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001938
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001939 // Construct block expecting 16 statements.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001940 Block* body = factory()->NewBlock(labels, 16, false);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001941 Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001942
1943 // Parse the statements and collect escaping labels.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001944 Expect(Token::LBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001945 block_scope->set_start_position(scanner().location().beg_pos);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001946 { BlockState block_state(this, block_scope);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001947 TargetCollector collector(zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001948 Target target(&this->target_stack_, &collector);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001949 Target target_body(&this->target_stack_, body);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001950
1951 while (peek() != Token::RBRACE) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001952 Statement* stat = ParseBlockElement(NULL, CHECK_OK);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001953 if (stat && !stat->IsEmpty()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001954 body->AddStatement(stat, zone());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001955 }
1956 }
1957 }
1958 Expect(Token::RBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001959 block_scope->set_end_position(scanner().location().end_pos);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001960 block_scope = block_scope->FinalizeBlockScope();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001961 body->set_scope(block_scope);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001962 return body;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001963}
1964
1965
danno@chromium.orgb6451162011-08-17 14:33:23 +00001966Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
ulan@chromium.org812308e2012-02-29 15:58:45 +00001967 ZoneStringList* names,
danno@chromium.orgb6451162011-08-17 14:33:23 +00001968 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001969 // VariableStatement ::
1970 // VariableDeclarations ';'
1971
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001972 Handle<String> ignore;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001973 Block* result =
ulan@chromium.org812308e2012-02-29 15:58:45 +00001974 ParseVariableDeclarations(var_context, NULL, names, &ignore, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001975 ExpectSemicolon(CHECK_OK);
1976 return result;
1977}
1978
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001979
1980bool Parser::IsEvalOrArguments(Handle<String> string) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001981 return string.is_identical_to(isolate()->factory()->eval_string()) ||
1982 string.is_identical_to(isolate()->factory()->arguments_string());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001983}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001986// If the variable declaration declares exactly one non-const
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001987// variable, then *out is set to that variable. In all other cases,
1988// *out is untouched; in particular, it is the caller's responsibility
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001989// to initialize it properly. This mechanism is used for the parsing
1990// of 'for-in' loops.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001991Block* Parser::ParseVariableDeclarations(
1992 VariableDeclarationContext var_context,
1993 VariableDeclarationProperties* decl_props,
ulan@chromium.org812308e2012-02-29 15:58:45 +00001994 ZoneStringList* names,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001995 Handle<String>* out,
1996 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997 // VariableDeclarations ::
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001998 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
1999 //
2000 // The ES6 Draft Rev3 specifies the following grammar for const declarations
2001 //
2002 // ConstDeclaration ::
2003 // const ConstBinding (',' ConstBinding)* ';'
2004 // ConstBinding ::
2005 // Identifier '=' AssignmentExpression
2006 //
2007 // TODO(ES6):
2008 // ConstBinding ::
2009 // BindingPattern '=' AssignmentExpression
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002010 VariableMode mode = VAR;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002011 // True if the binding needs initialization. 'let' and 'const' declared
2012 // bindings are created uninitialized by their declaration nodes and
2013 // need initialization. 'var' declared bindings are always initialized
2014 // immediately by their declaration nodes.
2015 bool needs_init = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016 bool is_const = false;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002017 Token::Value init_op = Token::INIT_VAR;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002018 if (peek() == Token::VAR) {
2019 Consume(Token::VAR);
2020 } else if (peek() == Token::CONST) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002021 // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
2022 //
2023 // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
2024 //
2025 // * It is a Syntax Error if the code that matches this production is not
2026 // contained in extended code.
2027 //
2028 // However disallowing const in classic mode will break compatibility with
2029 // existing pages. Therefore we keep allowing const with the old
2030 // non-harmony semantics in classic mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002031 Consume(Token::CONST);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002032 switch (top_scope_->language_mode()) {
2033 case CLASSIC_MODE:
2034 mode = CONST;
2035 init_op = Token::INIT_CONST;
2036 break;
2037 case STRICT_MODE:
2038 ReportMessage("strict_const", Vector<const char*>::empty());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002039 *ok = false;
2040 return NULL;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002041 case EXTENDED_MODE:
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002042 if (var_context == kStatement) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002043 // In extended mode 'const' declarations are only allowed in source
2044 // element positions.
2045 ReportMessage("unprotected_const", Vector<const char*>::empty());
2046 *ok = false;
2047 return NULL;
2048 }
2049 mode = CONST_HARMONY;
2050 init_op = Token::INIT_CONST_HARMONY;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002051 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002052 is_const = true;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002053 needs_init = true;
danno@chromium.orgb6451162011-08-17 14:33:23 +00002054 } else if (peek() == Token::LET) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002055 // ES6 Draft Rev4 section 12.2.1:
2056 //
2057 // LetDeclaration : let LetBindingList ;
2058 //
2059 // * It is a Syntax Error if the code that matches this production is not
2060 // contained in extended code.
2061 if (!is_extended_mode()) {
2062 ReportMessage("illegal_let", Vector<const char*>::empty());
2063 *ok = false;
2064 return NULL;
2065 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00002066 Consume(Token::LET);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002067 if (var_context == kStatement) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002068 // Let declarations are only allowed in source element positions.
danno@chromium.orgb6451162011-08-17 14:33:23 +00002069 ReportMessage("unprotected_let", Vector<const char*>::empty());
2070 *ok = false;
2071 return NULL;
2072 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002073 mode = LET;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002074 needs_init = true;
2075 init_op = Token::INIT_LET;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076 } else {
2077 UNREACHABLE(); // by current callers
2078 }
2079
ulan@chromium.org812308e2012-02-29 15:58:45 +00002080 Scope* declaration_scope = DeclarationScope(mode);
2081
danno@chromium.orgb6451162011-08-17 14:33:23 +00002082 // The scope of a var/const declared variable anywhere inside a function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002083 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
danno@chromium.orgb6451162011-08-17 14:33:23 +00002084 // transform a source-level var/const declaration into a (Function)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002085 // Scope declaration, and rewrite the source-level initialization into an
2086 // assignment statement. We use a block to collect multiple assignments.
2087 //
2088 // We mark the block as initializer block because we don't want the
2089 // rewriter to add a '.result' assignment to such a block (to get compliant
2090 // behavior for code such as print(eval('var x = 7')), and for cosmetic
2091 // reasons when pretty-printing. Also, unless an assignment (initialization)
2092 // is inside an initializer block, it is ignored.
2093 //
2094 // Create new block with one expected declaration.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002095 Block* block = factory()->NewBlock(NULL, 1, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002096 int nvars = 0; // the number of variables declared
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002097 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002098 do {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002099 if (fni_ != NULL) fni_->Enter();
2100
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002101 // Parse variable name.
2102 if (nvars > 0) Consume(Token::COMMA);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002103 name = ParseIdentifier(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002104 if (fni_ != NULL) fni_->PushVariableName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002105
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002106 // Strict mode variables may not be named eval or arguments
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002107 if (!declaration_scope->is_classic_mode() && IsEvalOrArguments(name)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002108 ReportMessage("strict_var_name", Vector<const char*>::empty());
2109 *ok = false;
2110 return NULL;
2111 }
2112
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002113 // Declare variable.
2114 // Note that we *always* must treat the initial value via a separate init
2115 // assignment for variables and constants because the value must be assigned
2116 // when the variable is encountered in the source. But the variable/constant
2117 // is declared (and set to 'undefined') upon entering the function within
2118 // which the variable or constant is declared. Only function variables have
2119 // an initial value in the declaration (because they are initialized upon
2120 // entering the function).
2121 //
2122 // If we have a const declaration, in an inner scope, the proxy is always
2123 // bound to the declared variable (independent of possibly surrounding with
2124 // statements).
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002125 // For let/const declarations in harmony mode, we can also immediately
2126 // pre-resolve the proxy because it resides in the same scope as the
2127 // declaration.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002128 Interface* interface =
2129 is_const ? Interface::NewConst() : Interface::NewValue();
2130 VariableProxy* proxy = NewUnresolved(name, mode, interface);
ulan@chromium.org812308e2012-02-29 15:58:45 +00002131 Declaration* declaration =
2132 factory()->NewVariableDeclaration(proxy, mode, top_scope_);
2133 Declare(declaration, mode != VAR, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002134 nvars++;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002135 if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002136 ReportMessageAt(scanner().location(), "too_many_variables",
2137 Vector<const char*>::empty());
2138 *ok = false;
2139 return NULL;
2140 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002141 if (names) names->Add(name, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002142
2143 // Parse initialization expression if present and/or needed. A
2144 // declaration of the form:
2145 //
2146 // var v = x;
2147 //
2148 // is syntactic sugar for:
2149 //
2150 // var v; v = x;
2151 //
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002152 // In particular, we need to re-lookup 'v' (in top_scope_, not
2153 // declaration_scope) as it may be a different 'v' than the 'v' in the
2154 // declaration (e.g., if we are inside a 'with' statement or 'catch'
2155 // block).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002156 //
2157 // However, note that const declarations are different! A const
2158 // declaration of the form:
2159 //
2160 // const c = x;
2161 //
2162 // is *not* syntactic sugar for:
2163 //
2164 // const c; c = x;
2165 //
2166 // The "variable" c initialized to x is the same as the declared
2167 // one - there is no re-lookup (see the last parameter of the
2168 // Declare() call above).
2169
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002170 Scope* initialization_scope = is_const ? declaration_scope : top_scope_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002171 Expression* value = NULL;
2172 int position = -1;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002173 // Harmony consts have non-optional initializers.
2174 if (peek() == Token::ASSIGN || mode == CONST_HARMONY) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002175 Expect(Token::ASSIGN, CHECK_OK);
2176 position = scanner().location().beg_pos;
danno@chromium.orgb6451162011-08-17 14:33:23 +00002177 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002178 // Don't infer if it is "a = function(){...}();"-like expression.
ager@chromium.org04921a82011-06-27 13:21:41 +00002179 if (fni_ != NULL &&
2180 value->AsCall() == NULL &&
2181 value->AsCallNew() == NULL) {
2182 fni_->Infer();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002183 } else {
2184 fni_->RemoveLastFunction();
ager@chromium.org04921a82011-06-27 13:21:41 +00002185 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002186 if (decl_props != NULL) *decl_props = kHasInitializers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002187 }
2188
danno@chromium.orgc612e022011-11-10 11:38:15 +00002189 // Record the end position of the initializer.
2190 if (proxy->var() != NULL) {
2191 proxy->var()->set_initializer_position(scanner().location().end_pos);
2192 }
2193
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002194 // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
2195 if (value == NULL && needs_init) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002196 value = GetLiteralUndefined();
2197 }
2198
2199 // Global variable declarations must be compiled in a specific
2200 // way. When the script containing the global variable declaration
2201 // is entered, the global variable must be declared, so that if it
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002202 // doesn't exist (on the global object itself, see ES5 errata) it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002203 // gets created with an initial undefined value. This is handled
2204 // by the declarations part of the function representing the
2205 // top-level global code; see Runtime::DeclareGlobalVariable. If
2206 // it already exists (in the object or in a prototype), it is
2207 // *not* touched until the variable declaration statement is
2208 // executed.
2209 //
2210 // Executing the variable declaration statement will always
2211 // guarantee to give the global object a "local" variable; a
2212 // variable defined in the global object and not in any
2213 // prototype. This way, global variable declarations can shadow
2214 // properties in the prototype chain, but only after the variable
2215 // declaration statement has been executed. This is important in
2216 // browsers where the global object (window) has lots of
2217 // properties defined in prototype objects.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002218 if (initialization_scope->is_global_scope() &&
2219 !IsLexicalVariableMode(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002220 // Compute the arguments for the runtime call.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002221 ZoneList<Expression*>* arguments =
2222 new(zone()) ZoneList<Expression*>(3, zone());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002223 // We have at least 1 parameter.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002224 arguments->Add(factory()->NewLiteral(name), zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002225 CallRuntime* initialize;
2226
2227 if (is_const) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002228 arguments->Add(value, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002229 value = NULL; // zap the value to avoid the unnecessary assignment
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002230
2231 // Construct the call to Runtime_InitializeConstGlobal
2232 // and add it to the initialization statement block.
2233 // Note that the function does different things depending on
2234 // the number of arguments (1 or 2).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002235 initialize = factory()->NewCallRuntime(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002236 isolate()->factory()->InitializeConstGlobal_string(),
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002237 Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
2238 arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002239 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002240 // Add strict mode.
2241 // We may want to pass singleton to avoid Literal allocations.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002242 LanguageMode language_mode = initialization_scope->language_mode();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002243 arguments->Add(factory()->NewNumberLiteral(language_mode), zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002244
2245 // Be careful not to assign a value to the global variable if
2246 // we're in a with. The initialization value should not
2247 // necessarily be stored in the global object in that case,
2248 // which is why we need to generate a separate assignment node.
2249 if (value != NULL && !inside_with()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002250 arguments->Add(value, zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002251 value = NULL; // zap the value to avoid the unnecessary assignment
2252 }
2253
2254 // Construct the call to Runtime_InitializeVarGlobal
2255 // and add it to the initialization statement block.
2256 // Note that the function does different things depending on
2257 // the number of arguments (2 or 3).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002258 initialize = factory()->NewCallRuntime(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002259 isolate()->factory()->InitializeVarGlobal_string(),
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002260 Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
2261 arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002262 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002263
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002264 block->AddStatement(factory()->NewExpressionStatement(initialize),
2265 zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002266 } else if (needs_init) {
2267 // Constant initializations always assign to the declared constant which
2268 // is always at the function scope level. This is only relevant for
2269 // dynamically looked-up variables and constants (the start context for
2270 // constant lookups is always the function context, while it is the top
2271 // context for var declared variables). Sigh...
2272 // For 'let' and 'const' declared variables in harmony mode the
2273 // initialization also always assigns to the declared variable.
2274 ASSERT(proxy != NULL);
2275 ASSERT(proxy->var() != NULL);
2276 ASSERT(value != NULL);
2277 Assignment* assignment =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002278 factory()->NewAssignment(init_op, proxy, value, position);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002279 block->AddStatement(factory()->NewExpressionStatement(assignment),
2280 zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002281 value = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002282 }
2283
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002284 // Add an assignment node to the initialization statement block if we still
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002285 // have a pending initialization value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002286 if (value != NULL) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002287 ASSERT(mode == VAR);
2288 // 'var' initializations are simply assignments (with all the consequences
2289 // if they are inside a 'with' statement - they may change a 'with' object
2290 // property).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002291 VariableProxy* proxy =
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002292 initialization_scope->NewUnresolved(factory(), name, interface);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002293 Assignment* assignment =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002294 factory()->NewAssignment(init_op, proxy, value, position);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002295 block->AddStatement(factory()->NewExpressionStatement(assignment),
2296 zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002297 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002298
2299 if (fni_ != NULL) fni_->Leave();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002300 } while (peek() == Token::COMMA);
2301
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002302 // If there was a single non-const declaration, return it in the output
2303 // parameter for possible use by for/in.
2304 if (nvars == 1 && !is_const) {
2305 *out = name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002306 }
2307
2308 return block;
2309}
2310
2311
2312static bool ContainsLabel(ZoneStringList* labels, Handle<String> label) {
2313 ASSERT(!label.is_null());
2314 if (labels != NULL)
2315 for (int i = labels->length(); i-- > 0; )
2316 if (labels->at(i).is_identical_to(label))
2317 return true;
2318
2319 return false;
2320}
2321
2322
2323Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
2324 bool* ok) {
2325 // ExpressionStatement | LabelledStatement ::
2326 // Expression ';'
2327 // Identifier ':' Statement
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002328 bool starts_with_idenfifier = peek_any_identifier();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002329 Expression* expr = ParseExpression(true, CHECK_OK);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002330 if (peek() == Token::COLON && starts_with_idenfifier && expr != NULL &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002331 expr->AsVariableProxy() != NULL &&
2332 !expr->AsVariableProxy()->is_this()) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002333 // Expression is a single identifier, and not, e.g., a parenthesized
2334 // identifier.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002335 VariableProxy* var = expr->AsVariableProxy();
2336 Handle<String> label = var->name();
2337 // TODO(1240780): We don't check for redeclaration of labels
2338 // during preparsing since keeping track of the set of active
2339 // labels requires nontrivial changes to the way scopes are
2340 // structured. However, these are probably changes we want to
2341 // make later anyway so we should go back and fix this then.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002342 if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002343 SmartArrayPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002344 const char* elms[2] = { "Label", *c_string };
2345 Vector<const char*> args(elms, 2);
2346 ReportMessage("redeclaration", args);
2347 *ok = false;
2348 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002349 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002350 if (labels == NULL) {
2351 labels = new(zone()) ZoneStringList(4, zone());
2352 }
2353 labels->Add(label, zone());
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002354 // Remove the "ghost" variable that turned out to be a label
2355 // from the top scope. This way, we don't try to resolve it
2356 // during the scope processing.
2357 top_scope_->RemoveUnresolved(var);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002358 Expect(Token::COLON, CHECK_OK);
2359 return ParseStatement(labels, ok);
2360 }
2361
whesse@chromium.org7b260152011-06-20 15:33:18 +00002362 // If we have an extension, we allow a native function declaration.
2363 // A native function declaration starts with "native function" with
2364 // no line-terminator between the two words.
2365 if (extension_ != NULL &&
2366 peek() == Token::FUNCTION &&
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002367 !scanner().HasAnyLineTerminatorBeforeNext() &&
whesse@chromium.org7b260152011-06-20 15:33:18 +00002368 expr != NULL &&
2369 expr->AsVariableProxy() != NULL &&
2370 expr->AsVariableProxy()->name()->Equals(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002371 isolate()->heap()->native_string()) &&
whesse@chromium.org7b260152011-06-20 15:33:18 +00002372 !scanner().literal_contains_escapes()) {
2373 return ParseNativeDeclaration(ok);
2374 }
2375
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00002376 // Parsed expression statement, or the context-sensitive 'module' keyword.
2377 // Only expect semicolon in the former case.
2378 if (!FLAG_harmony_modules ||
2379 peek() != Token::IDENTIFIER ||
2380 scanner().HasAnyLineTerminatorBeforeNext() ||
2381 expr->AsVariableProxy() == NULL ||
2382 !expr->AsVariableProxy()->name()->Equals(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002383 isolate()->heap()->module_string()) ||
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00002384 scanner().literal_contains_escapes()) {
2385 ExpectSemicolon(CHECK_OK);
2386 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002387 return factory()->NewExpressionStatement(expr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002388}
2389
2390
2391IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) {
2392 // IfStatement ::
2393 // 'if' '(' Expression ')' Statement ('else' Statement)?
2394
2395 Expect(Token::IF, CHECK_OK);
2396 Expect(Token::LPAREN, CHECK_OK);
2397 Expression* condition = ParseExpression(true, CHECK_OK);
2398 Expect(Token::RPAREN, CHECK_OK);
2399 Statement* then_statement = ParseStatement(labels, CHECK_OK);
2400 Statement* else_statement = NULL;
2401 if (peek() == Token::ELSE) {
2402 Next();
2403 else_statement = ParseStatement(labels, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002404 } else {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002405 else_statement = factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002406 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002407 return factory()->NewIfStatement(condition, then_statement, else_statement);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002408}
2409
2410
2411Statement* Parser::ParseContinueStatement(bool* ok) {
2412 // ContinueStatement ::
2413 // 'continue' Identifier? ';'
2414
2415 Expect(Token::CONTINUE, CHECK_OK);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002416 Handle<String> label = Handle<String>::null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002417 Token::Value tok = peek();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002418 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002419 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002420 label = ParseIdentifier(CHECK_OK);
2421 }
2422 IterationStatement* target = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002423 target = LookupContinueTarget(label, CHECK_OK);
2424 if (target == NULL) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002425 // Illegal continue statement.
2426 const char* message = "illegal_continue";
2427 Vector<Handle<String> > args;
2428 if (!label.is_null()) {
2429 message = "unknown_label";
2430 args = Vector<Handle<String> >(&label, 1);
2431 }
2432 ReportMessageAt(scanner().location(), message, args);
2433 *ok = false;
2434 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002435 }
2436 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002437 return factory()->NewContinueStatement(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002438}
2439
2440
2441Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
2442 // BreakStatement ::
2443 // 'break' Identifier? ';'
2444
2445 Expect(Token::BREAK, CHECK_OK);
2446 Handle<String> label;
2447 Token::Value tok = peek();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002448 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002449 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002450 label = ParseIdentifier(CHECK_OK);
2451 }
ager@chromium.org32912102009-01-16 10:38:43 +00002452 // Parse labeled break statements that target themselves into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002453 // empty statements, e.g. 'l1: l2: l3: break l2;'
2454 if (!label.is_null() && ContainsLabel(labels, label)) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002455 ExpectSemicolon(CHECK_OK);
2456 return factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002457 }
2458 BreakableStatement* target = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002459 target = LookupBreakTarget(label, CHECK_OK);
2460 if (target == NULL) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002461 // Illegal break statement.
2462 const char* message = "illegal_break";
2463 Vector<Handle<String> > args;
2464 if (!label.is_null()) {
2465 message = "unknown_label";
2466 args = Vector<Handle<String> >(&label, 1);
2467 }
2468 ReportMessageAt(scanner().location(), message, args);
2469 *ok = false;
2470 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002471 }
2472 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002473 return factory()->NewBreakStatement(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002474}
2475
2476
2477Statement* Parser::ParseReturnStatement(bool* ok) {
2478 // ReturnStatement ::
2479 // 'return' Expression? ';'
2480
2481 // Consume the return token. It is necessary to do the before
2482 // reporting any errors on it, because of the way errors are
2483 // reported (underlining).
2484 Expect(Token::RETURN, CHECK_OK);
2485
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002486 Token::Value tok = peek();
2487 Statement* result;
2488 if (scanner().HasAnyLineTerminatorBeforeNext() ||
2489 tok == Token::SEMICOLON ||
2490 tok == Token::RBRACE ||
2491 tok == Token::EOS) {
2492 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002493 result = factory()->NewReturnStatement(GetLiteralUndefined());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002494 } else {
2495 Expression* expr = ParseExpression(true, CHECK_OK);
2496 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002497 result = factory()->NewReturnStatement(expr);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002498 }
2499
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002500 // An ECMAScript program is considered syntactically incorrect if it
2501 // contains a return statement that is not within the body of a
2502 // function. See ECMA-262, section 12.9, page 67.
2503 //
2504 // To be consistent with KJS we report the syntax error at runtime.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002505 Scope* declaration_scope = top_scope_->DeclarationScope();
2506 if (declaration_scope->is_global_scope() ||
2507 declaration_scope->is_eval_scope()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002508 Handle<String> type = isolate()->factory()->illegal_return_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002509 Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002510 return factory()->NewExpressionStatement(throw_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002511 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002512 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002513}
2514
2515
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002516Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
2517 // WithStatement ::
2518 // 'with' '(' Expression ')' Statement
2519
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002520 Expect(Token::WITH, CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002521
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002522 if (!top_scope_->is_classic_mode()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002523 ReportMessage("strict_mode_with", Vector<const char*>::empty());
2524 *ok = false;
2525 return NULL;
2526 }
2527
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002528 Expect(Token::LPAREN, CHECK_OK);
2529 Expression* expr = ParseExpression(true, CHECK_OK);
2530 Expect(Token::RPAREN, CHECK_OK);
2531
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002532 top_scope_->DeclarationScope()->RecordWithStatement();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002533 Scope* with_scope = NewScope(top_scope_, WITH_SCOPE);
2534 Statement* stmt;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002535 { BlockState block_state(this, with_scope);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002536 with_scope->set_start_position(scanner().peek_location().beg_pos);
2537 stmt = ParseStatement(labels, CHECK_OK);
2538 with_scope->set_end_position(scanner().location().end_pos);
2539 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002540 return factory()->NewWithStatement(expr, stmt);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002541}
2542
2543
2544CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
2545 // CaseClause ::
2546 // 'case' Expression ':' Statement*
2547 // 'default' ':' Statement*
2548
2549 Expression* label = NULL; // NULL expression indicates default case
2550 if (peek() == Token::CASE) {
2551 Expect(Token::CASE, CHECK_OK);
2552 label = ParseExpression(true, CHECK_OK);
2553 } else {
2554 Expect(Token::DEFAULT, CHECK_OK);
2555 if (*default_seen_ptr) {
2556 ReportMessage("multiple_defaults_in_switch",
2557 Vector<const char*>::empty());
2558 *ok = false;
2559 return NULL;
2560 }
2561 *default_seen_ptr = true;
2562 }
2563 Expect(Token::COLON, CHECK_OK);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002564 int pos = scanner().location().beg_pos;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002565 ZoneList<Statement*>* statements =
2566 new(zone()) ZoneList<Statement*>(5, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002567 while (peek() != Token::CASE &&
2568 peek() != Token::DEFAULT &&
2569 peek() != Token::RBRACE) {
2570 Statement* stat = ParseStatement(NULL, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002571 statements->Add(stat, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002572 }
2573
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002574 return new(zone()) CaseClause(isolate(), label, statements, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002575}
2576
2577
2578SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels,
2579 bool* ok) {
2580 // SwitchStatement ::
2581 // 'switch' '(' Expression ')' '{' CaseClause* '}'
2582
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002583 SwitchStatement* statement = factory()->NewSwitchStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002584 Target target(&this->target_stack_, statement);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002585
2586 Expect(Token::SWITCH, CHECK_OK);
2587 Expect(Token::LPAREN, CHECK_OK);
2588 Expression* tag = ParseExpression(true, CHECK_OK);
2589 Expect(Token::RPAREN, CHECK_OK);
2590
2591 bool default_seen = false;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002592 ZoneList<CaseClause*>* cases = new(zone()) ZoneList<CaseClause*>(4, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002593 Expect(Token::LBRACE, CHECK_OK);
2594 while (peek() != Token::RBRACE) {
2595 CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002596 cases->Add(clause, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002597 }
2598 Expect(Token::RBRACE, CHECK_OK);
2599
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002600 if (statement) statement->Initialize(tag, cases);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002601 return statement;
2602}
2603
2604
2605Statement* Parser::ParseThrowStatement(bool* ok) {
2606 // ThrowStatement ::
2607 // 'throw' Expression ';'
2608
2609 Expect(Token::THROW, CHECK_OK);
2610 int pos = scanner().location().beg_pos;
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002611 if (scanner().HasAnyLineTerminatorBeforeNext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002612 ReportMessage("newline_after_throw", Vector<const char*>::empty());
2613 *ok = false;
2614 return NULL;
2615 }
2616 Expression* exception = ParseExpression(true, CHECK_OK);
2617 ExpectSemicolon(CHECK_OK);
2618
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002619 return factory()->NewExpressionStatement(factory()->NewThrow(exception, pos));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002620}
2621
2622
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002623TryStatement* Parser::ParseTryStatement(bool* ok) {
2624 // TryStatement ::
2625 // 'try' Block Catch
2626 // 'try' Block Finally
2627 // 'try' Block Catch Finally
2628 //
2629 // Catch ::
2630 // 'catch' '(' Identifier ')' Block
2631 //
2632 // Finally ::
2633 // 'finally' Block
2634
2635 Expect(Token::TRY, CHECK_OK);
2636
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002637 TargetCollector try_collector(zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002638 Block* try_block;
2639
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002640 { Target target(&this->target_stack_, &try_collector);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002641 try_block = ParseBlock(NULL, CHECK_OK);
2642 }
2643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002644 Token::Value tok = peek();
2645 if (tok != Token::CATCH && tok != Token::FINALLY) {
2646 ReportMessage("no_catch_or_finally", Vector<const char*>::empty());
2647 *ok = false;
2648 return NULL;
2649 }
2650
2651 // If we can break out from the catch block and there is a finally block,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002652 // then we will need to collect escaping targets from the catch
2653 // block. Since we don't know yet if there will be a finally block, we
2654 // always collect the targets.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002655 TargetCollector catch_collector(zone());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002656 Scope* catch_scope = NULL;
2657 Variable* catch_variable = NULL;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002658 Block* catch_block = NULL;
2659 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002660 if (tok == Token::CATCH) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002661 Consume(Token::CATCH);
2662
2663 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002664 catch_scope = NewScope(top_scope_, CATCH_SCOPE);
2665 catch_scope->set_start_position(scanner().location().beg_pos);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002666 name = ParseIdentifier(CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002667
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002668 if (!top_scope_->is_classic_mode() && IsEvalOrArguments(name)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002669 ReportMessage("strict_catch_variable", Vector<const char*>::empty());
2670 *ok = false;
2671 return NULL;
2672 }
2673
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002674 Expect(Token::RPAREN, CHECK_OK);
2675
2676 if (peek() == Token::LBRACE) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002677 Target target(&this->target_stack_, &catch_collector);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002678 VariableMode mode = is_extended_mode() ? LET : VAR;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002679 catch_variable =
2680 catch_scope->DeclareLocal(name, mode, kCreatedInitialized);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002681
danno@chromium.orgc612e022011-11-10 11:38:15 +00002682 BlockState block_state(this, catch_scope);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002683 catch_block = ParseBlock(NULL, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002684 } else {
2685 Expect(Token::LBRACE, CHECK_OK);
2686 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002687 catch_scope->set_end_position(scanner().location().end_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002688 tok = peek();
2689 }
2690
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002691 Block* finally_block = NULL;
2692 if (tok == Token::FINALLY || catch_block == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002693 Consume(Token::FINALLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002694 finally_block = ParseBlock(NULL, CHECK_OK);
2695 }
2696
2697 // Simplify the AST nodes by converting:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002698 // 'try B0 catch B1 finally B2'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002699 // to:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002700 // 'try { try B0 catch B1 } finally B2'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002701
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002702 if (catch_block != NULL && finally_block != NULL) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002703 // If we have both, create an inner try/catch.
2704 ASSERT(catch_scope != NULL && catch_variable != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002705 int index = current_function_state_->NextHandlerIndex();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002706 TryCatchStatement* statement = factory()->NewTryCatchStatement(
2707 index, try_block, catch_scope, catch_variable, catch_block);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002708 statement->set_escaping_targets(try_collector.targets());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002709 try_block = factory()->NewBlock(NULL, 1, false);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002710 try_block->AddStatement(statement, zone());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002711 catch_block = NULL; // Clear to indicate it's been handled.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002712 }
2713
2714 TryStatement* result = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002715 if (catch_block != NULL) {
2716 ASSERT(finally_block == NULL);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002717 ASSERT(catch_scope != NULL && catch_variable != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002718 int index = current_function_state_->NextHandlerIndex();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002719 result = factory()->NewTryCatchStatement(
2720 index, try_block, catch_scope, catch_variable, catch_block);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002721 } else {
2722 ASSERT(finally_block != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002723 int index = current_function_state_->NextHandlerIndex();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002724 result = factory()->NewTryFinallyStatement(index, try_block, finally_block);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002725 // Combine the jump targets of the try block and the possible catch block.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002726 try_collector.targets()->AddAll(*catch_collector.targets(), zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002727 }
2728
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002729 result->set_escaping_targets(try_collector.targets());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002730 return result;
2731}
2732
2733
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002734DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels,
2735 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002736 // DoStatement ::
2737 // 'do' Statement 'while' '(' Expression ')' ';'
2738
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002739 DoWhileStatement* loop = factory()->NewDoWhileStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002740 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002741
2742 Expect(Token::DO, CHECK_OK);
2743 Statement* body = ParseStatement(NULL, CHECK_OK);
2744 Expect(Token::WHILE, CHECK_OK);
2745 Expect(Token::LPAREN, CHECK_OK);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002746
2747 if (loop != NULL) {
2748 int position = scanner().location().beg_pos;
2749 loop->set_condition_position(position);
2750 }
2751
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002752 Expression* cond = ParseExpression(true, CHECK_OK);
2753 Expect(Token::RPAREN, CHECK_OK);
2754
2755 // Allow do-statements to be terminated with and without
2756 // semi-colons. This allows code such as 'do;while(0)return' to
2757 // parse, which would not be the case if we had used the
2758 // ExpectSemicolon() functionality here.
2759 if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
2760
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002761 if (loop != NULL) loop->Initialize(cond, body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002762 return loop;
2763}
2764
2765
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002766WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002767 // WhileStatement ::
2768 // 'while' '(' Expression ')' Statement
2769
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002770 WhileStatement* loop = factory()->NewWhileStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002771 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772
2773 Expect(Token::WHILE, CHECK_OK);
2774 Expect(Token::LPAREN, CHECK_OK);
2775 Expression* cond = ParseExpression(true, CHECK_OK);
2776 Expect(Token::RPAREN, CHECK_OK);
2777 Statement* body = ParseStatement(NULL, CHECK_OK);
2778
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002779 if (loop != NULL) loop->Initialize(cond, body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002780 return loop;
2781}
2782
2783
2784Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
2785 // ForStatement ::
2786 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
2787
2788 Statement* init = NULL;
2789
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002790 // Create an in-between scope for let-bound iteration variables.
2791 Scope* saved_scope = top_scope_;
2792 Scope* for_scope = NewScope(top_scope_, BLOCK_SCOPE);
2793 top_scope_ = for_scope;
2794
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002795 Expect(Token::FOR, CHECK_OK);
2796 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002797 for_scope->set_start_position(scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002798 if (peek() != Token::SEMICOLON) {
2799 if (peek() == Token::VAR || peek() == Token::CONST) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002800 bool is_const = peek() == Token::CONST;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002801 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002802 Block* variable_statement =
ulan@chromium.org812308e2012-02-29 15:58:45 +00002803 ParseVariableDeclarations(kForStatement, NULL, NULL, &name, CHECK_OK);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002804
2805 if (peek() == Token::IN && !name.is_null()) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002806 Interface* interface =
2807 is_const ? Interface::NewConst() : Interface::NewValue();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002808 ForInStatement* loop = factory()->NewForInStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002809 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002810
2811 Expect(Token::IN, CHECK_OK);
2812 Expression* enumerable = ParseExpression(true, CHECK_OK);
2813 Expect(Token::RPAREN, CHECK_OK);
2814
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002815 VariableProxy* each =
2816 top_scope_->NewUnresolved(factory(), name, interface);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002817 Statement* body = ParseStatement(NULL, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002818 loop->Initialize(each, enumerable, body);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002819 Block* result = factory()->NewBlock(NULL, 2, false);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002820 result->AddStatement(variable_statement, zone());
2821 result->AddStatement(loop, zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002822 top_scope_ = saved_scope;
2823 for_scope->set_end_position(scanner().location().end_pos);
2824 for_scope = for_scope->FinalizeBlockScope();
2825 ASSERT(for_scope == NULL);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002826 // Parsed for-in loop w/ variable/const declaration.
2827 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002828 } else {
2829 init = variable_statement;
2830 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002831 } else if (peek() == Token::LET) {
2832 Handle<String> name;
2833 VariableDeclarationProperties decl_props = kHasNoInitializers;
2834 Block* variable_statement =
ulan@chromium.org812308e2012-02-29 15:58:45 +00002835 ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name,
2836 CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002837 bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
2838 if (peek() == Token::IN && accept_IN) {
2839 // Rewrite a for-in statement of the form
2840 //
2841 // for (let x in e) b
2842 //
2843 // into
2844 //
2845 // <let x' be a temporary variable>
2846 // for (x' in e) {
2847 // let x;
2848 // x = x';
2849 // b;
2850 // }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002851
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002852 // TODO(keuchel): Move the temporary variable to the block scope, after
2853 // implementing stack allocated block scoped variables.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002854 Factory* heap_factory = isolate()->factory();
2855 Handle<String> tempstr =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002856 heap_factory->NewConsString(heap_factory->dot_for_string(), name);
2857 Handle<String> tempname = heap_factory->InternalizeString(tempstr);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002858 Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002859 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002860 ForInStatement* loop = factory()->NewForInStatement(labels);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002861 Target target(&this->target_stack_, loop);
2862
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002863 // The expression does not see the loop variable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002864 Expect(Token::IN, CHECK_OK);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002865 top_scope_ = saved_scope;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002866 Expression* enumerable = ParseExpression(true, CHECK_OK);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002867 top_scope_ = for_scope;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002868 Expect(Token::RPAREN, CHECK_OK);
2869
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002870 VariableProxy* each =
2871 top_scope_->NewUnresolved(factory(), name, Interface::NewValue());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002872 Statement* body = ParseStatement(NULL, CHECK_OK);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002873 Block* body_block = factory()->NewBlock(NULL, 3, false);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002874 Assignment* assignment = factory()->NewAssignment(
2875 Token::ASSIGN, each, temp_proxy, RelocInfo::kNoPosition);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002876 Statement* assignment_statement =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002877 factory()->NewExpressionStatement(assignment);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002878 body_block->AddStatement(variable_statement, zone());
2879 body_block->AddStatement(assignment_statement, zone());
2880 body_block->AddStatement(body, zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002881 loop->Initialize(temp_proxy, enumerable, body_block);
2882 top_scope_ = saved_scope;
2883 for_scope->set_end_position(scanner().location().end_pos);
2884 for_scope = for_scope->FinalizeBlockScope();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002885 body_block->set_scope(for_scope);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002886 // Parsed for-in loop w/ let declaration.
2887 return loop;
2888
2889 } else {
2890 init = variable_statement;
2891 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002892 } else {
2893 Expression* expression = ParseExpression(false, CHECK_OK);
2894 if (peek() == Token::IN) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002895 // Signal a reference error if the expression is an invalid
2896 // left-hand side expression. We could report this as a syntax
2897 // error here but for compatibility with JSC we choose to report
2898 // the error at runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002899 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002900 Handle<String> type =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002901 isolate()->factory()->invalid_lhs_in_for_in_string();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002902 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002903 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002904 ForInStatement* loop = factory()->NewForInStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002905 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002906
2907 Expect(Token::IN, CHECK_OK);
2908 Expression* enumerable = ParseExpression(true, CHECK_OK);
2909 Expect(Token::RPAREN, CHECK_OK);
2910
2911 Statement* body = ParseStatement(NULL, CHECK_OK);
2912 if (loop) loop->Initialize(expression, enumerable, body);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002913 top_scope_ = saved_scope;
2914 for_scope->set_end_position(scanner().location().end_pos);
2915 for_scope = for_scope->FinalizeBlockScope();
2916 ASSERT(for_scope == NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002917 // Parsed for-in loop.
2918 return loop;
2919
2920 } else {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002921 init = factory()->NewExpressionStatement(expression);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002922 }
2923 }
2924 }
2925
2926 // Standard 'for' loop
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002927 ForStatement* loop = factory()->NewForStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002928 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002929
2930 // Parsed initializer at this point.
2931 Expect(Token::SEMICOLON, CHECK_OK);
2932
2933 Expression* cond = NULL;
2934 if (peek() != Token::SEMICOLON) {
2935 cond = ParseExpression(true, CHECK_OK);
2936 }
2937 Expect(Token::SEMICOLON, CHECK_OK);
2938
2939 Statement* next = NULL;
2940 if (peek() != Token::RPAREN) {
2941 Expression* exp = ParseExpression(true, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002942 next = factory()->NewExpressionStatement(exp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002943 }
2944 Expect(Token::RPAREN, CHECK_OK);
2945
2946 Statement* body = ParseStatement(NULL, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002947 top_scope_ = saved_scope;
2948 for_scope->set_end_position(scanner().location().end_pos);
2949 for_scope = for_scope->FinalizeBlockScope();
2950 if (for_scope != NULL) {
2951 // Rewrite a for statement of the form
2952 //
2953 // for (let x = i; c; n) b
2954 //
2955 // into
2956 //
2957 // {
2958 // let x = i;
2959 // for (; c; n) b
2960 // }
2961 ASSERT(init != NULL);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002962 Block* result = factory()->NewBlock(NULL, 2, false);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002963 result->AddStatement(init, zone());
2964 result->AddStatement(loop, zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002965 result->set_scope(for_scope);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002966 if (loop) loop->Initialize(NULL, cond, next, body);
2967 return result;
2968 } else {
2969 if (loop) loop->Initialize(init, cond, next, body);
2970 return loop;
2971 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002972}
2973
2974
2975// Precedence = 1
2976Expression* Parser::ParseExpression(bool accept_IN, bool* ok) {
2977 // Expression ::
2978 // AssignmentExpression
2979 // Expression ',' AssignmentExpression
2980
2981 Expression* result = ParseAssignmentExpression(accept_IN, CHECK_OK);
2982 while (peek() == Token::COMMA) {
2983 Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002984 int position = scanner().location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002985 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002986 result =
2987 factory()->NewBinaryOperation(Token::COMMA, result, right, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002988 }
2989 return result;
2990}
2991
2992
2993// Precedence = 2
2994Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
2995 // AssignmentExpression ::
2996 // ConditionalExpression
2997 // LeftHandSideExpression AssignmentOperator AssignmentExpression
2998
ricow@chromium.org65fae842010-08-25 15:26:24 +00002999 if (fni_ != NULL) fni_->Enter();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003000 Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
3001
3002 if (!Token::IsAssignmentOp(peek())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003003 if (fni_ != NULL) fni_->Leave();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003004 // Parsed conditional expression only (no assignment).
3005 return expression;
3006 }
3007
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003008 // Signal a reference error if the expression is an invalid left-hand
3009 // side expression. We could report this as a syntax error here but
3010 // for compatibility with JSC we choose to report the error at
3011 // runtime.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003012 // TODO(ES5): Should change parsing for spec conformance.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003013 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003014 Handle<String> type =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003015 isolate()->factory()->invalid_lhs_in_assignment_string();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003016 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003017 }
3018
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003019 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003020 // Assignment to eval or arguments is disallowed in strict mode.
3021 CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK);
3022 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003023 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003024
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025 Token::Value op = Next(); // Get assignment operator.
3026 int pos = scanner().location().beg_pos;
3027 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
3028
3029 // TODO(1231235): We try to estimate the set of properties set by
3030 // constructors. We define a new property whenever there is an
3031 // assignment to a property of 'this'. We should probably only add
3032 // properties if we haven't seen them before. Otherwise we'll
3033 // probably overestimate the number of properties.
3034 Property* property = expression ? expression->AsProperty() : NULL;
3035 if (op == Token::ASSIGN &&
3036 property != NULL &&
3037 property->obj()->AsVariableProxy() != NULL &&
3038 property->obj()->AsVariableProxy()->is_this()) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003039 current_function_state_->AddProperty();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003040 }
3041
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003042 // If we assign a function literal to a property we pretenure the
3043 // literal so it can be added as a constant function property.
3044 if (property != NULL && right->AsFunctionLiteral() != NULL) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003045 right->AsFunctionLiteral()->set_pretenure();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003046 }
3047
ricow@chromium.org65fae842010-08-25 15:26:24 +00003048 if (fni_ != NULL) {
3049 // Check if the right hand side is a call to avoid inferring a
3050 // name if we're dealing with "a = function(){...}();"-like
3051 // expression.
3052 if ((op == Token::INIT_VAR
3053 || op == Token::INIT_CONST
3054 || op == Token::ASSIGN)
ager@chromium.org04921a82011-06-27 13:21:41 +00003055 && (right->AsCall() == NULL && right->AsCallNew() == NULL)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003056 fni_->Infer();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003057 } else {
3058 fni_->RemoveLastFunction();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003059 }
3060 fni_->Leave();
3061 }
3062
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003063 return factory()->NewAssignment(op, expression, right, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003064}
3065
3066
3067// Precedence = 3
3068Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
3069 // ConditionalExpression ::
3070 // LogicalOrExpression
3071 // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
3072
3073 // We start using the binary expression parser for prec >= 4 only!
3074 Expression* expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
3075 if (peek() != Token::CONDITIONAL) return expression;
3076 Consume(Token::CONDITIONAL);
3077 // In parsing the first assignment expression in conditional
3078 // expressions we always accept the 'in' keyword; see ECMA-262,
3079 // section 11.12, page 58.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003080 int left_position = scanner().peek_location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003081 Expression* left = ParseAssignmentExpression(true, CHECK_OK);
3082 Expect(Token::COLON, CHECK_OK);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003083 int right_position = scanner().peek_location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003084 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003085 return factory()->NewConditional(
3086 expression, left, right, left_position, right_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003087}
3088
3089
3090static int Precedence(Token::Value tok, bool accept_IN) {
3091 if (tok == Token::IN && !accept_IN)
3092 return 0; // 0 precedence will terminate binary expression parsing
3093
3094 return Token::Precedence(tok);
3095}
3096
3097
3098// Precedence >= 4
3099Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
3100 ASSERT(prec >= 4);
3101 Expression* x = ParseUnaryExpression(CHECK_OK);
3102 for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
3103 // prec1 >= 4
3104 while (Precedence(peek(), accept_IN) == prec1) {
3105 Token::Value op = Next();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003106 int position = scanner().location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003107 Expression* y = ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
3108
3109 // Compute some expressions involving only number literals.
3110 if (x && x->AsLiteral() && x->AsLiteral()->handle()->IsNumber() &&
3111 y && y->AsLiteral() && y->AsLiteral()->handle()->IsNumber()) {
3112 double x_val = x->AsLiteral()->handle()->Number();
3113 double y_val = y->AsLiteral()->handle()->Number();
3114
3115 switch (op) {
3116 case Token::ADD:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003117 x = factory()->NewNumberLiteral(x_val + y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003118 continue;
3119 case Token::SUB:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003120 x = factory()->NewNumberLiteral(x_val - y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003121 continue;
3122 case Token::MUL:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003123 x = factory()->NewNumberLiteral(x_val * y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003124 continue;
3125 case Token::DIV:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003126 x = factory()->NewNumberLiteral(x_val / y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003127 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003128 case Token::BIT_OR: {
3129 int value = DoubleToInt32(x_val) | DoubleToInt32(y_val);
3130 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003131 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003132 }
3133 case Token::BIT_AND: {
3134 int value = DoubleToInt32(x_val) & DoubleToInt32(y_val);
3135 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003136 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003137 }
3138 case Token::BIT_XOR: {
3139 int value = DoubleToInt32(x_val) ^ DoubleToInt32(y_val);
3140 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003141 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003142 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003143 case Token::SHL: {
3144 int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003145 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003146 continue;
3147 }
3148 case Token::SHR: {
3149 uint32_t shift = DoubleToInt32(y_val) & 0x1f;
3150 uint32_t value = DoubleToUint32(x_val) >> shift;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003151 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003152 continue;
3153 }
3154 case Token::SAR: {
3155 uint32_t shift = DoubleToInt32(y_val) & 0x1f;
3156 int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003157 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003158 continue;
3159 }
3160 default:
3161 break;
3162 }
3163 }
3164
3165 // For now we distinguish between comparisons and other binary
3166 // operations. (We could combine the two and get rid of this
ricow@chromium.org65fae842010-08-25 15:26:24 +00003167 // code and AST node eventually.)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003168 if (Token::IsCompareOp(op)) {
3169 // We have a comparison.
3170 Token::Value cmp = op;
3171 switch (op) {
3172 case Token::NE: cmp = Token::EQ; break;
3173 case Token::NE_STRICT: cmp = Token::EQ_STRICT; break;
3174 default: break;
3175 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003176 x = factory()->NewCompareOperation(cmp, x, y, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003177 if (cmp != op) {
3178 // The comparison was negated - add a NOT.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003179 x = factory()->NewUnaryOperation(Token::NOT, x, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003180 }
3181
3182 } else {
3183 // We have a "normal" binary operation.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003184 x = factory()->NewBinaryOperation(op, x, y, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003185 }
3186 }
3187 }
3188 return x;
3189}
3190
3191
3192Expression* Parser::ParseUnaryExpression(bool* ok) {
3193 // UnaryExpression ::
3194 // PostfixExpression
3195 // 'delete' UnaryExpression
3196 // 'void' UnaryExpression
3197 // 'typeof' UnaryExpression
3198 // '++' UnaryExpression
3199 // '--' UnaryExpression
3200 // '+' UnaryExpression
3201 // '-' UnaryExpression
3202 // '~' UnaryExpression
3203 // '!' UnaryExpression
3204
3205 Token::Value op = peek();
3206 if (Token::IsUnaryOp(op)) {
3207 op = Next();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003208 int position = scanner().location().beg_pos;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003209 Expression* expression = ParseUnaryExpression(CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003210
whesse@chromium.org7b260152011-06-20 15:33:18 +00003211 if (expression != NULL && (expression->AsLiteral() != NULL)) {
3212 Handle<Object> literal = expression->AsLiteral()->handle();
3213 if (op == Token::NOT) {
3214 // Convert the literal to a boolean condition and negate it.
3215 bool condition = literal->ToBoolean()->IsTrue();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003216 Handle<Object> result(isolate()->heap()->ToBoolean(!condition),
3217 isolate());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003218 return factory()->NewLiteral(result);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003219 } else if (literal->IsNumber()) {
3220 // Compute some expressions involving only number literals.
3221 double value = literal->Number();
3222 switch (op) {
3223 case Token::ADD:
3224 return expression;
3225 case Token::SUB:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003226 return factory()->NewNumberLiteral(-value);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003227 case Token::BIT_NOT:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003228 return factory()->NewNumberLiteral(~DoubleToInt32(value));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003229 default:
3230 break;
3231 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003232 }
3233 }
3234
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003235 // "delete identifier" is a syntax error in strict mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003236 if (op == Token::DELETE && !top_scope_->is_classic_mode()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003237 VariableProxy* operand = expression->AsVariableProxy();
3238 if (operand != NULL && !operand->is_this()) {
3239 ReportMessage("strict_delete", Vector<const char*>::empty());
3240 *ok = false;
3241 return NULL;
3242 }
3243 }
3244
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003245 return factory()->NewUnaryOperation(op, expression, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003246
3247 } else if (Token::IsCountOp(op)) {
3248 op = Next();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003249 Expression* expression = ParseUnaryExpression(CHECK_OK);
3250 // Signal a reference error if the expression is an invalid
3251 // left-hand side expression. We could report this as a syntax
3252 // error here but for compatibility with JSC we choose to report the
3253 // error at runtime.
3254 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003255 Handle<String> type =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003256 isolate()->factory()->invalid_lhs_in_prefix_op_string();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003257 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003258 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003259
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003260 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003261 // Prefix expression operand in strict mode may not be eval or arguments.
3262 CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
3263 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003264 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003265
ricow@chromium.org65fae842010-08-25 15:26:24 +00003266 int position = scanner().location().beg_pos;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003267 return factory()->NewCountOperation(op,
3268 true /* prefix */,
3269 expression,
3270 position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003271
3272 } else {
3273 return ParsePostfixExpression(ok);
3274 }
3275}
3276
3277
3278Expression* Parser::ParsePostfixExpression(bool* ok) {
3279 // PostfixExpression ::
3280 // LeftHandSideExpression ('++' | '--')?
3281
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003282 Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00003283 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003284 Token::IsCountOp(peek())) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003285 // Signal a reference error if the expression is an invalid
3286 // left-hand side expression. We could report this as a syntax
3287 // error here but for compatibility with JSC we choose to report the
3288 // error at runtime.
3289 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003290 Handle<String> type =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003291 isolate()->factory()->invalid_lhs_in_postfix_op_string();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003292 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003293 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003294
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003295 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003296 // Postfix expression operand in strict mode may not be eval or arguments.
3297 CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
3298 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003299 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003300
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003301 Token::Value next = Next();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003302 int position = scanner().location().beg_pos;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003303 expression =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003304 factory()->NewCountOperation(next,
3305 false /* postfix */,
3306 expression,
3307 position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003308 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003309 return expression;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003310}
3311
3312
3313Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
3314 // LeftHandSideExpression ::
3315 // (NewExpression | MemberExpression) ...
3316
3317 Expression* result;
3318 if (peek() == Token::NEW) {
3319 result = ParseNewExpression(CHECK_OK);
3320 } else {
3321 result = ParseMemberExpression(CHECK_OK);
3322 }
3323
3324 while (true) {
3325 switch (peek()) {
3326 case Token::LBRACK: {
3327 Consume(Token::LBRACK);
3328 int pos = scanner().location().beg_pos;
3329 Expression* index = ParseExpression(true, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003330 result = factory()->NewProperty(result, index, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003331 Expect(Token::RBRACK, CHECK_OK);
3332 break;
3333 }
3334
3335 case Token::LPAREN: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003336 int pos;
3337 if (scanner().current_token() == Token::IDENTIFIER) {
3338 // For call of an identifier we want to report position of
3339 // the identifier as position of the call in the stack trace.
3340 pos = scanner().location().beg_pos;
3341 } else {
3342 // For other kinds of calls we record position of the parenthesis as
3343 // position of the call. Note that this is extremely important for
3344 // expressions of the form function(){...}() for which call position
3345 // should not point to the closing brace otherwise it will intersect
3346 // with positions recorded for function literal and confuse debugger.
3347 pos = scanner().peek_location().beg_pos;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003348 // Also the trailing parenthesis are a hint that the function will
3349 // be called immediately. If we happen to have parsed a preceding
3350 // function literal eagerly, we can also compile it eagerly.
3351 if (result->IsFunctionLiteral() && mode() == PARSE_EAGERLY) {
3352 result->AsFunctionLiteral()->set_parenthesized();
3353 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003354 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003355 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
3356
3357 // Keep track of eval() calls since they disable all local variable
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003358 // optimizations.
3359 // The calls that need special treatment are the
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003360 // direct eval calls. These calls are all of the form eval(...), with
3361 // no explicit receiver.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003362 // These calls are marked as potentially direct eval calls. Whether
3363 // they are actually direct calls to eval is determined at run time.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003364 VariableProxy* callee = result->AsVariableProxy();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003365 if (callee != NULL &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003366 callee->IsVariable(isolate()->factory()->eval_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003367 top_scope_->DeclarationScope()->RecordEvalCall();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003368 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003369 result = factory()->NewCall(result, args, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370 break;
3371 }
3372
3373 case Token::PERIOD: {
3374 Consume(Token::PERIOD);
3375 int pos = scanner().location().beg_pos;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003376 Handle<String> name = ParseIdentifierName(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003377 result =
3378 factory()->NewProperty(result, factory()->NewLiteral(name), pos);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003379 if (fni_ != NULL) fni_->PushLiteralName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003380 break;
3381 }
3382
3383 default:
3384 return result;
3385 }
3386 }
3387}
3388
3389
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003390Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003391 // NewExpression ::
3392 // ('new')+ MemberExpression
3393
3394 // The grammar for new expressions is pretty warped. The keyword
3395 // 'new' can either be a part of the new expression (where it isn't
3396 // followed by an argument list) or a part of the member expression,
3397 // where it must be followed by an argument list. To accommodate
3398 // this, we parse the 'new' keywords greedily and keep track of how
3399 // many we have parsed. This information is then passed on to the
3400 // member expression parser, which is only allowed to match argument
3401 // lists as long as it has 'new' prefixes left
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003402 Expect(Token::NEW, CHECK_OK);
3403 PositionStack::Element pos(stack, scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003404
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003405 Expression* result;
3406 if (peek() == Token::NEW) {
3407 result = ParseNewPrefix(stack, CHECK_OK);
3408 } else {
3409 result = ParseMemberWithNewPrefixesExpression(stack, CHECK_OK);
3410 }
3411
3412 if (!stack->is_empty()) {
3413 int last = stack->pop();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003414 result = factory()->NewCallNew(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003415 result, new(zone()) ZoneList<Expression*>(0, zone()), last);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003416 }
3417 return result;
3418}
3419
3420
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003421Expression* Parser::ParseNewExpression(bool* ok) {
3422 PositionStack stack(ok);
3423 return ParseNewPrefix(&stack, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424}
3425
3426
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003427Expression* Parser::ParseMemberExpression(bool* ok) {
3428 return ParseMemberWithNewPrefixesExpression(NULL, ok);
3429}
3430
3431
3432Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
3433 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003434 // MemberExpression ::
3435 // (PrimaryExpression | FunctionLiteral)
3436 // ('[' Expression ']' | '.' Identifier | Arguments)*
3437
3438 // Parse the initial primary or function expression.
3439 Expression* result = NULL;
3440 if (peek() == Token::FUNCTION) {
3441 Expect(Token::FUNCTION, CHECK_OK);
3442 int function_token_position = scanner().location().beg_pos;
3443 Handle<String> name;
ager@chromium.org04921a82011-06-27 13:21:41 +00003444 bool is_strict_reserved_name = false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003445 if (peek_any_identifier()) {
ager@chromium.org04921a82011-06-27 13:21:41 +00003446 name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
3447 CHECK_OK);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003448 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003449 FunctionLiteral::Type type = name.is_null()
3450 ? FunctionLiteral::ANONYMOUS_EXPRESSION
3451 : FunctionLiteral::NAMED_EXPRESSION;
3452 result = ParseFunctionLiteral(name,
3453 is_strict_reserved_name,
3454 function_token_position,
3455 type,
3456 CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457 } else {
3458 result = ParsePrimaryExpression(CHECK_OK);
3459 }
3460
3461 while (true) {
3462 switch (peek()) {
3463 case Token::LBRACK: {
3464 Consume(Token::LBRACK);
3465 int pos = scanner().location().beg_pos;
3466 Expression* index = ParseExpression(true, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003467 result = factory()->NewProperty(result, index, pos);
ager@chromium.org04921a82011-06-27 13:21:41 +00003468 if (fni_ != NULL) {
3469 if (index->IsPropertyName()) {
3470 fni_->PushLiteralName(index->AsLiteral()->AsPropertyName());
3471 } else {
3472 fni_->PushLiteralName(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003473 isolate()->factory()->anonymous_function_string());
ager@chromium.org04921a82011-06-27 13:21:41 +00003474 }
3475 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003476 Expect(Token::RBRACK, CHECK_OK);
3477 break;
3478 }
3479 case Token::PERIOD: {
3480 Consume(Token::PERIOD);
3481 int pos = scanner().location().beg_pos;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003482 Handle<String> name = ParseIdentifierName(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003483 result =
3484 factory()->NewProperty(result, factory()->NewLiteral(name), pos);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003485 if (fni_ != NULL) fni_->PushLiteralName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003486 break;
3487 }
3488 case Token::LPAREN: {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003489 if ((stack == NULL) || stack->is_empty()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003490 // Consume one of the new prefixes (already parsed).
3491 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003492 int last = stack->pop();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003493 result = factory()->NewCallNew(result, args, last);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003494 break;
3495 }
3496 default:
3497 return result;
3498 }
3499 }
3500}
3501
3502
3503DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
3504 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
3505 // contexts this is used as a statement which invokes the debugger as i a
3506 // break point is present.
3507 // DebuggerStatement ::
3508 // 'debugger' ';'
3509
3510 Expect(Token::DEBUGGER, CHECK_OK);
3511 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003512 return factory()->NewDebuggerStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513}
3514
3515
3516void Parser::ReportUnexpectedToken(Token::Value token) {
3517 // We don't report stack overflows here, to avoid increasing the
3518 // stack depth even further. Instead we report it after parsing is
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003519 // over, in ParseProgram/ParseJson.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003520 if (token == Token::ILLEGAL && stack_overflow_) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 // Four of the tokens are treated specially
3522 switch (token) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003523 case Token::EOS:
3524 return ReportMessage("unexpected_eos", Vector<const char*>::empty());
3525 case Token::NUMBER:
3526 return ReportMessage("unexpected_token_number",
3527 Vector<const char*>::empty());
3528 case Token::STRING:
3529 return ReportMessage("unexpected_token_string",
3530 Vector<const char*>::empty());
3531 case Token::IDENTIFIER:
3532 return ReportMessage("unexpected_token_identifier",
3533 Vector<const char*>::empty());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003534 case Token::FUTURE_RESERVED_WORD:
ager@chromium.org04921a82011-06-27 13:21:41 +00003535 return ReportMessage("unexpected_reserved",
3536 Vector<const char*>::empty());
3537 case Token::FUTURE_STRICT_RESERVED_WORD:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003538 return ReportMessage(top_scope_->is_classic_mode() ?
3539 "unexpected_token_identifier" :
3540 "unexpected_strict_reserved",
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003541 Vector<const char*>::empty());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003542 default:
3543 const char* name = Token::String(token);
3544 ASSERT(name != NULL);
3545 ReportMessage("unexpected_token", Vector<const char*>(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546 }
3547}
3548
3549
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003550void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003551 SmartArrayPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003552 const char* element[1] = { *name_string };
3553 ReportMessage("invalid_preparser_data",
3554 Vector<const char*>(element, 1));
3555 *ok = false;
3556}
3557
3558
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003559Expression* Parser::ParsePrimaryExpression(bool* ok) {
3560 // PrimaryExpression ::
3561 // 'this'
3562 // 'null'
3563 // 'true'
3564 // 'false'
3565 // Identifier
3566 // Number
3567 // String
3568 // ArrayLiteral
3569 // ObjectLiteral
3570 // RegExpLiteral
3571 // '(' Expression ')'
3572
3573 Expression* result = NULL;
3574 switch (peek()) {
3575 case Token::THIS: {
3576 Consume(Token::THIS);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003577 result = factory()->NewVariableProxy(top_scope_->receiver());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003578 break;
3579 }
3580
3581 case Token::NULL_LITERAL:
3582 Consume(Token::NULL_LITERAL);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003583 result = factory()->NewLiteral(isolate()->factory()->null_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584 break;
3585
3586 case Token::TRUE_LITERAL:
3587 Consume(Token::TRUE_LITERAL);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003588 result = factory()->NewLiteral(isolate()->factory()->true_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003589 break;
3590
3591 case Token::FALSE_LITERAL:
3592 Consume(Token::FALSE_LITERAL);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003593 result = factory()->NewLiteral(isolate()->factory()->false_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003594 break;
3595
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003596 case Token::IDENTIFIER:
ager@chromium.org04921a82011-06-27 13:21:41 +00003597 case Token::FUTURE_STRICT_RESERVED_WORD: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 Handle<String> name = ParseIdentifier(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003599 if (fni_ != NULL) fni_->PushVariableName(name);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003600 // The name may refer to a module instance object, so its type is unknown.
3601#ifdef DEBUG
3602 if (FLAG_print_interface_details)
3603 PrintF("# Variable %s ", name->ToAsciiArray());
3604#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003605 Interface* interface = Interface::NewUnknown(zone());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003606 result = top_scope_->NewUnresolved(
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00003607 factory(), name, interface, scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003608 break;
3609 }
3610
3611 case Token::NUMBER: {
3612 Consume(Token::NUMBER);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003613 ASSERT(scanner().is_literal_ascii());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003614 double value = StringToDouble(isolate()->unicode_cache(),
3615 scanner().literal_ascii_string(),
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003616 ALLOW_HEX | ALLOW_OCTALS);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003617 result = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618 break;
3619 }
3620
3621 case Token::STRING: {
3622 Consume(Token::STRING);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003623 Handle<String> symbol = GetSymbol(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003624 result = factory()->NewLiteral(symbol);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003625 if (fni_ != NULL) fni_->PushLiteralName(symbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003626 break;
3627 }
3628
3629 case Token::ASSIGN_DIV:
3630 result = ParseRegExpLiteral(true, CHECK_OK);
3631 break;
3632
3633 case Token::DIV:
3634 result = ParseRegExpLiteral(false, CHECK_OK);
3635 break;
3636
3637 case Token::LBRACK:
3638 result = ParseArrayLiteral(CHECK_OK);
3639 break;
3640
3641 case Token::LBRACE:
3642 result = ParseObjectLiteral(CHECK_OK);
3643 break;
3644
3645 case Token::LPAREN:
3646 Consume(Token::LPAREN);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003647 // Heuristically try to detect immediately called functions before
3648 // seeing the call parentheses.
3649 parenthesized_function_ = (peek() == Token::FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003650 result = ParseExpression(true, CHECK_OK);
3651 Expect(Token::RPAREN, CHECK_OK);
3652 break;
3653
3654 case Token::MOD:
3655 if (allow_natives_syntax_ || extension_ != NULL) {
3656 result = ParseV8Intrinsic(CHECK_OK);
3657 break;
3658 }
3659 // If we're not allowing special syntax we fall-through to the
3660 // default case.
3661
3662 default: {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003663 Token::Value tok = Next();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003664 ReportUnexpectedToken(tok);
3665 *ok = false;
3666 return NULL;
3667 }
3668 }
3669
3670 return result;
3671}
3672
3673
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003674void Parser::BuildArrayLiteralBoilerplateLiterals(ZoneList<Expression*>* values,
3675 Handle<FixedArray> literals,
3676 bool* is_simple,
3677 int* depth) {
3678 // Fill in the literals.
3679 // Accumulate output values in local variables.
3680 bool is_simple_acc = true;
3681 int depth_acc = 1;
3682 for (int i = 0; i < values->length(); i++) {
3683 MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
3684 if (m_literal != NULL && m_literal->depth() >= depth_acc) {
3685 depth_acc = m_literal->depth() + 1;
3686 }
3687 Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
3688 if (boilerplate_value->IsUndefined()) {
3689 literals->set_the_hole(i);
3690 is_simple_acc = false;
3691 } else {
3692 literals->set(i, *boilerplate_value);
3693 }
3694 }
3695
3696 *is_simple = is_simple_acc;
3697 *depth = depth_acc;
3698}
3699
3700
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701Expression* Parser::ParseArrayLiteral(bool* ok) {
3702 // ArrayLiteral ::
3703 // '[' Expression? (',' Expression?)* ']'
3704
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003705 ZoneList<Expression*>* values = new(zone()) ZoneList<Expression*>(4, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003706 Expect(Token::LBRACK, CHECK_OK);
3707 while (peek() != Token::RBRACK) {
3708 Expression* elem;
3709 if (peek() == Token::COMMA) {
3710 elem = GetLiteralTheHole();
3711 } else {
3712 elem = ParseAssignmentExpression(true, CHECK_OK);
3713 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003714 values->Add(elem, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 if (peek() != Token::RBRACK) {
3716 Expect(Token::COMMA, CHECK_OK);
3717 }
3718 }
3719 Expect(Token::RBRACK, CHECK_OK);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003720
3721 // Update the scope information before the pre-parsing bailout.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003722 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003723
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003724 // Allocate a fixed array to hold all the object literals.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003725 Handle<JSArray> array =
3726 isolate()->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
3727 isolate()->factory()->SetElementsCapacityAndLength(
3728 array, values->length(), values->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003729
3730 // Fill in the literals.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003731 Heap* heap = isolate()->heap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003732 bool is_simple = true;
3733 int depth = 1;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003734 bool is_holey = false;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003735 for (int i = 0, n = values->length(); i < n; i++) {
3736 MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003737 if (m_literal != NULL && m_literal->depth() + 1 > depth) {
3738 depth = m_literal->depth() + 1;
3739 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003740 Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003741 if (boilerplate_value->IsTheHole()) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003742 is_holey = true;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003743 } else if (boilerplate_value->IsUndefined()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003744 is_simple = false;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003745 JSObject::SetOwnElement(
3746 array, i, handle(Smi::FromInt(0), isolate()), kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003747 } else {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003748 JSObject::SetOwnElement(array, i, boilerplate_value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 }
3750 }
3751
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003752 Handle<FixedArrayBase> element_values(array->elements());
3753
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003754 // Simple and shallow arrays can be lazily copied, we transform the
3755 // elements array to a copy-on-write array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003756 if (is_simple && depth == 1 && values->length() > 0 &&
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003757 array->HasFastSmiOrObjectElements()) {
3758 element_values->set_map(heap->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003759 }
3760
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003761 // Remember both the literal's constant values as well as the ElementsKind
3762 // in a 2-element FixedArray.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003763 Handle<FixedArray> literals = isolate()->factory()->NewFixedArray(2, TENURED);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003764
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003765 ElementsKind kind = array->GetElementsKind();
3766 kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003767
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003768 literals->set(0, Smi::FromInt(kind));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003769 literals->set(1, *element_values);
3770
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003771 return factory()->NewArrayLiteral(
3772 literals, values, literal_index, is_simple, depth);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773}
3774
3775
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003776bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) {
3777 return property != NULL &&
3778 property->kind() != ObjectLiteral::Property::PROTOTYPE;
3779}
3780
3781
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003782bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003783 if (expression->AsLiteral() != NULL) return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003784 MaterializedLiteral* lit = expression->AsMaterializedLiteral();
3785 return lit != NULL && lit->is_simple();
3786}
3787
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003788
3789bool CompileTimeValue::ArrayLiteralElementNeedsInitialization(
3790 Expression* value) {
3791 // If value is a literal the property value is already set in the
3792 // boilerplate object.
3793 if (value->AsLiteral() != NULL) return false;
3794 // If value is a materialized literal the property value is already set
3795 // in the boilerplate object if it is simple.
3796 if (CompileTimeValue::IsCompileTimeValue(value)) return false;
3797 return true;
3798}
3799
3800
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003801Handle<FixedArray> CompileTimeValue::GetValue(Expression* expression) {
3802 ASSERT(IsCompileTimeValue(expression));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003803 Handle<FixedArray> result = FACTORY->NewFixedArray(2, TENURED);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003804 ObjectLiteral* object_literal = expression->AsObjectLiteral();
3805 if (object_literal != NULL) {
3806 ASSERT(object_literal->is_simple());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003807 if (object_literal->fast_elements()) {
3808 result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS));
3809 } else {
3810 result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS));
3811 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003812 result->set(kElementsSlot, *object_literal->constant_properties());
3813 } else {
3814 ArrayLiteral* array_literal = expression->AsArrayLiteral();
3815 ASSERT(array_literal != NULL && array_literal->is_simple());
3816 result->set(kTypeSlot, Smi::FromInt(ARRAY_LITERAL));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003817 result->set(kElementsSlot, *array_literal->constant_elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003818 }
3819 return result;
3820}
3821
3822
3823CompileTimeValue::Type CompileTimeValue::GetType(Handle<FixedArray> value) {
3824 Smi* type_value = Smi::cast(value->get(kTypeSlot));
3825 return static_cast<Type>(type_value->value());
3826}
3827
3828
3829Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
3830 return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot)));
3831}
3832
3833
3834Handle<Object> Parser::GetBoilerplateValue(Expression* expression) {
3835 if (expression->AsLiteral() != NULL) {
3836 return expression->AsLiteral()->handle();
3837 }
3838 if (CompileTimeValue::IsCompileTimeValue(expression)) {
3839 return CompileTimeValue::GetValue(expression);
3840 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003841 return isolate()->factory()->undefined_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003842}
3843
ager@chromium.org378b34e2011-01-28 08:04:38 +00003844// Validation per 11.1.5 Object Initialiser
3845class ObjectLiteralPropertyChecker {
3846 public:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003847 ObjectLiteralPropertyChecker(Parser* parser, LanguageMode language_mode) :
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003848 props_(Literal::Match),
ager@chromium.org378b34e2011-01-28 08:04:38 +00003849 parser_(parser),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003850 language_mode_(language_mode) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003851 }
3852
3853 void CheckProperty(
3854 ObjectLiteral::Property* property,
3855 Scanner::Location loc,
3856 bool* ok);
3857
3858 private:
3859 enum PropertyKind {
3860 kGetAccessor = 0x01,
3861 kSetAccessor = 0x02,
3862 kAccessor = kGetAccessor | kSetAccessor,
3863 kData = 0x04
3864 };
3865
3866 static intptr_t GetPropertyKind(ObjectLiteral::Property* property) {
3867 switch (property->kind()) {
3868 case ObjectLiteral::Property::GETTER:
3869 return kGetAccessor;
3870 case ObjectLiteral::Property::SETTER:
3871 return kSetAccessor;
3872 default:
3873 return kData;
3874 }
3875 }
3876
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003877 HashMap props_;
ager@chromium.org378b34e2011-01-28 08:04:38 +00003878 Parser* parser_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003879 LanguageMode language_mode_;
ager@chromium.org378b34e2011-01-28 08:04:38 +00003880};
3881
3882
3883void ObjectLiteralPropertyChecker::CheckProperty(
3884 ObjectLiteral::Property* property,
3885 Scanner::Location loc,
3886 bool* ok) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003887 ASSERT(property != NULL);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003888 Literal* literal = property->key();
3889 HashMap::Entry* entry = props_.Lookup(literal, literal->Hash(), true);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003890 intptr_t prev = reinterpret_cast<intptr_t> (entry->value);
3891 intptr_t curr = GetPropertyKind(property);
3892
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003893 // Duplicate data properties are illegal in strict or extended mode.
3894 if (language_mode_ != CLASSIC_MODE && (curr & prev & kData) != 0) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003895 parser_->ReportMessageAt(loc, "strict_duplicate_property",
3896 Vector<const char*>::empty());
3897 *ok = false;
3898 return;
3899 }
3900 // Data property conflicting with an accessor.
3901 if (((curr & kData) && (prev & kAccessor)) ||
3902 ((prev & kData) && (curr & kAccessor))) {
3903 parser_->ReportMessageAt(loc, "accessor_data_property",
3904 Vector<const char*>::empty());
3905 *ok = false;
3906 return;
3907 }
3908 // Two accessors of the same type conflicting
3909 if ((curr & prev & kAccessor) != 0) {
3910 parser_->ReportMessageAt(loc, "accessor_get_set",
3911 Vector<const char*>::empty());
3912 *ok = false;
3913 return;
3914 }
3915
3916 // Update map
3917 entry->value = reinterpret_cast<void*> (prev | curr);
3918 *ok = true;
3919}
3920
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003921
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003922void Parser::BuildObjectLiteralConstantProperties(
3923 ZoneList<ObjectLiteral::Property*>* properties,
3924 Handle<FixedArray> constant_properties,
3925 bool* is_simple,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003926 bool* fast_elements,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003927 int* depth) {
3928 int position = 0;
3929 // Accumulate the value in local variables and store it at the end.
3930 bool is_simple_acc = true;
3931 int depth_acc = 1;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003932 uint32_t max_element_index = 0;
3933 uint32_t elements = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003934 for (int i = 0; i < properties->length(); i++) {
3935 ObjectLiteral::Property* property = properties->at(i);
3936 if (!IsBoilerplateProperty(property)) {
3937 is_simple_acc = false;
3938 continue;
3939 }
3940 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
3941 if (m_literal != NULL && m_literal->depth() >= depth_acc) {
3942 depth_acc = m_literal->depth() + 1;
3943 }
3944
3945 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
3946 // value for COMPUTED properties, the real value is filled in at
3947 // runtime. The enumeration order is maintained.
3948 Handle<Object> key = property->key()->handle();
3949 Handle<Object> value = GetBoilerplateValue(property->value());
3950 is_simple_acc = is_simple_acc && !value->IsUndefined();
3951
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003952 // Keep track of the number of elements in the object literal and
3953 // the largest element index. If the largest element index is
3954 // much larger than the number of elements, creating an object
3955 // literal with fast elements will be a waste of space.
3956 uint32_t element_index = 0;
3957 if (key->IsString()
3958 && Handle<String>::cast(key)->AsArrayIndex(&element_index)
3959 && element_index > max_element_index) {
3960 max_element_index = element_index;
3961 elements++;
3962 } else if (key->IsSmi()) {
3963 int key_value = Smi::cast(*key)->value();
3964 if (key_value > 0
3965 && static_cast<uint32_t>(key_value) > max_element_index) {
3966 max_element_index = key_value;
3967 }
3968 elements++;
3969 }
3970
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003971 // Add name, value pair to the fixed array.
3972 constant_properties->set(position++, *key);
3973 constant_properties->set(position++, *value);
3974 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003975 *fast_elements =
3976 (max_element_index <= 32) || ((2 * elements) >= max_element_index);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003977 *is_simple = is_simple_acc;
3978 *depth = depth_acc;
3979}
3980
3981
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003982ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter,
3983 bool* ok) {
3984 // Special handling of getter and setter syntax:
3985 // { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... }
3986 // We have already read the "get" or "set" keyword.
3987 Token::Value next = Next();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003988 bool is_keyword = Token::IsKeyword(next);
3989 if (next == Token::IDENTIFIER || next == Token::NUMBER ||
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003990 next == Token::FUTURE_RESERVED_WORD ||
ager@chromium.org04921a82011-06-27 13:21:41 +00003991 next == Token::FUTURE_STRICT_RESERVED_WORD ||
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003992 next == Token::STRING || is_keyword) {
3993 Handle<String> name;
3994 if (is_keyword) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003995 name = isolate_->factory()->InternalizeUtf8String(Token::String(next));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003996 } else {
3997 name = GetSymbol(CHECK_OK);
3998 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003999 FunctionLiteral* value =
4000 ParseFunctionLiteral(name,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004001 false, // reserved words are allowed here
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004002 RelocInfo::kNoPosition,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004003 FunctionLiteral::ANONYMOUS_EXPRESSION,
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004004 CHECK_OK);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004005 // Allow any number of parameters for compatibilty with JSC.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004006 // Specification only allows zero parameters for get and one for set.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004007 return factory()->NewObjectLiteralProperty(is_getter, value);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004008 } else {
4009 ReportUnexpectedToken(next);
4010 *ok = false;
4011 return NULL;
4012 }
4013}
4014
4015
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016Expression* Parser::ParseObjectLiteral(bool* ok) {
4017 // ObjectLiteral ::
4018 // '{' (
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004019 // ((IdentifierName | String | Number) ':' AssignmentExpression)
4020 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 // )*[','] '}'
4022
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004023 ZoneList<ObjectLiteral::Property*>* properties =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004024 new(zone()) ZoneList<ObjectLiteral::Property*>(4, zone());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004025 int number_of_boilerplate_properties = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004026 bool has_function = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004028 ObjectLiteralPropertyChecker checker(this, top_scope_->language_mode());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004029
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030 Expect(Token::LBRACE, CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004031
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 while (peek() != Token::RBRACE) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004033 if (fni_ != NULL) fni_->Enter();
4034
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004035 Literal* key = NULL;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004036 Token::Value next = peek();
ager@chromium.org378b34e2011-01-28 08:04:38 +00004037
4038 // Location of the property name token
4039 Scanner::Location loc = scanner().peek_location();
4040
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004041 switch (next) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004042 case Token::FUTURE_RESERVED_WORD:
ager@chromium.org04921a82011-06-27 13:21:41 +00004043 case Token::FUTURE_STRICT_RESERVED_WORD:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004044 case Token::IDENTIFIER: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 bool is_getter = false;
4046 bool is_setter = false;
4047 Handle<String> id =
ager@chromium.org04921a82011-06-27 13:21:41 +00004048 ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004049 if (fni_ != NULL) fni_->PushLiteralName(id);
4050
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004051 if ((is_getter || is_setter) && peek() != Token::COLON) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00004052 // Update loc to point to the identifier
4053 loc = scanner().peek_location();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 ObjectLiteral::Property* property =
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004055 ParseObjectLiteralGetSet(is_getter, CHECK_OK);
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004056 if (IsBoilerplateProperty(property)) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004057 number_of_boilerplate_properties++;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004058 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004059 // Validate the property.
4060 checker.CheckProperty(property, loc, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004061 properties->Add(property, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004063
4064 if (fni_ != NULL) {
4065 fni_->Infer();
4066 fni_->Leave();
4067 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004068 continue; // restart the while
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004070 // Failed to parse as get/set property, so it's just a property
4071 // called "get" or "set".
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004072 key = factory()->NewLiteral(id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 break;
4074 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 case Token::STRING: {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004076 Consume(Token::STRING);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004077 Handle<String> string = GetSymbol(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004078 if (fni_ != NULL) fni_->PushLiteralName(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 uint32_t index;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00004080 if (!string.is_null() && string->AsArrayIndex(&index)) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004081 key = factory()->NewNumberLiteral(index);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004082 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004083 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004084 key = factory()->NewLiteral(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004085 break;
4086 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004087 case Token::NUMBER: {
4088 Consume(Token::NUMBER);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004089 ASSERT(scanner().is_literal_ascii());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004090 double value = StringToDouble(isolate()->unicode_cache(),
4091 scanner().literal_ascii_string(),
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004092 ALLOW_HEX | ALLOW_OCTALS);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004093 key = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 break;
4095 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 default:
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004097 if (Token::IsKeyword(next)) {
4098 Consume(next);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004099 Handle<String> string = GetSymbol(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004100 key = factory()->NewLiteral(string);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004101 } else {
4102 // Unexpected token.
4103 Token::Value next = Next();
4104 ReportUnexpectedToken(next);
4105 *ok = false;
4106 return NULL;
4107 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108 }
4109
4110 Expect(Token::COLON, CHECK_OK);
4111 Expression* value = ParseAssignmentExpression(true, CHECK_OK);
4112
4113 ObjectLiteral::Property* property =
ulan@chromium.org812308e2012-02-29 15:58:45 +00004114 new(zone()) ObjectLiteral::Property(key, value, isolate());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004115
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00004116 // Mark top-level object literals that contain function literals and
4117 // pretenure the literal so it can be added as a constant function
4118 // property.
4119 if (top_scope_->DeclarationScope()->is_global_scope() &&
4120 value->AsFunctionLiteral() != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004121 has_function = true;
danno@chromium.orgc612e022011-11-10 11:38:15 +00004122 value->AsFunctionLiteral()->set_pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004123 }
4124
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004125 // Count CONSTANT or COMPUTED properties to maintain the enumeration order.
ager@chromium.org236ad962008-09-25 09:45:57 +00004126 if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++;
ager@chromium.org378b34e2011-01-28 08:04:38 +00004127 // Validate the property
4128 checker.CheckProperty(property, loc, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004129 properties->Add(property, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004130
4131 // TODO(1240767): Consider allowing trailing comma.
4132 if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004133
4134 if (fni_ != NULL) {
4135 fni_->Infer();
4136 fni_->Leave();
4137 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138 }
4139 Expect(Token::RBRACE, CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004140
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141 // Computation of literal_index must happen before pre parse bailout.
danno@chromium.orgc612e022011-11-10 11:38:15 +00004142 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004144 Handle<FixedArray> constant_properties = isolate()->factory()->NewFixedArray(
4145 number_of_boilerplate_properties * 2, TENURED);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004146
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004147 bool is_simple = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004148 bool fast_elements = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004149 int depth = 1;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004150 BuildObjectLiteralConstantProperties(properties,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004151 constant_properties,
4152 &is_simple,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004153 &fast_elements,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004154 &depth);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004155 return factory()->NewObjectLiteral(constant_properties,
4156 properties,
4157 literal_index,
4158 is_simple,
4159 fast_elements,
4160 depth,
4161 has_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004162}
4163
4164
4165Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004166 if (!scanner().ScanRegExpPattern(seen_equal)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004167 Next();
4168 ReportMessage("unterminated_regexp", Vector<const char*>::empty());
4169 *ok = false;
4170 return NULL;
4171 }
4172
danno@chromium.orgc612e022011-11-10 11:38:15 +00004173 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004174
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004175 Handle<String> js_pattern = NextLiteralString(TENURED);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004176 scanner().ScanRegExpFlags();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004177 Handle<String> js_flags = NextLiteralString(TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004178 Next();
4179
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004180 return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181}
4182
4183
4184ZoneList<Expression*>* Parser::ParseArguments(bool* ok) {
4185 // Arguments ::
4186 // '(' (AssignmentExpression)*[','] ')'
4187
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004188 ZoneList<Expression*>* result = new(zone()) ZoneList<Expression*>(4, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189 Expect(Token::LPAREN, CHECK_OK);
4190 bool done = (peek() == Token::RPAREN);
4191 while (!done) {
4192 Expression* argument = ParseAssignmentExpression(true, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004193 result->Add(argument, zone());
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004194 if (result->length() > kMaxNumFunctionParameters) {
4195 ReportMessageAt(scanner().location(), "too_many_arguments",
4196 Vector<const char*>::empty());
4197 *ok = false;
4198 return NULL;
4199 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 done = (peek() == Token::RPAREN);
4201 if (!done) Expect(Token::COMMA, CHECK_OK);
4202 }
4203 Expect(Token::RPAREN, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004204 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205}
4206
4207
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004208class SingletonLogger : public ParserRecorder {
4209 public:
4210 SingletonLogger() : has_error_(false), start_(-1), end_(-1) { }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004211 virtual ~SingletonLogger() { }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004212
4213 void Reset() { has_error_ = false; }
4214
4215 virtual void LogFunction(int start,
4216 int end,
4217 int literals,
4218 int properties,
4219 LanguageMode mode) {
4220 ASSERT(!has_error_);
4221 start_ = start;
4222 end_ = end;
4223 literals_ = literals;
4224 properties_ = properties;
4225 mode_ = mode;
4226 };
4227
4228 // Logs a symbol creation of a literal or identifier.
4229 virtual void LogAsciiSymbol(int start, Vector<const char> literal) { }
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004230 virtual void LogUtf16Symbol(int start, Vector<const uc16> literal) { }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004231
4232 // Logs an error message and marks the log as containing an error.
4233 // Further logging will be ignored, and ExtractData will return a vector
4234 // representing the error only.
4235 virtual void LogMessage(int start,
4236 int end,
4237 const char* message,
4238 const char* argument_opt) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004239 if (has_error_) return;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004240 has_error_ = true;
4241 start_ = start;
4242 end_ = end;
4243 message_ = message;
4244 argument_opt_ = argument_opt;
4245 }
4246
4247 virtual int function_position() { return 0; }
4248
4249 virtual int symbol_position() { return 0; }
4250
4251 virtual int symbol_ids() { return -1; }
4252
4253 virtual Vector<unsigned> ExtractData() {
4254 UNREACHABLE();
4255 return Vector<unsigned>();
4256 }
4257
4258 virtual void PauseRecording() { }
4259
4260 virtual void ResumeRecording() { }
4261
4262 bool has_error() { return has_error_; }
4263
4264 int start() { return start_; }
4265 int end() { return end_; }
4266 int literals() {
4267 ASSERT(!has_error_);
4268 return literals_;
4269 }
4270 int properties() {
4271 ASSERT(!has_error_);
4272 return properties_;
4273 }
4274 LanguageMode language_mode() {
4275 ASSERT(!has_error_);
4276 return mode_;
4277 }
4278 const char* message() {
4279 ASSERT(has_error_);
4280 return message_;
4281 }
4282 const char* argument_opt() {
4283 ASSERT(has_error_);
4284 return argument_opt_;
4285 }
4286
4287 private:
4288 bool has_error_;
4289 int start_;
4290 int end_;
4291 // For function entries.
4292 int literals_;
4293 int properties_;
4294 LanguageMode mode_;
4295 // For error messages.
4296 const char* message_;
4297 const char* argument_opt_;
4298};
4299
4300
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004301FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
ager@chromium.org04921a82011-06-27 13:21:41 +00004302 bool name_is_strict_reserved,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004303 int function_token_position,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004304 FunctionLiteral::Type type,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004305 bool* ok) {
4306 // Function ::
4307 // '(' FormalParameterList? ')' '{' FunctionBody '}'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004308
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004309 // Anonymous functions were passed either the empty symbol or a null
4310 // handle as the function name. Remember if we were passed a non-empty
4311 // handle to decide whether to invoke function name inference.
4312 bool should_infer_name = function_name.is_null();
4313
4314 // We want a non-null handle as the function name.
4315 if (should_infer_name) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004316 function_name = isolate()->factory()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004317 }
4318
4319 int num_parameters = 0;
danno@chromium.orgb6451162011-08-17 14:33:23 +00004320 // Function declarations are function scoped in normal mode, so they are
4321 // hoisted. In harmony block scoping mode they are block scoped, so they
4322 // are not hoisted.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004323 Scope* scope = (type == FunctionLiteral::DECLARATION && !is_extended_mode())
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004324 ? NewScope(top_scope_->DeclarationScope(), FUNCTION_SCOPE)
4325 : NewScope(top_scope_, FUNCTION_SCOPE);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004326 ZoneList<Statement*>* body = NULL;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004327 int materialized_literal_count = -1;
4328 int expected_property_count = -1;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004329 int handler_count = 0;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004330 bool only_simple_this_property_assignments;
4331 Handle<FixedArray> this_property_assignments;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004332 FunctionLiteral::ParameterFlag duplicate_parameters =
4333 FunctionLiteral::kNoDuplicateParameters;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004334 FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_
4335 ? FunctionLiteral::kIsParenthesized
4336 : FunctionLiteral::kNotParenthesized;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004337 AstProperties ast_properties;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004338 // Parse function body.
danno@chromium.orgc612e022011-11-10 11:38:15 +00004339 { FunctionState function_state(this, scope, isolate());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004340 top_scope_->SetScopeName(function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004341
4342 // FormalParameterList ::
4343 // '(' (Identifier)*[','] ')'
4344 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004345 scope->set_start_position(scanner().location().beg_pos);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004346 Scanner::Location name_loc = Scanner::Location::invalid();
4347 Scanner::Location dupe_loc = Scanner::Location::invalid();
4348 Scanner::Location reserved_loc = Scanner::Location::invalid();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004349
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004350 bool done = (peek() == Token::RPAREN);
4351 while (!done) {
ager@chromium.org04921a82011-06-27 13:21:41 +00004352 bool is_strict_reserved = false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004353 Handle<String> param_name =
ager@chromium.org04921a82011-06-27 13:21:41 +00004354 ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
4355 CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004356
4357 // Store locations for possible future error reports.
4358 if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) {
4359 name_loc = scanner().location();
4360 }
4361 if (!dupe_loc.IsValid() && top_scope_->IsDeclared(param_name)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004362 duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
ager@chromium.org378b34e2011-01-28 08:04:38 +00004363 dupe_loc = scanner().location();
4364 }
ager@chromium.org04921a82011-06-27 13:21:41 +00004365 if (!reserved_loc.IsValid() && is_strict_reserved) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004366 reserved_loc = scanner().location();
4367 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004368
yangguo@chromium.org56454712012-02-16 15:33:53 +00004369 top_scope_->DeclareParameter(param_name, VAR);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004370 num_parameters++;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004371 if (num_parameters > kMaxNumFunctionParameters) {
4372 ReportMessageAt(scanner().location(), "too_many_parameters",
4373 Vector<const char*>::empty());
4374 *ok = false;
4375 return NULL;
4376 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004377 done = (peek() == Token::RPAREN);
4378 if (!done) Expect(Token::COMMA, CHECK_OK);
4379 }
4380 Expect(Token::RPAREN, CHECK_OK);
4381
4382 Expect(Token::LBRACE, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004383
4384 // If we have a named function expression, we add a local variable
4385 // declaration to the body of the function with the name of the
4386 // function and let it refer to the function itself (closure).
4387 // NOTE: We create a proxy and resolve it here so that in the
4388 // future we can change the AST to only refer to VariableProxies
4389 // instead of Variables and Proxis as is the case now.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004390 Variable* fvar = NULL;
4391 Token::Value fvar_init_op = Token::INIT_CONST;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004392 if (type == FunctionLiteral::NAMED_EXPRESSION) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004393 if (is_extended_mode()) fvar_init_op = Token::INIT_CONST_HARMONY;
4394 VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST;
4395 fvar = new(zone()) Variable(top_scope_,
4396 function_name, fvar_mode, true /* is valid LHS */,
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00004397 Variable::NORMAL, kCreatedInitialized, Interface::NewConst());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004398 VariableProxy* proxy = factory()->NewVariableProxy(fvar);
4399 VariableDeclaration* fvar_declaration =
4400 factory()->NewVariableDeclaration(proxy, fvar_mode, top_scope_);
4401 top_scope_->DeclareFunctionVar(fvar_declaration);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004402 }
4403
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004404 // Determine whether the function will be lazily compiled.
4405 // The heuristics are:
4406 // - It must not have been prohibited by the caller to Parse (some callers
4407 // need a full AST).
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004408 // - The outer scope must allow lazy compilation of inner functions.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004409 // - The function mustn't be a function expression with an open parenthesis
4410 // before; we consider that a hint that the function will be called
4411 // immediately, and it would be a waste of time to make it lazily
4412 // compiled.
4413 // These are all things we can know at this point, without looking at the
4414 // function itself.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004415 bool is_lazily_compiled = (mode() == PARSE_LAZILY &&
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004416 top_scope_->AllowsLazyCompilation() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004417 !parenthesized_function_);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004418 parenthesized_function_ = false; // The bit was set for this function only.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004419
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004420 if (is_lazily_compiled) {
4421 int function_block_pos = scanner().location().beg_pos;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004422 FunctionEntry entry;
4423 if (pre_data_ != NULL) {
4424 // If we have pre_data_, we use it to skip parsing the function body.
4425 // the preparser data contains the information we need to construct the
4426 // lazy function.
4427 entry = pre_data()->GetFunctionEntry(function_block_pos);
4428 if (entry.is_valid()) {
4429 if (entry.end_pos() <= function_block_pos) {
4430 // End position greater than end of stream is safe, and hard
4431 // to check.
4432 ReportInvalidPreparseData(function_name, CHECK_OK);
4433 }
4434 scanner().SeekForward(entry.end_pos() - 1);
4435
4436 scope->set_end_position(entry.end_pos());
4437 Expect(Token::RBRACE, CHECK_OK);
4438 isolate()->counters()->total_preparse_skipped()->Increment(
4439 scope->end_position() - function_block_pos);
4440 materialized_literal_count = entry.literal_count();
4441 expected_property_count = entry.property_count();
4442 top_scope_->SetLanguageMode(entry.language_mode());
4443 only_simple_this_property_assignments = false;
4444 this_property_assignments = isolate()->factory()->empty_fixed_array();
4445 } else {
4446 is_lazily_compiled = false;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004447 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004448 } else {
4449 // With no preparser data, we partially parse the function, without
4450 // building an AST. This gathers the data needed to build a lazy
4451 // function.
4452 SingletonLogger logger;
4453 preparser::PreParser::PreParseResult result =
4454 LazyParseFunctionLiteral(&logger);
4455 if (result == preparser::PreParser::kPreParseStackOverflow) {
4456 // Propagate stack overflow.
4457 stack_overflow_ = true;
4458 *ok = false;
4459 return NULL;
4460 }
4461 if (logger.has_error()) {
4462 const char* arg = logger.argument_opt();
4463 Vector<const char*> args;
4464 if (arg != NULL) {
4465 args = Vector<const char*>(&arg, 1);
4466 }
4467 ReportMessageAt(Scanner::Location(logger.start(), logger.end()),
4468 logger.message(), args);
4469 *ok = false;
4470 return NULL;
4471 }
4472 scope->set_end_position(logger.end());
4473 Expect(Token::RBRACE, CHECK_OK);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004474 isolate()->counters()->total_preparse_skipped()->Increment(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004475 scope->end_position() - function_block_pos);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004476 materialized_literal_count = logger.literals();
4477 expected_property_count = logger.properties();
4478 top_scope_->SetLanguageMode(logger.language_mode());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004479 only_simple_this_property_assignments = false;
4480 this_property_assignments = isolate()->factory()->empty_fixed_array();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004481 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004482 }
4483
4484 if (!is_lazily_compiled) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004485 ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004486 body = new(zone()) ZoneList<Statement*>(8, zone());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004487 if (fvar != NULL) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00004488 VariableProxy* fproxy = top_scope_->NewUnresolved(
4489 factory(), function_name, Interface::NewConst());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004490 fproxy->BindTo(fvar);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004491 body->Add(factory()->NewExpressionStatement(
4492 factory()->NewAssignment(fvar_init_op,
4493 fproxy,
4494 factory()->NewThisFunction(),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004495 RelocInfo::kNoPosition)),
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004496 zone());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004497 }
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004498 ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004499
danno@chromium.orgc612e022011-11-10 11:38:15 +00004500 materialized_literal_count = function_state.materialized_literal_count();
4501 expected_property_count = function_state.expected_property_count();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004502 handler_count = function_state.handler_count();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004503 only_simple_this_property_assignments =
danno@chromium.orgc612e022011-11-10 11:38:15 +00004504 function_state.only_simple_this_property_assignments();
4505 this_property_assignments = function_state.this_property_assignments();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004507 Expect(Token::RBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004508 scope->set_end_position(scanner().location().end_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004509 }
4510
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004511 // Validate strict mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004512 if (!top_scope_->is_classic_mode()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004513 if (IsEvalOrArguments(function_name)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004514 int start_pos = scope->start_position();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004515 int position = function_token_position != RelocInfo::kNoPosition
ager@chromium.org378b34e2011-01-28 08:04:38 +00004516 ? function_token_position
4517 : (start_pos > 0 ? start_pos - 1 : start_pos);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004518 Scanner::Location location = Scanner::Location(position, start_pos);
4519 ReportMessageAt(location,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004520 "strict_function_name", Vector<const char*>::empty());
4521 *ok = false;
4522 return NULL;
4523 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004524 if (name_loc.IsValid()) {
4525 ReportMessageAt(name_loc, "strict_param_name",
4526 Vector<const char*>::empty());
4527 *ok = false;
4528 return NULL;
4529 }
4530 if (dupe_loc.IsValid()) {
4531 ReportMessageAt(dupe_loc, "strict_param_dupe",
4532 Vector<const char*>::empty());
4533 *ok = false;
4534 return NULL;
4535 }
ager@chromium.org04921a82011-06-27 13:21:41 +00004536 if (name_is_strict_reserved) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004537 int start_pos = scope->start_position();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004538 int position = function_token_position != RelocInfo::kNoPosition
4539 ? function_token_position
4540 : (start_pos > 0 ? start_pos - 1 : start_pos);
4541 Scanner::Location location = Scanner::Location(position, start_pos);
4542 ReportMessageAt(location, "strict_reserved_word",
4543 Vector<const char*>::empty());
4544 *ok = false;
4545 return NULL;
4546 }
4547 if (reserved_loc.IsValid()) {
4548 ReportMessageAt(reserved_loc, "strict_reserved_word",
4549 Vector<const char*>::empty());
4550 *ok = false;
4551 return NULL;
4552 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004553 CheckOctalLiteral(scope->start_position(),
4554 scope->end_position(),
4555 CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004556 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004557 ast_properties = *factory()->visitor()->ast_properties();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004558 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004559
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004560 if (is_extended_mode()) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004561 CheckConflictingVarDeclarations(scope, CHECK_OK);
4562 }
4563
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004564 FunctionLiteral* function_literal =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004565 factory()->NewFunctionLiteral(function_name,
4566 scope,
4567 body,
4568 materialized_literal_count,
4569 expected_property_count,
4570 handler_count,
4571 only_simple_this_property_assignments,
4572 this_property_assignments,
4573 num_parameters,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004574 duplicate_parameters,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004575 type,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004576 FunctionLiteral::kIsFunction,
4577 parenthesized);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004578 function_literal->set_function_token_position(function_token_position);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004579 function_literal->set_ast_properties(&ast_properties);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004580
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004581 if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004582 return function_literal;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004583}
4584
4585
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004586preparser::PreParser::PreParseResult Parser::LazyParseFunctionLiteral(
4587 SingletonLogger* logger) {
4588 HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse());
4589 ASSERT_EQ(Token::LBRACE, scanner().current_token());
4590
4591 if (reusable_preparser_ == NULL) {
4592 intptr_t stack_limit = isolate()->stack_guard()->real_climit();
4593 bool do_allow_lazy = true;
4594 reusable_preparser_ = new preparser::PreParser(&scanner_,
4595 NULL,
4596 stack_limit,
4597 do_allow_lazy,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00004598 allow_natives_syntax_,
4599 allow_modules_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004600 }
4601 preparser::PreParser::PreParseResult result =
4602 reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(),
4603 logger);
4604 return result;
4605}
4606
4607
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004608Expression* Parser::ParseV8Intrinsic(bool* ok) {
4609 // CallRuntime ::
4610 // '%' Identifier Arguments
4611
4612 Expect(Token::MOD, CHECK_OK);
4613 Handle<String> name = ParseIdentifier(CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004614 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004615
4616 if (extension_ != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004617 // The extension structures are only accessible while parsing the
4618 // very first time not when reparsing because of lazy compilation.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004619 top_scope_->DeclarationScope()->ForceEagerCompilation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004620 }
4621
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004622 const Runtime::Function* function = Runtime::FunctionForName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004623
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004624 // Check for built-in IS_VAR macro.
4625 if (function != NULL &&
4626 function->intrinsic_type == Runtime::RUNTIME &&
4627 function->function_id == Runtime::kIS_VAR) {
4628 // %IS_VAR(x) evaluates to x if x is a variable,
4629 // leads to a parse error otherwise. Could be implemented as an
4630 // inline function %_IS_VAR(x) to eliminate this special case.
4631 if (args->length() == 1 && args->at(0)->AsVariableProxy() != NULL) {
4632 return args->at(0);
4633 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 ReportMessage("unable_to_parse", Vector<const char*>::empty());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004635 *ok = false;
4636 return NULL;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004637 }
4638 }
4639
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004640 // Check that the expected number of arguments are being passed.
4641 if (function != NULL &&
4642 function->nargs != -1 &&
4643 function->nargs != args->length()) {
4644 ReportMessage("illegal_access", Vector<const char*>::empty());
4645 *ok = false;
4646 return NULL;
4647 }
4648
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00004649 // Check that the function is defined if it's an inline runtime call.
4650 if (function == NULL && name->Get(0) == '_') {
4651 ReportMessage("not_defined", Vector<Handle<String> >(&name, 1));
4652 *ok = false;
4653 return NULL;
4654 }
4655
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004656 // We have a valid intrinsics call or a call to a builtin.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004657 return factory()->NewCallRuntime(name, function, args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004658}
4659
4660
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004661bool Parser::peek_any_identifier() {
4662 Token::Value next = peek();
4663 return next == Token::IDENTIFIER ||
ager@chromium.org04921a82011-06-27 13:21:41 +00004664 next == Token::FUTURE_RESERVED_WORD ||
4665 next == Token::FUTURE_STRICT_RESERVED_WORD;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004666}
4667
4668
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669void Parser::Consume(Token::Value token) {
4670 Token::Value next = Next();
4671 USE(next);
4672 USE(token);
4673 ASSERT(next == token);
4674}
4675
4676
4677void Parser::Expect(Token::Value token, bool* ok) {
4678 Token::Value next = Next();
4679 if (next == token) return;
4680 ReportUnexpectedToken(next);
4681 *ok = false;
4682}
4683
4684
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004685bool Parser::Check(Token::Value token) {
4686 Token::Value next = peek();
4687 if (next == token) {
4688 Consume(next);
4689 return true;
4690 }
4691 return false;
4692}
4693
4694
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695void Parser::ExpectSemicolon(bool* ok) {
4696 // Check for automatic semicolon insertion according to
4697 // the rules given in ECMA-262, section 7.9, page 21.
4698 Token::Value tok = peek();
4699 if (tok == Token::SEMICOLON) {
4700 Next();
4701 return;
4702 }
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00004703 if (scanner().HasAnyLineTerminatorBeforeNext() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004704 tok == Token::RBRACE ||
4705 tok == Token::EOS) {
4706 return;
4707 }
4708 Expect(Token::SEMICOLON, ok);
4709}
4710
4711
ulan@chromium.org812308e2012-02-29 15:58:45 +00004712void Parser::ExpectContextualKeyword(const char* keyword, bool* ok) {
4713 Expect(Token::IDENTIFIER, ok);
4714 if (!*ok) return;
4715 Handle<String> symbol = GetSymbol(ok);
4716 if (!*ok) return;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004717 if (!symbol->IsUtf8EqualTo(CStrVector(keyword))) {
ulan@chromium.org812308e2012-02-29 15:58:45 +00004718 *ok = false;
4719 ReportUnexpectedToken(scanner().current_token());
4720 }
4721}
4722
4723
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724Literal* Parser::GetLiteralUndefined() {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004725 return factory()->NewLiteral(isolate()->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726}
4727
4728
4729Literal* Parser::GetLiteralTheHole() {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004730 return factory()->NewLiteral(isolate()->factory()->the_hole_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004731}
4732
4733
danno@chromium.orgb6451162011-08-17 14:33:23 +00004734// Parses an identifier that is valid for the current scope, in particular it
ager@chromium.org04921a82011-06-27 13:21:41 +00004735// fails on strict mode future reserved keywords in a strict scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004736Handle<String> Parser::ParseIdentifier(bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004737 if (!top_scope_->is_classic_mode()) {
ager@chromium.org04921a82011-06-27 13:21:41 +00004738 Expect(Token::IDENTIFIER, ok);
4739 } else if (!Check(Token::IDENTIFIER)) {
4740 Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
4741 }
4742 if (!*ok) return Handle<String>();
4743 return GetSymbol(ok);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004744}
4745
4746
ager@chromium.org04921a82011-06-27 13:21:41 +00004747// Parses and identifier or a strict mode future reserved word, and indicate
4748// whether it is strict mode future reserved.
4749Handle<String> Parser::ParseIdentifierOrStrictReservedWord(
4750 bool* is_strict_reserved, bool* ok) {
4751 *is_strict_reserved = false;
4752 if (!Check(Token::IDENTIFIER)) {
4753 Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
4754 *is_strict_reserved = true;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004755 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756 if (!*ok) return Handle<String>();
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004757 return GetSymbol(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004758}
4759
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004760
4761Handle<String> Parser::ParseIdentifierName(bool* ok) {
4762 Token::Value next = Next();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004763 if (next != Token::IDENTIFIER &&
ager@chromium.org04921a82011-06-27 13:21:41 +00004764 next != Token::FUTURE_RESERVED_WORD &&
4765 next != Token::FUTURE_STRICT_RESERVED_WORD &&
4766 !Token::IsKeyword(next)) {
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004767 ReportUnexpectedToken(next);
4768 *ok = false;
4769 return Handle<String>();
4770 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004771 return GetSymbol(ok);
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004772}
4773
ager@chromium.org378b34e2011-01-28 08:04:38 +00004774
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004775void Parser::MarkAsLValue(Expression* expression) {
4776 VariableProxy* proxy = expression != NULL
4777 ? expression->AsVariableProxy()
4778 : NULL;
4779
4780 if (proxy != NULL) proxy->MarkAsLValue();
4781}
4782
4783
ager@chromium.org378b34e2011-01-28 08:04:38 +00004784// Checks LHS expression for assignment and prefix/postfix increment/decrement
4785// in strict mode.
4786void Parser::CheckStrictModeLValue(Expression* expression,
4787 const char* error,
4788 bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004789 ASSERT(!top_scope_->is_classic_mode());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004790 VariableProxy* lhs = expression != NULL
4791 ? expression->AsVariableProxy()
4792 : NULL;
4793
4794 if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
4795 ReportMessage(error, Vector<const char*>::empty());
4796 *ok = false;
4797 }
4798}
4799
4800
lrn@chromium.org1c092762011-05-09 09:42:16 +00004801// Checks whether an octal literal was last seen between beg_pos and end_pos.
4802// If so, reports an error. Only called for strict mode.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004803void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00004804 Scanner::Location octal = scanner().octal_position();
4805 if (octal.IsValid() &&
4806 beg_pos <= octal.beg_pos &&
4807 octal.end_pos <= end_pos) {
4808 ReportMessageAt(octal, "strict_octal_literal",
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004809 Vector<const char*>::empty());
4810 scanner().clear_octal_position();
4811 *ok = false;
4812 }
4813}
4814
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004815
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004816void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
4817 Declaration* decl = scope->CheckConflictingVarDeclarations();
4818 if (decl != NULL) {
4819 // In harmony mode we treat conflicting variable bindinds as early
4820 // errors. See ES5 16 for a definition of early errors.
4821 Handle<String> name = decl->proxy()->name();
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004822 SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004823 const char* elms[2] = { "Variable", *c_string };
4824 Vector<const char*> args(elms, 2);
4825 int position = decl->proxy()->position();
4826 Scanner::Location location = position == RelocInfo::kNoPosition
4827 ? Scanner::Location::invalid()
4828 : Scanner::Location(position, position + 1);
4829 ReportMessageAt(location, "redeclaration", args);
4830 *ok = false;
4831 }
4832}
4833
4834
ager@chromium.org04921a82011-06-27 13:21:41 +00004835// This function reads an identifier name and determines whether or not it
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004836// is 'get' or 'set'.
ager@chromium.org04921a82011-06-27 13:21:41 +00004837Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get,
4838 bool* is_set,
4839 bool* ok) {
4840 Handle<String> result = ParseIdentifierName(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004841 if (!*ok) return Handle<String>();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004842 if (scanner().is_literal_ascii() && scanner().literal_length() == 3) {
4843 const char* token = scanner().literal_ascii_string().start();
4844 *is_get = strncmp(token, "get", 3) == 0;
4845 *is_set = !*is_get && strncmp(token, "set", 3) == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004846 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004847 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848}
4849
4850
4851// ----------------------------------------------------------------------------
4852// Parser support
4853
4854
4855bool Parser::TargetStackContainsLabel(Handle<String> label) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004856 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
4857 BreakableStatement* stat = t->node()->AsBreakableStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858 if (stat != NULL && ContainsLabel(stat->labels(), label))
4859 return true;
4860 }
4861 return false;
4862}
4863
4864
4865BreakableStatement* Parser::LookupBreakTarget(Handle<String> label, bool* ok) {
4866 bool anonymous = label.is_null();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004867 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
4868 BreakableStatement* stat = t->node()->AsBreakableStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869 if (stat == NULL) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870 if ((anonymous && stat->is_target_for_anonymous()) ||
4871 (!anonymous && ContainsLabel(stat->labels(), label))) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004872 RegisterTargetUse(stat->break_target(), t->previous());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004873 return stat;
4874 }
4875 }
4876 return NULL;
4877}
4878
4879
4880IterationStatement* Parser::LookupContinueTarget(Handle<String> label,
4881 bool* ok) {
4882 bool anonymous = label.is_null();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004883 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
4884 IterationStatement* stat = t->node()->AsIterationStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004885 if (stat == NULL) continue;
4886
4887 ASSERT(stat->is_target_for_anonymous());
4888 if (anonymous || ContainsLabel(stat->labels(), label)) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004889 RegisterTargetUse(stat->continue_target(), t->previous());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890 return stat;
4891 }
4892 }
4893 return NULL;
4894}
4895
4896
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004897void Parser::RegisterTargetUse(Label* target, Target* stop) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004898 // Register that a break target found at the given stop in the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004899 // target stack has been used from the top of the target stack. Add
4900 // the break target to any TargetCollectors passed on the stack.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004901 for (Target* t = target_stack_; t != stop; t = t->previous()) {
4902 TargetCollector* collector = t->node()->AsTargetCollector();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004903 if (collector != NULL) collector->AddTarget(target, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004904 }
4905}
4906
4907
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004908Expression* Parser::NewThrowReferenceError(Handle<String> type) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004909 return NewThrowError(isolate()->factory()->MakeReferenceError_string(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004910 type, HandleVector<Object>(NULL, 0));
4911}
4912
4913
4914Expression* Parser::NewThrowSyntaxError(Handle<String> type,
4915 Handle<Object> first) {
4916 int argc = first.is_null() ? 0 : 1;
4917 Vector< Handle<Object> > arguments = HandleVector<Object>(&first, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004918 return NewThrowError(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004919 isolate()->factory()->MakeSyntaxError_string(), type, arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004920}
4921
4922
4923Expression* Parser::NewThrowTypeError(Handle<String> type,
4924 Handle<Object> first,
4925 Handle<Object> second) {
4926 ASSERT(!first.is_null() && !second.is_null());
4927 Handle<Object> elements[] = { first, second };
4928 Vector< Handle<Object> > arguments =
4929 HandleVector<Object>(elements, ARRAY_SIZE(elements));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004930 return NewThrowError(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004931 isolate()->factory()->MakeTypeError_string(), type, arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004932}
4933
4934
4935Expression* Parser::NewThrowError(Handle<String> constructor,
4936 Handle<String> type,
4937 Vector< Handle<Object> > arguments) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004938 int argc = arguments.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004939 Handle<FixedArray> elements = isolate()->factory()->NewFixedArray(argc,
4940 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004941 for (int i = 0; i < argc; i++) {
4942 Handle<Object> element = arguments[i];
4943 if (!element.is_null()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004944 elements->set(i, *element);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004945 }
4946 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004947 Handle<JSArray> array = isolate()->factory()->NewJSArrayWithElements(
4948 elements, FAST_ELEMENTS, TENURED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004949
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004950 ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2, zone());
4951 args->Add(factory()->NewLiteral(type), zone());
4952 args->Add(factory()->NewLiteral(array), zone());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004953 CallRuntime* call_constructor =
4954 factory()->NewCallRuntime(constructor, NULL, args);
4955 return factory()->NewThrow(call_constructor, scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004956}
4957
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004958// ----------------------------------------------------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004959// Regular expressions
4960
4961
4962RegExpParser::RegExpParser(FlatStringReader* in,
4963 Handle<String>* error,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00004964 bool multiline,
4965 Zone* zone)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004966 : isolate_(Isolate::Current()),
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00004967 zone_(zone),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004968 error_(error),
4969 captures_(NULL),
4970 in_(in),
4971 current_(kEndMarker),
4972 next_pos_(0),
4973 capture_count_(0),
4974 has_more_(true),
4975 multiline_(multiline),
4976 simple_(false),
4977 contains_anchor_(false),
4978 is_scanned_for_captures_(false),
4979 failed_(false) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00004980 Advance();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004981}
4982
4983
4984uc32 RegExpParser::Next() {
4985 if (has_next()) {
4986 return in()->Get(next_pos_);
4987 } else {
4988 return kEndMarker;
4989 }
4990}
4991
4992
4993void RegExpParser::Advance() {
4994 if (next_pos_ < in()->length()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004995 StackLimitCheck check(isolate());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004996 if (check.HasOverflowed()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004997 ReportError(CStrVector(Isolate::kStackOverflowMessage));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00004998 } else if (zone()->excess_allocation()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004999 ReportError(CStrVector("Regular expression too large"));
5000 } else {
5001 current_ = in()->Get(next_pos_);
5002 next_pos_++;
5003 }
5004 } else {
5005 current_ = kEndMarker;
5006 has_more_ = false;
5007 }
5008}
5009
5010
5011void RegExpParser::Reset(int pos) {
5012 next_pos_ = pos;
5013 Advance();
5014}
5015
5016
5017void RegExpParser::Advance(int dist) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00005018 next_pos_ += dist - 1;
5019 Advance();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005020}
5021
5022
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005023bool RegExpParser::simple() {
5024 return simple_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005025}
5026
5027RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
5028 failed_ = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005029 *error_ = isolate()->factory()->NewStringFromAscii(message, NOT_TENURED);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005030 // Zip to the end to make sure the no more input is read.
5031 current_ = kEndMarker;
5032 next_pos_ = in()->length();
5033 return NULL;
5034}
5035
5036
5037// Pattern ::
5038// Disjunction
5039RegExpTree* RegExpParser::ParsePattern() {
5040 RegExpTree* result = ParseDisjunction(CHECK_FAILED);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005041 ASSERT(!has_more());
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005042 // If the result of parsing is a literal string atom, and it has the
5043 // same length as the input, then the atom is identical to the input.
5044 if (result->IsAtom() && result->AsAtom()->length() == in()->length()) {
5045 simple_ = true;
5046 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005047 return result;
5048}
5049
5050
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005051// Disjunction ::
5052// Alternative
5053// Alternative | Disjunction
5054// Alternative ::
5055// [empty]
5056// Term Alternative
5057// Term ::
5058// Assertion
5059// Atom
5060// Atom Quantifier
5061RegExpTree* RegExpParser::ParseDisjunction() {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005062 // Used to store current state while parsing subexpressions.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00005063 RegExpParserState initial_state(NULL, INITIAL, 0, zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005064 RegExpParserState* stored_state = &initial_state;
5065 // Cache the builder in a local variable for quick access.
5066 RegExpBuilder* builder = initial_state.builder();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005067 while (true) {
5068 switch (current()) {
5069 case kEndMarker:
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005070 if (stored_state->IsSubexpression()) {
5071 // Inside a parenthesized group when hitting end of input.
5072 ReportError(CStrVector("Unterminated group") CHECK_FAILED);
5073 }
5074 ASSERT_EQ(INITIAL, stored_state->group_type());
5075 // Parsing completed successfully.
5076 return builder->ToRegExp();
5077 case ')': {
5078 if (!stored_state->IsSubexpression()) {
5079 ReportError(CStrVector("Unmatched ')'") CHECK_FAILED);
5080 }
5081 ASSERT_NE(INITIAL, stored_state->group_type());
5082
5083 Advance();
5084 // End disjunction parsing and convert builder content to new single
5085 // regexp atom.
5086 RegExpTree* body = builder->ToRegExp();
5087
5088 int end_capture_index = captures_started();
5089
5090 int capture_index = stored_state->capture_index();
5091 SubexpressionType type = stored_state->group_type();
5092
5093 // Restore previous state.
5094 stored_state = stored_state->previous_state();
5095 builder = stored_state->builder();
5096
5097 // Build result of subexpression.
5098 if (type == CAPTURE) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005099 RegExpCapture* capture = new(zone()) RegExpCapture(body, capture_index);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005100 captures_->at(capture_index - 1) = capture;
5101 body = capture;
5102 } else if (type != GROUPING) {
5103 ASSERT(type == POSITIVE_LOOKAHEAD || type == NEGATIVE_LOOKAHEAD);
5104 bool is_positive = (type == POSITIVE_LOOKAHEAD);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005105 body = new(zone()) RegExpLookahead(body,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005106 is_positive,
5107 end_capture_index - capture_index,
5108 capture_index);
5109 }
5110 builder->AddAtom(body);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005111 // For compatability with JSC and ES3, we allow quantifiers after
5112 // lookaheads, and break in all cases.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005113 break;
5114 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005115 case '|': {
5116 Advance();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005117 builder->NewAlternative();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005118 continue;
5119 }
5120 case '*':
5121 case '+':
5122 case '?':
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005123 return ReportError(CStrVector("Nothing to repeat"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005124 case '^': {
5125 Advance();
iposva@chromium.org245aa852009-02-10 00:49:54 +00005126 if (multiline_) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005127 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005128 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_LINE));
iposva@chromium.org245aa852009-02-10 00:49:54 +00005129 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005130 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005131 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_INPUT));
iposva@chromium.org245aa852009-02-10 00:49:54 +00005132 set_contains_anchor();
5133 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005134 continue;
5135 }
5136 case '$': {
5137 Advance();
5138 RegExpAssertion::Type type =
5139 multiline_ ? RegExpAssertion::END_OF_LINE :
5140 RegExpAssertion::END_OF_INPUT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005141 builder->AddAssertion(new(zone()) RegExpAssertion(type));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005142 continue;
5143 }
5144 case '.': {
5145 Advance();
5146 // everything except \x0a, \x0d, \u2028 and \u2029
danno@chromium.org40cb8782011-05-25 07:58:50 +00005147 ZoneList<CharacterRange>* ranges =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005148 new(zone()) ZoneList<CharacterRange>(2, zone());
5149 CharacterRange::AddClassEscape('.', ranges, zone());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005150 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005151 builder->AddAtom(atom);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005152 break;
5153 }
5154 case '(': {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005155 SubexpressionType type = CAPTURE;
5156 Advance();
5157 if (current() == '?') {
5158 switch (Next()) {
5159 case ':':
5160 type = GROUPING;
5161 break;
5162 case '=':
5163 type = POSITIVE_LOOKAHEAD;
5164 break;
5165 case '!':
5166 type = NEGATIVE_LOOKAHEAD;
5167 break;
5168 default:
5169 ReportError(CStrVector("Invalid group") CHECK_FAILED);
5170 break;
5171 }
5172 Advance(2);
5173 } else {
5174 if (captures_ == NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005175 captures_ = new(zone()) ZoneList<RegExpCapture*>(2, zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005176 }
5177 if (captures_started() >= kMaxCaptures) {
5178 ReportError(CStrVector("Too many captures") CHECK_FAILED);
5179 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005180 captures_->Add(NULL, zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005181 }
5182 // Store current state and begin new disjunction parsing.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00005183 stored_state = new(zone()) RegExpParserState(stored_state, type,
5184 captures_started(), zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005185 builder = stored_state->builder();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005186 continue;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005187 }
5188 case '[': {
5189 RegExpTree* atom = ParseCharacterClass(CHECK_FAILED);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005190 builder->AddAtom(atom);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005191 break;
5192 }
5193 // Atom ::
5194 // \ AtomEscape
5195 case '\\':
5196 switch (Next()) {
5197 case kEndMarker:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005198 return ReportError(CStrVector("\\ at end of pattern"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005199 case 'b':
5200 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005201 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005202 new(zone()) RegExpAssertion(RegExpAssertion::BOUNDARY));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005203 continue;
5204 case 'B':
5205 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005206 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005207 new(zone()) RegExpAssertion(RegExpAssertion::NON_BOUNDARY));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005208 continue;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005209 // AtomEscape ::
5210 // CharacterClassEscape
5211 //
5212 // CharacterClassEscape :: one of
5213 // d D s S w W
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005214 case 'd': case 'D': case 's': case 'S': case 'w': case 'W': {
5215 uc32 c = Next();
5216 Advance(2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00005217 ZoneList<CharacterRange>* ranges =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005218 new(zone()) ZoneList<CharacterRange>(2, zone());
5219 CharacterRange::AddClassEscape(c, ranges, zone());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005220 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005221 builder->AddAtom(atom);
5222 break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005223 }
5224 case '1': case '2': case '3': case '4': case '5': case '6':
5225 case '7': case '8': case '9': {
5226 int index = 0;
5227 if (ParseBackReferenceIndex(&index)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005228 RegExpCapture* capture = NULL;
5229 if (captures_ != NULL && index <= captures_->length()) {
5230 capture = captures_->at(index - 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005231 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005232 if (capture == NULL) {
5233 builder->AddEmpty();
5234 break;
5235 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005236 RegExpTree* atom = new(zone()) RegExpBackReference(capture);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005237 builder->AddAtom(atom);
5238 break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005239 }
5240 uc32 first_digit = Next();
5241 if (first_digit == '8' || first_digit == '9') {
5242 // Treat as identity escape
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005243 builder->AddCharacter(first_digit);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005244 Advance(2);
5245 break;
5246 }
5247 }
5248 // FALLTHROUGH
5249 case '0': {
5250 Advance();
5251 uc32 octal = ParseOctalLiteral();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005252 builder->AddCharacter(octal);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005253 break;
5254 }
5255 // ControlEscape :: one of
5256 // f n r t v
5257 case 'f':
5258 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005259 builder->AddCharacter('\f');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005260 break;
5261 case 'n':
5262 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005263 builder->AddCharacter('\n');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005264 break;
5265 case 'r':
5266 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005267 builder->AddCharacter('\r');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005268 break;
5269 case 't':
5270 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005271 builder->AddCharacter('\t');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005272 break;
5273 case 'v':
5274 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005275 builder->AddCharacter('\v');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005276 break;
5277 case 'c': {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00005278 Advance();
5279 uc32 controlLetter = Next();
5280 // Special case if it is an ASCII letter.
5281 // Convert lower case letters to uppercase.
5282 uc32 letter = controlLetter & ~('a' ^ 'A');
5283 if (letter < 'A' || 'Z' < letter) {
5284 // controlLetter is not in range 'A'-'Z' or 'a'-'z'.
5285 // This is outside the specification. We match JSC in
5286 // reading the backslash as a literal character instead
5287 // of as starting an escape.
5288 builder->AddCharacter('\\');
5289 } else {
5290 Advance(2);
5291 builder->AddCharacter(controlLetter & 0x1f);
5292 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005293 break;
5294 }
5295 case 'x': {
5296 Advance(2);
5297 uc32 value;
5298 if (ParseHexEscape(2, &value)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005299 builder->AddCharacter(value);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005300 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005301 builder->AddCharacter('x');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005302 }
5303 break;
5304 }
5305 case 'u': {
5306 Advance(2);
5307 uc32 value;
5308 if (ParseHexEscape(4, &value)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005309 builder->AddCharacter(value);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005310 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005311 builder->AddCharacter('u');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005312 }
5313 break;
5314 }
5315 default:
5316 // Identity escape.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005317 builder->AddCharacter(Next());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005318 Advance(2);
5319 break;
5320 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005321 break;
5322 case '{': {
5323 int dummy;
5324 if (ParseIntervalQuantifier(&dummy, &dummy)) {
5325 ReportError(CStrVector("Nothing to repeat") CHECK_FAILED);
5326 }
5327 // fallthrough
5328 }
5329 default:
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005330 builder->AddCharacter(current());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005331 Advance();
5332 break;
5333 } // end switch(current())
5334
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005335 int min;
5336 int max;
5337 switch (current()) {
5338 // QuantifierPrefix ::
5339 // *
5340 // +
5341 // ?
5342 // {
5343 case '*':
5344 min = 0;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005345 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005346 Advance();
5347 break;
5348 case '+':
5349 min = 1;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005350 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005351 Advance();
5352 break;
5353 case '?':
5354 min = 0;
5355 max = 1;
5356 Advance();
5357 break;
5358 case '{':
5359 if (ParseIntervalQuantifier(&min, &max)) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005360 if (max < min) {
5361 ReportError(CStrVector("numbers out of order in {} quantifier.")
5362 CHECK_FAILED);
5363 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005364 break;
5365 } else {
5366 continue;
5367 }
5368 default:
5369 continue;
5370 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005371 RegExpQuantifier::Type type = RegExpQuantifier::GREEDY;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005372 if (current() == '?') {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005373 type = RegExpQuantifier::NON_GREEDY;
5374 Advance();
5375 } else if (FLAG_regexp_possessive_quantifier && current() == '+') {
5376 // FLAG_regexp_possessive_quantifier is a debug-only flag.
5377 type = RegExpQuantifier::POSSESSIVE;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005378 Advance();
5379 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005380 builder->AddQuantifierToAtom(min, max, type);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005381 }
5382}
5383
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005384
5385#ifdef DEBUG
5386// Currently only used in an ASSERT.
5387static bool IsSpecialClassEscape(uc32 c) {
5388 switch (c) {
5389 case 'd': case 'D':
5390 case 's': case 'S':
5391 case 'w': case 'W':
5392 return true;
5393 default:
5394 return false;
5395 }
5396}
5397#endif
5398
5399
5400// In order to know whether an escape is a backreference or not we have to scan
5401// the entire regexp and find the number of capturing parentheses. However we
5402// don't want to scan the regexp twice unless it is necessary. This mini-parser
5403// is called when needed. It can see the difference between capturing and
5404// noncapturing parentheses and can skip character classes and backslash-escaped
5405// characters.
5406void RegExpParser::ScanForCaptures() {
5407 // Start with captures started previous to current position
5408 int capture_count = captures_started();
5409 // Add count of captures after this position.
5410 int n;
5411 while ((n = current()) != kEndMarker) {
5412 Advance();
5413 switch (n) {
5414 case '\\':
5415 Advance();
5416 break;
5417 case '[': {
5418 int c;
5419 while ((c = current()) != kEndMarker) {
5420 Advance();
5421 if (c == '\\') {
5422 Advance();
5423 } else {
5424 if (c == ']') break;
5425 }
5426 }
5427 break;
5428 }
5429 case '(':
5430 if (current() != '?') capture_count++;
5431 break;
5432 }
5433 }
5434 capture_count_ = capture_count;
5435 is_scanned_for_captures_ = true;
5436}
5437
5438
5439bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
5440 ASSERT_EQ('\\', current());
5441 ASSERT('1' <= Next() && Next() <= '9');
iposva@chromium.org245aa852009-02-10 00:49:54 +00005442 // Try to parse a decimal literal that is no greater than the total number
5443 // of left capturing parentheses in the input.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005444 int start = position();
5445 int value = Next() - '0';
5446 Advance(2);
5447 while (true) {
5448 uc32 c = current();
5449 if (IsDecimalDigit(c)) {
5450 value = 10 * value + (c - '0');
iposva@chromium.org245aa852009-02-10 00:49:54 +00005451 if (value > kMaxCaptures) {
5452 Reset(start);
5453 return false;
5454 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005455 Advance();
5456 } else {
5457 break;
5458 }
5459 }
5460 if (value > captures_started()) {
5461 if (!is_scanned_for_captures_) {
5462 int saved_position = position();
5463 ScanForCaptures();
5464 Reset(saved_position);
5465 }
5466 if (value > capture_count_) {
5467 Reset(start);
5468 return false;
5469 }
5470 }
5471 *index_out = value;
5472 return true;
5473}
5474
5475
5476// QuantifierPrefix ::
5477// { DecimalDigits }
5478// { DecimalDigits , }
5479// { DecimalDigits , DecimalDigits }
iposva@chromium.org245aa852009-02-10 00:49:54 +00005480//
5481// Returns true if parsing succeeds, and set the min_out and max_out
5482// values. Values are truncated to RegExpTree::kInfinity if they overflow.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005483bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) {
5484 ASSERT_EQ(current(), '{');
5485 int start = position();
5486 Advance();
5487 int min = 0;
5488 if (!IsDecimalDigit(current())) {
5489 Reset(start);
5490 return false;
5491 }
5492 while (IsDecimalDigit(current())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005493 int next = current() - '0';
5494 if (min > (RegExpTree::kInfinity - next) / 10) {
5495 // Overflow. Skip past remaining decimal digits and return -1.
5496 do {
5497 Advance();
5498 } while (IsDecimalDigit(current()));
5499 min = RegExpTree::kInfinity;
5500 break;
5501 }
5502 min = 10 * min + next;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005503 Advance();
5504 }
5505 int max = 0;
5506 if (current() == '}') {
5507 max = min;
5508 Advance();
5509 } else if (current() == ',') {
5510 Advance();
5511 if (current() == '}') {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005512 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005513 Advance();
5514 } else {
5515 while (IsDecimalDigit(current())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005516 int next = current() - '0';
5517 if (max > (RegExpTree::kInfinity - next) / 10) {
5518 do {
5519 Advance();
5520 } while (IsDecimalDigit(current()));
5521 max = RegExpTree::kInfinity;
5522 break;
5523 }
5524 max = 10 * max + next;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005525 Advance();
5526 }
5527 if (current() != '}') {
5528 Reset(start);
5529 return false;
5530 }
5531 Advance();
5532 }
5533 } else {
5534 Reset(start);
5535 return false;
5536 }
5537 *min_out = min;
5538 *max_out = max;
5539 return true;
5540}
5541
5542
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005543uc32 RegExpParser::ParseOctalLiteral() {
5544 ASSERT('0' <= current() && current() <= '7');
5545 // For compatibility with some other browsers (not all), we parse
5546 // up to three octal digits with a value below 256.
5547 uc32 value = current() - '0';
5548 Advance();
5549 if ('0' <= current() && current() <= '7') {
5550 value = value * 8 + current() - '0';
5551 Advance();
5552 if (value < 32 && '0' <= current() && current() <= '7') {
5553 value = value * 8 + current() - '0';
5554 Advance();
5555 }
5556 }
5557 return value;
5558}
5559
5560
5561bool RegExpParser::ParseHexEscape(int length, uc32 *value) {
5562 int start = position();
5563 uc32 val = 0;
5564 bool done = false;
5565 for (int i = 0; !done; i++) {
5566 uc32 c = current();
5567 int d = HexValue(c);
5568 if (d < 0) {
5569 Reset(start);
5570 return false;
5571 }
5572 val = val * 16 + d;
5573 Advance();
5574 if (i == length - 1) {
5575 done = true;
5576 }
5577 }
5578 *value = val;
5579 return true;
5580}
5581
5582
5583uc32 RegExpParser::ParseClassCharacterEscape() {
5584 ASSERT(current() == '\\');
5585 ASSERT(has_next() && !IsSpecialClassEscape(Next()));
5586 Advance();
5587 switch (current()) {
5588 case 'b':
5589 Advance();
5590 return '\b';
5591 // ControlEscape :: one of
5592 // f n r t v
5593 case 'f':
5594 Advance();
5595 return '\f';
5596 case 'n':
5597 Advance();
5598 return '\n';
5599 case 'r':
5600 Advance();
5601 return '\r';
5602 case 't':
5603 Advance();
5604 return '\t';
5605 case 'v':
5606 Advance();
5607 return '\v';
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00005608 case 'c': {
5609 uc32 controlLetter = Next();
5610 uc32 letter = controlLetter & ~('A' ^ 'a');
5611 // For compatibility with JSC, inside a character class
5612 // we also accept digits and underscore as control characters.
5613 if ((controlLetter >= '0' && controlLetter <= '9') ||
5614 controlLetter == '_' ||
5615 (letter >= 'A' && letter <= 'Z')) {
5616 Advance(2);
5617 // Control letters mapped to ASCII control characters in the range
5618 // 0x00-0x1f.
5619 return controlLetter & 0x1f;
5620 }
5621 // We match JSC in reading the backslash as a literal
5622 // character instead of as starting an escape.
5623 return '\\';
5624 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005625 case '0': case '1': case '2': case '3': case '4': case '5':
5626 case '6': case '7':
5627 // For compatibility, we interpret a decimal escape that isn't
5628 // a back reference (and therefore either \0 or not valid according
5629 // to the specification) as a 1..3 digit octal character code.
5630 return ParseOctalLiteral();
5631 case 'x': {
5632 Advance();
5633 uc32 value;
5634 if (ParseHexEscape(2, &value)) {
5635 return value;
5636 }
5637 // If \x is not followed by a two-digit hexadecimal, treat it
5638 // as an identity escape.
5639 return 'x';
5640 }
5641 case 'u': {
5642 Advance();
5643 uc32 value;
5644 if (ParseHexEscape(4, &value)) {
5645 return value;
5646 }
5647 // If \u is not followed by a four-digit hexadecimal, treat it
5648 // as an identity escape.
5649 return 'u';
5650 }
5651 default: {
5652 // Extended identity escape. We accept any character that hasn't
5653 // been matched by a more specific case, not just the subset required
5654 // by the ECMAScript specification.
5655 uc32 result = current();
5656 Advance();
5657 return result;
5658 }
5659 }
5660 return 0;
5661}
5662
5663
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005664CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) {
5665 ASSERT_EQ(0, *char_class);
5666 uc32 first = current();
5667 if (first == '\\') {
5668 switch (Next()) {
5669 case 'w': case 'W': case 'd': case 'D': case 's': case 'S': {
5670 *char_class = Next();
5671 Advance(2);
5672 return CharacterRange::Singleton(0); // Return dummy value.
5673 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005674 case kEndMarker:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005675 return ReportError(CStrVector("\\ at end of pattern"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005676 default:
5677 uc32 c = ParseClassCharacterEscape(CHECK_FAILED);
5678 return CharacterRange::Singleton(c);
5679 }
5680 } else {
5681 Advance();
5682 return CharacterRange::Singleton(first);
5683 }
5684}
5685
5686
lrn@chromium.org14a70352010-12-15 12:43:21 +00005687static const uc16 kNoCharClass = 0;
5688
5689// Adds range or pre-defined character class to character ranges.
5690// If char_class is not kInvalidClass, it's interpreted as a class
5691// escape (i.e., 's' means whitespace, from '\s').
5692static inline void AddRangeOrEscape(ZoneList<CharacterRange>* ranges,
5693 uc16 char_class,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005694 CharacterRange range,
5695 Zone* zone) {
lrn@chromium.org14a70352010-12-15 12:43:21 +00005696 if (char_class != kNoCharClass) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005697 CharacterRange::AddClassEscape(char_class, ranges, zone);
lrn@chromium.org14a70352010-12-15 12:43:21 +00005698 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005699 ranges->Add(range, zone);
lrn@chromium.org14a70352010-12-15 12:43:21 +00005700 }
5701}
5702
5703
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005704RegExpTree* RegExpParser::ParseCharacterClass() {
5705 static const char* kUnterminated = "Unterminated character class";
5706 static const char* kRangeOutOfOrder = "Range out of order in character class";
5707
5708 ASSERT_EQ(current(), '[');
5709 Advance();
5710 bool is_negated = false;
5711 if (current() == '^') {
5712 is_negated = true;
5713 Advance();
5714 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005715 ZoneList<CharacterRange>* ranges =
5716 new(zone()) ZoneList<CharacterRange>(2, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005717 while (has_more() && current() != ']') {
lrn@chromium.org14a70352010-12-15 12:43:21 +00005718 uc16 char_class = kNoCharClass;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005719 CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005720 if (current() == '-') {
5721 Advance();
5722 if (current() == kEndMarker) {
5723 // If we reach the end we break out of the loop and let the
5724 // following code report an error.
5725 break;
5726 } else if (current() == ']') {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005727 AddRangeOrEscape(ranges, char_class, first, zone());
5728 ranges->Add(CharacterRange::Singleton('-'), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005729 break;
5730 }
lrn@chromium.org14a70352010-12-15 12:43:21 +00005731 uc16 char_class_2 = kNoCharClass;
5732 CharacterRange next = ParseClassAtom(&char_class_2 CHECK_FAILED);
5733 if (char_class != kNoCharClass || char_class_2 != kNoCharClass) {
5734 // Either end is an escaped character class. Treat the '-' verbatim.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005735 AddRangeOrEscape(ranges, char_class, first, zone());
5736 ranges->Add(CharacterRange::Singleton('-'), zone());
5737 AddRangeOrEscape(ranges, char_class_2, next, zone());
lrn@chromium.org14a70352010-12-15 12:43:21 +00005738 continue;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005739 }
5740 if (first.from() > next.to()) {
5741 return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED);
5742 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005743 ranges->Add(CharacterRange::Range(first.from(), next.to()), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005744 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005745 AddRangeOrEscape(ranges, char_class, first, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005746 }
5747 }
5748 if (!has_more()) {
5749 return ReportError(CStrVector(kUnterminated) CHECK_FAILED);
5750 }
5751 Advance();
5752 if (ranges->length() == 0) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005753 ranges->Add(CharacterRange::Everything(), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005754 is_negated = !is_negated;
5755 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005756 return new(zone()) RegExpCharacterClass(ranges, is_negated);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005757}
5758
5759
5760// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005761// The Parser interface.
5762
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005763ParserMessage::~ParserMessage() {
5764 for (int i = 0; i < args().length(); i++)
5765 DeleteArray(args()[i]);
5766 DeleteArray(args().start());
5767}
5768
5769
5770ScriptDataImpl::~ScriptDataImpl() {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005771 if (owns_store_) store_.Dispose();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005772}
5773
5774
5775int ScriptDataImpl::Length() {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005776 return store_.length() * sizeof(unsigned);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005777}
5778
5779
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005780const char* ScriptDataImpl::Data() {
5781 return reinterpret_cast<const char*>(store_.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005782}
5783
5784
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005785bool ScriptDataImpl::HasError() {
5786 return has_error();
5787}
5788
5789
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005790void ScriptDataImpl::Initialize() {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00005791 // Prepares state for use.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005792 if (store_.length() >= PreparseDataConstants::kHeaderSize) {
5793 function_index_ = PreparseDataConstants::kHeaderSize;
5794 int symbol_data_offset = PreparseDataConstants::kHeaderSize
5795 + store_[PreparseDataConstants::kFunctionsSizeOffset];
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005796 if (store_.length() > symbol_data_offset) {
5797 symbol_data_ = reinterpret_cast<byte*>(&store_[symbol_data_offset]);
5798 } else {
5799 // Partial preparse causes no symbol information.
5800 symbol_data_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
5801 }
5802 symbol_data_end_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
5803 }
5804}
5805
5806
5807int ScriptDataImpl::ReadNumber(byte** source) {
5808 // Reads a number from symbol_data_ in base 128. The most significant
5809 // bit marks that there are more digits.
5810 // If the first byte is 0x80 (kNumberTerminator), it would normally
5811 // represent a leading zero. Since that is useless, and therefore won't
5812 // appear as the first digit of any actual value, it is used to
5813 // mark the end of the input stream.
5814 byte* data = *source;
5815 if (data >= symbol_data_end_) return -1;
5816 byte input = *data;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005817 if (input == PreparseDataConstants::kNumberTerminator) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005818 // End of stream marker.
5819 return -1;
5820 }
5821 int result = input & 0x7f;
5822 data++;
5823 while ((input & 0x80u) != 0) {
5824 if (data >= symbol_data_end_) return -1;
5825 input = *data;
5826 result = (result << 7) | (input & 0x7f);
5827 data++;
5828 }
5829 *source = data;
5830 return result;
5831}
5832
5833
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00005834// Create a Scanner for the preparser to use as input, and preparse the source.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005835static ScriptDataImpl* DoPreParse(Utf16CharacterStream* source,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005836 int flags,
5837 ParserRecorder* recorder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005838 Isolate* isolate = Isolate::Current();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005839 HistogramTimerScope timer(isolate->counters()->pre_parse());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005840 Scanner scanner(isolate->unicode_cache());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005841 scanner.SetHarmonyScoping(FLAG_harmony_scoping);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005842 scanner.Initialize(source);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005843 intptr_t stack_limit = isolate->stack_guard()->real_climit();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005844 preparser::PreParser::PreParseResult result =
5845 preparser::PreParser::PreParseProgram(&scanner,
5846 recorder,
5847 flags,
5848 stack_limit);
5849 if (result == preparser::PreParser::kPreParseStackOverflow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005850 isolate->StackOverflow();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00005851 return NULL;
5852 }
5853
5854 // Extract the accumulated data from the recorder as a single
5855 // contiguous vector that we are responsible for disposing.
5856 Vector<unsigned> store = recorder->ExtractData();
5857 return new ScriptDataImpl(store);
5858}
5859
5860
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005861ScriptDataImpl* ParserApi::PreParse(Utf16CharacterStream* source,
danno@chromium.orgb6451162011-08-17 14:33:23 +00005862 v8::Extension* extension,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005863 int flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005864 Handle<Script> no_script;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005865 if (FLAG_lazy && (extension == NULL)) {
5866 flags |= kAllowLazy;
5867 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00005868 CompleteParserRecorder recorder;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005869 return DoPreParse(source, flags, &recorder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005870}
5871
5872
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00005873bool RegExpParser::ParseRegExp(FlatStringReader* input,
5874 bool multiline,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005875 RegExpCompileData* result,
5876 Zone* zone) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005877 ASSERT(result != NULL);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005878 RegExpParser parser(input, &result->error, multiline, zone);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005879 RegExpTree* tree = parser.ParsePattern();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005880 if (parser.failed()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005881 ASSERT(tree == NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005882 ASSERT(!result->error.is_null());
5883 } else {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005884 ASSERT(tree != NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005885 ASSERT(result->error.is_null());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005886 result->tree = tree;
5887 int capture_count = parser.captures_started();
5888 result->simple = tree->IsAtom() && parser.simple() && capture_count == 0;
iposva@chromium.org245aa852009-02-10 00:49:54 +00005889 result->contains_anchor = parser.contains_anchor();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005890 result->capture_count = capture_count;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005891 }
5892 return !parser.failed();
5893}
5894
5895
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005896bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005897 ASSERT(info->function() == NULL);
5898 FunctionLiteral* result = NULL;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005899 ASSERT((parsing_flags & kLanguageModeMask) == CLASSIC_MODE);
5900 if (!info->is_native() && FLAG_harmony_scoping) {
5901 // Harmony scoping is requested.
5902 parsing_flags |= EXTENDED_MODE;
5903 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00005904 if (!info->is_native() && FLAG_harmony_modules) {
5905 parsing_flags |= kAllowModules;
5906 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005907 if (FLAG_allow_natives_syntax || info->is_native()) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00005908 // We require %identifier(..) syntax.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005909 parsing_flags |= kAllowNativesSyntax;
5910 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005911 if (info->is_lazy()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005912 ASSERT(!info->is_eval());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005913 Parser parser(info, parsing_flags, NULL, NULL);
yangguo@chromium.org56454712012-02-16 15:33:53 +00005914 if (info->shared_info()->is_function()) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005915 result = parser.ParseLazy();
yangguo@chromium.org56454712012-02-16 15:33:53 +00005916 } else {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005917 result = parser.ParseProgram();
yangguo@chromium.org56454712012-02-16 15:33:53 +00005918 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005919 } else {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005920 ScriptDataImpl* pre_data = info->pre_parse_data();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005921 Parser parser(info, parsing_flags, info->extension(), pre_data);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005922 if (pre_data != NULL && pre_data->has_error()) {
5923 Scanner::Location loc = pre_data->MessageLocation();
5924 const char* message = pre_data->BuildMessage();
5925 Vector<const char*> args = pre_data->BuildArgs();
5926 parser.ReportMessageAt(loc, message, args);
5927 DeleteArray(message);
5928 for (int i = 0; i < args.length(); i++) {
5929 DeleteArray(args[i]);
5930 }
5931 DeleteArray(args.start());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005932 ASSERT(info->isolate()->has_pending_exception());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005933 } else {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005934 result = parser.ParseProgram();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005935 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005936 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005937 info->SetFunction(result);
5938 return (result != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005939}
5940
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941} } // namespace v8::internal