From e7c399c8d48342a51cdea4d81bda4032b0cdf543 Mon Sep 17 00:00:00 2001 From: Vivek N Date: Wed, 22 Nov 2017 17:25:12 +0530 Subject: [PATCH] issue #27: Implemented and tested for and if tags --- main.cpp | 2 +- seephit.h | 76 +++++++++++++++++++++++++------- tags.hpp | 4 +- test/if.spt.expected | 0 test/large_template.spt.expected | 0 test/loop.spt | 12 ++--- test/loop.spt.expected | 0 test/multi.spt | 10 +++++ test/multi.spt.expected | 0 util.h | 2 +- 10 files changed, 81 insertions(+), 25 deletions(-) create mode 100644 test/if.spt.expected create mode 100644 test/large_template.spt.expected create mode 100644 test/loop.spt.expected create mode 100644 test/multi.spt create mode 100644 test/multi.spt.expected diff --git a/main.cpp b/main.cpp index 384bd26..e109bc6 100644 --- a/main.cpp +++ b/main.cpp @@ -9,7 +9,7 @@ using namespace std; int main() { constexpr auto parser = - #include "test/if.spt" + #include "test/loop.spt" REPORT_ERRORS(parser); diff --git a/seephit.h b/seephit.h index 2420727..b6edd31 100644 --- a/seephit.h +++ b/seephit.h @@ -358,20 +358,23 @@ struct parser } // verifies a for tag - // ... + // ... constexpr void check_for_tag(node_attrs &attrs) { - // The three atrributes have to be in order (inc is optional) + // Check that we have var, from, and to atrributes (inc is optional) int nAttr = attrs.size(); - if(nAttr < 2 || attrs[1].name != "to" || (nAttr == 3 && attrs[2].name != "inc")) + bool bValid = attrs[0].name == "var" && attrs[1].name == "from" && attrs[2].name == "to"; + + // Check also if the 4th attribute is "inc" if it exists + if(!bValid || (nAttr > 3 && attrs[3].name != "inc")) { PARSE_ERR(Error_Invalid_syntax_in_for_tag); } // Verify that the for loop params are sane - int iBeg = attrs[0].value.toInt(); - int iEnd = attrs[1].value.toInt(); - int iInc = nAttr == 3 ? attrs[2].value.toInt() : 1; + int iBeg = attrs[1].value.toInt(); + int iEnd = attrs[2].value.toInt(); + int iInc = nAttr == 4 ? attrs[3].value.toInt() : 1; if((iBeg > iEnd && iInc >= 0) || (iBeg < iEnd && iInc <= 0) || iBeg == iEnd) { PARSE_ERR(Error_Infinite_loop_in_for_tag); @@ -692,7 +695,7 @@ class rnode bool m_bVoidNode {}; // Render the children of this node recursively - void render_children(ostream &ostr, const template_dict &dctTemplates, int indent) const + void render_children(ostream &ostr, template_dict &dctTemplates, int indent) const { for(const auto& child: m_arrChildren) { @@ -700,6 +703,46 @@ class rnode } } + // Render the children in a for tag + void render_for(ostream &ostr, template_dict &dctTemplates, int indent) const + { + // Get the for loop params + auto iStart = std::stoi(m_dctAttrs.at("from")); + auto iStop = std::stoi(m_dctAttrs.at("to")); + auto iInc = m_dctAttrs.count("inc") ? std::stoi(m_dctAttrs.at("inc")) : 1; + string sVar = m_dctAttrs.at("var"); + + // Save the existing variable if any (allows nested loops with same var) + bool bUsed = dctTemplates.count(sVar); + string sSaved = bUsed ? dctTemplates.at(sVar) : ""; + + // Loop and render + for(int i = iStart; iInc > 0 ? i < iStop : i > iStop; i += iInc) + { + dctTemplates[sVar] = std::to_string(i); + render_children(ostr, dctTemplates, indent); + } + + // Restore the loop var in the template dictionary or delete it if it didnt exits before + if(bUsed) + { + dctTemplates[sVar] = sSaved; + } + else + { + dctTemplates.erase(sVar); + } + } + + // Render an if tag + void render_if(ostream &ostr, template_dict &dctTemplates, int indent) const + { + if(std::stoi(m_dctAttrs.at("cond"))) + { + render_children(ostr, dctTemplates, indent); + } + } + public: rnode() = default; @@ -755,7 +798,7 @@ class rnode while(itCurr != text.end()); } - void render(ostream &ostr, const template_dict &dctTemplates, int indent = 0) const + void render(ostream &ostr, template_dict &dctTemplates, int indent = 0) const { string sIndent(indent * 2, ' '); string sTag{m_symTag.m_pBeg, m_symTag.m_pEnd}; @@ -797,26 +840,25 @@ class rnode // If tag has children add a newline if(!m_arrChildren.empty()) { - ostr << "\n"; + ostr << '\n'; // Render children if any render_children(ostr, dctTemplates, indent + 1); } } - else + else // control tags, do not indent { + // Render children conditionally for if if(m_symTag == g_symIf) { - bool bCond = std::stoi(m_dctAttrs.at("cond")); - if(bCond) - { - // Render children if any, don't indent for control tags - render_children(ostr, dctTemplates, indent); - } + render_if(ostr, dctTemplates, indent); + } + else if(m_symTag == g_symFor) + { + render_for(ostr, dctTemplates, indent); } else { - // Render children if any, don't indent for control tags render_children(ostr, dctTemplates, indent); } } diff --git a/tags.hpp b/tags.hpp index ea08c9f..927d6cd 100644 --- a/tags.hpp +++ b/tags.hpp @@ -182,8 +182,10 @@ constexpr const char *g_arrTags[] = constexpr const char *g_arrCtrlTags[] = { - // runtime loop + // runtime loop // inc is optional, defaults to 1 + // Interval is half open like in a for loop + // when var == to loop ends "for", // runtime if
Stuff rendered if cond is non-zero
diff --git a/test/if.spt.expected b/test/if.spt.expected new file mode 100644 index 0000000..e69de29 diff --git a/test/large_template.spt.expected b/test/large_template.spt.expected new file mode 100644 index 0000000..e69de29 diff --git a/test/loop.spt b/test/loop.spt index 83fcb92..a0169af 100644 --- a/test/loop.spt +++ b/test/loop.spt @@ -1,7 +1,9 @@ R"*( - -
- item{{n}} -
+ + +
+ item{{m}}{{n}} +
+
-)*"_html; \ No newline at end of file +)*"_html; diff --git a/test/loop.spt.expected b/test/loop.spt.expected new file mode 100644 index 0000000..e69de29 diff --git a/test/multi.spt b/test/multi.spt new file mode 100644 index 0000000..99e4193 --- /dev/null +++ b/test/multi.spt @@ -0,0 +1,10 @@ +R"*( +
+ item +
+ +
+ item2 +
+ +)*"_html; \ No newline at end of file diff --git a/test/multi.spt.expected b/test/multi.spt.expected new file mode 100644 index 0000000..e69de29 diff --git a/util.h b/util.h index e84fc35..18521bc 100644 --- a/util.h +++ b/util.h @@ -249,7 +249,7 @@ struct char_view } // Return with sign - return bNeg ? ret : -ret; + return bNeg ? -ret : ret; } };