Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
parse.hpp
Go to the documentation of this file.
1/*
2 PARSE.hpp - helpers for parsing textual specifications
3
4 Copyright (C)
5 2024, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12*/
13
14
140#ifndef LIB_PARSE_H
141#define LIB_PARSE_H
142
143
144#include "lib/error.hpp"
145#include "lib/branch-case.hpp"
146#include "lib/format-string.hpp"
148#include "lib/meta/function.hpp"
149#include "lib/meta/trait.hpp"
150#include "lib/regex.hpp"
151
152#include <optional>
153#include <utility>
154#include <cstddef>
155#include <tuple>
156#include <array>
157
158namespace util {
159 namespace parse {
160 namespace err = lumiera::error;
161
162 using std::move;
163 using std::forward;
164 using std::optional;
165 using lib::meta::_Fun;
166 using lib::meta::has_Sig;
167 using lib::meta::_Vari;
168 using lib::meta::Nil;
169 using std::decay_t;
170 using std::tuple;
171 using std::array;
172 using util::_Fmt;
173
174 using StrView = std::string_view;
175
176 template<class PAR>
177 class Syntax;
178
179 template<class CON>
180 class Parser;
181
182
183
188 template<class RES>
189 struct Eval
190 {
191 using Result = RES;
192 optional<RES> result;
193 size_t consumed{0};
194 };
195
200 template<class FUN>
201 struct Connex
202 {
203 using PFun = FUN;
205
207
208 Connex (FUN pFun)
209 : parse{pFun}
210 { }
211 };
212
214 template<class RES>
216
217 template<class RES>
219
220
221
222
223
225 inline auto
227 {
228 return Connex{[](StrView) -> Eval<Nil>
229 {
230 return {Nil()};
231 }};
232 }
233 using NulP = decltype(buildConnex (Nil()));
234
235
244 inline auto
245 buildConnex (regex rex)
246 {
247 return Connex{[regEx = move(rex)]
248 (StrView toParse) -> Eval<smatch>
249 { // skip leading whitespace...
250 size_t pre = leadingWhitespace (toParse);
251 toParse = toParse.substr(pre);
252 auto result{matchAtStart (toParse,regEx)};
253 size_t consumed = result? pre+result->length() : 0;
254 return {move(result), consumed};
255 }};
256 }
257 using Term = decltype(buildConnex (std::declval<regex>()));
258
260 inline Term
261 buildConnex (string const& rexDef)
262 {
263 return buildConnex (regex{rexDef});
264 }
265
267 template<class FUN>
268 inline auto
269 buildConnex (Connex<FUN> const& anchor)
270 {
271 return Connex{anchor};
272 }
273 template<class FUN>
274 inline auto
276 {
277 return Connex{move(anchor)};
278 }
279
280 template<class PAR>
281 inline auto
282 buildConnex (Syntax<PAR> const& anchor)
283 {
284 using Con = Syntax<PAR>::Connex;
285 return Con{anchor};
286 }
287
292 template<class RES>
293 inline auto
295 {
296 OpaqueConnex<RES>& refConnex = refClause;
297 return ForwardConnex<RES>{refConnex.parse};
298 }
299
300
301
302 namespace {
304 template<typename ARG, typename FUN, typename SEL =void>
306 {
307 static_assert (!sizeof(ARG),
308 "Model binding must accept preceding model result.");
309 };
310
311 template<typename ARG, typename FUN>
312 struct _ProbeFunReturn<ARG,FUN, std::void_t<decltype(std::declval<FUN>() (std::declval<ARG>()))>>
313 { // probe the λ with ARG to force template instantiation
314 using Ret = decltype(std::declval<FUN>() (std::declval<ARG>()));
315 };
316
317
318 template<class FUN>
319 inline bool
320 _boundFun(FUN const& fun)
321 {
322 if constexpr (std::is_constructible<bool, FUN const&>())
323 return bool(fun);
324 else
325 return std::is_invocable<FUN, StrView>();
326 }
327 }
328
335 template<class CON, class BIND>
336 inline auto
337 adaptConnex (CON&& connex, BIND&& modelBinding)
338 {
339 using RX = CON::Result;
340 using Arg = std::add_rvalue_reference_t<RX>;
341 using AdaptedRes = _ProbeFunReturn<Arg,BIND>::Ret;
342 return Connex{[origConnex = forward<CON>(connex)
343 ,binding = forward<BIND>(modelBinding)
344 ]
345 (StrView toParse) -> Eval<AdaptedRes>
346 {
347 auto eval = origConnex.parse (toParse);
348 if (eval.result)
349 return {binding (move (*eval.result))
350 ,eval.consumed};
351 else
352 return {std::nullopt};
353 }};
354 }
355
356 template<class CON>
357 inline auto
358 toStringConnex (CON&& connex, uint part)
359 {
360 using Result = CON::Result;
361 return Connex([baseConnex = forward<CON>(connex)
362 ,part
363 ]
364 (StrView toParse) -> Eval<string>
365 {
366 auto eval = baseConnex.parse (toParse);
367 if (eval.result)
369 return {eval.result->str(part)
370 ,eval.consumed
371 };
372 else
373 { // defensive fall-back: ignore model, return accepted input part
374 size_t pre = leadingWhitespace (toParse);
375 return {string{toParse.substr (pre, eval.consumed - pre)}
376 ,eval.consumed
377 };
378 }
379 else
380 return {std::nullopt};
381 });
382 }
383
384
385
386 /* ===== building structured models ===== */
387
392 template<typename...RESULTS>
393 struct SeqModel
394 : tuple<RESULTS...>
395 {
396 static constexpr size_t N = sizeof...(RESULTS);
397 using Seq = lib::meta::Types<RESULTS...>;
398 using Tup = std::tuple<RESULTS...>;
399
400 SeqModel() = default;
401
402 template<typename...XS, typename XX>
403 SeqModel (SeqModel<XS...>&& seq, XX&& extraElm)
404 : Tup{std::tuple_cat (seq.extractTuple()
405 ,std::make_tuple (forward<XX> (extraElm)) )}
406 { }
407
408 template<typename X1, typename X2>
409 SeqModel (X1&& res1, X2&& res2)
410 : Tup{move(res1), move(res2)}
411 { }
412
413 Tup&& extractTuple() { return move(*this); }
414
415 template<size_t i>
416 auto get() { return std::get<i> (*this); }
417 };
418
419
424 template<typename...CASES>
425 struct AltModel
426 : lib::BranchCase<CASES...>
427 {
428 using Alt = lib::BranchCase<CASES...>;
429 static constexpr size_t N = sizeof...(CASES);
430
431 template<typename EXTRA>
432 using Additionally = AltModel<CASES...,EXTRA>;
433
434 template<typename EXTRA>
437 {
438 Additionally<EXTRA>& upFaked = reinterpret_cast<Additionally<EXTRA>&> (*this);
439 return {move (upFaked)};
440 } // this trick works due to similar storage layout
441
442
443 /* === Builder functions to mark which side of the combinator to pick === */
444
445 using SubSeq = _Vari<AltModel, CASES...>::Prefix;
446 using Penult = _Vari<AltModel, CASES...>::Penult;
447 using Ultima = _Vari<AltModel, CASES...>::Ultima;
448
449 static AltModel
450 mark_left (SubSeq&& leftCases)
451 {
452 return {leftCases.template addBranch<Ultima>()};
453 }
454
455 static AltModel
456 mark_left (Penult&& leftCase)
457 {
458 return {Alt::TOP-1, move(leftCase)};
459 }
460
461 static AltModel
462 mark_right (Ultima&& rightCase)
463 {
464 return {Alt::TOP, move(rightCase)};
465 }
466
467 private:
468 template<typename INIT>
469 AltModel (size_t branchID, INIT&& init)
470 : Alt{branchID, forward<INIT> (init)}
471 { }
472 };
473
474
476 template<typename RES>
478 : std::vector<RES>
479 {
480 RES& get (size_t i) { return this->at(i); }
481 };
482
484 template<typename RES>
485 struct SubModel
486 { /* for metaprogramming only */ };
487
488
490 template<template<class...> class TAG, class R1, class R2 =void>
491 struct _Join
492 {
493 using Result = TAG<R1,R2>;
494 };
495
497 template<template<class...> class TAG, class...RS, class R2>
498 struct _Join<TAG,TAG<RS...>,R2>
499 {
500 using Result = TAG<RS...,R2>;
501 };
502
504 template<template<class...> class TAG, class R1, class R2>
505 struct _Join<TAG,SubModel<R1>,R2>
506 {
507 using Result = TAG<R1,R2>;
508 };
509 template<template<class...> class TAG, class R1, class R2>
510 struct _Join<TAG,R1, SubModel<R2>>
511 {
512 using Result = TAG<R1,R2>;
513 };
514 template<template<class...> class TAG, class R1, class R2>
515 struct _Join<TAG,SubModel<R1>,SubModel<R2>>
516 {
517 using Result = TAG<R1,R2>;
518 };
519
520
521
523 template<class C1, class C2>
524 inline auto
525 sequenceConnex (C1&& connex1, C2&& connex2)
526 {
527 using R1 = decay_t<C1>::Result;
528 using R2 = decay_t<C2>::Result;
529 using ProductResult = _Join<SeqModel, R1, R2>::Result;
530 using ProductEval = Eval<ProductResult>;
531 return Connex{[conL = forward<C1>(connex1)
532 ,conR = forward<C2>(connex2)
533 ]
534 (StrView toParse) -> ProductEval
535 {
536 auto eval1 = conL.parse (toParse);
537 if (eval1.result)
538 {
539 size_t posAfter1 = eval1.consumed;
540 StrView restInput = toParse.substr(posAfter1);
541 auto eval2 = conR.parse (restInput);
542 if (eval2.result)
543 {
544 uint consumedOverall = posAfter1 + eval2.consumed;
545 return ProductEval{ProductResult{move(*eval1.result)
546 ,move(*eval2.result)}
547 ,consumedOverall
548 };
549 }
550 }
551 return ProductEval{std::nullopt};
552 }};
553 }
554
555
557 template<class C1, class C2>
558 inline auto
559 branchedConnex (C1&& connex1, C2&& connex2)
560 {
561 using R1 = decay_t<C1>::Result;
562 using R2 = decay_t<C2>::Result;
563 using SumResult = _Join<AltModel, R1, R2>::Result;
564 using SumEval = Eval<SumResult>;
565 return Connex{[conL = forward<C1>(connex1)
566 ,conR = forward<C2>(connex2)
567 ]
568 (StrView toParse) -> SumEval
569 {
570 auto eval1 = conL.parse (toParse);
571 if (eval1.result)
572 {
573 uint endBranch1 = eval1.consumed;
574 return SumEval{SumResult::mark_left (move(*eval1.result))
575 ,endBranch1
576 };
577 }
578 auto eval2 = conR.parse (toParse);
579 if (eval2.result)
580 {
581 uint endBranch2 = eval2.consumed;
582 return SumEval{SumResult::mark_right (move(*eval2.result))
583 ,endBranch2
584 };
585 }
586 return SumEval{std::nullopt};
587 }};
588 }
589
590
592 template<class C1, class C2>
593 inline auto
595 ,C1&& delimConnex
596 ,C2&& bodyConnex)
597 {
598 using Res = decay_t<C2>::Result;
599 using IterResult = IterModel<Res>;
600 using IterEval = Eval<IterResult>;
601 return Connex{[sep = forward<C1>(delimConnex)
602 ,body = forward<C2>(bodyConnex)
603 ,min,max
604 ]
605 (StrView toParse) -> IterEval
606 {
607 size_t consumed{0};
608 IterResult results;
609 do
610 {
611 uint offset{0};
612 if (not results.empty())
613 { // look for delimiter within sequence
614 auto delim = sep.parse (toParse);
615 if (not delim.result)
616 break;
617 offset += delim.consumed;
618 }
619 auto eval = body.parse (toParse.substr(offset));
620 if (not eval.result)
621 break;
622 offset += eval.consumed;
623 results.emplace_back (move(*eval.result));
624 toParse = toParse.substr(offset);
625 consumed += offset;
626 }
627 while (results.size() < max);
628 return results.size() >= min? IterEval{move(results), consumed}
629 : IterEval{std::nullopt};
630 }};
631 }
632
633
635 template<class CNX>
636 inline auto
637 optionalConnex (CNX&& connex)
638 {
639 using Res = decay_t<CNX>::Result;
640 using OptResult = optional<Res>;
641 using OptEval = Eval<OptResult>;
642 return Connex{[body = forward<CNX>(connex)
643 ]
644 (StrView toParse) -> OptEval
645 {
646 auto eval = body.parse (toParse);
647 size_t consumed{eval.result? eval.consumed : 0};
648 return OptEval{OptResult{eval.result? move(eval.result) : std::nullopt}
649 ,consumed
650 };
651 }};
652 }
653
654
657 template<class C1, class C2, class C3>
658 inline auto
659 bracketedConnex (C1&& openingConnex
660 ,C2&& closingConnex
661 ,C3&& bodyConnex
662 ,bool isOptional)
663 {
664 using Res = decay_t<C3>::Result;
665 return Connex{[opening = forward<C1>(openingConnex)
666 ,closing = forward<C2>(closingConnex)
667 ,body = forward<C3>(bodyConnex)
668 ,isOptional
669 ]
670 (StrView toParse) -> Eval<Res>
671 {
672 auto bracket = opening.parse (toParse);
673 if (bracket.result or isOptional)
674 {
675 size_t consumed = bracket.consumed;
676 bool expectClose{bracket.result};
677 auto eval = body.parse (toParse.substr(consumed));
678 if (eval.result)
679 {
680 consumed += eval.consumed;
681 if (expectClose)
682 bracket = closing.parse (toParse.substr(consumed));
683 if (bracket.result or not expectClose)
684 {
685 consumed += bracket.consumed;
686 return Eval<Res>{move (*eval.result)
687 ,consumed
688 };
689 }
690 }
691 }
692 return Eval<Res>{std::nullopt};
693 }};
694 }
695
696
697
698
703 template<class CON>
704 class Parser
705 : public CON
706 {
707 using PFun = CON::PFun;
708 static_assert (_Fun<PFun>(), "Connex must define a parse-function");
709
710 public:
711 using Connex = CON;
712 using Result = CON::Result;
713
714 static_assert (has_Sig<PFun, Eval<Result>(StrView)>()
715 ,"Signature of the parse-function not suitable");
716
722 {
723 REQUIRE (_boundFun (CON::parse), "unbound recursive syntax");
724 return CON::parse (toParse);
725 }
726
727 template<typename SPEC>
728 Parser (SPEC&& spec)
729 : CON{buildConnex (forward<SPEC> (spec))}
730 { }
731 };
732
733 /* === Deduction guide : how to construct a Parser === */
735 Parser(regex &&) -> Parser<Term>;
736 Parser(regex const&) -> Parser<Term>;
737 Parser(string const&) -> Parser<Term>;
738
739 template<class FUN>
741
742 template<class PAR>
744
745 template<class RES>
747 // bind to recursive syntax by reference
748
749
751 template<typename SPEC, typename SEL =void>
752 struct is_usableSpec : std::false_type{ };
753
754 template<typename SPEC>
755 struct is_usableSpec<SPEC, std::void_t<decltype(Parser{std::declval<SPEC>()})>>
756 : std::true_type
757 { };
758
759 template<typename SPEC>
761
762 template<typename SPEC1, typename SPEC2>
765
766
767
768
769 /***********************************************************************/
781 template<class PAR>
782 class Syntax
783 : public Eval<typename PAR::Result>
784 {
786
787 public:
788 using Connex = PAR::Connex;
789 using Result = PAR::Result;
790
792 : parse_{Nil()}
793 { }
794
795 explicit
796 Syntax (PAR&& parser)
797 : parse_{move (parser)}
798 { }
799
800 explicit
801 operator bool() const { return success();}
802
803 operator Connex&() { return parse_; }
804 operator Connex const&() const { return parse_; }
805
806 bool success() const { return bool(Syntax::result); }
807 bool hasResult() const { return bool(Syntax::result); }
808 bool canInvoke() const { return _boundFun(parse_.parse);}
809 size_t consumed() const { return Eval<Result>::consumed; }
810 Result& getResult() { return * Syntax::result; }
811 Result&& extractResult() { return move(getResult()); }
812
813
814 /********************************************/
817 Syntax&&
818 parse (StrView toParse)
819 {
820 eval() = parse_(toParse);
821 return move(*this);
822 }
823
824
825 template<class PX>
826 Syntax&
828 {
829 using ConX = PX::Connex;
830 ConX& refConnex = refSyntax;
831 parse_.parse = move(refConnex.parse);
832 return *this;
833 }
834
835
838 template<typename SPEC>
839 auto seq (SPEC&& clauseDef);
840
841 template<typename SPEC>
842 auto alt (SPEC&& clauseDef);
843
844 template<typename SPEC>
845 auto opt (SPEC&& clauseDef);
846
847 template<typename SPEC1, typename SPEC2>
848 auto repeat (uint min, uint max, SPEC1&& delimDef, SPEC2&& clauseDef);
849
850 template<typename SPEC1, typename SPEC2>
851 auto repeat (uint cnt, SPEC1&& delimDef, SPEC2&& clauseDef);
852
853 template<typename SPEC1, typename SPEC2>
854 auto repeat (SPEC1&& delimDef, SPEC2&& clauseDef);
855
856 template<typename SPEC>
857 auto repeat (SPEC&& clauseDef);
858
859 template<typename SPEC1, typename SPEC2, typename SPEC3>
860 auto bracket (SPEC1&& openDef, SPEC2&& closeDef, SPEC3&& bodyDef);
861
862 template<typename SPEC>
863 auto bracket (string bracketSpec, SPEC&& bodyDef);
864
865 template<typename SPEC>
866 auto bracket (SPEC&& bodyDef);
867
868 template<typename SPEC>
869 auto bracketOpt (string bracketSpec, SPEC&& bodyDef);
870
871 template<typename SPEC>
872 auto bracketOpt (SPEC&& bodyDef);
873
874 template<class FUN>
875 auto bind (FUN&& modelAdapt);
876
877 auto bindMatch (uint group =0);
878
879 private:
880 Eval<Result>& eval() { return *this;}
881 };
882
883
884
885
889 template<typename SPEC>
890 inline auto
891 accept (SPEC&& clauseDef)
892 {
893 return Syntax{Parser{forward<SPEC> (clauseDef)}};
894 }
895
897 inline auto accept() { return Syntax<Parser<NulP>>{}; }
898
899
901 template<typename SPEC>
902 inline auto
903 accept_opt (SPEC&& clauseDef)
904 {
905 return accept(
906 optionalConnex (Parser{forward<SPEC> (clauseDef)}));
907 }
908
909
917 template<typename SPEC1, typename SPEC2>
918 inline auto
919 accept_repeated (uint min, uint max, SPEC1&& delimDef, SPEC2&& clauseDef)
920 {
921 if (max<min)
922 throw err::Invalid{_Fmt{"Invalid repeated syntax-spec: min:%d > max:%d"}
923 % min % max };
924 if (max == 0)
925 throw err::Invalid{"Invalid repeat with max ≡ 0 repetitions"};
926
927 return accept(
929 ,Parser{forward<SPEC1> (delimDef)}
930 ,Parser{forward<SPEC2> (clauseDef)}));
931 }
932
934 template<typename SPEC1, typename SPEC2, typename =if_acceptableSpecs<SPEC1,SPEC2>>
935 inline auto
936 accept_repeated (uint cnt, SPEC1&& delimDef, SPEC2&& clauseDef)
937 {
938 return accept_repeated (cnt,cnt, forward<SPEC1>(delimDef), forward<SPEC2>(clauseDef));
939 }
940
942 template<typename SPEC1, typename SPEC2, typename =if_acceptableSpecs<SPEC1,SPEC2>>
943 inline auto
944 accept_repeated (SPEC1&& delimDef, SPEC2&& clauseDef)
945 {
946 return accept_repeated (1,uint(-1), forward<SPEC1>(delimDef), forward<SPEC2>(clauseDef));
947 }
948
949 template<typename SPEC>
950 inline auto
951 accept_repeated (uint min, uint max, SPEC&& clauseDef)
952 {
953 return accept_repeated (min, max, Nil{}, forward<SPEC>(clauseDef));
954 }
955
956 template<typename SPEC>
957 inline auto
958 accept_repeated (uint cnt, SPEC&& clauseDef)
959 {
960 return accept_repeated (cnt, Nil{}, forward<SPEC>(clauseDef));
961 }
962
963 template<typename SPEC>
964 inline auto
965 accept_repeated (SPEC&& clauseDef)
966 {
967 return accept_repeated (Nil{}, forward<SPEC>(clauseDef));
968 }
969
976 template<typename SPEC1, typename SPEC2, typename SPEC3>
977 inline auto
978 accept_bracket (SPEC1&& openDef, SPEC2&& closeDef, SPEC3&& bodyDef)
979 {
980 return accept(
981 bracketedConnex (Parser{forward<SPEC1>(openDef) }
982 ,Parser{forward<SPEC2>(closeDef)}
983 ,Parser{forward<SPEC3>(bodyDef) }
984 ,false // bracket mandatory, not optional
985 ));
986 }
987
992 template<typename SPEC>
993 inline auto
994 accept_bracket (string bracketSpec, SPEC&& bodyDef)
995 {
996 if (bracketSpec.size() != 2)
997 throw err::Invalid{"Bracket spec with opening and closing character expected"};
998 return accept(
999 bracketedConnex (Parser{"\\"+bracketSpec.substr(0,1)}
1000 ,Parser{"\\"+bracketSpec.substr(1,1)}
1001 ,Parser{forward<SPEC>(bodyDef) }
1002 ,false // bracket mandatory, not optional
1003 ));
1004 }
1005
1007 template<typename SPEC>
1008 inline auto
1009 accept_bracket (SPEC&& bodyDef)
1010 {
1011 return accept_bracket ("()", forward<SPEC>(bodyDef));
1012 }
1013
1015 template<typename SPEC>
1016 inline auto
1017 accept_bracketOpt (string bracketSpec, SPEC&& bodyDef)
1018 {
1019 if (bracketSpec.size() != 2)
1020 throw err::Invalid{"Bracket spec with opening and closing character expected"};
1021 return accept(
1022 bracketedConnex (Parser{"\\"+bracketSpec.substr(0,1)}
1023 ,Parser{"\\"+bracketSpec.substr(1,1)}
1024 ,Parser{forward<SPEC>(bodyDef) }
1025 ,true // bracket optional, can be omitted
1026 ));
1027 }
1028
1029 template<typename SPEC>
1030 inline auto
1031 accept_bracketOpt (SPEC&& bodyDef)
1032 {
1033 return accept_bracketOpt ("()", forward<SPEC>(bodyDef));
1034 }
1035
1036
1054 template<typename RES>
1055 inline auto
1057 {
1058 return accept (Connex{std::function<Eval<RES>(StrView)>{}});
1059 }
1060
1061
1062
1071 template<class PAR>
1072 template<typename SPEC>
1073 inline auto
1074 Syntax<PAR>::seq (SPEC&& clauseDef)
1075 {
1076 return accept(
1077 sequenceConnex (move(parse_)
1078 ,Parser{forward<SPEC> (clauseDef)}));
1079 }
1080
1093 template<class PAR>
1094 template<typename SPEC>
1095 inline auto
1096 Syntax<PAR>::alt (SPEC&& clauseDef)
1097 {
1098 return accept(
1099 branchedConnex (move(parse_)
1100 ,Parser{forward<SPEC> (clauseDef)}));
1101 }
1102
1109 template<class PAR>
1110 template<typename SPEC>
1111 inline auto
1112 Syntax<PAR>::opt (SPEC&& clauseDef)
1113 {
1114 return seq (accept_opt (forward<SPEC> (clauseDef)));
1115 }
1116
1122 template<class PAR>
1123 template<typename SPEC1, typename SPEC2>
1124 inline auto
1125 Syntax<PAR>::repeat (uint min, uint max, SPEC1&& delimDef, SPEC2&& clauseDef)
1126 {
1127 return seq (accept_repeated (min,max
1128 ,forward<SPEC1>(clauseDef)
1129 ,forward<SPEC2>(clauseDef)));
1130 }
1131
1132 template<class PAR>
1133 template<typename SPEC1, typename SPEC2>
1134 inline auto
1135 Syntax<PAR>::repeat (uint cnt, SPEC1&& delimDef, SPEC2&& clauseDef)
1136 {
1137 return seq (accept_repeated (cnt
1138 ,forward<SPEC1>(clauseDef)
1139 ,forward<SPEC2>(clauseDef)));
1140 }
1141
1142 template<class PAR>
1143 template<typename SPEC1, typename SPEC2>
1144 inline auto
1145 Syntax<PAR>::repeat (SPEC1&& delimDef, SPEC2&& clauseDef)
1146 {
1147 return seq (accept_repeated (forward<SPEC1>(clauseDef)
1148 ,forward<SPEC2>(clauseDef)));
1149 }
1150
1151 template<class PAR>
1152 template<typename SPEC>
1153 inline auto
1154 Syntax<PAR>::repeat (SPEC&& clauseDef)
1155 {
1156 return seq (accept_repeated (forward<SPEC>(clauseDef)));
1157 }
1158
1163 template<class PAR>
1164 template<typename SPEC1, typename SPEC2, typename SPEC3>
1165 inline auto
1166 Syntax<PAR>::bracket (SPEC1&& openDef, SPEC2&& closeDef, SPEC3&& bodyDef)
1167 {
1168 return seq (accept_bracket (forward<SPEC1>(openDef)
1169 ,forward<SPEC2>(closeDef)
1170 ,forward<SPEC3>(bodyDef)));
1171 }
1172
1173 template<class PAR>
1174 template<typename SPEC>
1175 inline auto
1176 Syntax<PAR>::bracket (string bracketSpec, SPEC&& bodyDef)
1177 {
1178 return seq (accept_bracket (move (bracketSpec)
1179 ,forward<SPEC>(bodyDef)));
1180 }
1181
1182 template<class PAR>
1183 template<typename SPEC>
1184 inline auto
1185 Syntax<PAR>::bracket (SPEC&& bodyDef)
1186 {
1187 return seq (accept_bracket (forward<SPEC>(bodyDef)));
1188 }
1189
1190 template<class PAR>
1191 template<typename SPEC>
1192 inline auto
1193 Syntax<PAR>::bracketOpt (string bracketSpec, SPEC&& bodyDef)
1194 {
1195 return seq (accept_bracketOpt (move (bracketSpec)
1196 ,forward<SPEC>(bodyDef)));
1197 }
1198
1199 template<class PAR>
1200 template<typename SPEC>
1201 inline auto
1203 {
1204 return seq (accept_bracketOpt (forward<SPEC>(bodyDef)));
1205 }
1206
1207 template<class PAR>
1208 template<class FUN>
1209 inline auto
1210 Syntax<PAR>::bind (FUN&& modelAdapt)
1211 {
1212 return accept(
1213 adaptConnex (move(parse_)
1214 ,forward<FUN>(modelAdapt)));
1215 }
1216
1217 template<class PAR>
1218 inline auto
1220 {
1221 return accept(
1222 toStringConnex (move(parse_), group));
1223 }
1224
1225 }// namespace parse
1226
1227
1228 using parse::accept;
1229 using parse::accept_opt;
1232
1233}// namespace util
1234
1235
1236namespace std { // Specialisation to support C++ »Tuple Protocol« and structured bindings.
1237
1239 template<typename...ELMS>
1240 struct tuple_size<util::parse::SeqModel<ELMS...> >
1241 : tuple_size<typename util::parse::SeqModel<ELMS...>::Tup >
1242 { };
1243
1245 template<size_t I, typename...ELMS>
1246 struct tuple_element<I, util::parse::SeqModel<ELMS...> >
1247 : tuple_element<I, typename util::parse::SeqModel<ELMS...>::Tup >
1248 { };
1249}
1250#endif/*LIB_PARSE_H*/
A Sum Type (variant) to capture values from a branched evaluation.
A Sum Type to hold alternative results from a branched evaluation.
static constexpr auto TOP
Derived specific exceptions within Lumiera's exception hierarchy.
Definition error.hpp:193
A front-end for using printf-style formatting.
A Parser function to match and accept some syntax.
Definition parse.hpp:706
Eval< Result > operator()(StrView toParse)
Parse-Function operator: test input and yield Eval record.
Definition parse.hpp:721
CON::Result Result
Definition parse.hpp:712
Parser(SPEC &&spec)
Definition parse.hpp:728
A Syntax clause with a parser and result state.
Definition parse.hpp:784
auto bracketOpt(string bracketSpec, SPEC &&bodyDef)
Definition parse.hpp:1193
Syntax(PAR &&parser)
Definition parse.hpp:796
bool hasResult() const
Definition parse.hpp:807
auto seq(SPEC &&clauseDef)
===== Syntax clause builder DSL =====
Definition parse.hpp:1074
auto repeat(uint min, uint max, SPEC1 &&delimDef, SPEC2 &&clauseDef)
Combinator: extend this Syntax with a further sequenced sub-clause, which in this case accepts a repe...
Definition parse.hpp:1125
Syntax & operator=(Syntax< PX > refSyntax)
Definition parse.hpp:827
Syntax && parse(StrView toParse)
Core API : parse against this syntax clause.
Definition parse.hpp:818
Result & getResult()
Definition parse.hpp:810
Eval< Result > & eval()
Definition parse.hpp:880
auto alt(SPEC &&clauseDef)
Combinator: extend this Syntax by adding an alternative branch.
Definition parse.hpp:1096
PAR::Result Result
Definition parse.hpp:789
auto opt(SPEC &&clauseDef)
Combinator: extend this Syntax with a further sequenced sub-clause, which however is only optional an...
Definition parse.hpp:1112
bool canInvoke() const
Definition parse.hpp:808
auto bindMatch(uint group=0)
Definition parse.hpp:1219
auto bracket(SPEC1 &&openDef, SPEC2 &&closeDef, SPEC3 &&bodyDef)
Combinator: extend this Syntax with a further sequenced sub-clause in brackets.
Definition parse.hpp:1166
size_t consumed() const
Definition parse.hpp:809
Result && extractResult()
Definition parse.hpp:811
bool success() const
Definition parse.hpp:806
PAR::Connex Connex
Definition parse.hpp:788
Lumiera error handling (C++ interface).
Front-end for printf-style string template interpolation.
Metaprogramming tools for detecting and transforming function types.
unsigned int uint
Definition integral.hpp:29
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
»Empty« mark
Definition typelist.hpp:82
variadic sequence of types
Definition typelist.hpp:102
Metaprogramming helper to remould the type sequence in the template arguments of a variadic template.
STL namespace.
helper to detect return type of a possibly generic λ
Definition parse.hpp:306
auto adaptConnex(CON &&connex, BIND &&modelBinding)
Adapt by applying a result-transforming function after a successful parse.
Definition parse.hpp:337
auto accept_bracketOpt(string bracketSpec, SPEC &&bodyDef)
Start Syntax with a sub-clause, optionally enclosed into brackets.
Definition parse.hpp:1017
Connex< std::function< Eval< RES >(StrView)> & > ForwardConnex
Definition parse.hpp:218
auto accept_repeated(uint min, uint max, SPEC1 &&delimDef, SPEC2 &&clauseDef)
Start Syntax clause with a repeated sub-clause, with separator and repetition limit; repetitions ∊ [m...
Definition parse.hpp:919
auto sequenceConnex(C1 &&connex1, C2 &&connex2)
accept sequence of two parse functions
Definition parse.hpp:525
auto accept()
empty Syntax clause to start further definition
Definition parse.hpp:897
auto buildConnex(Nil)
»Null-Connex« which always successfully accepts the empty sequence
Definition parse.hpp:226
auto toStringConnex(CON &&connex, uint part)
Definition parse.hpp:358
optional< RES > result
Definition parse.hpp:192
auto branchedConnex(C1 &&connex1, C2 &&connex2)
accept either one of two alternative parse functions
Definition parse.hpp:559
auto repeatedConnex(uint min, uint max, C1 &&delimConnex, C2 &&bodyConnex)
repeatedly accept parse-function, optionally delimited.
Definition parse.hpp:594
auto accept_bracket(SPEC1 &&openDef, SPEC2 &&closeDef, SPEC3 &&bodyDef)
Start Syntax with a sub-clause enclosed into a bracketing construct.
Definition parse.hpp:978
lib::meta::enable_if< is_usableSpec< SPEC1 >,lib::meta::enable_if< is_usableSpec< SPEC2 > > > if_acceptableSpecs
Definition parse.hpp:764
Connex< std::function< Eval< RES >(StrView)> > OpaqueConnex
special setup to be pre-declared and then used recursively
Definition parse.hpp:215
auto accept_opt(SPEC &&clauseDef)
start Syntax clause with an optional syntax part
Definition parse.hpp:903
decltype(buildConnex(Nil())) NulP
Definition parse.hpp:233
auto expectResult()
Setup an assignable, recursive Syntax clause, initially empty.
Definition parse.hpp:1056
decltype(buildConnex(std::declval< regex >())) Term
Definition parse.hpp:257
lib::meta::enable_if< is_usableSpec< SPEC > > if_acceptableSpec
Definition parse.hpp:760
TAG< R1, R2 > Result
Definition parse.hpp:493
auto optionalConnex(CNX &&connex)
try to accept parse-function, backtracking if not successful.
Definition parse.hpp:637
auto bracketedConnex(C1 &&openingConnex, C2 &&closingConnex, C3 &&bodyConnex, bool isOptional)
accept some structure enclosed into a bracketing construct.
Definition parse.hpp:659
std::string_view StrView
Definition parse.hpp:174
Parse evaluation result.
Definition parse.hpp:190
Marker-Tag for the result from a sub-expression, not to be joined.
Definition parse.hpp:486
Standard case : combinator of two model branches.
Definition parse.hpp:492
auto max(IT &&elms)
size_t leadingWhitespace(STR &&toParse)
Definition regex.hpp:83
auto min(IT &&elms)
std::optional< smatch > matchAtStart(STR &&toParse, regex const &regex)
Helper algorithm to perform a search but require the match to start at the beginning of the string or...
Definition regex.hpp:71
Convenience wrappers and helpers for dealing with regular expressions.
Trait template for uniform access to function signature types.
Definition function.hpp:144
Meta-function to check that some function like entity offers the expected signature.
Definition function.hpp:303
Sum Model : results from a disjunction of parsing clauses, which are are tested and accepted as alter...
Definition parse.hpp:427
Additionally< EXTRA > addBranch()
Definition parse.hpp:436
static AltModel mark_left(SubSeq &&leftCases)
Definition parse.hpp:450
_Vari< AltModel, CASES... >::Penult Penult
plain value expected for left-branch
Definition parse.hpp:446
AltModel(size_t branchID, INIT &&init)
Definition parse.hpp:469
_Vari< AltModel, CASES... >::Prefix SubSeq
a nested sub-model to extend
Definition parse.hpp:445
static AltModel mark_left(Penult &&leftCase)
Definition parse.hpp:456
static AltModel mark_right(Ultima &&rightCase)
Definition parse.hpp:462
_Vari< AltModel, CASES... >::Ultima Ultima
plain value expected for right-branch
Definition parse.hpp:447
static constexpr size_t N
Definition parse.hpp:429
AltModel< CASES..., EXTRA > Additionally
Definition parse.hpp:432
Building block: parser function definition and connection element.
Definition parse.hpp:202
Connex(FUN pFun)
Definition parse.hpp:208
_Fun< PFun >::Ret::Result Result
Definition parse.hpp:206
Special case Product Model to represent iterative sequence.
Definition parse.hpp:479
RES & get(size_t i)
Definition parse.hpp:480
Product Model : results from a conjunction of parsing clauses, which are to be accepted in sequence,...
Definition parse.hpp:395
Tup && extractTuple()
Definition parse.hpp:413
lib::meta::Types< RESULTS... > Seq
Definition parse.hpp:397
SeqModel(X1 &&res1, X2 &&res2)
Definition parse.hpp:409
SeqModel(SeqModel< XS... > &&seq, XX &&extraElm)
Definition parse.hpp:403
static constexpr size_t N
Definition parse.hpp:396
std::tuple< RESULTS... > Tup
Definition parse.hpp:398
Helpers for type detection, type rewriting and metaprogramming.
Metaprogramming support to rebuild and rebind variadic templates.