8 #include "cetlib/compiler_macros.h" 10 #include "boost/any.hpp" 12 #pragma warning(push, disable : 780) 14 #pragma GCC diagnostic push 15 #pragma GCC diagnostic ignored "-Wshadow" 16 #pragma GCC diagnostic ignored "-Wstrict-aliasing" 17 #pragma GCC diagnostic ignored "-Wunused-parameter" 18 #include "boost/spirit/include/phoenix_bind.hpp" 19 #include "boost/spirit/include/phoenix_operator.hpp" 20 #include "boost/spirit/include/qi.hpp" 21 #include "boost/spirit/include/qi_no_skip.hpp" 22 #include "boost/spirit/include/support_istream_iterator.hpp" 24 #pragma clang diagnostic ignored "-Wpedantic" 26 #pragma GCC diagnostic ignored "-Wpedantic" 28 #include "boost/spirit/repository/home/qi/primitive/iter_pos.hpp" 29 #pragma GCC diagnostic pop 34 #include "cetlib/canonical_number.h" 35 #include "cetlib/canonical_string.h" 36 #include "cetlib/include.h" 37 #include "cetlib/includer.h" 49 namespace ascii = ::boost::spirit::ascii;
50 namespace phx = ::boost::phoenix;
51 namespace qi = ::boost::spirit::qi;
60 using boost::spirit::repository::qi::iter_pos;
64 using namespace shims;
69 using namespace fhicl;
92 <<
"Nested item " << name <<
" has protection " 97 <<
", which is incompatible with an enclosing item's protection of " 101 std::size_t count = 0;
109 std::string sname(name);
110 if (!sname.empty()) {
113 sname.append(kvp.first);
114 check_protection(
max(p, v.
protection), kvp.second, std::move(sname));
123 check_protection(v.
protection, v, std::move(name));
131 case binding_modifier::NONE:
133 case binding_modifier::PROTECT_IGNORE:
134 case binding_modifier::PROTECT_ERROR:
137 check_protection(v, name);
146 static std::string
const canon_nil(9,
'\0');
151 canon_inf(std::string
const& inf)
153 return inf[0] ==
'i' ? (
'+' + inf) : inf;
157 canon_num(std::string
const& num)
160 if (!cet::canonical_number(num, result)) {
167 canon_str(std::string
const& str)
170 if (!cet::canonical_string(str, result)) {
177 rebool(
bool& b,
bool value)
183 xvalue_vp(
bool b,
value_tag t, boost::any v)
188 template <
typename FwdIter>
194 cet::includer
const&
s)
196 std::string
const src_info = s.src_whereis(pos);
203 return std::make_pair(c1, c2);
206 template <
typename FwdIter>
208 local_lookup(std::string
const& name,
212 cet::includer
const& s)
try {
220 <<
"at " << s.highlighted_whereis(pos) <<
"\n";
223 template <
typename FwdIter>
225 database_lookup(std::string
const&,
229 cet::includer
const& s)
232 <<
"at " << s.highlighted_whereis(pos)
233 <<
"\nFHiCL-cpp database lookup not yet available.\n";
236 template <
typename FwdIter>
238 tbl_insert(std::string
const& name,
243 cet::includer
const& s)
246 set_protection(name, m, value);
252 <<
" at " << s.highlighted_whereis(pos) <<
'\n';
256 template <
typename FwdIter>
258 tbl_erase(std::string
const& name,
262 cet::includer
const& s)
265 t.
erase(name, in_prolog);
270 <<
" at " << s.highlighted_whereis(pos) <<
'\n';
275 map_insert(std::string
const& name,
280 set_protection(name, m, value);
281 auto const i = t.
find(name);
283 auto existing_protection = i->second.protection;
286 <<
"Inserting name " << name <<
" would increase protection from " 287 <<
to_string(existing_protection) <<
" to " 289 << i->second.pretty_src_info() <<
")\n";
291 switch (i->second.protection) {
292 case Protection::NONE:
294 case Protection::PROTECT_IGNORE:
297 case Protection::PROTECT_ERROR:
299 <<
'"' << name <<
"\" is protected on " 300 << i->second.pretty_src_info() <<
'\n';
306 template <
typename FwdIter>
308 map_insert_loc(std::string
const& name,
313 cet::includer
const& s)
316 map_insert(name, m, value, t);
321 <<
" at " << s.highlighted_whereis(pos) <<
'\n';
325 template <
typename FwdIter>
327 insert_table_in_table(std::string
const& name,
332 cet::includer
const& s)
334 extended_value const& xval = local_lookup(name, tbl,
false, pos, s);
337 <<
"key \"" << name <<
"\" does not refer to a table at " 338 << s.highlighted_whereis(pos) <<
"\n";
340 auto const& incoming = boost::any_cast<
table_t const&>(xval.
value);
341 for (
auto incoming_item = incoming.cbegin(), e = incoming.cend();
344 auto& element = t[incoming_item->first];
347 auto incoming_protection = incoming_item->second.protection;
348 if (incoming_protection > element.protection) {
350 <<
"@table::" << name <<
": inserting name " << incoming_item->first
351 <<
" would increase protection from " 352 <<
to_string(element.protection) <<
" to " 353 <<
to_string(incoming_protection) <<
"\n(previous definition on " 354 << element.pretty_src_info() <<
")\n";
356 switch (element.protection) {
357 case Protection::NONE:
359 case Protection::PROTECT_IGNORE:
361 case Protection::PROTECT_ERROR:
363 <<
"@table::" << name <<
": inserting name " 364 << incoming_item->first
365 <<
"would violate protection on existing item" 366 <<
"\n(previous definition on " << element.pretty_src_info()
370 element = incoming_item->second;
371 element.set_prolog(in_prolog);
372 element.set_src_info(s.src_whereis(pos));
376 template <
typename FwdIter>
378 insert_table(std::string
const& name,
382 cet::includer
const& s)
384 extended_value const& xval = local_lookup(name, tbl,
false, pos, s);
387 <<
"key \"" << name <<
"\" does not refer to a table at " 388 << s.highlighted_whereis(pos) <<
"\n";
390 auto const& incoming = boost::any_cast<
table_t const&>(xval.
value);
391 for (
auto incoming_item = incoming.cbegin(), e = incoming.cend();
394 auto const& key = incoming_item->first;
395 auto element = incoming_item->second;
396 element.set_prolog(in_prolog);
397 element.set_src_info(s.src_whereis(pos));
398 tbl.
insert(key, std::move(element));
402 template <
typename FwdIter>
404 seq_insert_sequence(std::string
const& name,
409 cet::includer
const& s)
414 <<
"key \"" << name <<
"\" does not refer to a sequence at " 415 << s.highlighted_whereis(pos) <<
"\n";
418 #if GCC_IS_AT_LEAST(4, 9, 0) || \ 421 auto it = v.insert(v.end(), incoming.cbegin(), incoming.cend());
423 v.insert(v.end(), incoming.cbegin(), incoming.cend());
424 auto it = v.end() - incoming.size();
427 for (
auto const e = v.end(); it !=
e; ++it, ++count) {
429 it->protection = Protection::NONE;
430 it->set_prolog(in_prolog);
431 it->set_src_info(s.src_whereis(pos));
439 v.emplace_back(std::move(xval));
443 map_erase(std::string
const& name,
table_t& t)
445 auto const i = t.
find(name);
447 switch (i->second.protection) {
448 case Protection::NONE:
450 case Protection::PROTECT_IGNORE:
452 case Protection::PROTECT_ERROR:
454 <<
"Unable to erase " << name <<
" due to protection.\n";
459 template <
typename FwdIter>
461 map_erase_loc(std::string
const& name,
464 cet::includer
const& s)
472 <<
" at " << s.highlighted_whereis(pos) <<
'\n';
478 template <
class FwdIter,
class Skip>
481 template <
class FwdIter,
class Skip>
482 struct document_parser;
486 template <
class FwdIter,
class Skip>
487 struct value_parser : qi::grammar<FwdIter, extended_value(), Skip> {
488 using atom_token = qi::rule<FwdIter, atom_t(), Skip>;
489 using complex_token = qi::rule<FwdIter, complex_t(), Skip>;
490 using sequence_token = qi::rule<FwdIter, sequence_t(), Skip>;
491 using table_token = qi::rule<FwdIter, table_t(), Skip>;
492 using value_token = qi::rule<FwdIter, extended_value(), Skip>;
501 atom_token nil, boolean;
503 atom_token squoted, dquoted;
504 atom_token number, string, name, catchall;
506 complex_token complex;
507 sequence_token sequence;
515 template <
class FwdIter,
class Skip>
516 struct document_parser : qi::grammar<FwdIter, void(), Skip> {
517 using val_parser = value_parser<FwdIter, Skip>;
519 using atom_token =
typename val_parser::atom_token;
520 using sequence_token =
typename val_parser::sequence_token;
521 using table_token =
typename val_parser::table_token;
522 using value_token =
typename val_parser::value_token;
523 using nothing_token = qi::rule<FwdIter, void(), Skip>;
525 document_parser(cet::includer
const& s);
533 atom_token name, qualname, noskip_qualname, localref, dbref;
534 sequence_token sequence;
537 nothing_token prolog, document;
543 template <
class FwdIter,
class Skip>
544 value_parser<FwdIter, Skip>::value_parser()
545 : value_parser::base_type{value}, v()
548 lexeme[(qi::string(
"@nil") >>
549 !(graph - char_(
",]}")))[_val = phx::bind(
canon_nil, qi::_1)]];
550 boolean = lexeme[(qi::string(
"true") | qi::string(
"false")) >>
551 !(graph - char_(
",]}"))];
552 inf = lexeme[-(qi::string(
"+") | qi::string(
"-")) >>
553 qi::string(
"infinity") >> !(graph - char_(
"),]}"))];
554 squoted = lexeme[char_(
'\'') >> *(char_ - char_(
'\'')) >> char_(
'\'') >>
555 !(graph - char_(
",]}"))];
557 lexeme[
raw[char_(
'\"') >> *(qi::string(
"\\\"") | (char_ - char_(
'\"'))) >>
558 char_(
'\"') >> !(graph - char_(
",]}"))]];
560 (fhicl::uint[_val = phx::bind(canon_num, qi::_1)] |
561 inf[_val = phx::bind(canon_inf, qi::_1)] | fhicl::real[_val = qi::_1] |
562 fhicl::hex[_val = qi::_1] |
fhicl::bin[_val = qi::_1]);
563 string = (fhicl::ass | fhicl::dss | squoted |
564 dquoted)[_val = phx::bind(canon_str, ref(qi::_1))];
565 name = fhicl::ass[_val = qi::_1];
566 complex = (
lit(
'(') > number >
lit(
',') > number >
567 lit(
')'))[_val = phx::bind(cplx, qi::_1, qi::_2)];
568 sequence =
lit(
'[') > -(value %
',') >
lit(
']');
571 *((name >> fhicl::binding >>
572 value)[phx::bind(map_insert, ref(qi::_1), qi::_2, ref(qi::_3), _val)] |
574 (
lit(
':') >
lit(
"@erase")))[phx::bind(map_erase, ref(qi::_1), _val)]) >
576 id =
lit(
"@id::") > no_skip[fhicl::dbid][_val = qi::_1];
577 catchall = shims::catchall[_val = phx::bind(canon_str, ref(qi::_1))];
578 value = (nil[_val = phx::bind(xvalue_vp,
false,
NIL, qi::_1)] |
579 boolean[_val = phx::bind(xvalue_vp,
false,
BOOL, qi::_1)] |
580 number[_val = phx::bind(xvalue_vp,
false,
NUMBER, qi::_1)] |
581 complex[_val = phx::bind(xvalue_vp,
false,
COMPLEX, qi::_1)] |
582 string[_val = phx::bind(xvalue_vp,
false,
STRING, qi::_1)] |
583 sequence[_val = phx::bind(xvalue_vp,
false,
SEQUENCE, qi::_1)] |
584 table[_val = phx::bind(xvalue_vp,
false,
TABLE, qi::_1)] |
585 id[_val = phx::bind(xvalue_vp,
false,
TABLEID, qi::_1)] |
586 catchall[_val = phx::bind(xvalue_vp,
false,
STRING, qi::_1)]);
587 nil.name(
"nil token");
588 boolean.name(
"boolean token");
589 inf.name(
"inf token");
590 squoted.name(
"squoted token");
591 dquoted.name(
"dquoted token");
592 number.name(
"number atom");
593 string.name(
"string atom");
594 name.name(
"name atom");
595 complex.name(
"complex atom");
596 sequence.name(
"sequence");
600 catchall.name(
"catchall atom");
605 template <
class FwdIter,
class Skip>
606 document_parser<FwdIter, Skip>::document_parser(cet::includer
const& s)
607 : document_parser::base_type(document), in_prolog(
false), tbl(), vp()
612 fhicl::ass[_val = qi::_1] >>
613 *((char_(
'.') > fhicl::ass)[_val += qi::_1 + qi::_2] |
614 (char_(
'[') > fhicl::uint >
615 char_(
']'))[_val += qi::_1 + qi::_2 + qi::_3]);
620 no_skip[fhicl::ass][_val = qi::_1] >>
621 *((char_(
'.') > fhicl::ass)[_val += qi::_1 + qi::_2] |
622 (char_(
'[') > fhicl::uint >
623 char_(
']'))[_val += qi::_1 + qi::_2 + qi::_3]);
627 localref =
lit(
"@local::") > noskip_qualname;
628 dbref =
lit(
"@db::") > noskip_qualname;
632 lit(
'[') > -(((value[phx::bind(seq_insert_value, ref(qi::_1), _val)]) |
633 ((iter_pos >>
lit(
"@sequence::")) >
634 noskip_qualname)[phx::bind(&seq_insert_sequence<iter_t>,
641 *(
lit(
',') > ((value[phx::bind(seq_insert_value, ref(qi::_1), _val)]) |
642 ((iter_pos >>
lit(
"@sequence::")) >
643 noskip_qualname)[phx::bind(&seq_insert_sequence<iter_t>,
649 ref(s))])) >
lit(
']');
651 *((iter_pos >> name >> fhicl::binding >>
652 value)[phx::bind(&map_insert_loc<iter_t>,
659 (iter_pos >> name >> (
lit(
':') >
lit(
"@erase")))[phx::bind(
660 &map_erase_loc<iter_t>, ref(qi::_2), _val, qi::_1, ref(s))] |
661 ((iter_pos >>
lit(
"@table::")) >
662 noskip_qualname)[phx::bind(&insert_table_in_table<iter_t>,
668 ref(s))]) >
lit(
'}');
672 #pragma clang diagnostic push 673 #pragma clang diagnostic ignored "-Wunsequenced" 676 ((iter_pos >> vp.nil)
678 &xvalue_dp<iter_t>, ref(in_prolog),
NIL, qi::_2, qi::_1, ref(s))] |
679 (iter_pos >> vp.boolean)
681 &xvalue_dp<iter_t>, ref(in_prolog),
BOOL, qi::_2, qi::_1, ref(s))] |
682 (iter_pos >> vp.number)[_val = phx::bind(&xvalue_dp<iter_t>,
688 (iter_pos >> vp.complex)[_val = phx::bind(&xvalue_dp<iter_t>,
694 (iter_pos >> vp.string)[_val = phx::bind(&xvalue_dp<iter_t>,
700 (iter_pos >> localref)[_val = phx::bind(&local_lookup<iter_t>,
706 (iter_pos >> dbref)[_val = phx::bind(&database_lookup<iter_t>,
712 (iter_pos >> vp.id)[_val = phx::bind(&xvalue_dp<iter_t>,
718 (iter_pos >> sequence)[_val = phx::bind(&xvalue_dp<iter_t>,
724 (iter_pos >> table)[_val = phx::bind(&xvalue_dp<iter_t>,
730 (iter_pos >> vp.catchall)[_val = phx::bind(&xvalue_dp<iter_t>,
737 #pragma clang diagnostic pop 739 prolog =
lit(
"BEGIN_PROLOG")[phx::bind(rebool, ref(in_prolog),
true)] >
740 *((iter_pos >> qualname >> fhicl::binding >>
741 value)[phx::bind(&tbl_insert<iter_t>,
748 (iter_pos >> qualname >>
749 (
lit(
':') >
lit(
"@erase")))[phx::bind(&tbl_erase<iter_t>,
755 ((iter_pos >>
lit(
"@table::")) >
756 noskip_qualname)[phx::bind(&insert_table<iter_t>,
762 lit(
"END_PROLOG")[phx::bind(rebool, ref(in_prolog),
false)];
764 (*prolog) >> *((iter_pos >> qualname >> fhicl::binding >>
765 value)[phx::bind(&tbl_insert<iter_t>,
772 (iter_pos >> qualname >>
773 (
lit(
':') >
lit(
"@erase")))[phx::bind(&tbl_erase<iter_t>,
779 ((iter_pos >>
lit(
"@table::")) >
780 noskip_qualname)[phx::bind(&insert_table<iter_t>,
786 name.name(
"name atom");
787 localref.name(
"localref atom");
788 dbref.name(
"dbref atom");
789 qualname.name(
"qualified name");
790 noskip_qualname.name(
"qualified name (no pre-skip)");
791 sequence.name(
"sequence");
794 prolog.name(
"prolog");
795 document.name(
"document");
804 std::string& unparsed)
807 typedef qi::rule<iter_t> ws_t;
808 ws_t whitespace = space |
lit(
'#') >> *(char_ - eol) >> eol |
809 lit(
"//") >> *(char_ - eol) >> eol;
810 value_parser<iter_t, ws_t> p;
811 iter_t
begin = s.begin();
812 iter_t
const end = s.end();
814 qi::phrase_parse(begin, end, p >> *whitespace, whitespace, result) &&
816 unparsed = std::string(begin, end);
828 typedef qi::rule<iter_t> ws_t;
829 ws_t whitespace = space |
lit(
'#') >> *(char_ - eol) >> eol |
830 lit(
"//") >> *(char_ - eol) >> eol;
831 document_parser<iter_t, ws_t> p(s);
832 iter_t
begin = s.begin();
833 iter_t
const end = s.end();
836 b = qi::phrase_parse(begin, end, p, whitespace);
838 catch (qi::expectation_failure<iter_t>
const&
e) {
841 std::string unparsed(begin, end);
842 if (b && unparsed.empty()) {
846 << s.highlighted_whereis(begin) <<
"\n";
847 if (unparsed.find(
"BEGIN_PROLOG"s) == 0ull) {
848 e <<
"PROLOG blocks must be both contiguous and not nested.\n";
857 cet::filepath_maker& maker,
860 parse_document_(cet::includer(filename, maker), result);
865 cet::filepath_maker& maker,
868 parse_document_(cet::includer(is, maker), result);
intermediate_table::complex_t complex_t
size_t erase(Key const &key)
bool parse_value_string(std::string const &s, extended_value &v, std::string &unparsed)
void set_src_info(std::string const &src)
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
bool is_a(value_tag t) const
static std::string canon_nil()
extended_value::table_t table_t
fhicl::extended_value::sequence_t sequence_t
intermediate_table::atom_t atom_t
extended_value::atom_t atom_t
std::string value(boost::any const &)
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
std::string pretty_src_info() const
extended_value::complex_t complex_t
void set_prolog(bool new_prolog_state)
iterator find(Key const &key)
cet::coded_exception< error, detail::translate > exception
void parse_document(std::string const &filename, cet::filepath_maker &maker, intermediate_table &result)
extended_value::sequence_t sequence_t