Library: prepare for a ETD binding

Document existing data binding logic and investigate in detail
what must be done to enable a similar binding backed by Lumiera's ETD structures.
This analysis highlights some tricky aspects, which can be accommodated by
slight adjustments and generalisations in the `TextTemplate` implementation
 * `GenNode` is not structured string data, rather binary data
 * thus exposing a std::string_view is not adequate, requiring to
   pick up the result type from the actual data binding
 * moreover, to allow for arbitrary nested scopes, a back-pointer
   to the parent scope must be maintained, which requires stable memory locations.
   This can best be solved within the InstanceCore itself, which manages
   the actual hierarchy of data source references.
 * the existing code happens already to fulfil this requirement, but
   for sake of clarity, handling of such a nested scope is now extracted
   into a dedicated operation, to highlight the guaranteed memory layout.
This commit is contained in:
Fischlurch 2024-03-26 19:25:35 +01:00
parent c0439b265c
commit 64f60356b7
4 changed files with 332 additions and 63 deletions

View file

@ -41,6 +41,7 @@ namespace util {
using std::regex;
using std::smatch;
using std::string;
using std::string_view;
@ -53,6 +54,10 @@ namespace util {
RegexSearchIter (string const& toParse, regex const& regex)
: std::sregex_iterator{toParse.begin(), toParse.end(), regex}
{ }
RegexSearchIter (string_view toParse, regex const& regex)
: std::sregex_iterator{string::const_iterator{toParse.begin()}
,string::const_iterator{toParse.end()}, regex}
{ }
operator bool() const { return isValid(); }

View file

@ -71,21 +71,96 @@
**
** # Implementation notes
**
** The template specification is parsed and compiled immediately when constructing
** the TextTemplate instance. At this point, syntactical errors, e.g. mismatched
** conditional opening and closing tags will be detected and raised as exceptions.
** The _compiled template_ is represented as a vector of action tokens, holding the
** constant parts as strings in heap memory and marking the positions of placeholders
** and block bounds.
** The template specification is [parsed and compiled](\ref TextTemplate::parse)
** immediately when constructing the TextTemplate instance. At this point, syntactical
** and logical errors, e.g. mismatched conditional opening and closing tags will be
** detected and raised as exceptions. The _compiled template_ is represented as a
** vector of action tokens, holding the constant parts as strings in heap memory
** and marking the positions of placeholders and block bounds. The branching
** and looping possibly happening later, on instantiation, is prepared
** by issuing appropriate branching and jump markers, referring
** to other points in the sequence by index number...
** - `TEXT` stores a text segment to be included literally
** - `KEY` marks the placeholders, storing the key to retrieve a substitution value
** - `COND` indicates a branching point, based on a data value retrieved by key
** - `ITER` indicates the start of an iteration over data indicated by key
** - `LOOP` marks the end of the iterated segment, linked back to the start
** - `JUMP` represents an unconditional jump to the index number given
** Whenever an _else-section_ is specified in the template, a `JUMP` is emitted
** beforehand, while the first `TEXT` in the _else-section_ is wired as `refIDX`
** from the starting token.
**
** The actual instantiation is initiated through TextTemplate::render(), which picks
** a suitable data binding (causing a compilation failure in case not binding can
** The actual instantiation is initiated through TextTemplate::submit(), which picks
** a suitable data binding (causing a compilation failure in case no binding can
** be established). This function yields an iterator, which will traverse the
** sequence of action tokens precompiled for this template and combine them
** with the retrieved data, yielding a std::string_view for each instantiated
** chunk of the template. The full result can thus be generated either by
** looping, or by invoking util::join() on the provided iterator.
**
**
** ## Data Access
**
** ** The [instantiation processing logic](\ref TextTemplate::Action::instantiate) is
** defined in terms of a *data binding*, represented as TextTemplate::DataSource.
** This binding, assuming a _generic data access protocol,_ has to be supplied by
** a concrete (partial) specialisation of the template `DataSource<DAT>`. This
** allows to render the text template with _structured data,_ in whatever
** actual format the data is available. Notably, bindings are pre-defined
** for string data in a Map, and for Lumiera's »[External Tree Description]«
** format, based on a [generic data node](\ref gen-node.hpp). Generally speaking,
** the following _abstracted primitive operations_ are required to access data:
** - the `DataSource<DAT>` object itself is a copyable value object, representing
** an _abstracted reference to the data._ We can assume that it stores a `const *`
** internally, pointing to some data entity residing elsewhere in memory.
** - it must somehow be possible, to generate a nested sub-data context, represented
** by the same reference data type; this implies that there is some implementation
** mechanism in place to tap into a _nested sub-scope_ within the data.
** - `bool dataSrc.contains(key)` checks if a binding is available for the given \a key.
** If this function returns `false` no further access is attempted for this \a key.
** - `string const& retrieveContent(key)` acquires a reference to string data representing
** the _content_ bound to this \a key. This string content is assumed to remain stable
** in memory during the instantiation process, which exposes a `std::string_view`
** - `Iter getSequence(key)` attempts to _»open« a data sequence,_ assuming that the
** \a key somehow links to data that can somehow be interpreted as a sequence of
** nested sub-data-entities. The result is expected as »[Lumiera Forward Iterator]«.
** - `DataSource<DAT> openContext(Iter)` is supplied with the \a Iter from `getSequence()`
** and assumed to return a new data binding as `DataSource` object, tied to the nested
** data entity or context corresponding to the current »yield« of the Iterator. This
** implies that a `Iter it` can be advanced by `++iter` and then passed in again to
** get the data-src (reference handle) to access the next »sub entity«, repeating
** this procedure until the iterator is _exhausted_ (bool `false`). Moreover, it is
** assumed, that recursive invocations of `retrieveConent(key)` on this sub-scope
** reference will yield the _data values_ designated by \a key _for this sub-entity,
** as well as possibly also accessing data _visible from enclosing scopes._
**
** \par Map Binding
** The preconfigured binding to `std::map<string,string>` implements this protocol relying
** however on some trickery and conventions, since the map as such is one single flat data
** repository. The intricate part relates to iteration (which can be considered more a »proof
** of concept« for testing). More specifically, accessing data for a _loop control key_ should
** yield a CSV list of key prefixes. These are combined with the loop control key to form
** a prefix for individual data values: `"<loop>.<entity>.<key>"`. When encountering a "key"
** while in iteration, first an access is attempted with this _decoration prefix; if this
** fails, a second attempt is made with the bare key alone. See TextTemplate_test::verify_iteration,
** which uses a special setup, where a string of `key=value` pairs is parsed on-the-fly to populate
** a `map<string,string>`
**
** \par ETD Binding
** While the _Map Binding_ detailed in the preceding paragraph is mostly intended to handle
** simple key substitutions, the more elaborate binding to `GenNode` data (ETD) is meant to
** handle structural data, as encountered in the internal communication of components within
** the Lumiera application notably the »diff binding« used to populate the GUI with entities
** represented in the _Session Model_ in Steam-Layer. The mapping is straight-forward, as the
** required concepts can be supported directly
** - Key lookup is translated into _Attribute Lookup_ starting in the current record and
** possibly walking up a scope path
** - the loop key accesses a _nested Attribute_ (lib::diff::GenNode) and exposes its _children_
** for the iteration; thus each entity is again a `Rec<GenNode>` and can be represented
** recursively as a DataSource<Rec<GenNode>>
** - the DataSource implementation includes an _optional parent link,_ which is consulted
** whenever _Attribute Lookup_ in the current record does not yield a result.
** [External Tree Description]: https://lumiera.org/documentation/design/architecture/ETD.html
** [Lumiera Forward Iterator]: https://lumiera.org/documentation/technical/library/iterator.html
** @todo WIP-WIP-WIP 3/2024
** @see TextTemplate_test
** @see gnuplot-gen.hpp
@ -132,7 +207,7 @@ namespace lib {
const regex ACCEPT_DATA_ELM {MATCH_DELIMITER + MATCH_DATA_TOKEN};
inline auto
iterNestedKeys (string key, string const& iterDef)
iterNestedKeys (string key, StrView const& iterDef)
{
return explore (util::RegexSearchIter{iterDef, ACCEPT_DATA_ELM})
.transform ([key](smatch mat){ return key+"."+string{mat[1]}+"."; });
@ -274,7 +349,7 @@ namespace lib {
Idx refIDX{0};
template<class SRC>
StrView instantiate (InstanceCore<SRC>&) const;
auto instantiate (InstanceCore<SRC>&) const;
};
/** the text template is compiled into a sequence of Actions */
@ -296,25 +371,27 @@ namespace lib {
using DataCtxIter = typename SRC::Iter;
using NestedCtx = std::pair<DataCtxIter, SRC>;
using CtxStack = std::stack<NestedCtx, std::vector<NestedCtx>>;
using Value = typename SRC::Value;
SRC dataSrc_;
ActionIter actionIter_;
CtxStack ctxStack_;
StrView rendered_;
Value rendered_;
public:
InstanceCore (ActionSeq const& actions, SRC);
bool checkPoint() const;
StrView& yield() const;
auto& yield() const;
void iterNext();
StrView instantiateNext();
StrView reInstatiate (Idx =Idx(-1));
StrView getContent(string key);
Value instantiateNext();
Value reInstatiate (Idx =Idx(-1));
Value getContent(string key);
bool conditional (string key);
bool openIteration (string key);
bool loopFurther();
void focusNested();
};
@ -579,6 +656,10 @@ namespace lib {
: data_{&map}
{ }
using Value = std::string_view;
using Iter = decltype(iterNestedKeys("",""));
bool
contains (string key)
{
@ -586,7 +667,7 @@ namespace lib {
or util::contains (*data_, key);
}
string const&
Value
retrieveContent (string key)
{
MapS::const_iterator elm;
@ -602,9 +683,6 @@ namespace lib {
return elm->second;
}
using Iter = decltype(iterNestedKeys("",""));
Iter
getSequence (string key)
{
@ -684,12 +762,13 @@ namespace lib {
* @return a string-view pointing to the effective rendered chunk corresponding to this action
*/
template<class SRC>
inline StrView
inline auto
TextTemplate::Action::instantiate (InstanceCore<SRC>& core) const
{
using Result = decltype (core.getContent(val));
switch (code) {
case TEXT:
return val;
return Result(val);
case KEY:
return core.getContent (val);
case COND:
@ -733,7 +812,7 @@ namespace lib {
}
template<class SRC>
inline StrView&
inline auto&
TextTemplate::InstanceCore<SRC>::yield() const
{
return unConst(this)->rendered_;
@ -750,7 +829,7 @@ namespace lib {
/** Instantiate next Action token and expose its rendering */
template<class SRC>
inline StrView
inline typename SRC::Value
TextTemplate::InstanceCore<SRC>::instantiateNext()
{
return actionIter_? actionIter_->instantiate(*this)
@ -764,7 +843,7 @@ namespace lib {
* @return the rendering produced by the selected next Action token
*/
template<class SRC>
inline StrView
inline typename SRC::Value
TextTemplate::InstanceCore<SRC>::reInstatiate (Idx nextCode)
{
if (nextCode == Idx(-1))
@ -776,7 +855,7 @@ namespace lib {
/** retrieve a data value from the data source for the indiated key */
template<class SRC>
inline StrView
inline typename SRC::Value
TextTemplate::InstanceCore<SRC>::getContent (string key)
{
static StrView nil{""};
@ -811,7 +890,7 @@ namespace lib {
{
ctxStack_.push (NestedCtx{move (dataIter)
,dataSrc_});
dataSrc_ = dataSrc_.openContext (ctxStack_.top().first);
focusNested();
return true;
}
return false;
@ -831,7 +910,7 @@ namespace lib {
++dataIter;
if (dataIter)
{ // open next nested context *from enclosing context*
dataSrc_ = ctxStack_.top().second.openContext (dataIter);
focusNested();
return true;
}
else
@ -842,6 +921,28 @@ namespace lib {
}
}
/**
* Step down into the innermost data item context, prepared at the top of #ctxStack_.
* This includes re-assigning the current #dataSrc_ to a new nested data scope,
* created from the enclosing scope, which is assumed to sit at the top of ctxStack_,
* and which is _guaranteed to rest locked at this memory location_ as long as operation
* is carried on within the new nested context. This is to say that a pointer to the
* parent scope (residing at ctxStack_.top()) can be embedded and used from this
* nested context safely. To leave this nested scope, it is sufficient to
* swap this->dataSrc_ with the stack top and then pop the topmost frame.
*/
template<class SRC>
inline void
TextTemplate::InstanceCore<SRC>::focusNested()
{
REQUIRE (not ctxStack_.empty());
NestedCtx& innermostScope = ctxStack_.top();
DataCtxIter& currentDataItem = innermostScope.first;
SRC& parentDataSrc = innermostScope.second;
this->dataSrc_ = parentDataSrc.openContext (currentDataItem);
}

View file

@ -319,7 +319,7 @@ for} tail...
VERIFY_FAIL ("TextTemplate spec without active placeholders"
, TextTemplate::compile("horror boredom"));
, TextTemplate::compile("O tempora O mores"));
VERIFY_FAIL ("Tag without key: ...horror ${<placeholder> |↯|}"
, TextTemplate::compile("horror ${ } vacui"));

View file

@ -113541,8 +113541,8 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710804833930" ID="ID_1766619477" MODIFIED="1710804839987" TEXT="Test-Binding">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1710804833930" ID="ID_1766619477" MODIFIED="1711475112219" TEXT="Test-Binding">
<icon BUILTIN="button_ok"/>
<node CREATED="1710804841699" ID="ID_933127899" MODIFIED="1710804917699" TEXT="eine String-Spec mit kommaseparierten key=val -Literalen"/>
<node CREATED="1710804918648" ID="ID_1642910022" MODIFIED="1710804947480" TEXT="wird einmal geparst und in eine Map gepackt &#x27f6; Map-Binding">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1711385576730" ID="ID_941884997" MODIFIED="1711385595496" TEXT="mu&#xdf; die geparste Map irgendwo dauerhaft bereithalten">
@ -113569,16 +113569,13 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<icon BUILTIN="broken-line"/>
<node CREATED="1711406517514" ID="ID_1242921809" MODIFIED="1711406555810">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
zun&#228;chst einmal: Deklaration kann <font face="Monospaced" color="#1524b7">auto</font>&#160;verwenden
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1711406562556" ID="ID_21985660" MODIFIED="1711406577582" TEXT="...sofern dann weiter unten, bei der Definition der Typ inferiert werden kann"/>
@ -113589,16 +113586,13 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<icon BUILTIN="clanbomber"/>
<node COLOR="#8d2b6b" CREATED="1711406755346" HGAP="31" ID="ID_866002002" MODIFIED="1711406886648" TEXT="Compiler findet nur den Copy-Konstruktor" VSHIFT="4">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Grund: die expliziten Spezialisierungen kommen &#252;berhaupt erst ins's Spiel, wenn der Compiler die konkreten Template-Argumente bereits erschlossen hat. Vorher schaut er nur in das prim&#228;re Template... und wenn das keinen Konstruktor hat, dann kennt der Compiler nur den Copy-Konstruktor. <i>Die resultierende Fehlermeldung ist dann unglaublich hilfreich...</i>
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<font NAME="SansSerif" SIZE="10"/>
<icon BUILTIN="smiley-angry"/>
</node>
@ -113614,9 +113608,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
<node COLOR="#5b280f" CREATED="1711416080681" ID="ID_1704611898" MODIFIED="1711416428174" TEXT="weil diese dann mit einem enable-if-Spezialfall kollidiert">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Das sind die Limitierungen bei Function-Overloads. Mit Template-Deduction-Guides h&#228;tten wir dieses Problem vermutlich nicht (wenn wir sie denn schreiben k&#246;nnten).
@ -113628,8 +113620,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<u>Im Detail</u>: Bei der Function Overload-Resolution werden die verschiedenen Kandidaten geordnet. Dabei werden zun&#228;chst <b>alle &#252;bersch&#252;ssigen und Default-Argumente weggestrichen</b>. Konsequenz: ein enable-If kann zwar einen einzelnen Overload <i>entfernen </i>&#8212; wenn er aber <i>nicht entfernt</i>&#160;wurde, stehen zwei &#228;quivalente Overloads da, und es gibt einen Compilation-Fehler. R&#252;ckgabewerte helfen hier auch nichts (die tragen nur zur const-ness-Auswahl bei). Das hei&#223;t, bei Function-Overload-Resolution mu&#223; das enable-If auf einem <b>weiteren</b>&#160; Parameter stehen, der auch <b>tats&#228;chlich verwendet</b>&#160;wird. Und an der Stelle wird's dann wirklich so trickreich, das es mir fragil erscheint.
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="closed"/>
</node>
<node CREATED="1711416429849" ID="ID_1709082514" MODIFIED="1711416453288" TEXT="Kann deshalb nur Spezial-Bindings bieten, kein generisches Binding">
@ -113651,11 +113642,191 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710793367246" ID="ID_1695880616" MODIFIED="1710793369256" TEXT="ETD">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1710804556008" ID="ID_1997691101" MODIFIED="1710804588772" TEXT="DataSrc ist ein Rec&lt;GenNode&gt;"/>
<node CREATED="1710804591691" ID="ID_1815976275" MODIFIED="1710804603973" TEXT="Key-Zugriff wird &#xfc;bersetzt in Attribut-Zugriff"/>
<node CREATED="1710804616944" ID="ID_538897899" MODIFIED="1710804626706" TEXT="Iteration wird &#xfc;bersetzt in Scope-Iteration"/>
<node CREATED="1710804633837" ID="ID_1119504137" MODIFIED="1710804648600" TEXT="jedes Element im Scope ist wieder ein Rec&lt;GenNode&gt;"/>
<node CREATED="1710804715954" ID="ID_1537394187" MODIFIED="1710804736900" TEXT="diese Elemente k&#xf6;nnen aber leer sein (wegen Parent-Delegation)"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710804556008" ID="ID_1997691101" MODIFIED="1711475133506" TEXT="DataSrc repr&#xe4;sentiert ein &#xbb;Objekt&#xab; &#x2259; Rec&lt;GenNode&gt;">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1711475218638" ID="ID_44068114" MODIFIED="1711475231130" TEXT="Ben&#xf6;tigte Eigenschaften">
<icon BUILTIN="yes"/>
<node CREATED="1711475232644" ID="ID_315057671" MODIFIED="1711475241511" TEXT="mu&#xdf; auf Attribute per Key zugreifen k&#xf6;nnen"/>
<node CREATED="1711475244323" ID="ID_1323303321" MODIFIED="1711475260460" TEXT="mu&#xdf; f&#xfc;r einen solchen Zugriff eine String-Repr&#xe4;sentation liefern">
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1711475264023" ID="ID_1962088901" MODIFIED="1711497355791" TEXT="das ist ein kritischer Punkt f&#xfc;r dieses Binding">
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1711475279862" HGAP="21" ID="ID_392726526" MODIFIED="1711497352861" STYLE="bubble" VSHIFT="-4">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p style="text-align: center">
GenNode wurde explizit entworfen
</p>
<p style="text-align: center">
um &#187;Programming by Reflection&#171;
</p>
<p style="text-align: center">
zu unterbinden
</p>
<p style="text-align: center">
<font size="6">&#8252;</font>
</p>
</body>
</html></richcontent>
<edge COLOR="#7e4c4c"/>
</node>
<node CREATED="1711475487018" ID="ID_240701708" MODIFIED="1711475497215" TEXT="aber GenNode hat eine String-Repr&#xe4;sentation">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1711475501474" ID="ID_1956601098" MODIFIED="1711475509907" TEXT="das gilt auch f&#xfc;r den &#xbb;DataCap&#xab;">
<node CREATED="1711475606554" ID="ID_716867341" MODIFIED="1711475616097" TEXT="der beruht auf einer lib::Variant"/>
<node CREATED="1711475617289" ID="ID_653285103" MODIFIED="1711475627315" TEXT="und hat einen eingebetteten Buffer"/>
<node CREATED="1711475628101" ID="ID_89556720" MODIFIED="1711475672880">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
mit einer <b>pure virtual</b>&#160;String-Repr&#228;sentation
</p>
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1711475675289" ID="ID_369134454" MODIFIED="1711477410646" TEXT="f&#xfc;r GenNode ist das mit einem Variant-Visitor hinterlegt?">
<icon BUILTIN="help"/>
<node CREATED="1711477412790" ID="ID_512513677" MODIFIED="1711477429494" TEXT="gen-node.cpp : DataCap::operator string()"/>
<node CREATED="1711477430263" ID="ID_931178080" MODIFIED="1711477462879" TEXT="delegiert an Variant&lt;DataValues&gt;::operator string()"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1711477398892" ID="ID_130677787" MODIFIED="1711477476253" TEXT="ich finde den nicht??">
<icon BUILTIN="flag-pink"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1711477477202" ID="ID_1417186531" MODIFIED="1711477489600" TEXT="wo versteckt sich der Wicht?">
<icon BUILTIN="smiley-oh"/>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711477500254" ID="ID_403443386" MODIFIED="1711477519140" TEXT="man k&#xf6;nnte es ganz einfach mal &#xbb;pragmatisch&#xab; nutzen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1711477520228" ID="ID_1881261418" MODIFIED="1711477535488" TEXT="und so herausfinden wo es implementiert ist">
<icon BUILTIN="idea"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1711486639403" ID="ID_57682971" MODIFIED="1711486666394" TEXT="au&#xdf;erdem gibt es ein Konsistenz-Problem">
<icon BUILTIN="clanbomber"/>
<node CREATED="1711486668095" ID="ID_325496153" MODIFIED="1711486682097" TEXT="das API gibt eine eine string_view auf gerenderte Daten"/>
<node CREATED="1711486682877" ID="ID_1454625427" MODIFIED="1711486705366" TEXT="aber nicht-String-Content existiert nur als transientes Rendering"/>
<node CREATED="1711486706362" ID="ID_1823130623" MODIFIED="1711491152545" TEXT="nur tempor&#xe4;r bereithalten?">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Man k&#246;nnte erwarten, da&#223; diese string-view tats&#228;chlich nur w&#228;hrend der Iteration genutzt wird &#8212; letztlich m&#246;chte man ja das gerenderte Text-Template irgendwo integrieren...
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
<icon BUILTIN="button_cancel"/>
<node CREATED="1711486798598" ID="ID_1504667047" MODIFIED="1711488886985" TEXT="d.h. wieder der shared-ptr-Trick"/>
<node CREATED="1711486786808" ID="ID_1943118433" MODIFIED="1711486796658" TEXT="das ist bei der Map-aus-string-spect genauso"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711491153943" ID="ID_561443056" MODIFIED="1711491282329" TEXT="noch besser: Ergebnistyp dynamisieren">
<icon BUILTIN="forward"/>
<node CREATED="1711491167092" ID="ID_679038844" MODIFIED="1711491179598" TEXT="dem Iterations-Mechanismus ist dieser Typ n&#xe4;mlich schei&#xdf;egal"/>
<node CREATED="1711491180498" ID="ID_1200622160" MODIFIED="1711491194500" TEXT="und da die InstanceCore ohnehin geTemplated ist...."/>
<node CREATED="1711491217221" ID="ID_1271938499" MODIFIED="1711491269346" TEXT="zudem ist GenNode explizit keine String-Datenstruktur (sondern bin&#xe4;r)"/>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711475137705" ID="ID_265880025" MODIFIED="1711475154240" TEXT="Implementierung der Repr&#xe4;sentation">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1711491795547" ID="ID_1481897171" MODIFIED="1711491809910" TEXT="Einstiegspunkt f&#xfc;r einen Scope ist stets eine GenNode">
<node CREATED="1711491812270" ID="ID_234227882" MODIFIED="1711491820513" TEXT="man k&#xf6;nnte das auch genau anders herum handhaben"/>
<node CREATED="1711491821460" ID="ID_1916429769" MODIFIED="1711491899861" TEXT="aber dann h&#xe4;tten wir ein Problem mit Zugriffen auf Nodes die kein Record sind"/>
<node CREATED="1711491921789" ID="ID_714056549" MODIFIED="1711491940208" TEXT="GenNode als Einstiegspunkt dagegen stellt keine Einschr&#xe4;nkung dar">
<node CREATED="1711491941836" ID="ID_194254261" MODIFIED="1711491952929" TEXT="denn sollte man doch einmal einen Record haben,"/>
<node CREATED="1711491953690" ID="ID_477686075" MODIFIED="1711491964956" TEXT="dann l&#xe4;&#xdf;t sich leicht eine Ref-GenNode bauen"/>
</node>
</node>
<node CREATED="1711492643022" ID="ID_149060446" MODIFIED="1711492665647" TEXT="als Abk&#xfc;rzung / Cache wird ein sekund&#xe4;rer Rec-Pointer mitgef&#xfc;hrt">
<node CREATED="1711492667078" ID="ID_502425157" MODIFIED="1711492672470" TEXT="dieser kann NULL sein"/>
<node CREATED="1711492673202" ID="ID_1566411442" MODIFIED="1711492715043" TEXT="&#x27f9; dann ist klar da&#xdf; das Target value-GenNode ist"/>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1711492744185" ID="ID_1414659694" MODIFIED="1711493061959" TEXT="zudem brauchen wir einen parent-Scope">
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1711493190221" ID="ID_1049043334" MODIFIED="1711493218882" TEXT="hier wird die Sache brandgef&#xe4;hrlich">
<icon BUILTIN="clanbomber"/>
<node CREATED="1711493248149" ID="ID_1396313935" MODIFIED="1711493305705" TEXT="denn die ETD schlie&#xdf;t das per Design explizit aus">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Das ist gradezu die Grundannahme: der Verarbeiter hat die Struktur zu kennen &#8212; die Node hat <i>keine introspektiven F&#228;higkeiten</i>
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1711493338536" ID="ID_1143325593" MODIFIED="1711493361420" TEXT="w&#xe4;re aber m&#xf6;glich &#x2014; so wie der Zugriff aktuell implementiert ist">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1711493364914" ID="ID_1017484098" MODIFIED="1711493380944" TEXT="sinnvollerweise m&#xfc;&#xdf;te man das als Teil des Konzepts betrachten"/>
</node>
</node>
</node>
</node>
<node CREATED="1710804591691" ID="ID_1815976275" MODIFIED="1710804603973" TEXT="Key-Zugriff wird &#xfc;bersetzt in Attribut-Zugriff">
<node CREATED="1711469498958" ID="ID_106772989" MODIFIED="1711469520804" TEXT="kann kaskadieren in einen parent-Scope"/>
<node CREATED="1711469521509" ID="ID_680558791" MODIFIED="1711469543766" TEXT="daf&#xfc;r wird ein optionaler Rec&lt;GenNode&gt;* verwendet"/>
</node>
<node CREATED="1710804616944" ID="ID_538897899" MODIFIED="1710804626706" TEXT="Iteration wird &#xfc;bersetzt in Scope-Iteration">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1711469668314" ID="ID_1640263666" MODIFIED="1711469688642" TEXT="hier ist eine zus&#xe4;tzliche Binding-Konvention notwendig">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1711469692623" ID="ID_210919622" MODIFIED="1711469701114" TEXT="der der Scope ist ein vector&lt;GenNode&gt;"/>
<node CREATED="1711469701958" ID="ID_1217697238" MODIFIED="1711469731982" TEXT="und nicht eine Liste von &#xbb;Objekten&#xab; &#x2259; Rec&lt;GenNode&gt;"/>
<node CREATED="1711469737057" ID="ID_1561127899" MODIFIED="1711469838206" TEXT="notwendig nur aus Konsistenz-Gr&#xfc;nden">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...denn in der Praxis wird erwartet, da&#223; im Scope sehr wohl wieder verschachtelte Records liegen; sonst w&#252;rde diese Datenstruktur ja wenig Sinn machen
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
</node>
<node CREATED="1711469895229" ID="ID_1582744279" MODIFIED="1711469917481">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
&#10233; wenn Kind <i>kein Record</i>&#160;ist
</p>
</body>
</html>
</richcontent>
<node CREATED="1711469919922" ID="ID_1678329722" MODIFIED="1711469936011" TEXT="dann m&#xfc;ssen wir einen pseudo-Scope synthetisieren"/>
<node CREATED="1711469936951" ID="ID_1819512723" MODIFIED="1711469968399" TEXT="dieser enth&#xe4;lt nur ein virtuelles Attribut &quot;value&quot;"/>
</node>
<node CREATED="1711469979505" ID="ID_1900618698" MODIFIED="1711470039575" TEXT="&#x27f9; sonst: verschachteltes Binding">
<arrowlink COLOR="#4d81bd" DESTINATION="ID_1119504137" ENDARROW="Default" ENDINCLINATION="5;-35;" ID="Arrow_ID_279787572" STARTARROW="None" STARTINCLINATION="-46;4;"/>
</node>
<node CREATED="1711491341932" ID="ID_224092406" MODIFIED="1711491362644" TEXT="all dies soll komplett dynamisch (demand-driven) gehandhabt werden">
<icon BUILTIN="yes"/>
<node CREATED="1711491377592" ID="ID_1223395543" MODIFIED="1711491418403">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
es gibt ein Pr&#228;dikat <font face="Monospaced" color="#1729bd">genNode.isNested()</font>
</p>
</body>
</html>
</richcontent>
</node>
</node>
</node>
<node CREATED="1710804633837" ID="ID_1119504137" MODIFIED="1711470052179" TEXT="normalerweise ist Element im Scope wieder ein Rec&lt;GenNode&gt;">
<linktarget COLOR="#4d81bd" DESTINATION="ID_1119504137" ENDARROW="Default" ENDINCLINATION="5;-35;" ID="Arrow_ID_279787572" SOURCE="ID_1900618698" STARTARROW="None" STARTINCLINATION="-46;4;"/>
</node>
<node CREATED="1710804715954" ID="ID_1537394187" MODIFIED="1711470077889" TEXT="verschachtelte Scopes k&#xf6;nnen aber leer sein (wegen Parent-Delegation)"/>
</node>
</node>
</node>
@ -121239,9 +121410,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<linktarget COLOR="#65354c" DESTINATION="ID_135618716" ENDARROW="Default" ENDINCLINATION="21;-62;" ID="Arrow_ID_696408734" SOURCE="ID_1103669600" STARTARROW="None" STARTINCLINATION="-2;93;"/>
<node CREATED="1711405899493" ID="ID_423341464" MODIFIED="1711406049382" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<table http-equiv="content-type" content="text/html; charset=utf-8" class="t-sdsc-begin">
<tr class="t-sdsc">
@ -121266,9 +121435,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
<node CREATED="1711406206524" ID="ID_1416799059" MODIFIED="1711406241333">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
Automatic Deduction setzt ctor im <b>prim&#228;ren</b>&#160; Template vorraus
@ -121279,9 +121446,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1711406253820" ID="ID_985724957" MODIFIED="1711406261329" TEXT="+ diverse partielle Spezialisierungen"/>
<node BACKGROUND_COLOR="#d6b67b" COLOR="#a50125" CREATED="1711406265488" ID="ID_24293979" MODIFIED="1711406390599">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
&#10233; dann findet der Compiler ohne Hilfe <b>keinen Construktor</b>
@ -121289,9 +121454,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
bzw. er findet nur den Copy-Konstruktur