1 /*============================================================================= 2 Copyright (c) 2014 Joel de Guzman 3 4 Distributed under the Boost Software License, Version 1.0. (See accompanying 5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 ==============================================================================*/ 7 #if !defined(BOOST_SPIRIT_X3_POSITION_TAGGED_MAY_01_2014_0321PM) 8 #define BOOST_SPIRIT_X3_POSITION_TAGGED_MAY_01_2014_0321PM 9 10 #include <boost/range.hpp> 11 #include <boost/type_traits/is_base_of.hpp> 12 #include <boost/core/enable_if.hpp> 13 14 namespace boost { namespace spirit { namespace x3 15 { 16 struct position_tagged 17 { 18 // Use this to annotate an AST with the iterator position. 19 // These ids are used as a key to the position_cache (below) 20 // and marks the start and end of an AST node. 21 int id_first = -1; 22 int id_last = -1; 23 }; 24 25 template <typename Container> 26 class position_cache 27 { 28 public: 29 30 typedef typename Container::value_type iterator_type; 31 position_cache(iterator_type first,iterator_type last)32 position_cache( 33 iterator_type first 34 , iterator_type last) 35 : first_(first), last_(last) {} 36 37 // This will catch all nodes inheriting from position_tagged 38 boost::iterator_range<iterator_type> position_of(position_tagged const & ast) const39 position_of(position_tagged const& ast) const 40 { 41 return 42 boost::iterator_range<iterator_type>( 43 positions.at(ast.id_first) // throws if out of range 44 , positions.at(ast.id_last) // throws if out of range 45 ); 46 } 47 48 // This will catch all nodes except those inheriting from position_tagged 49 template <typename AST> 50 typename boost::enable_if_c< 51 (!is_base_of<position_tagged, AST>::value) 52 , boost::iterator_range<iterator_type> 53 >::type position_of(AST const &) const54 position_of(AST const& /* ast */) const 55 { 56 // returns an empty position 57 return boost::iterator_range<iterator_type>(); 58 } 59 60 // This will catch all nodes except those inheriting from position_tagged 61 template <typename AST> annotate(AST &,iterator_type,iterator_type,mpl::false_)62 void annotate(AST& /* ast */, iterator_type /* first */, iterator_type /* last */, mpl::false_) 63 { 64 // (no-op) no need for tags 65 } 66 67 // This will catch all nodes inheriting from position_tagged annotate(position_tagged & ast,iterator_type first,iterator_type last,mpl::true_)68 void annotate(position_tagged& ast, iterator_type first, iterator_type last, mpl::true_) 69 { 70 ast.id_first = int(positions.size()); 71 positions.push_back(first); 72 ast.id_last = int(positions.size()); 73 positions.push_back(last); 74 } 75 76 template <typename AST> annotate(AST & ast,iterator_type first,iterator_type last)77 void annotate(AST& ast, iterator_type first, iterator_type last) 78 { 79 annotate(ast, first, last, is_base_of<position_tagged, AST>()); 80 } 81 82 Container const& get_positions() const83 get_positions() const 84 { 85 return positions; 86 } 87 first() const88 iterator_type first() const { return first_; } last() const89 iterator_type last() const { return last_; } 90 91 private: 92 93 Container positions; 94 iterator_type first_; 95 iterator_type last_; 96 }; 97 98 }}} 99 100 #endif 101