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 13 namespace boost { namespace spirit { namespace x3 14 { 15 struct position_tagged 16 { 17 // Use this to annotate an AST with the iterator position. 18 // These ids are used as a key to the position_cache (below) 19 // and marks the start and end of an AST node. 20 int id_first = -1; 21 int id_last = -1; 22 }; 23 24 template <typename Container> 25 class position_cache 26 { 27 public: 28 29 typedef typename Container::value_type iterator_type; 30 position_cache(iterator_type first,iterator_type last)31 position_cache( 32 iterator_type first 33 , iterator_type last) 34 : first_(first), last_(last) {} 35 36 // This will catch all nodes inheriting from position_tagged 37 boost::iterator_range<iterator_type> position_of(position_tagged const & ast) const38 position_of(position_tagged const& ast) const 39 { 40 return 41 boost::iterator_range<iterator_type>( 42 positions.at(ast.id_first) // throws if out of range 43 , positions.at(ast.id_last) // throws if out of range 44 ); 45 } 46 47 // This will catch all nodes except those inheriting from position_tagged 48 template <typename AST> 49 boost::iterator_range<iterator_type> position_of(AST const & ast) const50 position_of(AST const& ast) const 51 { 52 // returns an empty position 53 return boost::iterator_range<iterator_type>(); 54 } 55 56 // This will catch all nodes except those inheriting from position_tagged 57 template <typename AST> annotate(AST & ast,iterator_type first,iterator_type last,mpl::false_)58 void annotate(AST& ast, iterator_type first, iterator_type last, mpl::false_) 59 { 60 // (no-op) no need for tags 61 } 62 63 // This will catch all nodes inheriting from position_tagged annotate(position_tagged & ast,iterator_type first,iterator_type last,mpl::true_)64 void annotate(position_tagged& ast, iterator_type first, iterator_type last, mpl::true_) 65 { 66 ast.id_first = int(positions.size()); 67 positions.push_back(first); 68 ast.id_last = int(positions.size()); 69 positions.push_back(last); 70 } 71 72 template <typename AST> annotate(AST & ast,iterator_type first,iterator_type last)73 void annotate(AST& ast, iterator_type first, iterator_type last) 74 { 75 annotate(ast, first, last, is_base_of<position_tagged, AST>()); 76 } 77 78 Container const& get_positions() const79 get_positions() const 80 { 81 return positions; 82 } 83 first() const84 iterator_type first() const { return first_; } last() const85 iterator_type last() const { return last_; } 86 87 private: 88 89 Container positions; 90 iterator_type first_; 91 iterator_type last_; 92 }; 93 94 }}} 95 96 #endif 97