Skip to content

Commit

Permalink
Added initial template benchmark
Browse files Browse the repository at this point in the history
Added for loop syntax
  • Loading branch information
rep-movsd committed Aug 22, 2017
1 parent 5da9de5 commit b417a43
Show file tree
Hide file tree
Showing 8 changed files with 337 additions and 218 deletions.
8 changes: 5 additions & 3 deletions main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <iostream>
#include <type_traits>
#include <chrono>
#include "seephit.h"
using namespace std;

Expand All @@ -8,14 +9,15 @@ using namespace std;
int main()
{
constexpr auto parser =
#include "test/trunc.spt"
#include "test/loop.spt"

REPORT_ERRORS(parser);

spt::tree spt_tree(parser);
spt::template_dict dct;
spt::template_dict dct = spt_tree.get_default_dict();
spt_tree.root.render(cout, dct);
cerr << endl;

cout << endl;
}


37 changes: 37 additions & 0 deletions main_bench.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <iostream>
#include <type_traits>
#include <chrono>
#include "seephit.h"
using namespace std;



int main()
{
constexpr auto parser =
#include "test/large_template.spt"

REPORT_ERRORS(parser);

// Start timer and run it
auto tmStart = chrono::high_resolution_clock::now();

int k;
for(int i = 0; i < 1000; ++i)
{
spt::tree spt_tree(parser);
spt::template_dict dct = spt_tree.get_default_dict();
spt_tree.root.render(cout, dct);
k = dct.size();
}

auto tmElapsed = chrono::high_resolution_clock::now() - tmStart;
long long nano = chrono::duration_cast<std::chrono::nanoseconds>(tmElapsed).count();
double ms = nano/1000000.0F;
cerr << ms << " ms elapsed" << endl;
cerr << k << " unique template keys" << endl;

cerr << endl;
}


14 changes: 9 additions & 5 deletions parse_error_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ enum Messages
Error_Expecting_an_identifier,
Error_Unexpected_character_inside_tag_content,
Error_Expecting_a_tag_name_after_open_bracket,
Error_Expecting_open_quote_for_attribute_value,
Error_Empty_value_for_non_boolean_attribute,
Error_Duplicate_ID_on_tag,
Error_Expecting_a_value_for_attribute,
Expand All @@ -20,14 +19,15 @@ enum Messages
Error_Mismatched_Close_Tag,
Error_Missing_close_bracket_in_close_tag,
Error_Missing_close_brace_in_template,
Error_Unexpected_end_of_stream
Error_Unexpected_end_of_stream,
Error_Invalid_syntax_in_for_tag,
Error_Infinite_loop_in_for_tag
};

struct None;
struct Expecting_an_identifier {};
struct Unexpected_character_inside_tag_content {};
struct Expecting_a_tag_name_after_open_bracket {};
struct Expecting_open_quote_for_attribute_value {};
struct Empty_value_for_non_boolean_attribute {};
struct Duplicate_ID_on_tag {};
struct Expecting_a_value_for_attribute {};
Expand All @@ -40,14 +40,15 @@ struct Mismatched_Close_Tag {};
struct Missing_close_bracket_in_close_tag {};
struct Missing_close_brace_in_template {};
struct Unexpected_end_of_stream {};
struct Invalid_syntax_in_for_tag {};
struct Infinite_loop_in_for_tag {};

template<Messages m> struct MsgToType{};

template<> struct MsgToType<Error_None>{using type = None;};
template<> struct MsgToType<Error_Expecting_an_identifier>{using type = Expecting_an_identifier;};
template<> struct MsgToType<Error_Unexpected_character_inside_tag_content>{using type = Unexpected_character_inside_tag_content;};
template<> struct MsgToType<Error_Expecting_a_tag_name_after_open_bracket>{using type = Expecting_a_tag_name_after_open_bracket;};
template<> struct MsgToType<Error_Expecting_open_quote_for_attribute_value>{using type = Expecting_open_quote_for_attribute_value;};
template<> struct MsgToType<Error_Empty_value_for_non_boolean_attribute>{using type = Empty_value_for_non_boolean_attribute;};
template<> struct MsgToType<Error_Duplicate_ID_on_tag>{using type = Duplicate_ID_on_tag;};
template<> struct MsgToType<Error_Expecting_a_value_for_attribute>{using type = Expecting_a_value_for_attribute;};
Expand All @@ -60,6 +61,8 @@ template<> struct MsgToType<Error_Mismatched_Close_Tag>{using type = Mismatched_
template<> struct MsgToType<Error_Missing_close_bracket_in_close_tag>{using type = Missing_close_bracket_in_close_tag;};
template<> struct MsgToType<Error_Missing_close_brace_in_template>{using type = Missing_close_brace_in_template;};
template<> struct MsgToType<Error_Unexpected_end_of_stream>{using type = Unexpected_end_of_stream;};
template<> struct MsgToType<Error_Invalid_syntax_in_for_tag>{using type = Invalid_syntax_in_for_tag;};
template<> struct MsgToType<Error_Infinite_loop_in_for_tag>{using type = Infinite_loop_in_for_tag;};

#ifndef SPT_DEBUG

Expand All @@ -70,7 +73,6 @@ if((x) < n) \
spt::IF<w.m == spt::Error_Expecting_an_identifier, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
spt::IF<w.m == spt::Error_Unexpected_character_inside_tag_content, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
spt::IF<w.m == spt::Error_Expecting_a_tag_name_after_open_bracket, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
spt::IF<w.m == spt::Error_Expecting_open_quote_for_attribute_value, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
spt::IF<w.m == spt::Error_Empty_value_for_non_boolean_attribute, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
spt::IF<w.m == spt::Error_Duplicate_ID_on_tag, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
spt::IF<w.m == spt::Error_Expecting_a_value_for_attribute, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
Expand All @@ -83,6 +85,8 @@ if((x) < n) \
spt::IF<w.m == spt::Error_Missing_close_bracket_in_close_tag, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
spt::IF<w.m == spt::Error_Missing_close_brace_in_template, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
spt::IF<w.m == spt::Error_Unexpected_end_of_stream, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
spt::IF<w.m == spt::Error_Invalid_syntax_in_for_tag, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
spt::IF<w.m == spt::Error_Infinite_loop_in_for_tag, spt::Warning<w.row, w.col, spt::MsgToType<w.m>::type>> (); \
}

#define REPORT_ERRORS(parser) \
Expand Down
4 changes: 3 additions & 1 deletion scripts/generate_parse_error_code.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ const errs = [
'Expecting_an_identifier',
'Unexpected_character_inside_tag_content',
'Expecting_a_tag_name_after_open_bracket',
'Expecting_open_quote_for_attribute_value',
'Empty_value_for_non_boolean_attribute',
'Duplicate_ID_on_tag',
'Expecting_a_value_for_attribute',
Expand All @@ -15,6 +14,9 @@ const errs = [
'Missing_close_bracket_in_close_tag',
'Missing_close_brace_in_template',
'Unexpected_end_of_stream',

'Invalid_syntax_in_for_tag',
'Infinite_loop_in_for_tag',
];

function makeEnums(e) {return 'Error_' + e;}
Expand Down
74 changes: 60 additions & 14 deletions seephit.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ constexpr const char_view g_symID{"id"};
constexpr const char_view g_symStyle{"style"};
constexpr const char_view g_symPre{"pre"};

// Control structures
constexpr const char_view g_symFor{"for"};

// These two tags are used internally to handle bare text and attributes
constexpr const char_view g_symText{"@text"};
constexpr const char_view g_symAttr{"@attr"};
Expand Down Expand Up @@ -151,8 +154,8 @@ struct parser
while(*pszText && *pszText <= 32) { ++pszText; }
}

// Consumes [a-z]+
template<typename F> constexpr const char_view eat_alpha(F isX)
// Consumes characters matched by isX
template<typename F> constexpr const char_view eat_only(F isX)
{
// Ensure not EOS
check_eos();
Expand Down Expand Up @@ -270,21 +273,29 @@ struct parser
if(is_alpha(*pszText))
{
// Get the attr name
const char_view &name = eat_alpha(is_attr);
const char_view &name = eat_only(is_attr);

bool bHasEqual = eat_str("=");

if(bHasEqual)
{
char_view value;
// Check what delimiter is used " or '
char chDelim = pszText[0];
if(chDelim != '"' && chDelim != '\'')
if(chDelim == '"' || chDelim == '\'')
{
PARSE_ERR(Error_Expecting_open_quote_for_attribute_value);
// Eat the open delim
++pszText;
value = eat_until(chDelim, nullptr);

// Eat the close delim
pszText++;
}
++pszText;

char_view value = eat_until(chDelim, nullptr);
else // no delimiter, stop at space
{
value = eat_only(is_attrval);
eat_space();
}

if(value.empty())
{
Expand All @@ -293,9 +304,6 @@ struct parser

check_eos();
ON_ERR_RETURN false;

// Eat the close delim
pszText++;


// Swallow any space
Expand All @@ -320,7 +328,7 @@ struct parser
else
{
attrs.push_back(attr(name, value));
//DUMP << "Parsed attr " << name << "=" << value << ENDL;
DUMP << "Parsed attr " << name << "=" << value << ENDL;
}

}
Expand All @@ -341,6 +349,27 @@ struct parser
return false;
}

// verifies a for tag
// <for var=N to=N [inc=N]> ...
constexpr void check_for_tag(node_attrs &attrs)
{
// The three atrributes have to be in order (inc is optional)
int nAttr = attrs.size();
if(nAttr < 2 || attrs[1].name != "to" || (nAttr == 3 && attrs[2].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;
if((iBeg > iEnd && iInc >= 0) || (iBeg < iEnd && iInc <= 0) || iBeg == iEnd)
{
PARSE_ERR(Error_Infinite_loop_in_for_tag);
}
}

// Parse "<TAG>", ignores leading whitespace
// https://www.w3.org/TR/REC-xml/#sec-starttags
// No space allowed between < and tag name
Expand All @@ -360,7 +389,7 @@ struct parser

// Try to parse an [a-z0-9]+ as a tag -
// is_open_tag would have already ensure first char is [a-z]
char_view sym = eat_alpha(is_alnum);
char_view sym = eat_only(is_alnum);

DUMP << "Parsed open tag: " << sym << ENDL;

Expand All @@ -386,6 +415,12 @@ struct parser
while(parse_attrs(attrs));
ON_ERR_RETURN false;

// Check if its a for node and verify
if(node.tag == g_symFor)
{
check_for_tag(attrs);
}

// Check if void tag
const int nVoidTags = sizeof(arrVoidTags)/sizeof(arrVoidTags[0]);
bool bIsVoidTag = find_arr(arrVoidTags, nVoidTags, node.tag.m_pBeg) != -1;
Expand Down Expand Up @@ -427,7 +462,7 @@ struct parser
}

// Try to parse the tag name
char_view sym = eat_alpha(is_alnum);
char_view sym = eat_only(is_alnum);
if(sym != symExpected)
{
DUMP << "Expected '" << symExpected << "' got '" << sym << "'" << ENDL;
Expand Down Expand Up @@ -773,6 +808,17 @@ struct tree
build(parser, root, templates, 0);
}

// Test function that returns a map of all the keys with value == key
template_dict get_default_dict()
{
template_dict ret;
for(const auto &i: templates)
{
ret[i.first] = i.first;
}
return ret;
}

// Recursively builds the runtime tree structure from the compile time parser
// Detects strings of the form {{key}} inside node content and adds it to a template_dict
static void build(const parser &parser, rnode &parent, template_dict &dctTemplates, int index)
Expand Down
Loading

0 comments on commit b417a43

Please sign in to comment.