ast.cc revision 3e5fa29ddb82551500b118e9bf37af3966277b70
1// Copyright 2010 the V8 project authors. All rights reserved.
2// 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"
31#include "parser.h"
32#include "scopes.h"
33#include "string-stream.h"
34#include "ast-inl.h"
35#include "jump-target-inl.h"
36
37namespace v8 {
38namespace internal {
39
40
41VariableProxySentinel VariableProxySentinel::this_proxy_(true);
42VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
43ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
44Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
45Call Call::sentinel_(NULL, NULL, 0);
46
47
48// ----------------------------------------------------------------------------
49// All the Accept member functions for each syntax tree node type.
50
51#define DECL_ACCEPT(type)                                       \
52  void type::Accept(AstVisitor* v) { v->Visit##type(this); }
53AST_NODE_LIST(DECL_ACCEPT)
54#undef DECL_ACCEPT
55
56
57// ----------------------------------------------------------------------------
58// Implementation of other node functionality.
59
60Assignment* 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
73VariableProxy::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
83VariableProxy::VariableProxy(Handle<String> name,
84                             bool is_this,
85                             bool inside_with)
86  : name_(name),
87    var_(NULL),
88    is_this_(is_this),
89    inside_with_(inside_with),
90    is_trivial_(false) {
91  // names must be canonicalized for fast equality checks
92  ASSERT(name->IsSymbol());
93}
94
95
96VariableProxy::VariableProxy(bool is_this)
97  : var_(NULL),
98    is_this_(is_this),
99    inside_with_(false),
100    is_trivial_(false) {
101}
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...
113  var_ = var;
114  var->set_is_used(true);
115}
116
117
118Token::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) {
143  emit_store_ = true;
144  key_ = key;
145  value_ = value;
146  Object* k = *key->handle();
147  if (k->IsSymbol() && Heap::Proto_symbol()->Equals(String::cast(k))) {
148    kind_ = PROTOTYPE;
149  } else if (value_->AsMaterializedLiteral() != NULL) {
150    kind_ = MATERIALIZED_LITERAL;
151  } else if (value_->AsLiteral() != NULL) {
152    kind_ = CONSTANT;
153  } else {
154    kind_ = COMPUTED;
155  }
156}
157
158
159ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
160  emit_store_ = true;
161  key_ = new Literal(value->name());
162  value_ = value;
163  kind_ = is_getter ? GETTER : SETTER;
164}
165
166
167bool ObjectLiteral::Property::IsCompileTimeValue() {
168  return kind_ == CONSTANT ||
169      (kind_ == MATERIALIZED_LITERAL &&
170       CompileTimeValue::IsCompileTimeValue(value_));
171}
172
173
174void 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
246void TargetCollector::AddTarget(BreakTarget* target) {
247  // Add the label to the collector, but discard duplicates.
248  int length = targets_->length();
249  for (int i = 0; i < length; i++) {
250    if (targets_->at(i) == target) return;
251  }
252  targets_->Add(target);
253}
254
255
256bool 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
322
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
375// ----------------------------------------------------------------------------
376// Implementation of AstVisitor
377
378bool AstVisitor::CheckStackOverflow() {
379  if (stack_overflow_) return true;
380  StackLimitCheck check;
381  if (!check.HasOverflowed()) return false;
382  return (stack_overflow_ = true);
383}
384
385
386void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) {
387  for (int i = 0; i < declarations->length(); i++) {
388    Visit(declarations->at(i));
389  }
390}
391
392
393void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
394  for (int i = 0; i < statements->length(); i++) {
395    Visit(statements->at(i));
396  }
397}
398
399
400void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
401  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
412// ----------------------------------------------------------------------------
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
441static 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
475bool RegExpAssertion::IsAnchoredAtStart() {
476  return type() == RegExpAssertion::START_OF_INPUT;
477}
478
479
480bool RegExpAssertion::IsAnchoredAtEnd() {
481  return type() == RegExpAssertion::END_OF_INPUT;
482}
483
484
485bool RegExpAlternative::IsAnchoredAtStart() {
486  ZoneList<RegExpTree*>* nodes = this->nodes();
487  for (int i = 0; i < nodes->length(); i++) {
488    RegExpTree* node = nodes->at(i);
489    if (node->IsAnchoredAtStart()) { return true; }
490    if (node->max_match() > 0) { return false; }
491  }
492  return false;
493}
494
495
496bool 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() {
508  ZoneList<RegExpTree*>* alternatives = this->alternatives();
509  for (int i = 0; i < alternatives->length(); i++) {
510    if (!alternatives->at(i)->IsAnchoredAtStart())
511      return false;
512  }
513  return true;
514}
515
516
517bool 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;
524}
525
526
527bool 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();
539}
540
541
542// 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());
664  if (that->max() == RegExpTree::kInfinity) {
665    stream()->Add("- ");
666  } else {
667    stream()->Add("%i ", that->max());
668  }
669  stream()->Add(that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n ");
670  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
713RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
714    : alternatives_(alternatives) {
715  ASSERT(alternatives->length() > 1);
716  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) {
729  ASSERT(nodes->length() > 1);
730  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
744
745WhileStatement::WhileStatement(ZoneStringList* labels)
746    : IterationStatement(labels),
747      cond_(NULL),
748      may_have_function_literal_(true) {
749}
750
751
752CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements)
753    : label_(label), statements_(statements) {
754}
755
756} }  // namespace v8::internal
757