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