blob: 5ec28577a8a22b2d52ba9c389614b68c7b5895d7 [file] [log] [blame]
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
danno@chromium.orgc612e022011-11-10 11:38:15 +000031#include "ast.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "bootstrapper.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000033#include "char-predicates-inl.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000034#include "codegen.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000035#include "compiler.h"
ricow@chromium.org65fae842010-08-25 15:26:24 +000036#include "func-name-inferrer.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000037#include "messages.h"
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +000038#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include "platform.h"
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000040#include "preparser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "runtime.h"
ricow@chromium.org55ee8072011-09-08 16:33:10 +000042#include "scanner-character-streams.h"
ager@chromium.orgb5737492010-07-15 09:29:43 +000043#include "scopeinfo.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000044#include "string-stream.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
kasperl@chromium.org71affb52009-05-26 05:44:31 +000046namespace v8 {
47namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000049// PositionStack is used for on-stack allocation of token positions for
50// new expressions. Please look at ParseNewExpression.
51
52class PositionStack {
53 public:
54 explicit PositionStack(bool* ok) : top_(NULL), ok_(ok) {}
55 ~PositionStack() { ASSERT(!*ok_ || is_empty()); }
56
57 class Element {
58 public:
59 Element(PositionStack* stack, int value) {
60 previous_ = stack->top();
61 value_ = value;
62 stack->set_top(this);
63 }
64
65 private:
66 Element* previous() { return previous_; }
67 int value() { return value_; }
68 friend class PositionStack;
69 Element* previous_;
70 int value_;
71 };
72
73 bool is_empty() { return top_ == NULL; }
74 int pop() {
75 ASSERT(!is_empty());
76 int result = top_->value();
77 top_ = top_->previous();
78 return result;
79 }
80
81 private:
82 Element* top() { return top_; }
83 void set_top(Element* value) { top_ = value; }
84 Element* top_;
85 bool* ok_;
86};
87
88
rossberg@chromium.org400388e2012-06-06 09:29:22 +000089RegExpBuilder::RegExpBuilder(Zone* zone)
90 : zone_(zone),
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000091 pending_empty_(false),
92 characters_(NULL),
93 terms_(),
94 alternatives_()
ager@chromium.orga74f0da2008-12-03 16:05:52 +000095#ifdef DEBUG
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000096 , last_added_(ADD_NONE)
ager@chromium.orga74f0da2008-12-03 16:05:52 +000097#endif
98 {}
99
100
101void RegExpBuilder::FlushCharacters() {
102 pending_empty_ = false;
103 if (characters_ != NULL) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000104 RegExpTree* atom = new(zone()) RegExpAtom(characters_->ToConstVector());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000105 characters_ = NULL;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000106 text_.Add(atom, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000107 LAST(ADD_ATOM);
108 }
109}
110
111
112void RegExpBuilder::FlushText() {
113 FlushCharacters();
114 int num_text = text_.length();
115 if (num_text == 0) {
116 return;
117 } else if (num_text == 1) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000118 terms_.Add(text_.last(), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000119 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000120 RegExpText* text = new(zone()) RegExpText(zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000121 for (int i = 0; i < num_text; i++)
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000122 text_.Get(i)->AppendToText(text, zone());
123 terms_.Add(text, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000124 }
125 text_.Clear();
126}
127
128
129void RegExpBuilder::AddCharacter(uc16 c) {
130 pending_empty_ = false;
131 if (characters_ == NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000132 characters_ = new(zone()) ZoneList<uc16>(4, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000133 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000134 characters_->Add(c, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000135 LAST(ADD_CHAR);
136}
137
138
139void RegExpBuilder::AddEmpty() {
140 pending_empty_ = true;
141}
142
143
144void RegExpBuilder::AddAtom(RegExpTree* term) {
145 if (term->IsEmpty()) {
146 AddEmpty();
147 return;
148 }
149 if (term->IsTextElement()) {
150 FlushCharacters();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000151 text_.Add(term, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000152 } else {
153 FlushText();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000154 terms_.Add(term, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000155 }
156 LAST(ADD_ATOM);
157}
158
159
160void RegExpBuilder::AddAssertion(RegExpTree* assert) {
161 FlushText();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000162 terms_.Add(assert, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000163 LAST(ADD_ASSERT);
164}
165
166
167void RegExpBuilder::NewAlternative() {
168 FlushTerms();
169}
170
171
172void RegExpBuilder::FlushTerms() {
173 FlushText();
174 int num_terms = terms_.length();
175 RegExpTree* alternative;
176 if (num_terms == 0) {
177 alternative = RegExpEmpty::GetInstance();
178 } else if (num_terms == 1) {
179 alternative = terms_.last();
180 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000181 alternative = new(zone()) RegExpAlternative(terms_.GetList(zone()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000182 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000183 alternatives_.Add(alternative, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000184 terms_.Clear();
185 LAST(ADD_NONE);
186}
187
188
189RegExpTree* RegExpBuilder::ToRegExp() {
190 FlushTerms();
191 int num_alternatives = alternatives_.length();
192 if (num_alternatives == 0) {
193 return RegExpEmpty::GetInstance();
194 }
195 if (num_alternatives == 1) {
196 return alternatives_.last();
197 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000198 return new(zone()) RegExpDisjunction(alternatives_.GetList(zone()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000199}
200
201
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000202void RegExpBuilder::AddQuantifierToAtom(int min,
203 int max,
204 RegExpQuantifier::Type type) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000205 if (pending_empty_) {
206 pending_empty_ = false;
207 return;
208 }
209 RegExpTree* atom;
210 if (characters_ != NULL) {
211 ASSERT(last_added_ == ADD_CHAR);
212 // Last atom was character.
213 Vector<const uc16> char_vector = characters_->ToConstVector();
214 int num_chars = char_vector.length();
215 if (num_chars > 1) {
216 Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000217 text_.Add(new(zone()) RegExpAtom(prefix), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000218 char_vector = char_vector.SubVector(num_chars - 1, num_chars);
219 }
220 characters_ = NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000221 atom = new(zone()) RegExpAtom(char_vector);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000222 FlushText();
223 } else if (text_.length() > 0) {
224 ASSERT(last_added_ == ADD_ATOM);
225 atom = text_.RemoveLast();
226 FlushText();
227 } else if (terms_.length() > 0) {
228 ASSERT(last_added_ == ADD_ATOM);
229 atom = terms_.RemoveLast();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000230 if (atom->max_match() == 0) {
231 // Guaranteed to only match an empty string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000232 LAST(ADD_TERM);
233 if (min == 0) {
234 return;
235 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000236 terms_.Add(atom, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000237 return;
238 }
239 } else {
240 // Only call immediately after adding an atom or character!
241 UNREACHABLE();
242 return;
243 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000244 terms_.Add(new(zone()) RegExpQuantifier(min, max, type, atom), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000245 LAST(ADD_TERM);
246}
247
248
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000249Handle<String> Parser::LookupSymbol(int symbol_id) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000250 // Length of symbol cache is the number of identified symbols.
251 // If we are larger than that, or negative, it's not a cached symbol.
252 // This might also happen if there is no preparser symbol data, even
253 // if there is some preparser data.
254 if (static_cast<unsigned>(symbol_id)
255 >= static_cast<unsigned>(symbol_cache_.length())) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000256 if (scanner().is_literal_ascii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000257 return isolate()->factory()->LookupAsciiSymbol(
258 scanner().literal_ascii_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000259 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000260 return isolate()->factory()->LookupTwoByteSymbol(
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000261 scanner().literal_utf16_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000262 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000263 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000264 return LookupCachedSymbol(symbol_id);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000265}
266
267
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000268Handle<String> Parser::LookupCachedSymbol(int symbol_id) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000269 // Make sure the cache is large enough to hold the symbol identifier.
270 if (symbol_cache_.length() <= symbol_id) {
271 // Increase length to index + 1.
272 symbol_cache_.AddBlock(Handle<String>::null(),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000273 symbol_id + 1 - symbol_cache_.length(), zone());
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000274 }
275 Handle<String> result = symbol_cache_.at(symbol_id);
276 if (result.is_null()) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000277 if (scanner().is_literal_ascii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000278 result = isolate()->factory()->LookupAsciiSymbol(
279 scanner().literal_ascii_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000280 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 result = isolate()->factory()->LookupTwoByteSymbol(
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000282 scanner().literal_utf16_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000283 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000284 symbol_cache_.at(symbol_id) = result;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000285 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000286 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000287 isolate()->counters()->total_preparse_symbols_skipped()->Increment();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000288 return result;
289}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000290
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000291
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000292FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) {
293 // The current pre-data entry must be a FunctionEntry with the given
294 // start position.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000295 if ((function_index_ + FunctionEntry::kSize <= store_.length())
296 && (static_cast<int>(store_[function_index_]) == start)) {
297 int index = function_index_;
298 function_index_ += FunctionEntry::kSize;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000299 return FunctionEntry(store_.SubVector(index,
300 index + FunctionEntry::kSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000301 }
302 return FunctionEntry();
303}
304
305
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000306int ScriptDataImpl::GetSymbolIdentifier() {
307 return ReadNumber(&symbol_data_);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000308}
309
310
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000311bool ScriptDataImpl::SanityCheck() {
312 // Check that the header data is valid and doesn't specify
313 // point to positions outside the store.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000314 if (store_.length() < PreparseDataConstants::kHeaderSize) return false;
315 if (magic() != PreparseDataConstants::kMagicNumber) return false;
316 if (version() != PreparseDataConstants::kCurrentVersion) return false;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000317 if (has_error()) {
318 // Extra sane sanity check for error message encoding.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000319 if (store_.length() <= PreparseDataConstants::kHeaderSize
320 + PreparseDataConstants::kMessageTextPos) {
321 return false;
322 }
323 if (Read(PreparseDataConstants::kMessageStartPos) >
324 Read(PreparseDataConstants::kMessageEndPos)) {
325 return false;
326 }
327 unsigned arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
328 int pos = PreparseDataConstants::kMessageTextPos;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000329 for (unsigned int i = 0; i <= arg_count; i++) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000330 if (store_.length() <= PreparseDataConstants::kHeaderSize + pos) {
331 return false;
332 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000333 int length = static_cast<int>(Read(pos));
334 if (length < 0) return false;
335 pos += 1 + length;
336 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000337 if (store_.length() < PreparseDataConstants::kHeaderSize + pos) {
338 return false;
339 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000340 return true;
341 }
342 // Check that the space allocated for function entries is sane.
343 int functions_size =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000344 static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000345 if (functions_size < 0) return false;
346 if (functions_size % FunctionEntry::kSize != 0) return false;
347 // Check that the count of symbols is non-negative.
348 int symbol_count =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000349 static_cast<int>(store_[PreparseDataConstants::kSymbolCountOffset]);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000350 if (symbol_count < 0) return false;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000351 // Check that the total size has room for header and function entries.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000352 int minimum_size =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000353 PreparseDataConstants::kHeaderSize + functions_size;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000354 if (store_.length() < minimum_size) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 return true;
356}
357
358
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000359
ricow@chromium.org65fae842010-08-25 15:26:24 +0000360const char* ScriptDataImpl::ReadString(unsigned* start, int* chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 int length = start[0];
362 char* result = NewArray<char>(length + 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000363 for (int i = 0; i < length; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 result[i] = start[i + 1];
ricow@chromium.org65fae842010-08-25 15:26:24 +0000365 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366 result[length] = '\0';
367 if (chars != NULL) *chars = length;
368 return result;
369}
370
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000371Scanner::Location ScriptDataImpl::MessageLocation() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000372 int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
373 int end_pos = Read(PreparseDataConstants::kMessageEndPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374 return Scanner::Location(beg_pos, end_pos);
375}
376
377
378const char* ScriptDataImpl::BuildMessage() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000379 unsigned* start = ReadAddress(PreparseDataConstants::kMessageTextPos);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000380 return ReadString(start, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381}
382
383
384Vector<const char*> ScriptDataImpl::BuildArgs() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000385 int arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 const char** array = NewArray<const char*>(arg_count);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000387 // Position after text found by skipping past length field and
388 // length field content words.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000389 int pos = PreparseDataConstants::kMessageTextPos + 1
390 + Read(PreparseDataConstants::kMessageTextPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 for (int i = 0; i < arg_count; i++) {
392 int count = 0;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000393 array[i] = ReadString(ReadAddress(pos), &count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 pos += count + 1;
395 }
396 return Vector<const char*>(array, arg_count);
397}
398
399
400unsigned ScriptDataImpl::Read(int position) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000401 return store_[PreparseDataConstants::kHeaderSize + position];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402}
403
404
405unsigned* ScriptDataImpl::ReadAddress(int position) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000406 return &store_[PreparseDataConstants::kHeaderSize + position];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407}
408
409
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000410Scope* Parser::NewScope(Scope* parent, ScopeType type) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000411 Scope* result = new(zone()) Scope(parent, type, zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000412 result->Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 return result;
414}
415
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000416
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417// ----------------------------------------------------------------------------
418// Target is a support class to facilitate manipulation of the
419// Parser's target_stack_ (the stack of potential 'break' and
420// 'continue' statement targets). Upon construction, a new target is
421// added; it is removed upon destruction.
422
423class Target BASE_EMBEDDED {
424 public:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000425 Target(Target** variable, AstNode* node)
426 : variable_(variable), node_(node), previous_(*variable) {
427 *variable = this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 }
429
430 ~Target() {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000431 *variable_ = previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000434 Target* previous() { return previous_; }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000435 AstNode* node() { return node_; }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437 private:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000438 Target** variable_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000439 AstNode* node_;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000440 Target* previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000441};
442
443
444class TargetScope BASE_EMBEDDED {
445 public:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000446 explicit TargetScope(Target** variable)
447 : variable_(variable), previous_(*variable) {
448 *variable = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449 }
450
451 ~TargetScope() {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000452 *variable_ = previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453 }
454
455 private:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000456 Target** variable_;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000457 Target* previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000458};
459
460
461// ----------------------------------------------------------------------------
danno@chromium.orgc612e022011-11-10 11:38:15 +0000462// FunctionState and BlockState together implement the parser's scope stack.
463// The parser's current scope is in top_scope_. The BlockState and
464// FunctionState constructors push on the scope stack and the destructors
465// pop. They are also used to hold the parser's per-function and per-block
466// state.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000467
danno@chromium.orgc612e022011-11-10 11:38:15 +0000468class Parser::BlockState BASE_EMBEDDED {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000469 public:
danno@chromium.orgc612e022011-11-10 11:38:15 +0000470 BlockState(Parser* parser, Scope* scope)
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000471 : parser_(parser),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000472 outer_scope_(parser->top_scope_) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000473 parser->top_scope_ = scope;
474 }
475
danno@chromium.orgc612e022011-11-10 11:38:15 +0000476 ~BlockState() { parser_->top_scope_ = outer_scope_; }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000477
478 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000479 Parser* parser_;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000480 Scope* outer_scope_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000481};
482
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000483
danno@chromium.orgc612e022011-11-10 11:38:15 +0000484Parser::FunctionState::FunctionState(Parser* parser,
485 Scope* scope,
486 Isolate* isolate)
487 : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000488 next_handler_index_(0),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000489 expected_property_count_(0),
490 only_simple_this_property_assignments_(false),
491 this_property_assignments_(isolate->factory()->empty_fixed_array()),
492 parser_(parser),
493 outer_function_state_(parser->current_function_state_),
494 outer_scope_(parser->top_scope_),
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000495 saved_ast_node_id_(isolate->ast_node_id()),
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000496 factory_(isolate, parser->zone()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000497 parser->top_scope_ = scope;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000498 parser->current_function_state_ = this;
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000499 isolate->set_ast_node_id(AstNode::kDeclarationsId + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000500}
501
502
danno@chromium.orgc612e022011-11-10 11:38:15 +0000503Parser::FunctionState::~FunctionState() {
504 parser_->top_scope_ = outer_scope_;
505 parser_->current_function_state_ = outer_function_state_;
yangguo@chromium.org56454712012-02-16 15:33:53 +0000506 if (outer_function_state_ != NULL) {
507 parser_->isolate()->set_ast_node_id(saved_ast_node_id_);
508 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509}
510
511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512// ----------------------------------------------------------------------------
513// The CHECK_OK macro is a convenient macro to enforce error
514// handling for functions that may fail (by returning !*ok).
515//
516// CAUTION: This macro appends extra statements after a call,
517// thus it must never be used where only a single statement
518// is correct (e.g. an if statement branch w/o braces)!
519
520#define CHECK_OK ok); \
521 if (!*ok) return NULL; \
522 ((void)0
523#define DUMMY ) // to make indentation work
524#undef DUMMY
525
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000526#define CHECK_FAILED /**/); \
527 if (failed_) return NULL; \
528 ((void)0
529#define DUMMY ) // to make indentation work
530#undef DUMMY
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531
532// ----------------------------------------------------------------------------
533// Implementation of Parser
534
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000535Parser::Parser(CompilationInfo* info,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000536 int parser_flags,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537 v8::Extension* extension,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000538 ScriptDataImpl* pre_data)
539 : isolate_(info->isolate()),
540 symbol_cache_(pre_data ? pre_data->symbol_count() : 0, info->zone()),
541 script_(info->script()),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000542 scanner_(isolate_->unicode_cache()),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000543 reusable_preparser_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544 top_scope_(NULL),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000545 current_function_state_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546 target_stack_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547 extension_(extension),
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000548 pre_data_(pre_data),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000549 fni_(NULL),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000550 allow_natives_syntax_((parser_flags & kAllowNativesSyntax) != 0),
551 allow_lazy_((parser_flags & kAllowLazy) != 0),
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000552 allow_modules_((parser_flags & kAllowModules) != 0),
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000553 stack_overflow_(false),
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000554 parenthesized_function_(false),
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000555 zone_(info->zone()),
556 info_(info) {
557 ASSERT(!script_.is_null());
yangguo@chromium.org56454712012-02-16 15:33:53 +0000558 isolate_->set_ast_node_id(0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000559 if ((parser_flags & kLanguageModeMask) == EXTENDED_MODE) {
560 scanner().SetHarmonyScoping(true);
561 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000562 if ((parser_flags & kAllowModules) != 0) {
563 scanner().SetHarmonyModules(true);
564 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565}
566
567
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000568FunctionLiteral* Parser::ParseProgram() {
569 ZoneScope zone_scope(zone(), DONT_DELETE_ON_EXIT);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000570
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000571 HistogramTimerScope timer(isolate()->counters()->parse());
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000572 Handle<String> source(String::cast(script_->source()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000573 isolate()->counters()->total_parse_size()->Increment(source->length());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000574 fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000575
576 // Initialize parser state.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000577 source->TryFlatten();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000578 if (source->IsExternalTwoByteString()) {
579 // Notice that the stream is destroyed at the end of the branch block.
580 // The last line of the blocks can't be moved outside, even though they're
581 // identical calls.
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000582 ExternalTwoByteStringUtf16CharacterStream stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000583 Handle<ExternalTwoByteString>::cast(source), 0, source->length());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000584 scanner_.Initialize(&stream);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000585 return DoParseProgram(info(), source, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000586 } else {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000587 GenericStringUtf16CharacterStream stream(source, 0, source->length());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000588 scanner_.Initialize(&stream);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000589 return DoParseProgram(info(), source, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000590 }
591}
592
593
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000594FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
595 Handle<String> source,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000596 ZoneScope* zone_scope) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000597 ASSERT(top_scope_ == NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000598 ASSERT(target_stack_ == NULL);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000599 if (pre_data_ != NULL) pre_data_->Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600
601 // Compute the parsing mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000602 mode_ = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603 if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;
604
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000605 Handle<String> no_name = isolate()->factory()->empty_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000606
607 FunctionLiteral* result = NULL;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000608 { Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
609 info->SetGlobalScope(scope);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000610 if (info->is_eval()) {
611 Handle<SharedFunctionInfo> shared = info->shared_info();
612 if (!info->is_global() && (shared.is_null() || shared->is_function())) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000613 scope = Scope::DeserializeScopeChain(*info->calling_context(), scope,
614 zone());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000615 }
616 if (!scope->is_global_scope() || info->language_mode() != CLASSIC_MODE) {
617 scope = NewScope(scope, EVAL_SCOPE);
618 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000619 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000620 scope->set_start_position(0);
621 scope->set_end_position(source->length());
danno@chromium.orgc612e022011-11-10 11:38:15 +0000622 FunctionState function_state(this, scope, isolate());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000623 top_scope_->SetLanguageMode(info->language_mode());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000624 ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000625 bool ok = true;
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000626 int beg_loc = scanner().location().beg_pos;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000627 ParseSourceElements(body, Token::EOS, info->is_eval(), &ok);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000628 if (ok && !top_scope_->is_classic_mode()) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000629 CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok);
630 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000631
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000632 if (ok && is_extended_mode()) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000633 CheckConflictingVarDeclarations(top_scope_, &ok);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000634 }
635
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636 if (ok) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000637 result = factory()->NewFunctionLiteral(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000638 no_name,
639 top_scope_,
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000640 body,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000641 function_state.materialized_literal_count(),
642 function_state.expected_property_count(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000643 function_state.handler_count(),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000644 function_state.only_simple_this_property_assignments(),
645 function_state.this_property_assignments(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000646 0,
yangguo@chromium.org56454712012-02-16 15:33:53 +0000647 FunctionLiteral::kNoDuplicateParameters,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000648 FunctionLiteral::ANONYMOUS_EXPRESSION,
yangguo@chromium.org56454712012-02-16 15:33:53 +0000649 FunctionLiteral::kGlobalOrEval);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000650 result->set_ast_properties(factory()->visitor()->ast_properties());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000651 } else if (stack_overflow_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000652 isolate()->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000653 }
654 }
655
656 // Make sure the target stack is empty.
657 ASSERT(target_stack_ == NULL);
658
659 // If there was a syntax error we have to get rid of the AST
660 // and it is not safe to do so before the scope has been deleted.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000661 if (result == NULL) zone_scope->DeleteOnExit();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000662 return result;
663}
664
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000665
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000666FunctionLiteral* Parser::ParseLazy() {
667 ZoneScope zone_scope(zone(), DONT_DELETE_ON_EXIT);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000668 HistogramTimerScope timer(isolate()->counters()->parse_lazy());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000669 Handle<String> source(String::cast(script_->source()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000670 isolate()->counters()->total_parse_size()->Increment(source->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000672 Handle<SharedFunctionInfo> shared_info = info()->shared_info();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000673 // Initialize parser state.
674 source->TryFlatten();
675 if (source->IsExternalTwoByteString()) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000676 ExternalTwoByteStringUtf16CharacterStream stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000677 Handle<ExternalTwoByteString>::cast(source),
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000678 shared_info->start_position(),
679 shared_info->end_position());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000680 FunctionLiteral* result = ParseLazy(&stream, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000681 return result;
682 } else {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000683 GenericStringUtf16CharacterStream stream(source,
684 shared_info->start_position(),
685 shared_info->end_position());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000686 FunctionLiteral* result = ParseLazy(&stream, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000687 return result;
688 }
689}
690
691
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000692FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000693 ZoneScope* zone_scope) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000694 Handle<SharedFunctionInfo> shared_info = info()->shared_info();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000695 scanner_.Initialize(source);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000696 ASSERT(top_scope_ == NULL);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000697 ASSERT(target_stack_ == NULL);
698
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000699 Handle<String> name(String::cast(shared_info->name()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000700 fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000701 fni_->PushEnclosingName(name);
702
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000703 mode_ = PARSE_EAGERLY;
704
705 // Place holder for the result.
706 FunctionLiteral* result = NULL;
707
708 {
709 // Parse the function literal.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000710 Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000711 info()->SetGlobalScope(scope);
712 if (!info()->closure().is_null()) {
713 scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000714 zone());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000715 }
danno@chromium.orgc612e022011-11-10 11:38:15 +0000716 FunctionState function_state(this, scope, isolate());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000717 ASSERT(scope->language_mode() != STRICT_MODE || !info()->is_classic_mode());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000718 ASSERT(scope->language_mode() != EXTENDED_MODE ||
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000719 info()->is_extended_mode());
720 ASSERT(info()->language_mode() == shared_info->language_mode());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000721 scope->SetLanguageMode(shared_info->language_mode());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000722 FunctionLiteral::Type type = shared_info->is_expression()
723 ? (shared_info->is_anonymous()
724 ? FunctionLiteral::ANONYMOUS_EXPRESSION
725 : FunctionLiteral::NAMED_EXPRESSION)
726 : FunctionLiteral::DECLARATION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000727 bool ok = true;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000728 result = ParseFunctionLiteral(name,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000729 false, // Strict mode name already checked.
730 RelocInfo::kNoPosition,
731 type,
732 &ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000733 // Make sure the results agree.
734 ASSERT(ok == (result != NULL));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735 }
736
737 // Make sure the target stack is empty.
738 ASSERT(target_stack_ == NULL);
739
740 // If there was a stack overflow we have to get rid of AST and it is
741 // not safe to do before scope has been deleted.
742 if (result == NULL) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000743 zone_scope->DeleteOnExit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000744 if (stack_overflow_) isolate()->StackOverflow();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000745 } else {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000746 Handle<String> inferred_name(shared_info->inferred_name());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000747 result->set_inferred_name(inferred_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000748 }
749 return result;
750}
751
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000752
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000753Handle<String> Parser::GetSymbol(bool* ok) {
754 int symbol_id = -1;
755 if (pre_data() != NULL) {
756 symbol_id = pre_data()->GetSymbolIdentifier();
757 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000758 return LookupSymbol(symbol_id);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000759}
760
761
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000762void Parser::ReportMessage(const char* type, Vector<const char*> args) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000763 Scanner::Location source_location = scanner().location();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764 ReportMessageAt(source_location, type, args);
765}
766
767
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000768void Parser::ReportMessage(const char* type, Vector<Handle<String> > args) {
769 Scanner::Location source_location = scanner().location();
770 ReportMessageAt(source_location, type, args);
771}
772
773
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000774void Parser::ReportMessageAt(Scanner::Location source_location,
775 const char* type,
776 Vector<const char*> args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777 MessageLocation location(script_,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000778 source_location.beg_pos,
779 source_location.end_pos);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000780 Factory* factory = isolate()->factory();
781 Handle<FixedArray> elements = factory->NewFixedArray(args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000782 for (int i = 0; i < args.length(); i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000783 Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000784 elements->set(i, *arg_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000785 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000786 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
787 Handle<Object> result = factory->NewSyntaxError(type, array);
788 isolate()->Throw(*result, &location);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000789}
790
791
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000792void Parser::ReportMessageAt(Scanner::Location source_location,
793 const char* type,
794 Vector<Handle<String> > args) {
795 MessageLocation location(script_,
796 source_location.beg_pos,
797 source_location.end_pos);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000798 Factory* factory = isolate()->factory();
799 Handle<FixedArray> elements = factory->NewFixedArray(args.length());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000800 for (int i = 0; i < args.length(); i++) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000801 elements->set(i, *args[i]);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000802 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000803 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
804 Handle<Object> result = factory->NewSyntaxError(type, array);
805 isolate()->Throw(*result, &location);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000806}
807
808
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000809// Base class containing common code for the different finder classes used by
810// the parser.
811class ParserFinder {
812 protected:
813 ParserFinder() {}
814 static Assignment* AsAssignment(Statement* stat) {
815 if (stat == NULL) return NULL;
816 ExpressionStatement* exp_stat = stat->AsExpressionStatement();
817 if (exp_stat == NULL) return NULL;
818 return exp_stat->expression()->AsAssignment();
819 }
820};
821
822
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000823// An InitializationBlockFinder finds and marks sequences of statements of the
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000824// form expr.a = ...; expr.b = ...; etc.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000825class InitializationBlockFinder : public ParserFinder {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000826 public:
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000827 // We find and mark the initialization blocks in top level
828 // non-looping code only. This is because the optimization prevents
829 // reuse of the map transitions, so it should be used only for code
830 // that will only be run once.
831 InitializationBlockFinder(Scope* top_scope, Target* target)
832 : enabled_(top_scope->DeclarationScope()->is_global_scope() &&
833 !IsLoopTarget(target)),
834 first_in_block_(NULL),
835 last_in_block_(NULL),
836 block_size_(0) {}
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000837
838 ~InitializationBlockFinder() {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000839 if (!enabled_) return;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000840 if (InBlock()) EndBlock();
841 }
842
843 void Update(Statement* stat) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000844 if (!enabled_) return;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000845 Assignment* assignment = AsAssignment(stat);
846 if (InBlock()) {
847 if (BlockContinues(assignment)) {
848 UpdateBlock(assignment);
849 } else {
850 EndBlock();
851 }
852 }
853 if (!InBlock() && (assignment != NULL) &&
854 (assignment->op() == Token::ASSIGN)) {
855 StartBlock(assignment);
856 }
857 }
858
859 private:
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000860 // The minimum number of contiguous assignment that will
861 // be treated as an initialization block. Benchmarks show that
862 // the overhead exceeds the savings below this limit.
863 static const int kMinInitializationBlock = 3;
864
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000865 static bool IsLoopTarget(Target* target) {
866 while (target != NULL) {
867 if (target->node()->AsIterationStatement() != NULL) return true;
868 target = target->previous();
869 }
870 return false;
871 }
872
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000873 // Returns true if the expressions appear to denote the same object.
874 // In the context of initialization blocks, we only consider expressions
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000875 // of the form 'expr.x' or expr["x"].
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000876 static bool SameObject(Expression* e1, Expression* e2) {
877 VariableProxy* v1 = e1->AsVariableProxy();
878 VariableProxy* v2 = e2->AsVariableProxy();
879 if (v1 != NULL && v2 != NULL) {
880 return v1->name()->Equals(*v2->name());
881 }
882 Property* p1 = e1->AsProperty();
883 Property* p2 = e2->AsProperty();
884 if ((p1 == NULL) || (p2 == NULL)) return false;
885 Literal* key1 = p1->key()->AsLiteral();
886 Literal* key2 = p2->key()->AsLiteral();
887 if ((key1 == NULL) || (key2 == NULL)) return false;
888 if (!key1->handle()->IsString() || !key2->handle()->IsString()) {
889 return false;
890 }
891 String* name1 = String::cast(*key1->handle());
892 String* name2 = String::cast(*key2->handle());
893 if (!name1->Equals(name2)) return false;
894 return SameObject(p1->obj(), p2->obj());
895 }
896
897 // Returns true if the expressions appear to denote different properties
898 // of the same object.
899 static bool PropertyOfSameObject(Expression* e1, Expression* e2) {
900 Property* p1 = e1->AsProperty();
901 Property* p2 = e2->AsProperty();
902 if ((p1 == NULL) || (p2 == NULL)) return false;
903 return SameObject(p1->obj(), p2->obj());
904 }
905
906 bool BlockContinues(Assignment* assignment) {
907 if ((assignment == NULL) || (first_in_block_ == NULL)) return false;
908 if (assignment->op() != Token::ASSIGN) return false;
909 return PropertyOfSameObject(first_in_block_->target(),
910 assignment->target());
911 }
912
913 void StartBlock(Assignment* assignment) {
914 first_in_block_ = assignment;
915 last_in_block_ = assignment;
916 block_size_ = 1;
917 }
918
919 void UpdateBlock(Assignment* assignment) {
920 last_in_block_ = assignment;
921 ++block_size_;
922 }
923
924 void EndBlock() {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000925 if (block_size_ >= kMinInitializationBlock) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000926 first_in_block_->mark_block_start();
927 last_in_block_->mark_block_end();
928 }
929 last_in_block_ = first_in_block_ = NULL;
930 block_size_ = 0;
931 }
932
933 bool InBlock() { return first_in_block_ != NULL; }
934
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000935 const bool enabled_;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000936 Assignment* first_in_block_;
937 Assignment* last_in_block_;
938 int block_size_;
939
940 DISALLOW_COPY_AND_ASSIGN(InitializationBlockFinder);
941};
942
943
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000944// A ThisNamedPropertyAssignmentFinder finds and marks statements of the form
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000945// this.x = ...;, where x is a named property. It also determines whether a
946// function contains only assignments of this type.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000947class ThisNamedPropertyAssignmentFinder : public ParserFinder {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000948 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000949 ThisNamedPropertyAssignmentFinder(Isolate* isolate, Zone* zone)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000950 : isolate_(isolate),
951 only_simple_this_property_assignments_(true),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000952 names_(0, zone),
953 assigned_arguments_(0, zone),
954 assigned_constants_(0, zone),
955 zone_(zone) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000956 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000957
958 void Update(Scope* scope, Statement* stat) {
ager@chromium.orgb9a15452009-11-11 09:55:05 +0000959 // Bail out if function already has property assignment that are
960 // not simple this property assignments.
961 if (!only_simple_this_property_assignments_) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000962 return;
963 }
964
965 // Check whether this statement is of the form this.x = ...;
966 Assignment* assignment = AsAssignment(stat);
967 if (IsThisPropertyAssignment(assignment)) {
968 HandleThisPropertyAssignment(scope, assignment);
969 } else {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000970 only_simple_this_property_assignments_ = false;
971 }
972 }
973
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000974 // Returns whether only statements of the form this.x = y; where y is either a
975 // constant or a function argument was encountered.
976 bool only_simple_this_property_assignments() {
977 return only_simple_this_property_assignments_;
978 }
979
980 // Returns a fixed array containing three elements for each assignment of the
981 // form this.x = y;
982 Handle<FixedArray> GetThisPropertyAssignments() {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000983 if (names_.is_empty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 return isolate_->factory()->empty_fixed_array();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000985 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000986 ASSERT_EQ(names_.length(), assigned_arguments_.length());
987 ASSERT_EQ(names_.length(), assigned_constants_.length());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000988 Handle<FixedArray> assignments =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000989 isolate_->factory()->NewFixedArray(names_.length() * 3);
990 for (int i = 0; i < names_.length(); ++i) {
991 assignments->set(i * 3, *names_[i]);
992 assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_[i]));
993 assignments->set(i * 3 + 2, *assigned_constants_[i]);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000994 }
995 return assignments;
996 }
997
998 private:
999 bool IsThisPropertyAssignment(Assignment* assignment) {
1000 if (assignment != NULL) {
1001 Property* property = assignment->target()->AsProperty();
1002 return assignment->op() == Token::ASSIGN
1003 && property != NULL
1004 && property->obj()->AsVariableProxy() != NULL
1005 && property->obj()->AsVariableProxy()->is_this();
1006 }
1007 return false;
1008 }
1009
1010 void HandleThisPropertyAssignment(Scope* scope, Assignment* assignment) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001011 // Check that the property assigned to is a named property, which is not
1012 // __proto__.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001013 Property* property = assignment->target()->AsProperty();
1014 ASSERT(property != NULL);
1015 Literal* literal = property->key()->AsLiteral();
1016 uint32_t dummy;
1017 if (literal != NULL &&
1018 literal->handle()->IsString() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001019 !String::cast(*(literal->handle()))->Equals(
1020 isolate_->heap()->Proto_symbol()) &&
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001021 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
1022 Handle<String> key = Handle<String>::cast(literal->handle());
1023
1024 // Check whether the value assigned is either a constant or matches the
1025 // name of one of the arguments to the function.
1026 if (assignment->value()->AsLiteral() != NULL) {
1027 // Constant assigned.
1028 Literal* literal = assignment->value()->AsLiteral();
1029 AssignmentFromConstant(key, literal->handle());
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001030 return;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001031 } else if (assignment->value()->AsVariableProxy() != NULL) {
1032 // Variable assigned.
1033 Handle<String> name =
1034 assignment->value()->AsVariableProxy()->name();
1035 // Check whether the variable assigned matches an argument name.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001036 for (int i = 0; i < scope->num_parameters(); i++) {
1037 if (*scope->parameter(i)->name() == *name) {
1038 // Assigned from function argument.
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001039 AssignmentFromParameter(key, i);
1040 return;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001041 }
1042 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001043 }
1044 }
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001045 // It is not a simple "this.x = value;" assignment with a constant
1046 // or parameter value.
1047 AssignmentFromSomethingElse();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001048 }
1049
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001050
1051
1052
1053 // We will potentially reorder the property assignments, so they must be
1054 // simple enough that the ordering does not matter.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001055 void AssignmentFromParameter(Handle<String> name, int index) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001056 EnsureInitialized();
1057 for (int i = 0; i < names_.length(); ++i) {
1058 if (name->Equals(*names_[i])) {
1059 assigned_arguments_[i] = index;
1060 assigned_constants_[i] = isolate_->factory()->undefined_value();
1061 return;
1062 }
1063 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001064 names_.Add(name, zone());
1065 assigned_arguments_.Add(index, zone());
1066 assigned_constants_.Add(isolate_->factory()->undefined_value(), zone());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001067 }
1068
1069 void AssignmentFromConstant(Handle<String> name, Handle<Object> value) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001070 EnsureInitialized();
1071 for (int i = 0; i < names_.length(); ++i) {
1072 if (name->Equals(*names_[i])) {
1073 assigned_arguments_[i] = -1;
1074 assigned_constants_[i] = value;
1075 return;
1076 }
1077 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001078 names_.Add(name, zone());
1079 assigned_arguments_.Add(-1, zone());
1080 assigned_constants_.Add(value, zone());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001081 }
1082
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001083 void AssignmentFromSomethingElse() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001084 // The this assignment is not a simple one.
1085 only_simple_this_property_assignments_ = false;
1086 }
1087
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001088 void EnsureInitialized() {
1089 if (names_.capacity() == 0) {
1090 ASSERT(assigned_arguments_.capacity() == 0);
1091 ASSERT(assigned_constants_.capacity() == 0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001092 names_.Initialize(4, zone());
1093 assigned_arguments_.Initialize(4, zone());
1094 assigned_constants_.Initialize(4, zone());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001095 }
1096 }
1097
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001098 Zone* zone() const { return zone_; }
1099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001100 Isolate* isolate_;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001101 bool only_simple_this_property_assignments_;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001102 ZoneStringList names_;
1103 ZoneList<int> assigned_arguments_;
1104 ZoneObjectList assigned_constants_;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001105 Zone* zone_;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001106};
1107
1108
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001109void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001110 int end_token,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001111 bool is_eval,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112 bool* ok) {
1113 // SourceElements ::
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001114 // (ModuleElement)* <end_token>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001115
1116 // Allocate a target stack to use for this set of source
1117 // elements. This way, all scripts and functions get their own
1118 // target stack thus avoiding illegal breaks and continues across
1119 // functions.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001120 TargetScope scope(&this->target_stack_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001121
1122 ASSERT(processor != NULL);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001123 InitializationBlockFinder block_finder(top_scope_, target_stack_);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001124 ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate(),
1125 zone());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001126 bool directive_prologue = true; // Parsing directive prologue.
1127
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001128 while (peek() != end_token) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001129 if (directive_prologue && peek() != Token::STRING) {
1130 directive_prologue = false;
1131 }
1132
1133 Scanner::Location token_loc = scanner().peek_location();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001134 Statement* stat = ParseModuleElement(NULL, CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001135 if (stat == NULL || stat->IsEmpty()) {
1136 directive_prologue = false; // End of directive prologue.
1137 continue;
1138 }
1139
1140 if (directive_prologue) {
1141 // A shot at a directive.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001142 ExpressionStatement* e_stat;
1143 Literal* literal;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001144 // Still processing directive prologue?
1145 if ((e_stat = stat->AsExpressionStatement()) != NULL &&
1146 (literal = e_stat->expression()->AsLiteral()) != NULL &&
1147 literal->handle()->IsString()) {
1148 Handle<String> directive = Handle<String>::cast(literal->handle());
1149
1150 // Check "use strict" directive (ES5 14.1).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001151 if (top_scope_->is_classic_mode() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001152 directive->Equals(isolate()->heap()->use_strict()) &&
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001153 token_loc.end_pos - token_loc.beg_pos ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001154 isolate()->heap()->use_strict()->length() + 2) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001155 // TODO(mstarzinger): Global strict eval calls, need their own scope
1156 // as specified in ES5 10.4.2(3). The correct fix would be to always
1157 // add this scope in DoParseProgram(), but that requires adaptations
1158 // all over the code base, so we go with a quick-fix for now.
1159 if (is_eval && !top_scope_->is_eval_scope()) {
1160 ASSERT(top_scope_->is_global_scope());
1161 Scope* scope = NewScope(top_scope_, EVAL_SCOPE);
1162 scope->set_start_position(top_scope_->start_position());
1163 scope->set_end_position(top_scope_->end_position());
1164 top_scope_ = scope;
1165 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001166 // TODO(ES6): Fix entering extended mode, once it is specified.
1167 top_scope_->SetLanguageMode(FLAG_harmony_scoping
1168 ? EXTENDED_MODE : STRICT_MODE);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001169 // "use strict" is the only directive for now.
1170 directive_prologue = false;
1171 }
1172 } else {
1173 // End of the directive prologue.
1174 directive_prologue = false;
1175 }
1176 }
1177
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001178 block_finder.Update(stat);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001179 // Find and mark all assignments to named properties in this (this.x =)
1180 if (top_scope_->is_function_scope()) {
1181 this_property_assignment_finder.Update(top_scope_, stat);
1182 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001183 processor->Add(stat, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001185
1186 // Propagate the collected information on this property assignments.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001187 if (top_scope_->is_function_scope()) {
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001188 bool only_simple_this_property_assignments =
ager@chromium.org5c838252010-02-19 08:53:10 +00001189 this_property_assignment_finder.only_simple_this_property_assignments()
1190 && top_scope_->declarations()->length() == 0;
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001191 if (only_simple_this_property_assignments) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001192 current_function_state_->SetThisPropertyAssignmentInfo(
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001193 only_simple_this_property_assignments,
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001194 this_property_assignment_finder.GetThisPropertyAssignments());
1195 }
1196 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 return 0;
1199}
1200
1201
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001202Statement* Parser::ParseModuleElement(ZoneStringList* labels,
1203 bool* ok) {
1204 // (Ecma 262 5th Edition, clause 14):
1205 // SourceElement:
1206 // Statement
1207 // FunctionDeclaration
1208 //
1209 // In harmony mode we allow additionally the following productions
1210 // ModuleElement:
1211 // LetDeclaration
1212 // ConstDeclaration
1213 // ModuleDeclaration
1214 // ImportDeclaration
1215 // ExportDeclaration
1216
1217 switch (peek()) {
1218 case Token::FUNCTION:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001219 return ParseFunctionDeclaration(NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001220 case Token::LET:
1221 case Token::CONST:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001222 return ParseVariableStatement(kModuleElement, NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001223 case Token::IMPORT:
1224 return ParseImportDeclaration(ok);
1225 case Token::EXPORT:
1226 return ParseExportDeclaration(ok);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00001227 default: {
1228 Statement* stmt = ParseStatement(labels, CHECK_OK);
1229 // Handle 'module' as a context-sensitive keyword.
1230 if (FLAG_harmony_modules &&
1231 peek() == Token::IDENTIFIER &&
1232 !scanner().HasAnyLineTerminatorBeforeNext() &&
1233 stmt != NULL) {
1234 ExpressionStatement* estmt = stmt->AsExpressionStatement();
1235 if (estmt != NULL &&
1236 estmt->expression()->AsVariableProxy() != NULL &&
1237 estmt->expression()->AsVariableProxy()->name()->Equals(
1238 isolate()->heap()->module_symbol()) &&
1239 !scanner().literal_contains_escapes()) {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001240 return ParseModuleDeclaration(NULL, ok);
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00001241 }
1242 }
1243 return stmt;
1244 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001245 }
1246}
1247
1248
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001249Statement* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001250 // ModuleDeclaration:
1251 // 'module' Identifier Module
1252
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001253 Handle<String> name = ParseIdentifier(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001254
1255#ifdef DEBUG
1256 if (FLAG_print_interface_details)
1257 PrintF("# Module %s...\n", name->ToAsciiArray());
1258#endif
1259
ulan@chromium.org812308e2012-02-29 15:58:45 +00001260 Module* module = ParseModule(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001261 VariableProxy* proxy = NewUnresolved(name, LET, module->interface());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001262 Declaration* declaration =
1263 factory()->NewModuleDeclaration(proxy, module, top_scope_);
1264 Declare(declaration, true, CHECK_OK);
1265
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001266#ifdef DEBUG
1267 if (FLAG_print_interface_details)
1268 PrintF("# Module %s.\n", name->ToAsciiArray());
1269
1270 if (FLAG_print_interfaces) {
1271 PrintF("module %s : ", name->ToAsciiArray());
1272 module->interface()->Print();
1273 }
1274#endif
1275
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001276 if (names) names->Add(name, zone());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001277 if (module->body() == NULL)
1278 return factory()->NewEmptyStatement();
1279 else
1280 return module->body();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001281}
1282
1283
1284Module* Parser::ParseModule(bool* ok) {
1285 // Module:
1286 // '{' ModuleElement '}'
ulan@chromium.org812308e2012-02-29 15:58:45 +00001287 // '=' ModulePath ';'
1288 // 'at' String ';'
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001289
1290 switch (peek()) {
1291 case Token::LBRACE:
1292 return ParseModuleLiteral(ok);
1293
ulan@chromium.org812308e2012-02-29 15:58:45 +00001294 case Token::ASSIGN: {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001295 Expect(Token::ASSIGN, CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001296 Module* result = ParseModulePath(CHECK_OK);
1297 ExpectSemicolon(CHECK_OK);
1298 return result;
1299 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001300
ulan@chromium.org812308e2012-02-29 15:58:45 +00001301 default: {
1302 ExpectContextualKeyword("at", CHECK_OK);
1303 Module* result = ParseModuleUrl(CHECK_OK);
1304 ExpectSemicolon(CHECK_OK);
1305 return result;
1306 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001307 }
1308}
1309
1310
1311Module* Parser::ParseModuleLiteral(bool* ok) {
1312 // Module:
1313 // '{' ModuleElement '}'
1314
1315 // Construct block expecting 16 statements.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001316 Block* body = factory()->NewBlock(NULL, 16, false);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001317#ifdef DEBUG
1318 if (FLAG_print_interface_details) PrintF("# Literal ");
1319#endif
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001320 Scope* scope = NewScope(top_scope_, MODULE_SCOPE);
1321
1322 Expect(Token::LBRACE, CHECK_OK);
1323 scope->set_start_position(scanner().location().beg_pos);
1324 scope->SetLanguageMode(EXTENDED_MODE);
1325
1326 {
1327 BlockState block_state(this, scope);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001328 TargetCollector collector(zone());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001329 Target target(&this->target_stack_, &collector);
1330 Target target_body(&this->target_stack_, body);
1331 InitializationBlockFinder block_finder(top_scope_, target_stack_);
1332
1333 while (peek() != Token::RBRACE) {
1334 Statement* stat = ParseModuleElement(NULL, CHECK_OK);
1335 if (stat && !stat->IsEmpty()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001336 body->AddStatement(stat, zone());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001337 block_finder.Update(stat);
1338 }
1339 }
1340 }
1341
1342 Expect(Token::RBRACE, CHECK_OK);
1343 scope->set_end_position(scanner().location().end_pos);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001344 body->set_scope(scope);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001345
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001346 // Check that all exports are bound.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001347 Interface* interface = scope->interface();
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001348 for (Interface::Iterator it = interface->iterator();
1349 !it.done(); it.Advance()) {
1350 if (scope->LocalLookup(it.name()) == NULL) {
1351 Handle<String> name(it.name());
1352 ReportMessage("module_export_undefined",
1353 Vector<Handle<String> >(&name, 1));
1354 *ok = false;
1355 return NULL;
1356 }
1357 }
1358
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001359 interface->MakeModule(ok);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001360 ASSERT(*ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001361 interface->Freeze(ok);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001362 ASSERT(*ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001363 return factory()->NewModuleLiteral(body, interface);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001364}
1365
1366
1367Module* Parser::ParseModulePath(bool* ok) {
1368 // ModulePath:
1369 // Identifier
1370 // ModulePath '.' Identifier
1371
1372 Module* result = ParseModuleVariable(CHECK_OK);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001373 while (Check(Token::PERIOD)) {
1374 Handle<String> name = ParseIdentifierName(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001375#ifdef DEBUG
1376 if (FLAG_print_interface_details)
1377 PrintF("# Path .%s ", name->ToAsciiArray());
1378#endif
1379 Module* member = factory()->NewModulePath(result, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001380 result->interface()->Add(name, member->interface(), zone(), ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001381 if (!*ok) {
1382#ifdef DEBUG
1383 if (FLAG_print_interfaces) {
1384 PrintF("PATH TYPE ERROR at '%s'\n", name->ToAsciiArray());
1385 PrintF("result: ");
1386 result->interface()->Print();
1387 PrintF("member: ");
1388 member->interface()->Print();
1389 }
1390#endif
1391 ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
1392 return NULL;
1393 }
1394 result = member;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001395 }
1396
1397 return result;
1398}
1399
1400
1401Module* Parser::ParseModuleVariable(bool* ok) {
1402 // ModulePath:
1403 // Identifier
1404
1405 Handle<String> name = ParseIdentifier(CHECK_OK);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001406#ifdef DEBUG
1407 if (FLAG_print_interface_details)
1408 PrintF("# Module variable %s ", name->ToAsciiArray());
1409#endif
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001410 VariableProxy* proxy = top_scope_->NewUnresolved(
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001411 factory(), name, Interface::NewModule(zone()),
1412 scanner().location().beg_pos);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001413
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001414 return factory()->NewModuleVariable(proxy);
1415}
1416
1417
1418Module* Parser::ParseModuleUrl(bool* ok) {
1419 // Module:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001420 // String
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001421
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001422 Expect(Token::STRING, CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001423 Handle<String> symbol = GetSymbol(CHECK_OK);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001424
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001425 // TODO(ES6): Request JS resource from environment...
1426
1427#ifdef DEBUG
1428 if (FLAG_print_interface_details) PrintF("# Url ");
1429#endif
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001430
1431 Module* result = factory()->NewModuleUrl(symbol);
1432 Interface* interface = result->interface();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001433 interface->Freeze(ok);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001434 ASSERT(*ok);
1435 // Create dummy scope to avoid errors as long as the feature isn't finished.
1436 Scope* scope = NewScope(top_scope_, MODULE_SCOPE);
1437 interface->Unify(scope->interface(), zone(), ok);
1438 ASSERT(*ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001439 return result;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001440}
1441
1442
ulan@chromium.org812308e2012-02-29 15:58:45 +00001443Module* Parser::ParseModuleSpecifier(bool* ok) {
1444 // ModuleSpecifier:
1445 // String
1446 // ModulePath
1447
1448 if (peek() == Token::STRING) {
1449 return ParseModuleUrl(ok);
1450 } else {
1451 return ParseModulePath(ok);
1452 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001453}
1454
1455
ulan@chromium.org812308e2012-02-29 15:58:45 +00001456Block* Parser::ParseImportDeclaration(bool* ok) {
1457 // ImportDeclaration:
1458 // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleSpecifier ';'
1459 //
1460 // TODO(ES6): implement destructuring ImportSpecifiers
1461
1462 Expect(Token::IMPORT, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001463 ZoneStringList names(1, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001464
1465 Handle<String> name = ParseIdentifierName(CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001466 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001467 while (peek() == Token::COMMA) {
1468 Consume(Token::COMMA);
1469 name = ParseIdentifierName(CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001470 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001471 }
1472
1473 ExpectContextualKeyword("from", CHECK_OK);
1474 Module* module = ParseModuleSpecifier(CHECK_OK);
1475 ExpectSemicolon(CHECK_OK);
1476
1477 // Generate a separate declaration for each identifier.
1478 // TODO(ES6): once we implement destructuring, make that one declaration.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001479 Block* block = factory()->NewBlock(NULL, 1, true);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001480 for (int i = 0; i < names.length(); ++i) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001481#ifdef DEBUG
1482 if (FLAG_print_interface_details)
1483 PrintF("# Import %s ", names[i]->ToAsciiArray());
1484#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001485 Interface* interface = Interface::NewUnknown(zone());
1486 module->interface()->Add(names[i], interface, zone(), ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001487 if (!*ok) {
1488#ifdef DEBUG
1489 if (FLAG_print_interfaces) {
1490 PrintF("IMPORT TYPE ERROR at '%s'\n", names[i]->ToAsciiArray());
1491 PrintF("module: ");
1492 module->interface()->Print();
1493 }
1494#endif
1495 ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
1496 return NULL;
1497 }
1498 VariableProxy* proxy = NewUnresolved(names[i], LET, interface);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001499 Declaration* declaration =
1500 factory()->NewImportDeclaration(proxy, module, top_scope_);
1501 Declare(declaration, true, CHECK_OK);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001502 }
1503
ulan@chromium.org812308e2012-02-29 15:58:45 +00001504 return block;
1505}
1506
1507
1508Statement* Parser::ParseExportDeclaration(bool* ok) {
1509 // ExportDeclaration:
1510 // 'export' Identifier (',' Identifier)* ';'
1511 // 'export' VariableDeclaration
1512 // 'export' FunctionDeclaration
1513 // 'export' ModuleDeclaration
1514 //
1515 // TODO(ES6): implement structuring ExportSpecifiers
1516
1517 Expect(Token::EXPORT, CHECK_OK);
1518
1519 Statement* result = NULL;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001520 ZoneStringList names(1, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001521 switch (peek()) {
1522 case Token::IDENTIFIER: {
1523 Handle<String> name = ParseIdentifier(CHECK_OK);
1524 // Handle 'module' as a context-sensitive keyword.
1525 if (!name->IsEqualTo(CStrVector("module"))) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001526 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001527 while (peek() == Token::COMMA) {
1528 Consume(Token::COMMA);
1529 name = ParseIdentifier(CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001530 names.Add(name, zone());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001531 }
1532 ExpectSemicolon(CHECK_OK);
1533 result = factory()->NewEmptyStatement();
1534 } else {
1535 result = ParseModuleDeclaration(&names, CHECK_OK);
1536 }
1537 break;
1538 }
1539
1540 case Token::FUNCTION:
1541 result = ParseFunctionDeclaration(&names, CHECK_OK);
1542 break;
1543
1544 case Token::VAR:
1545 case Token::LET:
1546 case Token::CONST:
1547 result = ParseVariableStatement(kModuleElement, &names, CHECK_OK);
1548 break;
1549
1550 default:
1551 *ok = false;
1552 ReportUnexpectedToken(scanner().current_token());
1553 return NULL;
1554 }
1555
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001556 // Extract declared names into export declarations and interface.
1557 Interface* interface = top_scope_->interface();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001558 for (int i = 0; i < names.length(); ++i) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001559#ifdef DEBUG
1560 if (FLAG_print_interface_details)
1561 PrintF("# Export %s ", names[i]->ToAsciiArray());
1562#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001563 Interface* inner = Interface::NewUnknown(zone());
1564 interface->Add(names[i], inner, zone(), CHECK_OK);
1565 if (!*ok)
1566 return NULL;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001567 VariableProxy* proxy = NewUnresolved(names[i], LET, inner);
1568 USE(proxy);
1569 // TODO(rossberg): Rethink whether we actually need to store export
1570 // declarations (for compilation?).
1571 // ExportDeclaration* declaration =
1572 // factory()->NewExportDeclaration(proxy, top_scope_);
1573 // top_scope_->AddDeclaration(declaration);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001574 }
1575
1576 ASSERT(result != NULL);
1577 return result;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001578}
1579
1580
1581Statement* Parser::ParseBlockElement(ZoneStringList* labels,
1582 bool* ok) {
1583 // (Ecma 262 5th Edition, clause 14):
1584 // SourceElement:
1585 // Statement
1586 // FunctionDeclaration
1587 //
1588 // In harmony mode we allow additionally the following productions
1589 // BlockElement (aka SourceElement):
1590 // LetDeclaration
1591 // ConstDeclaration
1592
1593 switch (peek()) {
1594 case Token::FUNCTION:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001595 return ParseFunctionDeclaration(NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001596 case Token::LET:
1597 case Token::CONST:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001598 return ParseVariableStatement(kModuleElement, NULL, ok);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001599 default:
1600 return ParseStatement(labels, ok);
1601 }
1602}
1603
1604
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
1606 // Statement ::
1607 // Block
1608 // VariableStatement
1609 // EmptyStatement
1610 // ExpressionStatement
1611 // IfStatement
1612 // IterationStatement
1613 // ContinueStatement
1614 // BreakStatement
1615 // ReturnStatement
1616 // WithStatement
1617 // LabelledStatement
1618 // SwitchStatement
1619 // ThrowStatement
1620 // TryStatement
1621 // DebuggerStatement
1622
1623 // Note: Since labels can only be used by 'break' and 'continue'
1624 // statements, which themselves are only valid within blocks,
1625 // iterations or 'switch' statements (i.e., BreakableStatements),
1626 // labels can be simply ignored in all other cases; except for
ager@chromium.org32912102009-01-16 10:38:43 +00001627 // trivial labeled break statements 'label: break label' which is
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628 // parsed into an empty statement.
1629
1630 // Keep the source position of the statement
1631 int statement_pos = scanner().peek_location().beg_pos;
1632 Statement* stmt = NULL;
1633 switch (peek()) {
1634 case Token::LBRACE:
1635 return ParseBlock(labels, ok);
1636
1637 case Token::CONST: // fall through
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001638 case Token::LET:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639 case Token::VAR:
ulan@chromium.org812308e2012-02-29 15:58:45 +00001640 stmt = ParseVariableStatement(kStatement, NULL, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001641 break;
1642
1643 case Token::SEMICOLON:
1644 Next();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001645 return factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001646
1647 case Token::IF:
1648 stmt = ParseIfStatement(labels, ok);
1649 break;
1650
1651 case Token::DO:
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001652 stmt = ParseDoWhileStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001653 break;
1654
1655 case Token::WHILE:
1656 stmt = ParseWhileStatement(labels, ok);
1657 break;
1658
1659 case Token::FOR:
1660 stmt = ParseForStatement(labels, ok);
1661 break;
1662
1663 case Token::CONTINUE:
1664 stmt = ParseContinueStatement(ok);
1665 break;
1666
1667 case Token::BREAK:
1668 stmt = ParseBreakStatement(labels, ok);
1669 break;
1670
1671 case Token::RETURN:
1672 stmt = ParseReturnStatement(ok);
1673 break;
1674
1675 case Token::WITH:
1676 stmt = ParseWithStatement(labels, ok);
1677 break;
1678
1679 case Token::SWITCH:
1680 stmt = ParseSwitchStatement(labels, ok);
1681 break;
1682
1683 case Token::THROW:
1684 stmt = ParseThrowStatement(ok);
1685 break;
1686
1687 case Token::TRY: {
1688 // NOTE: It is somewhat complicated to have labels on
1689 // try-statements. When breaking out of a try-finally statement,
1690 // one must take great care not to treat it as a
1691 // fall-through. It is much easier just to wrap the entire
1692 // try-statement in a statement block and put the labels there
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001693 Block* result = factory()->NewBlock(labels, 1, false);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001694 Target target(&this->target_stack_, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001695 TryStatement* statement = ParseTryStatement(CHECK_OK);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001696 if (statement) {
1697 statement->set_statement_pos(statement_pos);
1698 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001699 if (result) result->AddStatement(statement, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700 return result;
1701 }
1702
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001703 case Token::FUNCTION: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001704 // FunctionDeclaration is only allowed in the context of SourceElements
1705 // (Ecma 262 5th Edition, clause 14):
1706 // SourceElement:
1707 // Statement
1708 // FunctionDeclaration
1709 // Common language extension is to allow function declaration in place
1710 // of any statement. This language extension is disabled in strict mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001711 if (!top_scope_->is_classic_mode()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001712 ReportMessageAt(scanner().peek_location(), "strict_function",
1713 Vector<const char*>::empty());
1714 *ok = false;
1715 return NULL;
1716 }
ulan@chromium.org812308e2012-02-29 15:58:45 +00001717 return ParseFunctionDeclaration(NULL, ok);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001718 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001720 case Token::DEBUGGER:
1721 stmt = ParseDebuggerStatement(ok);
1722 break;
1723
1724 default:
1725 stmt = ParseExpressionOrLabelledStatement(labels, ok);
1726 }
1727
1728 // Store the source position of the statement
1729 if (stmt != NULL) stmt->set_statement_pos(statement_pos);
1730 return stmt;
1731}
1732
1733
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001734VariableProxy* Parser::NewUnresolved(
1735 Handle<String> name, VariableMode mode, Interface* interface) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00001736 // If we are inside a function, a declaration of a var/const variable is a
1737 // truly local variable, and the scope of the variable is always the function
1738 // scope.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001739 // Let/const variables in harmony mode are always added to the immediately
1740 // enclosing scope.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001741 return DeclarationScope(mode)->NewUnresolved(
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001742 factory(), name, interface, scanner().location().beg_pos);
ulan@chromium.org812308e2012-02-29 15:58:45 +00001743}
1744
1745
1746void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001747 VariableProxy* proxy = declaration->proxy();
1748 Handle<String> name = proxy->name();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001749 VariableMode mode = declaration->mode();
1750 Scope* declaration_scope = DeclarationScope(mode);
1751 Variable* var = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001752
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001753 // If a suitable scope exists, then we can statically declare this
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001754 // variable and also set its mode. In any case, a Declaration node
1755 // will be added to the scope so that the declaration can be added
1756 // to the corresponding activation frame at runtime if necessary.
1757 // For instance declarations inside an eval scope need to be added
1758 // to the calling function context.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001759 // Similarly, strict mode eval scope does not leak variable declarations to
1760 // the caller's scope so we declare all locals, too.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001761 if (declaration_scope->is_function_scope() ||
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001762 declaration_scope->is_strict_or_extended_eval_scope() ||
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001763 declaration_scope->is_block_scope() ||
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001764 declaration_scope->is_module_scope() ||
1765 declaration->AsModuleDeclaration() != NULL) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001766 // Declare the variable in the declaration scope.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001767 var = declaration_scope->LocalLookup(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768 if (var == NULL) {
1769 // Declare the name.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001770 var = declaration_scope->DeclareLocal(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001771 name, mode, declaration->initialization(), proxy->interface());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001773 // The name was declared in this scope before; check for conflicting
1774 // re-declarations. We have a conflict if either of the declarations is
1775 // not a var. There is similar code in runtime.cc in the Declare
1776 // functions. The function CheckNonConflictingScope checks for conflicting
1777 // var and let bindings from different scopes whereas this is a check for
1778 // conflicting declarations within the same scope. This check also covers
1779 //
1780 // function () { let x; { var x; } }
1781 //
1782 // because the var declaration is hoisted to the function scope where 'x'
1783 // is already bound.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001784 if ((mode != VAR) || (var->mode() != VAR)) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00001785 // We only have vars, consts and lets in declarations.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001786 ASSERT(var->mode() == VAR ||
1787 var->mode() == CONST ||
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001788 var->mode() == CONST_HARMONY ||
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001789 var->mode() == LET);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001790 if (is_extended_mode()) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001791 // In harmony mode we treat re-declarations as early errors. See
1792 // ES5 16 for a definition of early errors.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001793 SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001794 const char* elms[2] = { "Variable", *c_string };
1795 Vector<const char*> args(elms, 2);
1796 ReportMessage("redeclaration", args);
1797 *ok = false;
ulan@chromium.org812308e2012-02-29 15:58:45 +00001798 return;
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001799 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001800 const char* type = (var->mode() == VAR)
1801 ? "var" : var->is_const_mode() ? "const" : "let";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001802 Handle<String> type_string =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001803 isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804 Expression* expression =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001805 NewThrowTypeError(isolate()->factory()->redeclaration_symbol(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001806 type_string, name);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001807 declaration_scope->SetIllegalRedeclaration(expression);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001808 }
1809 }
1810 }
1811
1812 // We add a declaration node for every declaration. The compiler
1813 // will only generate code if necessary. In particular, declarations
1814 // for inner local variables that do not represent functions won't
1815 // result in any generated code.
1816 //
1817 // Note that we always add an unresolved proxy even if it's not
1818 // used, simply because we don't know in this method (w/o extra
1819 // parameters) if the proxy is needed or not. The proxy will be
1820 // bound during variable resolution time unless it was pre-bound
1821 // below.
1822 //
1823 // WARNING: This will lead to multiple declaration nodes for the
1824 // same variable if it is declared several times. This is not a
1825 // semantic issue as long as we keep the source order, but it may be
1826 // a performance issue since it may lead to repeated
1827 // Runtime::DeclareContextSlot() calls.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001828 declaration_scope->AddDeclaration(declaration);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001830 if ((mode == CONST || mode == CONST_HARMONY) &&
1831 declaration_scope->is_global_scope()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001832 // For global const variables we bind the proxy to a variable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833 ASSERT(resolve); // should be set by all callers
ager@chromium.org3e875802009-06-29 08:26:34 +00001834 Variable::Kind kind = Variable::NORMAL;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001835 var = new(zone()) Variable(declaration_scope,
1836 name,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001837 mode,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001838 true,
1839 kind,
1840 kNeedsInitialization);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001841 } else if (declaration_scope->is_eval_scope() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001842 declaration_scope->is_classic_mode()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001843 // For variable declarations in a non-strict eval scope the proxy is bound
1844 // to a lookup variable to force a dynamic declaration using the
1845 // DeclareContextSlot runtime function.
1846 Variable::Kind kind = Variable::NORMAL;
1847 var = new(zone()) Variable(declaration_scope,
1848 name,
1849 mode,
1850 true,
1851 kind,
ulan@chromium.org812308e2012-02-29 15:58:45 +00001852 declaration->initialization());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001853 var->AllocateTo(Variable::LOOKUP, -1);
1854 resolve = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001855 }
1856
1857 // If requested and we have a local variable, bind the proxy to the variable
1858 // at parse-time. This is used for functions (and consts) declared inside
1859 // statements: the corresponding function (or const) variable must be in the
1860 // function scope and not a statement-local scope, e.g. as provided with a
1861 // 'with' statement:
1862 //
1863 // with (obj) {
1864 // function f() {}
1865 // }
1866 //
1867 // which is translated into:
1868 //
1869 // with (obj) {
1870 // // in this case this is not: 'var f; f = function () {};'
1871 // var f = function () {};
1872 // }
1873 //
1874 // Note that if 'f' is accessed from inside the 'with' statement, it
1875 // will be allocated in the context (because we must be able to look
1876 // it up dynamically) but it will also be accessed statically, i.e.,
1877 // with a context slot index and a context chain length for this
1878 // initialization code. Thus, inside the 'with' statement, we need
1879 // both access to the static and the dynamic context chain; the
1880 // runtime needs to provide both.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001881 if (resolve && var != NULL) {
1882 proxy->BindTo(var);
1883
1884 if (FLAG_harmony_modules) {
1885 bool ok;
1886#ifdef DEBUG
1887 if (FLAG_print_interface_details)
1888 PrintF("# Declare %s\n", var->name()->ToAsciiArray());
1889#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001890 proxy->interface()->Unify(var->interface(), zone(), &ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001891 if (!ok) {
1892#ifdef DEBUG
1893 if (FLAG_print_interfaces) {
1894 PrintF("DECLARE TYPE ERROR\n");
1895 PrintF("proxy: ");
1896 proxy->interface()->Print();
1897 PrintF("var: ");
1898 var->interface()->Print();
1899 }
1900#endif
1901 ReportMessage("module_type_error", Vector<Handle<String> >(&name, 1));
1902 }
1903 }
1904 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001905}
1906
1907
1908// Language extension which is only enabled for source files loaded
1909// through the API's extension mechanism. A native function
1910// declaration is resolved by looking up the function through a
1911// callback provided by the extension.
1912Statement* Parser::ParseNativeDeclaration(bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001913 Expect(Token::FUNCTION, CHECK_OK);
1914 Handle<String> name = ParseIdentifier(CHECK_OK);
1915 Expect(Token::LPAREN, CHECK_OK);
1916 bool done = (peek() == Token::RPAREN);
1917 while (!done) {
1918 ParseIdentifier(CHECK_OK);
1919 done = (peek() == Token::RPAREN);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001920 if (!done) {
1921 Expect(Token::COMMA, CHECK_OK);
1922 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001923 }
1924 Expect(Token::RPAREN, CHECK_OK);
1925 Expect(Token::SEMICOLON, CHECK_OK);
1926
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001927 // Make sure that the function containing the native declaration
1928 // isn't lazily compiled. The extension structures are only
1929 // accessible while parsing the first time not when reparsing
1930 // because of lazy compilation.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001931 DeclarationScope(VAR)->ForceEagerCompilation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932
1933 // Compute the function template for the native function.
1934 v8::Handle<v8::FunctionTemplate> fun_template =
1935 extension_->GetNativeFunction(v8::Utils::ToLocal(name));
1936 ASSERT(!fun_template.IsEmpty());
1937
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001938 // Instantiate the function and create a shared function info from it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 Handle<JSFunction> fun = Utils::OpenHandle(*fun_template->GetFunction());
1940 const int literals = fun->NumberOfLiterals();
1941 Handle<Code> code = Handle<Code>(fun->shared()->code());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001942 Handle<Code> construct_stub = Handle<Code>(fun->shared()->construct_stub());
ager@chromium.orgb5737492010-07-15 09:29:43 +00001943 Handle<SharedFunctionInfo> shared =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001944 isolate()->factory()->NewSharedFunctionInfo(name, literals, code,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001945 Handle<ScopeInfo>(fun->shared()->scope_info()));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001946 shared->set_construct_stub(*construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001948 // Copy the function data to the shared function info.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001949 shared->set_function_data(fun->shared()->function_data());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001950 int parameters = fun->shared()->formal_parameter_count();
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001951 shared->set_formal_parameter_count(parameters);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001952
1953 // TODO(1240846): It's weird that native function declarations are
1954 // introduced dynamically when we meet their declarations, whereas
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001955 // other functions are set up when entering the surrounding scope.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001956 VariableProxy* proxy = NewUnresolved(name, VAR, Interface::NewValue());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001957 Declaration* declaration =
1958 factory()->NewVariableDeclaration(proxy, VAR, top_scope_);
1959 Declare(declaration, true, CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001960 SharedFunctionInfoLiteral* lit =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001961 factory()->NewSharedFunctionInfoLiteral(shared);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001962 return factory()->NewExpressionStatement(
1963 factory()->NewAssignment(
ulan@chromium.org812308e2012-02-29 15:58:45 +00001964 Token::INIT_VAR, proxy, lit, RelocInfo::kNoPosition));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001965}
1966
1967
ulan@chromium.org812308e2012-02-29 15:58:45 +00001968Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001969 // FunctionDeclaration ::
1970 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001971 Expect(Token::FUNCTION, CHECK_OK);
1972 int function_token_position = scanner().location().beg_pos;
ager@chromium.org04921a82011-06-27 13:21:41 +00001973 bool is_strict_reserved = false;
1974 Handle<String> name = ParseIdentifierOrStrictReservedWord(
1975 &is_strict_reserved, CHECK_OK);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001976 FunctionLiteral* fun = ParseFunctionLiteral(name,
ager@chromium.org04921a82011-06-27 13:21:41 +00001977 is_strict_reserved,
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001978 function_token_position,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001979 FunctionLiteral::DECLARATION,
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001980 CHECK_OK);
1981 // Even if we're not at the top-level of the global or a function
1982 // scope, we treat is as such and introduce the function with it's
1983 // initial value upon entering the corresponding scope.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001984 VariableMode mode = is_extended_mode() ? LET : VAR;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001985 VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue());
ulan@chromium.org812308e2012-02-29 15:58:45 +00001986 Declaration* declaration =
1987 factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_);
1988 Declare(declaration, true, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001989 if (names) names->Add(name, zone());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001990 return factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991}
1992
1993
1994Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001995 if (top_scope_->is_extended_mode()) return ParseScopedBlock(labels, ok);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001996
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997 // Block ::
1998 // '{' Statement* '}'
1999
2000 // Note that a Block does not introduce a new execution scope!
2001 // (ECMA-262, 3rd, 12.2)
2002 //
2003 // Construct block expecting 16 statements.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002004 Block* result = factory()->NewBlock(labels, 16, false);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002005 Target target(&this->target_stack_, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006 Expect(Token::LBRACE, CHECK_OK);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002007 InitializationBlockFinder block_finder(top_scope_, target_stack_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008 while (peek() != Token::RBRACE) {
2009 Statement* stat = ParseStatement(NULL, CHECK_OK);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002010 if (stat && !stat->IsEmpty()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002011 result->AddStatement(stat, zone());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002012 block_finder.Update(stat);
2013 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014 }
2015 Expect(Token::RBRACE, CHECK_OK);
2016 return result;
2017}
2018
2019
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002020Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002021 // The harmony mode uses block elements instead of statements.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002022 //
2023 // Block ::
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002024 // '{' BlockElement* '}'
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002025
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002026 // Construct block expecting 16 statements.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002027 Block* body = factory()->NewBlock(labels, 16, false);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002028 Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002029
2030 // Parse the statements and collect escaping labels.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002031 Expect(Token::LBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002032 block_scope->set_start_position(scanner().location().beg_pos);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002033 { BlockState block_state(this, block_scope);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002034 TargetCollector collector(zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002035 Target target(&this->target_stack_, &collector);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002036 Target target_body(&this->target_stack_, body);
2037 InitializationBlockFinder block_finder(top_scope_, target_stack_);
2038
2039 while (peek() != Token::RBRACE) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002040 Statement* stat = ParseBlockElement(NULL, CHECK_OK);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002041 if (stat && !stat->IsEmpty()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002042 body->AddStatement(stat, zone());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002043 block_finder.Update(stat);
2044 }
2045 }
2046 }
2047 Expect(Token::RBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002048 block_scope->set_end_position(scanner().location().end_pos);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002049 block_scope = block_scope->FinalizeBlockScope();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002050 body->set_scope(block_scope);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002051 return body;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002052}
2053
2054
danno@chromium.orgb6451162011-08-17 14:33:23 +00002055Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
ulan@chromium.org812308e2012-02-29 15:58:45 +00002056 ZoneStringList* names,
danno@chromium.orgb6451162011-08-17 14:33:23 +00002057 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058 // VariableStatement ::
2059 // VariableDeclarations ';'
2060
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002061 Handle<String> ignore;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002062 Block* result =
ulan@chromium.org812308e2012-02-29 15:58:45 +00002063 ParseVariableDeclarations(var_context, NULL, names, &ignore, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064 ExpectSemicolon(CHECK_OK);
2065 return result;
2066}
2067
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002068
2069bool Parser::IsEvalOrArguments(Handle<String> string) {
2070 return string.is_identical_to(isolate()->factory()->eval_symbol()) ||
2071 string.is_identical_to(isolate()->factory()->arguments_symbol());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002072}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002074
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002075// If the variable declaration declares exactly one non-const
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002076// variable, then *out is set to that variable. In all other cases,
2077// *out is untouched; in particular, it is the caller's responsibility
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002078// to initialize it properly. This mechanism is used for the parsing
2079// of 'for-in' loops.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002080Block* Parser::ParseVariableDeclarations(
2081 VariableDeclarationContext var_context,
2082 VariableDeclarationProperties* decl_props,
ulan@chromium.org812308e2012-02-29 15:58:45 +00002083 ZoneStringList* names,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002084 Handle<String>* out,
2085 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002086 // VariableDeclarations ::
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002087 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
2088 //
2089 // The ES6 Draft Rev3 specifies the following grammar for const declarations
2090 //
2091 // ConstDeclaration ::
2092 // const ConstBinding (',' ConstBinding)* ';'
2093 // ConstBinding ::
2094 // Identifier '=' AssignmentExpression
2095 //
2096 // TODO(ES6):
2097 // ConstBinding ::
2098 // BindingPattern '=' AssignmentExpression
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002099 VariableMode mode = VAR;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002100 // True if the binding needs initialization. 'let' and 'const' declared
2101 // bindings are created uninitialized by their declaration nodes and
2102 // need initialization. 'var' declared bindings are always initialized
2103 // immediately by their declaration nodes.
2104 bool needs_init = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002105 bool is_const = false;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002106 Token::Value init_op = Token::INIT_VAR;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002107 if (peek() == Token::VAR) {
2108 Consume(Token::VAR);
2109 } else if (peek() == Token::CONST) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002110 // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
2111 //
2112 // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
2113 //
2114 // * It is a Syntax Error if the code that matches this production is not
2115 // contained in extended code.
2116 //
2117 // However disallowing const in classic mode will break compatibility with
2118 // existing pages. Therefore we keep allowing const with the old
2119 // non-harmony semantics in classic mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002120 Consume(Token::CONST);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002121 switch (top_scope_->language_mode()) {
2122 case CLASSIC_MODE:
2123 mode = CONST;
2124 init_op = Token::INIT_CONST;
2125 break;
2126 case STRICT_MODE:
2127 ReportMessage("strict_const", Vector<const char*>::empty());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002128 *ok = false;
2129 return NULL;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002130 case EXTENDED_MODE:
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002131 if (var_context == kStatement) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002132 // In extended mode 'const' declarations are only allowed in source
2133 // element positions.
2134 ReportMessage("unprotected_const", Vector<const char*>::empty());
2135 *ok = false;
2136 return NULL;
2137 }
2138 mode = CONST_HARMONY;
2139 init_op = Token::INIT_CONST_HARMONY;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002140 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002141 is_const = true;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002142 needs_init = true;
danno@chromium.orgb6451162011-08-17 14:33:23 +00002143 } else if (peek() == Token::LET) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002144 // ES6 Draft Rev4 section 12.2.1:
2145 //
2146 // LetDeclaration : let LetBindingList ;
2147 //
2148 // * It is a Syntax Error if the code that matches this production is not
2149 // contained in extended code.
2150 if (!is_extended_mode()) {
2151 ReportMessage("illegal_let", Vector<const char*>::empty());
2152 *ok = false;
2153 return NULL;
2154 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00002155 Consume(Token::LET);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002156 if (var_context == kStatement) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002157 // Let declarations are only allowed in source element positions.
danno@chromium.orgb6451162011-08-17 14:33:23 +00002158 ReportMessage("unprotected_let", Vector<const char*>::empty());
2159 *ok = false;
2160 return NULL;
2161 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002162 mode = LET;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002163 needs_init = true;
2164 init_op = Token::INIT_LET;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002165 } else {
2166 UNREACHABLE(); // by current callers
2167 }
2168
ulan@chromium.org812308e2012-02-29 15:58:45 +00002169 Scope* declaration_scope = DeclarationScope(mode);
2170
danno@chromium.orgb6451162011-08-17 14:33:23 +00002171 // The scope of a var/const declared variable anywhere inside a function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
danno@chromium.orgb6451162011-08-17 14:33:23 +00002173 // transform a source-level var/const declaration into a (Function)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002174 // Scope declaration, and rewrite the source-level initialization into an
2175 // assignment statement. We use a block to collect multiple assignments.
2176 //
2177 // We mark the block as initializer block because we don't want the
2178 // rewriter to add a '.result' assignment to such a block (to get compliant
2179 // behavior for code such as print(eval('var x = 7')), and for cosmetic
2180 // reasons when pretty-printing. Also, unless an assignment (initialization)
2181 // is inside an initializer block, it is ignored.
2182 //
2183 // Create new block with one expected declaration.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002184 Block* block = factory()->NewBlock(NULL, 1, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002185 int nvars = 0; // the number of variables declared
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002186 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002187 do {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002188 if (fni_ != NULL) fni_->Enter();
2189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 // Parse variable name.
2191 if (nvars > 0) Consume(Token::COMMA);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002192 name = ParseIdentifier(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002193 if (fni_ != NULL) fni_->PushVariableName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002194
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002195 // Strict mode variables may not be named eval or arguments
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002196 if (!declaration_scope->is_classic_mode() && IsEvalOrArguments(name)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002197 ReportMessage("strict_var_name", Vector<const char*>::empty());
2198 *ok = false;
2199 return NULL;
2200 }
2201
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002202 // Declare variable.
2203 // Note that we *always* must treat the initial value via a separate init
2204 // assignment for variables and constants because the value must be assigned
2205 // when the variable is encountered in the source. But the variable/constant
2206 // is declared (and set to 'undefined') upon entering the function within
2207 // which the variable or constant is declared. Only function variables have
2208 // an initial value in the declaration (because they are initialized upon
2209 // entering the function).
2210 //
2211 // If we have a const declaration, in an inner scope, the proxy is always
2212 // bound to the declared variable (independent of possibly surrounding with
2213 // statements).
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002214 // For let/const declarations in harmony mode, we can also immediately
2215 // pre-resolve the proxy because it resides in the same scope as the
2216 // declaration.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002217 Interface* interface =
2218 is_const ? Interface::NewConst() : Interface::NewValue();
2219 VariableProxy* proxy = NewUnresolved(name, mode, interface);
ulan@chromium.org812308e2012-02-29 15:58:45 +00002220 Declaration* declaration =
2221 factory()->NewVariableDeclaration(proxy, mode, top_scope_);
2222 Declare(declaration, mode != VAR, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002223 nvars++;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002224 if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002225 ReportMessageAt(scanner().location(), "too_many_variables",
2226 Vector<const char*>::empty());
2227 *ok = false;
2228 return NULL;
2229 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002230 if (names) names->Add(name, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002231
2232 // Parse initialization expression if present and/or needed. A
2233 // declaration of the form:
2234 //
2235 // var v = x;
2236 //
2237 // is syntactic sugar for:
2238 //
2239 // var v; v = x;
2240 //
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002241 // In particular, we need to re-lookup 'v' (in top_scope_, not
2242 // declaration_scope) as it may be a different 'v' than the 'v' in the
2243 // declaration (e.g., if we are inside a 'with' statement or 'catch'
2244 // block).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002245 //
2246 // However, note that const declarations are different! A const
2247 // declaration of the form:
2248 //
2249 // const c = x;
2250 //
2251 // is *not* syntactic sugar for:
2252 //
2253 // const c; c = x;
2254 //
2255 // The "variable" c initialized to x is the same as the declared
2256 // one - there is no re-lookup (see the last parameter of the
2257 // Declare() call above).
2258
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002259 Scope* initialization_scope = is_const ? declaration_scope : top_scope_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002260 Expression* value = NULL;
2261 int position = -1;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002262 // Harmony consts have non-optional initializers.
2263 if (peek() == Token::ASSIGN || mode == CONST_HARMONY) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002264 Expect(Token::ASSIGN, CHECK_OK);
2265 position = scanner().location().beg_pos;
danno@chromium.orgb6451162011-08-17 14:33:23 +00002266 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002267 // Don't infer if it is "a = function(){...}();"-like expression.
ager@chromium.org04921a82011-06-27 13:21:41 +00002268 if (fni_ != NULL &&
2269 value->AsCall() == NULL &&
2270 value->AsCallNew() == NULL) {
2271 fni_->Infer();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002272 } else {
2273 fni_->RemoveLastFunction();
ager@chromium.org04921a82011-06-27 13:21:41 +00002274 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002275 if (decl_props != NULL) *decl_props = kHasInitializers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002276 }
2277
danno@chromium.orgc612e022011-11-10 11:38:15 +00002278 // Record the end position of the initializer.
2279 if (proxy->var() != NULL) {
2280 proxy->var()->set_initializer_position(scanner().location().end_pos);
2281 }
2282
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002283 // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
2284 if (value == NULL && needs_init) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002285 value = GetLiteralUndefined();
2286 }
2287
2288 // Global variable declarations must be compiled in a specific
2289 // way. When the script containing the global variable declaration
2290 // is entered, the global variable must be declared, so that if it
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002291 // doesn't exist (on the global object itself, see ES5 errata) it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002292 // gets created with an initial undefined value. This is handled
2293 // by the declarations part of the function representing the
2294 // top-level global code; see Runtime::DeclareGlobalVariable. If
2295 // it already exists (in the object or in a prototype), it is
2296 // *not* touched until the variable declaration statement is
2297 // executed.
2298 //
2299 // Executing the variable declaration statement will always
2300 // guarantee to give the global object a "local" variable; a
2301 // variable defined in the global object and not in any
2302 // prototype. This way, global variable declarations can shadow
2303 // properties in the prototype chain, but only after the variable
2304 // declaration statement has been executed. This is important in
2305 // browsers where the global object (window) has lots of
2306 // properties defined in prototype objects.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002307 if (initialization_scope->is_global_scope()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002308 // Compute the arguments for the runtime call.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002309 ZoneList<Expression*>* arguments =
2310 new(zone()) ZoneList<Expression*>(3, zone());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002311 // We have at least 1 parameter.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002312 arguments->Add(factory()->NewLiteral(name), zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002313 CallRuntime* initialize;
2314
2315 if (is_const) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002316 arguments->Add(value, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002317 value = NULL; // zap the value to avoid the unnecessary assignment
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002318
2319 // Construct the call to Runtime_InitializeConstGlobal
2320 // and add it to the initialization statement block.
2321 // Note that the function does different things depending on
2322 // the number of arguments (1 or 2).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002323 initialize = factory()->NewCallRuntime(
2324 isolate()->factory()->InitializeConstGlobal_symbol(),
2325 Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
2326 arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002327 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002328 // Add strict mode.
2329 // We may want to pass singleton to avoid Literal allocations.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002330 LanguageMode language_mode = initialization_scope->language_mode();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002331 arguments->Add(factory()->NewNumberLiteral(language_mode), zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002332
2333 // Be careful not to assign a value to the global variable if
2334 // we're in a with. The initialization value should not
2335 // necessarily be stored in the global object in that case,
2336 // which is why we need to generate a separate assignment node.
2337 if (value != NULL && !inside_with()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002338 arguments->Add(value, zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002339 value = NULL; // zap the value to avoid the unnecessary assignment
2340 }
2341
2342 // Construct the call to Runtime_InitializeVarGlobal
2343 // and add it to the initialization statement block.
2344 // Note that the function does different things depending on
2345 // the number of arguments (2 or 3).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002346 initialize = factory()->NewCallRuntime(
2347 isolate()->factory()->InitializeVarGlobal_symbol(),
2348 Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
2349 arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002350 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002351
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002352 block->AddStatement(factory()->NewExpressionStatement(initialize),
2353 zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002354 } else if (needs_init) {
2355 // Constant initializations always assign to the declared constant which
2356 // is always at the function scope level. This is only relevant for
2357 // dynamically looked-up variables and constants (the start context for
2358 // constant lookups is always the function context, while it is the top
2359 // context for var declared variables). Sigh...
2360 // For 'let' and 'const' declared variables in harmony mode the
2361 // initialization also always assigns to the declared variable.
2362 ASSERT(proxy != NULL);
2363 ASSERT(proxy->var() != NULL);
2364 ASSERT(value != NULL);
2365 Assignment* assignment =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002366 factory()->NewAssignment(init_op, proxy, value, position);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002367 block->AddStatement(factory()->NewExpressionStatement(assignment),
2368 zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002369 value = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002370 }
2371
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002372 // Add an assignment node to the initialization statement block if we still
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002373 // have a pending initialization value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002374 if (value != NULL) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002375 ASSERT(mode == VAR);
2376 // 'var' initializations are simply assignments (with all the consequences
2377 // if they are inside a 'with' statement - they may change a 'with' object
2378 // property).
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002379 VariableProxy* proxy =
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002380 initialization_scope->NewUnresolved(factory(), name, interface);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002381 Assignment* assignment =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002382 factory()->NewAssignment(init_op, proxy, value, position);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002383 block->AddStatement(factory()->NewExpressionStatement(assignment),
2384 zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002385 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002386
2387 if (fni_ != NULL) fni_->Leave();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002388 } while (peek() == Token::COMMA);
2389
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002390 // If there was a single non-const declaration, return it in the output
2391 // parameter for possible use by for/in.
2392 if (nvars == 1 && !is_const) {
2393 *out = name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002394 }
2395
2396 return block;
2397}
2398
2399
2400static bool ContainsLabel(ZoneStringList* labels, Handle<String> label) {
2401 ASSERT(!label.is_null());
2402 if (labels != NULL)
2403 for (int i = labels->length(); i-- > 0; )
2404 if (labels->at(i).is_identical_to(label))
2405 return true;
2406
2407 return false;
2408}
2409
2410
2411Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
2412 bool* ok) {
2413 // ExpressionStatement | LabelledStatement ::
2414 // Expression ';'
2415 // Identifier ':' Statement
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002416 bool starts_with_idenfifier = peek_any_identifier();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002417 Expression* expr = ParseExpression(true, CHECK_OK);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002418 if (peek() == Token::COLON && starts_with_idenfifier && expr != NULL &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002419 expr->AsVariableProxy() != NULL &&
2420 !expr->AsVariableProxy()->is_this()) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002421 // Expression is a single identifier, and not, e.g., a parenthesized
2422 // identifier.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002423 VariableProxy* var = expr->AsVariableProxy();
2424 Handle<String> label = var->name();
2425 // TODO(1240780): We don't check for redeclaration of labels
2426 // during preparsing since keeping track of the set of active
2427 // labels requires nontrivial changes to the way scopes are
2428 // structured. However, these are probably changes we want to
2429 // make later anyway so we should go back and fix this then.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002430 if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002431 SmartArrayPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002432 const char* elms[2] = { "Label", *c_string };
2433 Vector<const char*> args(elms, 2);
2434 ReportMessage("redeclaration", args);
2435 *ok = false;
2436 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002437 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002438 if (labels == NULL) {
2439 labels = new(zone()) ZoneStringList(4, zone());
2440 }
2441 labels->Add(label, zone());
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002442 // Remove the "ghost" variable that turned out to be a label
2443 // from the top scope. This way, we don't try to resolve it
2444 // during the scope processing.
2445 top_scope_->RemoveUnresolved(var);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002446 Expect(Token::COLON, CHECK_OK);
2447 return ParseStatement(labels, ok);
2448 }
2449
whesse@chromium.org7b260152011-06-20 15:33:18 +00002450 // If we have an extension, we allow a native function declaration.
2451 // A native function declaration starts with "native function" with
2452 // no line-terminator between the two words.
2453 if (extension_ != NULL &&
2454 peek() == Token::FUNCTION &&
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002455 !scanner().HasAnyLineTerminatorBeforeNext() &&
whesse@chromium.org7b260152011-06-20 15:33:18 +00002456 expr != NULL &&
2457 expr->AsVariableProxy() != NULL &&
2458 expr->AsVariableProxy()->name()->Equals(
2459 isolate()->heap()->native_symbol()) &&
2460 !scanner().literal_contains_escapes()) {
2461 return ParseNativeDeclaration(ok);
2462 }
2463
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +00002464 // Parsed expression statement, or the context-sensitive 'module' keyword.
2465 // Only expect semicolon in the former case.
2466 if (!FLAG_harmony_modules ||
2467 peek() != Token::IDENTIFIER ||
2468 scanner().HasAnyLineTerminatorBeforeNext() ||
2469 expr->AsVariableProxy() == NULL ||
2470 !expr->AsVariableProxy()->name()->Equals(
2471 isolate()->heap()->module_symbol()) ||
2472 scanner().literal_contains_escapes()) {
2473 ExpectSemicolon(CHECK_OK);
2474 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002475 return factory()->NewExpressionStatement(expr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002476}
2477
2478
2479IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) {
2480 // IfStatement ::
2481 // 'if' '(' Expression ')' Statement ('else' Statement)?
2482
2483 Expect(Token::IF, CHECK_OK);
2484 Expect(Token::LPAREN, CHECK_OK);
2485 Expression* condition = ParseExpression(true, CHECK_OK);
2486 Expect(Token::RPAREN, CHECK_OK);
2487 Statement* then_statement = ParseStatement(labels, CHECK_OK);
2488 Statement* else_statement = NULL;
2489 if (peek() == Token::ELSE) {
2490 Next();
2491 else_statement = ParseStatement(labels, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002492 } else {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002493 else_statement = factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002494 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002495 return factory()->NewIfStatement(condition, then_statement, else_statement);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002496}
2497
2498
2499Statement* Parser::ParseContinueStatement(bool* ok) {
2500 // ContinueStatement ::
2501 // 'continue' Identifier? ';'
2502
2503 Expect(Token::CONTINUE, CHECK_OK);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002504 Handle<String> label = Handle<String>::null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002505 Token::Value tok = peek();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002506 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002507 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002508 label = ParseIdentifier(CHECK_OK);
2509 }
2510 IterationStatement* target = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002511 target = LookupContinueTarget(label, CHECK_OK);
2512 if (target == NULL) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002513 // Illegal continue statement.
2514 const char* message = "illegal_continue";
2515 Vector<Handle<String> > args;
2516 if (!label.is_null()) {
2517 message = "unknown_label";
2518 args = Vector<Handle<String> >(&label, 1);
2519 }
2520 ReportMessageAt(scanner().location(), message, args);
2521 *ok = false;
2522 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002523 }
2524 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002525 return factory()->NewContinueStatement(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002526}
2527
2528
2529Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
2530 // BreakStatement ::
2531 // 'break' Identifier? ';'
2532
2533 Expect(Token::BREAK, CHECK_OK);
2534 Handle<String> label;
2535 Token::Value tok = peek();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002536 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002537 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002538 label = ParseIdentifier(CHECK_OK);
2539 }
ager@chromium.org32912102009-01-16 10:38:43 +00002540 // Parse labeled break statements that target themselves into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002541 // empty statements, e.g. 'l1: l2: l3: break l2;'
2542 if (!label.is_null() && ContainsLabel(labels, label)) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002543 ExpectSemicolon(CHECK_OK);
2544 return factory()->NewEmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002545 }
2546 BreakableStatement* target = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002547 target = LookupBreakTarget(label, CHECK_OK);
2548 if (target == NULL) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002549 // Illegal break statement.
2550 const char* message = "illegal_break";
2551 Vector<Handle<String> > args;
2552 if (!label.is_null()) {
2553 message = "unknown_label";
2554 args = Vector<Handle<String> >(&label, 1);
2555 }
2556 ReportMessageAt(scanner().location(), message, args);
2557 *ok = false;
2558 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002559 }
2560 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002561 return factory()->NewBreakStatement(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002562}
2563
2564
2565Statement* Parser::ParseReturnStatement(bool* ok) {
2566 // ReturnStatement ::
2567 // 'return' Expression? ';'
2568
2569 // Consume the return token. It is necessary to do the before
2570 // reporting any errors on it, because of the way errors are
2571 // reported (underlining).
2572 Expect(Token::RETURN, CHECK_OK);
2573
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002574 Token::Value tok = peek();
2575 Statement* result;
2576 if (scanner().HasAnyLineTerminatorBeforeNext() ||
2577 tok == Token::SEMICOLON ||
2578 tok == Token::RBRACE ||
2579 tok == Token::EOS) {
2580 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002581 result = factory()->NewReturnStatement(GetLiteralUndefined());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002582 } else {
2583 Expression* expr = ParseExpression(true, CHECK_OK);
2584 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002585 result = factory()->NewReturnStatement(expr);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002586 }
2587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002588 // An ECMAScript program is considered syntactically incorrect if it
2589 // contains a return statement that is not within the body of a
2590 // function. See ECMA-262, section 12.9, page 67.
2591 //
2592 // To be consistent with KJS we report the syntax error at runtime.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002593 Scope* declaration_scope = top_scope_->DeclarationScope();
2594 if (declaration_scope->is_global_scope() ||
2595 declaration_scope->is_eval_scope()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002596 Handle<String> type = isolate()->factory()->illegal_return_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002597 Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002598 return factory()->NewExpressionStatement(throw_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002599 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002600 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002601}
2602
2603
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002604Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
2605 // WithStatement ::
2606 // 'with' '(' Expression ')' Statement
2607
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002608 Expect(Token::WITH, CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002609
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002610 if (!top_scope_->is_classic_mode()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002611 ReportMessage("strict_mode_with", Vector<const char*>::empty());
2612 *ok = false;
2613 return NULL;
2614 }
2615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002616 Expect(Token::LPAREN, CHECK_OK);
2617 Expression* expr = ParseExpression(true, CHECK_OK);
2618 Expect(Token::RPAREN, CHECK_OK);
2619
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002620 top_scope_->DeclarationScope()->RecordWithStatement();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002621 Scope* with_scope = NewScope(top_scope_, WITH_SCOPE);
2622 Statement* stmt;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002623 { BlockState block_state(this, with_scope);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002624 with_scope->set_start_position(scanner().peek_location().beg_pos);
2625 stmt = ParseStatement(labels, CHECK_OK);
2626 with_scope->set_end_position(scanner().location().end_pos);
2627 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002628 return factory()->NewWithStatement(expr, stmt);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002629}
2630
2631
2632CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
2633 // CaseClause ::
2634 // 'case' Expression ':' Statement*
2635 // 'default' ':' Statement*
2636
2637 Expression* label = NULL; // NULL expression indicates default case
2638 if (peek() == Token::CASE) {
2639 Expect(Token::CASE, CHECK_OK);
2640 label = ParseExpression(true, CHECK_OK);
2641 } else {
2642 Expect(Token::DEFAULT, CHECK_OK);
2643 if (*default_seen_ptr) {
2644 ReportMessage("multiple_defaults_in_switch",
2645 Vector<const char*>::empty());
2646 *ok = false;
2647 return NULL;
2648 }
2649 *default_seen_ptr = true;
2650 }
2651 Expect(Token::COLON, CHECK_OK);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002652 int pos = scanner().location().beg_pos;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002653 ZoneList<Statement*>* statements =
2654 new(zone()) ZoneList<Statement*>(5, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002655 while (peek() != Token::CASE &&
2656 peek() != Token::DEFAULT &&
2657 peek() != Token::RBRACE) {
2658 Statement* stat = ParseStatement(NULL, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002659 statements->Add(stat, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002660 }
2661
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002662 return new(zone()) CaseClause(isolate(), label, statements, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002663}
2664
2665
2666SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels,
2667 bool* ok) {
2668 // SwitchStatement ::
2669 // 'switch' '(' Expression ')' '{' CaseClause* '}'
2670
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002671 SwitchStatement* statement = factory()->NewSwitchStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002672 Target target(&this->target_stack_, statement);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002673
2674 Expect(Token::SWITCH, CHECK_OK);
2675 Expect(Token::LPAREN, CHECK_OK);
2676 Expression* tag = ParseExpression(true, CHECK_OK);
2677 Expect(Token::RPAREN, CHECK_OK);
2678
2679 bool default_seen = false;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002680 ZoneList<CaseClause*>* cases = new(zone()) ZoneList<CaseClause*>(4, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002681 Expect(Token::LBRACE, CHECK_OK);
2682 while (peek() != Token::RBRACE) {
2683 CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002684 cases->Add(clause, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002685 }
2686 Expect(Token::RBRACE, CHECK_OK);
2687
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002688 if (statement) statement->Initialize(tag, cases);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002689 return statement;
2690}
2691
2692
2693Statement* Parser::ParseThrowStatement(bool* ok) {
2694 // ThrowStatement ::
2695 // 'throw' Expression ';'
2696
2697 Expect(Token::THROW, CHECK_OK);
2698 int pos = scanner().location().beg_pos;
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00002699 if (scanner().HasAnyLineTerminatorBeforeNext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002700 ReportMessage("newline_after_throw", Vector<const char*>::empty());
2701 *ok = false;
2702 return NULL;
2703 }
2704 Expression* exception = ParseExpression(true, CHECK_OK);
2705 ExpectSemicolon(CHECK_OK);
2706
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002707 return factory()->NewExpressionStatement(factory()->NewThrow(exception, pos));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002708}
2709
2710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002711TryStatement* Parser::ParseTryStatement(bool* ok) {
2712 // TryStatement ::
2713 // 'try' Block Catch
2714 // 'try' Block Finally
2715 // 'try' Block Catch Finally
2716 //
2717 // Catch ::
2718 // 'catch' '(' Identifier ')' Block
2719 //
2720 // Finally ::
2721 // 'finally' Block
2722
2723 Expect(Token::TRY, CHECK_OK);
2724
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002725 TargetCollector try_collector(zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002726 Block* try_block;
2727
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002728 { Target target(&this->target_stack_, &try_collector);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002729 try_block = ParseBlock(NULL, CHECK_OK);
2730 }
2731
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002732 Token::Value tok = peek();
2733 if (tok != Token::CATCH && tok != Token::FINALLY) {
2734 ReportMessage("no_catch_or_finally", Vector<const char*>::empty());
2735 *ok = false;
2736 return NULL;
2737 }
2738
2739 // If we can break out from the catch block and there is a finally block,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002740 // then we will need to collect escaping targets from the catch
2741 // block. Since we don't know yet if there will be a finally block, we
2742 // always collect the targets.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002743 TargetCollector catch_collector(zone());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002744 Scope* catch_scope = NULL;
2745 Variable* catch_variable = NULL;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002746 Block* catch_block = NULL;
2747 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002748 if (tok == Token::CATCH) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002749 Consume(Token::CATCH);
2750
2751 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002752 catch_scope = NewScope(top_scope_, CATCH_SCOPE);
2753 catch_scope->set_start_position(scanner().location().beg_pos);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002754 name = ParseIdentifier(CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002755
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002756 if (!top_scope_->is_classic_mode() && IsEvalOrArguments(name)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002757 ReportMessage("strict_catch_variable", Vector<const char*>::empty());
2758 *ok = false;
2759 return NULL;
2760 }
2761
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002762 Expect(Token::RPAREN, CHECK_OK);
2763
2764 if (peek() == Token::LBRACE) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002765 Target target(&this->target_stack_, &catch_collector);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002766 VariableMode mode = is_extended_mode() ? LET : VAR;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002767 catch_variable =
2768 catch_scope->DeclareLocal(name, mode, kCreatedInitialized);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002769
danno@chromium.orgc612e022011-11-10 11:38:15 +00002770 BlockState block_state(this, catch_scope);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002771 catch_block = ParseBlock(NULL, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772 } else {
2773 Expect(Token::LBRACE, CHECK_OK);
2774 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002775 catch_scope->set_end_position(scanner().location().end_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002776 tok = peek();
2777 }
2778
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002779 Block* finally_block = NULL;
2780 if (tok == Token::FINALLY || catch_block == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002781 Consume(Token::FINALLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002782 finally_block = ParseBlock(NULL, CHECK_OK);
2783 }
2784
2785 // Simplify the AST nodes by converting:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002786 // 'try B0 catch B1 finally B2'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002787 // to:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002788 // 'try { try B0 catch B1 } finally B2'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002789
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002790 if (catch_block != NULL && finally_block != NULL) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002791 // If we have both, create an inner try/catch.
2792 ASSERT(catch_scope != NULL && catch_variable != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002793 int index = current_function_state_->NextHandlerIndex();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002794 TryCatchStatement* statement = factory()->NewTryCatchStatement(
2795 index, try_block, catch_scope, catch_variable, catch_block);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002796 statement->set_escaping_targets(try_collector.targets());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002797 try_block = factory()->NewBlock(NULL, 1, false);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002798 try_block->AddStatement(statement, zone());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002799 catch_block = NULL; // Clear to indicate it's been handled.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002800 }
2801
2802 TryStatement* result = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002803 if (catch_block != NULL) {
2804 ASSERT(finally_block == NULL);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002805 ASSERT(catch_scope != NULL && catch_variable != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002806 int index = current_function_state_->NextHandlerIndex();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002807 result = factory()->NewTryCatchStatement(
2808 index, try_block, catch_scope, catch_variable, catch_block);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002809 } else {
2810 ASSERT(finally_block != NULL);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002811 int index = current_function_state_->NextHandlerIndex();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002812 result = factory()->NewTryFinallyStatement(index, try_block, finally_block);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002813 // Combine the jump targets of the try block and the possible catch block.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002814 try_collector.targets()->AddAll(*catch_collector.targets(), zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002815 }
2816
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002817 result->set_escaping_targets(try_collector.targets());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002818 return result;
2819}
2820
2821
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002822DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels,
2823 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002824 // DoStatement ::
2825 // 'do' Statement 'while' '(' Expression ')' ';'
2826
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002827 DoWhileStatement* loop = factory()->NewDoWhileStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002828 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002829
2830 Expect(Token::DO, CHECK_OK);
2831 Statement* body = ParseStatement(NULL, CHECK_OK);
2832 Expect(Token::WHILE, CHECK_OK);
2833 Expect(Token::LPAREN, CHECK_OK);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002834
2835 if (loop != NULL) {
2836 int position = scanner().location().beg_pos;
2837 loop->set_condition_position(position);
2838 }
2839
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002840 Expression* cond = ParseExpression(true, CHECK_OK);
2841 Expect(Token::RPAREN, CHECK_OK);
2842
2843 // Allow do-statements to be terminated with and without
2844 // semi-colons. This allows code such as 'do;while(0)return' to
2845 // parse, which would not be the case if we had used the
2846 // ExpectSemicolon() functionality here.
2847 if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
2848
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002849 if (loop != NULL) loop->Initialize(cond, body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002850 return loop;
2851}
2852
2853
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002854WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002855 // WhileStatement ::
2856 // 'while' '(' Expression ')' Statement
2857
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002858 WhileStatement* loop = factory()->NewWhileStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002859 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002860
2861 Expect(Token::WHILE, CHECK_OK);
2862 Expect(Token::LPAREN, CHECK_OK);
2863 Expression* cond = ParseExpression(true, CHECK_OK);
2864 Expect(Token::RPAREN, CHECK_OK);
2865 Statement* body = ParseStatement(NULL, CHECK_OK);
2866
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002867 if (loop != NULL) loop->Initialize(cond, body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002868 return loop;
2869}
2870
2871
2872Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
2873 // ForStatement ::
2874 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
2875
2876 Statement* init = NULL;
2877
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002878 // Create an in-between scope for let-bound iteration variables.
2879 Scope* saved_scope = top_scope_;
2880 Scope* for_scope = NewScope(top_scope_, BLOCK_SCOPE);
2881 top_scope_ = for_scope;
2882
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002883 Expect(Token::FOR, CHECK_OK);
2884 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002885 for_scope->set_start_position(scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002886 if (peek() != Token::SEMICOLON) {
2887 if (peek() == Token::VAR || peek() == Token::CONST) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002888 bool is_const = peek() == Token::CONST;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002889 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002890 Block* variable_statement =
ulan@chromium.org812308e2012-02-29 15:58:45 +00002891 ParseVariableDeclarations(kForStatement, NULL, NULL, &name, CHECK_OK);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002892
2893 if (peek() == Token::IN && !name.is_null()) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002894 Interface* interface =
2895 is_const ? Interface::NewConst() : Interface::NewValue();
2896 VariableProxy* each =
2897 top_scope_->NewUnresolved(factory(), name, interface);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002898 ForInStatement* loop = factory()->NewForInStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002899 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002900
2901 Expect(Token::IN, CHECK_OK);
2902 Expression* enumerable = ParseExpression(true, CHECK_OK);
2903 Expect(Token::RPAREN, CHECK_OK);
2904
2905 Statement* body = ParseStatement(NULL, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002906 loop->Initialize(each, enumerable, body);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002907 Block* result = factory()->NewBlock(NULL, 2, false);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002908 result->AddStatement(variable_statement, zone());
2909 result->AddStatement(loop, zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002910 top_scope_ = saved_scope;
2911 for_scope->set_end_position(scanner().location().end_pos);
2912 for_scope = for_scope->FinalizeBlockScope();
2913 ASSERT(for_scope == NULL);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002914 // Parsed for-in loop w/ variable/const declaration.
2915 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002916 } else {
2917 init = variable_statement;
2918 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002919 } else if (peek() == Token::LET) {
2920 Handle<String> name;
2921 VariableDeclarationProperties decl_props = kHasNoInitializers;
2922 Block* variable_statement =
ulan@chromium.org812308e2012-02-29 15:58:45 +00002923 ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name,
2924 CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002925 bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
2926 if (peek() == Token::IN && accept_IN) {
2927 // Rewrite a for-in statement of the form
2928 //
2929 // for (let x in e) b
2930 //
2931 // into
2932 //
2933 // <let x' be a temporary variable>
2934 // for (x' in e) {
2935 // let x;
2936 // x = x';
2937 // b;
2938 // }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002939
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002940 // TODO(keuchel): Move the temporary variable to the block scope, after
2941 // implementing stack allocated block scoped variables.
2942 Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002943 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002944 Interface* interface = Interface::NewValue();
2945 VariableProxy* each =
2946 top_scope_->NewUnresolved(factory(), name, interface);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002947 ForInStatement* loop = factory()->NewForInStatement(labels);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002948 Target target(&this->target_stack_, loop);
2949
2950 Expect(Token::IN, CHECK_OK);
2951 Expression* enumerable = ParseExpression(true, CHECK_OK);
2952 Expect(Token::RPAREN, CHECK_OK);
2953
2954 Statement* body = ParseStatement(NULL, CHECK_OK);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002955 Block* body_block = factory()->NewBlock(NULL, 3, false);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002956 Assignment* assignment = factory()->NewAssignment(
2957 Token::ASSIGN, each, temp_proxy, RelocInfo::kNoPosition);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002958 Statement* assignment_statement =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002959 factory()->NewExpressionStatement(assignment);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002960 body_block->AddStatement(variable_statement, zone());
2961 body_block->AddStatement(assignment_statement, zone());
2962 body_block->AddStatement(body, zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002963 loop->Initialize(temp_proxy, enumerable, body_block);
2964 top_scope_ = saved_scope;
2965 for_scope->set_end_position(scanner().location().end_pos);
2966 for_scope = for_scope->FinalizeBlockScope();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002967 body_block->set_scope(for_scope);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002968 // Parsed for-in loop w/ let declaration.
2969 return loop;
2970
2971 } else {
2972 init = variable_statement;
2973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002974 } else {
2975 Expression* expression = ParseExpression(false, CHECK_OK);
2976 if (peek() == Token::IN) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002977 // Signal a reference error if the expression is an invalid
2978 // left-hand side expression. We could report this as a syntax
2979 // error here but for compatibility with JSC we choose to report
2980 // the error at runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002981 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002982 Handle<String> type =
2983 isolate()->factory()->invalid_lhs_in_for_in_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002984 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002985 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00002986 ForInStatement* loop = factory()->NewForInStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002987 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002988
2989 Expect(Token::IN, CHECK_OK);
2990 Expression* enumerable = ParseExpression(true, CHECK_OK);
2991 Expect(Token::RPAREN, CHECK_OK);
2992
2993 Statement* body = ParseStatement(NULL, CHECK_OK);
2994 if (loop) loop->Initialize(expression, enumerable, body);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002995 top_scope_ = saved_scope;
2996 for_scope->set_end_position(scanner().location().end_pos);
2997 for_scope = for_scope->FinalizeBlockScope();
2998 ASSERT(for_scope == NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002999 // Parsed for-in loop.
3000 return loop;
3001
3002 } else {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003003 init = factory()->NewExpressionStatement(expression);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003004 }
3005 }
3006 }
3007
3008 // Standard 'for' loop
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003009 ForStatement* loop = factory()->NewForStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00003010 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003011
3012 // Parsed initializer at this point.
3013 Expect(Token::SEMICOLON, CHECK_OK);
3014
3015 Expression* cond = NULL;
3016 if (peek() != Token::SEMICOLON) {
3017 cond = ParseExpression(true, CHECK_OK);
3018 }
3019 Expect(Token::SEMICOLON, CHECK_OK);
3020
3021 Statement* next = NULL;
3022 if (peek() != Token::RPAREN) {
3023 Expression* exp = ParseExpression(true, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003024 next = factory()->NewExpressionStatement(exp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025 }
3026 Expect(Token::RPAREN, CHECK_OK);
3027
3028 Statement* body = ParseStatement(NULL, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003029 top_scope_ = saved_scope;
3030 for_scope->set_end_position(scanner().location().end_pos);
3031 for_scope = for_scope->FinalizeBlockScope();
3032 if (for_scope != NULL) {
3033 // Rewrite a for statement of the form
3034 //
3035 // for (let x = i; c; n) b
3036 //
3037 // into
3038 //
3039 // {
3040 // let x = i;
3041 // for (; c; n) b
3042 // }
3043 ASSERT(init != NULL);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003044 Block* result = factory()->NewBlock(NULL, 2, false);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003045 result->AddStatement(init, zone());
3046 result->AddStatement(loop, zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003047 result->set_scope(for_scope);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003048 if (loop) loop->Initialize(NULL, cond, next, body);
3049 return result;
3050 } else {
3051 if (loop) loop->Initialize(init, cond, next, body);
3052 return loop;
3053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003054}
3055
3056
3057// Precedence = 1
3058Expression* Parser::ParseExpression(bool accept_IN, bool* ok) {
3059 // Expression ::
3060 // AssignmentExpression
3061 // Expression ',' AssignmentExpression
3062
3063 Expression* result = ParseAssignmentExpression(accept_IN, CHECK_OK);
3064 while (peek() == Token::COMMA) {
3065 Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003066 int position = scanner().location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003067 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003068 result =
3069 factory()->NewBinaryOperation(Token::COMMA, result, right, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003070 }
3071 return result;
3072}
3073
3074
3075// Precedence = 2
3076Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
3077 // AssignmentExpression ::
3078 // ConditionalExpression
3079 // LeftHandSideExpression AssignmentOperator AssignmentExpression
3080
ricow@chromium.org65fae842010-08-25 15:26:24 +00003081 if (fni_ != NULL) fni_->Enter();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003082 Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
3083
3084 if (!Token::IsAssignmentOp(peek())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003085 if (fni_ != NULL) fni_->Leave();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003086 // Parsed conditional expression only (no assignment).
3087 return expression;
3088 }
3089
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003090 // Signal a reference error if the expression is an invalid left-hand
3091 // side expression. We could report this as a syntax error here but
3092 // for compatibility with JSC we choose to report the error at
3093 // runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003094 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003095 Handle<String> type =
3096 isolate()->factory()->invalid_lhs_in_assignment_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003097 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003098 }
3099
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003100 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003101 // Assignment to eval or arguments is disallowed in strict mode.
3102 CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK);
3103 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003104 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003106 Token::Value op = Next(); // Get assignment operator.
3107 int pos = scanner().location().beg_pos;
3108 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
3109
3110 // TODO(1231235): We try to estimate the set of properties set by
3111 // constructors. We define a new property whenever there is an
3112 // assignment to a property of 'this'. We should probably only add
3113 // properties if we haven't seen them before. Otherwise we'll
3114 // probably overestimate the number of properties.
3115 Property* property = expression ? expression->AsProperty() : NULL;
3116 if (op == Token::ASSIGN &&
3117 property != NULL &&
3118 property->obj()->AsVariableProxy() != NULL &&
3119 property->obj()->AsVariableProxy()->is_this()) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003120 current_function_state_->AddProperty();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003121 }
3122
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003123 // If we assign a function literal to a property we pretenure the
3124 // literal so it can be added as a constant function property.
3125 if (property != NULL && right->AsFunctionLiteral() != NULL) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003126 right->AsFunctionLiteral()->set_pretenure();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003127 }
3128
ricow@chromium.org65fae842010-08-25 15:26:24 +00003129 if (fni_ != NULL) {
3130 // Check if the right hand side is a call to avoid inferring a
3131 // name if we're dealing with "a = function(){...}();"-like
3132 // expression.
3133 if ((op == Token::INIT_VAR
3134 || op == Token::INIT_CONST
3135 || op == Token::ASSIGN)
ager@chromium.org04921a82011-06-27 13:21:41 +00003136 && (right->AsCall() == NULL && right->AsCallNew() == NULL)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003137 fni_->Infer();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003138 } else {
3139 fni_->RemoveLastFunction();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003140 }
3141 fni_->Leave();
3142 }
3143
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003144 return factory()->NewAssignment(op, expression, right, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003145}
3146
3147
3148// Precedence = 3
3149Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
3150 // ConditionalExpression ::
3151 // LogicalOrExpression
3152 // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
3153
3154 // We start using the binary expression parser for prec >= 4 only!
3155 Expression* expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
3156 if (peek() != Token::CONDITIONAL) return expression;
3157 Consume(Token::CONDITIONAL);
3158 // In parsing the first assignment expression in conditional
3159 // expressions we always accept the 'in' keyword; see ECMA-262,
3160 // section 11.12, page 58.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003161 int left_position = scanner().peek_location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003162 Expression* left = ParseAssignmentExpression(true, CHECK_OK);
3163 Expect(Token::COLON, CHECK_OK);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003164 int right_position = scanner().peek_location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003165 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003166 return factory()->NewConditional(
3167 expression, left, right, left_position, right_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003168}
3169
3170
3171static int Precedence(Token::Value tok, bool accept_IN) {
3172 if (tok == Token::IN && !accept_IN)
3173 return 0; // 0 precedence will terminate binary expression parsing
3174
3175 return Token::Precedence(tok);
3176}
3177
3178
3179// Precedence >= 4
3180Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
3181 ASSERT(prec >= 4);
3182 Expression* x = ParseUnaryExpression(CHECK_OK);
3183 for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
3184 // prec1 >= 4
3185 while (Precedence(peek(), accept_IN) == prec1) {
3186 Token::Value op = Next();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003187 int position = scanner().location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003188 Expression* y = ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
3189
3190 // Compute some expressions involving only number literals.
3191 if (x && x->AsLiteral() && x->AsLiteral()->handle()->IsNumber() &&
3192 y && y->AsLiteral() && y->AsLiteral()->handle()->IsNumber()) {
3193 double x_val = x->AsLiteral()->handle()->Number();
3194 double y_val = y->AsLiteral()->handle()->Number();
3195
3196 switch (op) {
3197 case Token::ADD:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003198 x = factory()->NewNumberLiteral(x_val + y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003199 continue;
3200 case Token::SUB:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003201 x = factory()->NewNumberLiteral(x_val - y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003202 continue;
3203 case Token::MUL:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003204 x = factory()->NewNumberLiteral(x_val * y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003205 continue;
3206 case Token::DIV:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003207 x = factory()->NewNumberLiteral(x_val / y_val);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003208 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003209 case Token::BIT_OR: {
3210 int value = DoubleToInt32(x_val) | DoubleToInt32(y_val);
3211 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003212 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003213 }
3214 case Token::BIT_AND: {
3215 int value = DoubleToInt32(x_val) & DoubleToInt32(y_val);
3216 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003217 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003218 }
3219 case Token::BIT_XOR: {
3220 int value = DoubleToInt32(x_val) ^ DoubleToInt32(y_val);
3221 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003222 continue;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003223 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003224 case Token::SHL: {
3225 int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003226 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003227 continue;
3228 }
3229 case Token::SHR: {
3230 uint32_t shift = DoubleToInt32(y_val) & 0x1f;
3231 uint32_t value = DoubleToUint32(x_val) >> shift;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003232 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003233 continue;
3234 }
3235 case Token::SAR: {
3236 uint32_t shift = DoubleToInt32(y_val) & 0x1f;
3237 int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003238 x = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003239 continue;
3240 }
3241 default:
3242 break;
3243 }
3244 }
3245
3246 // For now we distinguish between comparisons and other binary
3247 // operations. (We could combine the two and get rid of this
ricow@chromium.org65fae842010-08-25 15:26:24 +00003248 // code and AST node eventually.)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003249 if (Token::IsCompareOp(op)) {
3250 // We have a comparison.
3251 Token::Value cmp = op;
3252 switch (op) {
3253 case Token::NE: cmp = Token::EQ; break;
3254 case Token::NE_STRICT: cmp = Token::EQ_STRICT; break;
3255 default: break;
3256 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003257 x = factory()->NewCompareOperation(cmp, x, y, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003258 if (cmp != op) {
3259 // The comparison was negated - add a NOT.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003260 x = factory()->NewUnaryOperation(Token::NOT, x, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003261 }
3262
3263 } else {
3264 // We have a "normal" binary operation.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003265 x = factory()->NewBinaryOperation(op, x, y, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003266 }
3267 }
3268 }
3269 return x;
3270}
3271
3272
3273Expression* Parser::ParseUnaryExpression(bool* ok) {
3274 // UnaryExpression ::
3275 // PostfixExpression
3276 // 'delete' UnaryExpression
3277 // 'void' UnaryExpression
3278 // 'typeof' UnaryExpression
3279 // '++' UnaryExpression
3280 // '--' UnaryExpression
3281 // '+' UnaryExpression
3282 // '-' UnaryExpression
3283 // '~' UnaryExpression
3284 // '!' UnaryExpression
3285
3286 Token::Value op = peek();
3287 if (Token::IsUnaryOp(op)) {
3288 op = Next();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003289 int position = scanner().location().beg_pos;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003290 Expression* expression = ParseUnaryExpression(CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003291
whesse@chromium.org7b260152011-06-20 15:33:18 +00003292 if (expression != NULL && (expression->AsLiteral() != NULL)) {
3293 Handle<Object> literal = expression->AsLiteral()->handle();
3294 if (op == Token::NOT) {
3295 // Convert the literal to a boolean condition and negate it.
3296 bool condition = literal->ToBoolean()->IsTrue();
3297 Handle<Object> result(isolate()->heap()->ToBoolean(!condition));
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003298 return factory()->NewLiteral(result);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003299 } else if (literal->IsNumber()) {
3300 // Compute some expressions involving only number literals.
3301 double value = literal->Number();
3302 switch (op) {
3303 case Token::ADD:
3304 return expression;
3305 case Token::SUB:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003306 return factory()->NewNumberLiteral(-value);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003307 case Token::BIT_NOT:
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003308 return factory()->NewNumberLiteral(~DoubleToInt32(value));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003309 default:
3310 break;
3311 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003312 }
3313 }
3314
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003315 // "delete identifier" is a syntax error in strict mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003316 if (op == Token::DELETE && !top_scope_->is_classic_mode()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003317 VariableProxy* operand = expression->AsVariableProxy();
3318 if (operand != NULL && !operand->is_this()) {
3319 ReportMessage("strict_delete", Vector<const char*>::empty());
3320 *ok = false;
3321 return NULL;
3322 }
3323 }
3324
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003325 return factory()->NewUnaryOperation(op, expression, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003326
3327 } else if (Token::IsCountOp(op)) {
3328 op = Next();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003329 Expression* expression = ParseUnaryExpression(CHECK_OK);
3330 // Signal a reference error if the expression is an invalid
3331 // left-hand side expression. We could report this as a syntax
3332 // error here but for compatibility with JSC we choose to report the
3333 // error at runtime.
3334 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003335 Handle<String> type =
3336 isolate()->factory()->invalid_lhs_in_prefix_op_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003337 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003338 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003339
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003340 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003341 // Prefix expression operand in strict mode may not be eval or arguments.
3342 CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
3343 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003344 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003345
ricow@chromium.org65fae842010-08-25 15:26:24 +00003346 int position = scanner().location().beg_pos;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003347 return factory()->NewCountOperation(op,
3348 true /* prefix */,
3349 expression,
3350 position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003351
3352 } else {
3353 return ParsePostfixExpression(ok);
3354 }
3355}
3356
3357
3358Expression* Parser::ParsePostfixExpression(bool* ok) {
3359 // PostfixExpression ::
3360 // LeftHandSideExpression ('++' | '--')?
3361
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003362 Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00003363 if (!scanner().HasAnyLineTerminatorBeforeNext() &&
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003364 Token::IsCountOp(peek())) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003365 // Signal a reference error if the expression is an invalid
3366 // left-hand side expression. We could report this as a syntax
3367 // error here but for compatibility with JSC we choose to report the
3368 // error at runtime.
3369 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003370 Handle<String> type =
3371 isolate()->factory()->invalid_lhs_in_postfix_op_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003372 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003373 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003374
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003375 if (!top_scope_->is_classic_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003376 // Postfix expression operand in strict mode may not be eval or arguments.
3377 CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
3378 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003379 MarkAsLValue(expression);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003380
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003381 Token::Value next = Next();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003382 int position = scanner().location().beg_pos;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003383 expression =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003384 factory()->NewCountOperation(next,
3385 false /* postfix */,
3386 expression,
3387 position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003388 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003389 return expression;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003390}
3391
3392
3393Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
3394 // LeftHandSideExpression ::
3395 // (NewExpression | MemberExpression) ...
3396
3397 Expression* result;
3398 if (peek() == Token::NEW) {
3399 result = ParseNewExpression(CHECK_OK);
3400 } else {
3401 result = ParseMemberExpression(CHECK_OK);
3402 }
3403
3404 while (true) {
3405 switch (peek()) {
3406 case Token::LBRACK: {
3407 Consume(Token::LBRACK);
3408 int pos = scanner().location().beg_pos;
3409 Expression* index = ParseExpression(true, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003410 result = factory()->NewProperty(result, index, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003411 Expect(Token::RBRACK, CHECK_OK);
3412 break;
3413 }
3414
3415 case Token::LPAREN: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003416 int pos;
3417 if (scanner().current_token() == Token::IDENTIFIER) {
3418 // For call of an identifier we want to report position of
3419 // the identifier as position of the call in the stack trace.
3420 pos = scanner().location().beg_pos;
3421 } else {
3422 // For other kinds of calls we record position of the parenthesis as
3423 // position of the call. Note that this is extremely important for
3424 // expressions of the form function(){...}() for which call position
3425 // should not point to the closing brace otherwise it will intersect
3426 // with positions recorded for function literal and confuse debugger.
3427 pos = scanner().peek_location().beg_pos;
3428 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003429 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
3430
3431 // Keep track of eval() calls since they disable all local variable
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003432 // optimizations.
3433 // The calls that need special treatment are the
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003434 // direct eval calls. These calls are all of the form eval(...), with
3435 // no explicit receiver.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003436 // These calls are marked as potentially direct eval calls. Whether
3437 // they are actually direct calls to eval is determined at run time.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003438 VariableProxy* callee = result->AsVariableProxy();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003439 if (callee != NULL &&
3440 callee->IsVariable(isolate()->factory()->eval_symbol())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003441 top_scope_->DeclarationScope()->RecordEvalCall();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003442 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003443 result = factory()->NewCall(result, args, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003444 break;
3445 }
3446
3447 case Token::PERIOD: {
3448 Consume(Token::PERIOD);
3449 int pos = scanner().location().beg_pos;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003450 Handle<String> name = ParseIdentifierName(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003451 result =
3452 factory()->NewProperty(result, factory()->NewLiteral(name), pos);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003453 if (fni_ != NULL) fni_->PushLiteralName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454 break;
3455 }
3456
3457 default:
3458 return result;
3459 }
3460 }
3461}
3462
3463
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003464Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003465 // NewExpression ::
3466 // ('new')+ MemberExpression
3467
3468 // The grammar for new expressions is pretty warped. The keyword
3469 // 'new' can either be a part of the new expression (where it isn't
3470 // followed by an argument list) or a part of the member expression,
3471 // where it must be followed by an argument list. To accommodate
3472 // this, we parse the 'new' keywords greedily and keep track of how
3473 // many we have parsed. This information is then passed on to the
3474 // member expression parser, which is only allowed to match argument
3475 // lists as long as it has 'new' prefixes left
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003476 Expect(Token::NEW, CHECK_OK);
3477 PositionStack::Element pos(stack, scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003478
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003479 Expression* result;
3480 if (peek() == Token::NEW) {
3481 result = ParseNewPrefix(stack, CHECK_OK);
3482 } else {
3483 result = ParseMemberWithNewPrefixesExpression(stack, CHECK_OK);
3484 }
3485
3486 if (!stack->is_empty()) {
3487 int last = stack->pop();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003488 result = factory()->NewCallNew(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003489 result, new(zone()) ZoneList<Expression*>(0, zone()), last);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003490 }
3491 return result;
3492}
3493
3494
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003495Expression* Parser::ParseNewExpression(bool* ok) {
3496 PositionStack stack(ok);
3497 return ParseNewPrefix(&stack, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003498}
3499
3500
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003501Expression* Parser::ParseMemberExpression(bool* ok) {
3502 return ParseMemberWithNewPrefixesExpression(NULL, ok);
3503}
3504
3505
3506Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
3507 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003508 // MemberExpression ::
3509 // (PrimaryExpression | FunctionLiteral)
3510 // ('[' Expression ']' | '.' Identifier | Arguments)*
3511
3512 // Parse the initial primary or function expression.
3513 Expression* result = NULL;
3514 if (peek() == Token::FUNCTION) {
3515 Expect(Token::FUNCTION, CHECK_OK);
3516 int function_token_position = scanner().location().beg_pos;
3517 Handle<String> name;
ager@chromium.org04921a82011-06-27 13:21:41 +00003518 bool is_strict_reserved_name = false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003519 if (peek_any_identifier()) {
ager@chromium.org04921a82011-06-27 13:21:41 +00003520 name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
3521 CHECK_OK);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003522 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003523 FunctionLiteral::Type type = name.is_null()
3524 ? FunctionLiteral::ANONYMOUS_EXPRESSION
3525 : FunctionLiteral::NAMED_EXPRESSION;
3526 result = ParseFunctionLiteral(name,
3527 is_strict_reserved_name,
3528 function_token_position,
3529 type,
3530 CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003531 } else {
3532 result = ParsePrimaryExpression(CHECK_OK);
3533 }
3534
3535 while (true) {
3536 switch (peek()) {
3537 case Token::LBRACK: {
3538 Consume(Token::LBRACK);
3539 int pos = scanner().location().beg_pos;
3540 Expression* index = ParseExpression(true, CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003541 result = factory()->NewProperty(result, index, pos);
ager@chromium.org04921a82011-06-27 13:21:41 +00003542 if (fni_ != NULL) {
3543 if (index->IsPropertyName()) {
3544 fni_->PushLiteralName(index->AsLiteral()->AsPropertyName());
3545 } else {
3546 fni_->PushLiteralName(
3547 isolate()->factory()->anonymous_function_symbol());
3548 }
3549 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003550 Expect(Token::RBRACK, CHECK_OK);
3551 break;
3552 }
3553 case Token::PERIOD: {
3554 Consume(Token::PERIOD);
3555 int pos = scanner().location().beg_pos;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003556 Handle<String> name = ParseIdentifierName(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003557 result =
3558 factory()->NewProperty(result, factory()->NewLiteral(name), pos);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003559 if (fni_ != NULL) fni_->PushLiteralName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003560 break;
3561 }
3562 case Token::LPAREN: {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003563 if ((stack == NULL) || stack->is_empty()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003564 // Consume one of the new prefixes (already parsed).
3565 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003566 int last = stack->pop();
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003567 result = factory()->NewCallNew(result, args, last);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003568 break;
3569 }
3570 default:
3571 return result;
3572 }
3573 }
3574}
3575
3576
3577DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
3578 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
3579 // contexts this is used as a statement which invokes the debugger as i a
3580 // break point is present.
3581 // DebuggerStatement ::
3582 // 'debugger' ';'
3583
3584 Expect(Token::DEBUGGER, CHECK_OK);
3585 ExpectSemicolon(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003586 return factory()->NewDebuggerStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003587}
3588
3589
3590void Parser::ReportUnexpectedToken(Token::Value token) {
3591 // We don't report stack overflows here, to avoid increasing the
3592 // stack depth even further. Instead we report it after parsing is
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003593 // over, in ParseProgram/ParseJson.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003594 if (token == Token::ILLEGAL && stack_overflow_) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 // Four of the tokens are treated specially
3596 switch (token) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003597 case Token::EOS:
3598 return ReportMessage("unexpected_eos", Vector<const char*>::empty());
3599 case Token::NUMBER:
3600 return ReportMessage("unexpected_token_number",
3601 Vector<const char*>::empty());
3602 case Token::STRING:
3603 return ReportMessage("unexpected_token_string",
3604 Vector<const char*>::empty());
3605 case Token::IDENTIFIER:
3606 return ReportMessage("unexpected_token_identifier",
3607 Vector<const char*>::empty());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003608 case Token::FUTURE_RESERVED_WORD:
ager@chromium.org04921a82011-06-27 13:21:41 +00003609 return ReportMessage("unexpected_reserved",
3610 Vector<const char*>::empty());
3611 case Token::FUTURE_STRICT_RESERVED_WORD:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003612 return ReportMessage(top_scope_->is_classic_mode() ?
3613 "unexpected_token_identifier" :
3614 "unexpected_strict_reserved",
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003615 Vector<const char*>::empty());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003616 default:
3617 const char* name = Token::String(token);
3618 ASSERT(name != NULL);
3619 ReportMessage("unexpected_token", Vector<const char*>(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
3621}
3622
3623
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003624void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003625 SmartArrayPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003626 const char* element[1] = { *name_string };
3627 ReportMessage("invalid_preparser_data",
3628 Vector<const char*>(element, 1));
3629 *ok = false;
3630}
3631
3632
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003633Expression* Parser::ParsePrimaryExpression(bool* ok) {
3634 // PrimaryExpression ::
3635 // 'this'
3636 // 'null'
3637 // 'true'
3638 // 'false'
3639 // Identifier
3640 // Number
3641 // String
3642 // ArrayLiteral
3643 // ObjectLiteral
3644 // RegExpLiteral
3645 // '(' Expression ')'
3646
3647 Expression* result = NULL;
3648 switch (peek()) {
3649 case Token::THIS: {
3650 Consume(Token::THIS);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003651 result = factory()->NewVariableProxy(top_scope_->receiver());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652 break;
3653 }
3654
3655 case Token::NULL_LITERAL:
3656 Consume(Token::NULL_LITERAL);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003657 result = factory()->NewLiteral(isolate()->factory()->null_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003658 break;
3659
3660 case Token::TRUE_LITERAL:
3661 Consume(Token::TRUE_LITERAL);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003662 result = factory()->NewLiteral(isolate()->factory()->true_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003663 break;
3664
3665 case Token::FALSE_LITERAL:
3666 Consume(Token::FALSE_LITERAL);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003667 result = factory()->NewLiteral(isolate()->factory()->false_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003668 break;
3669
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003670 case Token::IDENTIFIER:
ager@chromium.org04921a82011-06-27 13:21:41 +00003671 case Token::FUTURE_STRICT_RESERVED_WORD: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 Handle<String> name = ParseIdentifier(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003673 if (fni_ != NULL) fni_->PushVariableName(name);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003674 // The name may refer to a module instance object, so its type is unknown.
3675#ifdef DEBUG
3676 if (FLAG_print_interface_details)
3677 PrintF("# Variable %s ", name->ToAsciiArray());
3678#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003679 Interface* interface = Interface::NewUnknown(zone());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003680 result = top_scope_->NewUnresolved(
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00003681 factory(), name, interface, scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003682 break;
3683 }
3684
3685 case Token::NUMBER: {
3686 Consume(Token::NUMBER);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003687 ASSERT(scanner().is_literal_ascii());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003688 double value = StringToDouble(isolate()->unicode_cache(),
3689 scanner().literal_ascii_string(),
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003690 ALLOW_HEX | ALLOW_OCTALS);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003691 result = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003692 break;
3693 }
3694
3695 case Token::STRING: {
3696 Consume(Token::STRING);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003697 Handle<String> symbol = GetSymbol(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003698 result = factory()->NewLiteral(symbol);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003699 if (fni_ != NULL) fni_->PushLiteralName(symbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 break;
3701 }
3702
3703 case Token::ASSIGN_DIV:
3704 result = ParseRegExpLiteral(true, CHECK_OK);
3705 break;
3706
3707 case Token::DIV:
3708 result = ParseRegExpLiteral(false, CHECK_OK);
3709 break;
3710
3711 case Token::LBRACK:
3712 result = ParseArrayLiteral(CHECK_OK);
3713 break;
3714
3715 case Token::LBRACE:
3716 result = ParseObjectLiteral(CHECK_OK);
3717 break;
3718
3719 case Token::LPAREN:
3720 Consume(Token::LPAREN);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003721 // Heuristically try to detect immediately called functions before
3722 // seeing the call parentheses.
3723 parenthesized_function_ = (peek() == Token::FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003724 result = ParseExpression(true, CHECK_OK);
3725 Expect(Token::RPAREN, CHECK_OK);
3726 break;
3727
3728 case Token::MOD:
3729 if (allow_natives_syntax_ || extension_ != NULL) {
3730 result = ParseV8Intrinsic(CHECK_OK);
3731 break;
3732 }
3733 // If we're not allowing special syntax we fall-through to the
3734 // default case.
3735
3736 default: {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003737 Token::Value tok = Next();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003738 ReportUnexpectedToken(tok);
3739 *ok = false;
3740 return NULL;
3741 }
3742 }
3743
3744 return result;
3745}
3746
3747
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003748void Parser::BuildArrayLiteralBoilerplateLiterals(ZoneList<Expression*>* values,
3749 Handle<FixedArray> literals,
3750 bool* is_simple,
3751 int* depth) {
3752 // Fill in the literals.
3753 // Accumulate output values in local variables.
3754 bool is_simple_acc = true;
3755 int depth_acc = 1;
3756 for (int i = 0; i < values->length(); i++) {
3757 MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
3758 if (m_literal != NULL && m_literal->depth() >= depth_acc) {
3759 depth_acc = m_literal->depth() + 1;
3760 }
3761 Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
3762 if (boilerplate_value->IsUndefined()) {
3763 literals->set_the_hole(i);
3764 is_simple_acc = false;
3765 } else {
3766 literals->set(i, *boilerplate_value);
3767 }
3768 }
3769
3770 *is_simple = is_simple_acc;
3771 *depth = depth_acc;
3772}
3773
3774
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003775Expression* Parser::ParseArrayLiteral(bool* ok) {
3776 // ArrayLiteral ::
3777 // '[' Expression? (',' Expression?)* ']'
3778
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003779 ZoneList<Expression*>* values = new(zone()) ZoneList<Expression*>(4, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003780 Expect(Token::LBRACK, CHECK_OK);
3781 while (peek() != Token::RBRACK) {
3782 Expression* elem;
3783 if (peek() == Token::COMMA) {
3784 elem = GetLiteralTheHole();
3785 } else {
3786 elem = ParseAssignmentExpression(true, CHECK_OK);
3787 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003788 values->Add(elem, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003789 if (peek() != Token::RBRACK) {
3790 Expect(Token::COMMA, CHECK_OK);
3791 }
3792 }
3793 Expect(Token::RBRACK, CHECK_OK);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003794
3795 // Update the scope information before the pre-parsing bailout.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003796 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003797
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003798 // Allocate a fixed array to hold all the object literals.
3799 Handle<FixedArray> object_literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003800 isolate()->factory()->NewFixedArray(values->length(), TENURED);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003801 Handle<FixedDoubleArray> double_literals;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003802 ElementsKind elements_kind = FAST_SMI_ELEMENTS;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003803 bool has_only_undefined_values = true;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003804 bool has_hole_values = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003805
3806 // Fill in the literals.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003807 Heap* heap = isolate()->heap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003808 bool is_simple = true;
3809 int depth = 1;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003810 for (int i = 0, n = values->length(); i < n; i++) {
3811 MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003812 if (m_literal != NULL && m_literal->depth() + 1 > depth) {
3813 depth = m_literal->depth() + 1;
3814 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003815 Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003816 if (boilerplate_value->IsTheHole()) {
3817 has_hole_values = true;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003818 object_literals->set_the_hole(i);
3819 if (elements_kind == FAST_DOUBLE_ELEMENTS) {
3820 double_literals->set_the_hole(i);
3821 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003822 } else if (boilerplate_value->IsUndefined()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003823 is_simple = false;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003824 object_literals->set(i, Smi::FromInt(0));
3825 if (elements_kind == FAST_DOUBLE_ELEMENTS) {
3826 double_literals->set(i, 0);
3827 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003828 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003829 // Examine each literal element, and adjust the ElementsKind if the
3830 // literal element is not of a type that can be stored in the current
3831 // ElementsKind. Start with FAST_SMI_ONLY_ELEMENTS, and transition to
3832 // FAST_DOUBLE_ELEMENTS and FAST_ELEMENTS as necessary. Always remember
3833 // the tagged value, no matter what the ElementsKind is in case we
3834 // ultimately end up in FAST_ELEMENTS.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003835 has_only_undefined_values = false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003836 object_literals->set(i, *boilerplate_value);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003837 if (elements_kind == FAST_SMI_ELEMENTS) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003838 // Smi only elements. Notice if a transition to FAST_DOUBLE_ELEMENTS or
3839 // FAST_ELEMENTS is required.
3840 if (!boilerplate_value->IsSmi()) {
3841 if (boilerplate_value->IsNumber() && FLAG_smi_only_arrays) {
3842 // Allocate a double array on the FAST_DOUBLE_ELEMENTS transition to
3843 // avoid over-allocating in TENURED space.
3844 double_literals = isolate()->factory()->NewFixedDoubleArray(
3845 values->length(), TENURED);
3846 // Copy the contents of the FAST_SMI_ONLY_ELEMENT array to the
3847 // FAST_DOUBLE_ELEMENTS array so that they are in sync.
3848 for (int j = 0; j < i; ++j) {
3849 Object* smi_value = object_literals->get(j);
3850 if (smi_value->IsTheHole()) {
3851 double_literals->set_the_hole(j);
3852 } else {
3853 double_literals->set(j, Smi::cast(smi_value)->value());
3854 }
3855 }
3856 double_literals->set(i, boilerplate_value->Number());
3857 elements_kind = FAST_DOUBLE_ELEMENTS;
3858 } else {
3859 elements_kind = FAST_ELEMENTS;
3860 }
3861 }
3862 } else if (elements_kind == FAST_DOUBLE_ELEMENTS) {
3863 // Continue to store double values in to FAST_DOUBLE_ELEMENTS arrays
3864 // until the first value is seen that can't be stored as a double.
3865 if (boilerplate_value->IsNumber()) {
3866 double_literals->set(i, boilerplate_value->Number());
3867 } else {
3868 elements_kind = FAST_ELEMENTS;
3869 }
3870 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003871 }
3872 }
3873
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003874 // Very small array literals that don't have a concrete hint about their type
3875 // from a constant value should default to the slow case to avoid lots of
3876 // elements transitions on really small objects.
3877 if (has_only_undefined_values && values->length() <= 2) {
3878 elements_kind = FAST_ELEMENTS;
3879 }
3880
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003881 // Simple and shallow arrays can be lazily copied, we transform the
3882 // elements array to a copy-on-write array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003883 if (is_simple && depth == 1 && values->length() > 0 &&
3884 elements_kind != FAST_DOUBLE_ELEMENTS) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003885 object_literals->set_map(heap->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003886 }
3887
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003888 Handle<FixedArrayBase> element_values = elements_kind == FAST_DOUBLE_ELEMENTS
3889 ? Handle<FixedArrayBase>(double_literals)
3890 : Handle<FixedArrayBase>(object_literals);
3891
3892 // Remember both the literal's constant values as well as the ElementsKind
3893 // in a 2-element FixedArray.
3894 Handle<FixedArray> literals =
3895 isolate()->factory()->NewFixedArray(2, TENURED);
3896
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003897 if (has_hole_values || !FLAG_packed_arrays) {
3898 elements_kind = GetHoleyElementsKind(elements_kind);
3899 }
3900
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003901 literals->set(0, Smi::FromInt(elements_kind));
3902 literals->set(1, *element_values);
3903
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003904 return factory()->NewArrayLiteral(
3905 literals, values, literal_index, is_simple, depth);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003906}
3907
3908
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003909bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) {
3910 return property != NULL &&
3911 property->kind() != ObjectLiteral::Property::PROTOTYPE;
3912}
3913
3914
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003915bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003916 if (expression->AsLiteral() != NULL) return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003917 MaterializedLiteral* lit = expression->AsMaterializedLiteral();
3918 return lit != NULL && lit->is_simple();
3919}
3920
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003921
3922bool CompileTimeValue::ArrayLiteralElementNeedsInitialization(
3923 Expression* value) {
3924 // If value is a literal the property value is already set in the
3925 // boilerplate object.
3926 if (value->AsLiteral() != NULL) return false;
3927 // If value is a materialized literal the property value is already set
3928 // in the boilerplate object if it is simple.
3929 if (CompileTimeValue::IsCompileTimeValue(value)) return false;
3930 return true;
3931}
3932
3933
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003934Handle<FixedArray> CompileTimeValue::GetValue(Expression* expression) {
3935 ASSERT(IsCompileTimeValue(expression));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003936 Handle<FixedArray> result = FACTORY->NewFixedArray(2, TENURED);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003937 ObjectLiteral* object_literal = expression->AsObjectLiteral();
3938 if (object_literal != NULL) {
3939 ASSERT(object_literal->is_simple());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003940 if (object_literal->fast_elements()) {
3941 result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS));
3942 } else {
3943 result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS));
3944 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003945 result->set(kElementsSlot, *object_literal->constant_properties());
3946 } else {
3947 ArrayLiteral* array_literal = expression->AsArrayLiteral();
3948 ASSERT(array_literal != NULL && array_literal->is_simple());
3949 result->set(kTypeSlot, Smi::FromInt(ARRAY_LITERAL));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003950 result->set(kElementsSlot, *array_literal->constant_elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003951 }
3952 return result;
3953}
3954
3955
3956CompileTimeValue::Type CompileTimeValue::GetType(Handle<FixedArray> value) {
3957 Smi* type_value = Smi::cast(value->get(kTypeSlot));
3958 return static_cast<Type>(type_value->value());
3959}
3960
3961
3962Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
3963 return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot)));
3964}
3965
3966
3967Handle<Object> Parser::GetBoilerplateValue(Expression* expression) {
3968 if (expression->AsLiteral() != NULL) {
3969 return expression->AsLiteral()->handle();
3970 }
3971 if (CompileTimeValue::IsCompileTimeValue(expression)) {
3972 return CompileTimeValue::GetValue(expression);
3973 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003974 return isolate()->factory()->undefined_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003975}
3976
ager@chromium.org378b34e2011-01-28 08:04:38 +00003977// Validation per 11.1.5 Object Initialiser
3978class ObjectLiteralPropertyChecker {
3979 public:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003980 ObjectLiteralPropertyChecker(Parser* parser, LanguageMode language_mode) :
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003981 props_(Literal::Match),
ager@chromium.org378b34e2011-01-28 08:04:38 +00003982 parser_(parser),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003983 language_mode_(language_mode) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003984 }
3985
3986 void CheckProperty(
3987 ObjectLiteral::Property* property,
3988 Scanner::Location loc,
3989 bool* ok);
3990
3991 private:
3992 enum PropertyKind {
3993 kGetAccessor = 0x01,
3994 kSetAccessor = 0x02,
3995 kAccessor = kGetAccessor | kSetAccessor,
3996 kData = 0x04
3997 };
3998
3999 static intptr_t GetPropertyKind(ObjectLiteral::Property* property) {
4000 switch (property->kind()) {
4001 case ObjectLiteral::Property::GETTER:
4002 return kGetAccessor;
4003 case ObjectLiteral::Property::SETTER:
4004 return kSetAccessor;
4005 default:
4006 return kData;
4007 }
4008 }
4009
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004010 HashMap props_;
ager@chromium.org378b34e2011-01-28 08:04:38 +00004011 Parser* parser_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004012 LanguageMode language_mode_;
ager@chromium.org378b34e2011-01-28 08:04:38 +00004013};
4014
4015
4016void ObjectLiteralPropertyChecker::CheckProperty(
4017 ObjectLiteral::Property* property,
4018 Scanner::Location loc,
4019 bool* ok) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00004020 ASSERT(property != NULL);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004021 Literal* literal = property->key();
4022 HashMap::Entry* entry = props_.Lookup(literal, literal->Hash(), true);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004023 intptr_t prev = reinterpret_cast<intptr_t> (entry->value);
4024 intptr_t curr = GetPropertyKind(property);
4025
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004026 // Duplicate data properties are illegal in strict or extended mode.
4027 if (language_mode_ != CLASSIC_MODE && (curr & prev & kData) != 0) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00004028 parser_->ReportMessageAt(loc, "strict_duplicate_property",
4029 Vector<const char*>::empty());
4030 *ok = false;
4031 return;
4032 }
4033 // Data property conflicting with an accessor.
4034 if (((curr & kData) && (prev & kAccessor)) ||
4035 ((prev & kData) && (curr & kAccessor))) {
4036 parser_->ReportMessageAt(loc, "accessor_data_property",
4037 Vector<const char*>::empty());
4038 *ok = false;
4039 return;
4040 }
4041 // Two accessors of the same type conflicting
4042 if ((curr & prev & kAccessor) != 0) {
4043 parser_->ReportMessageAt(loc, "accessor_get_set",
4044 Vector<const char*>::empty());
4045 *ok = false;
4046 return;
4047 }
4048
4049 // Update map
4050 entry->value = reinterpret_cast<void*> (prev | curr);
4051 *ok = true;
4052}
4053
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004054
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004055void Parser::BuildObjectLiteralConstantProperties(
4056 ZoneList<ObjectLiteral::Property*>* properties,
4057 Handle<FixedArray> constant_properties,
4058 bool* is_simple,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004059 bool* fast_elements,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004060 int* depth) {
4061 int position = 0;
4062 // Accumulate the value in local variables and store it at the end.
4063 bool is_simple_acc = true;
4064 int depth_acc = 1;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004065 uint32_t max_element_index = 0;
4066 uint32_t elements = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004067 for (int i = 0; i < properties->length(); i++) {
4068 ObjectLiteral::Property* property = properties->at(i);
4069 if (!IsBoilerplateProperty(property)) {
4070 is_simple_acc = false;
4071 continue;
4072 }
4073 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
4074 if (m_literal != NULL && m_literal->depth() >= depth_acc) {
4075 depth_acc = m_literal->depth() + 1;
4076 }
4077
4078 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
4079 // value for COMPUTED properties, the real value is filled in at
4080 // runtime. The enumeration order is maintained.
4081 Handle<Object> key = property->key()->handle();
4082 Handle<Object> value = GetBoilerplateValue(property->value());
4083 is_simple_acc = is_simple_acc && !value->IsUndefined();
4084
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004085 // Keep track of the number of elements in the object literal and
4086 // the largest element index. If the largest element index is
4087 // much larger than the number of elements, creating an object
4088 // literal with fast elements will be a waste of space.
4089 uint32_t element_index = 0;
4090 if (key->IsString()
4091 && Handle<String>::cast(key)->AsArrayIndex(&element_index)
4092 && element_index > max_element_index) {
4093 max_element_index = element_index;
4094 elements++;
4095 } else if (key->IsSmi()) {
4096 int key_value = Smi::cast(*key)->value();
4097 if (key_value > 0
4098 && static_cast<uint32_t>(key_value) > max_element_index) {
4099 max_element_index = key_value;
4100 }
4101 elements++;
4102 }
4103
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004104 // Add name, value pair to the fixed array.
4105 constant_properties->set(position++, *key);
4106 constant_properties->set(position++, *value);
4107 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004108 *fast_elements =
4109 (max_element_index <= 32) || ((2 * elements) >= max_element_index);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004110 *is_simple = is_simple_acc;
4111 *depth = depth_acc;
4112}
4113
4114
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004115ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter,
4116 bool* ok) {
4117 // Special handling of getter and setter syntax:
4118 // { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... }
4119 // We have already read the "get" or "set" keyword.
4120 Token::Value next = Next();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004121 bool is_keyword = Token::IsKeyword(next);
4122 if (next == Token::IDENTIFIER || next == Token::NUMBER ||
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004123 next == Token::FUTURE_RESERVED_WORD ||
ager@chromium.org04921a82011-06-27 13:21:41 +00004124 next == Token::FUTURE_STRICT_RESERVED_WORD ||
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004125 next == Token::STRING || is_keyword) {
4126 Handle<String> name;
4127 if (is_keyword) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004128 name = isolate_->factory()->LookupAsciiSymbol(Token::String(next));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004129 } else {
4130 name = GetSymbol(CHECK_OK);
4131 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004132 FunctionLiteral* value =
4133 ParseFunctionLiteral(name,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004134 false, // reserved words are allowed here
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004135 RelocInfo::kNoPosition,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004136 FunctionLiteral::ANONYMOUS_EXPRESSION,
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004137 CHECK_OK);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004138 // Allow any number of parameters for compatibilty with JSC.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004139 // Specification only allows zero parameters for get and one for set.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004140 return factory()->NewObjectLiteralProperty(is_getter, value);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004141 } else {
4142 ReportUnexpectedToken(next);
4143 *ok = false;
4144 return NULL;
4145 }
4146}
4147
4148
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004149Expression* Parser::ParseObjectLiteral(bool* ok) {
4150 // ObjectLiteral ::
4151 // '{' (
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004152 // ((IdentifierName | String | Number) ':' AssignmentExpression)
4153 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004154 // )*[','] '}'
4155
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004156 ZoneList<ObjectLiteral::Property*>* properties =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004157 new(zone()) ZoneList<ObjectLiteral::Property*>(4, zone());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004158 int number_of_boilerplate_properties = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004159 bool has_function = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004161 ObjectLiteralPropertyChecker checker(this, top_scope_->language_mode());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004162
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004163 Expect(Token::LBRACE, CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004164
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004165 while (peek() != Token::RBRACE) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004166 if (fni_ != NULL) fni_->Enter();
4167
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168 Literal* key = NULL;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004169 Token::Value next = peek();
ager@chromium.org378b34e2011-01-28 08:04:38 +00004170
4171 // Location of the property name token
4172 Scanner::Location loc = scanner().peek_location();
4173
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004174 switch (next) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004175 case Token::FUTURE_RESERVED_WORD:
ager@chromium.org04921a82011-06-27 13:21:41 +00004176 case Token::FUTURE_STRICT_RESERVED_WORD:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 case Token::IDENTIFIER: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004178 bool is_getter = false;
4179 bool is_setter = false;
4180 Handle<String> id =
ager@chromium.org04921a82011-06-27 13:21:41 +00004181 ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004182 if (fni_ != NULL) fni_->PushLiteralName(id);
4183
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004184 if ((is_getter || is_setter) && peek() != Token::COLON) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00004185 // Update loc to point to the identifier
4186 loc = scanner().peek_location();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 ObjectLiteral::Property* property =
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004188 ParseObjectLiteralGetSet(is_getter, CHECK_OK);
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004189 if (IsBoilerplateProperty(property)) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004190 number_of_boilerplate_properties++;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004191 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004192 // Validate the property.
4193 checker.CheckProperty(property, loc, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004194 properties->Add(property, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004196
4197 if (fni_ != NULL) {
4198 fni_->Infer();
4199 fni_->Leave();
4200 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201 continue; // restart the while
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004203 // Failed to parse as get/set property, so it's just a property
4204 // called "get" or "set".
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004205 key = factory()->NewLiteral(id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 break;
4207 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 case Token::STRING: {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004209 Consume(Token::STRING);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004210 Handle<String> string = GetSymbol(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004211 if (fni_ != NULL) fni_->PushLiteralName(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004212 uint32_t index;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00004213 if (!string.is_null() && string->AsArrayIndex(&index)) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004214 key = factory()->NewNumberLiteral(index);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004215 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004217 key = factory()->NewLiteral(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 break;
4219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220 case Token::NUMBER: {
4221 Consume(Token::NUMBER);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004222 ASSERT(scanner().is_literal_ascii());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004223 double value = StringToDouble(isolate()->unicode_cache(),
4224 scanner().literal_ascii_string(),
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004225 ALLOW_HEX | ALLOW_OCTALS);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004226 key = factory()->NewNumberLiteral(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004227 break;
4228 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004229 default:
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004230 if (Token::IsKeyword(next)) {
4231 Consume(next);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004232 Handle<String> string = GetSymbol(CHECK_OK);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004233 key = factory()->NewLiteral(string);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00004234 } else {
4235 // Unexpected token.
4236 Token::Value next = Next();
4237 ReportUnexpectedToken(next);
4238 *ok = false;
4239 return NULL;
4240 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 }
4242
4243 Expect(Token::COLON, CHECK_OK);
4244 Expression* value = ParseAssignmentExpression(true, CHECK_OK);
4245
4246 ObjectLiteral::Property* property =
ulan@chromium.org812308e2012-02-29 15:58:45 +00004247 new(zone()) ObjectLiteral::Property(key, value, isolate());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004248
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00004249 // Mark top-level object literals that contain function literals and
4250 // pretenure the literal so it can be added as a constant function
4251 // property.
4252 if (top_scope_->DeclarationScope()->is_global_scope() &&
4253 value->AsFunctionLiteral() != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004254 has_function = true;
danno@chromium.orgc612e022011-11-10 11:38:15 +00004255 value->AsFunctionLiteral()->set_pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004256 }
4257
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004258 // Count CONSTANT or COMPUTED properties to maintain the enumeration order.
ager@chromium.org236ad962008-09-25 09:45:57 +00004259 if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++;
ager@chromium.org378b34e2011-01-28 08:04:38 +00004260 // Validate the property
4261 checker.CheckProperty(property, loc, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004262 properties->Add(property, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004263
4264 // TODO(1240767): Consider allowing trailing comma.
4265 if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004266
4267 if (fni_ != NULL) {
4268 fni_->Infer();
4269 fni_->Leave();
4270 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004271 }
4272 Expect(Token::RBRACE, CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004274 // Computation of literal_index must happen before pre parse bailout.
danno@chromium.orgc612e022011-11-10 11:38:15 +00004275 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004276
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004277 Handle<FixedArray> constant_properties = isolate()->factory()->NewFixedArray(
4278 number_of_boilerplate_properties * 2, TENURED);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004279
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004280 bool is_simple = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004281 bool fast_elements = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004282 int depth = 1;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004283 BuildObjectLiteralConstantProperties(properties,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004284 constant_properties,
4285 &is_simple,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004286 &fast_elements,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004287 &depth);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004288 return factory()->NewObjectLiteral(constant_properties,
4289 properties,
4290 literal_index,
4291 is_simple,
4292 fast_elements,
4293 depth,
4294 has_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004295}
4296
4297
4298Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004299 if (!scanner().ScanRegExpPattern(seen_equal)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004300 Next();
4301 ReportMessage("unterminated_regexp", Vector<const char*>::empty());
4302 *ok = false;
4303 return NULL;
4304 }
4305
danno@chromium.orgc612e022011-11-10 11:38:15 +00004306 int literal_index = current_function_state_->NextMaterializedLiteralIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004307
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004308 Handle<String> js_pattern = NextLiteralString(TENURED);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004309 scanner().ScanRegExpFlags();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004310 Handle<String> js_flags = NextLiteralString(TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004311 Next();
4312
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004313 return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004314}
4315
4316
4317ZoneList<Expression*>* Parser::ParseArguments(bool* ok) {
4318 // Arguments ::
4319 // '(' (AssignmentExpression)*[','] ')'
4320
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004321 ZoneList<Expression*>* result = new(zone()) ZoneList<Expression*>(4, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004322 Expect(Token::LPAREN, CHECK_OK);
4323 bool done = (peek() == Token::RPAREN);
4324 while (!done) {
4325 Expression* argument = ParseAssignmentExpression(true, CHECK_OK);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004326 result->Add(argument, zone());
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004327 if (result->length() > kMaxNumFunctionParameters) {
4328 ReportMessageAt(scanner().location(), "too_many_arguments",
4329 Vector<const char*>::empty());
4330 *ok = false;
4331 return NULL;
4332 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004333 done = (peek() == Token::RPAREN);
4334 if (!done) Expect(Token::COMMA, CHECK_OK);
4335 }
4336 Expect(Token::RPAREN, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004337 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004338}
4339
4340
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004341class SingletonLogger : public ParserRecorder {
4342 public:
4343 SingletonLogger() : has_error_(false), start_(-1), end_(-1) { }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004344 virtual ~SingletonLogger() { }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004345
4346 void Reset() { has_error_ = false; }
4347
4348 virtual void LogFunction(int start,
4349 int end,
4350 int literals,
4351 int properties,
4352 LanguageMode mode) {
4353 ASSERT(!has_error_);
4354 start_ = start;
4355 end_ = end;
4356 literals_ = literals;
4357 properties_ = properties;
4358 mode_ = mode;
4359 };
4360
4361 // Logs a symbol creation of a literal or identifier.
4362 virtual void LogAsciiSymbol(int start, Vector<const char> literal) { }
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004363 virtual void LogUtf16Symbol(int start, Vector<const uc16> literal) { }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004364
4365 // Logs an error message and marks the log as containing an error.
4366 // Further logging will be ignored, and ExtractData will return a vector
4367 // representing the error only.
4368 virtual void LogMessage(int start,
4369 int end,
4370 const char* message,
4371 const char* argument_opt) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004372 if (has_error_) return;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004373 has_error_ = true;
4374 start_ = start;
4375 end_ = end;
4376 message_ = message;
4377 argument_opt_ = argument_opt;
4378 }
4379
4380 virtual int function_position() { return 0; }
4381
4382 virtual int symbol_position() { return 0; }
4383
4384 virtual int symbol_ids() { return -1; }
4385
4386 virtual Vector<unsigned> ExtractData() {
4387 UNREACHABLE();
4388 return Vector<unsigned>();
4389 }
4390
4391 virtual void PauseRecording() { }
4392
4393 virtual void ResumeRecording() { }
4394
4395 bool has_error() { return has_error_; }
4396
4397 int start() { return start_; }
4398 int end() { return end_; }
4399 int literals() {
4400 ASSERT(!has_error_);
4401 return literals_;
4402 }
4403 int properties() {
4404 ASSERT(!has_error_);
4405 return properties_;
4406 }
4407 LanguageMode language_mode() {
4408 ASSERT(!has_error_);
4409 return mode_;
4410 }
4411 const char* message() {
4412 ASSERT(has_error_);
4413 return message_;
4414 }
4415 const char* argument_opt() {
4416 ASSERT(has_error_);
4417 return argument_opt_;
4418 }
4419
4420 private:
4421 bool has_error_;
4422 int start_;
4423 int end_;
4424 // For function entries.
4425 int literals_;
4426 int properties_;
4427 LanguageMode mode_;
4428 // For error messages.
4429 const char* message_;
4430 const char* argument_opt_;
4431};
4432
4433
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004434FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
ager@chromium.org04921a82011-06-27 13:21:41 +00004435 bool name_is_strict_reserved,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004436 int function_token_position,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004437 FunctionLiteral::Type type,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 bool* ok) {
4439 // Function ::
4440 // '(' FormalParameterList? ')' '{' FunctionBody '}'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004441
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004442 // Anonymous functions were passed either the empty symbol or a null
4443 // handle as the function name. Remember if we were passed a non-empty
4444 // handle to decide whether to invoke function name inference.
4445 bool should_infer_name = function_name.is_null();
4446
4447 // We want a non-null handle as the function name.
4448 if (should_infer_name) {
4449 function_name = isolate()->factory()->empty_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004450 }
4451
4452 int num_parameters = 0;
danno@chromium.orgb6451162011-08-17 14:33:23 +00004453 // Function declarations are function scoped in normal mode, so they are
4454 // hoisted. In harmony block scoping mode they are block scoped, so they
4455 // are not hoisted.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004456 Scope* scope = (type == FunctionLiteral::DECLARATION && !is_extended_mode())
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004457 ? NewScope(top_scope_->DeclarationScope(), FUNCTION_SCOPE)
4458 : NewScope(top_scope_, FUNCTION_SCOPE);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004459 ZoneList<Statement*>* body = NULL;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004460 int materialized_literal_count = -1;
4461 int expected_property_count = -1;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004462 int handler_count = 0;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004463 bool only_simple_this_property_assignments;
4464 Handle<FixedArray> this_property_assignments;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004465 FunctionLiteral::ParameterFlag duplicate_parameters =
4466 FunctionLiteral::kNoDuplicateParameters;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004467 AstProperties ast_properties;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468 // Parse function body.
danno@chromium.orgc612e022011-11-10 11:38:15 +00004469 { FunctionState function_state(this, scope, isolate());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004470 top_scope_->SetScopeName(function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471
4472 // FormalParameterList ::
4473 // '(' (Identifier)*[','] ')'
4474 Expect(Token::LPAREN, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004475 scope->set_start_position(scanner().location().beg_pos);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004476 Scanner::Location name_loc = Scanner::Location::invalid();
4477 Scanner::Location dupe_loc = Scanner::Location::invalid();
4478 Scanner::Location reserved_loc = Scanner::Location::invalid();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004479
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480 bool done = (peek() == Token::RPAREN);
4481 while (!done) {
ager@chromium.org04921a82011-06-27 13:21:41 +00004482 bool is_strict_reserved = false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004483 Handle<String> param_name =
ager@chromium.org04921a82011-06-27 13:21:41 +00004484 ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
4485 CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004486
4487 // Store locations for possible future error reports.
4488 if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) {
4489 name_loc = scanner().location();
4490 }
4491 if (!dupe_loc.IsValid() && top_scope_->IsDeclared(param_name)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004492 duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
ager@chromium.org378b34e2011-01-28 08:04:38 +00004493 dupe_loc = scanner().location();
4494 }
ager@chromium.org04921a82011-06-27 13:21:41 +00004495 if (!reserved_loc.IsValid() && is_strict_reserved) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004496 reserved_loc = scanner().location();
4497 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004498
yangguo@chromium.org56454712012-02-16 15:33:53 +00004499 top_scope_->DeclareParameter(param_name, VAR);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004500 num_parameters++;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004501 if (num_parameters > kMaxNumFunctionParameters) {
4502 ReportMessageAt(scanner().location(), "too_many_parameters",
4503 Vector<const char*>::empty());
4504 *ok = false;
4505 return NULL;
4506 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507 done = (peek() == Token::RPAREN);
4508 if (!done) Expect(Token::COMMA, CHECK_OK);
4509 }
4510 Expect(Token::RPAREN, CHECK_OK);
4511
4512 Expect(Token::LBRACE, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513
4514 // If we have a named function expression, we add a local variable
4515 // declaration to the body of the function with the name of the
4516 // function and let it refer to the function itself (closure).
4517 // NOTE: We create a proxy and resolve it here so that in the
4518 // future we can change the AST to only refer to VariableProxies
4519 // instead of Variables and Proxis as is the case now.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004520 Variable* fvar = NULL;
4521 Token::Value fvar_init_op = Token::INIT_CONST;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004522 if (type == FunctionLiteral::NAMED_EXPRESSION) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004523 if (is_extended_mode()) fvar_init_op = Token::INIT_CONST_HARMONY;
4524 VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST;
4525 fvar = new(zone()) Variable(top_scope_,
4526 function_name, fvar_mode, true /* is valid LHS */,
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00004527 Variable::NORMAL, kCreatedInitialized, Interface::NewConst());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004528 VariableProxy* proxy = factory()->NewVariableProxy(fvar);
4529 VariableDeclaration* fvar_declaration =
4530 factory()->NewVariableDeclaration(proxy, fvar_mode, top_scope_);
4531 top_scope_->DeclareFunctionVar(fvar_declaration);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532 }
4533
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004534 // Determine whether the function will be lazily compiled.
4535 // The heuristics are:
4536 // - It must not have been prohibited by the caller to Parse (some callers
4537 // need a full AST).
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004538 // - The outer scope must allow lazy compilation of inner functions.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004539 // - The function mustn't be a function expression with an open parenthesis
4540 // before; we consider that a hint that the function will be called
4541 // immediately, and it would be a waste of time to make it lazily
4542 // compiled.
4543 // These are all things we can know at this point, without looking at the
4544 // function itself.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004545 bool is_lazily_compiled = (mode() == PARSE_LAZILY &&
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004546 top_scope_->AllowsLazyCompilation() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004547 !parenthesized_function_);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004548 parenthesized_function_ = false; // The bit was set for this function only.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004549
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004550 if (is_lazily_compiled) {
4551 int function_block_pos = scanner().location().beg_pos;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004552 FunctionEntry entry;
4553 if (pre_data_ != NULL) {
4554 // If we have pre_data_, we use it to skip parsing the function body.
4555 // the preparser data contains the information we need to construct the
4556 // lazy function.
4557 entry = pre_data()->GetFunctionEntry(function_block_pos);
4558 if (entry.is_valid()) {
4559 if (entry.end_pos() <= function_block_pos) {
4560 // End position greater than end of stream is safe, and hard
4561 // to check.
4562 ReportInvalidPreparseData(function_name, CHECK_OK);
4563 }
4564 scanner().SeekForward(entry.end_pos() - 1);
4565
4566 scope->set_end_position(entry.end_pos());
4567 Expect(Token::RBRACE, CHECK_OK);
4568 isolate()->counters()->total_preparse_skipped()->Increment(
4569 scope->end_position() - function_block_pos);
4570 materialized_literal_count = entry.literal_count();
4571 expected_property_count = entry.property_count();
4572 top_scope_->SetLanguageMode(entry.language_mode());
4573 only_simple_this_property_assignments = false;
4574 this_property_assignments = isolate()->factory()->empty_fixed_array();
4575 } else {
4576 is_lazily_compiled = false;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004577 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004578 } else {
4579 // With no preparser data, we partially parse the function, without
4580 // building an AST. This gathers the data needed to build a lazy
4581 // function.
4582 SingletonLogger logger;
4583 preparser::PreParser::PreParseResult result =
4584 LazyParseFunctionLiteral(&logger);
4585 if (result == preparser::PreParser::kPreParseStackOverflow) {
4586 // Propagate stack overflow.
4587 stack_overflow_ = true;
4588 *ok = false;
4589 return NULL;
4590 }
4591 if (logger.has_error()) {
4592 const char* arg = logger.argument_opt();
4593 Vector<const char*> args;
4594 if (arg != NULL) {
4595 args = Vector<const char*>(&arg, 1);
4596 }
4597 ReportMessageAt(Scanner::Location(logger.start(), logger.end()),
4598 logger.message(), args);
4599 *ok = false;
4600 return NULL;
4601 }
4602 scope->set_end_position(logger.end());
4603 Expect(Token::RBRACE, CHECK_OK);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004604 isolate()->counters()->total_preparse_skipped()->Increment(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004605 scope->end_position() - function_block_pos);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004606 materialized_literal_count = logger.literals();
4607 expected_property_count = logger.properties();
4608 top_scope_->SetLanguageMode(logger.language_mode());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004609 only_simple_this_property_assignments = false;
4610 this_property_assignments = isolate()->factory()->empty_fixed_array();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004611 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004612 }
4613
4614 if (!is_lazily_compiled) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004615 body = new(zone()) ZoneList<Statement*>(8, zone());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004616 if (fvar != NULL) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00004617 VariableProxy* fproxy = top_scope_->NewUnresolved(
4618 factory(), function_name, Interface::NewConst());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004619 fproxy->BindTo(fvar);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004620 body->Add(factory()->NewExpressionStatement(
4621 factory()->NewAssignment(fvar_init_op,
4622 fproxy,
4623 factory()->NewThisFunction(),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004624 RelocInfo::kNoPosition)),
4625 zone());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004626 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00004627 ParseSourceElements(body, Token::RBRACE, false, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004628
danno@chromium.orgc612e022011-11-10 11:38:15 +00004629 materialized_literal_count = function_state.materialized_literal_count();
4630 expected_property_count = function_state.expected_property_count();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004631 handler_count = function_state.handler_count();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004632 only_simple_this_property_assignments =
danno@chromium.orgc612e022011-11-10 11:38:15 +00004633 function_state.only_simple_this_property_assignments();
4634 this_property_assignments = function_state.this_property_assignments();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004635
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004636 Expect(Token::RBRACE, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004637 scope->set_end_position(scanner().location().end_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004638 }
4639
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004640 // Validate strict mode.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004641 if (!top_scope_->is_classic_mode()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004642 if (IsEvalOrArguments(function_name)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004643 int start_pos = scope->start_position();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004644 int position = function_token_position != RelocInfo::kNoPosition
ager@chromium.org378b34e2011-01-28 08:04:38 +00004645 ? function_token_position
4646 : (start_pos > 0 ? start_pos - 1 : start_pos);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004647 Scanner::Location location = Scanner::Location(position, start_pos);
4648 ReportMessageAt(location,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004649 "strict_function_name", Vector<const char*>::empty());
4650 *ok = false;
4651 return NULL;
4652 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004653 if (name_loc.IsValid()) {
4654 ReportMessageAt(name_loc, "strict_param_name",
4655 Vector<const char*>::empty());
4656 *ok = false;
4657 return NULL;
4658 }
4659 if (dupe_loc.IsValid()) {
4660 ReportMessageAt(dupe_loc, "strict_param_dupe",
4661 Vector<const char*>::empty());
4662 *ok = false;
4663 return NULL;
4664 }
ager@chromium.org04921a82011-06-27 13:21:41 +00004665 if (name_is_strict_reserved) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004666 int start_pos = scope->start_position();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004667 int position = function_token_position != RelocInfo::kNoPosition
4668 ? function_token_position
4669 : (start_pos > 0 ? start_pos - 1 : start_pos);
4670 Scanner::Location location = Scanner::Location(position, start_pos);
4671 ReportMessageAt(location, "strict_reserved_word",
4672 Vector<const char*>::empty());
4673 *ok = false;
4674 return NULL;
4675 }
4676 if (reserved_loc.IsValid()) {
4677 ReportMessageAt(reserved_loc, "strict_reserved_word",
4678 Vector<const char*>::empty());
4679 *ok = false;
4680 return NULL;
4681 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004682 CheckOctalLiteral(scope->start_position(),
4683 scope->end_position(),
4684 CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004685 }
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004686 ast_properties = *factory()->visitor()->ast_properties();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004687 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004688
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004689 if (is_extended_mode()) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004690 CheckConflictingVarDeclarations(scope, CHECK_OK);
4691 }
4692
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004693 FunctionLiteral* function_literal =
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004694 factory()->NewFunctionLiteral(function_name,
4695 scope,
4696 body,
4697 materialized_literal_count,
4698 expected_property_count,
4699 handler_count,
4700 only_simple_this_property_assignments,
4701 this_property_assignments,
4702 num_parameters,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004703 duplicate_parameters,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004704 type,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004705 FunctionLiteral::kIsFunction);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004706 function_literal->set_function_token_position(function_token_position);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004707 function_literal->set_ast_properties(&ast_properties);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004708
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004709 if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004710 return function_literal;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711}
4712
4713
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004714preparser::PreParser::PreParseResult Parser::LazyParseFunctionLiteral(
4715 SingletonLogger* logger) {
4716 HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse());
4717 ASSERT_EQ(Token::LBRACE, scanner().current_token());
4718
4719 if (reusable_preparser_ == NULL) {
4720 intptr_t stack_limit = isolate()->stack_guard()->real_climit();
4721 bool do_allow_lazy = true;
4722 reusable_preparser_ = new preparser::PreParser(&scanner_,
4723 NULL,
4724 stack_limit,
4725 do_allow_lazy,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00004726 allow_natives_syntax_,
4727 allow_modules_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004728 }
4729 preparser::PreParser::PreParseResult result =
4730 reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(),
4731 logger);
4732 return result;
4733}
4734
4735
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004736Expression* Parser::ParseV8Intrinsic(bool* ok) {
4737 // CallRuntime ::
4738 // '%' Identifier Arguments
4739
4740 Expect(Token::MOD, CHECK_OK);
4741 Handle<String> name = ParseIdentifier(CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004743
4744 if (extension_ != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004745 // The extension structures are only accessible while parsing the
4746 // very first time not when reparsing because of lazy compilation.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004747 top_scope_->DeclarationScope()->ForceEagerCompilation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004748 }
4749
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004750 const Runtime::Function* function = Runtime::FunctionForSymbol(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004751
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004752 // Check for built-in IS_VAR macro.
4753 if (function != NULL &&
4754 function->intrinsic_type == Runtime::RUNTIME &&
4755 function->function_id == Runtime::kIS_VAR) {
4756 // %IS_VAR(x) evaluates to x if x is a variable,
4757 // leads to a parse error otherwise. Could be implemented as an
4758 // inline function %_IS_VAR(x) to eliminate this special case.
4759 if (args->length() == 1 && args->at(0)->AsVariableProxy() != NULL) {
4760 return args->at(0);
4761 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 ReportMessage("unable_to_parse", Vector<const char*>::empty());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004763 *ok = false;
4764 return NULL;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004765 }
4766 }
4767
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004768 // Check that the expected number of arguments are being passed.
4769 if (function != NULL &&
4770 function->nargs != -1 &&
4771 function->nargs != args->length()) {
4772 ReportMessage("illegal_access", Vector<const char*>::empty());
4773 *ok = false;
4774 return NULL;
4775 }
4776
4777 // We have a valid intrinsics call or a call to a builtin.
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004778 return factory()->NewCallRuntime(name, function, args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779}
4780
4781
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004782bool Parser::peek_any_identifier() {
4783 Token::Value next = peek();
4784 return next == Token::IDENTIFIER ||
ager@chromium.org04921a82011-06-27 13:21:41 +00004785 next == Token::FUTURE_RESERVED_WORD ||
4786 next == Token::FUTURE_STRICT_RESERVED_WORD;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004787}
4788
4789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790void Parser::Consume(Token::Value token) {
4791 Token::Value next = Next();
4792 USE(next);
4793 USE(token);
4794 ASSERT(next == token);
4795}
4796
4797
4798void Parser::Expect(Token::Value token, bool* ok) {
4799 Token::Value next = Next();
4800 if (next == token) return;
4801 ReportUnexpectedToken(next);
4802 *ok = false;
4803}
4804
4805
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004806bool Parser::Check(Token::Value token) {
4807 Token::Value next = peek();
4808 if (next == token) {
4809 Consume(next);
4810 return true;
4811 }
4812 return false;
4813}
4814
4815
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004816void Parser::ExpectSemicolon(bool* ok) {
4817 // Check for automatic semicolon insertion according to
4818 // the rules given in ECMA-262, section 7.9, page 21.
4819 Token::Value tok = peek();
4820 if (tok == Token::SEMICOLON) {
4821 Next();
4822 return;
4823 }
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00004824 if (scanner().HasAnyLineTerminatorBeforeNext() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825 tok == Token::RBRACE ||
4826 tok == Token::EOS) {
4827 return;
4828 }
4829 Expect(Token::SEMICOLON, ok);
4830}
4831
4832
ulan@chromium.org812308e2012-02-29 15:58:45 +00004833void Parser::ExpectContextualKeyword(const char* keyword, bool* ok) {
4834 Expect(Token::IDENTIFIER, ok);
4835 if (!*ok) return;
4836 Handle<String> symbol = GetSymbol(ok);
4837 if (!*ok) return;
4838 if (!symbol->IsEqualTo(CStrVector(keyword))) {
4839 *ok = false;
4840 ReportUnexpectedToken(scanner().current_token());
4841 }
4842}
4843
4844
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004845Literal* Parser::GetLiteralUndefined() {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004846 return factory()->NewLiteral(isolate()->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847}
4848
4849
4850Literal* Parser::GetLiteralTheHole() {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00004851 return factory()->NewLiteral(isolate()->factory()->the_hole_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004852}
4853
4854
danno@chromium.orgb6451162011-08-17 14:33:23 +00004855// Parses an identifier that is valid for the current scope, in particular it
ager@chromium.org04921a82011-06-27 13:21:41 +00004856// fails on strict mode future reserved keywords in a strict scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004857Handle<String> Parser::ParseIdentifier(bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004858 if (!top_scope_->is_classic_mode()) {
ager@chromium.org04921a82011-06-27 13:21:41 +00004859 Expect(Token::IDENTIFIER, ok);
4860 } else if (!Check(Token::IDENTIFIER)) {
4861 Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
4862 }
4863 if (!*ok) return Handle<String>();
4864 return GetSymbol(ok);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004865}
4866
4867
ager@chromium.org04921a82011-06-27 13:21:41 +00004868// Parses and identifier or a strict mode future reserved word, and indicate
4869// whether it is strict mode future reserved.
4870Handle<String> Parser::ParseIdentifierOrStrictReservedWord(
4871 bool* is_strict_reserved, bool* ok) {
4872 *is_strict_reserved = false;
4873 if (!Check(Token::IDENTIFIER)) {
4874 Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
4875 *is_strict_reserved = true;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004876 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004877 if (!*ok) return Handle<String>();
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004878 return GetSymbol(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004879}
4880
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004881
4882Handle<String> Parser::ParseIdentifierName(bool* ok) {
4883 Token::Value next = Next();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004884 if (next != Token::IDENTIFIER &&
ager@chromium.org04921a82011-06-27 13:21:41 +00004885 next != Token::FUTURE_RESERVED_WORD &&
4886 next != Token::FUTURE_STRICT_RESERVED_WORD &&
4887 !Token::IsKeyword(next)) {
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004888 ReportUnexpectedToken(next);
4889 *ok = false;
4890 return Handle<String>();
4891 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004892 return GetSymbol(ok);
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004893}
4894
ager@chromium.org378b34e2011-01-28 08:04:38 +00004895
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004896void Parser::MarkAsLValue(Expression* expression) {
4897 VariableProxy* proxy = expression != NULL
4898 ? expression->AsVariableProxy()
4899 : NULL;
4900
4901 if (proxy != NULL) proxy->MarkAsLValue();
4902}
4903
4904
ager@chromium.org378b34e2011-01-28 08:04:38 +00004905// Checks LHS expression for assignment and prefix/postfix increment/decrement
4906// in strict mode.
4907void Parser::CheckStrictModeLValue(Expression* expression,
4908 const char* error,
4909 bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004910 ASSERT(!top_scope_->is_classic_mode());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004911 VariableProxy* lhs = expression != NULL
4912 ? expression->AsVariableProxy()
4913 : NULL;
4914
4915 if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
4916 ReportMessage(error, Vector<const char*>::empty());
4917 *ok = false;
4918 }
4919}
4920
4921
lrn@chromium.org1c092762011-05-09 09:42:16 +00004922// Checks whether an octal literal was last seen between beg_pos and end_pos.
4923// If so, reports an error. Only called for strict mode.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004924void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00004925 Scanner::Location octal = scanner().octal_position();
4926 if (octal.IsValid() &&
4927 beg_pos <= octal.beg_pos &&
4928 octal.end_pos <= end_pos) {
4929 ReportMessageAt(octal, "strict_octal_literal",
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004930 Vector<const char*>::empty());
4931 scanner().clear_octal_position();
4932 *ok = false;
4933 }
4934}
4935
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00004936
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004937void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
4938 Declaration* decl = scope->CheckConflictingVarDeclarations();
4939 if (decl != NULL) {
4940 // In harmony mode we treat conflicting variable bindinds as early
4941 // errors. See ES5 16 for a definition of early errors.
4942 Handle<String> name = decl->proxy()->name();
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004943 SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004944 const char* elms[2] = { "Variable", *c_string };
4945 Vector<const char*> args(elms, 2);
4946 int position = decl->proxy()->position();
4947 Scanner::Location location = position == RelocInfo::kNoPosition
4948 ? Scanner::Location::invalid()
4949 : Scanner::Location(position, position + 1);
4950 ReportMessageAt(location, "redeclaration", args);
4951 *ok = false;
4952 }
4953}
4954
4955
ager@chromium.org04921a82011-06-27 13:21:41 +00004956// This function reads an identifier name and determines whether or not it
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004957// is 'get' or 'set'.
ager@chromium.org04921a82011-06-27 13:21:41 +00004958Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get,
4959 bool* is_set,
4960 bool* ok) {
4961 Handle<String> result = ParseIdentifierName(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004962 if (!*ok) return Handle<String>();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004963 if (scanner().is_literal_ascii() && scanner().literal_length() == 3) {
4964 const char* token = scanner().literal_ascii_string().start();
4965 *is_get = strncmp(token, "get", 3) == 0;
4966 *is_set = !*is_get && strncmp(token, "set", 3) == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004967 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004968 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004969}
4970
4971
4972// ----------------------------------------------------------------------------
4973// Parser support
4974
4975
4976bool Parser::TargetStackContainsLabel(Handle<String> label) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004977 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
4978 BreakableStatement* stat = t->node()->AsBreakableStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004979 if (stat != NULL && ContainsLabel(stat->labels(), label))
4980 return true;
4981 }
4982 return false;
4983}
4984
4985
4986BreakableStatement* Parser::LookupBreakTarget(Handle<String> label, bool* ok) {
4987 bool anonymous = label.is_null();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004988 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
4989 BreakableStatement* stat = t->node()->AsBreakableStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990 if (stat == NULL) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004991 if ((anonymous && stat->is_target_for_anonymous()) ||
4992 (!anonymous && ContainsLabel(stat->labels(), label))) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004993 RegisterTargetUse(stat->break_target(), t->previous());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004994 return stat;
4995 }
4996 }
4997 return NULL;
4998}
4999
5000
5001IterationStatement* Parser::LookupContinueTarget(Handle<String> label,
5002 bool* ok) {
5003 bool anonymous = label.is_null();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00005004 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
5005 IterationStatement* stat = t->node()->AsIterationStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005006 if (stat == NULL) continue;
5007
5008 ASSERT(stat->is_target_for_anonymous());
5009 if (anonymous || ContainsLabel(stat->labels(), label)) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00005010 RegisterTargetUse(stat->continue_target(), t->previous());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011 return stat;
5012 }
5013 }
5014 return NULL;
5015}
5016
5017
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00005018void Parser::RegisterTargetUse(Label* target, Target* stop) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00005019 // Register that a break target found at the given stop in the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005020 // target stack has been used from the top of the target stack. Add
5021 // the break target to any TargetCollectors passed on the stack.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00005022 for (Target* t = target_stack_; t != stop; t = t->previous()) {
5023 TargetCollector* collector = t->node()->AsTargetCollector();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005024 if (collector != NULL) collector->AddTarget(target, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005025 }
5026}
5027
5028
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005029Expression* Parser::NewThrowReferenceError(Handle<String> type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005030 return NewThrowError(isolate()->factory()->MakeReferenceError_symbol(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005031 type, HandleVector<Object>(NULL, 0));
5032}
5033
5034
5035Expression* Parser::NewThrowSyntaxError(Handle<String> type,
5036 Handle<Object> first) {
5037 int argc = first.is_null() ? 0 : 1;
5038 Vector< Handle<Object> > arguments = HandleVector<Object>(&first, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005039 return NewThrowError(
5040 isolate()->factory()->MakeSyntaxError_symbol(), type, arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005041}
5042
5043
5044Expression* Parser::NewThrowTypeError(Handle<String> type,
5045 Handle<Object> first,
5046 Handle<Object> second) {
5047 ASSERT(!first.is_null() && !second.is_null());
5048 Handle<Object> elements[] = { first, second };
5049 Vector< Handle<Object> > arguments =
5050 HandleVector<Object>(elements, ARRAY_SIZE(elements));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005051 return NewThrowError(
5052 isolate()->factory()->MakeTypeError_symbol(), type, arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005053}
5054
5055
5056Expression* Parser::NewThrowError(Handle<String> constructor,
5057 Handle<String> type,
5058 Vector< Handle<Object> > arguments) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005059 int argc = arguments.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005060 Handle<FixedArray> elements = isolate()->factory()->NewFixedArray(argc,
5061 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005062 for (int i = 0; i < argc; i++) {
5063 Handle<Object> element = arguments[i];
5064 if (!element.is_null()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005065 elements->set(i, *element);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005066 }
5067 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005068 Handle<JSArray> array = isolate()->factory()->NewJSArrayWithElements(
5069 elements, FAST_ELEMENTS, TENURED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005070
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005071 ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2, zone());
5072 args->Add(factory()->NewLiteral(type), zone());
5073 args->Add(factory()->NewLiteral(array), zone());
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00005074 CallRuntime* call_constructor =
5075 factory()->NewCallRuntime(constructor, NULL, args);
5076 return factory()->NewThrow(call_constructor, scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005077}
5078
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005079// ----------------------------------------------------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005080// Regular expressions
5081
5082
5083RegExpParser::RegExpParser(FlatStringReader* in,
5084 Handle<String>* error,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005085 bool multiline,
5086 Zone* zone)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 : isolate_(Isolate::Current()),
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005088 zone_(zone),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005089 error_(error),
5090 captures_(NULL),
5091 in_(in),
5092 current_(kEndMarker),
5093 next_pos_(0),
5094 capture_count_(0),
5095 has_more_(true),
5096 multiline_(multiline),
5097 simple_(false),
5098 contains_anchor_(false),
5099 is_scanned_for_captures_(false),
5100 failed_(false) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00005101 Advance();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005102}
5103
5104
5105uc32 RegExpParser::Next() {
5106 if (has_next()) {
5107 return in()->Get(next_pos_);
5108 } else {
5109 return kEndMarker;
5110 }
5111}
5112
5113
5114void RegExpParser::Advance() {
5115 if (next_pos_ < in()->length()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005116 StackLimitCheck check(isolate());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005117 if (check.HasOverflowed()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005118 ReportError(CStrVector(Isolate::kStackOverflowMessage));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005119 } else if (zone()->excess_allocation()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005120 ReportError(CStrVector("Regular expression too large"));
5121 } else {
5122 current_ = in()->Get(next_pos_);
5123 next_pos_++;
5124 }
5125 } else {
5126 current_ = kEndMarker;
5127 has_more_ = false;
5128 }
5129}
5130
5131
5132void RegExpParser::Reset(int pos) {
5133 next_pos_ = pos;
5134 Advance();
5135}
5136
5137
5138void RegExpParser::Advance(int dist) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00005139 next_pos_ += dist - 1;
5140 Advance();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005141}
5142
5143
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005144bool RegExpParser::simple() {
5145 return simple_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005146}
5147
5148RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
5149 failed_ = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005150 *error_ = isolate()->factory()->NewStringFromAscii(message, NOT_TENURED);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005151 // Zip to the end to make sure the no more input is read.
5152 current_ = kEndMarker;
5153 next_pos_ = in()->length();
5154 return NULL;
5155}
5156
5157
5158// Pattern ::
5159// Disjunction
5160RegExpTree* RegExpParser::ParsePattern() {
5161 RegExpTree* result = ParseDisjunction(CHECK_FAILED);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005162 ASSERT(!has_more());
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005163 // If the result of parsing is a literal string atom, and it has the
5164 // same length as the input, then the atom is identical to the input.
5165 if (result->IsAtom() && result->AsAtom()->length() == in()->length()) {
5166 simple_ = true;
5167 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005168 return result;
5169}
5170
5171
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005172// Disjunction ::
5173// Alternative
5174// Alternative | Disjunction
5175// Alternative ::
5176// [empty]
5177// Term Alternative
5178// Term ::
5179// Assertion
5180// Atom
5181// Atom Quantifier
5182RegExpTree* RegExpParser::ParseDisjunction() {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005183 // Used to store current state while parsing subexpressions.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00005184 RegExpParserState initial_state(NULL, INITIAL, 0, zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005185 RegExpParserState* stored_state = &initial_state;
5186 // Cache the builder in a local variable for quick access.
5187 RegExpBuilder* builder = initial_state.builder();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005188 while (true) {
5189 switch (current()) {
5190 case kEndMarker:
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005191 if (stored_state->IsSubexpression()) {
5192 // Inside a parenthesized group when hitting end of input.
5193 ReportError(CStrVector("Unterminated group") CHECK_FAILED);
5194 }
5195 ASSERT_EQ(INITIAL, stored_state->group_type());
5196 // Parsing completed successfully.
5197 return builder->ToRegExp();
5198 case ')': {
5199 if (!stored_state->IsSubexpression()) {
5200 ReportError(CStrVector("Unmatched ')'") CHECK_FAILED);
5201 }
5202 ASSERT_NE(INITIAL, stored_state->group_type());
5203
5204 Advance();
5205 // End disjunction parsing and convert builder content to new single
5206 // regexp atom.
5207 RegExpTree* body = builder->ToRegExp();
5208
5209 int end_capture_index = captures_started();
5210
5211 int capture_index = stored_state->capture_index();
5212 SubexpressionType type = stored_state->group_type();
5213
5214 // Restore previous state.
5215 stored_state = stored_state->previous_state();
5216 builder = stored_state->builder();
5217
5218 // Build result of subexpression.
5219 if (type == CAPTURE) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005220 RegExpCapture* capture = new(zone()) RegExpCapture(body, capture_index);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005221 captures_->at(capture_index - 1) = capture;
5222 body = capture;
5223 } else if (type != GROUPING) {
5224 ASSERT(type == POSITIVE_LOOKAHEAD || type == NEGATIVE_LOOKAHEAD);
5225 bool is_positive = (type == POSITIVE_LOOKAHEAD);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005226 body = new(zone()) RegExpLookahead(body,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005227 is_positive,
5228 end_capture_index - capture_index,
5229 capture_index);
5230 }
5231 builder->AddAtom(body);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005232 // For compatability with JSC and ES3, we allow quantifiers after
5233 // lookaheads, and break in all cases.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005234 break;
5235 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005236 case '|': {
5237 Advance();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005238 builder->NewAlternative();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005239 continue;
5240 }
5241 case '*':
5242 case '+':
5243 case '?':
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005244 return ReportError(CStrVector("Nothing to repeat"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005245 case '^': {
5246 Advance();
iposva@chromium.org245aa852009-02-10 00:49:54 +00005247 if (multiline_) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005248 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005249 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_LINE));
iposva@chromium.org245aa852009-02-10 00:49:54 +00005250 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005251 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005252 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_INPUT));
iposva@chromium.org245aa852009-02-10 00:49:54 +00005253 set_contains_anchor();
5254 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005255 continue;
5256 }
5257 case '$': {
5258 Advance();
5259 RegExpAssertion::Type type =
5260 multiline_ ? RegExpAssertion::END_OF_LINE :
5261 RegExpAssertion::END_OF_INPUT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005262 builder->AddAssertion(new(zone()) RegExpAssertion(type));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005263 continue;
5264 }
5265 case '.': {
5266 Advance();
5267 // everything except \x0a, \x0d, \u2028 and \u2029
danno@chromium.org40cb8782011-05-25 07:58:50 +00005268 ZoneList<CharacterRange>* ranges =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005269 new(zone()) ZoneList<CharacterRange>(2, zone());
5270 CharacterRange::AddClassEscape('.', ranges, zone());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005271 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005272 builder->AddAtom(atom);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005273 break;
5274 }
5275 case '(': {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005276 SubexpressionType type = CAPTURE;
5277 Advance();
5278 if (current() == '?') {
5279 switch (Next()) {
5280 case ':':
5281 type = GROUPING;
5282 break;
5283 case '=':
5284 type = POSITIVE_LOOKAHEAD;
5285 break;
5286 case '!':
5287 type = NEGATIVE_LOOKAHEAD;
5288 break;
5289 default:
5290 ReportError(CStrVector("Invalid group") CHECK_FAILED);
5291 break;
5292 }
5293 Advance(2);
5294 } else {
5295 if (captures_ == NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005296 captures_ = new(zone()) ZoneList<RegExpCapture*>(2, zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005297 }
5298 if (captures_started() >= kMaxCaptures) {
5299 ReportError(CStrVector("Too many captures") CHECK_FAILED);
5300 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005301 captures_->Add(NULL, zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005302 }
5303 // Store current state and begin new disjunction parsing.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00005304 stored_state = new(zone()) RegExpParserState(stored_state, type,
5305 captures_started(), zone());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005306 builder = stored_state->builder();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005307 continue;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005308 }
5309 case '[': {
5310 RegExpTree* atom = ParseCharacterClass(CHECK_FAILED);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005311 builder->AddAtom(atom);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005312 break;
5313 }
5314 // Atom ::
5315 // \ AtomEscape
5316 case '\\':
5317 switch (Next()) {
5318 case kEndMarker:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005319 return ReportError(CStrVector("\\ at end of pattern"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005320 case 'b':
5321 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005322 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005323 new(zone()) RegExpAssertion(RegExpAssertion::BOUNDARY));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005324 continue;
5325 case 'B':
5326 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005327 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005328 new(zone()) RegExpAssertion(RegExpAssertion::NON_BOUNDARY));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005329 continue;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005330 // AtomEscape ::
5331 // CharacterClassEscape
5332 //
5333 // CharacterClassEscape :: one of
5334 // d D s S w W
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005335 case 'd': case 'D': case 's': case 'S': case 'w': case 'W': {
5336 uc32 c = Next();
5337 Advance(2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00005338 ZoneList<CharacterRange>* ranges =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005339 new(zone()) ZoneList<CharacterRange>(2, zone());
5340 CharacterRange::AddClassEscape(c, ranges, zone());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005341 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005342 builder->AddAtom(atom);
5343 break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005344 }
5345 case '1': case '2': case '3': case '4': case '5': case '6':
5346 case '7': case '8': case '9': {
5347 int index = 0;
5348 if (ParseBackReferenceIndex(&index)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005349 RegExpCapture* capture = NULL;
5350 if (captures_ != NULL && index <= captures_->length()) {
5351 capture = captures_->at(index - 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005352 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005353 if (capture == NULL) {
5354 builder->AddEmpty();
5355 break;
5356 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005357 RegExpTree* atom = new(zone()) RegExpBackReference(capture);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005358 builder->AddAtom(atom);
5359 break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005360 }
5361 uc32 first_digit = Next();
5362 if (first_digit == '8' || first_digit == '9') {
5363 // Treat as identity escape
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005364 builder->AddCharacter(first_digit);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005365 Advance(2);
5366 break;
5367 }
5368 }
5369 // FALLTHROUGH
5370 case '0': {
5371 Advance();
5372 uc32 octal = ParseOctalLiteral();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005373 builder->AddCharacter(octal);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005374 break;
5375 }
5376 // ControlEscape :: one of
5377 // f n r t v
5378 case 'f':
5379 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005380 builder->AddCharacter('\f');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005381 break;
5382 case 'n':
5383 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005384 builder->AddCharacter('\n');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005385 break;
5386 case 'r':
5387 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005388 builder->AddCharacter('\r');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005389 break;
5390 case 't':
5391 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005392 builder->AddCharacter('\t');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005393 break;
5394 case 'v':
5395 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005396 builder->AddCharacter('\v');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005397 break;
5398 case 'c': {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00005399 Advance();
5400 uc32 controlLetter = Next();
5401 // Special case if it is an ASCII letter.
5402 // Convert lower case letters to uppercase.
5403 uc32 letter = controlLetter & ~('a' ^ 'A');
5404 if (letter < 'A' || 'Z' < letter) {
5405 // controlLetter is not in range 'A'-'Z' or 'a'-'z'.
5406 // This is outside the specification. We match JSC in
5407 // reading the backslash as a literal character instead
5408 // of as starting an escape.
5409 builder->AddCharacter('\\');
5410 } else {
5411 Advance(2);
5412 builder->AddCharacter(controlLetter & 0x1f);
5413 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005414 break;
5415 }
5416 case 'x': {
5417 Advance(2);
5418 uc32 value;
5419 if (ParseHexEscape(2, &value)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005420 builder->AddCharacter(value);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005421 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005422 builder->AddCharacter('x');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005423 }
5424 break;
5425 }
5426 case 'u': {
5427 Advance(2);
5428 uc32 value;
5429 if (ParseHexEscape(4, &value)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005430 builder->AddCharacter(value);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005431 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005432 builder->AddCharacter('u');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005433 }
5434 break;
5435 }
5436 default:
5437 // Identity escape.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005438 builder->AddCharacter(Next());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005439 Advance(2);
5440 break;
5441 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005442 break;
5443 case '{': {
5444 int dummy;
5445 if (ParseIntervalQuantifier(&dummy, &dummy)) {
5446 ReportError(CStrVector("Nothing to repeat") CHECK_FAILED);
5447 }
5448 // fallthrough
5449 }
5450 default:
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005451 builder->AddCharacter(current());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005452 Advance();
5453 break;
5454 } // end switch(current())
5455
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005456 int min;
5457 int max;
5458 switch (current()) {
5459 // QuantifierPrefix ::
5460 // *
5461 // +
5462 // ?
5463 // {
5464 case '*':
5465 min = 0;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005466 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005467 Advance();
5468 break;
5469 case '+':
5470 min = 1;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005471 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005472 Advance();
5473 break;
5474 case '?':
5475 min = 0;
5476 max = 1;
5477 Advance();
5478 break;
5479 case '{':
5480 if (ParseIntervalQuantifier(&min, &max)) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005481 if (max < min) {
5482 ReportError(CStrVector("numbers out of order in {} quantifier.")
5483 CHECK_FAILED);
5484 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005485 break;
5486 } else {
5487 continue;
5488 }
5489 default:
5490 continue;
5491 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005492 RegExpQuantifier::Type type = RegExpQuantifier::GREEDY;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005493 if (current() == '?') {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005494 type = RegExpQuantifier::NON_GREEDY;
5495 Advance();
5496 } else if (FLAG_regexp_possessive_quantifier && current() == '+') {
5497 // FLAG_regexp_possessive_quantifier is a debug-only flag.
5498 type = RegExpQuantifier::POSSESSIVE;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005499 Advance();
5500 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005501 builder->AddQuantifierToAtom(min, max, type);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005502 }
5503}
5504
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005505
5506#ifdef DEBUG
5507// Currently only used in an ASSERT.
5508static bool IsSpecialClassEscape(uc32 c) {
5509 switch (c) {
5510 case 'd': case 'D':
5511 case 's': case 'S':
5512 case 'w': case 'W':
5513 return true;
5514 default:
5515 return false;
5516 }
5517}
5518#endif
5519
5520
5521// In order to know whether an escape is a backreference or not we have to scan
5522// the entire regexp and find the number of capturing parentheses. However we
5523// don't want to scan the regexp twice unless it is necessary. This mini-parser
5524// is called when needed. It can see the difference between capturing and
5525// noncapturing parentheses and can skip character classes and backslash-escaped
5526// characters.
5527void RegExpParser::ScanForCaptures() {
5528 // Start with captures started previous to current position
5529 int capture_count = captures_started();
5530 // Add count of captures after this position.
5531 int n;
5532 while ((n = current()) != kEndMarker) {
5533 Advance();
5534 switch (n) {
5535 case '\\':
5536 Advance();
5537 break;
5538 case '[': {
5539 int c;
5540 while ((c = current()) != kEndMarker) {
5541 Advance();
5542 if (c == '\\') {
5543 Advance();
5544 } else {
5545 if (c == ']') break;
5546 }
5547 }
5548 break;
5549 }
5550 case '(':
5551 if (current() != '?') capture_count++;
5552 break;
5553 }
5554 }
5555 capture_count_ = capture_count;
5556 is_scanned_for_captures_ = true;
5557}
5558
5559
5560bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
5561 ASSERT_EQ('\\', current());
5562 ASSERT('1' <= Next() && Next() <= '9');
iposva@chromium.org245aa852009-02-10 00:49:54 +00005563 // Try to parse a decimal literal that is no greater than the total number
5564 // of left capturing parentheses in the input.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005565 int start = position();
5566 int value = Next() - '0';
5567 Advance(2);
5568 while (true) {
5569 uc32 c = current();
5570 if (IsDecimalDigit(c)) {
5571 value = 10 * value + (c - '0');
iposva@chromium.org245aa852009-02-10 00:49:54 +00005572 if (value > kMaxCaptures) {
5573 Reset(start);
5574 return false;
5575 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005576 Advance();
5577 } else {
5578 break;
5579 }
5580 }
5581 if (value > captures_started()) {
5582 if (!is_scanned_for_captures_) {
5583 int saved_position = position();
5584 ScanForCaptures();
5585 Reset(saved_position);
5586 }
5587 if (value > capture_count_) {
5588 Reset(start);
5589 return false;
5590 }
5591 }
5592 *index_out = value;
5593 return true;
5594}
5595
5596
5597// QuantifierPrefix ::
5598// { DecimalDigits }
5599// { DecimalDigits , }
5600// { DecimalDigits , DecimalDigits }
iposva@chromium.org245aa852009-02-10 00:49:54 +00005601//
5602// Returns true if parsing succeeds, and set the min_out and max_out
5603// values. Values are truncated to RegExpTree::kInfinity if they overflow.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005604bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) {
5605 ASSERT_EQ(current(), '{');
5606 int start = position();
5607 Advance();
5608 int min = 0;
5609 if (!IsDecimalDigit(current())) {
5610 Reset(start);
5611 return false;
5612 }
5613 while (IsDecimalDigit(current())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005614 int next = current() - '0';
5615 if (min > (RegExpTree::kInfinity - next) / 10) {
5616 // Overflow. Skip past remaining decimal digits and return -1.
5617 do {
5618 Advance();
5619 } while (IsDecimalDigit(current()));
5620 min = RegExpTree::kInfinity;
5621 break;
5622 }
5623 min = 10 * min + next;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005624 Advance();
5625 }
5626 int max = 0;
5627 if (current() == '}') {
5628 max = min;
5629 Advance();
5630 } else if (current() == ',') {
5631 Advance();
5632 if (current() == '}') {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005633 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005634 Advance();
5635 } else {
5636 while (IsDecimalDigit(current())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00005637 int next = current() - '0';
5638 if (max > (RegExpTree::kInfinity - next) / 10) {
5639 do {
5640 Advance();
5641 } while (IsDecimalDigit(current()));
5642 max = RegExpTree::kInfinity;
5643 break;
5644 }
5645 max = 10 * max + next;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005646 Advance();
5647 }
5648 if (current() != '}') {
5649 Reset(start);
5650 return false;
5651 }
5652 Advance();
5653 }
5654 } else {
5655 Reset(start);
5656 return false;
5657 }
5658 *min_out = min;
5659 *max_out = max;
5660 return true;
5661}
5662
5663
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005664uc32 RegExpParser::ParseOctalLiteral() {
5665 ASSERT('0' <= current() && current() <= '7');
5666 // For compatibility with some other browsers (not all), we parse
5667 // up to three octal digits with a value below 256.
5668 uc32 value = current() - '0';
5669 Advance();
5670 if ('0' <= current() && current() <= '7') {
5671 value = value * 8 + current() - '0';
5672 Advance();
5673 if (value < 32 && '0' <= current() && current() <= '7') {
5674 value = value * 8 + current() - '0';
5675 Advance();
5676 }
5677 }
5678 return value;
5679}
5680
5681
5682bool RegExpParser::ParseHexEscape(int length, uc32 *value) {
5683 int start = position();
5684 uc32 val = 0;
5685 bool done = false;
5686 for (int i = 0; !done; i++) {
5687 uc32 c = current();
5688 int d = HexValue(c);
5689 if (d < 0) {
5690 Reset(start);
5691 return false;
5692 }
5693 val = val * 16 + d;
5694 Advance();
5695 if (i == length - 1) {
5696 done = true;
5697 }
5698 }
5699 *value = val;
5700 return true;
5701}
5702
5703
5704uc32 RegExpParser::ParseClassCharacterEscape() {
5705 ASSERT(current() == '\\');
5706 ASSERT(has_next() && !IsSpecialClassEscape(Next()));
5707 Advance();
5708 switch (current()) {
5709 case 'b':
5710 Advance();
5711 return '\b';
5712 // ControlEscape :: one of
5713 // f n r t v
5714 case 'f':
5715 Advance();
5716 return '\f';
5717 case 'n':
5718 Advance();
5719 return '\n';
5720 case 'r':
5721 Advance();
5722 return '\r';
5723 case 't':
5724 Advance();
5725 return '\t';
5726 case 'v':
5727 Advance();
5728 return '\v';
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00005729 case 'c': {
5730 uc32 controlLetter = Next();
5731 uc32 letter = controlLetter & ~('A' ^ 'a');
5732 // For compatibility with JSC, inside a character class
5733 // we also accept digits and underscore as control characters.
5734 if ((controlLetter >= '0' && controlLetter <= '9') ||
5735 controlLetter == '_' ||
5736 (letter >= 'A' && letter <= 'Z')) {
5737 Advance(2);
5738 // Control letters mapped to ASCII control characters in the range
5739 // 0x00-0x1f.
5740 return controlLetter & 0x1f;
5741 }
5742 // We match JSC in reading the backslash as a literal
5743 // character instead of as starting an escape.
5744 return '\\';
5745 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005746 case '0': case '1': case '2': case '3': case '4': case '5':
5747 case '6': case '7':
5748 // For compatibility, we interpret a decimal escape that isn't
5749 // a back reference (and therefore either \0 or not valid according
5750 // to the specification) as a 1..3 digit octal character code.
5751 return ParseOctalLiteral();
5752 case 'x': {
5753 Advance();
5754 uc32 value;
5755 if (ParseHexEscape(2, &value)) {
5756 return value;
5757 }
5758 // If \x is not followed by a two-digit hexadecimal, treat it
5759 // as an identity escape.
5760 return 'x';
5761 }
5762 case 'u': {
5763 Advance();
5764 uc32 value;
5765 if (ParseHexEscape(4, &value)) {
5766 return value;
5767 }
5768 // If \u is not followed by a four-digit hexadecimal, treat it
5769 // as an identity escape.
5770 return 'u';
5771 }
5772 default: {
5773 // Extended identity escape. We accept any character that hasn't
5774 // been matched by a more specific case, not just the subset required
5775 // by the ECMAScript specification.
5776 uc32 result = current();
5777 Advance();
5778 return result;
5779 }
5780 }
5781 return 0;
5782}
5783
5784
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005785CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) {
5786 ASSERT_EQ(0, *char_class);
5787 uc32 first = current();
5788 if (first == '\\') {
5789 switch (Next()) {
5790 case 'w': case 'W': case 'd': case 'D': case 's': case 'S': {
5791 *char_class = Next();
5792 Advance(2);
5793 return CharacterRange::Singleton(0); // Return dummy value.
5794 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005795 case kEndMarker:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005796 return ReportError(CStrVector("\\ at end of pattern"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005797 default:
5798 uc32 c = ParseClassCharacterEscape(CHECK_FAILED);
5799 return CharacterRange::Singleton(c);
5800 }
5801 } else {
5802 Advance();
5803 return CharacterRange::Singleton(first);
5804 }
5805}
5806
5807
lrn@chromium.org14a70352010-12-15 12:43:21 +00005808static const uc16 kNoCharClass = 0;
5809
5810// Adds range or pre-defined character class to character ranges.
5811// If char_class is not kInvalidClass, it's interpreted as a class
5812// escape (i.e., 's' means whitespace, from '\s').
5813static inline void AddRangeOrEscape(ZoneList<CharacterRange>* ranges,
5814 uc16 char_class,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005815 CharacterRange range,
5816 Zone* zone) {
lrn@chromium.org14a70352010-12-15 12:43:21 +00005817 if (char_class != kNoCharClass) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005818 CharacterRange::AddClassEscape(char_class, ranges, zone);
lrn@chromium.org14a70352010-12-15 12:43:21 +00005819 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005820 ranges->Add(range, zone);
lrn@chromium.org14a70352010-12-15 12:43:21 +00005821 }
5822}
5823
5824
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005825RegExpTree* RegExpParser::ParseCharacterClass() {
5826 static const char* kUnterminated = "Unterminated character class";
5827 static const char* kRangeOutOfOrder = "Range out of order in character class";
5828
5829 ASSERT_EQ(current(), '[');
5830 Advance();
5831 bool is_negated = false;
5832 if (current() == '^') {
5833 is_negated = true;
5834 Advance();
5835 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005836 ZoneList<CharacterRange>* ranges =
5837 new(zone()) ZoneList<CharacterRange>(2, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005838 while (has_more() && current() != ']') {
lrn@chromium.org14a70352010-12-15 12:43:21 +00005839 uc16 char_class = kNoCharClass;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005840 CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005841 if (current() == '-') {
5842 Advance();
5843 if (current() == kEndMarker) {
5844 // If we reach the end we break out of the loop and let the
5845 // following code report an error.
5846 break;
5847 } else if (current() == ']') {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005848 AddRangeOrEscape(ranges, char_class, first, zone());
5849 ranges->Add(CharacterRange::Singleton('-'), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005850 break;
5851 }
lrn@chromium.org14a70352010-12-15 12:43:21 +00005852 uc16 char_class_2 = kNoCharClass;
5853 CharacterRange next = ParseClassAtom(&char_class_2 CHECK_FAILED);
5854 if (char_class != kNoCharClass || char_class_2 != kNoCharClass) {
5855 // Either end is an escaped character class. Treat the '-' verbatim.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005856 AddRangeOrEscape(ranges, char_class, first, zone());
5857 ranges->Add(CharacterRange::Singleton('-'), zone());
5858 AddRangeOrEscape(ranges, char_class_2, next, zone());
lrn@chromium.org14a70352010-12-15 12:43:21 +00005859 continue;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005860 }
5861 if (first.from() > next.to()) {
5862 return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED);
5863 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005864 ranges->Add(CharacterRange::Range(first.from(), next.to()), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005865 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005866 AddRangeOrEscape(ranges, char_class, first, zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005867 }
5868 }
5869 if (!has_more()) {
5870 return ReportError(CStrVector(kUnterminated) CHECK_FAILED);
5871 }
5872 Advance();
5873 if (ranges->length() == 0) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005874 ranges->Add(CharacterRange::Everything(), zone());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005875 is_negated = !is_negated;
5876 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005877 return new(zone()) RegExpCharacterClass(ranges, is_negated);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005878}
5879
5880
5881// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005882// The Parser interface.
5883
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005884ParserMessage::~ParserMessage() {
5885 for (int i = 0; i < args().length(); i++)
5886 DeleteArray(args()[i]);
5887 DeleteArray(args().start());
5888}
5889
5890
5891ScriptDataImpl::~ScriptDataImpl() {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005892 if (owns_store_) store_.Dispose();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005893}
5894
5895
5896int ScriptDataImpl::Length() {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005897 return store_.length() * sizeof(unsigned);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005898}
5899
5900
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005901const char* ScriptDataImpl::Data() {
5902 return reinterpret_cast<const char*>(store_.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903}
5904
5905
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005906bool ScriptDataImpl::HasError() {
5907 return has_error();
5908}
5909
5910
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005911void ScriptDataImpl::Initialize() {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00005912 // Prepares state for use.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005913 if (store_.length() >= PreparseDataConstants::kHeaderSize) {
5914 function_index_ = PreparseDataConstants::kHeaderSize;
5915 int symbol_data_offset = PreparseDataConstants::kHeaderSize
5916 + store_[PreparseDataConstants::kFunctionsSizeOffset];
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005917 if (store_.length() > symbol_data_offset) {
5918 symbol_data_ = reinterpret_cast<byte*>(&store_[symbol_data_offset]);
5919 } else {
5920 // Partial preparse causes no symbol information.
5921 symbol_data_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
5922 }
5923 symbol_data_end_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
5924 }
5925}
5926
5927
5928int ScriptDataImpl::ReadNumber(byte** source) {
5929 // Reads a number from symbol_data_ in base 128. The most significant
5930 // bit marks that there are more digits.
5931 // If the first byte is 0x80 (kNumberTerminator), it would normally
5932 // represent a leading zero. Since that is useless, and therefore won't
5933 // appear as the first digit of any actual value, it is used to
5934 // mark the end of the input stream.
5935 byte* data = *source;
5936 if (data >= symbol_data_end_) return -1;
5937 byte input = *data;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005938 if (input == PreparseDataConstants::kNumberTerminator) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00005939 // End of stream marker.
5940 return -1;
5941 }
5942 int result = input & 0x7f;
5943 data++;
5944 while ((input & 0x80u) != 0) {
5945 if (data >= symbol_data_end_) return -1;
5946 input = *data;
5947 result = (result << 7) | (input & 0x7f);
5948 data++;
5949 }
5950 *source = data;
5951 return result;
5952}
5953
5954
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00005955// Create a Scanner for the preparser to use as input, and preparse the source.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005956static ScriptDataImpl* DoPreParse(Utf16CharacterStream* source,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005957 int flags,
5958 ParserRecorder* recorder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005959 Isolate* isolate = Isolate::Current();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005960 HistogramTimerScope timer(isolate->counters()->pre_parse());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005961 Scanner scanner(isolate->unicode_cache());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005962 scanner.SetHarmonyScoping(FLAG_harmony_scoping);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005963 scanner.Initialize(source);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005964 intptr_t stack_limit = isolate->stack_guard()->real_climit();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005965 preparser::PreParser::PreParseResult result =
5966 preparser::PreParser::PreParseProgram(&scanner,
5967 recorder,
5968 flags,
5969 stack_limit);
5970 if (result == preparser::PreParser::kPreParseStackOverflow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005971 isolate->StackOverflow();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00005972 return NULL;
5973 }
5974
5975 // Extract the accumulated data from the recorder as a single
5976 // contiguous vector that we are responsible for disposing.
5977 Vector<unsigned> store = recorder->ExtractData();
5978 return new ScriptDataImpl(store);
5979}
5980
5981
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005982ScriptDataImpl* ParserApi::PreParse(Utf16CharacterStream* source,
danno@chromium.orgb6451162011-08-17 14:33:23 +00005983 v8::Extension* extension,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005984 int flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005985 Handle<Script> no_script;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005986 if (FLAG_lazy && (extension == NULL)) {
5987 flags |= kAllowLazy;
5988 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00005989 CompleteParserRecorder recorder;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005990 return DoPreParse(source, flags, &recorder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991}
5992
5993
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00005994bool RegExpParser::ParseRegExp(FlatStringReader* input,
5995 bool multiline,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005996 RegExpCompileData* result,
5997 Zone* zone) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005998 ASSERT(result != NULL);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005999 RegExpParser parser(input, &result->error, multiline, zone);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006000 RegExpTree* tree = parser.ParsePattern();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006001 if (parser.failed()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006002 ASSERT(tree == NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006003 ASSERT(!result->error.is_null());
6004 } else {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006005 ASSERT(tree != NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006006 ASSERT(result->error.is_null());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006007 result->tree = tree;
6008 int capture_count = parser.captures_started();
6009 result->simple = tree->IsAtom() && parser.simple() && capture_count == 0;
iposva@chromium.org245aa852009-02-10 00:49:54 +00006010 result->contains_anchor = parser.contains_anchor();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006011 result->capture_count = capture_count;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006012 }
6013 return !parser.failed();
6014}
6015
6016
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00006017bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006018 ASSERT(info->function() == NULL);
6019 FunctionLiteral* result = NULL;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00006020 ASSERT((parsing_flags & kLanguageModeMask) == CLASSIC_MODE);
6021 if (!info->is_native() && FLAG_harmony_scoping) {
6022 // Harmony scoping is requested.
6023 parsing_flags |= EXTENDED_MODE;
6024 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00006025 if (!info->is_native() && FLAG_harmony_modules) {
6026 parsing_flags |= kAllowModules;
6027 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00006028 if (FLAG_allow_natives_syntax || info->is_native()) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00006029 // We require %identifier(..) syntax.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00006030 parsing_flags |= kAllowNativesSyntax;
6031 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006032 if (info->is_lazy()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006033 ASSERT(!info->is_eval());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006034 Parser parser(info, parsing_flags, NULL, NULL);
yangguo@chromium.org56454712012-02-16 15:33:53 +00006035 if (info->shared_info()->is_function()) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006036 result = parser.ParseLazy();
yangguo@chromium.org56454712012-02-16 15:33:53 +00006037 } else {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006038 result = parser.ParseProgram();
yangguo@chromium.org56454712012-02-16 15:33:53 +00006039 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006040 } else {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006041 ScriptDataImpl* pre_data = info->pre_parse_data();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006042 Parser parser(info, parsing_flags, info->extension(), pre_data);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006043 if (pre_data != NULL && pre_data->has_error()) {
6044 Scanner::Location loc = pre_data->MessageLocation();
6045 const char* message = pre_data->BuildMessage();
6046 Vector<const char*> args = pre_data->BuildArgs();
6047 parser.ReportMessageAt(loc, message, args);
6048 DeleteArray(message);
6049 for (int i = 0; i < args.length(); i++) {
6050 DeleteArray(args[i]);
6051 }
6052 DeleteArray(args.start());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006053 ASSERT(info->isolate()->has_pending_exception());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006054 } else {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006055 result = parser.ParseProgram();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006056 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006057 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006058 info->SetFunction(result);
6059 return (result != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060}
6061
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062} } // namespace v8::internal