Library: get the template compiler basically operative

...implementation of bracketed constructs and cross references still omitted

...define a fairly elaborate test example for parsing
This commit is contained in:
Fischlurch 2024-03-23 23:47:30 +01:00
parent a9cbe7eb90
commit b835d6a012
4 changed files with 145 additions and 52 deletions

View file

@ -336,6 +336,7 @@ namespace meta {
template<typename X>
struct is_StringLike
: __or_< is_basically<X, std::string>
, is_basically<X, std::string_view>
, is_convertible<X, const char*>
>
{ };

View file

@ -133,7 +133,7 @@ namespace lib {
const string MATCH_LOGIC_TOK = "if|for";
const string MATCH_END_TOK = "end\\s*";
const string MATCH_ELSE_TOK = "else";
const string MATCH_SYNTAX = "("+MATCH_ELSE_TOK+")|(?:("+MATCH_END_TOK+")?("+MATCH_LOGIC_TOK+")\\s+)?("+MATCH_KEY_PATH+")";
const string MATCH_SYNTAX = "("+MATCH_ELSE_TOK+")|(?:("+MATCH_END_TOK+")?("+MATCH_LOGIC_TOK+")\\s*)?("+MATCH_KEY_PATH+")?";
const string MATCH_FIELD = "\\$\\{\\s*(?:"+MATCH_SYNTAX+")\\s*\\}";
const string MATCH_ESCAPE = R"~((\\\$))~";
@ -199,6 +199,9 @@ namespace lib {
.transform (classify);
}
}
namespace test { // declared friend for test access
class TextTemplate_test;
}
@ -289,6 +292,8 @@ namespace lib {
template<class DAT>
static string
apply (string spec, DAT const& data);
friend class test::TextTemplate_test;
};
@ -309,9 +314,10 @@ namespace lib {
*/
template<class PAR>
class TextTemplate::ActionCompiler
: public PAR
{
Idx idx_{0};
Action currToken_{};
Action currToken_{TEXT, initLead()};
optional<StrView> post_{nullopt};
public:
@ -348,16 +354,16 @@ namespace lib {
{ //...throws if exhausted
TagSyntax& tag = PAR::yield();
auto isState = [this](Code c){ return c == currToken_.code; };
auto nextState = [this] {
StrView lead = tag.tail;
PAR::iterNext();
// first expose intermittent text before next tag
if (PAR::checkPoint())
lead = PAR::yield().lead;
else // expose tail after final match
post_ = lead;
return Action{TEXT, lead};
};
auto nextState = [this, &tag] {
StrView lead = tag.tail;
PAR::iterNext();
// first expose intermittent text before next tag
if (PAR::checkPoint())
lead = PAR::yield().lead;
else // expose tail after final match
post_ = lead;
return Action{TEXT, string{lead}};
};
switch (tag.syntax) {
case TagSyntax::ESCAPE:
return nextState();
@ -366,13 +372,46 @@ namespace lib {
return nextState();
return Action{KEY, tag.key};
case TagSyntax::IF:
if (isState (COND))
return nextState();
///////////////////////////////////////////////////OOO push IF-clause here
return Action{COND, tag.key};
case TagSyntax::END_IF:
///////////////////////////////////////////////////OOO verify and pop IF-clause here
return nextState();
case TagSyntax::FOR:
if (isState (ITER))
return nextState();
///////////////////////////////////////////////////OOO push FOR-clause here
return Action{ITER, tag.key};
case TagSyntax::END_FOR:
///////////////////////////////////////////////////OOO verify and pop FOR-clause here
return nextState();
case TagSyntax::ELSE:
if (true) /////////////////////////////////////////OOO derive IF or FOR from context
{
if (isState (JUMP))
return nextState();
///////////////////////////////////////////////////OOO actual IF-else implementation
return Action{JUMP};
}
else
{
if (isState (LOOP))
return nextState();
///////////////////////////////////////////////////OOO actual FOR-else implementation
return Action{LOOP};
}
default:
NOTREACHED ("uncovered TagSyntax keyword while compiling a TextTemplate.");
}
}
string
initLead() ///< first Action must present the literal text before the first tag
{
return string{PAR::checkPoint()? PAR::yield().lead : ""};
}
};

View file

@ -48,6 +48,7 @@ namespace lib {
namespace test {
using MapS = std::map<string, string>;
using LERR_(ITER_EXHAUST);
/***************************************************************************//**
@ -193,12 +194,49 @@ namespace test {
==
"${two}, \\$, ${if high}"_expect);
auto render = [](TagSyntax& tag) -> string
{ return _Fmt{"▶%s‖%d|%s‖▷"} % string{tag.lead} % uint(tag.syntax) % tag.key; };
auto wau = parse(input)
.transform(render);
SHOW_EXPR(util::join(wau))
// Parse matches of this regexp into well defined syntax elements
auto parser = parse(input);
CHECK (not isnil(parser));
CHECK (parser->syntax == TagSyntax::KEYID);
CHECK (parser->lead == "one "_expect);
CHECK (parser->key == "two"_expect);
++parser;
CHECK (parser);
CHECK (parser->syntax == TagSyntax::ESCAPE);
CHECK (parser->lead == " three "_expect);
CHECK (parser->key == ""_expect);
++parser;
CHECK (parser);
CHECK (parser->syntax == TagSyntax::IF);
CHECK (parser->lead == "\\${four} "_expect);
CHECK (parser->key == "high"_expect);
++parser;
CHECK (isnil (parser));
VERIFY_ERROR (ITER_EXHAUST, *parser);
VERIFY_ERROR (ITER_EXHAUST, ++parser);
// Generate sequence of Action tokens from parsing results
auto render = [](TextTemplate::Action const& act) -> string
{ return _Fmt{"‖%d|↷%d‖▷%s"} % uint(act.code) % act.refIDX % act.val; };
SHOW_EXPR(util::join(parse(input)
.processingLayer<TextTemplate::ActionCompiler>()
.transform(render)
, ""))
input = R"~(
Prefix-1 ${some.key} next one is \${escaped}
Prefix-2 ${if cond1} active ${else} inactive ${end if
}Prefix-3 ${if cond2} active2${end if cond2} more
Prefix-4 ${for data} fixed ${embedded}
Pre-5 ${if nested}nested-active${
else }nested-inactive${ end
if nested}loop-suffix${else}${end
for} tail...
)~";
auto compiler = parse(input)
.processingLayer<TextTemplate::ActionCompiler>();
SHOW_EXPR(util::join(compiler.transform(render),"\n"))
}

View file

@ -112544,9 +112544,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1711050505240" ID="ID_436317773" MODIFIED="1711050518794" TEXT="nicht klar ob ich diese Flexibilit&#xe4;t jemals brauche"/>
<node CREATED="1711050521566" ID="ID_323200192" MODIFIED="1711050666932" TEXT="und nicht klar wie das dann konfiguriert wird">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
als Einstellung des konkreten Templates? &#10233; das w&#228;re einfach, aber unpraktisch f&#252;r den Client
@ -112741,9 +112739,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<icon BUILTIN="button_ok"/>
<node CREATED="1711212050899" ID="ID_573965593" MODIFIED="1711212112634" TEXT="gibt jeweils einen TagSyntax-Record aus">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...dieser enth&#228;lt die Informationen aus dem RegExp-Match bereits semantisch aufgeschl&#252;sselt
@ -112754,9 +112750,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
<node CREATED="1711212113875" ID="ID_842279818" MODIFIED="1711212212420" TEXT="zudem wird eine Anschlu&#xdf;position im Functor &#xbb;versteckt mitgeschleppt&#xab;">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...das hei&#223;t, die einzelne Auswertung ist keine <i>pure function </i>&#8212; aber der Seiteneffekt-Stat verbleibt in der Pipeline selber und merkt sich den Endpunkt des vorausgehenden Matches
@ -112777,14 +112771,14 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710804999413" ID="ID_670708059" MODIFIED="1710805006332" TEXT="handzuhabende Situationen">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1710805054381" ID="ID_1600465677" MODIFIED="1710805058600" TEXT="erstes Tag">
<node CREATED="1710805070796" ID="ID_19487824" MODIFIED="1710805126616" TEXT="vorausgehender Text als text-Code emittieren"/>
<node CREATED="1710805127396" ID="ID_1769703452" MODIFIED="1710805138230" TEXT="rekursiver Aufruf"/>
<node COLOR="#435e98" CREATED="1710805070796" ID="ID_19487824" MODIFIED="1711231872228" TEXT="vorausgehenden Text als text-Code emittieren"/>
<node COLOR="#435e98" CREATED="1710805127396" ID="ID_1769703452" MODIFIED="1711231873849" TEXT="rekursiver Aufruf"/>
</node>
<node CREATED="1710805094112" ID="ID_1981750216" MODIFIED="1710805100142" TEXT="Platzhalter">
<node CREATED="1710805110670" ID="ID_1186940443" MODIFIED="1710805122102" TEXT="key-Code emittieren"/>
<node COLOR="#435e98" CREATED="1710805110670" ID="ID_1186940443" MODIFIED="1711231865125" TEXT="key-Code emittieren"/>
</node>
<node CREATED="1710805159120" ID="ID_966003839" MODIFIED="1710805161851" TEXT="if ID">
<node CREATED="1710805210794" ID="ID_1447898531" MODIFIED="1710805218710" TEXT="cond-Code mit key emittieren"/>
<node COLOR="#435e98" CREATED="1710805210794" ID="ID_1447898531" MODIFIED="1711231860504" TEXT="cond-Code mit key emittieren"/>
<node CREATED="1710805219728" ID="ID_373857285" MODIFIED="1710809681135" TEXT="push clause(IF)">
<node CREATED="1710805249556" ID="ID_1366141121" MODIFIED="1710805254583" TEXT="enth&#xe4;lt den Key"/>
<node CREATED="1710805255123" ID="ID_1075707089" MODIFIED="1710805271261" TEXT="enth&#xe4;lt den IDX des soeben emittierten Starters"/>
@ -112802,7 +112796,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<arrowlink COLOR="#6455aa" DESTINATION="ID_952557558" ENDARROW="Default" ENDINCLINATION="112;-9;" ID="Arrow_ID_1645155125" STARTARROW="None" STARTINCLINATION="103;11;"/>
</node>
<node CREATED="1710806120310" ID="ID_113535239" MODIFIED="1710806148751" TEXT="aktuell n&#xe4;chsten IDX in jump.afterIDX schreiben"/>
<node CREATED="1710806211723" ID="ID_544563630" MODIFIED="1710806216422" TEXT="(nichts zu emittieren)"/>
<node COLOR="#435e98" CREATED="1710806211723" ID="ID_544563630" MODIFIED="1711231882251" TEXT="(nichts zu emittieren)"/>
<node CREATED="1710806196725" ID="ID_1695937501" MODIFIED="1710806201560" TEXT="Stack pop"/>
</node>
<node CREATED="1710807375799" ID="ID_952557558" MODIFIED="1710807485995" TEXT="end if ID &#x2227; elseIDX noch leer">
@ -112815,7 +112809,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1710807649211" ID="ID_1724244138" MODIFIED="1710807651982" TEXT="Stack pop"/>
</node>
<node CREATED="1710806240319" ID="ID_21539921" MODIFIED="1710806243387" TEXT="for ID">
<node CREATED="1710806265628" ID="ID_1120675972" MODIFIED="1710806271623" TEXT="iter-Code mit kex emittieren"/>
<node COLOR="#435e98" CREATED="1710806265628" ID="ID_1120675972" MODIFIED="1711231886330" TEXT="iter-Code mit key emittieren"/>
<node CREATED="1710806276683" ID="ID_1007095460" MODIFIED="1710809759109" TEXT="push clause-FOR">
<node CREATED="1710806367675" ID="ID_1074384173" MODIFIED="1710806371937" TEXT="enth&#xe4;lt den Key"/>
<node CREATED="1710806375389" ID="ID_1970731379" MODIFIED="1710806384327" TEXT="enth&#xe4;lt den IDX des soeben emittierten Starters"/>
@ -112836,7 +112830,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<arrowlink COLOR="#6c5999" DESTINATION="ID_905517349" ENDARROW="Default" ENDINCLINATION="116;-16;" ID="Arrow_ID_130125525" STARTARROW="None" STARTINCLINATION="108;10;"/>
</node>
<node CREATED="1710806926394" ID="ID_1821893125" MODIFIED="1710806947252" TEXT="aktuell n&#xe4;chsten IDX in loop.afterIDX schreiben"/>
<node CREATED="1710807230043" ID="ID_877544642" MODIFIED="1710807234878" TEXT="(nichts zu emittieren)"/>
<node COLOR="#435e98" CREATED="1710807230043" ID="ID_877544642" MODIFIED="1711234256941" TEXT="(nichts zu emittieren)"/>
<node CREATED="1710807235490" ID="ID_598110285" MODIFIED="1710807239243" TEXT="Stack pop"/>
</node>
<node CREATED="1710807760468" ID="ID_905517349" MODIFIED="1710809796838" TEXT="end for ID &#x2227; loopIDX noch leer">
@ -113122,9 +113116,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
<node CREATED="1711209038541" ID="ID_363063181" MODIFIED="1711209133550">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
man k&#246;nnte wohl was basteln mit den Funktionen <font color="#8b1212" face="Monospaced">position(i)</font>&#160;und <font color="#8b1212" face="Monospaced">length(i)</font>
@ -113136,14 +113128,12 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
<node CREATED="1711158230860" ID="ID_421709614" MODIFIED="1711158244517" TEXT="also dann halt gleich als String speichern"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711158258547" ID="ID_431240403" MODIFIED="1711209191700" TEXT="mu&#xdf; das letzte Postfix ohne Match finden">
<node COLOR="#435e98" CREATED="1711158258547" ID="ID_431240403" MODIFIED="1711237046365" TEXT="mu&#xdf; das letzte Postfix ohne Match finden">
<linktarget COLOR="#b72676" DESTINATION="ID_431240403" ENDARROW="Default" ENDINCLINATION="-189;13;" ID="Arrow_ID_232745747" SOURCE="ID_1998845229" STARTARROW="None" STARTINCLINATION="170;-14;"/>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="yes"/>
<node CREATED="1711206740722" ID="ID_669120425" MODIFIED="1711206968242" TEXT="gute L&#xf6;sung h&#xe4;ngt stark von der intendierten Verwendung ab">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...und diese soll <i>irgendwie</i>&#160;auf eine Pipeline aufbauen. Das bedeutet, die L&#246;sung sollte m&#246;glichst <i>in der Verarbeitung selber </i>zug&#228;nglich sein, und nicht &#252;ber eine externe Zusatz-Information oder einen Seiteneffekt. Es w&#228;re denkbar, auf das Ende des letzten Match aufzubauen &#8212; allerdings noch viel sch&#246;ner w&#228;re es, wenn der letzte Match den Quell-String <i>komplett aussch&#246;pft, </i>so da&#223; gar kein Rest &#252;brig bleibt
@ -113164,8 +113154,8 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1711211697867" ID="ID_1270227186" MODIFIED="1711211718485" TEXT="damit pa&#xdf;t eine solche Spezial-Behandlung viel besser dorthin">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711211720040" ID="ID_1750995315" MODIFIED="1711211788529" TEXT="man m&#xfc;&#xdf;te nur einen continuation-Iterator durchgeben">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1711211720040" ID="ID_1750995315" MODIFIED="1711237096808" TEXT="mu&#xdf; daf&#xfc;r aber immer auch den aktuellen Rest/tail mit ausgeben">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
@ -113212,9 +113202,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1711218721440" ID="ID_676740256" MODIFIED="1711218738637" TEXT="diese exponiert den lead-Text (zwischen den Tags)"/>
<node CREATED="1711218743589" ID="ID_1099243535" MODIFIED="1711218795646">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
erst in einem zweiten Schritt wird explizit eine spezifische Action f&#252;r <i>diese Syntax </i>emittiert
@ -113230,9 +113218,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1711218821082" ID="ID_1017969918" MODIFIED="1711218843881" TEXT="dieser wird nur aktiviert, wenn das Weiterschalten den Basis(Syntax)-Iterartor verbraucht hat"/>
<node CREATED="1711218847503" ID="ID_730765448" MODIFIED="1711218910259">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
in diesem speziellen Fall wird das verbleibende Postfix
@ -113249,7 +113235,21 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711218958736" ID="ID_263202088" MODIFIED="1711218975015" TEXT="Klammer-Konstrukte">
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1711218958736" ID="ID_263202088" MODIFIED="1711237473886" TEXT="Klammer-Konstrukte">
<icon BUILTIN="pencil"/>
<node CREATED="1711231460288" ID="ID_882106671" LINK="#ID_966003839" MODIFIED="1711231525159" TEXT="IF"/>
<node CREATED="1711231463976" ID="ID_1802146457" LINK="#ID_21539921" MODIFIED="1711231507080" TEXT="FOR"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1711237221184" ID="ID_838370074" MODIFIED="1711237227436" TEXT="Fehlerbehandlung">
<icon BUILTIN="flag-pink"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711237228696" ID="ID_1920021000" MODIFIED="1711237271250" TEXT="unbalancierte Konstrukte">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711237235134" ID="ID_889276068" MODIFIED="1711237271250" TEXT="komplett leere Tags">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711237256363" ID="ID_522815331" MODIFIED="1711237271251" TEXT="fehlender Logic-Key">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
@ -113257,10 +113257,10 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
<node CREATED="1711158288320" ID="ID_309368656" MODIFIED="1711158292632" TEXT="Test....">
<node CREATED="1711158297133" ID="ID_788373690" MODIFIED="1711158307246" TEXT="Iteration als Solche ist m&#xf6;glich"/>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1711158308121" ID="ID_1938624994" MODIFIED="1711158363263" TEXT="K&#xfc;rzen des `lead` mu&#xdf; das Pattern selber &#xfc;berspringen">
<node COLOR="#435e98" CREATED="1711158308121" ID="ID_1938624994" MODIFIED="1711237020411" TEXT="K&#xfc;rzen des `lead` mu&#xdf; das Pattern selber &#xfc;berspringen">
<icon BUILTIN="broken-line"/>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1711158373801" ID="ID_1998845229" MODIFIED="1711209191700" TEXT="verliere das letzte Postfix">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#a50125" CREATED="1711158373801" ID="ID_1998845229" MODIFIED="1711237032425" TEXT="verliere das letzte Postfix">
<arrowlink COLOR="#b72676" DESTINATION="ID_431240403" ENDARROW="Default" ENDINCLINATION="-189;13;" ID="Arrow_ID_232745747" STARTARROW="None" STARTINCLINATION="170;-14;"/>
<icon BUILTIN="messagebox_warning"/>
</node>
@ -113353,6 +113353,21 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1710793387393" ID="ID_413372443" MODIFIED="1710811903746" TEXT="simpeUsage">
<icon BUILTIN="hourglass"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1711237120869" ID="ID_1535361808" MODIFIED="1711237133639" TEXT="verify_parsing">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1711237141859" ID="ID_798155590" MODIFIED="1711237176132" TEXT="Basis-Syntax">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1711237148285" ID="ID_1097637346" MODIFIED="1711237174630" TEXT="Syntax-Keyword-Erkennung">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1711237159112" ID="ID_292718692" MODIFIED="1711237172936" TEXT="Compilation in Action-Sequenz">
<icon BUILTIN="pencil"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1711237177758" ID="ID_428622943" MODIFIED="1711237184293" TEXT="Parse-Fehler">
<icon BUILTIN="flag-pink"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710793507744" ID="ID_1535977723" MODIFIED="1710793518661" TEXT="verify_instantiation">
<icon BUILTIN="flag-yellow"/>
</node>