/*
 *  Copyright (c) 2010 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.
 */

#include <Cauchy/AST/GenerationVisitor.h>

namespace Cauchy {
  class FunctionDeclaration;
  class Options;
}

namespace EigenBackend {
  class GenerationVisitor : public Cauchy::AST::GenerationVisitor {
    public:
      GenerationVisitor(const Cauchy::Options& options);
      virtual ~GenerationVisitor();
      Cauchy::String result() const;
    public:
      virtual void loadFunctionsDeclarations(Cauchy::DeclarationsRegistry* registry);
    public:
        virtual void startMainFunction();
        virtual void startFunction(const Cauchy::AST::FunctionDefinition* );
        virtual void declareGlobal(Cauchy::Variable* global);
    public:
      virtual Cauchy::AST::ExpressionResultSP generateNumber(const Cauchy::String& arg1, Cauchy::Type::DataType _type, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateComplexNumber(const Cauchy::String& _real, const Cauchy::String& _imag, Cauchy::Type::DataType _type, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateBoolean(bool arg1, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateMatrixExpression(const Cauchy::Type* _type, int size1, int size2, const std::list< Cauchy::AST::ExpressionResultSP >& results, const Cauchy::AST::Annotation&);
      virtual Cauchy::AST::ExpressionResultSP generateVariable(Cauchy::Variable* var, Cauchy::AST::ExpressionResultSP idx1, Cauchy::AST::ExpressionResultSP idx2, const Cauchy::AST::Annotation& annotation);
      virtual Cauchy::AST::ExpressionResultSP generateRangeExpression(Cauchy::AST::ExpressionResultSP startExpr, Cauchy::AST::ExpressionResultSP endExpr, Cauchy::AST::ExpressionResultSP stepExpr, const Cauchy::AST::Annotation& arg4);
      virtual Cauchy::AST::ExpressionResultSP generateInfiniteRangeExpression();
      virtual Cauchy::AST::ExpressionResultSP generateAssignementExpression(Cauchy::Variable*, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateFunctionCall(const Cauchy::String& _function, const Cauchy::FunctionDeclaration* declaration, const Cauchy::Variable* _variable, const std::list<Cauchy::AST::ExpressionResultSP>& _arguments, const std::vector<Cauchy::AST::ExpressionResultSP>& _returns, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateString(const Cauchy::String& arg1, const Cauchy::AST::Annotation&);
      virtual Cauchy::AST::ExpressionResultSP generateFunctionHandle(const Cauchy::String& arg1, const Cauchy::AST::Annotation& arg2);
      virtual Cauchy::AST::ExpressionResultSP generateGroupExpression(Cauchy::AST::ExpressionResultSP arg1, const Cauchy::AST::Annotation& _annotation);
    public: // binary expression
      virtual Cauchy::AST::ExpressionResultSP generateAndExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateOrExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateEqualExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateDifferentExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateInferiorExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateInferiorEqualExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateSupperiorExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateSupperiorEqualExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateAdditionExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateSubtractionExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateMultiplicationExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateElementWiseMultiplicationExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateDivisionExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateElementWiseDivisionExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generatePowerExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateElementWisePowerExpresion(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::ExpressionResultSP arg2, const Cauchy::AST::Annotation& _annotation);
    public: // Unary expressions
      virtual Cauchy::AST::ExpressionResultSP generateTildExpression(Cauchy::AST::ExpressionResultSP arg1, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateTransposeExpression(Cauchy::AST::ExpressionResultSP arg1, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateMinusExpression(Cauchy::AST::ExpressionResultSP arg1, const Cauchy::AST::Annotation& _annotation);
      virtual Cauchy::AST::ExpressionResultSP generateNotExpression(Cauchy::AST::ExpressionResultSP arg1, const Cauchy::AST::Annotation& _annotation);
    public: // Statements
      virtual void generateExpression(Cauchy::AST::ExpressionResultSP, const Cauchy::String& comment, const Cauchy::AST::Annotation& _annotation);
      virtual void generateComment(const Cauchy::String& arg1, const Cauchy::AST::Annotation& _annotation);
      virtual void generatePrintStatement(Cauchy::AST::ExpressionResultSP arg1, const Cauchy::String& comment, const Cauchy::AST::Annotation& _annotation);
      virtual void startWhileStatement(Cauchy::AST::ExpressionResultSP arg1, const Cauchy::String& comment, const Cauchy::AST::Annotation& arg3);
      virtual void endWhileStatement(const Cauchy::AST::Annotation& arg1);
      virtual void generateIfElseStatement(Cauchy::AST::ExpressionResultSP arg1, Cauchy::AST::Statement* ifStatements, const std::vector< std::pair<Cauchy::AST::Expression*, Cauchy::AST::Statement*> >& _elseIfStatements, Cauchy::AST::Statement* elseStatement, const Cauchy::String& comment, const Cauchy::AST::Annotation& arg3);
      virtual void generateForStatement(Cauchy::Variable* variable, Cauchy::AST::ExpressionResultSP expr, Cauchy::AST::Statement* forStatemebts, Cauchy::String comment, const Cauchy::AST::Annotation& annotation);
      virtual void generateBreak(const Cauchy::AST::Annotation& arg3);
      virtual void generateReturnStatement(Cauchy::AST::FunctionDefinition* arg1, const Cauchy::String& arg2, const Cauchy::AST::Annotation& arg3);
    private:
      struct Private;
      Private* const d;
  };
}
