//===--- ExprObjC.h - Classes for representing ObjC expressions -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the ExprObjC interface and subclasses.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_EXPROBJC_H
#define LLVM_CLANG_AST_EXPROBJC_H

#include "clang/AST/Expr.h"
#include "clang/Basic/IdentifierTable.h"

namespace clang {
  class IdentifierInfo;
  class ASTContext;
  class ObjCMethodDecl;
  class ObjCPropertyDecl;
  
/// ObjCStringLiteral, used for Objective-C string literals
/// i.e. @"foo".
class ObjCStringLiteral : public Expr {
  Stmt *String;
  SourceLocation AtLoc;
public:
  ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L)
    : Expr(ObjCStringLiteralClass, T), String(SL), AtLoc(L) {}
  
  StringLiteral* getString() { return cast<StringLiteral>(String); }
  const StringLiteral* getString() const { return cast<StringLiteral>(String); }

  SourceLocation getAtLoc() const { return AtLoc; }

  virtual SourceRange getSourceRange() const { 
    return SourceRange(AtLoc, String->getLocEnd());
  }
  
  static bool classof(const Stmt *T) { 
    return T->getStmtClass() == ObjCStringLiteralClass; 
  }
  static bool classof(const ObjCStringLiteral *) { return true; }  
  
  // Iterators
  virtual child_iterator child_begin();
  virtual child_iterator child_end();
  
  virtual void EmitImpl(llvm::Serializer& S) const;
  static ObjCStringLiteral* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};
  
/// ObjCEncodeExpr, used for @encode in Objective-C.
class ObjCEncodeExpr : public Expr {
  QualType EncType;
  SourceLocation AtLoc, RParenLoc;
public:
  ObjCEncodeExpr(QualType T, QualType ET, 
                 SourceLocation at, SourceLocation rp)
    : Expr(ObjCEncodeExprClass, T), EncType(ET), AtLoc(at), RParenLoc(rp) {}
  
  SourceLocation getAtLoc() const { return AtLoc; }
  SourceLocation getRParenLoc() const { return RParenLoc; }
  
  virtual SourceRange getSourceRange() const {
    return SourceRange(AtLoc, RParenLoc);
  }

  QualType getEncodedType() const { return EncType; }

  static bool classof(const Stmt *T) {
    return T->getStmtClass() == ObjCEncodeExprClass;
  }
  static bool classof(const ObjCEncodeExpr *) { return true; }
  
  // Iterators
  virtual child_iterator child_begin();
  virtual child_iterator child_end();
  
  virtual void EmitImpl(llvm::Serializer& S) const;
  static ObjCEncodeExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};

/// ObjCSelectorExpr used for @selector in Objective-C.
class ObjCSelectorExpr : public Expr {
  Selector SelName;
  SourceLocation AtLoc, RParenLoc;
public:
  ObjCSelectorExpr(QualType T, Selector selInfo,
                   SourceLocation at, SourceLocation rp)
  : Expr(ObjCSelectorExprClass, T), SelName(selInfo), 
  AtLoc(at), RParenLoc(rp) {}
  
  Selector getSelector() const { return SelName; }
  
  SourceLocation getAtLoc() const { return AtLoc; }
  SourceLocation getRParenLoc() const { return RParenLoc; }

  virtual SourceRange getSourceRange() const {
    return SourceRange(AtLoc, RParenLoc);
  }
  
  /// getNumArgs - Return the number of actual arguments to this call.
  unsigned getNumArgs() const { return SelName.getNumArgs(); }
  
  static bool classof(const Stmt *T) {
    return T->getStmtClass() == ObjCSelectorExprClass;
  }
  static bool classof(const ObjCSelectorExpr *) { return true; }
  
  // Iterators
  virtual child_iterator child_begin();
  virtual child_iterator child_end();

  virtual void EmitImpl(llvm::Serializer& S) const;
  static ObjCSelectorExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};
  
/// ObjCProtocolExpr used for protocol in Objective-C.
class ObjCProtocolExpr : public Expr {    
  ObjCProtocolDecl *Protocol;    
  SourceLocation AtLoc, RParenLoc;
public:
  ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol,
                   SourceLocation at, SourceLocation rp)
  : Expr(ObjCProtocolExprClass, T), Protocol(protocol), 
  AtLoc(at), RParenLoc(rp) {}
    
  ObjCProtocolDecl *getProtocol() const { return Protocol; }
    
  SourceLocation getAtLoc() const { return AtLoc; }
  SourceLocation getRParenLoc() const { return RParenLoc; }

  virtual SourceRange getSourceRange() const {
    return SourceRange(AtLoc, RParenLoc);
  }
        
  static bool classof(const Stmt *T) {
    return T->getStmtClass() == ObjCProtocolExprClass;
  }
  static bool classof(const ObjCProtocolExpr *) { return true; }
    
  // Iterators
  virtual child_iterator child_begin();
  virtual child_iterator child_end();

  virtual void EmitImpl(llvm::Serializer& S) const;
  static ObjCProtocolExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};

/// ObjCIvarRefExpr - A reference to an ObjC instance variable.
class ObjCIvarRefExpr : public Expr {
  class ObjCIvarDecl *D;
  SourceLocation Loc;
  Stmt *Base;
  bool IsArrow:1;      // True if this is "X->F", false if this is "X.F".
  bool IsFreeIvar:1;   // True if ivar reference has no base (self assumed).
  
public:
  ObjCIvarRefExpr(ObjCIvarDecl *d,
                  QualType t, SourceLocation l, Expr *base=0, 
                  bool arrow = false, bool freeIvar = false) : 
    Expr(ObjCIvarRefExprClass, t), D(d),
    Loc(l), Base(base), IsArrow(arrow),
    IsFreeIvar(freeIvar) {}
  
  ObjCIvarDecl *getDecl() { return D; }
  const ObjCIvarDecl *getDecl() const { return D; }
  virtual SourceRange getSourceRange() const { 
    return isFreeIvar() ? SourceRange(Loc)
                        : SourceRange(getBase()->getLocStart(), Loc); 
  }
  const Expr *getBase() const { return cast<Expr>(Base); }
  Expr *getBase() { return cast<Expr>(Base); }
  void setBase(Expr * base) { Base = base; }
  bool isArrow() const { return IsArrow; }
  bool isFreeIvar() const { return IsFreeIvar; }
  
  SourceLocation getLocation() const { return Loc; }
  
  static bool classof(const Stmt *T) { 
    return T->getStmtClass() == ObjCIvarRefExprClass; 
  }
  static bool classof(const ObjCIvarRefExpr *) { return true; }
  
  // Iterators
  virtual child_iterator child_begin();
  virtual child_iterator child_end();
  
  virtual void EmitImpl(llvm::Serializer& S) const;
  static ObjCIvarRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};

/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC
/// property.
///
class ObjCPropertyRefExpr : public Expr {
private:
  ObjCPropertyDecl *AsProperty;
  SourceLocation IdLoc;
  Stmt *Base;
  
public:
  ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, 
                      SourceLocation l, Expr *base)
    : Expr(ObjCPropertyRefExprClass, t), AsProperty(PD), IdLoc(l), Base(base) {
  }
  ObjCPropertyDecl *getProperty() const {
    return AsProperty;
  }
  
  virtual SourceRange getSourceRange() const {
    return SourceRange(getBase()->getLocStart(), IdLoc);
  }
  const Expr *getBase() const { return cast<Expr>(Base); }
  Expr *getBase() { return cast<Expr>(Base); }
  void setBase(Expr * base) { Base = base; }
  
  SourceLocation getLocation() const { return IdLoc; }

  static bool classof(const Stmt *T) { 
    return T->getStmtClass() == ObjCPropertyRefExprClass; 
  }
  static bool classof(const ObjCPropertyRefExpr *) { return true; }
  
  // Iterators
  virtual child_iterator child_begin();
  virtual child_iterator child_end();
  
  virtual void EmitImpl(llvm::Serializer& S) const;
  static ObjCPropertyRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};

/// ObjCKVCRefExpr - A dot-syntax expression to access "implicit" properties 
/// (i.e. methods following the property naming convention). KVC stands for
/// Key Value Encoding, a generic concept for accessing or setting a 'Key'
/// value for an object.
///

class ObjCKVCRefExpr : public Expr {
private:
  
  ObjCMethodDecl *Setter;
  ObjCMethodDecl *Getter;
  SourceLocation Loc;
  Stmt *Base;
    
public:
  ObjCKVCRefExpr(ObjCMethodDecl *getter,
                 QualType t, 
                 ObjCMethodDecl *setter,
                 SourceLocation l, Expr *base)
    : Expr(ObjCKVCRefExprClass, t), Setter(setter),
      Getter(getter), Loc(l), Base(base) {
    }
  
  ObjCMethodDecl *getGetterMethod() const {
      return Getter;
  }
  ObjCMethodDecl *getSetterMethod() const {
    return Setter;
  }
    
  virtual SourceRange getSourceRange() const { 
    return SourceRange(getBase()->getLocStart(), Loc); 
  }
  const Expr *getBase() const { return cast<Expr>(Base); }
  Expr *getBase() { return cast<Expr>(Base); }
  void setBase(Expr * base) { Base = base; }
    
  SourceLocation getLocation() const { return Loc; }
    
  static bool classof(const Stmt *T) { 
    return T->getStmtClass() == ObjCKVCRefExprClass; 
  }
  static bool classof(const ObjCKVCRefExpr *) { return true; }
    
  // Iterators
  virtual child_iterator child_begin();
  virtual child_iterator child_end();
    
  virtual void EmitImpl(llvm::Serializer& S) const;
  static ObjCKVCRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};
  
class ObjCMessageExpr : public Expr {
  // SubExprs - The receiver and arguments of the message expression.
  Stmt **SubExprs;
  
  // NumArgs - The number of arguments (not including the receiver) to the
  //  message expression.
  unsigned NumArgs;
  
  // A unigue name for this message.
  Selector SelName;
  
  // A method prototype for this message (optional). 
  // FIXME: Since method decls contain the selector, and most messages have a
  // prototype, consider devising a scheme for unifying SelName/MethodProto.
  ObjCMethodDecl *MethodProto;

  SourceLocation LBracloc, RBracloc;

  // Constants for indexing into SubExprs.
  enum { RECEIVER=0, ARGS_START=1 };

  // Bit-swizziling flags.
  enum { IsInstMeth=0, IsClsMethDeclUnknown, IsClsMethDeclKnown, Flags=0x3 };
  unsigned getFlag() const { return (uintptr_t) SubExprs[RECEIVER] & Flags; }
  
  // constructor used during deserialization
  ObjCMessageExpr(Selector selInfo, QualType retType,
                  SourceLocation LBrac, SourceLocation RBrac,
                  Stmt **subexprs, unsigned nargs)
  : Expr(ObjCMessageExprClass, retType), SubExprs(subexprs),
    NumArgs(nargs), SelName(selInfo), MethodProto(NULL),
    LBracloc(LBrac), RBracloc(RBrac) {}
  
public:
  /// This constructor is used to represent class messages where the
  /// ObjCInterfaceDecl* of the receiver is not known.
  ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
                  QualType retType, ObjCMethodDecl *methDecl,
                  SourceLocation LBrac, SourceLocation RBrac,
                  Expr **ArgExprs, unsigned NumArgs);

  /// This constructor is used to represent class messages where the
  /// ObjCInterfaceDecl* of the receiver is known.
  // FIXME: clsName should be typed to ObjCInterfaceType
  ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo,
                  QualType retType, ObjCMethodDecl *methDecl,
                  SourceLocation LBrac, SourceLocation RBrac,
                  Expr **ArgExprs, unsigned NumArgs);
  
  // constructor for instance messages.
  ObjCMessageExpr(Expr *receiver, Selector selInfo,
                  QualType retType, ObjCMethodDecl *methDecl,
                  SourceLocation LBrac, SourceLocation RBrac,
                  Expr **ArgExprs, unsigned NumArgs);
  
  ~ObjCMessageExpr() {
    delete [] SubExprs;
  }
  
  /// getReceiver - Returns the receiver of the message expression.
  ///  This can be NULL if the message is for class methods.  For
  ///  class methods, use getClassName.
  /// FIXME: need to handle/detect 'super' usage within a class method.
  Expr *getReceiver() { 
    uintptr_t x = (uintptr_t) SubExprs[RECEIVER];
    return (x & Flags) == IsInstMeth ? (Expr*) x : 0;
  }  
  const Expr *getReceiver() const {
    return const_cast<ObjCMessageExpr*>(this)->getReceiver();
  }
  
  Selector getSelector() const { return SelName; }

  const ObjCMethodDecl *getMethodDecl() const { return MethodProto; }
  ObjCMethodDecl *getMethodDecl() { return MethodProto; }

  typedef std::pair<ObjCInterfaceDecl*, IdentifierInfo*> ClassInfo;
  
  /// getClassInfo - For class methods, this returns both the ObjCInterfaceDecl*
  ///  and IdentifierInfo* of the invoked class.  Both can be NULL if this
  ///  is an instance message, and the ObjCInterfaceDecl* can be NULL if none
  ///  was available when this ObjCMessageExpr object was constructed.  
  ClassInfo getClassInfo() const;  
  
  /// getClassName - For class methods, this returns the invoked class,
  ///  and returns NULL otherwise.  For instance methods, use getReceiver.  
  IdentifierInfo *getClassName() const {
    return getClassInfo().second;
  }

  
  /// getNumArgs - Return the number of actual arguments to this call.
  unsigned getNumArgs() const { return NumArgs; }

  /// getArg - Return the specified argument.
  Expr *getArg(unsigned Arg) {
    assert(Arg < NumArgs && "Arg access out of range!");
    return cast<Expr>(SubExprs[Arg+ARGS_START]);
  }
  const Expr *getArg(unsigned Arg) const {
    assert(Arg < NumArgs && "Arg access out of range!");
    return cast<Expr>(SubExprs[Arg+ARGS_START]);
  }
  /// setArg - Set the specified argument.
  void setArg(unsigned Arg, Expr *ArgExpr) {
    assert(Arg < NumArgs && "Arg access out of range!");
    SubExprs[Arg+ARGS_START] = ArgExpr;
  }

  virtual SourceRange getSourceRange() const {
    return SourceRange(LBracloc, RBracloc);
  }

  static bool classof(const Stmt *T) {
    return T->getStmtClass() == ObjCMessageExprClass;
  }
  static bool classof(const ObjCMessageExpr *) { return true; }
  
  // Iterators
  virtual child_iterator child_begin();
  virtual child_iterator child_end();
  
  typedef ExprIterator arg_iterator;
  typedef ConstExprIterator const_arg_iterator;
  
  arg_iterator arg_begin() { return &SubExprs[ARGS_START]; }
  arg_iterator arg_end()   { return &SubExprs[ARGS_START] + NumArgs; }
  const_arg_iterator arg_begin() const { return &SubExprs[ARGS_START]; }
  const_arg_iterator arg_end() const { return &SubExprs[ARGS_START] + NumArgs; }
  
  // Serialization.
  virtual void EmitImpl(llvm::Serializer& S) const;
  static ObjCMessageExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};

/// ObjCSuperExpr - Represents the "super" expression in Objective-C,
/// which refers to the object on which the current method is executing.
class ObjCSuperExpr : public Expr {
  SourceLocation Loc;

public:
  ObjCSuperExpr(SourceLocation L, QualType Type) 
    : Expr(ObjCSuperExprClass, Type), Loc(L) { }

  virtual SourceRange getSourceRange() const { return SourceRange(Loc); }

  static bool classof(const Stmt *T) { 
    return T->getStmtClass() == ObjCSuperExprClass;
  }
  static bool classof(const ObjCSuperExpr *) { return true; }

  // Iterators
  virtual child_iterator child_begin();
  virtual child_iterator child_end();
  
  virtual void EmitImpl(llvm::Serializer& S) const;
  static ObjCSuperExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);  
};

}  // end namespace clang

#endif
