// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef V8_AST_H_
#define V8_AST_H_

#include "execution.h"
#include "factory.h"
#include "runtime.h"
#include "token.h"
#include "variables.h"
#include "macro-assembler.h"

namespace v8 { namespace internal {

// The abstract syntax tree is an intermediate, light-weight
// representation of the parsed JavaScript code suitable for
// compilation to native code.

// Nodes are allocated in a separate zone, which allows faster
// allocation and constant-time deallocation of the entire syntax
// tree.


// ----------------------------------------------------------------------------
// Nodes of the abstract syntax tree. Only concrete classes are
// enumerated here.

#define NODE_LIST(V)                            \
  V(Block)                                      \
  V(Declaration)                                \
  V(ExpressionStatement)                        \
  V(EmptyStatement)                             \
  V(IfStatement)                                \
  V(ContinueStatement)                          \
  V(BreakStatement)                             \
  V(ReturnStatement)                            \
  V(WithEnterStatement)                         \
  V(WithExitStatement)                          \
  V(SwitchStatement)                            \
  V(LoopStatement)                              \
  V(ForInStatement)                             \
  V(TryCatch)                                   \
  V(TryFinally)                                 \
  V(DebuggerStatement)                          \
  V(FunctionLiteral)                            \
  V(FunctionBoilerplateLiteral)                 \
  V(Conditional)                                \
  V(Slot)                                       \
  V(VariableProxy)                              \
  V(Literal)                                    \
  V(RegExpLiteral)                              \
  V(ObjectLiteral)                              \
  V(ArrayLiteral)                               \
  V(Assignment)                                 \
  V(Throw)                                      \
  V(Property)                                   \
  V(Call)                                       \
  V(CallNew)                                    \
  V(CallRuntime)                                \
  V(UnaryOperation)                             \
  V(CountOperation)                             \
  V(BinaryOperation)                            \
  V(CompareOperation)                           \
  V(ThisFunction)


#define DEF_FORWARD_DECLARATION(type) class type;
NODE_LIST(DEF_FORWARD_DECLARATION)
#undef DEF_FORWARD_DECLARATION


// Typedef only introduced to avoid unreadable code.
// Please do appreciate the required space in "> >".
typedef ZoneList<Handle<String> > ZoneStringList;


class Node: public ZoneObject {
 public:
  Node(): statement_pos_(RelocInfo::kNoPosition) { }
  virtual ~Node() { }
  virtual void Accept(Visitor* v) = 0;

  // Type testing & conversion.
  virtual Statement* AsStatement() { return NULL; }
  virtual ExpressionStatement* AsExpressionStatement() { return NULL; }
  virtual EmptyStatement* AsEmptyStatement() { return NULL; }
  virtual Expression* AsExpression() { return NULL; }
  virtual Literal* AsLiteral() { return NULL; }
  virtual Slot* AsSlot() { return NULL; }
  virtual VariableProxy* AsVariableProxy() { return NULL; }
  virtual Property* AsProperty() { return NULL; }
  virtual Call* AsCall() { return NULL; }
  virtual LabelCollector* AsLabelCollector() { return NULL; }
  virtual BreakableStatement* AsBreakableStatement() { return NULL; }
  virtual IterationStatement* AsIterationStatement() { return NULL; }
  virtual UnaryOperation* AsUnaryOperation() { return NULL; }
  virtual BinaryOperation* AsBinaryOperation() { return NULL; }
  virtual Assignment* AsAssignment() { return NULL; }
  virtual FunctionLiteral* AsFunctionLiteral() { return NULL; }

  void set_statement_pos(int statement_pos) { statement_pos_ = statement_pos; }
  int statement_pos() const { return statement_pos_; }

 private:
  int statement_pos_;
};


class Statement: public Node {
 public:
  virtual Statement* AsStatement()  { return this; }
  virtual ReturnStatement* AsReturnStatement() { return NULL; }

  bool IsEmpty() { return AsEmptyStatement() != NULL; }
};


class Reference;
enum InitState { CONST_INIT, NOT_CONST_INIT };

class Expression: public Node {
 public:
  virtual Expression* AsExpression()  { return this; }

  virtual bool IsValidLeftHandSide() { return false; }

  // Mark the expression as being compiled as an expression
  // statement. This is used to transform postfix increments to
  // (faster) prefix increments.
  virtual void MarkAsStatement() { /* do nothing */ }

  // Generate code to store into an expression evaluated as the left-hand
  // side of an assignment.  The code will expect the stored value on top of
  // the expression stack, and a reference containing the expression
  // immediately below that.  This function is overridden for expression
  // types that can be stored into.
  virtual void GenerateStoreCode(CodeGenerator* cgen,
                                 Reference* ref,
                                 InitState init_state) {
    UNREACHABLE();
  }
};


/**
 * A sentinel used during pre parsing that represents some expression
 * that is a valid left hand side without having to actually build
 * the expression.
 */
class ValidLeftHandSideSentinel: public Expression {
 public:
  virtual bool IsValidLeftHandSide() { return true; }
  virtual void Accept(Visitor* v) { UNREACHABLE(); }
  static ValidLeftHandSideSentinel* instance() { return &instance_; }
 private:
  static ValidLeftHandSideSentinel instance_;
};


class BreakableStatement: public Statement {
 public:
  enum Type {
    TARGET_FOR_ANONYMOUS,
    TARGET_FOR_NAMED_ONLY
  };

  // The labels associated with this statement. May be NULL;
  // if it is != NULL, guaranteed to contain at least one entry.
  ZoneStringList* labels() const { return labels_; }

  // Type testing & conversion.
  virtual BreakableStatement* AsBreakableStatement() { return this; }

  // Code generation
  Label* break_target() { return &break_target_; }

  // Used during code generation for restoring the stack when a
  // break/continue crosses a statement that keeps stuff on the stack.
  int break_stack_height() { return break_stack_height_; }
  void set_break_stack_height(int height) { break_stack_height_ = height; }

  // Testers.
  bool is_target_for_anonymous() const { return type_ == TARGET_FOR_ANONYMOUS; }

 protected:
  BreakableStatement(ZoneStringList* labels, Type type)
      : labels_(labels), type_(type) {
    ASSERT(labels == NULL || labels->length() > 0);
  }

 private:
  ZoneStringList* labels_;
  Type type_;
  Label break_target_;
  int break_stack_height_;
};


class Block: public BreakableStatement {
 public:
  Block(ZoneStringList* labels, int capacity, bool is_initializer_block)
      : BreakableStatement(labels, TARGET_FOR_NAMED_ONLY),
        statements_(capacity),
        is_initializer_block_(is_initializer_block) { }

  virtual void Accept(Visitor* v);

  void AddStatement(Statement* statement) { statements_.Add(statement); }

  ZoneList<Statement*>* statements() { return &statements_; }
  bool is_initializer_block() const  { return is_initializer_block_; }

 private:
  ZoneList<Statement*> statements_;
  bool is_initializer_block_;
};


class Declaration: public Node {
 public:
  Declaration(VariableProxy* proxy, Variable::Mode mode, FunctionLiteral* fun)
    : proxy_(proxy),
      mode_(mode),
      fun_(fun) {
    ASSERT(mode == Variable::VAR || mode == Variable::CONST);
    // At the moment there are no "const functions"'s in JavaScript...
    ASSERT(fun == NULL || mode == Variable::VAR);
  }

  virtual void Accept(Visitor* v);

  VariableProxy* proxy() const  { return proxy_; }
  Variable::Mode mode() const  { return mode_; }
  FunctionLiteral* fun() const  { return fun_; }  // may be NULL

 private:
  VariableProxy* proxy_;
  Variable::Mode mode_;
  FunctionLiteral* fun_;
};


class IterationStatement: public BreakableStatement {
 public:
  // Type testing & conversion.
  virtual IterationStatement* AsIterationStatement() { return this; }

  Statement* body() const { return body_; }

  // Code generation
  Label* continue_target()  { return &continue_target_; }

 protected:
  explicit IterationStatement(ZoneStringList* labels)
    : BreakableStatement(labels, TARGET_FOR_ANONYMOUS), body_(NULL) { }

  void Initialize(Statement* body) {
    body_ = body;
  }

 private:
  Statement* body_;
  Label continue_target_;
};


class LoopStatement: public IterationStatement {
 public:
  enum Type { DO_LOOP, FOR_LOOP, WHILE_LOOP };

  LoopStatement(ZoneStringList* labels, Type type)
      : IterationStatement(labels), type_(type), init_(NULL),
        cond_(NULL), next_(NULL) { }

  void Initialize(Statement* init,
                  Expression* cond,
                  Statement* next,
                  Statement* body) {
    ASSERT(init == NULL || type_ == FOR_LOOP);
    ASSERT(next == NULL || type_ == FOR_LOOP);
    IterationStatement::Initialize(body);
    init_ = init;
    cond_ = cond;
    next_ = next;
  }

  virtual void Accept(Visitor* v);

  Type type() const  { return type_; }
  Statement* init() const  { return init_; }
  Expression* cond() const  { return cond_; }
  Statement* next() const  { return next_; }

#ifdef DEBUG
  const char* OperatorString() const;
#endif

 private:
  Type type_;
  Statement* init_;
  Expression* cond_;
  Statement* next_;
};


class ForInStatement: public IterationStatement {
 public:
  explicit ForInStatement(ZoneStringList* labels)
    : IterationStatement(labels), each_(NULL), enumerable_(NULL) { }

  void Initialize(Expression* each, Expression* enumerable, Statement* body) {
    IterationStatement::Initialize(body);
    each_ = each;
    enumerable_ = enumerable;
  }

  virtual void Accept(Visitor* v);

  Expression* each() const { return each_; }
  Expression* enumerable() const { return enumerable_; }

 private:
  Expression* each_;
  Expression* enumerable_;
};


class ExpressionStatement: public Statement {
 public:
  explicit ExpressionStatement(Expression* expression)
      : expression_(expression) { }

  virtual void Accept(Visitor* v);

  // Type testing & conversion.
  virtual ExpressionStatement* AsExpressionStatement() { return this; }

  void set_expression(Expression* e) { expression_ = e; }
  Expression* expression() { return expression_; }

 private:
  Expression* expression_;
};


class ContinueStatement: public Statement {
 public:
  explicit ContinueStatement(IterationStatement* target)
      : target_(target) { }

  virtual void Accept(Visitor* v);

  IterationStatement* target() const  { return target_; }

 private:
  IterationStatement* target_;
};


class BreakStatement: public Statement {
 public:
  explicit BreakStatement(BreakableStatement* target)
      : target_(target) { }

  virtual void Accept(Visitor* v);

  BreakableStatement* target() const  { return target_; }

 private:
  BreakableStatement* target_;
};


class ReturnStatement: public Statement {
 public:
  explicit ReturnStatement(Expression* expression)
      : expression_(expression) { }

  virtual void Accept(Visitor* v);

  // Type testing & conversion.
  virtual ReturnStatement* AsReturnStatement() { return this; }

  Expression* expression() { return expression_; }

 private:
  Expression* expression_;
};


class WithEnterStatement: public Statement {
 public:
  explicit WithEnterStatement(Expression* expression)
      : expression_(expression) { }

  virtual void Accept(Visitor* v);

  Expression* expression() const  { return expression_; }

 private:
  Expression* expression_;
};


class WithExitStatement: public Statement {
 public:
  WithExitStatement() { }

  virtual void Accept(Visitor* v);
};


class CaseClause: public ZoneObject {
 public:
  CaseClause(Expression* label, ZoneList<Statement*>* statements)
      : label_(label), statements_(statements) { }

  bool is_default() const  { return label_ == NULL; }
  Expression* label() const  {
    CHECK(!is_default());
    return label_;
  }
  ZoneList<Statement*>* statements() const  { return statements_; }

 private:
  Expression* label_;
  ZoneList<Statement*>* statements_;
};


class SwitchStatement: public BreakableStatement {
 public:
  explicit SwitchStatement(ZoneStringList* labels)
      : BreakableStatement(labels, TARGET_FOR_ANONYMOUS),
        tag_(NULL), cases_(NULL) { }

  void Initialize(Expression* tag, ZoneList<CaseClause*>* cases) {
    tag_ = tag;
    cases_ = cases;
  }

  virtual void Accept(Visitor* v);

  Expression* tag() const  { return tag_; }
  ZoneList<CaseClause*>* cases() const  { return cases_; }

 private:
  Expression* tag_;
  ZoneList<CaseClause*>* cases_;
};


// If-statements always have non-null references to their then- and
// else-parts. When parsing if-statements with no explicit else-part,
// the parser implicitly creates an empty statement. Use the
// HasThenStatement() and HasElseStatement() functions to check if a
// given if-statement has a then- or an else-part containing code.
class IfStatement: public Statement {
 public:
  IfStatement(Expression* condition,
              Statement* then_statement,
              Statement* else_statement)
      : condition_(condition),
        then_statement_(then_statement),
        else_statement_(else_statement) { }

  virtual void Accept(Visitor* v);

  bool HasThenStatement() const { return !then_statement()->IsEmpty(); }
  bool HasElseStatement() const { return !else_statement()->IsEmpty(); }

  Expression* condition() const { return condition_; }
  Statement* then_statement() const { return then_statement_; }
  Statement* else_statement() const { return else_statement_; }

 private:
  Expression* condition_;
  Statement* then_statement_;
  Statement* else_statement_;
};


// NOTE: LabelCollectors are represented as nodes to fit in the target
// stack in the compiler; this should probably be reworked.
class LabelCollector: public Node {
 public:
  explicit LabelCollector(ZoneList<Label*>* labels) : labels_(labels) { }

  // Adds a label to the collector. The collector stores a pointer not
  // a copy of the label to make binding work, so make sure not to
  // pass in references to something on the stack.
  void AddLabel(Label* label);

  // Virtual behaviour. LabelCollectors are never part of the AST.
  virtual void Accept(Visitor* v) { UNREACHABLE(); }
  virtual LabelCollector* AsLabelCollector() { return this; }

  ZoneList<Label*>* labels() { return labels_; }

 private:
  ZoneList<Label*>* labels_;
};


class TryStatement: public Statement {
 public:
  explicit TryStatement(Block* try_block)
      : try_block_(try_block), escaping_labels_(NULL) { }

  void set_escaping_labels(ZoneList<Label*>* labels) {
    escaping_labels_ = labels;
  }

  Block* try_block() const { return try_block_; }
  ZoneList<Label*>* escaping_labels() const { return escaping_labels_; }

 private:
  Block* try_block_;
  ZoneList<Label*>* escaping_labels_;
};


class TryCatch: public TryStatement {
 public:
  TryCatch(Block* try_block, Expression* catch_var, Block* catch_block)
      : TryStatement(try_block),
        catch_var_(catch_var),
        catch_block_(catch_block) {
    ASSERT(catch_var->AsVariableProxy() != NULL);
  }

  virtual void Accept(Visitor* v);

  Expression* catch_var() const  { return catch_var_; }
  Block* catch_block() const  { return catch_block_; }

 private:
  Expression* catch_var_;
  Block* catch_block_;
};


class TryFinally: public TryStatement {
 public:
  TryFinally(Block* try_block, Block* finally_block)
      : TryStatement(try_block),
        finally_block_(finally_block) { }

  virtual void Accept(Visitor* v);

  Block* finally_block() const { return finally_block_; }

 private:
  Block* finally_block_;
};


class DebuggerStatement: public Statement {
 public:
  virtual void Accept(Visitor* v);
};


class EmptyStatement: public Statement {
 public:
  virtual void Accept(Visitor* v);

  // Type testing & conversion.
  virtual EmptyStatement* AsEmptyStatement() { return this; }
};


class Literal: public Expression {
 public:
  explicit Literal(Handle<Object> handle) : handle_(handle) { }

  virtual void Accept(Visitor* v);

  // Type testing & conversion.
  virtual Literal* AsLiteral() { return this; }

  // Check if this literal is identical to the other literal.
  bool IsIdenticalTo(const Literal* other) const {
    return handle_.is_identical_to(other->handle_);
  }

  // Identity testers.
  bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
  bool IsTrue() const { return handle_.is_identical_to(Factory::true_value()); }
  bool IsFalse() const {
    return handle_.is_identical_to(Factory::false_value());
  }

  Handle<Object> handle() const { return handle_; }

 private:
  Handle<Object> handle_;
};


// Base class for literals that needs space in the corresponding JSFunction.
class MaterializedLiteral: public Expression {
 public:
  explicit MaterializedLiteral(int literal_index)
      : literal_index_(literal_index) {}
  int literal_index() { return literal_index_; }
 private:
  int literal_index_;
};


// An object literal has a boilerplate object that is used
// for minimizing the work when constructing it at runtime.
class ObjectLiteral: public MaterializedLiteral {
 public:
  // Property is used for passing information
  // about an object literal's properties from the parser
  // to the code generator.
  class Property: public ZoneObject {
   public:

    enum Kind {
      CONSTANT,       // Property with constant value (at compile time).
      COMPUTED,       // Property with computed value (at execution time).
      GETTER, SETTER,  // Property is an accessor function.
      PROTOTYPE       // Property is __proto__.
    };

    Property(Literal* key, Expression* value);
    Property(bool is_getter, FunctionLiteral* value);

    Literal* key() { return key_; }
    Expression* value() { return value_; }
    Kind kind() { return kind_; }

   private:
    Literal* key_;
    Expression* value_;
    Kind kind_;
  };

  ObjectLiteral(Handle<FixedArray> constant_properties,
                ZoneList<Property*>* properties,
                int literal_index)
      : MaterializedLiteral(literal_index),
        constant_properties_(constant_properties),
        properties_(properties) {
  }

  virtual void Accept(Visitor* v);

  Handle<FixedArray> constant_properties() const {
    return constant_properties_;
  }
  ZoneList<Property*>* properties() const { return properties_; }

 private:
  Handle<FixedArray> constant_properties_;
  ZoneList<Property*>* properties_;
};


// Node for capturing a regexp literal.
class RegExpLiteral: public MaterializedLiteral {
 public:
  RegExpLiteral(Handle<String> pattern,
                Handle<String> flags,
                int literal_index)
      : MaterializedLiteral(literal_index),
        pattern_(pattern),
        flags_(flags) {}

  virtual void Accept(Visitor* v);

  Handle<String> pattern() const { return pattern_; }
  Handle<String> flags() const { return flags_; }

 private:
  Handle<String> pattern_;
  Handle<String> flags_;
};

// An array literal has a literals object that is used
// used for minimizing the work when contructing it at runtime.
class ArrayLiteral: public Expression {
 public:
  ArrayLiteral(Handle<FixedArray> literals,
               ZoneList<Expression*>* values)
      : literals_(literals), values_(values) {
  }

  virtual void Accept(Visitor* v);

  Handle<FixedArray> literals() const { return literals_; }
  ZoneList<Expression*>* values() const { return values_; }

 private:
  Handle<FixedArray> literals_;
  ZoneList<Expression*>* values_;
};


class VariableProxy: public Expression {
 public:
  virtual void Accept(Visitor* v);

  // Type testing & conversion
  virtual Property* AsProperty() {
    return var_ == NULL ? NULL : var_->AsProperty();
  }
  virtual VariableProxy* AsVariableProxy()  { return this; }

  Variable* AsVariable() {
    return this == NULL || var_ == NULL ? NULL : var_->AsVariable();
  }
  virtual bool IsValidLeftHandSide() {
    return var_ == NULL ? true : var_->IsValidLeftHandSide();
  }
  bool IsVariable(Handle<String> n) {
    return !is_this() && name().is_identical_to(n);
  }

  // If this assertion fails it means that some code has tried to
  // treat the special "this" variable as an ordinary variable with
  // the name "this".
  Handle<String> name() const  { return name_; }
  Variable* var() const  { return var_; }
  UseCount* var_uses()  { return &var_uses_; }
  UseCount* obj_uses()  { return &obj_uses_; }
  bool is_this() const  { return is_this_; }
  bool inside_with() const  { return inside_with_; }

  // Bind this proxy to the variable var.
  void BindTo(Variable* var);

  // Generate code to store into an expression evaluated as the left-hand
  // side of an assignment.  The code will expect the stored value on top of
  // the expression stack, and a reference containing the expression
  // immediately below that.
  virtual void GenerateStoreCode(CodeGenerator* cgen,
                                 Reference* ref,
                                 InitState init_state);
 protected:
  Handle<String> name_;
  Variable* var_;  // resolved variable, or NULL
  bool is_this_;
  bool inside_with_;

  // VariableProxy usage info.
  UseCount var_uses_;  // uses of the variable value
  UseCount obj_uses_;  // uses of the object the variable points to

  VariableProxy(Handle<String> name, bool is_this, bool inside_with);
  explicit VariableProxy(bool is_this);

  friend class Scope;
};


class VariableProxySentinel: public VariableProxy {
 public:
  virtual bool IsValidLeftHandSide() { return !is_this(); }
  static VariableProxySentinel* this_proxy() { return &this_proxy_; }
  static VariableProxySentinel* identifier_proxy() {
    return &identifier_proxy_;
  }

 private:
  explicit VariableProxySentinel(bool is_this) : VariableProxy(is_this) { }
  static VariableProxySentinel this_proxy_;
  static VariableProxySentinel identifier_proxy_;
};


class Slot: public Expression {
 public:
  enum Type {
    // A slot in the parameter section on the stack. index() is
    // the parameter index, counting left-to-right, starting at 0.
    PARAMETER,

    // A slot in the local section on the stack. index() is
    // the variable index in the stack frame, starting at 0.
    LOCAL,

    // An indexed slot in a heap context. index() is the
    // variable index in the context object on the heap,
    // starting at 0. var()->scope() is the corresponding
    // scope.
    CONTEXT,

    // A named slot in a heap context. var()->name() is the
    // variable name in the context object on the heap,
    // with lookup starting at the current context. index()
    // is invalid.
    LOOKUP,

    // A property in the global object. var()->name() is
    // the property name.
    GLOBAL
  };

  Slot(Variable* var, Type type, int index)
    : var_(var), type_(type), index_(index) {
    ASSERT(var != NULL);
  }

  virtual void Accept(Visitor* v);

  // Type testing & conversion
  virtual Slot* AsSlot()  { return this; }

  // Accessors
  Variable* var() const  { return var_; }
  Type type() const  { return type_; }
  int index() const  { return index_; }

  // Generate code to store into an expression evaluated as the left-hand
  // side of an assignment.  The code will expect the stored value on top of
  // the expression stack, and a reference containing the expression
  // immediately below that.
  virtual void GenerateStoreCode(CodeGenerator* cgen,
                                 Reference* ref,
                                 InitState init_state);
 private:
  Variable* var_;
  Type type_;
  int index_;
};


class Property: public Expression {
 public:
  Property(Expression* obj, Expression* key, int pos)
      : obj_(obj), key_(key), pos_(pos) { }

  virtual void Accept(Visitor* v);

  // Type testing & conversion
  virtual Property* AsProperty() { return this; }

  virtual bool IsValidLeftHandSide() { return true; }

  Expression* obj() const { return obj_; }
  Expression* key() const { return key_; }
  int position() const { return pos_; }

  // Returns a property singleton property access on 'this'.  Used
  // during preparsing.
  static Property* this_property() { return &this_property_; }

  // Generate code to store into an expression evaluated as the left-hand
  // side of an assignment.  The code will expect the stored value on top of
  // the expression stack, and a reference containing the expression
  // immediately below that.
  virtual void GenerateStoreCode(CodeGenerator* cgen,
                                 Reference* ref,
                                 InitState init_state);
 private:
  Expression* obj_;
  Expression* key_;
  int pos_;

  // Dummy property used during preparsing
  static Property this_property_;
};


class Call: public Expression {
 public:
  Call(Expression* expression,
       ZoneList<Expression*>* arguments,
       bool is_eval,
       int pos)
      : expression_(expression),
        arguments_(arguments),
        is_eval_(is_eval),
        pos_(pos) { }

  virtual void Accept(Visitor* v);

  // Type testing and conversion.
  virtual Call* AsCall() { return this; }

  Expression* expression() const { return expression_; }
  ZoneList<Expression*>* arguments() const { return arguments_; }
  bool is_eval()  { return is_eval_; }
  int position() { return pos_; }

  static Call* sentinel() { return &sentinel_; }

 private:
  Expression* expression_;
  ZoneList<Expression*>* arguments_;
  bool is_eval_;
  int pos_;

  static Call sentinel_;
};


class CallNew: public Call {
 public:
  CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos)
      : Call(expression, arguments, false, pos) { }

  virtual void Accept(Visitor* v);
};


// The CallRuntime class does not represent any official JavaScript
// language construct. Instead it is used to call a C or JS function
// with a set of arguments. This is used from the builtins that are
// implemented in JavaScript (see "v8natives.js").
class CallRuntime: public Expression {
 public:
  CallRuntime(Handle<String> name,
              Runtime::Function* function,
              ZoneList<Expression*>* arguments)
      : name_(name), function_(function), arguments_(arguments) { }

  virtual void Accept(Visitor* v);

  Handle<String> name() const { return name_; }
  Runtime::Function* function() const { return function_; }
  ZoneList<Expression*>* arguments() const { return arguments_; }

 private:
  Handle<String> name_;
  Runtime::Function* function_;
  ZoneList<Expression*>* arguments_;
};


class UnaryOperation: public Expression {
 public:
  UnaryOperation(Token::Value op, Expression* expression)
    : op_(op), expression_(expression) {
    ASSERT(Token::IsUnaryOp(op));
  }

  virtual void Accept(Visitor* v);

  // Type testing & conversion
  virtual UnaryOperation* AsUnaryOperation() { return this; }

  Token::Value op() const { return op_; }
  Expression* expression() const { return expression_; }

 private:
  Token::Value op_;
  Expression* expression_;
};


class BinaryOperation: public Expression {
 public:
  BinaryOperation(Token::Value op, Expression* left, Expression* right)
    : op_(op), left_(left), right_(right) {
    ASSERT(Token::IsBinaryOp(op));
  }

  virtual void Accept(Visitor* v);

  // Type testing & conversion
  virtual BinaryOperation* AsBinaryOperation() { return this; }

  // True iff the result can be safely overwritten (to avoid allocation).
  // False for operations that can return one of their operands.
  bool ResultOverwriteAllowed() {
    switch (op_) {
      case Token::COMMA:
      case Token::OR:
      case Token::AND:
        return false;
      case Token::BIT_OR:
      case Token::BIT_XOR:
      case Token::BIT_AND:
      case Token::SHL:
      case Token::SAR:
      case Token::SHR:
      case Token::ADD:
      case Token::SUB:
      case Token::MUL:
      case Token::DIV:
      case Token::MOD:
        return true;
      default:
        UNREACHABLE();
    }
    return false;
  }

  Token::Value op() const { return op_; }
  Expression* left() const { return left_; }
  Expression* right() const { return right_; }

 private:
  Token::Value op_;
  Expression* left_;
  Expression* right_;
};


class CountOperation: public Expression {
 public:
  CountOperation(bool is_prefix, Token::Value op, Expression* expression)
    : is_prefix_(is_prefix), op_(op), expression_(expression) {
    ASSERT(Token::IsCountOp(op));
  }

  virtual void Accept(Visitor* v);

  bool is_prefix() const { return is_prefix_; }
  bool is_postfix() const { return !is_prefix_; }
  Token::Value op() const { return op_; }
  Expression* expression() const { return expression_; }

  virtual void MarkAsStatement() { is_prefix_ = true; }

 private:
  bool is_prefix_;
  Token::Value op_;
  Expression* expression_;
};


class CompareOperation: public Expression {
 public:
  CompareOperation(Token::Value op, Expression* left, Expression* right)
    : op_(op), left_(left), right_(right) {
    ASSERT(Token::IsCompareOp(op));
  }

  virtual void Accept(Visitor* v);

  Token::Value op() const { return op_; }
  Expression* left() const { return left_; }
  Expression* right() const { return right_; }

 private:
  Token::Value op_;
  Expression* left_;
  Expression* right_;
};


class Conditional: public Expression {
 public:
  Conditional(Expression* condition,
              Expression* then_expression,
              Expression* else_expression)
      : condition_(condition),
        then_expression_(then_expression),
        else_expression_(else_expression) { }

  virtual void Accept(Visitor* v);

  Expression* condition() const { return condition_; }
  Expression* then_expression() const { return then_expression_; }
  Expression* else_expression() const { return else_expression_; }

 private:
  Expression* condition_;
  Expression* then_expression_;
  Expression* else_expression_;
};


class Assignment: public Expression {
 public:
  Assignment(Token::Value op, Expression* target, Expression* value, int pos)
    : op_(op), target_(target), value_(value), pos_(pos) {
    ASSERT(Token::IsAssignmentOp(op));
  }

  virtual void Accept(Visitor* v);
  virtual Assignment* AsAssignment() { return this; }

  Token::Value binary_op() const;

  Token::Value op() const { return op_; }
  Expression* target() const { return target_; }
  Expression* value() const { return value_; }
  int position() { return pos_; }

 private:
  Token::Value op_;
  Expression* target_;
  Expression* value_;
  int pos_;
};


class Throw: public Expression {
 public:
  Throw(Expression* exception, int pos)
      : exception_(exception), pos_(pos) {}

  virtual void Accept(Visitor* v);
  Expression* exception() const { return exception_; }
  int position() const { return pos_; }

 private:
  Expression* exception_;
  int pos_;
};


class FunctionLiteral: public Expression {
 public:
  FunctionLiteral(Handle<String> name,
                  Scope* scope,
                  ZoneList<Statement*>* body,
                  int materialized_literal_count,
                  bool contains_array_literal,
                  int expected_property_count,
                  int num_parameters,
                  int start_position,
                  int end_position,
                  bool is_expression)
      : name_(name),
        scope_(scope),
        body_(body),
        materialized_literal_count_(materialized_literal_count),
        contains_array_literal_(contains_array_literal),
        expected_property_count_(expected_property_count),
        num_parameters_(num_parameters),
        start_position_(start_position),
        end_position_(end_position),
        is_expression_(is_expression),
        function_token_position_(RelocInfo::kNoPosition) {
  }

  virtual void Accept(Visitor* v);

  // Type testing & conversion
  virtual FunctionLiteral* AsFunctionLiteral()  { return this; }

  Handle<String> name() const  { return name_; }
  Scope* scope() const  { return scope_; }
  ZoneList<Statement*>* body() const  { return body_; }
  void set_function_token_position(int pos) { function_token_position_ = pos; }
  int function_token_position() const { return function_token_position_; }
  int start_position() const { return start_position_; }
  int end_position() const { return end_position_; }
  bool is_expression() const { return is_expression_; }

  int materialized_literal_count() { return materialized_literal_count_; }
  bool contains_array_literal() { return contains_array_literal_; }
  int expected_property_count() { return expected_property_count_; }
  int num_parameters() { return num_parameters_; }

  bool AllowsLazyCompilation();

 private:
  Handle<String> name_;
  Scope* scope_;
  ZoneList<Statement*>* body_;
  int materialized_literal_count_;
  bool contains_array_literal_;
  int expected_property_count_;
  int num_parameters_;
  int start_position_;
  int end_position_;
  bool is_expression_;
  int function_token_position_;
};


class FunctionBoilerplateLiteral: public Expression {
 public:
  explicit FunctionBoilerplateLiteral(Handle<JSFunction> boilerplate)
      : boilerplate_(boilerplate) {
    ASSERT(boilerplate->IsBoilerplate());
  }

  Handle<JSFunction> boilerplate() const { return boilerplate_; }

  virtual void Accept(Visitor* v);

 private:
  Handle<JSFunction> boilerplate_;
};


class ThisFunction: public Expression {
 public:
  virtual void Accept(Visitor* v);
};


// ----------------------------------------------------------------------------
// Basic visitor
// - leaf node visitors are abstract.

class Visitor BASE_EMBEDDED {
 public:
  Visitor() : stack_overflow_(false) { }
  virtual ~Visitor() { }

  // Dispatch
  void Visit(Node* node) { node->Accept(this); }

  // Iteration
  virtual void VisitStatements(ZoneList<Statement*>* statements);
  virtual void VisitExpressions(ZoneList<Expression*>* expressions);

  // Stack overflow tracking support.
  bool HasStackOverflow() const { return stack_overflow_; }
  bool CheckStackOverflow() {
    if (stack_overflow_) return true;
    StackLimitCheck check;
    if (!check.HasOverflowed()) return false;
    return (stack_overflow_ = true);
  }

  // If a stack-overflow exception is encountered when visiting a
  // node, calling SetStackOverflow will make sure that the visitor
  // bails out without visiting more nodes.
  void SetStackOverflow() { stack_overflow_ = true; }


  // Individual nodes
#define DEF_VISIT(type)                         \
  virtual void Visit##type(type* node) = 0;
  NODE_LIST(DEF_VISIT)
#undef DEF_VISIT

 private:
  bool stack_overflow_;
};


} }  // namespace v8::internal

#endif  // V8_AST_H_
