blob: 69e71b862afcb72c5206dcfe18f26af80041b633 [file] [log] [blame]
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001// Copyright 2011 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"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000031#include "ast-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000033#include "codegen.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000034#include "compiler.h"
ricow@chromium.org65fae842010-08-25 15:26:24 +000035#include "func-name-inferrer.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000036#include "messages.h"
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +000037#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "platform.h"
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000039#include "preparser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "runtime.h"
ager@chromium.orgb5737492010-07-15 09:29:43 +000041#include "scopeinfo.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000042#include "string-stream.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043
kasperl@chromium.org71affb52009-05-26 05:44:31 +000044namespace v8 {
45namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000047// PositionStack is used for on-stack allocation of token positions for
48// new expressions. Please look at ParseNewExpression.
49
50class PositionStack {
51 public:
52 explicit PositionStack(bool* ok) : top_(NULL), ok_(ok) {}
53 ~PositionStack() { ASSERT(!*ok_ || is_empty()); }
54
55 class Element {
56 public:
57 Element(PositionStack* stack, int value) {
58 previous_ = stack->top();
59 value_ = value;
60 stack->set_top(this);
61 }
62
63 private:
64 Element* previous() { return previous_; }
65 int value() { return value_; }
66 friend class PositionStack;
67 Element* previous_;
68 int value_;
69 };
70
71 bool is_empty() { return top_ == NULL; }
72 int pop() {
73 ASSERT(!is_empty());
74 int result = top_->value();
75 top_ = top_->previous();
76 return result;
77 }
78
79 private:
80 Element* top() { return top_; }
81 void set_top(Element* value) { top_ = value; }
82 Element* top_;
83 bool* ok_;
84};
85
86
ager@chromium.orga74f0da2008-12-03 16:05:52 +000087RegExpBuilder::RegExpBuilder()
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000088 : zone_(Isolate::Current()->zone()),
89 pending_empty_(false),
90 characters_(NULL),
91 terms_(),
92 alternatives_()
ager@chromium.orga74f0da2008-12-03 16:05:52 +000093#ifdef DEBUG
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000094 , last_added_(ADD_NONE)
ager@chromium.orga74f0da2008-12-03 16:05:52 +000095#endif
96 {}
97
98
99void RegExpBuilder::FlushCharacters() {
100 pending_empty_ = false;
101 if (characters_ != NULL) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000102 RegExpTree* atom = new(zone()) RegExpAtom(characters_->ToConstVector());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000103 characters_ = NULL;
104 text_.Add(atom);
105 LAST(ADD_ATOM);
106 }
107}
108
109
110void RegExpBuilder::FlushText() {
111 FlushCharacters();
112 int num_text = text_.length();
113 if (num_text == 0) {
114 return;
115 } else if (num_text == 1) {
116 terms_.Add(text_.last());
117 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000118 RegExpText* text = new(zone()) RegExpText();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000119 for (int i = 0; i < num_text; i++)
120 text_.Get(i)->AppendToText(text);
121 terms_.Add(text);
122 }
123 text_.Clear();
124}
125
126
127void RegExpBuilder::AddCharacter(uc16 c) {
128 pending_empty_ = false;
129 if (characters_ == NULL) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000130 characters_ = new(zone()) ZoneList<uc16>(4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000131 }
132 characters_->Add(c);
133 LAST(ADD_CHAR);
134}
135
136
137void RegExpBuilder::AddEmpty() {
138 pending_empty_ = true;
139}
140
141
142void RegExpBuilder::AddAtom(RegExpTree* term) {
143 if (term->IsEmpty()) {
144 AddEmpty();
145 return;
146 }
147 if (term->IsTextElement()) {
148 FlushCharacters();
149 text_.Add(term);
150 } else {
151 FlushText();
152 terms_.Add(term);
153 }
154 LAST(ADD_ATOM);
155}
156
157
158void RegExpBuilder::AddAssertion(RegExpTree* assert) {
159 FlushText();
160 terms_.Add(assert);
161 LAST(ADD_ASSERT);
162}
163
164
165void RegExpBuilder::NewAlternative() {
166 FlushTerms();
167}
168
169
170void RegExpBuilder::FlushTerms() {
171 FlushText();
172 int num_terms = terms_.length();
173 RegExpTree* alternative;
174 if (num_terms == 0) {
175 alternative = RegExpEmpty::GetInstance();
176 } else if (num_terms == 1) {
177 alternative = terms_.last();
178 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000179 alternative = new(zone()) RegExpAlternative(terms_.GetList());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000180 }
181 alternatives_.Add(alternative);
182 terms_.Clear();
183 LAST(ADD_NONE);
184}
185
186
187RegExpTree* RegExpBuilder::ToRegExp() {
188 FlushTerms();
189 int num_alternatives = alternatives_.length();
190 if (num_alternatives == 0) {
191 return RegExpEmpty::GetInstance();
192 }
193 if (num_alternatives == 1) {
194 return alternatives_.last();
195 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000196 return new(zone()) RegExpDisjunction(alternatives_.GetList());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000197}
198
199
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000200void RegExpBuilder::AddQuantifierToAtom(int min,
201 int max,
202 RegExpQuantifier::Type type) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000203 if (pending_empty_) {
204 pending_empty_ = false;
205 return;
206 }
207 RegExpTree* atom;
208 if (characters_ != NULL) {
209 ASSERT(last_added_ == ADD_CHAR);
210 // Last atom was character.
211 Vector<const uc16> char_vector = characters_->ToConstVector();
212 int num_chars = char_vector.length();
213 if (num_chars > 1) {
214 Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000215 text_.Add(new(zone()) RegExpAtom(prefix));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000216 char_vector = char_vector.SubVector(num_chars - 1, num_chars);
217 }
218 characters_ = NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000219 atom = new(zone()) RegExpAtom(char_vector);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000220 FlushText();
221 } else if (text_.length() > 0) {
222 ASSERT(last_added_ == ADD_ATOM);
223 atom = text_.RemoveLast();
224 FlushText();
225 } else if (terms_.length() > 0) {
226 ASSERT(last_added_ == ADD_ATOM);
227 atom = terms_.RemoveLast();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000228 if (atom->max_match() == 0) {
229 // Guaranteed to only match an empty string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000230 LAST(ADD_TERM);
231 if (min == 0) {
232 return;
233 }
234 terms_.Add(atom);
235 return;
236 }
237 } else {
238 // Only call immediately after adding an atom or character!
239 UNREACHABLE();
240 return;
241 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000242 terms_.Add(new(zone()) RegExpQuantifier(min, max, type, atom));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000243 LAST(ADD_TERM);
244}
245
246
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000247Handle<String> Parser::LookupSymbol(int symbol_id) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000248 // Length of symbol cache is the number of identified symbols.
249 // If we are larger than that, or negative, it's not a cached symbol.
250 // This might also happen if there is no preparser symbol data, even
251 // if there is some preparser data.
252 if (static_cast<unsigned>(symbol_id)
253 >= static_cast<unsigned>(symbol_cache_.length())) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000254 if (scanner().is_literal_ascii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000255 return isolate()->factory()->LookupAsciiSymbol(
256 scanner().literal_ascii_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000257 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000258 return isolate()->factory()->LookupTwoByteSymbol(
259 scanner().literal_uc16_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000260 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000261 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000262 return LookupCachedSymbol(symbol_id);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000263}
264
265
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000266Handle<String> Parser::LookupCachedSymbol(int symbol_id) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000267 // Make sure the cache is large enough to hold the symbol identifier.
268 if (symbol_cache_.length() <= symbol_id) {
269 // Increase length to index + 1.
270 symbol_cache_.AddBlock(Handle<String>::null(),
271 symbol_id + 1 - symbol_cache_.length());
272 }
273 Handle<String> result = symbol_cache_.at(symbol_id);
274 if (result.is_null()) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000275 if (scanner().is_literal_ascii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000276 result = isolate()->factory()->LookupAsciiSymbol(
277 scanner().literal_ascii_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000278 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000279 result = isolate()->factory()->LookupTwoByteSymbol(
280 scanner().literal_uc16_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000281 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000282 symbol_cache_.at(symbol_id) = result;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000283 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000285 isolate()->counters()->total_preparse_symbols_skipped()->Increment();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000286 return result;
287}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000289
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000290FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) {
291 // The current pre-data entry must be a FunctionEntry with the given
292 // start position.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000293 if ((function_index_ + FunctionEntry::kSize <= store_.length())
294 && (static_cast<int>(store_[function_index_]) == start)) {
295 int index = function_index_;
296 function_index_ += FunctionEntry::kSize;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000297 return FunctionEntry(store_.SubVector(index,
298 index + FunctionEntry::kSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000299 }
300 return FunctionEntry();
301}
302
303
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000304int ScriptDataImpl::GetSymbolIdentifier() {
305 return ReadNumber(&symbol_data_);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000306}
307
308
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000309bool ScriptDataImpl::SanityCheck() {
310 // Check that the header data is valid and doesn't specify
311 // point to positions outside the store.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000312 if (store_.length() < PreparseDataConstants::kHeaderSize) return false;
313 if (magic() != PreparseDataConstants::kMagicNumber) return false;
314 if (version() != PreparseDataConstants::kCurrentVersion) return false;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000315 if (has_error()) {
316 // Extra sane sanity check for error message encoding.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000317 if (store_.length() <= PreparseDataConstants::kHeaderSize
318 + PreparseDataConstants::kMessageTextPos) {
319 return false;
320 }
321 if (Read(PreparseDataConstants::kMessageStartPos) >
322 Read(PreparseDataConstants::kMessageEndPos)) {
323 return false;
324 }
325 unsigned arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
326 int pos = PreparseDataConstants::kMessageTextPos;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000327 for (unsigned int i = 0; i <= arg_count; i++) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000328 if (store_.length() <= PreparseDataConstants::kHeaderSize + pos) {
329 return false;
330 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000331 int length = static_cast<int>(Read(pos));
332 if (length < 0) return false;
333 pos += 1 + length;
334 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000335 if (store_.length() < PreparseDataConstants::kHeaderSize + pos) {
336 return false;
337 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000338 return true;
339 }
340 // Check that the space allocated for function entries is sane.
341 int functions_size =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000342 static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000343 if (functions_size < 0) return false;
344 if (functions_size % FunctionEntry::kSize != 0) return false;
345 // Check that the count of symbols is non-negative.
346 int symbol_count =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000347 static_cast<int>(store_[PreparseDataConstants::kSymbolCountOffset]);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000348 if (symbol_count < 0) return false;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000349 // Check that the total size has room for header and function entries.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000350 int minimum_size =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000351 PreparseDataConstants::kHeaderSize + functions_size;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000352 if (store_.length() < minimum_size) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000353 return true;
354}
355
356
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000357
ricow@chromium.org65fae842010-08-25 15:26:24 +0000358const char* ScriptDataImpl::ReadString(unsigned* start, int* chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000359 int length = start[0];
360 char* result = NewArray<char>(length + 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000361 for (int i = 0; i < length; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 result[i] = start[i + 1];
ricow@chromium.org65fae842010-08-25 15:26:24 +0000363 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 result[length] = '\0';
365 if (chars != NULL) *chars = length;
366 return result;
367}
368
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000369Scanner::Location ScriptDataImpl::MessageLocation() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000370 int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
371 int end_pos = Read(PreparseDataConstants::kMessageEndPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000372 return Scanner::Location(beg_pos, end_pos);
373}
374
375
376const char* ScriptDataImpl::BuildMessage() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000377 unsigned* start = ReadAddress(PreparseDataConstants::kMessageTextPos);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000378 return ReadString(start, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000379}
380
381
382Vector<const char*> ScriptDataImpl::BuildArgs() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000383 int arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 const char** array = NewArray<const char*>(arg_count);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000385 // Position after text found by skipping past length field and
386 // length field content words.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000387 int pos = PreparseDataConstants::kMessageTextPos + 1
388 + Read(PreparseDataConstants::kMessageTextPos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389 for (int i = 0; i < arg_count; i++) {
390 int count = 0;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000391 array[i] = ReadString(ReadAddress(pos), &count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000392 pos += count + 1;
393 }
394 return Vector<const char*>(array, arg_count);
395}
396
397
398unsigned ScriptDataImpl::Read(int position) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000399 return store_[PreparseDataConstants::kHeaderSize + position];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400}
401
402
403unsigned* ScriptDataImpl::ReadAddress(int position) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000404 return &store_[PreparseDataConstants::kHeaderSize + position];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405}
406
407
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000408Scope* Parser::NewScope(Scope* parent, Scope::Type type, bool inside_with) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000409 Scope* result = new(zone()) Scope(parent, type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 result->Initialize(inside_with);
411 return result;
412}
413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414// ----------------------------------------------------------------------------
415// Target is a support class to facilitate manipulation of the
416// Parser's target_stack_ (the stack of potential 'break' and
417// 'continue' statement targets). Upon construction, a new target is
418// added; it is removed upon destruction.
419
420class Target BASE_EMBEDDED {
421 public:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000422 Target(Target** variable, AstNode* node)
423 : variable_(variable), node_(node), previous_(*variable) {
424 *variable = this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000425 }
426
427 ~Target() {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000428 *variable_ = previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 }
430
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000431 Target* previous() { return previous_; }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000432 AstNode* node() { return node_; }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000434 private:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000435 Target** variable_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000436 AstNode* node_;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000437 Target* previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438};
439
440
441class TargetScope BASE_EMBEDDED {
442 public:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000443 explicit TargetScope(Target** variable)
444 : variable_(variable), previous_(*variable) {
445 *variable = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000446 }
447
448 ~TargetScope() {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000449 *variable_ = previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000450 }
451
452 private:
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000453 Target** variable_;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000454 Target* previous_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455};
456
457
458// ----------------------------------------------------------------------------
459// LexicalScope is a support class to facilitate manipulation of the
460// Parser's scope stack. The constructor sets the parser's top scope
461// to the incoming scope, and the destructor resets it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462//
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000463// Additionally, it stores transient information used during parsing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000464// These scopes are not kept around after parsing or referenced by syntax
465// trees so they can be stack-allocated and hence used by the pre-parser.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000466
467class LexicalScope BASE_EMBEDDED {
468 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 LexicalScope(Parser* parser, Scope* scope, Isolate* isolate);
470 ~LexicalScope();
471
472 int NextMaterializedLiteralIndex() {
473 int next_index =
474 materialized_literal_count_ + JSFunction::kLiteralsPrefixSize;
475 materialized_literal_count_++;
476 return next_index;
477 }
478 int materialized_literal_count() { return materialized_literal_count_; }
479
480 void SetThisPropertyAssignmentInfo(
481 bool only_simple_this_property_assignments,
482 Handle<FixedArray> this_property_assignments) {
483 only_simple_this_property_assignments_ =
484 only_simple_this_property_assignments;
485 this_property_assignments_ = this_property_assignments;
486 }
487 bool only_simple_this_property_assignments() {
488 return only_simple_this_property_assignments_;
489 }
490 Handle<FixedArray> this_property_assignments() {
491 return this_property_assignments_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492 }
493
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000494 void AddProperty() { expected_property_count_++; }
495 int expected_property_count() { return expected_property_count_; }
496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000498 // Captures the number of literals that need materialization in the
499 // function. Includes regexp literals, and boilerplate for object
500 // and array literals.
501 int materialized_literal_count_;
502
503 // Properties count estimation.
504 int expected_property_count_;
505
506 // Keeps track of assignments to properties of this. Used for
507 // optimizing constructors.
508 bool only_simple_this_property_assignments_;
509 Handle<FixedArray> this_property_assignments_;
510
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000511 // Bookkeeping
512 Parser* parser_;
513 // Previous values
514 LexicalScope* lexical_scope_parent_;
515 Scope* previous_scope_;
516 int previous_with_nesting_level_;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000517 unsigned previous_ast_node_id_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518};
519
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520
521LexicalScope::LexicalScope(Parser* parser, Scope* scope, Isolate* isolate)
522 : materialized_literal_count_(0),
523 expected_property_count_(0),
524 only_simple_this_property_assignments_(false),
525 this_property_assignments_(isolate->factory()->empty_fixed_array()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000526 parser_(parser),
527 lexical_scope_parent_(parser->lexical_scope_),
528 previous_scope_(parser->top_scope_),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000529 previous_with_nesting_level_(parser->with_nesting_level_),
530 previous_ast_node_id_(isolate->ast_node_id()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000531 parser->top_scope_ = scope;
532 parser->lexical_scope_ = this;
533 parser->with_nesting_level_ = 0;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000534 isolate->set_ast_node_id(AstNode::kFunctionEntryId + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000535}
536
537
538LexicalScope::~LexicalScope() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 parser_->top_scope_ = previous_scope_;
540 parser_->lexical_scope_ = lexical_scope_parent_;
541 parser_->with_nesting_level_ = previous_with_nesting_level_;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000542 parser_->isolate()->set_ast_node_id(previous_ast_node_id_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543}
544
545
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546// ----------------------------------------------------------------------------
547// The CHECK_OK macro is a convenient macro to enforce error
548// handling for functions that may fail (by returning !*ok).
549//
550// CAUTION: This macro appends extra statements after a call,
551// thus it must never be used where only a single statement
552// is correct (e.g. an if statement branch w/o braces)!
553
554#define CHECK_OK ok); \
555 if (!*ok) return NULL; \
556 ((void)0
557#define DUMMY ) // to make indentation work
558#undef DUMMY
559
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000560#define CHECK_FAILED /**/); \
561 if (failed_) return NULL; \
562 ((void)0
563#define DUMMY ) // to make indentation work
564#undef DUMMY
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565
566// ----------------------------------------------------------------------------
567// Implementation of Parser
568
569Parser::Parser(Handle<Script> script,
570 bool allow_natives_syntax,
571 v8::Extension* extension,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572 ScriptDataImpl* pre_data)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000573 : isolate_(script->GetIsolate()),
574 symbol_cache_(pre_data ? pre_data->symbol_count() : 0),
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000575 script_(script),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000576 scanner_(isolate_->unicode_cache()),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577 top_scope_(NULL),
578 with_nesting_level_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 lexical_scope_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580 target_stack_(NULL),
581 allow_natives_syntax_(allow_natives_syntax),
582 extension_(extension),
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000583 pre_data_(pre_data),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000584 fni_(NULL),
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000585 stack_overflow_(false),
586 parenthesized_function_(false) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000587 AstNode::ResetIds();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588}
589
590
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000591FunctionLiteral* Parser::ParseProgram(Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000592 bool in_global_context,
593 StrictModeFlag strict_mode) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000594 ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000595
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000596 HistogramTimerScope timer(isolate()->counters()->parse());
597 isolate()->counters()->total_parse_size()->Increment(source->length());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000598 fni_ = new(zone()) FuncNameInferrer();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599
600 // Initialize parser state.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000601 source->TryFlatten();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000602 if (source->IsExternalTwoByteString()) {
603 // Notice that the stream is destroyed at the end of the branch block.
604 // The last line of the blocks can't be moved outside, even though they're
605 // identical calls.
606 ExternalTwoByteStringUC16CharacterStream stream(
607 Handle<ExternalTwoByteString>::cast(source), 0, source->length());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000608 scanner_.Initialize(&stream);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000609 return DoParseProgram(source, in_global_context, strict_mode, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000610 } else {
611 GenericStringUC16CharacterStream stream(source, 0, source->length());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000612 scanner_.Initialize(&stream);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000613 return DoParseProgram(source, in_global_context, strict_mode, &zone_scope);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000614 }
615}
616
617
618FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
619 bool in_global_context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000620 StrictModeFlag strict_mode,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000621 ZoneScope* zone_scope) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622 ASSERT(target_stack_ == NULL);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000623 if (pre_data_ != NULL) pre_data_->Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624
625 // Compute the parsing mode.
626 mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY;
627 if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;
628
629 Scope::Type type =
630 in_global_context
631 ? Scope::GLOBAL_SCOPE
632 : Scope::EVAL_SCOPE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000633 Handle<String> no_name = isolate()->factory()->empty_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634
635 FunctionLiteral* result = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000636 { Scope* scope = NewScope(top_scope_, type, inside_with());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000637 LexicalScope lexical_scope(this, scope, isolate());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000638 if (strict_mode == kStrictMode) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000639 top_scope_->EnableStrictMode();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000640 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000641 ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642 bool ok = true;
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000643 int beg_loc = scanner().location().beg_pos;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000644 ParseSourceElements(body, Token::EOS, &ok);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000645 if (ok && top_scope_->is_strict_mode()) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000646 CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok);
647 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648 if (ok) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000649 result = new(zone()) FunctionLiteral(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000650 no_name,
651 top_scope_,
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000652 body,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000653 lexical_scope.materialized_literal_count(),
654 lexical_scope.expected_property_count(),
655 lexical_scope.only_simple_this_property_assignments(),
656 lexical_scope.this_property_assignments(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000657 0,
658 0,
659 source->length(),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000660 false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000661 } else if (stack_overflow_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000662 isolate()->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000663 }
664 }
665
666 // Make sure the target stack is empty.
667 ASSERT(target_stack_ == NULL);
668
669 // If there was a syntax error we have to get rid of the AST
670 // and it is not safe to do so before the scope has been deleted.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000671 if (result == NULL) zone_scope->DeleteOnExit();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000672 return result;
673}
674
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000675FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000676 ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000677 HistogramTimerScope timer(isolate()->counters()->parse_lazy());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000678 Handle<String> source(String::cast(script_->source()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000679 isolate()->counters()->total_parse_size()->Increment(source->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000681 Handle<SharedFunctionInfo> shared_info = info->shared_info();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000682 // Initialize parser state.
683 source->TryFlatten();
684 if (source->IsExternalTwoByteString()) {
685 ExternalTwoByteStringUC16CharacterStream stream(
686 Handle<ExternalTwoByteString>::cast(source),
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000687 shared_info->start_position(),
688 shared_info->end_position());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000689 FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
690 return result;
691 } else {
692 GenericStringUC16CharacterStream stream(source,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000693 shared_info->start_position(),
694 shared_info->end_position());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000695 FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
696 return result;
697 }
698}
699
700
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000701FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000702 UC16CharacterStream* source,
703 ZoneScope* zone_scope) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000704 Handle<SharedFunctionInfo> shared_info = info->shared_info();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000705 scanner_.Initialize(source);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000706 ASSERT(target_stack_ == NULL);
707
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000708 Handle<String> name(String::cast(shared_info->name()));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000709 fni_ = new(zone()) FuncNameInferrer();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000710 fni_->PushEnclosingName(name);
711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712 mode_ = PARSE_EAGERLY;
713
714 // Place holder for the result.
715 FunctionLiteral* result = NULL;
716
717 {
718 // Parse the function literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000719 Handle<String> no_name = isolate()->factory()->empty_symbol();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000720 Scope* scope = NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
721 if (!info->closure().is_null()) {
722 scope = Scope::DeserializeScopeChain(info, scope);
723 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000724 LexicalScope lexical_scope(this, scope, isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000725
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000726 if (shared_info->strict_mode()) {
727 top_scope_->EnableStrictMode();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000728 }
729
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000730 FunctionLiteralType type =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000731 shared_info->is_expression() ? EXPRESSION : DECLARATION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000732 bool ok = true;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000733 result = ParseFunctionLiteral(name,
734 false, // Strict mode name already checked.
735 RelocInfo::kNoPosition, type, &ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000736 // Make sure the results agree.
737 ASSERT(ok == (result != NULL));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000738 }
739
740 // Make sure the target stack is empty.
741 ASSERT(target_stack_ == NULL);
742
743 // If there was a stack overflow we have to get rid of AST and it is
744 // not safe to do before scope has been deleted.
745 if (result == NULL) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000746 zone_scope->DeleteOnExit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000747 if (stack_overflow_) isolate()->StackOverflow();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000748 } else {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000749 Handle<String> inferred_name(shared_info->inferred_name());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000750 result->set_inferred_name(inferred_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751 }
752 return result;
753}
754
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000755
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000756Handle<String> Parser::GetSymbol(bool* ok) {
757 int symbol_id = -1;
758 if (pre_data() != NULL) {
759 symbol_id = pre_data()->GetSymbolIdentifier();
760 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000761 return LookupSymbol(symbol_id);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000762}
763
764
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000765void Parser::ReportMessage(const char* type, Vector<const char*> args) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000766 Scanner::Location source_location = scanner().location();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000767 ReportMessageAt(source_location, type, args);
768}
769
770
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000771void Parser::ReportMessageAt(Scanner::Location source_location,
772 const char* type,
773 Vector<const char*> args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000774 MessageLocation location(script_,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000775 source_location.beg_pos,
776 source_location.end_pos);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000777 Factory* factory = isolate()->factory();
778 Handle<FixedArray> elements = factory->NewFixedArray(args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000779 for (int i = 0; i < args.length(); i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000780 Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000781 elements->set(i, *arg_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000782 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000783 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
784 Handle<Object> result = factory->NewSyntaxError(type, array);
785 isolate()->Throw(*result, &location);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000786}
787
788
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000789void Parser::ReportMessageAt(Scanner::Location source_location,
790 const char* type,
791 Vector<Handle<String> > args) {
792 MessageLocation location(script_,
793 source_location.beg_pos,
794 source_location.end_pos);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000795 Factory* factory = isolate()->factory();
796 Handle<FixedArray> elements = factory->NewFixedArray(args.length());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000797 for (int i = 0; i < args.length(); i++) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000798 elements->set(i, *args[i]);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000799 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000800 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
801 Handle<Object> result = factory->NewSyntaxError(type, array);
802 isolate()->Throw(*result, &location);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000803}
804
805
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000806// Base class containing common code for the different finder classes used by
807// the parser.
808class ParserFinder {
809 protected:
810 ParserFinder() {}
811 static Assignment* AsAssignment(Statement* stat) {
812 if (stat == NULL) return NULL;
813 ExpressionStatement* exp_stat = stat->AsExpressionStatement();
814 if (exp_stat == NULL) return NULL;
815 return exp_stat->expression()->AsAssignment();
816 }
817};
818
819
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000820// An InitializationBlockFinder finds and marks sequences of statements of the
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000821// form expr.a = ...; expr.b = ...; etc.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000822class InitializationBlockFinder : public ParserFinder {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000823 public:
824 InitializationBlockFinder()
825 : first_in_block_(NULL), last_in_block_(NULL), block_size_(0) {}
826
827 ~InitializationBlockFinder() {
828 if (InBlock()) EndBlock();
829 }
830
831 void Update(Statement* stat) {
832 Assignment* assignment = AsAssignment(stat);
833 if (InBlock()) {
834 if (BlockContinues(assignment)) {
835 UpdateBlock(assignment);
836 } else {
837 EndBlock();
838 }
839 }
840 if (!InBlock() && (assignment != NULL) &&
841 (assignment->op() == Token::ASSIGN)) {
842 StartBlock(assignment);
843 }
844 }
845
846 private:
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000847 // The minimum number of contiguous assignment that will
848 // be treated as an initialization block. Benchmarks show that
849 // the overhead exceeds the savings below this limit.
850 static const int kMinInitializationBlock = 3;
851
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000852 // Returns true if the expressions appear to denote the same object.
853 // In the context of initialization blocks, we only consider expressions
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000854 // of the form 'expr.x' or expr["x"].
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000855 static bool SameObject(Expression* e1, Expression* e2) {
856 VariableProxy* v1 = e1->AsVariableProxy();
857 VariableProxy* v2 = e2->AsVariableProxy();
858 if (v1 != NULL && v2 != NULL) {
859 return v1->name()->Equals(*v2->name());
860 }
861 Property* p1 = e1->AsProperty();
862 Property* p2 = e2->AsProperty();
863 if ((p1 == NULL) || (p2 == NULL)) return false;
864 Literal* key1 = p1->key()->AsLiteral();
865 Literal* key2 = p2->key()->AsLiteral();
866 if ((key1 == NULL) || (key2 == NULL)) return false;
867 if (!key1->handle()->IsString() || !key2->handle()->IsString()) {
868 return false;
869 }
870 String* name1 = String::cast(*key1->handle());
871 String* name2 = String::cast(*key2->handle());
872 if (!name1->Equals(name2)) return false;
873 return SameObject(p1->obj(), p2->obj());
874 }
875
876 // Returns true if the expressions appear to denote different properties
877 // of the same object.
878 static bool PropertyOfSameObject(Expression* e1, Expression* e2) {
879 Property* p1 = e1->AsProperty();
880 Property* p2 = e2->AsProperty();
881 if ((p1 == NULL) || (p2 == NULL)) return false;
882 return SameObject(p1->obj(), p2->obj());
883 }
884
885 bool BlockContinues(Assignment* assignment) {
886 if ((assignment == NULL) || (first_in_block_ == NULL)) return false;
887 if (assignment->op() != Token::ASSIGN) return false;
888 return PropertyOfSameObject(first_in_block_->target(),
889 assignment->target());
890 }
891
892 void StartBlock(Assignment* assignment) {
893 first_in_block_ = assignment;
894 last_in_block_ = assignment;
895 block_size_ = 1;
896 }
897
898 void UpdateBlock(Assignment* assignment) {
899 last_in_block_ = assignment;
900 ++block_size_;
901 }
902
903 void EndBlock() {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000904 if (block_size_ >= kMinInitializationBlock) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000905 first_in_block_->mark_block_start();
906 last_in_block_->mark_block_end();
907 }
908 last_in_block_ = first_in_block_ = NULL;
909 block_size_ = 0;
910 }
911
912 bool InBlock() { return first_in_block_ != NULL; }
913
914 Assignment* first_in_block_;
915 Assignment* last_in_block_;
916 int block_size_;
917
918 DISALLOW_COPY_AND_ASSIGN(InitializationBlockFinder);
919};
920
921
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000922// A ThisNamedPropertyAssigmentFinder finds and marks statements of the form
923// this.x = ...;, where x is a named property. It also determines whether a
924// function contains only assignments of this type.
925class ThisNamedPropertyAssigmentFinder : public ParserFinder {
926 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 explicit ThisNamedPropertyAssigmentFinder(Isolate* isolate)
928 : isolate_(isolate),
929 only_simple_this_property_assignments_(true),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000930 names_(NULL),
931 assigned_arguments_(NULL),
932 assigned_constants_(NULL) {}
933
934 void Update(Scope* scope, Statement* stat) {
ager@chromium.orgb9a15452009-11-11 09:55:05 +0000935 // Bail out if function already has property assignment that are
936 // not simple this property assignments.
937 if (!only_simple_this_property_assignments_) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000938 return;
939 }
940
941 // Check whether this statement is of the form this.x = ...;
942 Assignment* assignment = AsAssignment(stat);
943 if (IsThisPropertyAssignment(assignment)) {
944 HandleThisPropertyAssignment(scope, assignment);
945 } else {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000946 only_simple_this_property_assignments_ = false;
947 }
948 }
949
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000950 // Returns whether only statements of the form this.x = y; where y is either a
951 // constant or a function argument was encountered.
952 bool only_simple_this_property_assignments() {
953 return only_simple_this_property_assignments_;
954 }
955
956 // Returns a fixed array containing three elements for each assignment of the
957 // form this.x = y;
958 Handle<FixedArray> GetThisPropertyAssignments() {
959 if (names_ == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000960 return isolate_->factory()->empty_fixed_array();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000961 }
962 ASSERT(names_ != NULL);
963 ASSERT(assigned_arguments_ != NULL);
964 ASSERT_EQ(names_->length(), assigned_arguments_->length());
965 ASSERT_EQ(names_->length(), assigned_constants_->length());
966 Handle<FixedArray> assignments =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000967 isolate_->factory()->NewFixedArray(names_->length() * 3);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000968 for (int i = 0; i < names_->length(); i++) {
969 assignments->set(i * 3, *names_->at(i));
970 assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_->at(i)));
971 assignments->set(i * 3 + 2, *assigned_constants_->at(i));
972 }
973 return assignments;
974 }
975
976 private:
977 bool IsThisPropertyAssignment(Assignment* assignment) {
978 if (assignment != NULL) {
979 Property* property = assignment->target()->AsProperty();
980 return assignment->op() == Token::ASSIGN
981 && property != NULL
982 && property->obj()->AsVariableProxy() != NULL
983 && property->obj()->AsVariableProxy()->is_this();
984 }
985 return false;
986 }
987
988 void HandleThisPropertyAssignment(Scope* scope, Assignment* assignment) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000989 // Check that the property assigned to is a named property, which is not
990 // __proto__.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000991 Property* property = assignment->target()->AsProperty();
992 ASSERT(property != NULL);
993 Literal* literal = property->key()->AsLiteral();
994 uint32_t dummy;
995 if (literal != NULL &&
996 literal->handle()->IsString() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000997 !String::cast(*(literal->handle()))->Equals(
998 isolate_->heap()->Proto_symbol()) &&
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000999 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
1000 Handle<String> key = Handle<String>::cast(literal->handle());
1001
1002 // Check whether the value assigned is either a constant or matches the
1003 // name of one of the arguments to the function.
1004 if (assignment->value()->AsLiteral() != NULL) {
1005 // Constant assigned.
1006 Literal* literal = assignment->value()->AsLiteral();
1007 AssignmentFromConstant(key, literal->handle());
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001008 return;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001009 } else if (assignment->value()->AsVariableProxy() != NULL) {
1010 // Variable assigned.
1011 Handle<String> name =
1012 assignment->value()->AsVariableProxy()->name();
1013 // Check whether the variable assigned matches an argument name.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001014 for (int i = 0; i < scope->num_parameters(); i++) {
1015 if (*scope->parameter(i)->name() == *name) {
1016 // Assigned from function argument.
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001017 AssignmentFromParameter(key, i);
1018 return;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001019 }
1020 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001021 }
1022 }
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001023 // It is not a simple "this.x = value;" assignment with a constant
1024 // or parameter value.
1025 AssignmentFromSomethingElse();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001026 }
1027
1028 void AssignmentFromParameter(Handle<String> name, int index) {
1029 EnsureAllocation();
1030 names_->Add(name);
1031 assigned_arguments_->Add(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 assigned_constants_->Add(isolate_->factory()->undefined_value());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001033 }
1034
1035 void AssignmentFromConstant(Handle<String> name, Handle<Object> value) {
1036 EnsureAllocation();
1037 names_->Add(name);
1038 assigned_arguments_->Add(-1);
1039 assigned_constants_->Add(value);
1040 }
1041
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001042 void AssignmentFromSomethingElse() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001043 // The this assignment is not a simple one.
1044 only_simple_this_property_assignments_ = false;
1045 }
1046
1047 void EnsureAllocation() {
1048 if (names_ == NULL) {
1049 ASSERT(assigned_arguments_ == NULL);
1050 ASSERT(assigned_constants_ == NULL);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001051 Zone* zone = isolate_->zone();
1052 names_ = new(zone) ZoneStringList(4);
1053 assigned_arguments_ = new(zone) ZoneList<int>(4);
1054 assigned_constants_ = new(zone) ZoneObjectList(4);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001055 }
1056 }
1057
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001058 Isolate* isolate_;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001059 bool only_simple_this_property_assignments_;
1060 ZoneStringList* names_;
1061 ZoneList<int>* assigned_arguments_;
1062 ZoneObjectList* assigned_constants_;
1063};
1064
1065
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001066void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001067 int end_token,
1068 bool* ok) {
1069 // SourceElements ::
1070 // (Statement)* <end_token>
1071
1072 // Allocate a target stack to use for this set of source
1073 // elements. This way, all scripts and functions get their own
1074 // target stack thus avoiding illegal breaks and continues across
1075 // functions.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001076 TargetScope scope(&this->target_stack_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077
1078 ASSERT(processor != NULL);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001079 InitializationBlockFinder block_finder;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001080 ThisNamedPropertyAssigmentFinder this_property_assignment_finder(isolate());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001081 bool directive_prologue = true; // Parsing directive prologue.
1082
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083 while (peek() != end_token) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001084 if (directive_prologue && peek() != Token::STRING) {
1085 directive_prologue = false;
1086 }
1087
1088 Scanner::Location token_loc = scanner().peek_location();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001089
1090 Statement* stat;
1091 if (peek() == Token::FUNCTION) {
1092 // FunctionDeclaration is only allowed in the context of SourceElements
1093 // (Ecma 262 5th Edition, clause 14):
1094 // SourceElement:
1095 // Statement
1096 // FunctionDeclaration
1097 // Common language extension is to allow function declaration in place
1098 // of any statement. This language extension is disabled in strict mode.
1099 stat = ParseFunctionDeclaration(CHECK_OK);
1100 } else {
1101 stat = ParseStatement(NULL, CHECK_OK);
1102 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001103
1104 if (stat == NULL || stat->IsEmpty()) {
1105 directive_prologue = false; // End of directive prologue.
1106 continue;
1107 }
1108
1109 if (directive_prologue) {
1110 // A shot at a directive.
1111 ExpressionStatement *e_stat;
1112 Literal *literal;
1113 // Still processing directive prologue?
1114 if ((e_stat = stat->AsExpressionStatement()) != NULL &&
1115 (literal = e_stat->expression()->AsLiteral()) != NULL &&
1116 literal->handle()->IsString()) {
1117 Handle<String> directive = Handle<String>::cast(literal->handle());
1118
1119 // Check "use strict" directive (ES5 14.1).
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001120 if (!top_scope_->is_strict_mode() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001121 directive->Equals(isolate()->heap()->use_strict()) &&
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001122 token_loc.end_pos - token_loc.beg_pos ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001123 isolate()->heap()->use_strict()->length() + 2) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001124 top_scope_->EnableStrictMode();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001125 // "use strict" is the only directive for now.
1126 directive_prologue = false;
1127 }
1128 } else {
1129 // End of the directive prologue.
1130 directive_prologue = false;
1131 }
1132 }
1133
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001134 // We find and mark the initialization blocks on top level code only.
1135 // This is because the optimization prevents reuse of the map transitions,
1136 // so it should be used only for code that will only be run once.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001137 if (top_scope_->is_global_scope()) {
1138 block_finder.Update(stat);
1139 }
1140 // Find and mark all assignments to named properties in this (this.x =)
1141 if (top_scope_->is_function_scope()) {
1142 this_property_assignment_finder.Update(top_scope_, stat);
1143 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001144 processor->Add(stat);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001146
1147 // Propagate the collected information on this property assignments.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001148 if (top_scope_->is_function_scope()) {
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001149 bool only_simple_this_property_assignments =
ager@chromium.org5c838252010-02-19 08:53:10 +00001150 this_property_assignment_finder.only_simple_this_property_assignments()
1151 && top_scope_->declarations()->length() == 0;
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001152 if (only_simple_this_property_assignments) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001153 lexical_scope_->SetThisPropertyAssignmentInfo(
ager@chromium.orgb9a15452009-11-11 09:55:05 +00001154 only_simple_this_property_assignments,
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001155 this_property_assignment_finder.GetThisPropertyAssignments());
1156 }
1157 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001158 return 0;
1159}
1160
1161
1162Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
1163 // Statement ::
1164 // Block
1165 // VariableStatement
1166 // EmptyStatement
1167 // ExpressionStatement
1168 // IfStatement
1169 // IterationStatement
1170 // ContinueStatement
1171 // BreakStatement
1172 // ReturnStatement
1173 // WithStatement
1174 // LabelledStatement
1175 // SwitchStatement
1176 // ThrowStatement
1177 // TryStatement
1178 // DebuggerStatement
1179
1180 // Note: Since labels can only be used by 'break' and 'continue'
1181 // statements, which themselves are only valid within blocks,
1182 // iterations or 'switch' statements (i.e., BreakableStatements),
1183 // labels can be simply ignored in all other cases; except for
ager@chromium.org32912102009-01-16 10:38:43 +00001184 // trivial labeled break statements 'label: break label' which is
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185 // parsed into an empty statement.
1186
1187 // Keep the source position of the statement
1188 int statement_pos = scanner().peek_location().beg_pos;
1189 Statement* stmt = NULL;
1190 switch (peek()) {
1191 case Token::LBRACE:
1192 return ParseBlock(labels, ok);
1193
1194 case Token::CONST: // fall through
1195 case Token::VAR:
1196 stmt = ParseVariableStatement(ok);
1197 break;
1198
1199 case Token::SEMICOLON:
1200 Next();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001201 return EmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202
1203 case Token::IF:
1204 stmt = ParseIfStatement(labels, ok);
1205 break;
1206
1207 case Token::DO:
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001208 stmt = ParseDoWhileStatement(labels, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209 break;
1210
1211 case Token::WHILE:
1212 stmt = ParseWhileStatement(labels, ok);
1213 break;
1214
1215 case Token::FOR:
1216 stmt = ParseForStatement(labels, ok);
1217 break;
1218
1219 case Token::CONTINUE:
1220 stmt = ParseContinueStatement(ok);
1221 break;
1222
1223 case Token::BREAK:
1224 stmt = ParseBreakStatement(labels, ok);
1225 break;
1226
1227 case Token::RETURN:
1228 stmt = ParseReturnStatement(ok);
1229 break;
1230
1231 case Token::WITH:
1232 stmt = ParseWithStatement(labels, ok);
1233 break;
1234
1235 case Token::SWITCH:
1236 stmt = ParseSwitchStatement(labels, ok);
1237 break;
1238
1239 case Token::THROW:
1240 stmt = ParseThrowStatement(ok);
1241 break;
1242
1243 case Token::TRY: {
1244 // NOTE: It is somewhat complicated to have labels on
1245 // try-statements. When breaking out of a try-finally statement,
1246 // one must take great care not to treat it as a
1247 // fall-through. It is much easier just to wrap the entire
1248 // try-statement in a statement block and put the labels there
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001249 Block* result = new(zone()) Block(labels, 1, false);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001250 Target target(&this->target_stack_, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 TryStatement* statement = ParseTryStatement(CHECK_OK);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001252 if (statement) {
1253 statement->set_statement_pos(statement_pos);
1254 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 if (result) result->AddStatement(statement);
1256 return result;
1257 }
1258
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001259 case Token::FUNCTION: {
1260 // In strict mode, FunctionDeclaration is only allowed in the context
1261 // of SourceElements.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001262 if (top_scope_->is_strict_mode()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001263 ReportMessageAt(scanner().peek_location(), "strict_function",
1264 Vector<const char*>::empty());
1265 *ok = false;
1266 return NULL;
1267 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268 return ParseFunctionDeclaration(ok);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001269 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270
1271 case Token::NATIVE:
1272 return ParseNativeDeclaration(ok);
1273
1274 case Token::DEBUGGER:
1275 stmt = ParseDebuggerStatement(ok);
1276 break;
1277
1278 default:
1279 stmt = ParseExpressionOrLabelledStatement(labels, ok);
1280 }
1281
1282 // Store the source position of the statement
1283 if (stmt != NULL) stmt->set_statement_pos(statement_pos);
1284 return stmt;
1285}
1286
1287
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001288VariableProxy* Parser::Declare(Handle<String> name,
1289 Variable::Mode mode,
1290 FunctionLiteral* fun,
1291 bool resolve,
1292 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 Variable* var = NULL;
1294 // If we are inside a function, a declaration of a variable
1295 // is a truly local variable, and the scope of the variable
1296 // is always the function scope.
1297
1298 // If a function scope exists, then we can statically declare this
1299 // variable and also set its mode. In any case, a Declaration node
1300 // will be added to the scope so that the declaration can be added
1301 // to the corresponding activation frame at runtime if necessary.
1302 // For instance declarations inside an eval scope need to be added
1303 // to the calling function context.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001304 // Similarly, strict mode eval scope does not leak variable declarations to
1305 // the caller's scope so we declare all locals, too.
1306 if (top_scope_->is_function_scope() ||
1307 top_scope_->is_strict_mode_eval_scope()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001308 // Declare the variable in the function scope.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001309 var = top_scope_->LocalLookup(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 if (var == NULL) {
1311 // Declare the name.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001312 var = top_scope_->DeclareLocal(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313 } else {
1314 // The name was declared before; check for conflicting
1315 // re-declarations. If the previous declaration was a const or the
1316 // current declaration is a const then we have a conflict. There is
1317 // similar code in runtime.cc in the Declare functions.
1318 if ((mode == Variable::CONST) || (var->mode() == Variable::CONST)) {
1319 // We only have vars and consts in declarations.
1320 ASSERT(var->mode() == Variable::VAR ||
1321 var->mode() == Variable::CONST);
1322 const char* type = (var->mode() == Variable::VAR) ? "var" : "const";
1323 Handle<String> type_string =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001324 isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 Expression* expression =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 NewThrowTypeError(isolate()->factory()->redeclaration_symbol(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 type_string, name);
1328 top_scope_->SetIllegalRedeclaration(expression);
1329 }
1330 }
1331 }
1332
1333 // We add a declaration node for every declaration. The compiler
1334 // will only generate code if necessary. In particular, declarations
1335 // for inner local variables that do not represent functions won't
1336 // result in any generated code.
1337 //
1338 // Note that we always add an unresolved proxy even if it's not
1339 // used, simply because we don't know in this method (w/o extra
1340 // parameters) if the proxy is needed or not. The proxy will be
1341 // bound during variable resolution time unless it was pre-bound
1342 // below.
1343 //
1344 // WARNING: This will lead to multiple declaration nodes for the
1345 // same variable if it is declared several times. This is not a
1346 // semantic issue as long as we keep the source order, but it may be
1347 // a performance issue since it may lead to repeated
1348 // Runtime::DeclareContextSlot() calls.
1349 VariableProxy* proxy = top_scope_->NewUnresolved(name, inside_with());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001350 top_scope_->AddDeclaration(new(zone()) Declaration(proxy, mode, fun));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351
1352 // For global const variables we bind the proxy to a variable.
1353 if (mode == Variable::CONST && top_scope_->is_global_scope()) {
1354 ASSERT(resolve); // should be set by all callers
ager@chromium.org3e875802009-06-29 08:26:34 +00001355 Variable::Kind kind = Variable::NORMAL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001356 var = new(zone()) Variable(top_scope_, name, Variable::CONST, true, kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357 }
1358
1359 // If requested and we have a local variable, bind the proxy to the variable
1360 // at parse-time. This is used for functions (and consts) declared inside
1361 // statements: the corresponding function (or const) variable must be in the
1362 // function scope and not a statement-local scope, e.g. as provided with a
1363 // 'with' statement:
1364 //
1365 // with (obj) {
1366 // function f() {}
1367 // }
1368 //
1369 // which is translated into:
1370 //
1371 // with (obj) {
1372 // // in this case this is not: 'var f; f = function () {};'
1373 // var f = function () {};
1374 // }
1375 //
1376 // Note that if 'f' is accessed from inside the 'with' statement, it
1377 // will be allocated in the context (because we must be able to look
1378 // it up dynamically) but it will also be accessed statically, i.e.,
1379 // with a context slot index and a context chain length for this
1380 // initialization code. Thus, inside the 'with' statement, we need
1381 // both access to the static and the dynamic context chain; the
1382 // runtime needs to provide both.
1383 if (resolve && var != NULL) proxy->BindTo(var);
1384
1385 return proxy;
1386}
1387
1388
1389// Language extension which is only enabled for source files loaded
1390// through the API's extension mechanism. A native function
1391// declaration is resolved by looking up the function through a
1392// callback provided by the extension.
1393Statement* Parser::ParseNativeDeclaration(bool* ok) {
1394 if (extension_ == NULL) {
1395 ReportUnexpectedToken(Token::NATIVE);
1396 *ok = false;
1397 return NULL;
1398 }
1399
1400 Expect(Token::NATIVE, CHECK_OK);
1401 Expect(Token::FUNCTION, CHECK_OK);
1402 Handle<String> name = ParseIdentifier(CHECK_OK);
1403 Expect(Token::LPAREN, CHECK_OK);
1404 bool done = (peek() == Token::RPAREN);
1405 while (!done) {
1406 ParseIdentifier(CHECK_OK);
1407 done = (peek() == Token::RPAREN);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001408 if (!done) {
1409 Expect(Token::COMMA, CHECK_OK);
1410 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411 }
1412 Expect(Token::RPAREN, CHECK_OK);
1413 Expect(Token::SEMICOLON, CHECK_OK);
1414
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 // Make sure that the function containing the native declaration
1416 // isn't lazily compiled. The extension structures are only
1417 // accessible while parsing the first time not when reparsing
1418 // because of lazy compilation.
1419 top_scope_->ForceEagerCompilation();
1420
1421 // Compute the function template for the native function.
1422 v8::Handle<v8::FunctionTemplate> fun_template =
1423 extension_->GetNativeFunction(v8::Utils::ToLocal(name));
1424 ASSERT(!fun_template.IsEmpty());
1425
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001426 // Instantiate the function and create a shared function info from it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001427 Handle<JSFunction> fun = Utils::OpenHandle(*fun_template->GetFunction());
1428 const int literals = fun->NumberOfLiterals();
1429 Handle<Code> code = Handle<Code>(fun->shared()->code());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001430 Handle<Code> construct_stub = Handle<Code>(fun->shared()->construct_stub());
ager@chromium.orgb5737492010-07-15 09:29:43 +00001431 Handle<SharedFunctionInfo> shared =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001432 isolate()->factory()->NewSharedFunctionInfo(name, literals, code,
ager@chromium.orgb5737492010-07-15 09:29:43 +00001433 Handle<SerializedScopeInfo>(fun->shared()->scope_info()));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001434 shared->set_construct_stub(*construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001436 // Copy the function data to the shared function info.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001437 shared->set_function_data(fun->shared()->function_data());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001438 int parameters = fun->shared()->formal_parameter_count();
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001439 shared->set_formal_parameter_count(parameters);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440
1441 // TODO(1240846): It's weird that native function declarations are
1442 // introduced dynamically when we meet their declarations, whereas
1443 // other functions are setup when entering the surrounding scope.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001444 SharedFunctionInfoLiteral* lit =
1445 new(zone()) SharedFunctionInfoLiteral(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001446 VariableProxy* var = Declare(name, Variable::VAR, NULL, true, CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001447 return new(zone()) ExpressionStatement(new(zone()) Assignment(
1448 Token::INIT_VAR, var, lit, RelocInfo::kNoPosition));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449}
1450
1451
1452Statement* Parser::ParseFunctionDeclaration(bool* ok) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001453 // FunctionDeclaration ::
1454 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001455 Expect(Token::FUNCTION, CHECK_OK);
1456 int function_token_position = scanner().location().beg_pos;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001457 bool is_reserved = false;
1458 Handle<String> name = ParseIdentifierOrReservedWord(&is_reserved, CHECK_OK);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001459 FunctionLiteral* fun = ParseFunctionLiteral(name,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001460 is_reserved,
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001461 function_token_position,
1462 DECLARATION,
1463 CHECK_OK);
1464 // Even if we're not at the top-level of the global or a function
1465 // scope, we treat is as such and introduce the function with it's
1466 // initial value upon entering the corresponding scope.
1467 Declare(name, Variable::VAR, fun, true, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001468 return EmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469}
1470
1471
1472Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
1473 // Block ::
1474 // '{' Statement* '}'
1475
1476 // Note that a Block does not introduce a new execution scope!
1477 // (ECMA-262, 3rd, 12.2)
1478 //
1479 // Construct block expecting 16 statements.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001480 Block* result = new(zone()) Block(labels, 16, false);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001481 Target target(&this->target_stack_, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482 Expect(Token::LBRACE, CHECK_OK);
1483 while (peek() != Token::RBRACE) {
1484 Statement* stat = ParseStatement(NULL, CHECK_OK);
1485 if (stat && !stat->IsEmpty()) result->AddStatement(stat);
1486 }
1487 Expect(Token::RBRACE, CHECK_OK);
1488 return result;
1489}
1490
1491
1492Block* Parser::ParseVariableStatement(bool* ok) {
1493 // VariableStatement ::
1494 // VariableDeclarations ';'
1495
1496 Expression* dummy; // to satisfy the ParseVariableDeclarations() signature
1497 Block* result = ParseVariableDeclarations(true, &dummy, CHECK_OK);
1498 ExpectSemicolon(CHECK_OK);
1499 return result;
1500}
1501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001502
1503bool Parser::IsEvalOrArguments(Handle<String> string) {
1504 return string.is_identical_to(isolate()->factory()->eval_symbol()) ||
1505 string.is_identical_to(isolate()->factory()->arguments_symbol());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001506}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001508
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509// If the variable declaration declares exactly one non-const
1510// variable, then *var is set to that variable. In all other cases,
1511// *var is untouched; in particular, it is the caller's responsibility
1512// to initialize it properly. This mechanism is used for the parsing
1513// of 'for-in' loops.
1514Block* Parser::ParseVariableDeclarations(bool accept_IN,
1515 Expression** var,
1516 bool* ok) {
1517 // VariableDeclarations ::
1518 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
1519
1520 Variable::Mode mode = Variable::VAR;
1521 bool is_const = false;
1522 if (peek() == Token::VAR) {
1523 Consume(Token::VAR);
1524 } else if (peek() == Token::CONST) {
1525 Consume(Token::CONST);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001526 if (top_scope_->is_strict_mode()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001527 ReportMessage("strict_const", Vector<const char*>::empty());
1528 *ok = false;
1529 return NULL;
1530 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 mode = Variable::CONST;
1532 is_const = true;
1533 } else {
1534 UNREACHABLE(); // by current callers
1535 }
1536
1537 // The scope of a variable/const declared anywhere inside a function
1538 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
1539 // transform a source-level variable/const declaration into a (Function)
1540 // Scope declaration, and rewrite the source-level initialization into an
1541 // assignment statement. We use a block to collect multiple assignments.
1542 //
1543 // We mark the block as initializer block because we don't want the
1544 // rewriter to add a '.result' assignment to such a block (to get compliant
1545 // behavior for code such as print(eval('var x = 7')), and for cosmetic
1546 // reasons when pretty-printing. Also, unless an assignment (initialization)
1547 // is inside an initializer block, it is ignored.
1548 //
1549 // Create new block with one expected declaration.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001550 Block* block = new(zone()) Block(NULL, 1, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551 VariableProxy* last_var = NULL; // the last variable declared
1552 int nvars = 0; // the number of variables declared
1553 do {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001554 if (fni_ != NULL) fni_->Enter();
1555
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 // Parse variable name.
1557 if (nvars > 0) Consume(Token::COMMA);
1558 Handle<String> name = ParseIdentifier(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001559 if (fni_ != NULL) fni_->PushVariableName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001561 // Strict mode variables may not be named eval or arguments
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001562 if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001563 ReportMessage("strict_var_name", Vector<const char*>::empty());
1564 *ok = false;
1565 return NULL;
1566 }
1567
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 // Declare variable.
1569 // Note that we *always* must treat the initial value via a separate init
1570 // assignment for variables and constants because the value must be assigned
1571 // when the variable is encountered in the source. But the variable/constant
1572 // is declared (and set to 'undefined') upon entering the function within
1573 // which the variable or constant is declared. Only function variables have
1574 // an initial value in the declaration (because they are initialized upon
1575 // entering the function).
1576 //
1577 // If we have a const declaration, in an inner scope, the proxy is always
1578 // bound to the declared variable (independent of possibly surrounding with
1579 // statements).
1580 last_var = Declare(name, mode, NULL,
1581 is_const /* always bound for CONST! */,
1582 CHECK_OK);
1583 nvars++;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001584 if (top_scope_->num_var_or_const() > kMaxNumFunctionLocals) {
1585 ReportMessageAt(scanner().location(), "too_many_variables",
1586 Vector<const char*>::empty());
1587 *ok = false;
1588 return NULL;
1589 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590
1591 // Parse initialization expression if present and/or needed. A
1592 // declaration of the form:
1593 //
1594 // var v = x;
1595 //
1596 // is syntactic sugar for:
1597 //
1598 // var v; v = x;
1599 //
1600 // In particular, we need to re-lookup 'v' as it may be a
1601 // different 'v' than the 'v' in the declaration (if we are inside
1602 // a 'with' statement that makes a object property with name 'v'
1603 // visible).
1604 //
1605 // However, note that const declarations are different! A const
1606 // declaration of the form:
1607 //
1608 // const c = x;
1609 //
1610 // is *not* syntactic sugar for:
1611 //
1612 // const c; c = x;
1613 //
1614 // The "variable" c initialized to x is the same as the declared
1615 // one - there is no re-lookup (see the last parameter of the
1616 // Declare() call above).
1617
1618 Expression* value = NULL;
1619 int position = -1;
1620 if (peek() == Token::ASSIGN) {
1621 Expect(Token::ASSIGN, CHECK_OK);
1622 position = scanner().location().beg_pos;
1623 value = ParseAssignmentExpression(accept_IN, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001624 // Don't infer if it is "a = function(){...}();"-like expression.
1625 if (fni_ != NULL && value->AsCall() == NULL) fni_->Infer();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 }
1627
1628 // Make sure that 'const c' actually initializes 'c' to undefined
1629 // even though it seems like a stupid thing to do.
1630 if (value == NULL && is_const) {
1631 value = GetLiteralUndefined();
1632 }
1633
1634 // Global variable declarations must be compiled in a specific
1635 // way. When the script containing the global variable declaration
1636 // is entered, the global variable must be declared, so that if it
1637 // doesn't exist (not even in a prototype of the global object) it
1638 // gets created with an initial undefined value. This is handled
1639 // by the declarations part of the function representing the
1640 // top-level global code; see Runtime::DeclareGlobalVariable. If
1641 // it already exists (in the object or in a prototype), it is
1642 // *not* touched until the variable declaration statement is
1643 // executed.
1644 //
1645 // Executing the variable declaration statement will always
1646 // guarantee to give the global object a "local" variable; a
1647 // variable defined in the global object and not in any
1648 // prototype. This way, global variable declarations can shadow
1649 // properties in the prototype chain, but only after the variable
1650 // declaration statement has been executed. This is important in
1651 // browsers where the global object (window) has lots of
1652 // properties defined in prototype objects.
1653
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001654 if (top_scope_->is_global_scope()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001655 // Compute the arguments for the runtime call.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001656 ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001657 // We have at least 1 parameter.
1658 arguments->Add(new(zone()) Literal(name));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001659 CallRuntime* initialize;
1660
1661 if (is_const) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001662 arguments->Add(value);
1663 value = NULL; // zap the value to avoid the unnecessary assignment
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001664
1665 // Construct the call to Runtime_InitializeConstGlobal
1666 // and add it to the initialization statement block.
1667 // Note that the function does different things depending on
1668 // the number of arguments (1 or 2).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669 initialize =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001670 new(zone()) CallRuntime(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001671 isolate()->factory()->InitializeConstGlobal_symbol(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001672 Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
1673 arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001674 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001675 // Add strict mode.
1676 // We may want to pass singleton to avoid Literal allocations.
1677 arguments->Add(NewNumberLiteral(
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001678 top_scope_->is_strict_mode() ? kStrictMode : kNonStrictMode));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001679
1680 // Be careful not to assign a value to the global variable if
1681 // we're in a with. The initialization value should not
1682 // necessarily be stored in the global object in that case,
1683 // which is why we need to generate a separate assignment node.
1684 if (value != NULL && !inside_with()) {
1685 arguments->Add(value);
1686 value = NULL; // zap the value to avoid the unnecessary assignment
1687 }
1688
1689 // Construct the call to Runtime_InitializeVarGlobal
1690 // and add it to the initialization statement block.
1691 // Note that the function does different things depending on
1692 // the number of arguments (2 or 3).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001693 initialize =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001694 new(zone()) CallRuntime(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001695 isolate()->factory()->InitializeVarGlobal_symbol(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001696 Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
1697 arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001698 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001700 block->AddStatement(new(zone()) ExpressionStatement(initialize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001701 }
1702
1703 // Add an assignment node to the initialization statement block if
1704 // we still have a pending initialization value. We must distinguish
1705 // between variables and constants: Variable initializations are simply
1706 // assignments (with all the consequences if they are inside a 'with'
1707 // statement - they may change a 'with' object property). Constant
1708 // initializations always assign to the declared constant which is
1709 // always at the function scope level. This is only relevant for
1710 // dynamically looked-up variables and constants (the start context
1711 // for constant lookups is always the function context, while it is
1712 // the top context for variables). Sigh...
1713 if (value != NULL) {
1714 Token::Value op = (is_const ? Token::INIT_CONST : Token::INIT_VAR);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001715 Assignment* assignment =
1716 new(zone()) Assignment(op, last_var, value, position);
1717 if (block) {
1718 block->AddStatement(new(zone()) ExpressionStatement(assignment));
1719 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001720 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001721
1722 if (fni_ != NULL) fni_->Leave();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723 } while (peek() == Token::COMMA);
1724
1725 if (!is_const && nvars == 1) {
1726 // We have a single, non-const variable.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001727 ASSERT(last_var != NULL);
1728 *var = last_var;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001729 }
1730
1731 return block;
1732}
1733
1734
1735static bool ContainsLabel(ZoneStringList* labels, Handle<String> label) {
1736 ASSERT(!label.is_null());
1737 if (labels != NULL)
1738 for (int i = labels->length(); i-- > 0; )
1739 if (labels->at(i).is_identical_to(label))
1740 return true;
1741
1742 return false;
1743}
1744
1745
1746Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
1747 bool* ok) {
1748 // ExpressionStatement | LabelledStatement ::
1749 // Expression ';'
1750 // Identifier ':' Statement
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001751 bool starts_with_idenfifier = peek_any_identifier();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001752 Expression* expr = ParseExpression(true, CHECK_OK);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001753 if (peek() == Token::COLON && starts_with_idenfifier && expr &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001754 expr->AsVariableProxy() != NULL &&
1755 !expr->AsVariableProxy()->is_this()) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001756 // Expression is a single identifier, and not, e.g., a parenthesized
1757 // identifier.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001758 VariableProxy* var = expr->AsVariableProxy();
1759 Handle<String> label = var->name();
1760 // TODO(1240780): We don't check for redeclaration of labels
1761 // during preparsing since keeping track of the set of active
1762 // labels requires nontrivial changes to the way scopes are
1763 // structured. However, these are probably changes we want to
1764 // make later anyway so we should go back and fix this then.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001765 if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
1766 SmartPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
1767 const char* elms[2] = { "Label", *c_string };
1768 Vector<const char*> args(elms, 2);
1769 ReportMessage("redeclaration", args);
1770 *ok = false;
1771 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00001773 if (labels == NULL) labels = new(zone()) ZoneStringList(4);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001774 labels->Add(label);
1775 // Remove the "ghost" variable that turned out to be a label
1776 // from the top scope. This way, we don't try to resolve it
1777 // during the scope processing.
1778 top_scope_->RemoveUnresolved(var);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001779 Expect(Token::COLON, CHECK_OK);
1780 return ParseStatement(labels, ok);
1781 }
1782
1783 // Parsed expression statement.
1784 ExpectSemicolon(CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001785 return new(zone()) ExpressionStatement(expr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001786}
1787
1788
1789IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) {
1790 // IfStatement ::
1791 // 'if' '(' Expression ')' Statement ('else' Statement)?
1792
1793 Expect(Token::IF, CHECK_OK);
1794 Expect(Token::LPAREN, CHECK_OK);
1795 Expression* condition = ParseExpression(true, CHECK_OK);
1796 Expect(Token::RPAREN, CHECK_OK);
1797 Statement* then_statement = ParseStatement(labels, CHECK_OK);
1798 Statement* else_statement = NULL;
1799 if (peek() == Token::ELSE) {
1800 Next();
1801 else_statement = ParseStatement(labels, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001802 } else {
1803 else_statement = EmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001805 return new(zone()) IfStatement(condition, then_statement, else_statement);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001806}
1807
1808
1809Statement* Parser::ParseContinueStatement(bool* ok) {
1810 // ContinueStatement ::
1811 // 'continue' Identifier? ';'
1812
1813 Expect(Token::CONTINUE, CHECK_OK);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001814 Handle<String> label = Handle<String>::null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001815 Token::Value tok = peek();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001816 if (!scanner().has_line_terminator_before_next() &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001817 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001818 label = ParseIdentifier(CHECK_OK);
1819 }
1820 IterationStatement* target = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001821 target = LookupContinueTarget(label, CHECK_OK);
1822 if (target == NULL) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001823 // Illegal continue statement.
1824 const char* message = "illegal_continue";
1825 Vector<Handle<String> > args;
1826 if (!label.is_null()) {
1827 message = "unknown_label";
1828 args = Vector<Handle<String> >(&label, 1);
1829 }
1830 ReportMessageAt(scanner().location(), message, args);
1831 *ok = false;
1832 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833 }
1834 ExpectSemicolon(CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001835 return new(zone()) ContinueStatement(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001836}
1837
1838
1839Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
1840 // BreakStatement ::
1841 // 'break' Identifier? ';'
1842
1843 Expect(Token::BREAK, CHECK_OK);
1844 Handle<String> label;
1845 Token::Value tok = peek();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001846 if (!scanner().has_line_terminator_before_next() &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001847 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001848 label = ParseIdentifier(CHECK_OK);
1849 }
ager@chromium.org32912102009-01-16 10:38:43 +00001850 // Parse labeled break statements that target themselves into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001851 // empty statements, e.g. 'l1: l2: l3: break l2;'
1852 if (!label.is_null() && ContainsLabel(labels, label)) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001853 return EmptyStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001854 }
1855 BreakableStatement* target = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001856 target = LookupBreakTarget(label, CHECK_OK);
1857 if (target == NULL) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001858 // Illegal break statement.
1859 const char* message = "illegal_break";
1860 Vector<Handle<String> > args;
1861 if (!label.is_null()) {
1862 message = "unknown_label";
1863 args = Vector<Handle<String> >(&label, 1);
1864 }
1865 ReportMessageAt(scanner().location(), message, args);
1866 *ok = false;
1867 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001868 }
1869 ExpectSemicolon(CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001870 return new(zone()) BreakStatement(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001871}
1872
1873
1874Statement* Parser::ParseReturnStatement(bool* ok) {
1875 // ReturnStatement ::
1876 // 'return' Expression? ';'
1877
1878 // Consume the return token. It is necessary to do the before
1879 // reporting any errors on it, because of the way errors are
1880 // reported (underlining).
1881 Expect(Token::RETURN, CHECK_OK);
1882
1883 // An ECMAScript program is considered syntactically incorrect if it
1884 // contains a return statement that is not within the body of a
1885 // function. See ECMA-262, section 12.9, page 67.
1886 //
1887 // To be consistent with KJS we report the syntax error at runtime.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001888 if (!top_scope_->is_function_scope()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 Handle<String> type = isolate()->factory()->illegal_return_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001891 return new(zone()) ExpressionStatement(throw_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892 }
1893
1894 Token::Value tok = peek();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001895 if (scanner().has_line_terminator_before_next() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 tok == Token::SEMICOLON ||
1897 tok == Token::RBRACE ||
1898 tok == Token::EOS) {
1899 ExpectSemicolon(CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001900 return new(zone()) ReturnStatement(GetLiteralUndefined());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001901 }
1902
1903 Expression* expr = ParseExpression(true, CHECK_OK);
1904 ExpectSemicolon(CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001905 return new(zone()) ReturnStatement(expr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001906}
1907
1908
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001909Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001910 // Parse the statement and collect escaping labels.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001911 TargetCollector collector;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 Statement* stat;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001913 { Target target(&this->target_stack_, &collector);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914 with_nesting_level_++;
1915 top_scope_->RecordWithStatement();
1916 stat = ParseStatement(labels, CHECK_OK);
1917 with_nesting_level_--;
1918 }
1919 // Create resulting block with two statements.
1920 // 1: Evaluate the with expression.
1921 // 2: The try-finally block evaluating the body.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001922 Block* result = new(zone()) Block(NULL, 2, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001923
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001924 if (result != NULL) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001925 result->AddStatement(new(zone()) EnterWithContextStatement(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926
1927 // Create body block.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001928 Block* body = new(zone()) Block(NULL, 1, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 body->AddStatement(stat);
1930
1931 // Create exit block.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001932 Block* exit = new(zone()) Block(NULL, 1, false);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001933 exit->AddStatement(new(zone()) ExitContextStatement());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934
1935 // Return a try-finally statement.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001936 TryFinallyStatement* wrapper = new(zone()) TryFinallyStatement(body, exit);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001937 wrapper->set_escaping_targets(collector.targets());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001938 result->AddStatement(wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001940 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941}
1942
1943
1944Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
1945 // WithStatement ::
1946 // 'with' '(' Expression ')' Statement
1947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001948 Expect(Token::WITH, CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001949
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001950 if (top_scope_->is_strict_mode()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001951 ReportMessage("strict_mode_with", Vector<const char*>::empty());
1952 *ok = false;
1953 return NULL;
1954 }
1955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956 Expect(Token::LPAREN, CHECK_OK);
1957 Expression* expr = ParseExpression(true, CHECK_OK);
1958 Expect(Token::RPAREN, CHECK_OK);
1959
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001960 return WithHelper(expr, labels, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001961}
1962
1963
1964CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
1965 // CaseClause ::
1966 // 'case' Expression ':' Statement*
1967 // 'default' ':' Statement*
1968
1969 Expression* label = NULL; // NULL expression indicates default case
1970 if (peek() == Token::CASE) {
1971 Expect(Token::CASE, CHECK_OK);
1972 label = ParseExpression(true, CHECK_OK);
1973 } else {
1974 Expect(Token::DEFAULT, CHECK_OK);
1975 if (*default_seen_ptr) {
1976 ReportMessage("multiple_defaults_in_switch",
1977 Vector<const char*>::empty());
1978 *ok = false;
1979 return NULL;
1980 }
1981 *default_seen_ptr = true;
1982 }
1983 Expect(Token::COLON, CHECK_OK);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001984 int pos = scanner().location().beg_pos;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001985 ZoneList<Statement*>* statements = new(zone()) ZoneList<Statement*>(5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001986 while (peek() != Token::CASE &&
1987 peek() != Token::DEFAULT &&
1988 peek() != Token::RBRACE) {
1989 Statement* stat = ParseStatement(NULL, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001990 statements->Add(stat);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991 }
1992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001993 return new(zone()) CaseClause(label, statements, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001994}
1995
1996
1997SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels,
1998 bool* ok) {
1999 // SwitchStatement ::
2000 // 'switch' '(' Expression ')' '{' CaseClause* '}'
2001
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002002 SwitchStatement* statement = new(zone()) SwitchStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002003 Target target(&this->target_stack_, statement);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002004
2005 Expect(Token::SWITCH, CHECK_OK);
2006 Expect(Token::LPAREN, CHECK_OK);
2007 Expression* tag = ParseExpression(true, CHECK_OK);
2008 Expect(Token::RPAREN, CHECK_OK);
2009
2010 bool default_seen = false;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002011 ZoneList<CaseClause*>* cases = new(zone()) ZoneList<CaseClause*>(4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012 Expect(Token::LBRACE, CHECK_OK);
2013 while (peek() != Token::RBRACE) {
2014 CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002015 cases->Add(clause);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016 }
2017 Expect(Token::RBRACE, CHECK_OK);
2018
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002019 if (statement) statement->Initialize(tag, cases);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002020 return statement;
2021}
2022
2023
2024Statement* Parser::ParseThrowStatement(bool* ok) {
2025 // ThrowStatement ::
2026 // 'throw' Expression ';'
2027
2028 Expect(Token::THROW, CHECK_OK);
2029 int pos = scanner().location().beg_pos;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002030 if (scanner().has_line_terminator_before_next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002031 ReportMessage("newline_after_throw", Vector<const char*>::empty());
2032 *ok = false;
2033 return NULL;
2034 }
2035 Expression* exception = ParseExpression(true, CHECK_OK);
2036 ExpectSemicolon(CHECK_OK);
2037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002038 return new(zone()) ExpressionStatement(new(zone()) Throw(exception, pos));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002039}
2040
2041
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002042TryStatement* Parser::ParseTryStatement(bool* ok) {
2043 // TryStatement ::
2044 // 'try' Block Catch
2045 // 'try' Block Finally
2046 // 'try' Block Catch Finally
2047 //
2048 // Catch ::
2049 // 'catch' '(' Identifier ')' Block
2050 //
2051 // Finally ::
2052 // 'finally' Block
2053
2054 Expect(Token::TRY, CHECK_OK);
2055
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002056 TargetCollector try_collector;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002057 Block* try_block;
2058
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002059 { Target target(&this->target_stack_, &try_collector);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060 try_block = ParseBlock(NULL, CHECK_OK);
2061 }
2062
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002063 Token::Value tok = peek();
2064 if (tok != Token::CATCH && tok != Token::FINALLY) {
2065 ReportMessage("no_catch_or_finally", Vector<const char*>::empty());
2066 *ok = false;
2067 return NULL;
2068 }
2069
2070 // If we can break out from the catch block and there is a finally block,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002071 // then we will need to collect escaping targets from the catch
2072 // block. Since we don't know yet if there will be a finally block, we
2073 // always collect the targets.
2074 TargetCollector catch_collector;
2075 Block* catch_block = NULL;
2076 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002077 if (tok == Token::CATCH) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002078 Consume(Token::CATCH);
2079
2080 Expect(Token::LPAREN, CHECK_OK);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002081 name = ParseIdentifier(CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002082
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002083 if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002084 ReportMessage("strict_catch_variable", Vector<const char*>::empty());
2085 *ok = false;
2086 return NULL;
2087 }
2088
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002089 Expect(Token::RPAREN, CHECK_OK);
2090
2091 if (peek() == Token::LBRACE) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002092 // Rewrite the catch body B to a single statement block
2093 // { try B finally { PopContext }}.
2094 Block* inner_body;
2095 // We need to collect escapes from the body for both the inner
2096 // try/finally used to pop the catch context and any possible outer
2097 // try/finally.
2098 TargetCollector inner_collector;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002099 { Target target(&this->target_stack_, &catch_collector);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002100 { Target target(&this->target_stack_, &inner_collector);
2101 ++with_nesting_level_;
2102 top_scope_->RecordWithStatement();
2103 inner_body = ParseBlock(NULL, CHECK_OK);
2104 --with_nesting_level_;
2105 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002106 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002107
2108 // Create exit block.
2109 Block* inner_finally = new(zone()) Block(NULL, 1, false);
2110 inner_finally->AddStatement(new(zone()) ExitContextStatement());
2111
2112 // Create a try/finally statement.
2113 TryFinallyStatement* inner_try_finally =
2114 new(zone()) TryFinallyStatement(inner_body, inner_finally);
2115 inner_try_finally->set_escaping_targets(inner_collector.targets());
2116
2117 catch_block = new(zone()) Block(NULL, 1, false);
2118 catch_block->AddStatement(inner_try_finally);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002119 } else {
2120 Expect(Token::LBRACE, CHECK_OK);
2121 }
2122
2123 tok = peek();
2124 }
2125
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002126 Block* finally_block = NULL;
2127 if (tok == Token::FINALLY || catch_block == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002128 Consume(Token::FINALLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002129 finally_block = ParseBlock(NULL, CHECK_OK);
2130 }
2131
2132 // Simplify the AST nodes by converting:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002133 // 'try B0 catch B1 finally B2'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002134 // to:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002135 // 'try { try B0 catch B1 } finally B2'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002136
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002137 if (catch_block != NULL && finally_block != NULL) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002138 TryCatchStatement* statement =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002139 new(zone()) TryCatchStatement(try_block, name, catch_block);
2140 statement->set_escaping_targets(try_collector.targets());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002141 try_block = new(zone()) Block(NULL, 1, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002142 try_block->AddStatement(statement);
2143 catch_block = NULL;
2144 }
2145
2146 TryStatement* result = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002147 if (catch_block != NULL) {
2148 ASSERT(finally_block == NULL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002149 result =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002150 new(zone()) TryCatchStatement(try_block, name, catch_block);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002151 } else {
2152 ASSERT(finally_block != NULL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002153 result = new(zone()) TryFinallyStatement(try_block, finally_block);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002154 // Combine the jump targets of the try block and the possible catch block.
2155 try_collector.targets()->AddAll(*catch_collector.targets());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002156 }
2157
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002158 result->set_escaping_targets(try_collector.targets());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002159 return result;
2160}
2161
2162
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002163DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels,
2164 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002165 // DoStatement ::
2166 // 'do' Statement 'while' '(' Expression ')' ';'
2167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002168 DoWhileStatement* loop = new(zone()) DoWhileStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002169 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002170
2171 Expect(Token::DO, CHECK_OK);
2172 Statement* body = ParseStatement(NULL, CHECK_OK);
2173 Expect(Token::WHILE, CHECK_OK);
2174 Expect(Token::LPAREN, CHECK_OK);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002175
2176 if (loop != NULL) {
2177 int position = scanner().location().beg_pos;
2178 loop->set_condition_position(position);
2179 }
2180
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002181 Expression* cond = ParseExpression(true, CHECK_OK);
2182 Expect(Token::RPAREN, CHECK_OK);
2183
2184 // Allow do-statements to be terminated with and without
2185 // semi-colons. This allows code such as 'do;while(0)return' to
2186 // parse, which would not be the case if we had used the
2187 // ExpectSemicolon() functionality here.
2188 if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
2189
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002190 if (loop != NULL) loop->Initialize(cond, body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002191 return loop;
2192}
2193
2194
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002195WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002196 // WhileStatement ::
2197 // 'while' '(' Expression ')' Statement
2198
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002199 WhileStatement* loop = new(zone()) WhileStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002200 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002201
2202 Expect(Token::WHILE, CHECK_OK);
2203 Expect(Token::LPAREN, CHECK_OK);
2204 Expression* cond = ParseExpression(true, CHECK_OK);
2205 Expect(Token::RPAREN, CHECK_OK);
2206 Statement* body = ParseStatement(NULL, CHECK_OK);
2207
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002208 if (loop != NULL) loop->Initialize(cond, body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002209 return loop;
2210}
2211
2212
2213Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
2214 // ForStatement ::
2215 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
2216
2217 Statement* init = NULL;
2218
2219 Expect(Token::FOR, CHECK_OK);
2220 Expect(Token::LPAREN, CHECK_OK);
2221 if (peek() != Token::SEMICOLON) {
2222 if (peek() == Token::VAR || peek() == Token::CONST) {
2223 Expression* each = NULL;
2224 Block* variable_statement =
2225 ParseVariableDeclarations(false, &each, CHECK_OK);
2226 if (peek() == Token::IN && each != NULL) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002227 ForInStatement* loop = new(zone()) ForInStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002228 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002229
2230 Expect(Token::IN, CHECK_OK);
2231 Expression* enumerable = ParseExpression(true, CHECK_OK);
2232 Expect(Token::RPAREN, CHECK_OK);
2233
2234 Statement* body = ParseStatement(NULL, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002235 loop->Initialize(each, enumerable, body);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002236 Block* result = new(zone()) Block(NULL, 2, false);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002237 result->AddStatement(variable_statement);
2238 result->AddStatement(loop);
2239 // Parsed for-in loop w/ variable/const declaration.
2240 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002241 } else {
2242 init = variable_statement;
2243 }
2244
2245 } else {
2246 Expression* expression = ParseExpression(false, CHECK_OK);
2247 if (peek() == Token::IN) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002248 // Signal a reference error if the expression is an invalid
2249 // left-hand side expression. We could report this as a syntax
2250 // error here but for compatibility with JSC we choose to report
2251 // the error at runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002252 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002253 Handle<String> type =
2254 isolate()->factory()->invalid_lhs_in_for_in_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002255 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002256 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002257 ForInStatement* loop = new(zone()) ForInStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002258 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002259
2260 Expect(Token::IN, CHECK_OK);
2261 Expression* enumerable = ParseExpression(true, CHECK_OK);
2262 Expect(Token::RPAREN, CHECK_OK);
2263
2264 Statement* body = ParseStatement(NULL, CHECK_OK);
2265 if (loop) loop->Initialize(expression, enumerable, body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002266 // Parsed for-in loop.
2267 return loop;
2268
2269 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002270 init = new(zone()) ExpressionStatement(expression);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002271 }
2272 }
2273 }
2274
2275 // Standard 'for' loop
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002276 ForStatement* loop = new(zone()) ForStatement(labels);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00002277 Target target(&this->target_stack_, loop);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002278
2279 // Parsed initializer at this point.
2280 Expect(Token::SEMICOLON, CHECK_OK);
2281
2282 Expression* cond = NULL;
2283 if (peek() != Token::SEMICOLON) {
2284 cond = ParseExpression(true, CHECK_OK);
2285 }
2286 Expect(Token::SEMICOLON, CHECK_OK);
2287
2288 Statement* next = NULL;
2289 if (peek() != Token::RPAREN) {
2290 Expression* exp = ParseExpression(true, CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002291 next = new(zone()) ExpressionStatement(exp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002292 }
2293 Expect(Token::RPAREN, CHECK_OK);
2294
2295 Statement* body = ParseStatement(NULL, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002296 if (loop) loop->Initialize(init, cond, next, body);
2297 return loop;
2298}
2299
2300
2301// Precedence = 1
2302Expression* Parser::ParseExpression(bool accept_IN, bool* ok) {
2303 // Expression ::
2304 // AssignmentExpression
2305 // Expression ',' AssignmentExpression
2306
2307 Expression* result = ParseAssignmentExpression(accept_IN, CHECK_OK);
2308 while (peek() == Token::COMMA) {
2309 Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002310 int position = scanner().location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002311 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002312 result = new(zone()) BinaryOperation(Token::COMMA, result, right, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002313 }
2314 return result;
2315}
2316
2317
2318// Precedence = 2
2319Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
2320 // AssignmentExpression ::
2321 // ConditionalExpression
2322 // LeftHandSideExpression AssignmentOperator AssignmentExpression
2323
ricow@chromium.org65fae842010-08-25 15:26:24 +00002324 if (fni_ != NULL) fni_->Enter();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002325 Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
2326
2327 if (!Token::IsAssignmentOp(peek())) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002328 if (fni_ != NULL) fni_->Leave();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002329 // Parsed conditional expression only (no assignment).
2330 return expression;
2331 }
2332
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002333 // Signal a reference error if the expression is an invalid left-hand
2334 // side expression. We could report this as a syntax error here but
2335 // for compatibility with JSC we choose to report the error at
2336 // runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002337 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002338 Handle<String> type =
2339 isolate()->factory()->invalid_lhs_in_assignment_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002340 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002341 }
2342
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002343 if (top_scope_->is_strict_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002344 // Assignment to eval or arguments is disallowed in strict mode.
2345 CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK);
2346 }
2347
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002348 Token::Value op = Next(); // Get assignment operator.
2349 int pos = scanner().location().beg_pos;
2350 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
2351
2352 // TODO(1231235): We try to estimate the set of properties set by
2353 // constructors. We define a new property whenever there is an
2354 // assignment to a property of 'this'. We should probably only add
2355 // properties if we haven't seen them before. Otherwise we'll
2356 // probably overestimate the number of properties.
2357 Property* property = expression ? expression->AsProperty() : NULL;
2358 if (op == Token::ASSIGN &&
2359 property != NULL &&
2360 property->obj()->AsVariableProxy() != NULL &&
2361 property->obj()->AsVariableProxy()->is_this()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002362 lexical_scope_->AddProperty();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002363 }
2364
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00002365 // If we assign a function literal to a property we pretenure the
2366 // literal so it can be added as a constant function property.
2367 if (property != NULL && right->AsFunctionLiteral() != NULL) {
2368 right->AsFunctionLiteral()->set_pretenure(true);
2369 }
2370
ricow@chromium.org65fae842010-08-25 15:26:24 +00002371 if (fni_ != NULL) {
2372 // Check if the right hand side is a call to avoid inferring a
2373 // name if we're dealing with "a = function(){...}();"-like
2374 // expression.
2375 if ((op == Token::INIT_VAR
2376 || op == Token::INIT_CONST
2377 || op == Token::ASSIGN)
2378 && (right->AsCall() == NULL)) {
2379 fni_->Infer();
2380 }
2381 fni_->Leave();
2382 }
2383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002384 return new(zone()) Assignment(op, expression, right, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002385}
2386
2387
2388// Precedence = 3
2389Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
2390 // ConditionalExpression ::
2391 // LogicalOrExpression
2392 // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
2393
2394 // We start using the binary expression parser for prec >= 4 only!
2395 Expression* expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
2396 if (peek() != Token::CONDITIONAL) return expression;
2397 Consume(Token::CONDITIONAL);
2398 // In parsing the first assignment expression in conditional
2399 // expressions we always accept the 'in' keyword; see ECMA-262,
2400 // section 11.12, page 58.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002401 int left_position = scanner().peek_location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002402 Expression* left = ParseAssignmentExpression(true, CHECK_OK);
2403 Expect(Token::COLON, CHECK_OK);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002404 int right_position = scanner().peek_location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002405 Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002406 return new(zone()) Conditional(expression, left, right,
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002407 left_position, right_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002408}
2409
2410
2411static int Precedence(Token::Value tok, bool accept_IN) {
2412 if (tok == Token::IN && !accept_IN)
2413 return 0; // 0 precedence will terminate binary expression parsing
2414
2415 return Token::Precedence(tok);
2416}
2417
2418
2419// Precedence >= 4
2420Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
2421 ASSERT(prec >= 4);
2422 Expression* x = ParseUnaryExpression(CHECK_OK);
2423 for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
2424 // prec1 >= 4
2425 while (Precedence(peek(), accept_IN) == prec1) {
2426 Token::Value op = Next();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002427 int position = scanner().location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002428 Expression* y = ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
2429
2430 // Compute some expressions involving only number literals.
2431 if (x && x->AsLiteral() && x->AsLiteral()->handle()->IsNumber() &&
2432 y && y->AsLiteral() && y->AsLiteral()->handle()->IsNumber()) {
2433 double x_val = x->AsLiteral()->handle()->Number();
2434 double y_val = y->AsLiteral()->handle()->Number();
2435
2436 switch (op) {
2437 case Token::ADD:
2438 x = NewNumberLiteral(x_val + y_val);
2439 continue;
2440 case Token::SUB:
2441 x = NewNumberLiteral(x_val - y_val);
2442 continue;
2443 case Token::MUL:
2444 x = NewNumberLiteral(x_val * y_val);
2445 continue;
2446 case Token::DIV:
2447 x = NewNumberLiteral(x_val / y_val);
2448 continue;
2449 case Token::BIT_OR:
2450 x = NewNumberLiteral(DoubleToInt32(x_val) | DoubleToInt32(y_val));
2451 continue;
2452 case Token::BIT_AND:
2453 x = NewNumberLiteral(DoubleToInt32(x_val) & DoubleToInt32(y_val));
2454 continue;
2455 case Token::BIT_XOR:
2456 x = NewNumberLiteral(DoubleToInt32(x_val) ^ DoubleToInt32(y_val));
2457 continue;
2458 case Token::SHL: {
2459 int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f);
2460 x = NewNumberLiteral(value);
2461 continue;
2462 }
2463 case Token::SHR: {
2464 uint32_t shift = DoubleToInt32(y_val) & 0x1f;
2465 uint32_t value = DoubleToUint32(x_val) >> shift;
2466 x = NewNumberLiteral(value);
2467 continue;
2468 }
2469 case Token::SAR: {
2470 uint32_t shift = DoubleToInt32(y_val) & 0x1f;
2471 int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift);
2472 x = NewNumberLiteral(value);
2473 continue;
2474 }
2475 default:
2476 break;
2477 }
2478 }
2479
2480 // For now we distinguish between comparisons and other binary
2481 // operations. (We could combine the two and get rid of this
ricow@chromium.org65fae842010-08-25 15:26:24 +00002482 // code and AST node eventually.)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002483 if (Token::IsCompareOp(op)) {
2484 // We have a comparison.
2485 Token::Value cmp = op;
2486 switch (op) {
2487 case Token::NE: cmp = Token::EQ; break;
2488 case Token::NE_STRICT: cmp = Token::EQ_STRICT; break;
2489 default: break;
2490 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002491 x = NewCompareNode(cmp, x, y, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002492 if (cmp != op) {
2493 // The comparison was negated - add a NOT.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002494 x = new(zone()) UnaryOperation(Token::NOT, x, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002495 }
2496
2497 } else {
2498 // We have a "normal" binary operation.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002499 x = new(zone()) BinaryOperation(op, x, y, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002500 }
2501 }
2502 }
2503 return x;
2504}
2505
2506
ricow@chromium.org65fae842010-08-25 15:26:24 +00002507Expression* Parser::NewCompareNode(Token::Value op,
2508 Expression* x,
2509 Expression* y,
2510 int position) {
2511 ASSERT(op != Token::NE && op != Token::NE_STRICT);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002512 if (op == Token::EQ || op == Token::EQ_STRICT) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002513 bool is_strict = (op == Token::EQ_STRICT);
2514 Literal* x_literal = x->AsLiteral();
2515 if (x_literal != NULL && x_literal->IsNull()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002516 return new(zone()) CompareToNull(is_strict, y);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002517 }
2518
2519 Literal* y_literal = y->AsLiteral();
2520 if (y_literal != NULL && y_literal->IsNull()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002521 return new(zone()) CompareToNull(is_strict, x);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002522 }
2523 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002524 return new(zone()) CompareOperation(op, x, y, position);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002525}
2526
2527
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002528Expression* Parser::ParseUnaryExpression(bool* ok) {
2529 // UnaryExpression ::
2530 // PostfixExpression
2531 // 'delete' UnaryExpression
2532 // 'void' UnaryExpression
2533 // 'typeof' UnaryExpression
2534 // '++' UnaryExpression
2535 // '--' UnaryExpression
2536 // '+' UnaryExpression
2537 // '-' UnaryExpression
2538 // '~' UnaryExpression
2539 // '!' UnaryExpression
2540
2541 Token::Value op = peek();
2542 if (Token::IsUnaryOp(op)) {
2543 op = Next();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002544 int position = scanner().location().beg_pos;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002545 Expression* expression = ParseUnaryExpression(CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002546
2547 // Compute some expressions involving only number literals.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002548 if (expression != NULL && expression->AsLiteral() &&
2549 expression->AsLiteral()->handle()->IsNumber()) {
2550 double value = expression->AsLiteral()->handle()->Number();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002551 switch (op) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002552 case Token::ADD:
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002553 return expression;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002554 case Token::SUB:
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002555 return NewNumberLiteral(-value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002556 case Token::BIT_NOT:
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002557 return NewNumberLiteral(~DoubleToInt32(value));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002558 default: break;
2559 }
2560 }
2561
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002562 // "delete identifier" is a syntax error in strict mode.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002563 if (op == Token::DELETE && top_scope_->is_strict_mode()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002564 VariableProxy* operand = expression->AsVariableProxy();
2565 if (operand != NULL && !operand->is_this()) {
2566 ReportMessage("strict_delete", Vector<const char*>::empty());
2567 *ok = false;
2568 return NULL;
2569 }
2570 }
2571
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002572 return new(zone()) UnaryOperation(op, expression, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002573
2574 } else if (Token::IsCountOp(op)) {
2575 op = Next();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002576 Expression* expression = ParseUnaryExpression(CHECK_OK);
2577 // Signal a reference error if the expression is an invalid
2578 // left-hand side expression. We could report this as a syntax
2579 // error here but for compatibility with JSC we choose to report the
2580 // error at runtime.
2581 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002582 Handle<String> type =
2583 isolate()->factory()->invalid_lhs_in_prefix_op_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002584 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002585 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00002586
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002587 if (top_scope_->is_strict_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002588 // Prefix expression operand in strict mode may not be eval or arguments.
2589 CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
2590 }
2591
ricow@chromium.org65fae842010-08-25 15:26:24 +00002592 int position = scanner().location().beg_pos;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002593 return new(zone()) CountOperation(op,
2594 true /* prefix */,
2595 expression,
2596 position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002597
2598 } else {
2599 return ParsePostfixExpression(ok);
2600 }
2601}
2602
2603
2604Expression* Parser::ParsePostfixExpression(bool* ok) {
2605 // PostfixExpression ::
2606 // LeftHandSideExpression ('++' | '--')?
2607
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002608 Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002609 if (!scanner().has_line_terminator_before_next() &&
2610 Token::IsCountOp(peek())) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002611 // Signal a reference error if the expression is an invalid
2612 // left-hand side expression. We could report this as a syntax
2613 // error here but for compatibility with JSC we choose to report the
2614 // error at runtime.
2615 if (expression == NULL || !expression->IsValidLeftHandSide()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002616 Handle<String> type =
2617 isolate()->factory()->invalid_lhs_in_postfix_op_symbol();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002618 expression = NewThrowReferenceError(type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002619 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00002620
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002621 if (top_scope_->is_strict_mode()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002622 // Postfix expression operand in strict mode may not be eval or arguments.
2623 CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
2624 }
2625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002626 Token::Value next = Next();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002627 int position = scanner().location().beg_pos;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002628 expression =
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002629 new(zone()) CountOperation(next,
2630 false /* postfix */,
2631 expression,
2632 position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002633 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002634 return expression;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002635}
2636
2637
2638Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
2639 // LeftHandSideExpression ::
2640 // (NewExpression | MemberExpression) ...
2641
2642 Expression* result;
2643 if (peek() == Token::NEW) {
2644 result = ParseNewExpression(CHECK_OK);
2645 } else {
2646 result = ParseMemberExpression(CHECK_OK);
2647 }
2648
2649 while (true) {
2650 switch (peek()) {
2651 case Token::LBRACK: {
2652 Consume(Token::LBRACK);
2653 int pos = scanner().location().beg_pos;
2654 Expression* index = ParseExpression(true, CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002655 result = new(zone()) Property(result, index, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002656 Expect(Token::RBRACK, CHECK_OK);
2657 break;
2658 }
2659
2660 case Token::LPAREN: {
2661 int pos = scanner().location().beg_pos;
2662 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
2663
2664 // Keep track of eval() calls since they disable all local variable
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002665 // optimizations.
2666 // The calls that need special treatment are the
2667 // direct (i.e. not aliased) eval calls. These calls are all of the
2668 // form eval(...) with no explicit receiver object where eval is not
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002669 // declared in the current scope chain.
2670 // These calls are marked as potentially direct eval calls. Whether
2671 // they are actually direct calls to eval is determined at run time.
2672 // TODO(994): In ES5, it doesn't matter if the "eval" var is declared
2673 // in the local scope chain. It only matters that it's called "eval",
2674 // is called without a receiver and it refers to the original eval
2675 // function.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002676 VariableProxy* callee = result->AsVariableProxy();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002677 if (callee != NULL &&
2678 callee->IsVariable(isolate()->factory()->eval_symbol())) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002679 Handle<String> name = callee->name();
2680 Variable* var = top_scope_->Lookup(name);
2681 if (var == NULL) {
2682 top_scope_->RecordEvalCall();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002683 }
2684 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002685 result = NewCall(result, args, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002686 break;
2687 }
2688
2689 case Token::PERIOD: {
2690 Consume(Token::PERIOD);
2691 int pos = scanner().location().beg_pos;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00002692 Handle<String> name = ParseIdentifierName(CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002693 result = new(zone()) Property(result, new(zone()) Literal(name), pos);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002694 if (fni_ != NULL) fni_->PushLiteralName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002695 break;
2696 }
2697
2698 default:
2699 return result;
2700 }
2701 }
2702}
2703
2704
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002705Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002706 // NewExpression ::
2707 // ('new')+ MemberExpression
2708
2709 // The grammar for new expressions is pretty warped. The keyword
2710 // 'new' can either be a part of the new expression (where it isn't
2711 // followed by an argument list) or a part of the member expression,
2712 // where it must be followed by an argument list. To accommodate
2713 // this, we parse the 'new' keywords greedily and keep track of how
2714 // many we have parsed. This information is then passed on to the
2715 // member expression parser, which is only allowed to match argument
2716 // lists as long as it has 'new' prefixes left
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002717 Expect(Token::NEW, CHECK_OK);
2718 PositionStack::Element pos(stack, scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002719
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002720 Expression* result;
2721 if (peek() == Token::NEW) {
2722 result = ParseNewPrefix(stack, CHECK_OK);
2723 } else {
2724 result = ParseMemberWithNewPrefixesExpression(stack, CHECK_OK);
2725 }
2726
2727 if (!stack->is_empty()) {
2728 int last = stack->pop();
danno@chromium.org40cb8782011-05-25 07:58:50 +00002729 result = new(zone()) CallNew(result,
2730 new(zone()) ZoneList<Expression*>(0),
2731 last);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002732 }
2733 return result;
2734}
2735
2736
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002737Expression* Parser::ParseNewExpression(bool* ok) {
2738 PositionStack stack(ok);
2739 return ParseNewPrefix(&stack, ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002740}
2741
2742
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002743Expression* Parser::ParseMemberExpression(bool* ok) {
2744 return ParseMemberWithNewPrefixesExpression(NULL, ok);
2745}
2746
2747
2748Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
2749 bool* ok) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002750 // MemberExpression ::
2751 // (PrimaryExpression | FunctionLiteral)
2752 // ('[' Expression ']' | '.' Identifier | Arguments)*
2753
2754 // Parse the initial primary or function expression.
2755 Expression* result = NULL;
2756 if (peek() == Token::FUNCTION) {
2757 Expect(Token::FUNCTION, CHECK_OK);
2758 int function_token_position = scanner().location().beg_pos;
2759 Handle<String> name;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002760 bool is_reserved_name = false;
2761 if (peek_any_identifier()) {
2762 name = ParseIdentifierOrReservedWord(&is_reserved_name, CHECK_OK);
2763 }
2764 result = ParseFunctionLiteral(name, is_reserved_name,
2765 function_token_position, NESTED, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002766 } else {
2767 result = ParsePrimaryExpression(CHECK_OK);
2768 }
2769
2770 while (true) {
2771 switch (peek()) {
2772 case Token::LBRACK: {
2773 Consume(Token::LBRACK);
2774 int pos = scanner().location().beg_pos;
2775 Expression* index = ParseExpression(true, CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002776 result = new(zone()) Property(result, index, pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002777 Expect(Token::RBRACK, CHECK_OK);
2778 break;
2779 }
2780 case Token::PERIOD: {
2781 Consume(Token::PERIOD);
2782 int pos = scanner().location().beg_pos;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00002783 Handle<String> name = ParseIdentifierName(CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002784 result = new(zone()) Property(result, new(zone()) Literal(name), pos);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002785 if (fni_ != NULL) fni_->PushLiteralName(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002786 break;
2787 }
2788 case Token::LPAREN: {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002789 if ((stack == NULL) || stack->is_empty()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002790 // Consume one of the new prefixes (already parsed).
2791 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002792 int last = stack->pop();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002793 result = new CallNew(result, args, last);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002794 break;
2795 }
2796 default:
2797 return result;
2798 }
2799 }
2800}
2801
2802
2803DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
2804 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
2805 // contexts this is used as a statement which invokes the debugger as i a
2806 // break point is present.
2807 // DebuggerStatement ::
2808 // 'debugger' ';'
2809
2810 Expect(Token::DEBUGGER, CHECK_OK);
2811 ExpectSemicolon(CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002812 return new(zone()) DebuggerStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002813}
2814
2815
2816void Parser::ReportUnexpectedToken(Token::Value token) {
2817 // We don't report stack overflows here, to avoid increasing the
2818 // stack depth even further. Instead we report it after parsing is
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002819 // over, in ParseProgram/ParseJson.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002820 if (token == Token::ILLEGAL && stack_overflow_) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002821 // Four of the tokens are treated specially
2822 switch (token) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002823 case Token::EOS:
2824 return ReportMessage("unexpected_eos", Vector<const char*>::empty());
2825 case Token::NUMBER:
2826 return ReportMessage("unexpected_token_number",
2827 Vector<const char*>::empty());
2828 case Token::STRING:
2829 return ReportMessage("unexpected_token_string",
2830 Vector<const char*>::empty());
2831 case Token::IDENTIFIER:
2832 return ReportMessage("unexpected_token_identifier",
2833 Vector<const char*>::empty());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002834 case Token::FUTURE_RESERVED_WORD:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002835 return ReportMessage(top_scope_->is_strict_mode() ?
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002836 "unexpected_strict_reserved" :
2837 "unexpected_token_identifier",
2838 Vector<const char*>::empty());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002839 default:
2840 const char* name = Token::String(token);
2841 ASSERT(name != NULL);
2842 ReportMessage("unexpected_token", Vector<const char*>(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002843 }
2844}
2845
2846
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002847void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
2848 SmartPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
2849 const char* element[1] = { *name_string };
2850 ReportMessage("invalid_preparser_data",
2851 Vector<const char*>(element, 1));
2852 *ok = false;
2853}
2854
2855
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002856Expression* Parser::ParsePrimaryExpression(bool* ok) {
2857 // PrimaryExpression ::
2858 // 'this'
2859 // 'null'
2860 // 'true'
2861 // 'false'
2862 // Identifier
2863 // Number
2864 // String
2865 // ArrayLiteral
2866 // ObjectLiteral
2867 // RegExpLiteral
2868 // '(' Expression ')'
2869
2870 Expression* result = NULL;
2871 switch (peek()) {
2872 case Token::THIS: {
2873 Consume(Token::THIS);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002874 VariableProxy* recv = top_scope_->receiver();
2875 result = recv;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002876 break;
2877 }
2878
2879 case Token::NULL_LITERAL:
2880 Consume(Token::NULL_LITERAL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002881 result = new(zone()) Literal(isolate()->factory()->null_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002882 break;
2883
2884 case Token::TRUE_LITERAL:
2885 Consume(Token::TRUE_LITERAL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002886 result = new(zone()) Literal(isolate()->factory()->true_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002887 break;
2888
2889 case Token::FALSE_LITERAL:
2890 Consume(Token::FALSE_LITERAL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002891 result = new(zone()) Literal(isolate()->factory()->false_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002892 break;
2893
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002894 case Token::IDENTIFIER:
2895 case Token::FUTURE_RESERVED_WORD: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002896 Handle<String> name = ParseIdentifier(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002897 if (fni_ != NULL) fni_->PushVariableName(name);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002898 result = top_scope_->NewUnresolved(name,
2899 inside_with(),
2900 scanner().location().beg_pos);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002901 break;
2902 }
2903
2904 case Token::NUMBER: {
2905 Consume(Token::NUMBER);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002906 ASSERT(scanner().is_literal_ascii());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002907 double value = StringToDouble(isolate()->unicode_cache(),
2908 scanner().literal_ascii_string(),
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002909 ALLOW_HEX | ALLOW_OCTALS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002910 result = NewNumberLiteral(value);
2911 break;
2912 }
2913
2914 case Token::STRING: {
2915 Consume(Token::STRING);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00002916 Handle<String> symbol = GetSymbol(CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002917 result = new(zone()) Literal(symbol);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002918 if (fni_ != NULL) fni_->PushLiteralName(symbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002919 break;
2920 }
2921
2922 case Token::ASSIGN_DIV:
2923 result = ParseRegExpLiteral(true, CHECK_OK);
2924 break;
2925
2926 case Token::DIV:
2927 result = ParseRegExpLiteral(false, CHECK_OK);
2928 break;
2929
2930 case Token::LBRACK:
2931 result = ParseArrayLiteral(CHECK_OK);
2932 break;
2933
2934 case Token::LBRACE:
2935 result = ParseObjectLiteral(CHECK_OK);
2936 break;
2937
2938 case Token::LPAREN:
2939 Consume(Token::LPAREN);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002940 // Heuristically try to detect immediately called functions before
2941 // seeing the call parentheses.
2942 parenthesized_function_ = (peek() == Token::FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002943 result = ParseExpression(true, CHECK_OK);
2944 Expect(Token::RPAREN, CHECK_OK);
2945 break;
2946
2947 case Token::MOD:
2948 if (allow_natives_syntax_ || extension_ != NULL) {
2949 result = ParseV8Intrinsic(CHECK_OK);
2950 break;
2951 }
2952 // If we're not allowing special syntax we fall-through to the
2953 // default case.
2954
2955 default: {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00002956 Token::Value tok = Next();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002957 ReportUnexpectedToken(tok);
2958 *ok = false;
2959 return NULL;
2960 }
2961 }
2962
2963 return result;
2964}
2965
2966
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002967void Parser::BuildArrayLiteralBoilerplateLiterals(ZoneList<Expression*>* values,
2968 Handle<FixedArray> literals,
2969 bool* is_simple,
2970 int* depth) {
2971 // Fill in the literals.
2972 // Accumulate output values in local variables.
2973 bool is_simple_acc = true;
2974 int depth_acc = 1;
2975 for (int i = 0; i < values->length(); i++) {
2976 MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
2977 if (m_literal != NULL && m_literal->depth() >= depth_acc) {
2978 depth_acc = m_literal->depth() + 1;
2979 }
2980 Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
2981 if (boilerplate_value->IsUndefined()) {
2982 literals->set_the_hole(i);
2983 is_simple_acc = false;
2984 } else {
2985 literals->set(i, *boilerplate_value);
2986 }
2987 }
2988
2989 *is_simple = is_simple_acc;
2990 *depth = depth_acc;
2991}
2992
2993
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002994Expression* Parser::ParseArrayLiteral(bool* ok) {
2995 // ArrayLiteral ::
2996 // '[' Expression? (',' Expression?)* ']'
2997
danno@chromium.org40cb8782011-05-25 07:58:50 +00002998 ZoneList<Expression*>* values = new(zone()) ZoneList<Expression*>(4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002999 Expect(Token::LBRACK, CHECK_OK);
3000 while (peek() != Token::RBRACK) {
3001 Expression* elem;
3002 if (peek() == Token::COMMA) {
3003 elem = GetLiteralTheHole();
3004 } else {
3005 elem = ParseAssignmentExpression(true, CHECK_OK);
3006 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003007 values->Add(elem);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003008 if (peek() != Token::RBRACK) {
3009 Expect(Token::COMMA, CHECK_OK);
3010 }
3011 }
3012 Expect(Token::RBRACK, CHECK_OK);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003013
3014 // Update the scope information before the pre-parsing bailout.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003015 int literal_index = lexical_scope_->NextMaterializedLiteralIndex();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003016
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003017 // Allocate a fixed array with all the literals.
3018 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003019 isolate()->factory()->NewFixedArray(values->length(), TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003020
3021 // Fill in the literals.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003022 bool is_simple = true;
3023 int depth = 1;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003024 for (int i = 0, n = values->length(); i < n; i++) {
3025 MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003026 if (m_literal != NULL && m_literal->depth() + 1 > depth) {
3027 depth = m_literal->depth() + 1;
3028 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003029 Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003030 if (boilerplate_value->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003031 literals->set_the_hole(i);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003032 is_simple = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003033 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003034 literals->set(i, *boilerplate_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003035 }
3036 }
3037
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003038 // Simple and shallow arrays can be lazily copied, we transform the
3039 // elements array to a copy-on-write array.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003040 if (is_simple && depth == 1 && values->length() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003041 literals->set_map(isolate()->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003042 }
3043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003044 return new(zone()) ArrayLiteral(literals, values,
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003045 literal_index, is_simple, depth);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003046}
3047
3048
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003049bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) {
3050 return property != NULL &&
3051 property->kind() != ObjectLiteral::Property::PROTOTYPE;
3052}
3053
3054
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003055bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003056 if (expression->AsLiteral() != NULL) return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003057 MaterializedLiteral* lit = expression->AsMaterializedLiteral();
3058 return lit != NULL && lit->is_simple();
3059}
3060
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003061
3062bool CompileTimeValue::ArrayLiteralElementNeedsInitialization(
3063 Expression* value) {
3064 // If value is a literal the property value is already set in the
3065 // boilerplate object.
3066 if (value->AsLiteral() != NULL) return false;
3067 // If value is a materialized literal the property value is already set
3068 // in the boilerplate object if it is simple.
3069 if (CompileTimeValue::IsCompileTimeValue(value)) return false;
3070 return true;
3071}
3072
3073
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003074Handle<FixedArray> CompileTimeValue::GetValue(Expression* expression) {
3075 ASSERT(IsCompileTimeValue(expression));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003076 Handle<FixedArray> result = FACTORY->NewFixedArray(2, TENURED);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003077 ObjectLiteral* object_literal = expression->AsObjectLiteral();
3078 if (object_literal != NULL) {
3079 ASSERT(object_literal->is_simple());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003080 if (object_literal->fast_elements()) {
3081 result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS));
3082 } else {
3083 result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS));
3084 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003085 result->set(kElementsSlot, *object_literal->constant_properties());
3086 } else {
3087 ArrayLiteral* array_literal = expression->AsArrayLiteral();
3088 ASSERT(array_literal != NULL && array_literal->is_simple());
3089 result->set(kTypeSlot, Smi::FromInt(ARRAY_LITERAL));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003090 result->set(kElementsSlot, *array_literal->constant_elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003091 }
3092 return result;
3093}
3094
3095
3096CompileTimeValue::Type CompileTimeValue::GetType(Handle<FixedArray> value) {
3097 Smi* type_value = Smi::cast(value->get(kTypeSlot));
3098 return static_cast<Type>(type_value->value());
3099}
3100
3101
3102Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
3103 return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot)));
3104}
3105
3106
3107Handle<Object> Parser::GetBoilerplateValue(Expression* expression) {
3108 if (expression->AsLiteral() != NULL) {
3109 return expression->AsLiteral()->handle();
3110 }
3111 if (CompileTimeValue::IsCompileTimeValue(expression)) {
3112 return CompileTimeValue::GetValue(expression);
3113 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003114 return isolate()->factory()->undefined_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003115}
3116
ager@chromium.org378b34e2011-01-28 08:04:38 +00003117// Defined in ast.cc
3118bool IsEqualString(void* first, void* second);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003119bool IsEqualNumber(void* first, void* second);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003120
3121
3122// Validation per 11.1.5 Object Initialiser
3123class ObjectLiteralPropertyChecker {
3124 public:
3125 ObjectLiteralPropertyChecker(Parser* parser, bool strict) :
3126 props(&IsEqualString),
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003127 elems(&IsEqualNumber),
ager@chromium.org378b34e2011-01-28 08:04:38 +00003128 parser_(parser),
3129 strict_(strict) {
3130 }
3131
3132 void CheckProperty(
3133 ObjectLiteral::Property* property,
3134 Scanner::Location loc,
3135 bool* ok);
3136
3137 private:
3138 enum PropertyKind {
3139 kGetAccessor = 0x01,
3140 kSetAccessor = 0x02,
3141 kAccessor = kGetAccessor | kSetAccessor,
3142 kData = 0x04
3143 };
3144
3145 static intptr_t GetPropertyKind(ObjectLiteral::Property* property) {
3146 switch (property->kind()) {
3147 case ObjectLiteral::Property::GETTER:
3148 return kGetAccessor;
3149 case ObjectLiteral::Property::SETTER:
3150 return kSetAccessor;
3151 default:
3152 return kData;
3153 }
3154 }
3155
3156 HashMap props;
3157 HashMap elems;
3158 Parser* parser_;
3159 bool strict_;
3160};
3161
3162
3163void ObjectLiteralPropertyChecker::CheckProperty(
3164 ObjectLiteral::Property* property,
3165 Scanner::Location loc,
3166 bool* ok) {
3167
3168 ASSERT(property != NULL);
3169
3170 Literal *lit = property->key();
3171 Handle<Object> handle = lit->handle();
3172
3173 uint32_t hash;
3174 HashMap* map;
3175 void* key;
ager@chromium.org378b34e2011-01-28 08:04:38 +00003176
3177 if (handle->IsSymbol()) {
3178 Handle<String> name(String::cast(*handle));
3179 if (name->AsArrayIndex(&hash)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003180 Handle<Object> key_handle = FACTORY->NewNumberFromUint(hash);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003181 key = key_handle.location();
ager@chromium.org378b34e2011-01-28 08:04:38 +00003182 map = &elems;
3183 } else {
3184 key = handle.location();
3185 hash = name->Hash();
3186 map = &props;
3187 }
3188 } else if (handle->ToArrayIndex(&hash)) {
3189 key = handle.location();
3190 map = &elems;
3191 } else {
3192 ASSERT(handle->IsNumber());
3193 double num = handle->Number();
3194 char arr[100];
3195 Vector<char> buffer(arr, ARRAY_SIZE(arr));
3196 const char* str = DoubleToCString(num, buffer);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003197 Handle<String> name = FACTORY->NewStringFromAscii(CStrVector(str));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003198 key = name.location();
3199 hash = name->Hash();
3200 map = &props;
3201 }
3202
3203 // Lookup property previously defined, if any.
3204 HashMap::Entry* entry = map->Lookup(key, hash, true);
3205 intptr_t prev = reinterpret_cast<intptr_t> (entry->value);
3206 intptr_t curr = GetPropertyKind(property);
3207
3208 // Duplicate data properties are illegal in strict mode.
3209 if (strict_ && (curr & prev & kData) != 0) {
3210 parser_->ReportMessageAt(loc, "strict_duplicate_property",
3211 Vector<const char*>::empty());
3212 *ok = false;
3213 return;
3214 }
3215 // Data property conflicting with an accessor.
3216 if (((curr & kData) && (prev & kAccessor)) ||
3217 ((prev & kData) && (curr & kAccessor))) {
3218 parser_->ReportMessageAt(loc, "accessor_data_property",
3219 Vector<const char*>::empty());
3220 *ok = false;
3221 return;
3222 }
3223 // Two accessors of the same type conflicting
3224 if ((curr & prev & kAccessor) != 0) {
3225 parser_->ReportMessageAt(loc, "accessor_get_set",
3226 Vector<const char*>::empty());
3227 *ok = false;
3228 return;
3229 }
3230
3231 // Update map
3232 entry->value = reinterpret_cast<void*> (prev | curr);
3233 *ok = true;
3234}
3235
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003236
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003237void Parser::BuildObjectLiteralConstantProperties(
3238 ZoneList<ObjectLiteral::Property*>* properties,
3239 Handle<FixedArray> constant_properties,
3240 bool* is_simple,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003241 bool* fast_elements,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003242 int* depth) {
3243 int position = 0;
3244 // Accumulate the value in local variables and store it at the end.
3245 bool is_simple_acc = true;
3246 int depth_acc = 1;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003247 uint32_t max_element_index = 0;
3248 uint32_t elements = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003249 for (int i = 0; i < properties->length(); i++) {
3250 ObjectLiteral::Property* property = properties->at(i);
3251 if (!IsBoilerplateProperty(property)) {
3252 is_simple_acc = false;
3253 continue;
3254 }
3255 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
3256 if (m_literal != NULL && m_literal->depth() >= depth_acc) {
3257 depth_acc = m_literal->depth() + 1;
3258 }
3259
3260 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
3261 // value for COMPUTED properties, the real value is filled in at
3262 // runtime. The enumeration order is maintained.
3263 Handle<Object> key = property->key()->handle();
3264 Handle<Object> value = GetBoilerplateValue(property->value());
3265 is_simple_acc = is_simple_acc && !value->IsUndefined();
3266
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003267 // Keep track of the number of elements in the object literal and
3268 // the largest element index. If the largest element index is
3269 // much larger than the number of elements, creating an object
3270 // literal with fast elements will be a waste of space.
3271 uint32_t element_index = 0;
3272 if (key->IsString()
3273 && Handle<String>::cast(key)->AsArrayIndex(&element_index)
3274 && element_index > max_element_index) {
3275 max_element_index = element_index;
3276 elements++;
3277 } else if (key->IsSmi()) {
3278 int key_value = Smi::cast(*key)->value();
3279 if (key_value > 0
3280 && static_cast<uint32_t>(key_value) > max_element_index) {
3281 max_element_index = key_value;
3282 }
3283 elements++;
3284 }
3285
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003286 // Add name, value pair to the fixed array.
3287 constant_properties->set(position++, *key);
3288 constant_properties->set(position++, *value);
3289 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003290 *fast_elements =
3291 (max_element_index <= 32) || ((2 * elements) >= max_element_index);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003292 *is_simple = is_simple_acc;
3293 *depth = depth_acc;
3294}
3295
3296
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003297ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter,
3298 bool* ok) {
3299 // Special handling of getter and setter syntax:
3300 // { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... }
3301 // We have already read the "get" or "set" keyword.
3302 Token::Value next = Next();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003303 bool is_keyword = Token::IsKeyword(next);
3304 if (next == Token::IDENTIFIER || next == Token::NUMBER ||
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003305 next == Token::FUTURE_RESERVED_WORD ||
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003306 next == Token::STRING || is_keyword) {
3307 Handle<String> name;
3308 if (is_keyword) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003309 name = isolate_->factory()->LookupAsciiSymbol(Token::String(next));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003310 } else {
3311 name = GetSymbol(CHECK_OK);
3312 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003313 FunctionLiteral* value =
3314 ParseFunctionLiteral(name,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003315 false, // reserved words are allowed here
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003316 RelocInfo::kNoPosition,
3317 DECLARATION,
3318 CHECK_OK);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003319 // Allow any number of parameters for compatiabilty with JSC.
3320 // Specification only allows zero parameters for get and one for set.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003321 ObjectLiteral::Property* property =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003322 new(zone()) ObjectLiteral::Property(is_getter, value);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003323 return property;
3324 } else {
3325 ReportUnexpectedToken(next);
3326 *ok = false;
3327 return NULL;
3328 }
3329}
3330
3331
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003332Expression* Parser::ParseObjectLiteral(bool* ok) {
3333 // ObjectLiteral ::
3334 // '{' (
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003335 // ((IdentifierName | String | Number) ':' AssignmentExpression)
3336 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003337 // )*[','] '}'
3338
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003339 ZoneList<ObjectLiteral::Property*>* properties =
danno@chromium.org40cb8782011-05-25 07:58:50 +00003340 new(zone()) ZoneList<ObjectLiteral::Property*>(4);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003341 int number_of_boilerplate_properties = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003342 bool has_function = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003343
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003344 ObjectLiteralPropertyChecker checker(this, top_scope_->is_strict_mode());
ager@chromium.org378b34e2011-01-28 08:04:38 +00003345
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003346 Expect(Token::LBRACE, CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003347 Scanner::Location loc = scanner().location();
3348
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003349 while (peek() != Token::RBRACE) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003350 if (fni_ != NULL) fni_->Enter();
3351
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003352 Literal* key = NULL;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003353 Token::Value next = peek();
ager@chromium.org378b34e2011-01-28 08:04:38 +00003354
3355 // Location of the property name token
3356 Scanner::Location loc = scanner().peek_location();
3357
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003358 switch (next) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003359 case Token::FUTURE_RESERVED_WORD:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003360 case Token::IDENTIFIER: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003361 bool is_getter = false;
3362 bool is_setter = false;
3363 Handle<String> id =
3364 ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003365 if (fni_ != NULL) fni_->PushLiteralName(id);
3366
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003367 if ((is_getter || is_setter) && peek() != Token::COLON) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003368 // Update loc to point to the identifier
3369 loc = scanner().peek_location();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370 ObjectLiteral::Property* property =
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003371 ParseObjectLiteralGetSet(is_getter, CHECK_OK);
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003372 if (IsBoilerplateProperty(property)) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003373 number_of_boilerplate_properties++;
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003374 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003375 // Validate the property.
3376 checker.CheckProperty(property, loc, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003377 properties->Add(property);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003378 if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003379
3380 if (fni_ != NULL) {
3381 fni_->Infer();
3382 fni_->Leave();
3383 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003384 continue; // restart the while
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003385 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003386 // Failed to parse as get/set property, so it's just a property
3387 // called "get" or "set".
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003388 key = new(zone()) Literal(id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003389 break;
3390 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003391 case Token::STRING: {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003392 Consume(Token::STRING);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003393 Handle<String> string = GetSymbol(CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003394 if (fni_ != NULL) fni_->PushLiteralName(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003395 uint32_t index;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00003396 if (!string.is_null() && string->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003397 key = NewNumberLiteral(index);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003398 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003400 key = new(zone()) Literal(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 break;
3402 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003403 case Token::NUMBER: {
3404 Consume(Token::NUMBER);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003405 ASSERT(scanner().is_literal_ascii());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003406 double value = StringToDouble(isolate()->unicode_cache(),
3407 scanner().literal_ascii_string(),
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003408 ALLOW_HEX | ALLOW_OCTALS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409 key = NewNumberLiteral(value);
3410 break;
3411 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003412 default:
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003413 if (Token::IsKeyword(next)) {
3414 Consume(next);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003415 Handle<String> string = GetSymbol(CHECK_OK);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003416 key = new(zone()) Literal(string);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003417 } else {
3418 // Unexpected token.
3419 Token::Value next = Next();
3420 ReportUnexpectedToken(next);
3421 *ok = false;
3422 return NULL;
3423 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424 }
3425
3426 Expect(Token::COLON, CHECK_OK);
3427 Expression* value = ParseAssignmentExpression(true, CHECK_OK);
3428
3429 ObjectLiteral::Property* property =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003430 new(zone()) ObjectLiteral::Property(key, value);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003432 // Mark object literals that contain function literals and pretenure the
3433 // literal so it can be added as a constant function property.
3434 if (value->AsFunctionLiteral() != NULL) {
3435 has_function = true;
3436 value->AsFunctionLiteral()->set_pretenure(true);
3437 }
3438
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003439 // Count CONSTANT or COMPUTED properties to maintain the enumeration order.
ager@chromium.org236ad962008-09-25 09:45:57 +00003440 if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++;
ager@chromium.org378b34e2011-01-28 08:04:38 +00003441 // Validate the property
3442 checker.CheckProperty(property, loc, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003443 properties->Add(property);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003444
3445 // TODO(1240767): Consider allowing trailing comma.
3446 if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003447
3448 if (fni_ != NULL) {
3449 fni_->Infer();
3450 fni_->Leave();
3451 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003452 }
3453 Expect(Token::RBRACE, CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003454
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003455 // Computation of literal_index must happen before pre parse bailout.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003456 int literal_index = lexical_scope_->NextMaterializedLiteralIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003458 Handle<FixedArray> constant_properties = isolate()->factory()->NewFixedArray(
3459 number_of_boilerplate_properties * 2, TENURED);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003460
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003461 bool is_simple = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003462 bool fast_elements = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003463 int depth = 1;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003464 BuildObjectLiteralConstantProperties(properties,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003465 constant_properties,
3466 &is_simple,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003467 &fast_elements,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003468 &depth);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003469 return new(zone()) ObjectLiteral(constant_properties,
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003470 properties,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003471 literal_index,
3472 is_simple,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003473 fast_elements,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003474 depth,
3475 has_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003476}
3477
3478
3479Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003480 if (!scanner().ScanRegExpPattern(seen_equal)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003481 Next();
3482 ReportMessage("unterminated_regexp", Vector<const char*>::empty());
3483 *ok = false;
3484 return NULL;
3485 }
3486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003487 int literal_index = lexical_scope_->NextMaterializedLiteralIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003489 Handle<String> js_pattern = NextLiteralString(TENURED);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003490 scanner().ScanRegExpFlags();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003491 Handle<String> js_flags = NextLiteralString(TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003492 Next();
3493
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003494 return new(zone()) RegExpLiteral(js_pattern, js_flags, literal_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003495}
3496
3497
3498ZoneList<Expression*>* Parser::ParseArguments(bool* ok) {
3499 // Arguments ::
3500 // '(' (AssignmentExpression)*[','] ')'
3501
danno@chromium.org40cb8782011-05-25 07:58:50 +00003502 ZoneList<Expression*>* result = new(zone()) ZoneList<Expression*>(4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003503 Expect(Token::LPAREN, CHECK_OK);
3504 bool done = (peek() == Token::RPAREN);
3505 while (!done) {
3506 Expression* argument = ParseAssignmentExpression(true, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003507 result->Add(argument);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003508 if (result->length() > kMaxNumFunctionParameters) {
3509 ReportMessageAt(scanner().location(), "too_many_arguments",
3510 Vector<const char*>::empty());
3511 *ok = false;
3512 return NULL;
3513 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003514 done = (peek() == Token::RPAREN);
3515 if (!done) Expect(Token::COMMA, CHECK_OK);
3516 }
3517 Expect(Token::RPAREN, CHECK_OK);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003518 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003519}
3520
3521
3522FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003523 bool name_is_reserved,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003524 int function_token_position,
3525 FunctionLiteralType type,
3526 bool* ok) {
3527 // Function ::
3528 // '(' FormalParameterList? ')' '{' FunctionBody '}'
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003529 bool is_named = !var_name.is_null();
3530
3531 // The name associated with this function. If it's a function expression,
3532 // this is the actual function name, otherwise this is the name of the
3533 // variable declared and initialized with the function (expression). In
3534 // that case, we don't have a function name (it's empty).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003535 Handle<String> name =
3536 is_named ? var_name : isolate()->factory()->empty_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537 // The function name, if any.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003538 Handle<String> function_name = isolate()->factory()->empty_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003539 if (is_named && (type == EXPRESSION || type == NESTED)) {
3540 function_name = name;
3541 }
3542
3543 int num_parameters = 0;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003544 Scope* scope = NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003545 ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003546 int materialized_literal_count;
3547 int expected_property_count;
3548 int start_pos;
3549 int end_pos;
3550 bool only_simple_this_property_assignments;
3551 Handle<FixedArray> this_property_assignments;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003552 // Parse function body.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003553 { LexicalScope lexical_scope(this, scope, isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554 top_scope_->SetScopeName(name);
3555
3556 // FormalParameterList ::
3557 // '(' (Identifier)*[','] ')'
3558 Expect(Token::LPAREN, CHECK_OK);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003559 start_pos = scanner().location().beg_pos;
lrn@chromium.org1c092762011-05-09 09:42:16 +00003560 Scanner::Location name_loc = Scanner::Location::invalid();
3561 Scanner::Location dupe_loc = Scanner::Location::invalid();
3562 Scanner::Location reserved_loc = Scanner::Location::invalid();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003563
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003564 bool done = (peek() == Token::RPAREN);
3565 while (!done) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003566 bool is_reserved = false;
3567 Handle<String> param_name =
3568 ParseIdentifierOrReservedWord(&is_reserved, CHECK_OK);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003569
3570 // Store locations for possible future error reports.
3571 if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) {
3572 name_loc = scanner().location();
3573 }
3574 if (!dupe_loc.IsValid() && top_scope_->IsDeclared(param_name)) {
3575 dupe_loc = scanner().location();
3576 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003577 if (!reserved_loc.IsValid() && is_reserved) {
3578 reserved_loc = scanner().location();
3579 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003580
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003581 top_scope_->DeclareParameter(param_name);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003582 num_parameters++;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003583 if (num_parameters > kMaxNumFunctionParameters) {
3584 ReportMessageAt(scanner().location(), "too_many_parameters",
3585 Vector<const char*>::empty());
3586 *ok = false;
3587 return NULL;
3588 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003589 done = (peek() == Token::RPAREN);
3590 if (!done) Expect(Token::COMMA, CHECK_OK);
3591 }
3592 Expect(Token::RPAREN, CHECK_OK);
3593
3594 Expect(Token::LBRACE, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595
3596 // If we have a named function expression, we add a local variable
3597 // declaration to the body of the function with the name of the
3598 // function and let it refer to the function itself (closure).
3599 // NOTE: We create a proxy and resolve it here so that in the
3600 // future we can change the AST to only refer to VariableProxies
3601 // instead of Variables and Proxis as is the case now.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003602 if (!function_name.is_null() && function_name->length() > 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003603 Variable* fvar = top_scope_->DeclareFunctionVar(function_name);
3604 VariableProxy* fproxy =
3605 top_scope_->NewUnresolved(function_name, inside_with());
3606 fproxy->BindTo(fvar);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003607 body->Add(new(zone()) ExpressionStatement(
3608 new(zone()) Assignment(Token::INIT_CONST, fproxy,
3609 new(zone()) ThisFunction(),
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003610 RelocInfo::kNoPosition)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 }
3612
3613 // Determine if the function will be lazily compiled. The mode can
3614 // only be PARSE_LAZILY if the --lazy flag is true.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003615 bool is_lazily_compiled = (mode() == PARSE_LAZILY &&
3616 top_scope_->outer_scope()->is_global_scope() &&
3617 top_scope_->HasTrivialOuterContext() &&
3618 !parenthesized_function_);
3619 parenthesized_function_ = false; // The bit was set for this function only.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003621 int function_block_pos = scanner().location().beg_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 if (is_lazily_compiled && pre_data() != NULL) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003623 FunctionEntry entry = pre_data()->GetFunctionEntry(function_block_pos);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003624 if (!entry.is_valid()) {
3625 ReportInvalidPreparseData(name, CHECK_OK);
3626 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003627 end_pos = entry.end_pos();
3628 if (end_pos <= function_block_pos) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003629 // End position greater than end of stream is safe, and hard to check.
3630 ReportInvalidPreparseData(name, CHECK_OK);
3631 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003632 isolate()->counters()->total_preparse_skipped()->Increment(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003633 end_pos - function_block_pos);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003634 // Seek to position just before terminal '}'.
3635 scanner().SeekForward(end_pos - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003636 materialized_literal_count = entry.literal_count();
3637 expected_property_count = entry.property_count();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003638 if (entry.strict_mode()) top_scope_->EnableStrictMode();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00003639 only_simple_this_property_assignments = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003640 this_property_assignments = isolate()->factory()->empty_fixed_array();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003641 Expect(Token::RBRACE, CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 } else {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00003643 ParseSourceElements(body, Token::RBRACE, CHECK_OK);
3644
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003645 materialized_literal_count = lexical_scope.materialized_literal_count();
3646 expected_property_count = lexical_scope.expected_property_count();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00003647 only_simple_this_property_assignments =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003648 lexical_scope.only_simple_this_property_assignments();
3649 this_property_assignments = lexical_scope.this_property_assignments();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003650
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003651 Expect(Token::RBRACE, CHECK_OK);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003652 end_pos = scanner().location().end_pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 }
3654
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003655 // Validate strict mode.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003656 if (top_scope_->is_strict_mode()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003657 if (IsEvalOrArguments(name)) {
3658 int position = function_token_position != RelocInfo::kNoPosition
ager@chromium.org378b34e2011-01-28 08:04:38 +00003659 ? function_token_position
3660 : (start_pos > 0 ? start_pos - 1 : start_pos);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003661 Scanner::Location location = Scanner::Location(position, start_pos);
3662 ReportMessageAt(location,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003663 "strict_function_name", Vector<const char*>::empty());
3664 *ok = false;
3665 return NULL;
3666 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003667 if (name_loc.IsValid()) {
3668 ReportMessageAt(name_loc, "strict_param_name",
3669 Vector<const char*>::empty());
3670 *ok = false;
3671 return NULL;
3672 }
3673 if (dupe_loc.IsValid()) {
3674 ReportMessageAt(dupe_loc, "strict_param_dupe",
3675 Vector<const char*>::empty());
3676 *ok = false;
3677 return NULL;
3678 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003679 if (name_is_reserved) {
3680 int position = function_token_position != RelocInfo::kNoPosition
3681 ? function_token_position
3682 : (start_pos > 0 ? start_pos - 1 : start_pos);
3683 Scanner::Location location = Scanner::Location(position, start_pos);
3684 ReportMessageAt(location, "strict_reserved_word",
3685 Vector<const char*>::empty());
3686 *ok = false;
3687 return NULL;
3688 }
3689 if (reserved_loc.IsValid()) {
3690 ReportMessageAt(reserved_loc, "strict_reserved_word",
3691 Vector<const char*>::empty());
3692 *ok = false;
3693 return NULL;
3694 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003695 CheckOctalLiteral(start_pos, end_pos, CHECK_OK);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003696 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003697 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003698
3699 FunctionLiteral* function_literal =
3700 new(zone()) FunctionLiteral(name,
3701 scope,
3702 body,
3703 materialized_literal_count,
3704 expected_property_count,
3705 only_simple_this_property_assignments,
3706 this_property_assignments,
3707 num_parameters,
3708 start_pos,
3709 end_pos,
3710 (function_name->length() > 0));
3711 function_literal->set_function_token_position(function_token_position);
3712
3713 if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
3714 return function_literal;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715}
3716
3717
3718Expression* Parser::ParseV8Intrinsic(bool* ok) {
3719 // CallRuntime ::
3720 // '%' Identifier Arguments
3721
3722 Expect(Token::MOD, CHECK_OK);
3723 Handle<String> name = ParseIdentifier(CHECK_OK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003724 ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003725
3726 if (extension_ != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003727 // The extension structures are only accessible while parsing the
3728 // very first time not when reparsing because of lazy compilation.
3729 top_scope_->ForceEagerCompilation();
3730 }
3731
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003732 const Runtime::Function* function = Runtime::FunctionForSymbol(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003733
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003734 // Check for built-in IS_VAR macro.
3735 if (function != NULL &&
3736 function->intrinsic_type == Runtime::RUNTIME &&
3737 function->function_id == Runtime::kIS_VAR) {
3738 // %IS_VAR(x) evaluates to x if x is a variable,
3739 // leads to a parse error otherwise. Could be implemented as an
3740 // inline function %_IS_VAR(x) to eliminate this special case.
3741 if (args->length() == 1 && args->at(0)->AsVariableProxy() != NULL) {
3742 return args->at(0);
3743 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003744 ReportMessage("unable_to_parse", Vector<const char*>::empty());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003745 *ok = false;
3746 return NULL;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00003747 }
3748 }
3749
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003750 // Check that the expected number of arguments are being passed.
3751 if (function != NULL &&
3752 function->nargs != -1 &&
3753 function->nargs != args->length()) {
3754 ReportMessage("illegal_access", Vector<const char*>::empty());
3755 *ok = false;
3756 return NULL;
3757 }
3758
3759 // We have a valid intrinsics call or a call to a builtin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003760 return new(zone()) CallRuntime(name, function, args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003761}
3762
3763
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003764bool Parser::peek_any_identifier() {
3765 Token::Value next = peek();
3766 return next == Token::IDENTIFIER ||
3767 next == Token::FUTURE_RESERVED_WORD;
3768}
3769
3770
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771void Parser::Consume(Token::Value token) {
3772 Token::Value next = Next();
3773 USE(next);
3774 USE(token);
3775 ASSERT(next == token);
3776}
3777
3778
3779void Parser::Expect(Token::Value token, bool* ok) {
3780 Token::Value next = Next();
3781 if (next == token) return;
3782 ReportUnexpectedToken(next);
3783 *ok = false;
3784}
3785
3786
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003787bool Parser::Check(Token::Value token) {
3788 Token::Value next = peek();
3789 if (next == token) {
3790 Consume(next);
3791 return true;
3792 }
3793 return false;
3794}
3795
3796
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003797void Parser::ExpectSemicolon(bool* ok) {
3798 // Check for automatic semicolon insertion according to
3799 // the rules given in ECMA-262, section 7.9, page 21.
3800 Token::Value tok = peek();
3801 if (tok == Token::SEMICOLON) {
3802 Next();
3803 return;
3804 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003805 if (scanner().has_line_terminator_before_next() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003806 tok == Token::RBRACE ||
3807 tok == Token::EOS) {
3808 return;
3809 }
3810 Expect(Token::SEMICOLON, ok);
3811}
3812
3813
3814Literal* Parser::GetLiteralUndefined() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003815 return new(zone()) Literal(isolate()->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003816}
3817
3818
3819Literal* Parser::GetLiteralTheHole() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003820 return new(zone()) Literal(isolate()->factory()->the_hole_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003821}
3822
3823
3824Literal* Parser::GetLiteralNumber(double value) {
3825 return NewNumberLiteral(value);
3826}
3827
3828
3829Handle<String> Parser::ParseIdentifier(bool* ok) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003830 bool is_reserved;
3831 return ParseIdentifierOrReservedWord(&is_reserved, ok);
3832}
3833
3834
3835Handle<String> Parser::ParseIdentifierOrReservedWord(bool* is_reserved,
3836 bool* ok) {
3837 *is_reserved = false;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003838 if (top_scope_->is_strict_mode()) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003839 Expect(Token::IDENTIFIER, ok);
3840 } else {
3841 if (!Check(Token::IDENTIFIER)) {
3842 Expect(Token::FUTURE_RESERVED_WORD, ok);
3843 *is_reserved = true;
3844 }
3845 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003846 if (!*ok) return Handle<String>();
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003847 return GetSymbol(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003848}
3849
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003850
3851Handle<String> Parser::ParseIdentifierName(bool* ok) {
3852 Token::Value next = Next();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003853 if (next != Token::IDENTIFIER &&
3854 next != Token::FUTURE_RESERVED_WORD &&
3855 !Token::IsKeyword(next)) {
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003856 ReportUnexpectedToken(next);
3857 *ok = false;
3858 return Handle<String>();
3859 }
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003860 return GetSymbol(ok);
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003861}
3862
ager@chromium.org378b34e2011-01-28 08:04:38 +00003863
3864// Checks LHS expression for assignment and prefix/postfix increment/decrement
3865// in strict mode.
3866void Parser::CheckStrictModeLValue(Expression* expression,
3867 const char* error,
3868 bool* ok) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003869 ASSERT(top_scope_->is_strict_mode());
ager@chromium.org378b34e2011-01-28 08:04:38 +00003870 VariableProxy* lhs = expression != NULL
3871 ? expression->AsVariableProxy()
3872 : NULL;
3873
3874 if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
3875 ReportMessage(error, Vector<const char*>::empty());
3876 *ok = false;
3877 }
3878}
3879
3880
lrn@chromium.org1c092762011-05-09 09:42:16 +00003881// Checks whether an octal literal was last seen between beg_pos and end_pos.
3882// If so, reports an error. Only called for strict mode.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003883void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00003884 Scanner::Location octal = scanner().octal_position();
3885 if (octal.IsValid() &&
3886 beg_pos <= octal.beg_pos &&
3887 octal.end_pos <= end_pos) {
3888 ReportMessageAt(octal, "strict_octal_literal",
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003889 Vector<const char*>::empty());
3890 scanner().clear_octal_position();
3891 *ok = false;
3892 }
3893}
3894
sgjesse@chromium.orgd3b3be02010-08-06 08:09:27 +00003895
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003896// This function reads an identifier and determines whether or not it
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003897// is 'get' or 'set'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003898Handle<String> Parser::ParseIdentifierOrGetOrSet(bool* is_get,
3899 bool* is_set,
3900 bool* ok) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003901 Handle<String> result = ParseIdentifier(ok);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003902 if (!*ok) return Handle<String>();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003903 if (scanner().is_literal_ascii() && scanner().literal_length() == 3) {
3904 const char* token = scanner().literal_ascii_string().start();
3905 *is_get = strncmp(token, "get", 3) == 0;
3906 *is_set = !*is_get && strncmp(token, "set", 3) == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003907 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003908 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003909}
3910
3911
3912// ----------------------------------------------------------------------------
3913// Parser support
3914
3915
3916bool Parser::TargetStackContainsLabel(Handle<String> label) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003917 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
3918 BreakableStatement* stat = t->node()->AsBreakableStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003919 if (stat != NULL && ContainsLabel(stat->labels(), label))
3920 return true;
3921 }
3922 return false;
3923}
3924
3925
3926BreakableStatement* Parser::LookupBreakTarget(Handle<String> label, bool* ok) {
3927 bool anonymous = label.is_null();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003928 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
3929 BreakableStatement* stat = t->node()->AsBreakableStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003930 if (stat == NULL) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003931 if ((anonymous && stat->is_target_for_anonymous()) ||
3932 (!anonymous && ContainsLabel(stat->labels(), label))) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003933 RegisterTargetUse(stat->break_target(), t->previous());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003934 return stat;
3935 }
3936 }
3937 return NULL;
3938}
3939
3940
3941IterationStatement* Parser::LookupContinueTarget(Handle<String> label,
3942 bool* ok) {
3943 bool anonymous = label.is_null();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003944 for (Target* t = target_stack_; t != NULL; t = t->previous()) {
3945 IterationStatement* stat = t->node()->AsIterationStatement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 if (stat == NULL) continue;
3947
3948 ASSERT(stat->is_target_for_anonymous());
3949 if (anonymous || ContainsLabel(stat->labels(), label)) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003950 RegisterTargetUse(stat->continue_target(), t->previous());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003951 return stat;
3952 }
3953 }
3954 return NULL;
3955}
3956
3957
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003958void Parser::RegisterTargetUse(Label* target, Target* stop) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003959 // Register that a break target found at the given stop in the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003960 // target stack has been used from the top of the target stack. Add
3961 // the break target to any TargetCollectors passed on the stack.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003962 for (Target* t = target_stack_; t != stop; t = t->previous()) {
3963 TargetCollector* collector = t->node()->AsTargetCollector();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003964 if (collector != NULL) collector->AddTarget(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 }
3966}
3967
3968
3969Literal* Parser::NewNumberLiteral(double number) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003970 return new(zone()) Literal(isolate()->factory()->NewNumber(number, TENURED));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971}
3972
3973
3974Expression* Parser::NewThrowReferenceError(Handle<String> type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003975 return NewThrowError(isolate()->factory()->MakeReferenceError_symbol(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003976 type, HandleVector<Object>(NULL, 0));
3977}
3978
3979
3980Expression* Parser::NewThrowSyntaxError(Handle<String> type,
3981 Handle<Object> first) {
3982 int argc = first.is_null() ? 0 : 1;
3983 Vector< Handle<Object> > arguments = HandleVector<Object>(&first, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003984 return NewThrowError(
3985 isolate()->factory()->MakeSyntaxError_symbol(), type, arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986}
3987
3988
3989Expression* Parser::NewThrowTypeError(Handle<String> type,
3990 Handle<Object> first,
3991 Handle<Object> second) {
3992 ASSERT(!first.is_null() && !second.is_null());
3993 Handle<Object> elements[] = { first, second };
3994 Vector< Handle<Object> > arguments =
3995 HandleVector<Object>(elements, ARRAY_SIZE(elements));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 return NewThrowError(
3997 isolate()->factory()->MakeTypeError_symbol(), type, arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998}
3999
4000
4001Expression* Parser::NewThrowError(Handle<String> constructor,
4002 Handle<String> type,
4003 Vector< Handle<Object> > arguments) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004 int argc = arguments.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004005 Handle<FixedArray> elements = isolate()->factory()->NewFixedArray(argc,
4006 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004007 for (int i = 0; i < argc; i++) {
4008 Handle<Object> element = arguments[i];
4009 if (!element.is_null()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004010 elements->set(i, *element);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011 }
4012 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004013 Handle<JSArray> array = isolate()->factory()->NewJSArrayWithElements(elements,
4014 TENURED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004015
danno@chromium.org40cb8782011-05-25 07:58:50 +00004016 ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004017 args->Add(new(zone()) Literal(type));
4018 args->Add(new(zone()) Literal(array));
4019 return new(zone()) Throw(new(zone()) CallRuntime(constructor, NULL, args),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 scanner().location().beg_pos);
4021}
4022
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004023// ----------------------------------------------------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004024// Regular expressions
4025
4026
4027RegExpParser::RegExpParser(FlatStringReader* in,
4028 Handle<String>* error,
4029 bool multiline)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004030 : isolate_(Isolate::Current()),
4031 error_(error),
4032 captures_(NULL),
4033 in_(in),
4034 current_(kEndMarker),
4035 next_pos_(0),
4036 capture_count_(0),
4037 has_more_(true),
4038 multiline_(multiline),
4039 simple_(false),
4040 contains_anchor_(false),
4041 is_scanned_for_captures_(false),
4042 failed_(false) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00004043 Advance();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004044}
4045
4046
4047uc32 RegExpParser::Next() {
4048 if (has_next()) {
4049 return in()->Get(next_pos_);
4050 } else {
4051 return kEndMarker;
4052 }
4053}
4054
4055
4056void RegExpParser::Advance() {
4057 if (next_pos_ < in()->length()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004058 StackLimitCheck check(isolate());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004059 if (check.HasOverflowed()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004060 ReportError(CStrVector(Isolate::kStackOverflowMessage));
4061 } else if (isolate()->zone()->excess_allocation()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004062 ReportError(CStrVector("Regular expression too large"));
4063 } else {
4064 current_ = in()->Get(next_pos_);
4065 next_pos_++;
4066 }
4067 } else {
4068 current_ = kEndMarker;
4069 has_more_ = false;
4070 }
4071}
4072
4073
4074void RegExpParser::Reset(int pos) {
4075 next_pos_ = pos;
4076 Advance();
4077}
4078
4079
4080void RegExpParser::Advance(int dist) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00004081 next_pos_ += dist - 1;
4082 Advance();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004083}
4084
4085
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004086bool RegExpParser::simple() {
4087 return simple_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004088}
4089
4090RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
4091 failed_ = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004092 *error_ = isolate()->factory()->NewStringFromAscii(message, NOT_TENURED);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004093 // Zip to the end to make sure the no more input is read.
4094 current_ = kEndMarker;
4095 next_pos_ = in()->length();
4096 return NULL;
4097}
4098
4099
4100// Pattern ::
4101// Disjunction
4102RegExpTree* RegExpParser::ParsePattern() {
4103 RegExpTree* result = ParseDisjunction(CHECK_FAILED);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004104 ASSERT(!has_more());
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004105 // If the result of parsing is a literal string atom, and it has the
4106 // same length as the input, then the atom is identical to the input.
4107 if (result->IsAtom() && result->AsAtom()->length() == in()->length()) {
4108 simple_ = true;
4109 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004110 return result;
4111}
4112
4113
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004114// Disjunction ::
4115// Alternative
4116// Alternative | Disjunction
4117// Alternative ::
4118// [empty]
4119// Term Alternative
4120// Term ::
4121// Assertion
4122// Atom
4123// Atom Quantifier
4124RegExpTree* RegExpParser::ParseDisjunction() {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004125 // Used to store current state while parsing subexpressions.
4126 RegExpParserState initial_state(NULL, INITIAL, 0);
4127 RegExpParserState* stored_state = &initial_state;
4128 // Cache the builder in a local variable for quick access.
4129 RegExpBuilder* builder = initial_state.builder();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004130 while (true) {
4131 switch (current()) {
4132 case kEndMarker:
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004133 if (stored_state->IsSubexpression()) {
4134 // Inside a parenthesized group when hitting end of input.
4135 ReportError(CStrVector("Unterminated group") CHECK_FAILED);
4136 }
4137 ASSERT_EQ(INITIAL, stored_state->group_type());
4138 // Parsing completed successfully.
4139 return builder->ToRegExp();
4140 case ')': {
4141 if (!stored_state->IsSubexpression()) {
4142 ReportError(CStrVector("Unmatched ')'") CHECK_FAILED);
4143 }
4144 ASSERT_NE(INITIAL, stored_state->group_type());
4145
4146 Advance();
4147 // End disjunction parsing and convert builder content to new single
4148 // regexp atom.
4149 RegExpTree* body = builder->ToRegExp();
4150
4151 int end_capture_index = captures_started();
4152
4153 int capture_index = stored_state->capture_index();
4154 SubexpressionType type = stored_state->group_type();
4155
4156 // Restore previous state.
4157 stored_state = stored_state->previous_state();
4158 builder = stored_state->builder();
4159
4160 // Build result of subexpression.
4161 if (type == CAPTURE) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004162 RegExpCapture* capture = new(zone()) RegExpCapture(body, capture_index);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004163 captures_->at(capture_index - 1) = capture;
4164 body = capture;
4165 } else if (type != GROUPING) {
4166 ASSERT(type == POSITIVE_LOOKAHEAD || type == NEGATIVE_LOOKAHEAD);
4167 bool is_positive = (type == POSITIVE_LOOKAHEAD);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004168 body = new(zone()) RegExpLookahead(body,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004169 is_positive,
4170 end_capture_index - capture_index,
4171 capture_index);
4172 }
4173 builder->AddAtom(body);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004174 // For compatability with JSC and ES3, we allow quantifiers after
4175 // lookaheads, and break in all cases.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004176 break;
4177 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004178 case '|': {
4179 Advance();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004180 builder->NewAlternative();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004181 continue;
4182 }
4183 case '*':
4184 case '+':
4185 case '?':
kasperl@chromium.orge959c182009-07-27 08:59:04 +00004186 return ReportError(CStrVector("Nothing to repeat"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004187 case '^': {
4188 Advance();
iposva@chromium.org245aa852009-02-10 00:49:54 +00004189 if (multiline_) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004190 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004191 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_LINE));
iposva@chromium.org245aa852009-02-10 00:49:54 +00004192 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004193 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004194 new(zone()) RegExpAssertion(RegExpAssertion::START_OF_INPUT));
iposva@chromium.org245aa852009-02-10 00:49:54 +00004195 set_contains_anchor();
4196 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004197 continue;
4198 }
4199 case '$': {
4200 Advance();
4201 RegExpAssertion::Type type =
4202 multiline_ ? RegExpAssertion::END_OF_LINE :
4203 RegExpAssertion::END_OF_INPUT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004204 builder->AddAssertion(new(zone()) RegExpAssertion(type));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004205 continue;
4206 }
4207 case '.': {
4208 Advance();
4209 // everything except \x0a, \x0d, \u2028 and \u2029
danno@chromium.org40cb8782011-05-25 07:58:50 +00004210 ZoneList<CharacterRange>* ranges =
4211 new(zone()) ZoneList<CharacterRange>(2);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004212 CharacterRange::AddClassEscape('.', ranges);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004213 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004214 builder->AddAtom(atom);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004215 break;
4216 }
4217 case '(': {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004218 SubexpressionType type = CAPTURE;
4219 Advance();
4220 if (current() == '?') {
4221 switch (Next()) {
4222 case ':':
4223 type = GROUPING;
4224 break;
4225 case '=':
4226 type = POSITIVE_LOOKAHEAD;
4227 break;
4228 case '!':
4229 type = NEGATIVE_LOOKAHEAD;
4230 break;
4231 default:
4232 ReportError(CStrVector("Invalid group") CHECK_FAILED);
4233 break;
4234 }
4235 Advance(2);
4236 } else {
4237 if (captures_ == NULL) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004238 captures_ = new(zone()) ZoneList<RegExpCapture*>(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004239 }
4240 if (captures_started() >= kMaxCaptures) {
4241 ReportError(CStrVector("Too many captures") CHECK_FAILED);
4242 }
4243 captures_->Add(NULL);
4244 }
4245 // Store current state and begin new disjunction parsing.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004246 stored_state = new(zone()) RegExpParserState(stored_state,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004247 type,
4248 captures_started());
4249 builder = stored_state->builder();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004250 continue;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004251 }
4252 case '[': {
4253 RegExpTree* atom = ParseCharacterClass(CHECK_FAILED);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004254 builder->AddAtom(atom);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004255 break;
4256 }
4257 // Atom ::
4258 // \ AtomEscape
4259 case '\\':
4260 switch (Next()) {
4261 case kEndMarker:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00004262 return ReportError(CStrVector("\\ at end of pattern"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004263 case 'b':
4264 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004265 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004266 new(zone()) RegExpAssertion(RegExpAssertion::BOUNDARY));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004267 continue;
4268 case 'B':
4269 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004270 builder->AddAssertion(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004271 new(zone()) RegExpAssertion(RegExpAssertion::NON_BOUNDARY));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004272 continue;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004273 // AtomEscape ::
4274 // CharacterClassEscape
4275 //
4276 // CharacterClassEscape :: one of
4277 // d D s S w W
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004278 case 'd': case 'D': case 's': case 'S': case 'w': case 'W': {
4279 uc32 c = Next();
4280 Advance(2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004281 ZoneList<CharacterRange>* ranges =
4282 new(zone()) ZoneList<CharacterRange>(2);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004283 CharacterRange::AddClassEscape(c, ranges);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004284 RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004285 builder->AddAtom(atom);
4286 break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004287 }
4288 case '1': case '2': case '3': case '4': case '5': case '6':
4289 case '7': case '8': case '9': {
4290 int index = 0;
4291 if (ParseBackReferenceIndex(&index)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004292 RegExpCapture* capture = NULL;
4293 if (captures_ != NULL && index <= captures_->length()) {
4294 capture = captures_->at(index - 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004295 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004296 if (capture == NULL) {
4297 builder->AddEmpty();
4298 break;
4299 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004300 RegExpTree* atom = new(zone()) RegExpBackReference(capture);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004301 builder->AddAtom(atom);
4302 break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004303 }
4304 uc32 first_digit = Next();
4305 if (first_digit == '8' || first_digit == '9') {
4306 // Treat as identity escape
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004307 builder->AddCharacter(first_digit);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004308 Advance(2);
4309 break;
4310 }
4311 }
4312 // FALLTHROUGH
4313 case '0': {
4314 Advance();
4315 uc32 octal = ParseOctalLiteral();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004316 builder->AddCharacter(octal);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004317 break;
4318 }
4319 // ControlEscape :: one of
4320 // f n r t v
4321 case 'f':
4322 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004323 builder->AddCharacter('\f');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004324 break;
4325 case 'n':
4326 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004327 builder->AddCharacter('\n');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004328 break;
4329 case 'r':
4330 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004331 builder->AddCharacter('\r');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004332 break;
4333 case 't':
4334 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004335 builder->AddCharacter('\t');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004336 break;
4337 case 'v':
4338 Advance(2);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004339 builder->AddCharacter('\v');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004340 break;
4341 case 'c': {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004342 Advance();
4343 uc32 controlLetter = Next();
4344 // Special case if it is an ASCII letter.
4345 // Convert lower case letters to uppercase.
4346 uc32 letter = controlLetter & ~('a' ^ 'A');
4347 if (letter < 'A' || 'Z' < letter) {
4348 // controlLetter is not in range 'A'-'Z' or 'a'-'z'.
4349 // This is outside the specification. We match JSC in
4350 // reading the backslash as a literal character instead
4351 // of as starting an escape.
4352 builder->AddCharacter('\\');
4353 } else {
4354 Advance(2);
4355 builder->AddCharacter(controlLetter & 0x1f);
4356 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004357 break;
4358 }
4359 case 'x': {
4360 Advance(2);
4361 uc32 value;
4362 if (ParseHexEscape(2, &value)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004363 builder->AddCharacter(value);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004364 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004365 builder->AddCharacter('x');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004366 }
4367 break;
4368 }
4369 case 'u': {
4370 Advance(2);
4371 uc32 value;
4372 if (ParseHexEscape(4, &value)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004373 builder->AddCharacter(value);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004374 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004375 builder->AddCharacter('u');
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004376 }
4377 break;
4378 }
4379 default:
4380 // Identity escape.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004381 builder->AddCharacter(Next());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004382 Advance(2);
4383 break;
4384 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004385 break;
4386 case '{': {
4387 int dummy;
4388 if (ParseIntervalQuantifier(&dummy, &dummy)) {
4389 ReportError(CStrVector("Nothing to repeat") CHECK_FAILED);
4390 }
4391 // fallthrough
4392 }
4393 default:
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004394 builder->AddCharacter(current());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004395 Advance();
4396 break;
4397 } // end switch(current())
4398
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004399 int min;
4400 int max;
4401 switch (current()) {
4402 // QuantifierPrefix ::
4403 // *
4404 // +
4405 // ?
4406 // {
4407 case '*':
4408 min = 0;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004409 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004410 Advance();
4411 break;
4412 case '+':
4413 min = 1;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004414 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004415 Advance();
4416 break;
4417 case '?':
4418 min = 0;
4419 max = 1;
4420 Advance();
4421 break;
4422 case '{':
4423 if (ParseIntervalQuantifier(&min, &max)) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00004424 if (max < min) {
4425 ReportError(CStrVector("numbers out of order in {} quantifier.")
4426 CHECK_FAILED);
4427 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004428 break;
4429 } else {
4430 continue;
4431 }
4432 default:
4433 continue;
4434 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004435 RegExpQuantifier::Type type = RegExpQuantifier::GREEDY;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004436 if (current() == '?') {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004437 type = RegExpQuantifier::NON_GREEDY;
4438 Advance();
4439 } else if (FLAG_regexp_possessive_quantifier && current() == '+') {
4440 // FLAG_regexp_possessive_quantifier is a debug-only flag.
4441 type = RegExpQuantifier::POSSESSIVE;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004442 Advance();
4443 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004444 builder->AddQuantifierToAtom(min, max, type);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004445 }
4446}
4447
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004448
4449#ifdef DEBUG
4450// Currently only used in an ASSERT.
4451static bool IsSpecialClassEscape(uc32 c) {
4452 switch (c) {
4453 case 'd': case 'D':
4454 case 's': case 'S':
4455 case 'w': case 'W':
4456 return true;
4457 default:
4458 return false;
4459 }
4460}
4461#endif
4462
4463
4464// In order to know whether an escape is a backreference or not we have to scan
4465// the entire regexp and find the number of capturing parentheses. However we
4466// don't want to scan the regexp twice unless it is necessary. This mini-parser
4467// is called when needed. It can see the difference between capturing and
4468// noncapturing parentheses and can skip character classes and backslash-escaped
4469// characters.
4470void RegExpParser::ScanForCaptures() {
4471 // Start with captures started previous to current position
4472 int capture_count = captures_started();
4473 // Add count of captures after this position.
4474 int n;
4475 while ((n = current()) != kEndMarker) {
4476 Advance();
4477 switch (n) {
4478 case '\\':
4479 Advance();
4480 break;
4481 case '[': {
4482 int c;
4483 while ((c = current()) != kEndMarker) {
4484 Advance();
4485 if (c == '\\') {
4486 Advance();
4487 } else {
4488 if (c == ']') break;
4489 }
4490 }
4491 break;
4492 }
4493 case '(':
4494 if (current() != '?') capture_count++;
4495 break;
4496 }
4497 }
4498 capture_count_ = capture_count;
4499 is_scanned_for_captures_ = true;
4500}
4501
4502
4503bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
4504 ASSERT_EQ('\\', current());
4505 ASSERT('1' <= Next() && Next() <= '9');
iposva@chromium.org245aa852009-02-10 00:49:54 +00004506 // Try to parse a decimal literal that is no greater than the total number
4507 // of left capturing parentheses in the input.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004508 int start = position();
4509 int value = Next() - '0';
4510 Advance(2);
4511 while (true) {
4512 uc32 c = current();
4513 if (IsDecimalDigit(c)) {
4514 value = 10 * value + (c - '0');
iposva@chromium.org245aa852009-02-10 00:49:54 +00004515 if (value > kMaxCaptures) {
4516 Reset(start);
4517 return false;
4518 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004519 Advance();
4520 } else {
4521 break;
4522 }
4523 }
4524 if (value > captures_started()) {
4525 if (!is_scanned_for_captures_) {
4526 int saved_position = position();
4527 ScanForCaptures();
4528 Reset(saved_position);
4529 }
4530 if (value > capture_count_) {
4531 Reset(start);
4532 return false;
4533 }
4534 }
4535 *index_out = value;
4536 return true;
4537}
4538
4539
4540// QuantifierPrefix ::
4541// { DecimalDigits }
4542// { DecimalDigits , }
4543// { DecimalDigits , DecimalDigits }
iposva@chromium.org245aa852009-02-10 00:49:54 +00004544//
4545// Returns true if parsing succeeds, and set the min_out and max_out
4546// values. Values are truncated to RegExpTree::kInfinity if they overflow.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004547bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) {
4548 ASSERT_EQ(current(), '{');
4549 int start = position();
4550 Advance();
4551 int min = 0;
4552 if (!IsDecimalDigit(current())) {
4553 Reset(start);
4554 return false;
4555 }
4556 while (IsDecimalDigit(current())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00004557 int next = current() - '0';
4558 if (min > (RegExpTree::kInfinity - next) / 10) {
4559 // Overflow. Skip past remaining decimal digits and return -1.
4560 do {
4561 Advance();
4562 } while (IsDecimalDigit(current()));
4563 min = RegExpTree::kInfinity;
4564 break;
4565 }
4566 min = 10 * min + next;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004567 Advance();
4568 }
4569 int max = 0;
4570 if (current() == '}') {
4571 max = min;
4572 Advance();
4573 } else if (current() == ',') {
4574 Advance();
4575 if (current() == '}') {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004576 max = RegExpTree::kInfinity;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004577 Advance();
4578 } else {
4579 while (IsDecimalDigit(current())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00004580 int next = current() - '0';
4581 if (max > (RegExpTree::kInfinity - next) / 10) {
4582 do {
4583 Advance();
4584 } while (IsDecimalDigit(current()));
4585 max = RegExpTree::kInfinity;
4586 break;
4587 }
4588 max = 10 * max + next;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004589 Advance();
4590 }
4591 if (current() != '}') {
4592 Reset(start);
4593 return false;
4594 }
4595 Advance();
4596 }
4597 } else {
4598 Reset(start);
4599 return false;
4600 }
4601 *min_out = min;
4602 *max_out = max;
4603 return true;
4604}
4605
4606
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004607uc32 RegExpParser::ParseOctalLiteral() {
4608 ASSERT('0' <= current() && current() <= '7');
4609 // For compatibility with some other browsers (not all), we parse
4610 // up to three octal digits with a value below 256.
4611 uc32 value = current() - '0';
4612 Advance();
4613 if ('0' <= current() && current() <= '7') {
4614 value = value * 8 + current() - '0';
4615 Advance();
4616 if (value < 32 && '0' <= current() && current() <= '7') {
4617 value = value * 8 + current() - '0';
4618 Advance();
4619 }
4620 }
4621 return value;
4622}
4623
4624
4625bool RegExpParser::ParseHexEscape(int length, uc32 *value) {
4626 int start = position();
4627 uc32 val = 0;
4628 bool done = false;
4629 for (int i = 0; !done; i++) {
4630 uc32 c = current();
4631 int d = HexValue(c);
4632 if (d < 0) {
4633 Reset(start);
4634 return false;
4635 }
4636 val = val * 16 + d;
4637 Advance();
4638 if (i == length - 1) {
4639 done = true;
4640 }
4641 }
4642 *value = val;
4643 return true;
4644}
4645
4646
4647uc32 RegExpParser::ParseClassCharacterEscape() {
4648 ASSERT(current() == '\\');
4649 ASSERT(has_next() && !IsSpecialClassEscape(Next()));
4650 Advance();
4651 switch (current()) {
4652 case 'b':
4653 Advance();
4654 return '\b';
4655 // ControlEscape :: one of
4656 // f n r t v
4657 case 'f':
4658 Advance();
4659 return '\f';
4660 case 'n':
4661 Advance();
4662 return '\n';
4663 case 'r':
4664 Advance();
4665 return '\r';
4666 case 't':
4667 Advance();
4668 return '\t';
4669 case 'v':
4670 Advance();
4671 return '\v';
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004672 case 'c': {
4673 uc32 controlLetter = Next();
4674 uc32 letter = controlLetter & ~('A' ^ 'a');
4675 // For compatibility with JSC, inside a character class
4676 // we also accept digits and underscore as control characters.
4677 if ((controlLetter >= '0' && controlLetter <= '9') ||
4678 controlLetter == '_' ||
4679 (letter >= 'A' && letter <= 'Z')) {
4680 Advance(2);
4681 // Control letters mapped to ASCII control characters in the range
4682 // 0x00-0x1f.
4683 return controlLetter & 0x1f;
4684 }
4685 // We match JSC in reading the backslash as a literal
4686 // character instead of as starting an escape.
4687 return '\\';
4688 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004689 case '0': case '1': case '2': case '3': case '4': case '5':
4690 case '6': case '7':
4691 // For compatibility, we interpret a decimal escape that isn't
4692 // a back reference (and therefore either \0 or not valid according
4693 // to the specification) as a 1..3 digit octal character code.
4694 return ParseOctalLiteral();
4695 case 'x': {
4696 Advance();
4697 uc32 value;
4698 if (ParseHexEscape(2, &value)) {
4699 return value;
4700 }
4701 // If \x is not followed by a two-digit hexadecimal, treat it
4702 // as an identity escape.
4703 return 'x';
4704 }
4705 case 'u': {
4706 Advance();
4707 uc32 value;
4708 if (ParseHexEscape(4, &value)) {
4709 return value;
4710 }
4711 // If \u is not followed by a four-digit hexadecimal, treat it
4712 // as an identity escape.
4713 return 'u';
4714 }
4715 default: {
4716 // Extended identity escape. We accept any character that hasn't
4717 // been matched by a more specific case, not just the subset required
4718 // by the ECMAScript specification.
4719 uc32 result = current();
4720 Advance();
4721 return result;
4722 }
4723 }
4724 return 0;
4725}
4726
4727
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004728CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) {
4729 ASSERT_EQ(0, *char_class);
4730 uc32 first = current();
4731 if (first == '\\') {
4732 switch (Next()) {
4733 case 'w': case 'W': case 'd': case 'D': case 's': case 'S': {
4734 *char_class = Next();
4735 Advance(2);
4736 return CharacterRange::Singleton(0); // Return dummy value.
4737 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004738 case kEndMarker:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00004739 return ReportError(CStrVector("\\ at end of pattern"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004740 default:
4741 uc32 c = ParseClassCharacterEscape(CHECK_FAILED);
4742 return CharacterRange::Singleton(c);
4743 }
4744 } else {
4745 Advance();
4746 return CharacterRange::Singleton(first);
4747 }
4748}
4749
4750
lrn@chromium.org14a70352010-12-15 12:43:21 +00004751static const uc16 kNoCharClass = 0;
4752
4753// Adds range or pre-defined character class to character ranges.
4754// If char_class is not kInvalidClass, it's interpreted as a class
4755// escape (i.e., 's' means whitespace, from '\s').
4756static inline void AddRangeOrEscape(ZoneList<CharacterRange>* ranges,
4757 uc16 char_class,
4758 CharacterRange range) {
4759 if (char_class != kNoCharClass) {
4760 CharacterRange::AddClassEscape(char_class, ranges);
4761 } else {
4762 ranges->Add(range);
4763 }
4764}
4765
4766
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004767RegExpTree* RegExpParser::ParseCharacterClass() {
4768 static const char* kUnterminated = "Unterminated character class";
4769 static const char* kRangeOutOfOrder = "Range out of order in character class";
4770
4771 ASSERT_EQ(current(), '[');
4772 Advance();
4773 bool is_negated = false;
4774 if (current() == '^') {
4775 is_negated = true;
4776 Advance();
4777 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004778 ZoneList<CharacterRange>* ranges = new(zone()) ZoneList<CharacterRange>(2);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004779 while (has_more() && current() != ']') {
lrn@chromium.org14a70352010-12-15 12:43:21 +00004780 uc16 char_class = kNoCharClass;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004781 CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004782 if (current() == '-') {
4783 Advance();
4784 if (current() == kEndMarker) {
4785 // If we reach the end we break out of the loop and let the
4786 // following code report an error.
4787 break;
4788 } else if (current() == ']') {
lrn@chromium.org14a70352010-12-15 12:43:21 +00004789 AddRangeOrEscape(ranges, char_class, first);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004790 ranges->Add(CharacterRange::Singleton('-'));
4791 break;
4792 }
lrn@chromium.org14a70352010-12-15 12:43:21 +00004793 uc16 char_class_2 = kNoCharClass;
4794 CharacterRange next = ParseClassAtom(&char_class_2 CHECK_FAILED);
4795 if (char_class != kNoCharClass || char_class_2 != kNoCharClass) {
4796 // Either end is an escaped character class. Treat the '-' verbatim.
4797 AddRangeOrEscape(ranges, char_class, first);
4798 ranges->Add(CharacterRange::Singleton('-'));
4799 AddRangeOrEscape(ranges, char_class_2, next);
4800 continue;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004801 }
4802 if (first.from() > next.to()) {
4803 return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED);
4804 }
4805 ranges->Add(CharacterRange::Range(first.from(), next.to()));
4806 } else {
lrn@chromium.org14a70352010-12-15 12:43:21 +00004807 AddRangeOrEscape(ranges, char_class, first);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004808 }
4809 }
4810 if (!has_more()) {
4811 return ReportError(CStrVector(kUnterminated) CHECK_FAILED);
4812 }
4813 Advance();
4814 if (ranges->length() == 0) {
4815 ranges->Add(CharacterRange::Everything());
4816 is_negated = !is_negated;
4817 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004818 return new(zone()) RegExpCharacterClass(ranges, is_negated);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004819}
4820
4821
4822// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823// The Parser interface.
4824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825ParserMessage::~ParserMessage() {
4826 for (int i = 0; i < args().length(); i++)
4827 DeleteArray(args()[i]);
4828 DeleteArray(args().start());
4829}
4830
4831
4832ScriptDataImpl::~ScriptDataImpl() {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004833 if (owns_store_) store_.Dispose();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004834}
4835
4836
4837int ScriptDataImpl::Length() {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004838 return store_.length() * sizeof(unsigned);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004839}
4840
4841
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004842const char* ScriptDataImpl::Data() {
4843 return reinterpret_cast<const char*>(store_.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004844}
4845
4846
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004847bool ScriptDataImpl::HasError() {
4848 return has_error();
4849}
4850
4851
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004852void ScriptDataImpl::Initialize() {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004853 // Prepares state for use.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00004854 if (store_.length() >= PreparseDataConstants::kHeaderSize) {
4855 function_index_ = PreparseDataConstants::kHeaderSize;
4856 int symbol_data_offset = PreparseDataConstants::kHeaderSize
4857 + store_[PreparseDataConstants::kFunctionsSizeOffset];
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004858 if (store_.length() > symbol_data_offset) {
4859 symbol_data_ = reinterpret_cast<byte*>(&store_[symbol_data_offset]);
4860 } else {
4861 // Partial preparse causes no symbol information.
4862 symbol_data_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
4863 }
4864 symbol_data_end_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
4865 }
4866}
4867
4868
4869int ScriptDataImpl::ReadNumber(byte** source) {
4870 // Reads a number from symbol_data_ in base 128. The most significant
4871 // bit marks that there are more digits.
4872 // If the first byte is 0x80 (kNumberTerminator), it would normally
4873 // represent a leading zero. Since that is useless, and therefore won't
4874 // appear as the first digit of any actual value, it is used to
4875 // mark the end of the input stream.
4876 byte* data = *source;
4877 if (data >= symbol_data_end_) return -1;
4878 byte input = *data;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00004879 if (input == PreparseDataConstants::kNumberTerminator) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004880 // End of stream marker.
4881 return -1;
4882 }
4883 int result = input & 0x7f;
4884 data++;
4885 while ((input & 0x80u) != 0) {
4886 if (data >= symbol_data_end_) return -1;
4887 input = *data;
4888 result = (result << 7) | (input & 0x7f);
4889 data++;
4890 }
4891 *source = data;
4892 return result;
4893}
4894
4895
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00004896// Create a Scanner for the preparser to use as input, and preparse the source.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004897static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00004898 bool allow_lazy,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004899 ParserRecorder* recorder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004900 Isolate* isolate = Isolate::Current();
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004901 V8JavaScriptScanner scanner(isolate->unicode_cache());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004902 scanner.Initialize(source);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004903 intptr_t stack_limit = isolate->stack_guard()->real_climit();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004904 if (!preparser::PreParser::PreParseProgram(&scanner,
4905 recorder,
4906 allow_lazy,
4907 stack_limit)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004908 isolate->StackOverflow();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00004909 return NULL;
4910 }
4911
4912 // Extract the accumulated data from the recorder as a single
4913 // contiguous vector that we are responsible for disposing.
4914 Vector<unsigned> store = recorder->ExtractData();
4915 return new ScriptDataImpl(store);
4916}
4917
4918
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004919// Preparse, but only collect data that is immediately useful,
4920// even if the preparser data is only used once.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004921ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source,
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004922 v8::Extension* extension) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004923 bool allow_lazy = FLAG_lazy && (extension == NULL);
4924 if (!allow_lazy) {
4925 // Partial preparsing is only about lazily compiled functions.
4926 // If we don't allow lazy compilation, the log data will be empty.
4927 return NULL;
4928 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004929 PartialParserRecorder recorder;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004930 return DoPreParse(source, allow_lazy, &recorder);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004931}
4932
4933
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004934ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00004935 v8::Extension* extension) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004936 Handle<Script> no_script;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004937 bool allow_lazy = FLAG_lazy && (extension == NULL);
4938 CompleteParserRecorder recorder;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004939 return DoPreParse(source, allow_lazy, &recorder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004940}
4941
4942
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00004943bool RegExpParser::ParseRegExp(FlatStringReader* input,
4944 bool multiline,
4945 RegExpCompileData* result) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004946 ASSERT(result != NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004947 RegExpParser parser(input, &result->error, multiline);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004948 RegExpTree* tree = parser.ParsePattern();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004949 if (parser.failed()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004950 ASSERT(tree == NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004951 ASSERT(!result->error.is_null());
4952 } else {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004953 ASSERT(tree != NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004954 ASSERT(result->error.is_null());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004955 result->tree = tree;
4956 int capture_count = parser.captures_started();
4957 result->simple = tree->IsAtom() && parser.simple() && capture_count == 0;
iposva@chromium.org245aa852009-02-10 00:49:54 +00004958 result->contains_anchor = parser.contains_anchor();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004959 result->capture_count = capture_count;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004960 }
4961 return !parser.failed();
4962}
4963
4964
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00004965bool ParserApi::Parse(CompilationInfo* info) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004966 ASSERT(info->function() == NULL);
4967 FunctionLiteral* result = NULL;
4968 Handle<Script> script = info->script();
4969 if (info->is_lazy()) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004970 Parser parser(script, true, NULL, NULL);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004971 result = parser.ParseLazy(info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004972 } else {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004973 bool allow_natives_syntax =
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004974 info->allows_natives_syntax() || FLAG_allow_natives_syntax;
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004975 ScriptDataImpl* pre_data = info->pre_parse_data();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00004976 Parser parser(script, allow_natives_syntax, info->extension(), pre_data);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004977 if (pre_data != NULL && pre_data->has_error()) {
4978 Scanner::Location loc = pre_data->MessageLocation();
4979 const char* message = pre_data->BuildMessage();
4980 Vector<const char*> args = pre_data->BuildArgs();
4981 parser.ReportMessageAt(loc, message, args);
4982 DeleteArray(message);
4983 for (int i = 0; i < args.length(); i++) {
4984 DeleteArray(args[i]);
4985 }
4986 DeleteArray(args.start());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004987 ASSERT(info->isolate()->has_pending_exception());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004988 } else {
4989 Handle<String> source = Handle<String>(String::cast(script->source()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004990 result = parser.ParseProgram(source,
4991 info->is_global(),
4992 info->StrictMode());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004993 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004995
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004996 info->SetFunction(result);
4997 return (result != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004998}
4999
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005000} } // namespace v8::internal