// This file is part of the AspectC++ compiler 'ac++'.
// Copyright (C) 1999-2003  The 'ac++' developers (see aspectc.org)
//                                                                
// 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.            
//                                                                
// This program 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 General Public License for more details.                   
//                                                                
// You should have received a copy of the GNU General Public      
// License along with this program; if not, write to the Free     
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
// MA  02111-1307  USA                                            

#ifndef __Phase1_h__
#define __Phase1_h__

#include <string>
#include <vector>
#include <set>

#include "ACModel/Elements.h"

#include "Phase1Sema.h"
#include "IncludeGraph.h"
#include "ModelBuilder.h"
#include "CodeWeaver.h"
#include "ACPreprocessor.h"
#include "PosHints.h"

class CodeWeaver;

namespace Puma {
  class CProject;
  class Unit;
  class FileUnit;
  class TokenProvider;
  class Token;
}

// This class performs preliminary parsing of a translation unit. Its
// purpose is to find all aspect-oriented constructs in the code,
// store information about it in the translation unit's model, and
// remove or replace the aspect-oriented code. Thereby, the main
// parsing can be performed by an ordinary C++ parser without
// token and grammar extensions.

class Phase1 : public Phase1Sema, public ACPreprocessor {

  // Exception type
  struct ParseError {};

  ModelBuilder &_jpm;
  PosHints &_pos_hints;
  CodeWeaver &_code_weaver;
  bool _in_template;
  string _tunit_name;
  ACConfig &_conf;

  void skip_block (int open, int close, bool inclusive = true);
  void skip_round_block (bool inclusive = true);
  void skip_curly_block (bool inclusive = true);
  void skip_square_block (bool inclusive = true);
  void skip_template_params ();
  bool is_attribute_token (const ACToken &token, const ACToken &next) const;
  bool is_cxx11_attribute_token (const ACToken &token, const ACToken &next) const;
  bool is_gnu_attribute_token (const ACToken &token) const;
  void skip_attributes (bool inclusive = true);
  void skip_cxx11_attributes (bool inclusive = true);
  void skip_gnu_attributes (bool inclusive = true);

  // internal parse functions
  void parse_scope (Scope &scope, std::string *anon_member_class_copy = 0);
  void parse_namespace (bool is_inline);
  void parse_qual_name (std::vector<std::string> &names,
      bool &root_qualified, bool &contains_template_id);
  void parse_base_clause (Scope &class_scope);
  void parse_base_spec (Scope &class_scope);
  void parse_aspectof_function (const string &prot);
  void parse_using_directive_or_declaration ();
  void parse_pointcut_def ();
#ifdef FRONTEND_CLANG
  void parse_attribute_decl ();
#endif
  void parse_advice_def (const std::string &prot);
  void parse_advice_body (AdviceCodeContext &context, int open, int close, CodeWeaver::TypeUse &uses_type, bool transform = false );

#ifdef FRONTEND_PUMA
  Scope *find_slice (Puma::Unit *rec);
#else
  Scope *find_slice (ACPreprocessor::TokenVector &rec);
#endif

  // internal helper functions
  void create_pct_expr_tree(TU_Pointcut *pct, ACToken start_pos, ACToken end_pos);

#ifdef FRONTEND_PUMA
  void handle_slice_member (Puma::Unit *rec, ACToken from, ACToken to);
  std::string recording_to_string (Puma::Unit *);
#else
  void handle_slice_member (ACPreprocessor::TokenVector &rec, ACToken from, ACToken to);
  std::string recording_to_string (const ACPreprocessor::TokenVector &);
#endif

#ifdef FRONTEND_CLANG
  TU_ClassSlice::SliceBody
  format_non_inline_member(ACPreprocessor::TokenVector &, const std::string &);
  void whitespace (unsigned &line, const ACToken &token, std::string &);
  void set_slice_tokens (TU_ClassSlice *, ACPreprocessor::TokenVector &);
#endif

public:
  Phase1 (ModelBuilder &jpm, PosHints &pos_hints, const string &tunit_name, ACProject &project, ACConfig &conf,
      CodeWeaver &code_weaver, IncludeGraph &include_graph) :
#ifdef FRONTEND_PUMA
        ACPreprocessor(tunit_name, conf, project), _jpm (jpm), _pos_hints(pos_hints),
        _code_weaver (code_weaver), _in_template (false), _tunit_name (tunit_name),
        _conf( conf ) {}
  Puma::Unit *unit() const { return ACPreprocessor::unit (); }

#else
  ACPreprocessor(tunit_name, conf, include_graph, project, code_weaver),
        _jpm (jpm), _pos_hints(pos_hints), _code_weaver (code_weaver), _in_template (false),
        _tunit_name (tunit_name), _conf( conf ) {
  }
#endif
  // run the analysis and transformation
  // result: -1 error; 0 empty file; 1 OK
  int run ();
};

#endif // __Phase1_h__
