/*
 *  Copyright (c) 2009 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 _GENERATION_VISITOR_H_
#define _GENERATION_VISITOR_H_

#include <list>
#include <vector>
#include "ExpressionResult.h"
#include "Cauchy/StdTypes.h"
#include "Cauchy/Type.h"

namespace std {
template<class _Tp >
class complex;
}

namespace Cauchy {

class CompilationMessages;
  class Function;
  class DeclarationsRegistry;
  class FunctionDeclaration;
  class String;
  class CompilationMessage;
  class Variable;
  class Type;
  namespace AST {
    class FunctionDefinition;
    class Annotation;
    class Expression;
    class Statement;
    /**
     * @internal
     * @ingroup Cauchy_AST
     *
     * This class countains the information necesseray to generate code.
     * It is then subclassed by the backends.
     */
    class GenerationVisitor {
      protected:
        GenerationVisitor();
        GenerationVisitor(const GenerationVisitor& );
        GenerationVisitor& operator=(const GenerationVisitor& );
        virtual ~GenerationVisitor();
      public:
        virtual void loadFunctionsDeclarations(DeclarationsRegistry* registry) = 0;
      public:
        virtual void startMainFunction() = 0;
        virtual void startFunction(const FunctionDefinition*) = 0;
        virtual void declareGlobal(Variable* global) = 0;
      public:
        /**
         * Generate a float 32 from @p arg1
         */
        virtual ExpressionResultSP generateNumber(const String& arg1, Type::DataType _type, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateComplexNumber(const String& _real, const String& _imag, Type::DataType _type, const Annotation& _annotation) = 0;
        /**
         * Generate a boolean from @p arg1
         */
        virtual ExpressionResultSP generateBoolean(bool arg1, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateMatrixExpression(const Type* _type, int size1, int size2, const std::list<ExpressionResultSP>& results, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateVariable(Variable* var, ExpressionResultSP idx1, ExpressionResultSP idx2, const Cauchy::AST::Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateRangeExpression(ExpressionResultSP startExpr, ExpressionResultSP endExpr, ExpressionResultSP stepExpr, const Annotation& arg4) = 0;
        /**
         * Generate an infinite range expression, ie a ":".
         */
        virtual ExpressionResultSP generateInfiniteRangeExpression() = 0;
        /**
         * Generate a function call to @p _function with arguments @p _arguments
         */
        virtual ExpressionResultSP generateFunctionCall(const String& _function, const Cauchy::FunctionDeclaration* declaration, const Variable*, const std::list<ExpressionResultSP>& _arguments, const std::vector<ExpressionResultSP>& _returns, const Annotation& _annotation) = 0;
        /**
         * Generate a string from @p arg1.
         */
        virtual ExpressionResultSP generateString(const String& arg1, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateFunctionHandle(const String& arg1, const Annotation& arg2) = 0;
        virtual ExpressionResultSP generateGroupExpression(ExpressionResultSP arg1, const Annotation& _annotation) = 0;
      public: // binary expression
        virtual ExpressionResultSP generateAndExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateOrExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        /**
         * Generate a equality comparison between two expressions.
         */
        virtual ExpressionResultSP generateEqualExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateDifferentExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateInferiorExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateInferiorEqualExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateSupperiorExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateSupperiorEqualExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateAdditionExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateSubtractionExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateMultiplicationExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateElementWiseMultiplicationExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateDivisionExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateElementWiseDivisionExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generatePowerExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateElementWisePowerExpresion(ExpressionResultSP arg1, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
      public: // Unary expressions
        virtual ExpressionResultSP generateTildExpression(ExpressionResultSP arg1, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateTransposeExpression(ExpressionResultSP arg1, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateMinusExpression(ExpressionResultSP arg1, const Annotation& _annotation) = 0;
        virtual ExpressionResultSP generateNotExpression(ExpressionResultSP arg1, const Annotation& _annotation) = 0;
      public:
        virtual ExpressionResultSP generateAssignementExpression(Variable*, ExpressionResultSP arg2, const Annotation& _annotation) = 0;
        ExpressionResultSP generateFunctionCall(const String& _function, const Cauchy::FunctionDeclaration* declaration, const Variable*, const std::list<AST::Expression*>& _arguments, const std::vector<AST::Expression*>& _returns, const Annotation& _annotation);
      protected:
        /**
         * Call this function to report an error occuring at generation time.
         */
        void reportError(const String& _message, const Annotation& _annotation);
      public:
        CompilationMessages generationMessages();
      public:
        /**
         * Generate an expresion
         */
        virtual void generateExpression(ExpressionResultSP, const String& comment, const Annotation& _annotation) = 0;
        virtual void generateComment(const String& arg1, const Annotation& _annotation) = 0;
        virtual void generatePrintStatement(ExpressionResultSP arg1, const Cauchy::String& comment, const Annotation& _annotation) = 0;
        virtual void startWhileStatement(ExpressionResultSP arg1, const String& comment, const Annotation& arg3) = 0;
        virtual void endWhileStatement(const Annotation& arg1) = 0 ;
        virtual void generateIfElseStatement(ExpressionResultSP arg1, Statement* ifStatements, const std::vector< std::pair<Expression*, Statement*> >& _elseIfStatements, Statement* elseStatement, const String& comment, const Annotation& arg3) = 0;
        virtual void generateBreak(const Annotation& arg3) = 0;
        virtual void generateForStatement(Cauchy::Variable* variable, ExpressionResultSP expr, Statement* forStatemebts, String comment, const Annotation& annotation) = 0;
        virtual void generateReturnStatement(FunctionDefinition* arg1, const String& arg2, const Annotation& arg3) = 0;
      private:
        struct Private;
        Private* const d;
    };
  }
}

#endif
