/***************************************************************************
  begin                : Sat Jul 21 2001
  copyright            : (C) 2001 by Victor R�er
  email                : victor_roeder@gmx.de
  copyright            : (C) 2002,2003 by Roberto Raggi
  email                : roberto@kdevelop.org
  copyright            : (C) 2005 by Adam Treat
  email                : manyoso@yahoo.com
  copyright            : (C) 2006 by David Nolden
  email                : david.nolden.kdevelop@art-master.de
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef CPPEVALUATION_H
#define CPPEVALUATION_H

#include <qvaluelist.h>

#include "expressioninfo.h"
#include "simpletype.h"
#include "declarationinfo.h"
#include <hashedstring.h>

class SimpleContext;

void statusBarText( const QString& str, int time = 1000 );

namespace CppEvaluation {

template <class To, class From>
extern QValueList<To> convertList( const QValueList<From>& from );

extern QString nameFromType( SimpleType t );

class Operator;

struct OperatorIdentification {
  QValueList<QString> innerParams; /** Inner parameters of the operator( for the vec["hello"] the "hello" ) */
  int start, end; /** Range the operator occupies */
  bool found;
  Operator* op; ///Can be 0 !

  OperatorIdentification() : start( 0 ), end( 0 ), found( false ), op( 0 ) {}

  operator bool() {
    return found;
  }
};


class EvaluationResult {
  public:
    EvaluationResult& operator = ( const EvaluationResult& rhs ) {
      resultType = rhs.resultType;
      sourceVariable = rhs.sourceVariable;
      expr = rhs.expr;
      isMacro = rhs.isMacro;
      macro = rhs.macro;
      return *this;
    }

    EvaluationResult( const EvaluationResult& rhs ) : resultType( rhs.resultType ), expr( rhs.expr ), sourceVariable( rhs.sourceVariable ), isMacro( rhs.isMacro ), macro( rhs.macro ) {}

    LocateResult resultType; ///The resulting type

    ExpressionInfo expr; ///Information about the expression that was processed

    DeclarationInfo sourceVariable; ///If the type comes from a variable, this stores Information about it

    bool isMacro;
    Macro macro;
  
    ///should be removed
    EvaluationResult( SimpleType rhs ) : isMacro( false ) {
      if ( rhs.get() != 0 )
        resultType = rhs->desc();
    }

    EvaluationResult( LocateResult tp = TypeDesc(), DeclarationInfo var = DeclarationInfo() ) : resultType( tp ), sourceVariable( var ), isMacro( false )  {}

    /*operator TypeDesc () const {
       return (TypeDesc)resultType;
     }*/

    ///This must be removed
    operator SimpleType() const {
      if ( resultType->resolved() ) {
        return SimpleType( resultType->resolved() );
      } else {
        return SimpleType( new SimpleTypeImpl( ( TypeDesc ) resultType ) );
      }
    }

    TypeDesc* operator -> () {
      return & resultType.desc();
    }

    operator LocateResult () const {
      return resultType;
    }

    operator bool() const {
      return ( bool ) resultType;
    }
};



class Operator {
  public:
    enum BindingSide {
      Neutral = 0,
      Left = 1,
      Right = 2
  };
    enum Type {
      Unary = 1,
      Binary = 2,
      Ternary = 3
  };

    virtual ~Operator() {}

    virtual int priority() = 0;

    virtual Type type() = 0;
    virtual int paramCount() = 0;

    ///"binding" means that the operator needs the evaluated type of the expression on that side
    ///The types of all bound sides will later be sent in the "params"-list of the apply-function
    virtual BindingSide binding() = 0;  ///The side to which the operator binds

    ///When this returns true, the ident-structure must be filled correctly
    virtual OperatorIdentification identify( QString& str ) = 0;

    ///params
    virtual EvaluationResult apply( QValueList<EvaluationResult> params, QValueList<EvaluationResult> innerParams ) = 0;

    virtual QString name() = 0;

    ///Should return whether the item it the given side can be a type(Neutral stands for the inner paremeters)
    virtual bool canBeType( BindingSide side ) {
      return true;
    }

  protected:
    void log( const QString& msg );
    QString printTypeList( QValueList<EvaluationResult>& lst );
};


class OperatorSet {
  private:
    typedef QValueList< Operator* > OperatorList;
    OperatorList m_operators;
  public:
    OperatorSet() {}

    ~OperatorSet();

    void registerOperator( Operator* op ) {
      m_operators << op;
    }

    OperatorIdentification identifyOperator( const QString& str_ , Operator::BindingSide allowedBindings = ( Operator::BindingSide ) ( Operator::Left | Operator::Right | Operator::Neutral ) );

};
extern OperatorSet AllOperators;


template <class OperatorType>
class RegisterOperator {
  public:
    RegisterOperator( OperatorSet& set
                      ) {
      set.registerOperator( new OperatorType() );
    }
    ~RegisterOperator() {}
}
;


class UnaryOperator : public Operator {
  public:
    UnaryOperator( int priority , QString identString, QString description, Operator::BindingSide binding ) : Operator(), m_priority( priority ), m_identString( identString ), m_name( description ), m_binding( binding ) {}

    virtual int priority() {
      return m_priority;
    }

    virtual Operator::Type type() {
      return Operator::Unary;
    }

    virtual Operator::BindingSide binding() {
      return m_binding;
    }

    virtual int paramCount() {
      return 1;
    }

    virtual OperatorIdentification identify( QString& str );

    virtual EvaluationResult unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& innerParams ) = 0;

    virtual bool checkParams( const QValueList<EvaluationResult>& params ) {
      return !params.isEmpty() && params[ 0 ];
    }

    virtual EvaluationResult apply( QValueList<EvaluationResult> params, QValueList<EvaluationResult> innerParams );

    virtual QString name() {
      return m_name;
    }

  private:
    int m_priority;
    QString m_identString;
    QString m_name;
    Operator::BindingSide m_binding;
  protected:

    QString identString() const {
      return m_identString;
    }

};


class NestedTypeOperator : public UnaryOperator {
  public:
    NestedTypeOperator() : UnaryOperator( 18, "::", "nested-type-operator", Operator::Left ) {}

    virtual EvaluationResult unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& /*innerParams*/ );
};

//RegisterOperator< NestedTypeOperator > NestedTypeReg( AllOperators ); ///This registers the operator to the list of all operators

class DotOperator : public UnaryOperator {
  public:
    DotOperator() : UnaryOperator( 17, ".", "dot-operator", Operator::Left ) {}

    virtual EvaluationResult unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& /*innerParams*/ );

    virtual bool canBeType( BindingSide side ) {
      return false;
    }
};

class ArrowOperator : public UnaryOperator {
  public:
    ArrowOperator() : UnaryOperator( 17, "->", "arrow-operator", Operator::Left ) {}

    virtual EvaluationResult unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& innerParams );
    
	virtual bool canBeType( BindingSide side ) {
      return false;
    }
};


class StarOperator : public UnaryOperator {
  public:
    StarOperator() : UnaryOperator( 15, "*", "star-operator", Operator::Right ) { ///Normally this should have a priority of 16, but that would need changes to the expression-parsin g-loop
    }

    virtual EvaluationResult unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& /*innerParams*/ );

	virtual bool canBeType( BindingSide side ) {
		return false;
	}
};


class AddressOperator : public UnaryOperator {
  public:
    AddressOperator() : UnaryOperator( 16, "&", "address-operator", Operator::Right ) {}

    virtual EvaluationResult unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& /*innerParams*/ );

	virtual bool canBeType( BindingSide side ) {
		return false;
	}
};


class UnaryParenOperator : public UnaryOperator {
  public:
    ///Identstring should be both parens, for Example "[]" or "()"
    UnaryParenOperator( int priority , QString identString, QString description, Operator::BindingSide binding ) : UnaryOperator( priority, identString, description, binding ) {}

    virtual OperatorIdentification identify( QString& str );

	virtual bool canBeType( BindingSide side ) {
		return false;
	}
};

class IndexOperator : public UnaryParenOperator {
  public:
    IndexOperator() : UnaryParenOperator( 17, "[]", "index-operator", Operator::Left ) {}

    virtual EvaluationResult unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& innerParams );

	virtual bool canBeType( BindingSide side ) {
		return false;
	}
};


class ParenOperator : public UnaryParenOperator {
  public:
    ParenOperator() : UnaryParenOperator( 16, "()", "paren-operator", Operator::Left ) {}

    virtual bool checkParams( const QValueList<EvaluationResult>& params ) {
      return !params.isEmpty();
    }

    virtual EvaluationResult unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& innerParams );

	virtual bool canBeType( BindingSide side ) {
		return false;
	}
};

//This is used in CppCodeCompletion::evaluateExpression(..)
class ExpressionEvaluation {
  private:
    CppCodeCompletion* m_data;
    SimpleContext* m_ctx;
    ExpressionInfo m_expr;
    bool m_global;
    OperatorSet& m_operators;
    HashedStringSet m_includeFiles;

  public:
    ExpressionEvaluation( CppCodeCompletion* data, ExpressionInfo expr, OperatorSet& operators, const HashedStringSet& includeFiles, SimpleContext* ctx = 0 );

    EvaluationResult evaluate();

  private:
    /**
    recursion-method:
    1. Find the rightmost operator with the lowest priority, split the expression

    vector[ (*it)->position ]().
    */
    virtual EvaluationResult evaluateExpressionInternal( QString expr, EvaluationResult scope, SimpleContext * ctx, SimpleContext* innerCtx , bool canBeTypeExpression = true );

	///Locates types or members
    EvaluationResult evaluateAtomicExpression( TypeDesc expr, EvaluationResult scope, SimpleContext * ctx = 0, bool canBeTypeExpression = true );
};


}

#endif 
// kate: indent-mode csands; tab-width 4;
