/*============================================================================= Copyright (c) 2010-2011 Daniel James Copyright (c) 2003 Martin Wille http://spirit.sourceforge.net/ Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ // Some custom parsers for use in quickbook. #ifndef BOOST_QUICKBOOK_PARSERS_HPP #define BOOST_QUICKBOOK_PARSERS_HPP #include #include #include #include #include #include "fwd.hpp" #include "iterator.hpp" namespace quickbook { namespace cl = boost::spirit::classic; /////////////////////////////////////////////////////////////////////////// // // scoped_parser // // Impl is a struct with the methods: // // void start(); // void success(parse_iterator, parse_iterator); // void failure(); // void cleanup(); // /////////////////////////////////////////////////////////////////////////// template struct scoped_parser_impl : public cl::unary< ParserT, cl::parser > > { typedef scoped_parser_impl self_t; typedef cl::unary< ParserT, cl::parser > > base_t; template struct result { typedef cl::match<> type; }; scoped_parser_impl( Impl const& impl, Arguments const& arguments, ParserT const& p) : base_t(p), impl_(impl), arguments_(arguments) { } struct scoped { explicit scoped(Impl const& impl) : impl_(impl), in_progress_(false) { } typedef phoenix::tuple_index<0> t0; typedef phoenix::tuple_index<1> t1; bool start(phoenix::tuple<> const&) { in_progress_ = impl_.start(); return in_progress_; } template bool start(phoenix::tuple const& x) { in_progress_ = phoenix::bind(&Impl::start)(phoenix::var(impl_), x[t0()])(); return in_progress_; } template bool start(phoenix::tuple const& x) { in_progress_ = phoenix::bind(&Impl::start)( phoenix::var(impl_), x[t0()], x[t1()])(); return in_progress_; } void success(parse_iterator f, parse_iterator l) { in_progress_ = false; impl_.success(f, l); } void failure() { in_progress_ = false; impl_.failure(); } ~scoped() { if (in_progress_) impl_.failure(); impl_.cleanup(); } Impl impl_; bool in_progress_; }; template typename result::type parse(ScannerT const& scan) const { typedef typename ScannerT::iterator_t iterator_t; iterator_t save = scan.first; scoped scope(impl_); if (!scope.start(arguments_)) return scan.no_match(); typename cl::parser_result::type r = this->subject().parse(scan); bool success = scope.impl_.result(r, scan); if (success) { scope.success(save, scan.first); if (r) { return scan.create_match( r.length(), cl::nil_t(), save, scan.first); } else { return scan.create_match( scan.first.base() - save.base(), cl::nil_t(), save, scan.first); } } else { scope.failure(); return scan.no_match(); } } Impl impl_; Arguments arguments_; }; template struct scoped_parser_gen { explicit scoped_parser_gen(Impl impl, Arguments const& arguments) : impl_(impl), arguments_(arguments) { } template scoped_parser_impl< Impl, Arguments, typename cl::as_parser::type> operator[](ParserT const& p) const { typedef cl::as_parser as_parser_t; typedef typename as_parser_t::type parser_t; return scoped_parser_impl( impl_, arguments_, p); } Impl impl_; Arguments arguments_; }; template struct scoped_parser { scoped_parser(Impl const& impl) : impl_(impl) {} scoped_parser_gen > operator()() const { typedef phoenix::tuple<> tuple; return scoped_parser_gen(impl_, tuple()); } template scoped_parser_gen > operator()(Arg1 x1) const { typedef phoenix::tuple tuple; return scoped_parser_gen(impl_, tuple(x1)); } template scoped_parser_gen > operator()( Arg1 x1, Arg2 x2) const { typedef phoenix::tuple tuple; return scoped_parser_gen(impl_, tuple(x1, x2)); } Impl impl_; private: scoped_parser& operator=(scoped_parser const&); }; /////////////////////////////////////////////////////////////////////////// // // Lookback parser // // usage: lookback[body] // // Requires that iterator has typedef 'lookback_range' and function // 'lookback' returning a 'lookback_range'. // /////////////////////////////////////////////////////////////////////////// template struct lookback_parser : public cl::unary > > { typedef lookback_parser self_t; typedef cl::unary > > base_t; template struct result { typedef typename cl::parser_result::type type; }; lookback_parser(ParserT const& p) : base_t(p) {} template typename result::type parse(ScannerT const& scan) const { typedef typename ScannerT::iterator_t::lookback_range::iterator iterator_t; typedef cl::scanner scanner_t; iterator_t begin = scan.first.lookback().begin(); scanner_t lookback_scan(begin, scan.first.lookback().end(), scan); if (this->subject().parse(lookback_scan)) return scan.empty_match(); else return scan.no_match(); } }; struct lookback_gen { template lookback_parser operator[](ParserT const& p) const { return lookback_parser(p); } }; lookback_gen const lookback = lookback_gen(); /////////////////////////////////////////////////////////////////////////// // // UTF-8 code point // // Very crude, it doesn't check that the code point is in any way valid. // Just looks for the beginning of the next character. This is just for // implementing some crude fixes, rather than full unicode support. I'm // sure experts would be appalled. // /////////////////////////////////////////////////////////////////////////// struct u8_codepoint_parser : public cl::parser { typedef u8_codepoint_parser self_t; template struct result { typedef cl::match<> type; }; template typename result::type parse(Scanner const& scan) const { typedef typename Scanner::iterator_t iterator_t; if (scan.at_end()) return scan.no_match(); iterator_t save(scan.first); do { ++scan.first; } while (!scan.at_end() && ((unsigned char)*scan.first & 0xc0) == 0x80); return scan.create_match( scan.first.base() - save.base(), cl::nil_t(), save, scan.first); } }; u8_codepoint_parser const u8_codepoint_p = u8_codepoint_parser(); } #endif // BOOST_QUICKBOOK_SCOPED_BLOCK_HPP