Library: further straighten iteration logic

playing the »fence post problem« the other way round
and abandoning the ''pull processing'' in favour of direct manipulation
leads to much clearer formulation of the code-generation logic
This commit is contained in:
Fischlurch 2024-03-24 15:51:38 +01:00
parent bc8e947f3c
commit aab446ce48
2 changed files with 45 additions and 54 deletions

View file

@ -316,7 +316,6 @@ namespace lib {
*/
class TextTemplate::ActionCompiler
{
Idx idx_{0};
ScopeStack scope_{};
public:
@ -325,83 +324,72 @@ namespace lib {
buildActions (PAR&& parseIter)
{
ActionSeq actions;
actions.emplace_back (Action{TEXT, initLead(parseIter)});
while (parseIter)
{
idx_ = actions.size();
actions.emplace_back(
compile (parseIter, actions.back().code));
}
compile (parseIter, actions);
return actions;
}
private:
template<class PAR>
Action
compile (PAR& parseIter, Code currCode)
{ //...throws if exhausted
TagSyntax& tag = *parseIter;
auto isState = [&](Code c){ return c == currCode; };
auto nextState = [&] {
StrView lead = tag.tail;
++parseIter;
// first expose intermittent text before next tag
if (parseIter)
lead = parseIter->lead;
return Action{TEXT, string{lead}};
};
switch (tag.syntax) {
void
compile (PAR& parseIter, ActionSeq& actions)
{
auto add = [&](Code c, string v){ actions.push_back (Action{c,v}); };
auto addCode = [&](Code c) { add ( c, parseIter->key); };
auto addLead = [&] { add (TEXT, string{parseIter->lead}); };
auto openScope = [&](Clause c){ scope_.push (ParseCtx{c, actions.size()});};
switch (parseIter->syntax) {
case TagSyntax::ESCAPE:
return nextState();
addLead();
break;
case TagSyntax::KEYID:
if (isState (KEY))
return nextState();
return Action{KEY, tag.key};
addLead();
addCode(KEY);
break;
case TagSyntax::IF:
if (isState (COND))
return nextState();
///////////////////////////////////////////////////OOO push IF-clause here
scope_.push (ParseCtx{IF, idx_});
return Action{COND, tag.key};
addLead();
openScope(IF);
addCode(COND);
break;
case TagSyntax::END_IF:
addLead();
///////////////////////////////////////////////////OOO verify and pop IF-clause here
// if (scope_.empty() or
// (not isnil(tag.key) scope_.top())
return nextState();
break;
case TagSyntax::FOR:
if (isState (ITER))
return nextState();
addLead();
openScope(FOR);
///////////////////////////////////////////////////OOO push FOR-clause here
return Action{ITER, tag.key};
addCode(ITER);
break;
case TagSyntax::END_FOR:
addLead();
///////////////////////////////////////////////////OOO verify and pop FOR-clause here
return nextState();
break;
case TagSyntax::ELSE:
addLead();
if (true) /////////////////////////////////////////OOO derive IF or FOR from context
{
if (isState (JUMP))
return nextState();
///////////////////////////////////////////////////OOO actual IF-else implementation
return Action{JUMP};
addCode(JUMP);
}
else
{
if (isState (LOOP))
return nextState();
///////////////////////////////////////////////////OOO actual FOR-else implementation
return Action{LOOP};
addCode(LOOP);
}
break;
default:
NOTREACHED ("uncovered TagSyntax keyword while compiling a TextTemplate.");
}
}
template<class PAR>
string
initLead (PAR& parseIter) ///< first Action must present the literal text before the first tag
{
return string{parseIter? parseIter->lead : ""};
}
StrView tail = parseIter->tail;
++parseIter;
if (not parseIter)
add (TEXT, string{tail});
} // add final action to supply text after last active tag
};

View file

@ -113259,13 +113259,16 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1711283145848" ID="ID_493051003" MODIFIED="1711283157218" TEXT="ehrlich gesagt: es war schon ganz sch&#xf6;n komplex"/>
<node CREATED="1711283158094" ID="ID_316804248" MODIFIED="1711283210930" TEXT="wiewohl im Rahmen des Iterator-Schemas (f&#xfc;r mich) verst&#xe4;ndlich"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711283024446" ID="ID_559056931" MODIFIED="1711283047068" TEXT="stattdessen: den Compiler als Builder-Komponente anlegen">
<node COLOR="#338800" CREATED="1711283024446" ID="ID_559056931" MODIFIED="1711291844432" TEXT="stattdessen: den Compiler als Builder-Komponente anlegen">
<icon BUILTIN="yes"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711283086632" ID="ID_396780439" MODIFIED="1711283215456" TEXT="erzeugen als freie (kopierbare) Komponente">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1711283086632" ID="ID_396780439" MODIFIED="1711291784325" TEXT="erzeugen als freie (kopierbare) Komponente">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711283101287" ID="ID_1709357131" MODIFIED="1711283215456" TEXT="Arbeitsmethode: buildActions(ParseIterator)">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1711283101287" ID="ID_1709357131" MODIFIED="1711291786010" TEXT="Arbeitsmethode: buildActions(ParseIterator)">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1711291788419" ID="ID_1652146964" MODIFIED="1711291834531" TEXT="das &#xbb;funktionale&#xab; pull-Processing aufgeben &#x27f9; Code viel klarer">
<icon BUILTIN="ksmiletris"/>
</node>
</node>
</node>