position_tagged.hpp 3.2 KB

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