From 5c2b6b69f6777d9def5e7be0333e70251ebe7ea3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 1 Feb 2025 02:21:34 +0100 Subject: [PATCH] Invocation: can now ''just parse'' the argument spec can you imagine? spell out that convoluted syntax, and it just works!!! --- src/lib/parse.hpp | 87 ++++++------- src/steam/engine/proc-node.cpp | 82 +++++++++++-- tests/core/steam/engine/node-meta-test.cpp | 5 + wiki/thinkPad.ichthyo.mm | 134 +++++++++++++++++---- 4 files changed, 232 insertions(+), 76 deletions(-) diff --git a/src/lib/parse.hpp b/src/lib/parse.hpp index 295e0b2a5..83c734cd2 100644 --- a/src/lib/parse.hpp +++ b/src/lib/parse.hpp @@ -220,7 +220,7 @@ namespace util { /** »Null-Connex« which always successfully accepts the empty sequence */ - auto + inline auto buildConnex(NullType) { return Connex{[](StrView) -> Eval @@ -239,7 +239,7 @@ namespace util { * returns an \ref Eval context, to hold a _Result Model_ and * the number of characters matched by this terminal symbol. */ - auto + inline auto buildConnex (regex rex) { return Connex{[regEx = move(rex)] @@ -255,7 +255,7 @@ namespace util { using Term = decltype(buildConnex (std::declval())); /** build from a string with Regular-Epression spec */ - Term + inline Term buildConnex (string const& rexDef) { return buildConnex (regex{rexDef}); @@ -263,20 +263,20 @@ namespace util { /** copy-builder from an existing parser function */ template - auto + inline auto buildConnex (Connex const& anchor) { return Connex{anchor}; } template - auto + inline auto buildConnex (Connex && anchor) { return Connex{move(anchor)}; } template - auto + inline auto buildConnex (Syntax const& anchor) { using Con = typename Syntax::Connex; @@ -288,7 +288,7 @@ namespace util { * resulting ForwardConnex holds a _reference_ to std::function, * and thus gets to see the full definition reassigned later. */ template - auto + inline auto buildConnex (Syntax>> & refClause) { OpaqueConnex& refConnex = refClause; @@ -331,7 +331,7 @@ namespace util { * and thus the parse can be configured to produce custom result data. */ template - auto + inline auto adaptConnex (CON&& connex, BIND&& modelBinding) { using RX = typename CON::Result; @@ -352,7 +352,7 @@ namespace util { } template - auto + inline auto toStringConnex (CON&& connex, uint part) { using Result = typename CON::Result; @@ -519,7 +519,7 @@ namespace util { /** accept sequence of two parse functions */ template - auto + inline auto sequenceConnex (C1&& connex1, C2&& connex2) { using R1 = typename decay_t::Result; @@ -553,7 +553,7 @@ namespace util { /** accept either one of two alternative parse functions */ template - auto + inline auto branchedConnex (C1&& connex1, C2&& connex2) { using R1 = typename decay_t::Result; @@ -588,7 +588,7 @@ namespace util { /** repeatedly accept parse-function, optionally delimited. */ template - auto + inline auto repeatedConnex (uint min, uint max ,C1&& delimConnex ,C2&& bodyConnex) @@ -631,7 +631,7 @@ namespace util { /** try to accept parse-function, backtracking if not successful. */ template - auto + inline auto optionalConnex (CNX&& connex) { using Res = typename decay_t::Result; @@ -653,7 +653,7 @@ namespace util { /** accept some structure enclosed into a bracketing construct. * \param isOptional if the bracketing can be omitted */ template - auto + inline auto bracketedConnex (C1&& openingConnex ,C2&& closingConnex ,C3&& bodyConnex @@ -885,19 +885,19 @@ namespace util { /** build a Syntax clause from anything usable as parser-spec. */ template - auto + inline auto accept (SPEC&& clauseDef) { return Syntax{Parser{forward (clauseDef)}}; } /** empty Syntax clause to start further definition */ - auto accept() { return Syntax>{}; } + inline auto accept() { return Syntax>{}; } /** start Syntax clause with an optional syntax part */ template - auto + inline auto accept_opt (SPEC&& clauseDef) { return accept( @@ -913,7 +913,7 @@ namespace util { * which implies it is a vector (uses heap storage); if min ≡ 0, the model can be empty. */ template - auto + inline auto accept_repeated (uint min, uint max, SPEC1&& delimDef, SPEC2&& clauseDef) { if (max> - auto + inline auto accept_repeated (uint cnt, SPEC1&& delimDef, SPEC2&& clauseDef) { return accept_repeated (cnt,cnt, forward(delimDef), forward(clauseDef)); @@ -938,28 +938,28 @@ namespace util { /** start Syntax with an arbitrarily repeated sub-clause, with separator */ template> - auto + inline auto accept_repeated (SPEC1&& delimDef, SPEC2&& clauseDef) { return accept_repeated (1,uint(-1), forward(delimDef), forward(clauseDef)); } template - auto + inline auto accept_repeated (uint min, uint max, SPEC&& clauseDef) { return accept_repeated (min, max, NullType{}, forward(clauseDef)); } template - auto + inline auto accept_repeated (uint cnt, SPEC&& clauseDef) { return accept_repeated (cnt, NullType{}, forward(clauseDef)); } template - auto + inline auto accept_repeated (SPEC&& clauseDef) { return accept_repeated (NullType{}, forward(clauseDef)); @@ -972,7 +972,7 @@ namespace util { * the full sequence `open body close` can be matched. */ template - auto + inline auto accept_bracket (SPEC1&& openDef, SPEC2&& closeDef, SPEC3&& bodyDef) { return accept( @@ -988,7 +988,7 @@ namespace util { * \param bracketSpec a 2-char string, e.g. "{}" to expect curly braces. */ template - auto + inline auto accept_bracket (string bracketSpec, SPEC&& bodyDef) { if (bracketSpec.size() != 2) @@ -1003,7 +1003,7 @@ namespace util { /** Start Syntax with a sub-clause enclosed in parentheses */ template - auto + inline auto accept_bracket (SPEC&& bodyDef) { return accept_bracket ("()", forward(bodyDef)); @@ -1011,7 +1011,7 @@ namespace util { /** Start Syntax with a sub-clause, _optionally_ enclosed into brackets. */ template - auto + inline auto accept_bracketOpt (string bracketSpec, SPEC&& bodyDef) { if (bracketSpec.size() != 2) @@ -1025,7 +1025,7 @@ namespace util { } template - auto + inline auto accept_bracketOpt (SPEC&& bodyDef) { return accept_bracketOpt ("()", forward(bodyDef)); @@ -1050,7 +1050,7 @@ namespace util { * @see Parse_test::verify_recursiveSyntax() */ template - auto + inline auto expectResult() { return accept (Connex{std::function(StrView)>{}}); @@ -1068,7 +1068,7 @@ namespace util { */ template template - auto + inline auto Syntax::seq (SPEC&& clauseDef) { return accept( @@ -1090,7 +1090,7 @@ namespace util { */ template template - auto + inline auto Syntax::alt (SPEC&& clauseDef) { return accept( @@ -1106,7 +1106,7 @@ namespace util { */ template template - auto + inline auto Syntax::opt (SPEC&& clauseDef) { return seq (accept_opt (forward (clauseDef))); @@ -1119,7 +1119,7 @@ namespace util { */ template template - auto + inline auto Syntax::repeat (uint min, uint max, SPEC1&& delimDef, SPEC2&& clauseDef) { return seq (accept_repeated (min,max @@ -1129,7 +1129,7 @@ namespace util { template template - auto + inline auto Syntax::repeat (uint cnt, SPEC1&& delimDef, SPEC2&& clauseDef) { return seq (accept_repeated (cnt @@ -1139,7 +1139,7 @@ namespace util { template template - auto + inline auto Syntax::repeat (SPEC1&& delimDef, SPEC2&& clauseDef) { return seq (accept_repeated (forward(clauseDef) @@ -1148,7 +1148,7 @@ namespace util { template template - auto + inline auto Syntax::repeat (SPEC&& clauseDef) { return seq (accept_repeated (forward(clauseDef))); @@ -1160,7 +1160,7 @@ namespace util { */ template template - auto + inline auto Syntax::bracket (SPEC1&& openDef, SPEC2&& closeDef, SPEC3&& bodyDef) { return seq (accept_bracket (forward(openDef) @@ -1170,7 +1170,7 @@ namespace util { template template - auto + inline auto Syntax::bracket (string bracketSpec, SPEC&& bodyDef) { return seq (accept_bracket (move (bracketSpec) @@ -1179,7 +1179,7 @@ namespace util { template template - auto + inline auto Syntax::bracket (SPEC&& bodyDef) { return seq (accept_bracket (forward(bodyDef))); @@ -1187,7 +1187,7 @@ namespace util { template template - auto + inline auto Syntax::bracketOpt (string bracketSpec, SPEC&& bodyDef) { return seq (accept_bracketOpt (move (bracketSpec) @@ -1196,7 +1196,7 @@ namespace util { template template - auto + inline auto Syntax::bracketOpt (SPEC&& bodyDef) { return seq (accept_bracketOpt (forward(bodyDef))); @@ -1204,7 +1204,7 @@ namespace util { template template - auto + inline auto Syntax::bind (FUN&& modelAdapt) { return accept( @@ -1213,7 +1213,7 @@ namespace util { } template - auto + inline auto Syntax::bindMatch (uint group) { return accept( @@ -1226,6 +1226,7 @@ namespace util { using parse::accept; using parse::accept_opt; using parse::accept_repeated; + using parse::accept_bracket; }// namespace util diff --git a/src/steam/engine/proc-node.cpp b/src/steam/engine/proc-node.cpp index 96551d5ed..76beabbf5 100644 --- a/src/steam/engine/proc-node.cpp +++ b/src/steam/engine/proc-node.cpp @@ -25,7 +25,7 @@ #include "lib/iter-explorer.hpp" #include "lib/format-string.hpp" #include "lib/format-util.hpp" -#include "lib/regex.hpp" +#include "lib/parse.hpp" #include "lib/util.hpp" #include /////////////////////////////////////////////////////TICKET #1391 is boost-hash the proper tool for this task? @@ -55,6 +55,54 @@ namespace engine { auto res = symbRegistry.emplace (symbol); symbol = *res.first; } + + /* ===== Parse nested spec ===== */ + + using util::parse::accept; + using util::parse::accept_bracket; + using util::parse::accept_repeated; + using util::parse::expectResult; + using lib::meta::NullType; + using std::regex; + + const regex SPEC_CONTENT{R"_([^,\\\(\)\[\]{}<>"]+)_", regex::optimize}; + const regex NON_QUOTE {R"_([^"\\]+)_" , regex::optimize}; + const regex ESCAPE {R"_(\\.)_" , regex::optimize}; + const regex COMMA {R"_(,)_" , regex::optimize}; + const regex D_QUOTE {R"_(")_" , regex::optimize}; + + auto quoted = accept_repeated(accept(NON_QUOTE).alt(ESCAPE)); + auto quote = accept_bracket(D_QUOTE,D_QUOTE, quoted); + + template + auto& + syntaxBracketed() + { + string esc{"\\"}; + regex OPENING{esc+OPE}; + regex CLOSING{esc+CLO}; + regex NON_PAREN{R"_([^\\)_"+esc+OPE+esc+CLO+"]+"}; + + static auto paren = expectResult(); + auto parenContent = accept_repeated(accept(NON_PAREN) + .alt(ESCAPE) + .alt(quote) + .alt(paren)); + + paren = accept_bracket(OPENING,CLOSING, parenContent).bind([](auto){ return NullType{}; }); + return paren; + } + + auto specTermSyntax = accept_repeated(accept(SPEC_CONTENT) + .alt(ESCAPE) + .alt(quote) + .alt(syntaxBracketed<'(',')'>()) + .alt(syntaxBracketed<'<','>'>()) + .alt(syntaxBracketed<'[',']'>()) + .alt(syntaxBracketed<'{','}'>()) + ) + .bindMatch(); + } // (END) Details... @@ -209,12 +257,32 @@ namespace engine { ProcID::ArgModel ProcID::genArgModel() { - using VecS = std::vector; - VecS v1{"bla","blubb"}; - VecS v2; - auto elms1 = lib::makeSeveral().appendAll(v1); - auto elms2 = lib::makeSeveral().appendAll(v2); - return ProcID::ArgModel{elms1.build(), elms2.build()}; + auto argListSyntax = accept_bracket(accept_repeated(COMMA, specTermSyntax)); + auto argSpecSyntax = accept(argListSyntax) + .opt(argListSyntax) + .bind([](auto model) -> ProcID::ArgModel + { + auto packageAsSeveral = [](std::vector& parsedTerms) + { + return lib::makeSeveral() + .appendAll(parsedTerms); + }; + + auto [list1,list2] = model; + auto elms1 = packageAsSeveral(list1); + auto elms2 = list2? packageAsSeveral(*list2) + : lib::makeSeveral(); + + return ProcID::ArgModel{elms1.build(), elms2.build()}; + }); + + argSpecSyntax.parse (argLists_); + if (not argSpecSyntax.success()) + throw err::Invalid{_Fmt{"Unable to parse argument list. " + "Node:%s Spec:%s"} + % genProcName() % argLists_ + }; + return argSpecSyntax.extractResult(); } diff --git a/tests/core/steam/engine/node-meta-test.cpp b/tests/core/steam/engine/node-meta-test.cpp index 0889220fb..358ea3d29 100644 --- a/tests/core/steam/engine/node-meta-test.cpp +++ b/tests/core/steam/engine/node-meta-test.cpp @@ -83,6 +83,11 @@ namespace test { ProcID::ArgModel arg2 = p2.genArgModel(); ProcID::ArgModel arg3 = p3.genArgModel(); SHOW_EXPR(join (arg1.iArg)) +SHOW_EXPR(join (arg1.oArg)) +SHOW_EXPR(join (arg2.iArg)) +SHOW_EXPR(join (arg2.oArg)) +SHOW_EXPR(join (arg3.iArg)) +SHOW_EXPR(join (arg3.oArg)) UNIMPLEMENTED ("parse and evaluate"); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 7d0f19011..b67944fce 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -105319,8 +105319,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ich war blockiert mit dem testgetriebenen Ansatz, denn ich kann zwar jetzt Nodes bauen, aber nicht einfach verifizieren und dokumentieren, daß sie korrekt verdrahtet sind.

- - + @@ -105330,8 +105329,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) die gleiche Funktionalität wird später zur Problem-Diagnose benötigt; also nichts performance-kritisches

- -
+
@@ -105341,8 +105339,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) im Moment sieht's so aus, daß der erzeugende Code im Library-Plug-In ohnehin von internen strukturierten Daten ausgeht, um daraus die Node-Spec zu generieren. Diese wird dann einmal beim Builde per Parse zerlegt und ggfs noch zusätzlich dekoriert, und das war's dann.

- -
+
@@ -105449,8 +105446,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ⟹ alle Deklarationen zum Spec / Model dorthin

- - +
@@ -105477,7 +105473,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + @@ -105493,8 +105490,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) d.h. ArgumentModel könnte eine Struct sein, und lediglich zusätzliche Informations-Funktionen bieten

- - +
@@ -105531,8 +105527,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ...mußte dazu erst mal eine Runde raus, dann hab ichs rasch gesehen...

- - +
@@ -105559,6 +105554,62 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ da schreibt man so eine Monster-Syntax einfach hin +

+ + +
+
+ + + + + + +

+ und der Parser funktioniert auf Anhieb +

+ + +
+ + + +
+
@@ -105595,8 +105646,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Ja, es würde definitiv gehen, und der User würde fluchen, denn die allgegenwärtigen Quotes haben die Nützlichkeit einer »einfachen Listen-Spec« wieder auf. Hinzu kommt, daß es einige spziell lästige Grenzfälle gibt, wie nested-Quotes , die man dann finden und escapen muß

- - + @@ -105606,8 +105656,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) weiß noch nicht recht, wohin das mit der Node-Spec noch führen wird; nach der Lösung mit einer textuellen Spech habe ich vor allem gegriffen, da ich eine Festlegung auf ein Meta-Modell vermeiden möchte — da noch auf lange Zeit das Projekt nicht im Stande sein wird, das Feld der Möglichkeiten hier zu überblicken (was für Medien werden überhaupt verarbeitet? Außer Video und Sound, meine ich....)

- -
+
@@ -105619,8 +105668,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ....und jetzt hab ich einen echten LL-Parser, der diese Aufgabe direkt und ohne Implementierungstricks handhaben kann

- - +
@@ -105642,8 +105690,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ...deshalb habe ich ja auch die Node-Connectivity beibehalten (obwohl zum Rendern nur die Port-Connectivity gebraucht wird). Zusätzlich könnten noch Attribute in der ProcID eine Rolle spielen. Also insgesamt ehr kein separates Parsing

- - +
@@ -105654,8 +105701,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ⟹ also so implementieren wie's am einfachsten geht

- - +
@@ -105694,8 +105740,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Aua, dieses Thema ist zu lange liegen geblieben; drei Monate später weiß ich nicht mehr, was ich überhaupt bezwecken wollte....  Kam das mit der Pipeline so zustande, weil ich mir vorgestllt hatte, einen Spec-String mit einer RegExp zu »scannen« — denn so einfach wird es nicht sein

- - + @@ -106677,7 +106722,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -106718,6 +106763,10 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + @@ -107279,6 +107328,29 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+ + + + + + + + + + + + +

+ weil dies auf einem Array beruht, also im Speicher kompakt liegen muß +

+ + +
+ + +
+
+
@@ -107465,6 +107537,12 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + +
@@ -107635,6 +107713,10 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + +