/*
 *  Copyright (c) 2008 Cyrille Berger <cberger@cberger.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * either version 2, or (at your option) any later version of the License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#ifndef _AST_EXPRESSION_H_
#define _AST_EXPRESSION_H_

#include "Cauchy/String.h"
#include "Cauchy/Type.h"
#include "Cauchy/AST/Statement.h"
#include "Cauchy/AST/ExpressionResult.h"

namespace Cauchy {
  class FunctionDeclaration;
  class Variable;
  namespace AST {
    /**
     * @internal
     * Base class for Expression node in the
     * @ingroup Cauchy_AST
     */
    class Expression : public Statement {
      public:
        virtual ~Expression() {}
        virtual void generateStatement( GenerationVisitor* _generationVisitor) const;
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const = 0;
        virtual const Type* type() const = 0;
    };

    /**
     * @internal
     * A ProxyExpression is used when you want to clone some part of
     * the AST tree. The main reason behind this is that, usually
     * the Expression object is owned by the parent, this means
     * when that Expression objects are deleted by the parent.
     * While the proxy Expression won't delete the Expression it
     * got in its constructor.
     * 
     * The following construct is wrong, because the expression
     * will leak:
     * @code
     * ProxyExpression pe(new NumberExpression\<int\>(10) );
     * @endcode
     * @ingroup Cauchy_AST
     */
    class ProxyExpression : public Expression {
      public:
        ProxyExpression( Expression* expr ) : m_clone( expr)
        {}
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const;
        virtual const Type* type() const { return m_clone->type(); }
      private:
        Expression* m_clone;
    };
    /**
     * @internal
     * This represent a constant value in the tree. _T_ can be a float, int or bool.
     * @ingroup Cauchy_AST
     */
    class NumberExpression : public Expression {
      public:
        explicit NumberExpression(const String& val, Type::DataType _type) : m_val(val), m_numberType(_type) { }
        String value() const { return m_val; }
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const;
        virtual const Type* type() const;
      private:
        String m_val;
        Type::DataType m_numberType;
    };
    class ComplexNumberExpression : public Expression {
      public:
        explicit ComplexNumberExpression(const String& real, const String& imag, Type::DataType _type) : m_real(real), m_imag(imag), m_numberType(_type) { }
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const;
        virtual const Type* type() const;
      private:
        String m_real, m_imag;
        Type::DataType m_numberType;
    };
    
    /**
     * @internal
     * This expression call a function.
     * @ingroup Cauchy_AST
     */
    class FunctionCallExpression : public Expression {
      public:
        FunctionCallExpression( const Variable* _variable, std::list<Expression*> _arguments, std::vector<Expression*> _returns = std::vector<Expression*>() );
        /**
         * @param _function a pointer to the function that will be called by this expression
         * @param _arguments list of expression used as argument of the function
         */
        FunctionCallExpression( const String& _function, const Cauchy::FunctionDeclaration* declaration, std::list<Expression*> _arguments, std::vector<Expression*> _returns = std::vector<Expression*>() );
        ~FunctionCallExpression();
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const;
        virtual const Type* type() const;
        String name() const { return m_function; }
      private:
        String m_function;
        const Variable* m_variable;
        std::list<Expression*> m_arguments;
        std::vector<Expression*> m_returns;
        const Cauchy::FunctionDeclaration* m_declaration;
    };
    /**
     * @internal
     * This \ref Expression is used to hold a string (i.e. "my string")
     *
     * @ingroup Cauchy_AST
     */
    class StringExpression : public Expression {
      public:
        /**
         * Construct a string expression.
         * @param _string string value
         */
        explicit StringExpression( const String& _string ) : m_string(_string)
        {
        }
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const;
        virtual const Type* type() const { return Type::String; }
      private:
        String m_string;
    };
    /**
     * @internal
     * This \ref Expression is used to hold an handle to a function (a.k.a a function pointer)
     *
     * @ingroup Cauchy_AST
     */
    class FunctionHandleExpression : public Expression {
      public:
        /**
         * Construct an identifier expression.
         * @param _identifier name of the function
         */
        explicit FunctionHandleExpression( const String& _identifier ) : m_identifier(_identifier)
        {
        }
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const;
        virtual const Type* type() const { return Type::functionHandleType(Type::defaultType(), Type::defaultType()); }
      private:
        String m_identifier;
    };
    /**
     * @internal
     * Represent a range
     * @ingroup Cauchy_AST
     */
    class RangeExpression : public Expression {
      public:
        /**
         * Construct a range expression
         */
        RangeExpression(AST::Expression* startExpression, AST::Expression* endExpression);
        ~RangeExpression();
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const;
        virtual const Type* type() const { return Type::Range; }
        bool hasStepExpression() const { return m_stepExpression; }
      private:
        AST::Expression* m_startExpression;
        AST::Expression* m_endExpression;
        AST::Expression* m_stepExpression;
    };
    /**
     * @internal
     * Represent an infinite range
     * @ingroup Cauchy_AST
     */
    class InfiniteRangeExpression : public Expression {
      public:
        /**
         * Construct a range expression
         */
        InfiniteRangeExpression();
        ~InfiniteRangeExpression();
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const;
        virtual const Type* type() const { return Type::InfiniteRange; }
      private:
    };
    /**
     * @internal
     * Represent a matrix expression (ie [1 2] or [[1 2 3][3 4 5]])
     * @ingroup Cauchy_AST
     */
    class MatrixExpression : public Expression {
      public:
        MatrixExpression( const std::vector< std::vector<AST::Expression*> >& expressions);
        ~MatrixExpression();
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const;
        virtual const Type* type() const { return m_type; }
      private:
        const Type* m_type;
        std::vector< std::vector<AST::Expression*> > m_expressions;
    };
    class VariableExpression : public Expression {
      public:
        VariableExpression( Variable*, AST::Expression* idx1, AST::Expression* idx2);
        ~VariableExpression();
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const;
        virtual const Type* type() const;
        Variable* variable() const;
        void setVariable(Variable* var) { m_var = var; }
      private:
        Cauchy::Variable* m_var;
        Expression* m_idx1;
        Expression* m_idx2;
    };
    /**
     * @internal
     * This expression group expression together, usually by enclosing them with parenthesis.
     * @ingroup Cauchy_AST
     */
    class GroupExpression : public Expression {
      public:
        explicit GroupExpression(Expression* expr) : m_expr(expr) {}
        ~GroupExpression();
        virtual ExpressionResultSP generateValue( GenerationVisitor* _generationVisitor) const;
        virtual const Type* type() const;
      private:
        Expression* m_expr;
    };    
  }

}

#endif
