#ifndef __EXPR_H__
#define __EXPR_H__

#include "Common.h"

namespace AScript {

//-----------------------------------------------------------------------------
// Expr
//-----------------------------------------------------------------------------
class ExprVisitor {
public:
	virtual bool Visit(const Expr *pExpr) = 0;
};

class Expr {
public:
	class ExprVisitor_FindSymbol : public ExprVisitor {
	private:
		const Symbol *_pSymbol;
		bool _flag;
	public:
		inline ExprVisitor_FindSymbol(const Symbol *pSymbol) :
									_pSymbol(pSymbol), _flag(false) {}
		virtual bool Visit(const Expr *pExpr);
		inline bool GetFlag() const { return _flag; }
	};
	class ExprVisitor_GatherSymbol : public ExprVisitor {
	private:
		SymbolSet &_symbolSet;
	public:
		inline ExprVisitor_GatherSymbol(SymbolSet &symbolSet) :
												_symbolSet(symbolSet) {}
		virtual bool Visit(const Expr *pExpr);
	};
private:
	int _cntRef;	// const_cast is used to update this value
	int _lineNo;
public:
	inline Expr() : _cntRef(1), _lineNo(0) {}
	virtual ~Expr();
	virtual Expr *IncRef() const;
	inline int DecRef() { _cntRef--; return _cntRef; }
	inline int GetRefCnt() const { return _cntRef; }
	inline static void Delete(Expr *pExpr) {
		if (pExpr != NULL && pExpr->DecRef() <= 0) delete pExpr;
	}
	inline void SetLineNo(int lineNo) { _lineNo = lineNo; }
	inline int GetLineNo() const { return _lineNo; }
	bool FindSymbol(const Symbol *pSymbol) const;
	void GatherSymbol(SymbolSet &symbolSet) const;
	void SetError_NotAssignableSymbol(Signal sig, const Symbol *pSymbol) const;
	virtual Expr *Clone() const = 0;
	virtual Expr *CloneSubstituted(Environment &env, Signal sig) const;
	virtual Expr *CloneOptimized(Environment &env, Signal sig) const;
	virtual Value Exec(Environment &env, Signal sig) const = 0;
	virtual ValueType GetStaticValueType() const;
	virtual Value DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const;
	virtual Expr *Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const;
	virtual void Accept(ExprVisitor &visitor) const = 0;
	virtual const Expr *Unquote() const;
	virtual bool IsValue() const;
	virtual bool IsSymbol() const;
	virtual bool IsConstructor() const;
	virtual bool IsFunction() const;
	virtual bool IsIndexer() const;
	virtual bool IsContainer() const;
	virtual bool IsBlock() const;
	virtual bool IsBlockParam() const;
	virtual bool IsLister() const;
	virtual bool IsUnary() const;
	virtual bool IsBinary() const;
	virtual bool IsField() const;
	virtual bool IsUnaryOp() const;
	virtual bool IsBinaryOp() const;
	virtual bool IsNeg() const;
	virtual bool IsPlus() const;
	virtual bool IsMinus() const;
	virtual bool IsMultiply() const;
	virtual bool IsDivide() const;
	virtual bool IsPower() const;
	virtual bool IsAssign() const;
	virtual bool IsDictAssign() const;
	virtual bool IsContainCheck() const;
	virtual bool IsQuote() const;
	virtual bool IsForce() const;
	virtual bool IsPrefix() const;
	virtual bool IsSuffix() const;
	virtual bool IsConstZero() const;
	virtual bool IsConstOne() const;
	virtual bool IsConstMinusOne() const;
	virtual bool IsConstMinus() const;
	virtual String ToString(Signal sig) const = 0;
};

class ExprList : public std::vector<Expr *> {
private:
	class ValueVisitorEx : public ValueVisitor {
	private:
		ValueList &_valList;
	public:
		inline ValueVisitorEx(ValueList &valList) : _valList(valList) {}
		virtual void Visit(Signal sig, const Value &value);
	};
public:
	static const ExprList Null;
public:
	inline ExprList() {};
	inline ExprList(Expr *pExpr) : std::vector<Expr *>(1) {
		(*this)[0] = pExpr;
	}
	inline ExprList(Expr *pExpr1, Expr *pExpr2) : std::vector<Expr *>(2) {
		(*this)[0] = pExpr1, (*this)[1] = pExpr2;
	}
	Value Exec(Environment &env, Signal sig) const;
	Value ExecForList(Environment &env, Signal sig, bool flattenFlag) const;
	void IncRef() const;
	virtual void DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const;
	String ToString(Signal sig, const TCHAR *sep = _T(", ")) const;
	void Accept(ExprVisitor &visitor) const;
private:
	inline ExprList(const ExprList &exprList) {}; // not supported
};

class ExprOwner : public ExprList {
public:
	inline ExprOwner() {}
	ExprOwner(const ExprList &exprList);
	ExprOwner(const ExprOwner &exprOwner);
	~ExprOwner();
};

class Expr_Unary : public Expr {
private:
	ExprOwner _exprOwner;
public:
	inline Expr_Unary(Expr *pExprChild) { _exprOwner.push_back(pExprChild); }
	inline Expr_Unary(const Expr_Unary &expr) : _exprOwner(expr._exprOwner) {}
	virtual ~Expr_Unary();
	virtual bool IsUnary() const;
	virtual Expr *IncRef() const;
	virtual void Accept(ExprVisitor &visitor) const;
	inline Expr *GetExprChild() { return const_cast<Expr *>(_exprOwner[0]); }
	inline const Expr *GetExprChild() const { return _exprOwner[0]; }
	inline const ExprList &GetExprList() const { return _exprOwner; }
};

class Expr_Binary : public Expr {
private:
	ExprOwner _exprOwner;
public:
	inline Expr_Binary(Expr *pExprLeft, Expr *pExprRight) {
		_exprOwner.push_back(pExprLeft); _exprOwner.push_back(pExprRight);
	}
	inline Expr_Binary(const Expr_Binary &expr) : _exprOwner(expr._exprOwner) {}
	virtual ~Expr_Binary();
	virtual bool IsBinary() const;
	virtual Expr *IncRef() const;
	virtual void Accept(ExprVisitor &visitor) const;
	inline Expr *GetExprLeft() { return const_cast<Expr *>(_exprOwner[0]); }
	inline Expr *GetExprRight() { return const_cast<Expr *>(_exprOwner[1]); }
	inline const Expr *GetExprLeft() const { return _exprOwner[0]; }
	inline const Expr *GetExprRight() const { return _exprOwner[1]; }
	inline const ExprList &GetExprList() const { return _exprOwner; }
};

class Expr_Value : public Expr {
protected:
	const Value _value;
public:
	inline Expr_Value(Number num) : _value(num) {}
	inline Expr_Value(const Complex &comp) : _value(comp) {}
	inline Expr_Value(const Value &value) : _value(value) {}
	inline Expr_Value(const Expr_Value &expr) : _value(expr._value) {}
	virtual ~Expr_Value();
	virtual Expr *IncRef() const;
	inline const Value &GetValue() const { return _value; }
	virtual bool IsValue() const;
	virtual bool IsConstZero() const;
	virtual bool IsConstOne() const;
	virtual bool IsConstMinusOne() const;
	virtual bool IsConstMinus() const;
	virtual Expr *Clone() const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual ValueType GetStaticValueType() const;
	virtual Expr *Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const;
	virtual void Accept(ExprVisitor &visitor) const;
	virtual String ToString(Signal sig) const;
};

class Expr_Symbol : public Expr {
protected:
	const Symbol *_pSymbol;
	SymbolSet _attrs;
public:
	inline Expr_Symbol(const Symbol *pSymbol) : _pSymbol(pSymbol) {}
	inline Expr_Symbol(const Expr_Symbol &expr) :
							_pSymbol(expr._pSymbol), _attrs(expr._attrs) {}
	virtual ~Expr_Symbol();
	virtual Expr *IncRef() const;
	virtual bool IsSymbol() const;
	virtual Expr *Clone() const;
	virtual Expr *CloneSubstituted(Environment &env, Signal sig) const;
	virtual Expr *CloneOptimized(Environment &env, Signal sig) const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual Value DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const;
	virtual Expr *Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const;
	virtual void Accept(ExprVisitor &visitor) const;
	inline void AddAttr(const Symbol *pSymbol) { _attrs.Insert(pSymbol); }
	inline const SymbolSet &GetAttrs() const { return _attrs; }
	inline const Symbol *GetSymbol() const { return _pSymbol; }
	virtual String ToString(Signal sig) const;
};

class Expr_Container : public Expr {
protected:
	ExprOwner _exprOwner;
public:
	inline Expr_Container() {}
	inline Expr_Container(const Expr_Container &expr) : _exprOwner(expr._exprOwner) {}
	virtual bool IsContainer() const;
	virtual ~Expr_Container();
	virtual Expr *IncRef() const;
	virtual void Accept(ExprVisitor &visitor) const;
	inline void AddExpr(Expr *pExpr) { _exprOwner.push_back(pExpr); }
	inline ExprList &GetExprList() { return _exprOwner; }
	inline const ExprList &GetExprList() const { return _exprOwner; }
};

class Expr_BlockParam : public Expr_Container {
public:
	inline Expr_BlockParam() {}
	inline Expr_BlockParam(const Expr_BlockParam &expr) : Expr_Container(expr) {}
	virtual ~Expr_BlockParam();
	virtual bool IsBlockParam() const;
	virtual Expr *Clone() const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual String ToString(Signal sig) const;
};

class Expr_Block : public Expr_Container {
protected:
	Expr_BlockParam *_pExprBlockParam;	// this may be NULL
public:
	inline Expr_Block() : _pExprBlockParam(NULL) {}
	inline Expr_Block(const Expr_Block &expr) : Expr_Container(expr),
		_pExprBlockParam((expr._pExprBlockParam == NULL)? NULL :
				dynamic_cast<Expr_BlockParam *>(expr._pExprBlockParam->Clone())) {}
	virtual ~Expr_Block();
	virtual bool IsBlock() const;
	virtual Expr *Clone() const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual void Accept(ExprVisitor &visitor) const;
	virtual String ToString(Signal sig) const;
	inline void SetParam(Expr_BlockParam *pExprBlockParam) {
		_pExprBlockParam = pExprBlockParam;
	}
	inline const Expr_BlockParam *GetParam() const { return _pExprBlockParam; }
};

class Expr_Lister : public Expr_Container {
public:
	inline Expr_Lister() {}
	inline Expr_Lister(const Expr_Lister &expr) : Expr_Container(expr) {}
	virtual ~Expr_Lister();
	virtual bool IsLister() const;
	virtual Expr *Clone() const;
	virtual Expr *CloneOptimized(Environment &env, Signal sig) const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual Value DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const;
	virtual Expr *Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const;
	virtual String ToString(Signal sig) const;
};

class Expr_Indexer : public Expr {
private:
	class ValueVisitor_AssignList : public ValueVisitor {
	private:
		Object &_objDst;
		const ValueList &_valListSrc;
		ValueList::const_iterator _pValueSrc;
	public:
		inline ValueVisitor_AssignList(Object &objDst, const ValueList &valListSrc) :
								_objDst(objDst), _valListSrc(valListSrc),
								_pValueSrc(valListSrc.begin()) {}
		virtual void Visit(Signal sig, const Value &valueIdx);
	};
	class ValueVisitor_AssignValue : public ValueVisitor {
	private:
		Object &_objDst;
		const Value &_value;
	public:
		inline ValueVisitor_AssignValue(Object &objDst, const Value &value) :
								_objDst(objDst), _value(value) {}
		virtual void Visit(Signal sig, const Value &valueIdx);
	};
protected:
	Expr *_pExprCar;
	Expr_Lister *_pExprLister;
public:
	inline Expr_Indexer(Expr *pExprCar, Expr_Lister *pExprLister) :
								_pExprCar(pExprCar), _pExprLister(pExprLister) {}
	inline Expr_Indexer(const Expr_Indexer &expr) :
			_pExprCar(expr._pExprCar->Clone()),
			_pExprLister(dynamic_cast<Expr_Lister *>(expr._pExprLister->Clone())) {}
	virtual ~Expr_Indexer();
	virtual Expr *IncRef() const;
	inline Expr *GetExprCar() { return _pExprCar; }
	inline const Expr *GetExprCar() const { return _pExprCar; }
	inline Expr_Lister *GetExprLister() { return _pExprLister; }
	inline const Expr_Lister *GetExprLister() const { return _pExprLister; }
	virtual bool IsIndexer() const;
	virtual Expr *Clone() const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual Value DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const;
	virtual void Accept(ExprVisitor &visitor) const;
	virtual String ToString(Signal sig) const;
	static TCHAR GetStringChar(Signal sig,
						const TCHAR *str, size_t len, const Value &valueIdx);
};

class Expr_Function : public Expr {
protected:
	const Function *_pFunc;			// set to NULL if parser create this instance
	SymbolSet _attrs;
	SymbolSet _attrsOpt;
	Expr *_pExprCar;
	Expr_Lister *_pExprLister;
	Expr_Block *_pExprBlock;		// this may be NULL
	Expr_Function *_pExprFuncSucc;	// this may be NULL
public:
	Expr_Function(Expr *pExprCar, Expr_Lister *pExprLister, Expr_Block *pExprBlock);
	Expr_Function(const Function *pFunc, Expr *pExprArg);
	Expr_Function(const Function *pFunc, Expr *pExprArg1, Expr *pExprArg2);
	Expr_Function(const Expr_Function &expr);
	virtual ~Expr_Function();
	virtual Expr *IncRef() const;
	virtual bool IsFunction() const;
	virtual Expr *Clone() const;
	virtual Expr *CloneOptimized(Environment &env, Signal sig) const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual Value DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const;
	virtual Expr *Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const;
	virtual void Accept(ExprVisitor &visitor) const;
	inline void AddAttr(const Symbol *pSymbol) { _attrs.Insert(pSymbol); }
	inline void AddAttrOpt(const Symbol *pSymbol) { _attrsOpt.Insert(pSymbol); }
	inline const SymbolSet &GetAttrs() const { return _attrs; }
	inline const SymbolSet &GetAttrsOpt() const { return _attrsOpt; }
	inline void SetBlock(Expr_Block *pExprBlock) {
		Expr::Delete(_pExprBlock);
		_pExprBlock = pExprBlock;
	}
	inline void SetSucceeding(Expr_Function *pExprFunc) {
		// _pExprFuncSucc must be NULL at this time
		_pExprFuncSucc = pExprFunc;
	}
	inline const Expr *GetExprCar() const { return _pExprCar; }
	inline ExprList &GetExprList() { return _pExprLister->GetExprList(); }
	inline const ExprList &GetExprList() const { return _pExprLister->GetExprList(); }
	inline const Expr_Block *GetBlock() const { return _pExprBlock; }
	virtual String ToString(Signal sig) const;
	inline const Expr_Function *GetSucceeding() const { return _pExprFuncSucc; }
	inline Expr_Function *GetLastSucceeding() {
		return (_pExprFuncSucc == NULL)? this : _pExprFuncSucc->GetLastSucceeding();
	}
	Value EvalFunction(Environment &env, Signal sig,
		Value &valueSelf, Value &value, const Function **ppFuncSuccRequester) const;
private:
	Value ExecEach(Environment &env, Signal sig, const Function **ppFuncSuccRequester) const;
};

class Expr_UnaryOp : public Expr_Unary {
protected:
	const Function &_func;
public:
	Expr_UnaryOp(const Function &func, Expr *pExprChild);
	inline Expr_UnaryOp(const Expr_UnaryOp &expr) :
							Expr_Unary(expr), _func(expr._func) {}
	virtual ~Expr_UnaryOp();
	virtual Expr *Clone() const;
	virtual Expr *CloneOptimized(Environment &env, Signal sig) const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual Expr *Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const;
	virtual bool IsUnaryOp() const;
	virtual bool IsNeg() const;
	virtual String ToString(Signal sig) const;
};

class Expr_BinaryOp : public Expr_Binary {
protected:
	const Function &_func;
public:
	Expr_BinaryOp(const Function &func, Expr *pExprLeft, Expr *pExprRight);
	inline Expr_BinaryOp(const Expr_BinaryOp &expr) :
							Expr_Binary(expr), _func(expr._func) {}
	virtual ~Expr_BinaryOp();
	virtual Expr *Clone() const;
	virtual Expr *CloneOptimized(Environment &env, Signal sig) const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual Expr *Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const;
	virtual bool IsBinaryOp() const;
	virtual bool IsPlus() const;
	virtual bool IsMinus() const;
	virtual bool IsMultiply() const;
	virtual bool IsDivide() const;
	virtual bool IsPower() const;
	virtual bool IsContainCheck() const;
	virtual String ToString(Signal sig) const;
};

class Expr_Quote : public Expr_Unary {
public:
	inline Expr_Quote(Expr *pExprChild) : Expr_Unary(pExprChild) {}
	inline Expr_Quote(const Expr_Quote &expr) : Expr_Unary(expr) {}
	virtual ~Expr_Quote();
	virtual Expr *Clone() const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual Expr *Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const;
	virtual ValueType GetStaticValueType() const;
	virtual const Expr *Unquote() const;
	virtual bool IsQuote() const;
	virtual String ToString(Signal sig) const;
};

class Expr_Force : public Expr_Unary {
public:
	inline Expr_Force(Expr *pExprChild) : Expr_Unary(pExprChild) {}
	inline Expr_Force(const Expr_Force &expr) : Expr_Unary(expr) {}
	virtual ~Expr_Force();
	virtual Expr *Clone() const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual bool IsForce() const;
	virtual String ToString(Signal sig) const;
};

class Expr_Prefix : public Expr_Unary {
private:
	const Symbol *_pSymbol;
public:
	inline Expr_Prefix(Expr *pExprChild, const Symbol *pSymbol) :
							Expr_Unary(pExprChild), _pSymbol(pSymbol) {}
	inline Expr_Prefix(const Expr_Prefix &expr) :
							Expr_Unary(expr), _pSymbol(expr._pSymbol) {}
	virtual ~Expr_Prefix();
	virtual Expr *Clone() const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual bool IsPrefix() const;
	inline const Symbol *GetSymbol() const { return _pSymbol; }
	virtual String ToString(Signal sig) const;
};

class Expr_Suffix : public Expr_Unary {
private:
	const Symbol *_pSymbol;
public:
	inline Expr_Suffix(Expr *pExprChild, const Symbol *pSymbol) :
							Expr_Unary(pExprChild), _pSymbol(pSymbol) {}
	inline Expr_Suffix(const Expr_Suffix &expr) :
							Expr_Unary(expr), _pSymbol(expr._pSymbol) {}
	virtual ~Expr_Suffix();
	virtual Expr *Clone() const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual bool IsSuffix() const;
	inline const Symbol *GetSymbol() const { return _pSymbol; }
	OccurPattern GetOccurPattern() const;
	virtual String ToString(Signal sig) const;
};

class Expr_Assign : public Expr_Binary {
private:
	const Function *_pFuncToApply;
public:
	inline Expr_Assign(Expr *pExprLeft, Expr *pExprRight, const Function *pFuncToApply) :
				Expr_Binary(pExprLeft, pExprRight), _pFuncToApply(pFuncToApply) {}
	inline Expr_Assign(const Expr_Assign &expr) :
				Expr_Binary(expr), _pFuncToApply(expr._pFuncToApply) {}
	virtual ~Expr_Assign();
	virtual Value Exec(Environment &env, Signal sig) const;
	Value Exec(Environment &env, Signal sig,
				Environment &envDst, const SymbolSet *pSymbolsAssignable) const;
	virtual Expr *Clone() const;
	virtual bool IsAssign() const;
	virtual String ToString(Signal sig) const;
};

class Expr_DictAssign : public Expr_Binary {
public:
	inline Expr_DictAssign(Expr *pExprLeft, Expr *pExprRight) :
									Expr_Binary(pExprLeft, pExprRight) {}
	inline Expr_DictAssign(const Expr_DictAssign &expr) : Expr_Binary(expr) {}
	virtual ~Expr_DictAssign();
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual Expr *Clone() const;
	virtual bool IsDictAssign() const;
	virtual String ToString(Signal sig) const;
	Value GetKey(Signal sig) const;
};

class Expr_Field : public Expr_Binary {
private:
	int _fieldDepthLevel;
public:
	inline Expr_Field(Expr *pExprLeft, Expr *pExprRight, int fieldDepthLevel) :
			Expr_Binary(pExprLeft, pExprRight), _fieldDepthLevel(fieldDepthLevel) {}
	inline Expr_Field(const Expr_Field &expr) : Expr_Binary(expr),
									_fieldDepthLevel(expr._fieldDepthLevel) {}
	inline int GetFieldDepthLevel() const { return _fieldDepthLevel; }
	virtual ~Expr_Field();
	virtual Expr *Clone() const;
	virtual Value Exec(Environment &env, Signal sig) const;
	virtual Value DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const;
	virtual bool IsField() const;
	virtual String ToString(Signal sig) const;
};

}

#endif
