/*
 *  Copyright (c) 2008,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 "Token_p.h"

namespace Cauchy {
  namespace AST {
    class Expression;
    class Tree;
    class MatrixExpression;
    class Statement;
  }
  class CompilationMessages;
  class DeclarationsRegistry;
  class Lexer;
  class String;
  class Variable;
  class Parser {
    public:
      Parser(Lexer* lexer, DeclarationsRegistry* _registry);
      ~Parser();
      AST::Tree* parse();
      CompilationMessages compilationMessages() const;
    private:
      void getNextToken();
      const Token& currentToken();
      void reportError( const String& errMsg, const Token& token );
      void reportWarning( const String& warnMsg, const Token& token );
      void reportUnexpected( const Token& token );
      bool isOfType( const Token& , Token::Type type );
      /**
       * Parse a single statement
       */
      AST::Statement* parseStatement();
      void parseFunction();
      /**
       * Parse a list of statements until an end token is encoutered
       */
      AST::Statement* parseStatementsList();
      /**
       * Indicate which mode is used for parsing an expression. This mostly control wether
       * conscecutive unseperated expressions are allowed i.e. "1 2"
       */
      enum ExpressionParseMode {
        EPM_Normal,
        EPM_Matrix,   ///< parsing matrix
        EPM_Condition ///< parsing while/if expression condition
      };
      /**
       * Will continiously call \ref parseBinaryOperator until there is no more
       * binary operator in the tree.
       */
      AST::Expression* parseFlatBinaryOperator( Cauchy::AST::Expression* _lhs, Cauchy::Parser::ExpressionParseMode _mode);
      /**
       * Parse for a binary operator, either return when at the end of the expression
       * or if the next operator has an inferior priority.
       */
      AST::Expression* parseBinaryOperator( Cauchy::AST::Expression* _lhs, ExpressionParseMode _mode );
      AST::Expression* parseExpression(ExpressionParseMode mode);
      AST::Expression* parseUnaryOperator();
      /**
       * Parse matrix expression ( [ 1, 2; 3 4 ] )
       */
      AST::Expression* parseMatrixExpression( );
      /**
       * Get the constant expression out of the current token. Also positionate the
       * token flow on the token after the constant.
       */
      AST::Expression* parsePrimaryExpression();
      AST::Expression* createBinaryOperator( const Token& token, AST::Expression* lhs, AST::Expression* rhs );
      /**
       * Parse the arguments of a function.
       */
      std::list<AST::Expression*> parseArguments( );
      AST::Expression* parseMemberArrayExpression(Variable* _variable);
      /**
       * If the next token is a comment, then it should be added as a comment of this statement
       */
      AST::Statement* makeComment(AST::Statement* arg1);
    private:
      void parseBody();
    private:
      struct Private;
      Private* const d;
  };
}
