From 8d432a6e0bfbc4047d94387cf6fa1e93283ba891 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 24 Mar 2024 23:05:16 +0100 Subject: [PATCH] Library: connect both parts of the engine ...gets the hello-world test to run --- src/lib/iter-index.hpp | 11 +++++++---- src/lib/text-template.hpp | 27 ++++++++++++++++++++++----- tests/library/text-template-test.cpp | 27 +++++++++++---------------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/lib/iter-index.hpp b/src/lib/iter-index.hpp index 388f6829f..6e496e84a 100644 --- a/src/lib/iter-index.hpp +++ b/src/lib/iter-index.hpp @@ -45,9 +45,12 @@ namespace lib { - - namespace {// Implementation of the access core + namespace iter { + /** + * Implementation of a »IterStateCore« + * to access the container through an embedded index variable. + */ template struct IndexAccessCore { @@ -116,9 +119,9 @@ namespace lib { */ template class IterIndex - : public IndexAccessCore::IterWrapper + : public iter::IndexAccessCore::IterWrapper { - using _Cor = IndexAccessCore; + using _Cor = iter::IndexAccessCore; using _Par = typename _Cor::IterWrapper; public: diff --git a/src/lib/text-template.hpp b/src/lib/text-template.hpp index f2ffc22bf..bfdc40ca2 100644 --- a/src/lib/text-template.hpp +++ b/src/lib/text-template.hpp @@ -286,8 +286,11 @@ namespace lib { template using InstanceIter = ExploreIter>>; + ActionSeq actions_; + public: TextTemplate(string spec) + : actions_{compile (spec)} { } template @@ -298,6 +301,7 @@ namespace lib { static string apply (string spec, DAT const& data); + static ActionSeq compile (string const&); friend class test::TextTemplate_test; }; @@ -461,6 +465,15 @@ namespace lib { } // add final action to supply text after last active tag }; + inline TextTemplate::ActionSeq + TextTemplate::compile (string const& spec) + { + ActionSeq code = ActionCompiler().buildActions (parse (spec)); + if (isnil (code)) + throw error::Invalid ("TextTemplate spec without active placeholders."); + return code; + } + @@ -479,7 +492,7 @@ namespace lib { template<> struct TextTemplate::DataSource { - MapS* data_; + MapS const * data_; using Iter = std::string_view; bool @@ -491,7 +504,9 @@ namespace lib { string const& retrieveContent (string key) { - return (*data_)[key]; + auto elm = data_->find (key); + ENSURE (elm != data_->end()); + return elm->second; } }; @@ -533,7 +548,7 @@ namespace lib { template TextTemplate::InstanceCore::InstanceCore (TextTemplate::ActionSeq const& actions, SRC s) : dataSrc_{s} - , actionIter_{explore (actions)} + , actionIter_{actions} , ctxStack_{} , rendered_{} { @@ -587,12 +602,14 @@ namespace lib { - /** */ + /** + * Instantiate this (pre-compiled) TextTemplate using the given data binding. + */ template inline TextTemplate::InstanceIter TextTemplate::render (DAT const& data) const { - UNIMPLEMENTED ("actually instantiate the text template"); + return explore (InstanceCore{actions_, DataSource{&data}}); } /** */ diff --git a/tests/library/text-template-test.cpp b/tests/library/text-template-test.cpp index 0de2f8600..3078e0732 100644 --- a/tests/library/text-template-test.cpp +++ b/tests/library/text-template-test.cpp @@ -67,7 +67,7 @@ namespace test { virtual void run (Arg) { -// simpeUsage(); + simpeUsage(); verify_parsing(); verify_instantiation(); verify_keySubstituton(); @@ -79,8 +79,8 @@ namespace test { } - /** @test TODO simple point-and-shot usage... - * @todo WIP 4/24 ✔ define ⟶ 🔁 implement + /** @test simple point-and-shot usage... + * @todo WIP 4/24 ✔ define ⟶ ✔ implement */ void simpeUsage() @@ -92,7 +92,7 @@ namespace test { } - /** @test TODO + /** @test parsing of tag markup and compilation into a sequence of Action-codes * @note the regular expression \ref ACCEPT_FIELD is comprised of several * alternatives and optional parts, which are marked by 5 sub-expressions * - 1 ≙ an escaped field (which should not be processed) @@ -100,7 +100,7 @@ namespace test { * - 3 ≙ end token * - 4 ≙ some logic token ("if" or "for") * - 5 ≙ a key or key path - * @todo WIP 4/24 🔁 define ⟶ implement + * @todo WIP 4/24 ✔ define ⟶ ✔ implement */ void verify_parsing() @@ -118,7 +118,7 @@ namespace test { CHECK (mat.length() == 7); CHECK (mat.prefix() == " stale"_expect); CHECK (mat.suffix() == "forever"_expect); - CHECK (mat[0] == "${beer}"_expect); // so this first example demonstrates placeholder recognition + CHECK (mat[0] == "${beer}"_expect); // so this first example demonstrates placeholder recognition CHECK (not mat[1].matched); // Sub-1 : this is not an escaped pattern CHECK (not mat[2].matched); // Sub-2 : this pattern does not start with "else" CHECK (not mat[3].matched); // Sub-3 : no "end" keyword @@ -177,7 +177,7 @@ namespace test { CHECK (mat.position() == 24); CHECK (mat.length() == 2); CHECK (mat.prefix() == " catch ${else if} fever "_expect); // Note: first pattern does not match as "else" must be solitary - CHECK (mat.suffix() == "{can.beer} "_expect); // Note: the following braced expression is tossed aside + CHECK (mat.suffix() == "{can.beer} "_expect); // Note: the following braced expression is tossed aside CHECK (mat[0] == "\\$"_expect); // Only the escaped pattern mark opening is picked up CHECK (not mat[2].matched); CHECK (not mat[3].matched); @@ -186,6 +186,7 @@ namespace test { CHECK (mat[1] == "\\$"_expect); // Sub-1 picks the escaped mark (and the remainder is no complete tag) + // Demonstration: can use this regular expression in a matching pipeline.... input = "one ${two} three \\${four} ${if high} five"; CHECK (util::join( @@ -196,7 +197,7 @@ namespace test { // Parse matches of this regexp into well defined syntax elements - auto parser = parse(input); + auto parser = parse (input); CHECK (not isnil(parser)); CHECK (parser->syntax == TagSyntax::KEYID); CHECK (parser->lead == "one "_expect); @@ -217,13 +218,8 @@ namespace test { 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; }; - auto act1 = TextTemplate::ActionCompiler().buildActions(parse(input)); -SHOW_EXPR(util::join(explore(act1) - .transform(render) - , "▶")) input = R"~( Prefix-1 ${some.key} next one is \${escaped} Prefix-2 ${if cond1} active ${else} inactive ${end if @@ -234,8 +230,7 @@ SHOW_EXPR(util::join(explore(act1) if nested}loop-suffix${else}${end for} tail... )~"; - auto actions = TextTemplate::ActionCompiler().buildActions(parse(input)); -SHOW_EXPR(util::join (explore(actions).transform(render),"▶\n▶")) + auto actions = TextTemplate::compile (input); CHECK (25 == actions.size()); CHECK (actions[ 0].code == TextTemplate::Code::TEXT);