Chris@102: /*============================================================================= Chris@102: Copyright (c) 2001-2014 Joel de Guzman Chris@102: Chris@102: Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@102: file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@102: ==============================================================================*/ Chris@102: #if !defined(BOOST_SPIRIT_X3_DETAIL_RULE_JAN_08_2012_0326PM) Chris@102: #define BOOST_SPIRIT_X3_DETAIL_RULE_JAN_08_2012_0326PM Chris@102: Chris@102: #if defined(_MSC_VER) Chris@102: #pragma once Chris@102: #endif Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: #if defined(BOOST_SPIRIT_X3_DEBUG) Chris@102: #include Chris@102: #endif Chris@102: Chris@102: namespace boost { namespace spirit { namespace x3 Chris@102: { Chris@102: template Chris@102: struct identity; Chris@102: Chris@102: template Chris@102: struct rule; Chris@102: Chris@102: struct parse_pass_context_tag; Chris@102: Chris@102: namespace detail Chris@102: { Chris@102: // we use this so we can detect if the default parse_rule Chris@102: // is the being called. Chris@102: struct default_parse_rule_result Chris@102: { Chris@102: default_parse_rule_result(bool r) Chris@102: : r(r) {} Chris@102: operator bool() const { return r; } Chris@102: bool r; Chris@102: }; Chris@102: } Chris@102: Chris@102: // default parse_rule implementation Chris@102: template Chris@102: inline detail::default_parse_rule_result Chris@102: parse_rule( Chris@102: rule rule_ Chris@102: , Iterator& first, Iterator const& last Chris@102: , Context const& context, ActualAttribute& attr); Chris@102: }}} Chris@102: Chris@102: namespace boost { namespace spirit { namespace x3 { namespace detail Chris@102: { Chris@102: #if defined(BOOST_SPIRIT_X3_DEBUG) Chris@102: template Chris@102: struct context_debug Chris@102: { Chris@102: context_debug( Chris@102: char const* rule_name Chris@102: , Iterator const& first, Iterator const& last Chris@102: , Attribute const& attr Chris@102: , bool const& ok_parse //was parse successful? Chris@102: ) Chris@102: : ok_parse(ok_parse), rule_name(rule_name) Chris@102: , first(first), last(last) Chris@102: , attr(attr) Chris@102: , f(detail::get_simple_trace()) Chris@102: { Chris@102: f(first, last, attr, pre_parse, rule_name); Chris@102: } Chris@102: Chris@102: ~context_debug() Chris@102: { Chris@102: auto status = ok_parse ? successful_parse : failed_parse ; Chris@102: f(first, last, attr, status, rule_name); Chris@102: } Chris@102: Chris@102: bool const& ok_parse; Chris@102: char const* rule_name; Chris@102: Iterator const& first; Chris@102: Iterator const& last; Chris@102: Attribute const& attr; Chris@102: detail::simple_trace_type& f; Chris@102: }; Chris@102: #endif Chris@102: Chris@102: template Chris@102: struct has_on_error : mpl::false_ {}; Chris@102: Chris@102: template Chris@102: struct has_on_error().on_error( Chris@102: std::declval() Chris@102: , std::declval() Chris@102: , std::declval>() Chris@102: , std::declval() Chris@102: ) Chris@102: )>::type Chris@102: > Chris@102: : mpl::true_ Chris@102: {}; Chris@102: Chris@102: template Chris@102: struct has_on_success : mpl::false_ {}; Chris@102: Chris@102: template Chris@102: struct has_on_success().on_success( Chris@102: std::declval() Chris@102: , std::declval() Chris@102: , std::declval() Chris@102: , std::declval() Chris@102: ) Chris@102: )>::type Chris@102: > Chris@102: : mpl::true_ Chris@102: {}; Chris@102: Chris@102: template Chris@102: struct make_id Chris@102: { Chris@102: typedef identity type; Chris@102: }; Chris@102: Chris@102: template Chris@102: struct make_id> Chris@102: { Chris@102: typedef identity type; Chris@102: }; Chris@102: Chris@102: template Chris@102: Context const& Chris@102: make_rule_context(RHS const& rhs, Context const& context Chris@102: , mpl::false_ /* is_default_parse_rule */) Chris@102: { Chris@102: return context; Chris@102: } Chris@102: Chris@102: template Chris@102: auto make_rule_context(RHS const& rhs, Context const& context Chris@102: , mpl::true_ /* is_default_parse_rule */ ) Chris@102: { Chris@102: return make_unique_context(rhs, context); Chris@102: } Chris@102: Chris@102: template Chris@102: struct rule_parser Chris@102: { Chris@102: template Chris@102: static bool call_on_success( Chris@102: Iterator& first, Iterator const& last Chris@102: , Context const& context, ActualAttribute& attr Chris@102: , mpl::false_ /* No on_success handler */ ) Chris@102: { Chris@102: return true; Chris@102: } Chris@102: Chris@102: template Chris@102: static bool call_on_success( Chris@102: Iterator& first, Iterator const& last Chris@102: , Context const& context, ActualAttribute& attr Chris@102: , mpl::true_ /* Has on_success handler */) Chris@102: { Chris@102: bool pass = true; Chris@102: ID().on_success( Chris@102: first Chris@102: , last Chris@102: , attr Chris@102: , make_context(pass, context) Chris@102: ); Chris@102: return pass; Chris@102: } Chris@102: Chris@102: template Chris@102: static bool parse_rhs_main( Chris@102: RHS const& rhs Chris@102: , Iterator& first, Iterator const& last Chris@102: , Context const& context, RContext& rcontext, ActualAttribute& attr Chris@102: , mpl::false_) Chris@102: { Chris@102: // see if the user has a BOOST_SPIRIT_DEFINE for this rule Chris@102: typedef Chris@102: decltype(parse_rule( Chris@102: rule(), first, last Chris@102: , make_unique_context(rhs, context), attr)) Chris@102: parse_rule_result; Chris@102: Chris@102: // If there is no BOOST_SPIRIT_DEFINE for this rule, Chris@102: // we'll make a context for this rule tagged by its ID Chris@102: // so we can extract the rule later on in the default Chris@102: // (generic) parse_rule function. Chris@102: typedef Chris@102: is_same Chris@102: is_default_parse_rule; Chris@102: Chris@102: Iterator i = first; Chris@102: bool r = rhs.parse( Chris@102: i Chris@102: , last Chris@102: , make_rule_context(rhs, context, is_default_parse_rule()) Chris@102: , rcontext Chris@102: , attr Chris@102: ); Chris@102: Chris@102: if (r) Chris@102: { Chris@102: auto first_ = first; Chris@102: x3::skip_over(first_, last, context); Chris@102: r = call_on_success(first_, i, context, attr Chris@102: , has_on_success()); Chris@102: } Chris@102: Chris@102: if (r) Chris@102: first = i; Chris@102: return r; Chris@102: } Chris@102: Chris@102: template Chris@102: static bool parse_rhs_main( Chris@102: RHS const& rhs Chris@102: , Iterator& first, Iterator const& last Chris@102: , Context const& context, RContext& rcontext, ActualAttribute& attr Chris@102: , mpl::true_ /* on_error is found */) Chris@102: { Chris@102: for (;;) Chris@102: { Chris@102: try Chris@102: { Chris@102: return parse_rhs_main( Chris@102: rhs, first, last, context, rcontext, attr, mpl::false_()); Chris@102: } Chris@102: catch (expectation_failure const& x) Chris@102: { Chris@102: switch (ID().on_error(first, last, x, context)) Chris@102: { Chris@102: case error_handler_result::fail: Chris@102: return false; Chris@102: case error_handler_result::retry: Chris@102: continue; Chris@102: case error_handler_result::accept: Chris@102: return true; Chris@102: case error_handler_result::rethrow: Chris@102: throw; Chris@102: } Chris@102: } Chris@102: } Chris@102: } Chris@102: Chris@102: template Chris@102: static bool parse_rhs_main( Chris@102: RHS const& rhs Chris@102: , Iterator& first, Iterator const& last Chris@102: , Context const& context, RContext& rcontext, ActualAttribute& attr) Chris@102: { Chris@102: return parse_rhs_main( Chris@102: rhs, first, last, context, rcontext, attr Chris@102: , has_on_error() Chris@102: ); Chris@102: } Chris@102: Chris@102: template Chris@102: static bool parse_rhs( Chris@102: RHS const& rhs Chris@102: , Iterator& first, Iterator const& last Chris@102: , Context const& context, RContext& rcontext, ActualAttribute& attr Chris@102: , mpl::false_) Chris@102: { Chris@102: return parse_rhs_main(rhs, first, last, context, rcontext, attr); Chris@102: } Chris@102: Chris@102: template Chris@102: static bool parse_rhs( Chris@102: RHS const& rhs Chris@102: , Iterator& first, Iterator const& last Chris@102: , Context const& context, RContext& rcontext, ActualAttribute& attr Chris@102: , mpl::true_) Chris@102: { Chris@102: return parse_rhs_main(rhs, first, last, context, rcontext, unused); Chris@102: } Chris@102: Chris@102: template Chris@102: static bool call_rule_definition( Chris@102: RHS const& rhs Chris@102: , char const* rule_name Chris@102: , Iterator& first, Iterator const& last Chris@102: , Context const& context, ActualAttribute& attr Chris@102: , ExplicitAttrPropagation) Chris@102: { Chris@102: typedef traits::make_attribute make_attribute; Chris@102: Chris@102: // do down-stream transformation, provides attribute for Chris@102: // rhs parser Chris@102: typedef traits::transform_attribute< Chris@102: typename make_attribute::type, Attribute, parser_id> Chris@102: transform; Chris@102: Chris@102: typedef typename make_attribute::value_type value_type; Chris@102: typedef typename transform::type transform_attr; Chris@102: value_type made_attr = make_attribute::call(attr); Chris@102: transform_attr attr_ = transform::pre(made_attr); Chris@102: Chris@102: bool ok_parse Chris@102: //Creates a place to hold the result of parse_rhs Chris@102: //called inside the following scope. Chris@102: ; Chris@102: { Chris@102: //Create a scope to cause the dbg variable below (within Chris@102: //the #if...#endif) to call it's DTOR before any Chris@102: //modifications are made to the attribute, attr_ passed Chris@102: //to parse_rhs (such as might be done in Chris@102: //traits::post_transform when, for example, Chris@102: //ActualAttribute is a recursive variant). Chris@102: #if defined(BOOST_SPIRIT_X3_DEBUG) Chris@102: context_debug Chris@102: dbg(rule_name, first, last, attr_, ok_parse); Chris@102: #endif Chris@102: ok_parse=parse_rhs(rhs, first, last, context, attr_, attr_ Chris@102: , mpl::bool_ Chris@102: < ( RHS::has_action Chris@102: && !ExplicitAttrPropagation::value Chris@102: ) Chris@102: >() Chris@102: ); Chris@102: } Chris@102: if(ok_parse) Chris@102: { Chris@102: // do up-stream transformation, this integrates the results Chris@102: // back into the original attribute value, if appropriate Chris@102: traits::post_transform(attr, attr_); Chris@102: } Chris@102: return ok_parse; Chris@102: } Chris@102: Chris@102: // template Chris@102: // static bool call_from_rule( Chris@102: // RuleDef const& rule_def Chris@102: // , char const* rule_name Chris@102: // , Iterator& first, Iterator const& last Chris@102: // , Context const& context, ActualAttribute& attr, AttributeContext& attr_ctx) Chris@102: // { Chris@102: // // This is called when a rule-body has already been established. Chris@102: // // The rule body is already established by the rule_definition class, Chris@102: // // we will not do it again. We'll simply call the RHS by calling Chris@102: // // call_rule_definition. Chris@102: // Chris@102: // return call_rule_definition( Chris@102: // rule_def.rhs, rule_name, first, last Chris@102: // , context, attr, attr_ctx.attr_ptr Chris@102: // , mpl::bool_<(RuleDef::explicit_attribute_propagation)>()); Chris@102: // } Chris@102: // Chris@102: // template Chris@102: // static bool call_from_rule( Chris@102: // RuleDef const& rule_def Chris@102: // , char const* rule_name Chris@102: // , Iterator& first, Iterator const& last Chris@102: // , Context const& context, ActualAttribute& attr, unused_type) Chris@102: // { Chris@102: // // This is called when a rule-body has *not yet* been established. Chris@102: // // The rule body is established by the rule_definition class, so Chris@102: // // we call it to parse and establish the rule-body. Chris@102: // Chris@102: // return rule_def.parse(first, last, context, unused, attr); // $$$ fix unused param $$$ Chris@102: // } Chris@102: }; Chris@102: }}}} Chris@102: Chris@102: #endif