blob: bb445c4d243877947705b6fb5377fcd93beebb6a [file] [log] [blame]
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001// Copyright 2010 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 "ast.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000031#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "scopes.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000033#include "string-stream.h"
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +000034#include "ast-inl.h"
35#include "jump-target-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
kasperl@chromium.org71affb52009-05-26 05:44:31 +000037namespace v8 {
38namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
40
41VariableProxySentinel VariableProxySentinel::this_proxy_(true);
42VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
43ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
44Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
ager@chromium.orga74f0da2008-12-03 16:05:52 +000045Call Call::sentinel_(NULL, NULL, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
47
48// ----------------------------------------------------------------------------
49// All the Accept member functions for each syntax tree node type.
50
lrn@chromium.org25156de2010-04-06 13:10:27 +000051#define DECL_ACCEPT(type) \
52 void type::Accept(AstVisitor* v) { v->Visit##type(this); }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000053AST_NODE_LIST(DECL_ACCEPT)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054#undef DECL_ACCEPT
55
56
57// ----------------------------------------------------------------------------
58// Implementation of other node functionality.
59
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000060Assignment* ExpressionStatement::StatementAsSimpleAssignment() {
61 return (expression()->AsAssignment() != NULL &&
62 !expression()->AsAssignment()->is_compound())
63 ? expression()->AsAssignment()
64 : NULL;
65}
66
67
68CountOperation* ExpressionStatement::StatementAsCountOperation() {
69 return expression()->AsCountOperation();
70}
71
72
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000073VariableProxy::VariableProxy(Variable* var)
74 : name_(var->name()),
75 var_(NULL), // Will be set by the call to BindTo.
76 is_this_(var->is_this()),
77 inside_with_(false),
78 is_trivial_(false) {
79 BindTo(var);
80}
81
82
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000083VariableProxy::VariableProxy(Handle<String> name,
84 bool is_this,
85 bool inside_with)
86 : name_(name),
87 var_(NULL),
88 is_this_(is_this),
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000089 inside_with_(inside_with),
ricow@chromium.org65fae842010-08-25 15:26:24 +000090 is_trivial_(false) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091 // names must be canonicalized for fast equality checks
92 ASSERT(name->IsSymbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000093}
94
95
96VariableProxy::VariableProxy(bool is_this)
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +000097 : var_(NULL),
98 is_this_(is_this),
99 inside_with_(false),
100 is_trivial_(false) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101}
102
103
104void VariableProxy::BindTo(Variable* var) {
105 ASSERT(var_ == NULL); // must be bound only once
106 ASSERT(var != NULL); // must bind
107 ASSERT((is_this() && var->is_this()) || name_.is_identical_to(var->name()));
108 // Ideally CONST-ness should match. However, this is very hard to achieve
109 // because we don't know the exact semantics of conflicting (const and
110 // non-const) multiple variable declarations, const vars introduced via
111 // eval() etc. Const-ness and variable declarations are a complete mess
112 // in JS. Sigh...
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113 var_ = var;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000114 var->set_is_used(true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115}
116
117
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000118Token::Value Assignment::binary_op() const {
119 switch (op_) {
120 case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
121 case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
122 case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
123 case Token::ASSIGN_SHL: return Token::SHL;
124 case Token::ASSIGN_SAR: return Token::SAR;
125 case Token::ASSIGN_SHR: return Token::SHR;
126 case Token::ASSIGN_ADD: return Token::ADD;
127 case Token::ASSIGN_SUB: return Token::SUB;
128 case Token::ASSIGN_MUL: return Token::MUL;
129 case Token::ASSIGN_DIV: return Token::DIV;
130 case Token::ASSIGN_MOD: return Token::MOD;
131 default: UNREACHABLE();
132 }
133 return Token::ILLEGAL;
134}
135
136
137bool FunctionLiteral::AllowsLazyCompilation() {
138 return scope()->AllowsLazyCompilation();
139}
140
141
142ObjectLiteral::Property::Property(Literal* key, Expression* value) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000143 emit_store_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000144 key_ = key;
145 value_ = value;
146 Object* k = *key->handle();
147 if (k->IsSymbol() && Heap::Proto_symbol()->Equals(String::cast(k))) {
148 kind_ = PROTOTYPE;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 } else if (value_->AsMaterializedLiteral() != NULL) {
150 kind_ = MATERIALIZED_LITERAL;
151 } else if (value_->AsLiteral() != NULL) {
152 kind_ = CONSTANT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 kind_ = COMPUTED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155 }
156}
157
158
159ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000160 emit_store_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000161 key_ = new Literal(value->name());
162 value_ = value;
163 kind_ = is_getter ? GETTER : SETTER;
164}
165
166
ager@chromium.org3811b432009-10-28 14:53:37 +0000167bool ObjectLiteral::Property::IsCompileTimeValue() {
168 return kind_ == CONSTANT ||
169 (kind_ == MATERIALIZED_LITERAL &&
170 CompileTimeValue::IsCompileTimeValue(value_));
171}
172
173
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000174void ObjectLiteral::Property::set_emit_store(bool emit_store) {
175 emit_store_ = emit_store;
176}
177
178
179bool ObjectLiteral::Property::emit_store() {
180 return emit_store_;
181}
182
183
184bool IsEqualString(void* first, void* second) {
185 Handle<String> h1(reinterpret_cast<String**>(first));
186 Handle<String> h2(reinterpret_cast<String**>(second));
187 return (*h1)->Equals(*h2);
188}
189
190bool IsEqualSmi(void* first, void* second) {
191 Handle<Smi> h1(reinterpret_cast<Smi**>(first));
192 Handle<Smi> h2(reinterpret_cast<Smi**>(second));
193 return (*h1)->value() == (*h2)->value();
194}
195
196void ObjectLiteral::CalculateEmitStore() {
197 HashMap properties(&IsEqualString);
198 HashMap elements(&IsEqualSmi);
199 for (int i = this->properties()->length() - 1; i >= 0; i--) {
200 ObjectLiteral::Property* property = this->properties()->at(i);
201 Literal* literal = property->key();
202 Handle<Object> handle = literal->handle();
203
204 if (handle->IsNull()) {
205 continue;
206 }
207
208 uint32_t hash;
209 HashMap* table;
210 void* key;
211 uint32_t index;
212 if (handle->IsSymbol()) {
213 Handle<String> name(String::cast(*handle));
214 ASSERT(!name->AsArrayIndex(&index));
215 key = name.location();
216 hash = name->Hash();
217 table = &properties;
218 } else if (handle->ToArrayIndex(&index)) {
219 key = handle.location();
220 hash = index;
221 table = &elements;
222 } else {
223 ASSERT(handle->IsNumber());
224 double num = handle->Number();
225 char arr[100];
226 Vector<char> buffer(arr, ARRAY_SIZE(arr));
227 const char* str = DoubleToCString(num, buffer);
228 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
229 key = name.location();
230 hash = name->Hash();
231 table = &properties;
232 }
233 // If the key of a computed property is in the table, do not emit
234 // a store for the property later.
235 if (property->kind() == ObjectLiteral::Property::COMPUTED) {
236 if (table->Lookup(literal, hash, false) != NULL) {
237 property->set_emit_store(false);
238 }
239 }
240 // Add key to the table.
241 table->Lookup(literal, hash, true);
242 }
243}
244
245
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000246void TargetCollector::AddTarget(BreakTarget* target) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247 // Add the label to the collector, but discard duplicates.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000248 int length = targets_->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000249 for (int i = 0; i < length; i++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000250 if (targets_->at(i) == target) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000252 targets_->Add(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253}
254
255
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000256bool Expression::GuaranteedSmiResult() {
257 BinaryOperation* node = AsBinaryOperation();
258 if (node == NULL) return false;
259 Token::Value op = node->op();
260 switch (op) {
261 case Token::COMMA:
262 case Token::OR:
263 case Token::AND:
264 case Token::ADD:
265 case Token::SUB:
266 case Token::MUL:
267 case Token::DIV:
268 case Token::MOD:
269 case Token::BIT_XOR:
270 case Token::SHL:
271 return false;
272 break;
273 case Token::BIT_OR:
274 case Token::BIT_AND: {
275 Literal* left = node->left()->AsLiteral();
276 Literal* right = node->right()->AsLiteral();
277 if (left != NULL && left->handle()->IsSmi()) {
278 int value = Smi::cast(*left->handle())->value();
279 if (op == Token::BIT_OR && ((value & 0xc0000000) == 0xc0000000)) {
280 // Result of bitwise or is always a negative Smi.
281 return true;
282 }
283 if (op == Token::BIT_AND && ((value & 0xc0000000) == 0)) {
284 // Result of bitwise and is always a positive Smi.
285 return true;
286 }
287 }
288 if (right != NULL && right->handle()->IsSmi()) {
289 int value = Smi::cast(*right->handle())->value();
290 if (op == Token::BIT_OR && ((value & 0xc0000000) == 0xc0000000)) {
291 // Result of bitwise or is always a negative Smi.
292 return true;
293 }
294 if (op == Token::BIT_AND && ((value & 0xc0000000) == 0)) {
295 // Result of bitwise and is always a positive Smi.
296 return true;
297 }
298 }
299 return false;
300 break;
301 }
302 case Token::SAR:
303 case Token::SHR: {
304 Literal* right = node->right()->AsLiteral();
305 if (right != NULL && right->handle()->IsSmi()) {
306 int value = Smi::cast(*right->handle())->value();
307 if ((value & 0x1F) > 1 ||
308 (op == Token::SAR && (value & 0x1F) == 1)) {
309 return true;
310 }
311 }
312 return false;
313 break;
314 }
315 default:
316 UNREACHABLE();
317 break;
318 }
319 return false;
320}
321
ricow@chromium.org65fae842010-08-25 15:26:24 +0000322
323void Expression::CopyAnalysisResultsFrom(Expression* other) {
324 bitfields_ = other->bitfields_;
325 type_ = other->type_;
326}
327
328
329bool UnaryOperation::ResultOverwriteAllowed() {
330 switch (op_) {
331 case Token::BIT_NOT:
332 case Token::SUB:
333 return true;
334 default:
335 return false;
336 }
337}
338
339
340bool BinaryOperation::ResultOverwriteAllowed() {
341 switch (op_) {
342 case Token::COMMA:
343 case Token::OR:
344 case Token::AND:
345 return false;
346 case Token::BIT_OR:
347 case Token::BIT_XOR:
348 case Token::BIT_AND:
349 case Token::SHL:
350 case Token::SAR:
351 case Token::SHR:
352 case Token::ADD:
353 case Token::SUB:
354 case Token::MUL:
355 case Token::DIV:
356 case Token::MOD:
357 return true;
358 default:
359 UNREACHABLE();
360 }
361 return false;
362}
363
364
365BinaryOperation::BinaryOperation(Assignment* assignment) {
366 ASSERT(assignment->is_compound());
367 op_ = assignment->binary_op();
368 left_ = assignment->target();
369 right_ = assignment->value();
370 pos_ = assignment->position();
371 CopyAnalysisResultsFrom(assignment);
372}
373
374
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000375// ----------------------------------------------------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000376// Implementation of AstVisitor
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377
lrn@chromium.org25156de2010-04-06 13:10:27 +0000378bool AstVisitor::CheckStackOverflow() {
379 if (stack_overflow_) return true;
380 StackLimitCheck check;
381 if (!check.HasOverflowed()) return false;
382 return (stack_overflow_ = true);
383}
384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000386void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) {
387 for (int i = 0; i < declarations->length(); i++) {
388 Visit(declarations->at(i));
389 }
390}
391
392
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000393void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 for (int i = 0; i < statements->length(); i++) {
395 Visit(statements->at(i));
396 }
397}
398
399
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000400void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 for (int i = 0; i < expressions->length(); i++) {
402 // The variable statement visiting code may pass NULL expressions
403 // to this code. Maybe this should be handled by introducing an
404 // undefined expression or literal? Revisit this code if this
405 // changes
406 Expression* expression = expressions->at(i);
407 if (expression != NULL) Visit(expression);
408 }
409}
410
411
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000412// ----------------------------------------------------------------------------
413// Regular expressions
414
415#define MAKE_ACCEPT(Name) \
416 void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \
417 return visitor->Visit##Name(this, data); \
418 }
419FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT)
420#undef MAKE_ACCEPT
421
422#define MAKE_TYPE_CASE(Name) \
423 RegExp##Name* RegExpTree::As##Name() { \
424 return NULL; \
425 } \
426 bool RegExpTree::Is##Name() { return false; }
427FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
428#undef MAKE_TYPE_CASE
429
430#define MAKE_TYPE_CASE(Name) \
431 RegExp##Name* RegExp##Name::As##Name() { \
432 return this; \
433 } \
434 bool RegExp##Name::Is##Name() { return true; }
435FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
436#undef MAKE_TYPE_CASE
437
438RegExpEmpty RegExpEmpty::kInstance;
439
440
ager@chromium.org32912102009-01-16 10:38:43 +0000441static Interval ListCaptureRegisters(ZoneList<RegExpTree*>* children) {
442 Interval result = Interval::Empty();
443 for (int i = 0; i < children->length(); i++)
444 result = result.Union(children->at(i)->CaptureRegisters());
445 return result;
446}
447
448
449Interval RegExpAlternative::CaptureRegisters() {
450 return ListCaptureRegisters(nodes());
451}
452
453
454Interval RegExpDisjunction::CaptureRegisters() {
455 return ListCaptureRegisters(alternatives());
456}
457
458
459Interval RegExpLookahead::CaptureRegisters() {
460 return body()->CaptureRegisters();
461}
462
463
464Interval RegExpCapture::CaptureRegisters() {
465 Interval self(StartRegister(index()), EndRegister(index()));
466 return self.Union(body()->CaptureRegisters());
467}
468
469
470Interval RegExpQuantifier::CaptureRegisters() {
471 return body()->CaptureRegisters();
472}
473
474
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000475bool RegExpAssertion::IsAnchoredAtStart() {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000476 return type() == RegExpAssertion::START_OF_INPUT;
477}
478
479
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000480bool RegExpAssertion::IsAnchoredAtEnd() {
481 return type() == RegExpAssertion::END_OF_INPUT;
482}
483
484
485bool RegExpAlternative::IsAnchoredAtStart() {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000486 ZoneList<RegExpTree*>* nodes = this->nodes();
487 for (int i = 0; i < nodes->length(); i++) {
488 RegExpTree* node = nodes->at(i);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000489 if (node->IsAnchoredAtStart()) { return true; }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000490 if (node->max_match() > 0) { return false; }
491 }
492 return false;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000493}
494
495
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000496bool RegExpAlternative::IsAnchoredAtEnd() {
497 ZoneList<RegExpTree*>* nodes = this->nodes();
498 for (int i = nodes->length() - 1; i >= 0; i--) {
499 RegExpTree* node = nodes->at(i);
500 if (node->IsAnchoredAtEnd()) { return true; }
501 if (node->max_match() > 0) { return false; }
502 }
503 return false;
504}
505
506
507bool RegExpDisjunction::IsAnchoredAtStart() {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000508 ZoneList<RegExpTree*>* alternatives = this->alternatives();
509 for (int i = 0; i < alternatives->length(); i++) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000510 if (!alternatives->at(i)->IsAnchoredAtStart())
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000511 return false;
512 }
513 return true;
514}
515
516
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000517bool RegExpDisjunction::IsAnchoredAtEnd() {
518 ZoneList<RegExpTree*>* alternatives = this->alternatives();
519 for (int i = 0; i < alternatives->length(); i++) {
520 if (!alternatives->at(i)->IsAnchoredAtEnd())
521 return false;
522 }
523 return true;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000524}
525
526
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000527bool RegExpLookahead::IsAnchoredAtStart() {
528 return is_positive() && body()->IsAnchoredAtStart();
529}
530
531
532bool RegExpCapture::IsAnchoredAtStart() {
533 return body()->IsAnchoredAtStart();
534}
535
536
537bool RegExpCapture::IsAnchoredAtEnd() {
538 return body()->IsAnchoredAtEnd();
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000539}
540
541
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000542// Convert regular expression trees to a simple sexp representation.
543// This representation should be different from the input grammar
544// in as many cases as possible, to make it more difficult for incorrect
545// parses to look as correct ones which is likely if the input and
546// output formats are alike.
547class RegExpUnparser: public RegExpVisitor {
548 public:
549 RegExpUnparser();
550 void VisitCharacterRange(CharacterRange that);
551 SmartPointer<const char> ToString() { return stream_.ToCString(); }
552#define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data);
553 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
554#undef MAKE_CASE
555 private:
556 StringStream* stream() { return &stream_; }
557 HeapStringAllocator alloc_;
558 StringStream stream_;
559};
560
561
562RegExpUnparser::RegExpUnparser() : stream_(&alloc_) {
563}
564
565
566void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
567 stream()->Add("(|");
568 for (int i = 0; i < that->alternatives()->length(); i++) {
569 stream()->Add(" ");
570 that->alternatives()->at(i)->Accept(this, data);
571 }
572 stream()->Add(")");
573 return NULL;
574}
575
576
577void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
578 stream()->Add("(:");
579 for (int i = 0; i < that->nodes()->length(); i++) {
580 stream()->Add(" ");
581 that->nodes()->at(i)->Accept(this, data);
582 }
583 stream()->Add(")");
584 return NULL;
585}
586
587
588void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
589 stream()->Add("%k", that.from());
590 if (!that.IsSingleton()) {
591 stream()->Add("-%k", that.to());
592 }
593}
594
595
596
597void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
598 void* data) {
599 if (that->is_negated())
600 stream()->Add("^");
601 stream()->Add("[");
602 for (int i = 0; i < that->ranges()->length(); i++) {
603 if (i > 0) stream()->Add(" ");
604 VisitCharacterRange(that->ranges()->at(i));
605 }
606 stream()->Add("]");
607 return NULL;
608}
609
610
611void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
612 switch (that->type()) {
613 case RegExpAssertion::START_OF_INPUT:
614 stream()->Add("@^i");
615 break;
616 case RegExpAssertion::END_OF_INPUT:
617 stream()->Add("@$i");
618 break;
619 case RegExpAssertion::START_OF_LINE:
620 stream()->Add("@^l");
621 break;
622 case RegExpAssertion::END_OF_LINE:
623 stream()->Add("@$l");
624 break;
625 case RegExpAssertion::BOUNDARY:
626 stream()->Add("@b");
627 break;
628 case RegExpAssertion::NON_BOUNDARY:
629 stream()->Add("@B");
630 break;
631 }
632 return NULL;
633}
634
635
636void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
637 stream()->Add("'");
638 Vector<const uc16> chardata = that->data();
639 for (int i = 0; i < chardata.length(); i++) {
640 stream()->Add("%k", chardata[i]);
641 }
642 stream()->Add("'");
643 return NULL;
644}
645
646
647void* RegExpUnparser::VisitText(RegExpText* that, void* data) {
648 if (that->elements()->length() == 1) {
649 that->elements()->at(0).data.u_atom->Accept(this, data);
650 } else {
651 stream()->Add("(!");
652 for (int i = 0; i < that->elements()->length(); i++) {
653 stream()->Add(" ");
654 that->elements()->at(i).data.u_atom->Accept(this, data);
655 }
656 stream()->Add(")");
657 }
658 return NULL;
659}
660
661
662void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
663 stream()->Add("(# %i ", that->min());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000664 if (that->max() == RegExpTree::kInfinity) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000665 stream()->Add("- ");
666 } else {
667 stream()->Add("%i ", that->max());
668 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000669 stream()->Add(that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n ");
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000670 that->body()->Accept(this, data);
671 stream()->Add(")");
672 return NULL;
673}
674
675
676void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
677 stream()->Add("(^ ");
678 that->body()->Accept(this, data);
679 stream()->Add(")");
680 return NULL;
681}
682
683
684void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
685 stream()->Add("(-> ");
686 stream()->Add(that->is_positive() ? "+ " : "- ");
687 that->body()->Accept(this, data);
688 stream()->Add(")");
689 return NULL;
690}
691
692
693void* RegExpUnparser::VisitBackReference(RegExpBackReference* that,
694 void* data) {
695 stream()->Add("(<- %i)", that->index());
696 return NULL;
697}
698
699
700void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
701 stream()->Put('%');
702 return NULL;
703}
704
705
706SmartPointer<const char> RegExpTree::ToString() {
707 RegExpUnparser unparser;
708 Accept(&unparser, NULL);
709 return unparser.ToString();
710}
711
712
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000713RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
714 : alternatives_(alternatives) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000715 ASSERT(alternatives->length() > 1);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000716 RegExpTree* first_alternative = alternatives->at(0);
717 min_match_ = first_alternative->min_match();
718 max_match_ = first_alternative->max_match();
719 for (int i = 1; i < alternatives->length(); i++) {
720 RegExpTree* alternative = alternatives->at(i);
721 min_match_ = Min(min_match_, alternative->min_match());
722 max_match_ = Max(max_match_, alternative->max_match());
723 }
724}
725
726
727RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
728 : nodes_(nodes) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000729 ASSERT(nodes->length() > 1);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000730 min_match_ = 0;
731 max_match_ = 0;
732 for (int i = 0; i < nodes->length(); i++) {
733 RegExpTree* node = nodes->at(i);
734 min_match_ += node->min_match();
735 int node_max_match = node->max_match();
736 if (kInfinity - max_match_ < node_max_match) {
737 max_match_ = kInfinity;
738 } else {
739 max_match_ += node->max_match();
740 }
741 }
742}
743
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000744
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000745WhileStatement::WhileStatement(ZoneStringList* labels)
746 : IterationStatement(labels),
747 cond_(NULL),
748 may_have_function_literal_(true) {
749}
750
751
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000752CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements)
753 : label_(label), statements_(statements) {
754}
755
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000756} } // namespace v8::internal