From dd65af44576784cda00dfe860fbd1e3b84957a17 Mon Sep 17 00:00:00 2001 From: pantor Date: Sun, 20 Aug 2017 13:15:57 +0200 Subject: [PATCH] crop image, more enum classes --- doc/logo.jpg | Bin 22147 -> 20743 bytes src/inja.hpp | 314 +++++++++++++++++++------------- test/src/unit-parser.cpp | 4 +- test/src/unit-renderer.cpp | 3 +- test/src/unit-string-helper.cpp | 4 +- 5 files changed, 189 insertions(+), 136 deletions(-) diff --git a/doc/logo.jpg b/doc/logo.jpg index c7aa137b7cd468f6204ee6974c4afb1b162b37a4..4181d4dd25a4cd8c572a8ad7ca72b399b9f0f5ad 100644 GIT binary patch delta 17552 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 diff --git a/src/inja.hpp b/src/inja.hpp index 4dc911f..66b3b11 100644 --- a/src/inja.hpp +++ b/src/inja.hpp @@ -111,7 +111,7 @@ inline Match search(const std::string& input, std::vector regexes, size_t } } - int number_regex = 0, number_inner = 1; + int number_regex = -1, number_inner = 1; for (int i = 1; i < search_match.size(); i++) { if (search_match.length(i) > 0) { number_inner = i; @@ -122,11 +122,11 @@ inline Match search(const std::string& input, std::vector regexes, size_t search_match.setGroupOffset(number_inner); search_match.setRegexNumber(number_regex); - search_match.setRegex(regexes[number_regex]); + if (number_regex >= 0) { search_match.setRegex(regexes[number_regex]); } return search_match; } -inline MatchClosed search_closed_match_on_level(const std::string& input, Regex regex_statement, Regex regex_level_up, Regex regex_level_down, Regex regex_search, Match open_match) { +inline MatchClosed search_closed_on_level(const std::string& input, Regex regex_statement, Regex regex_level_up, Regex regex_level_down, Regex regex_search, Match open_match) { int level = 0; size_t current_position = open_match.end_position(); @@ -145,8 +145,21 @@ inline MatchClosed search_closed_match_on_level(const std::string& input, Regex return MatchClosed(open_match, match_delimiter); } -inline MatchClosed search_closed_match(std::string input, Regex regex_statement, Regex regex_open, Regex regex_close, Match open_match) { - return search_closed_match_on_level(input, regex_statement, regex_open, regex_close, regex_close, open_match); +inline MatchClosed search_closed(std::string input, Regex regex_statement, Regex regex_open, Regex regex_close, Match open_match) { + return search_closed_on_level(input, regex_statement, regex_open, regex_close, regex_close, open_match); +} + +inline Match match(std::string input, std::vector regexes) { + Match match; + match.setRegexNumber(-1); + for (int i = 0; i < regexes.size(); i++) { + if (std::regex_match(input, match, regexes[i])) { + match.setRegexNumber(i); + match.setRegex(regexes[i]); + break; + } + } + return match; } @@ -176,32 +189,66 @@ public: {Delimiter::Comment, Regex{"\\{#\\s*(.*?)\\s*#\\}"}} }; - const Regex regex_loop_open{"for (.*)"}; + enum class Statement { + Loop, + Condition, + Include + }; + + const std::map regex_map_statement_openers = { + {Statement::Loop, Regex{"for (.*)"}}, + {Statement::Condition, Regex{"if (.*)"}}, + {Statement::Include, Regex{"include \"(.*)\""}} + }; + + const Regex regex_loop_open = regex_map_statement_openers.at(Statement::Loop); const Regex regex_loop_in_list{"for (\\w+) in (.+)"}; const Regex regex_loop_close{"endfor"}; - const Regex regex_include{"include \"(.*)\""}; - - const Regex regex_condition_open{"if (.*)"}; + const Regex regex_condition_open = regex_map_statement_openers.at(Statement::Condition); const Regex regex_condition_else_if{"else if (.*)"}; const Regex regex_condition_else{"else"}; const Regex regex_condition_close{"endif"}; - const Regex regex_condition_not{"not (.+)"}; - const Regex regex_condition_and{"(.+) and (.+)"}; - const Regex regex_condition_or{"(.+) or (.+)"}; - const Regex regex_condition_in{"(.+) in (.+)"}; - const Regex regex_condition_equal{"(.+) == (.+)"}; - const Regex regex_condition_greater{"(.+) > (.+)"}; - const Regex regex_condition_less{"(.+) < (.+)"}; - const Regex regex_condition_greater_equal{"(.+) >= (.+)"}; - const Regex regex_condition_less_equal{"(.+) <= (.+)"}; - const Regex regex_condition_different{"(.+) != (.+)"}; + enum class ConditionOperators { + Not, + And, + Or, + In, + Equal, + Greater, + Less, + GreaterEqual, + LessEqual, + Different + }; - const Regex regex_function_upper{"upper\\(\\s*(.*?)\\s*\\)"}; - const Regex regex_function_lower{"lower\\(\\s*(.*?)\\s*\\)"}; - const Regex regex_function_range{"range\\(\\s*(.*?)\\s*\\)"}; - const Regex regex_function_length{"length\\(\\s*(.*?)\\s*\\)"}; + const std::map regex_map_condition_operators = { + {ConditionOperators::Not, Regex{"not (.+)"}}, + {ConditionOperators::And, Regex{"(.+) and (.+)"}}, + {ConditionOperators::Or, Regex{"(.+) or (.+)"}}, + {ConditionOperators::In, Regex{"(.+) in (.+)"}}, + {ConditionOperators::Equal, Regex{"(.+) == (.+)"}}, + {ConditionOperators::Greater, Regex{"(.+) > (.+)"}}, + {ConditionOperators::Less, Regex{"(.+) < (.+)"}}, + {ConditionOperators::GreaterEqual, Regex{"(.+) >= (.+)"}}, + {ConditionOperators::LessEqual, Regex{"(.+) <= (.+)"}}, + {ConditionOperators::Different, Regex{"(.+) != (.+)"}} + }; + + enum class Function { + Upper, + Lower, + Range, + Length + }; + + const std::map regex_map_functions = { + {Function::Upper, Regex{"upper\\(\\s*(.*?)\\s*\\)"}}, + {Function::Lower, Regex{"lower\\(\\s*(.*?)\\s*\\)"}}, + {Function::Range, Regex{"range\\(\\s*(.*?)\\s*\\)"}}, + {Function::Length, Regex{"length\\(\\s*(.*?)\\s*\\)"}}, + }; Parser() { } @@ -229,48 +276,51 @@ public: case Delimiter::Statement: case Delimiter::LineStatement: { - Match inner_match_delimiter; - // Loop - if (std::regex_match(delimiter_inner, inner_match_delimiter, regex_loop_open)) { - MatchClosed loop_match = search_closed_match(input, match_delimiter.regex(), regex_loop_open, regex_loop_close, match_delimiter); + Match match_statement = match(delimiter_inner, get_values(regex_map_statement_openers)); + switch ( static_cast(match_statement.regex_number()) ) { + case Statement::Loop: { + MatchClosed loop_match = search_closed(input, match_delimiter.regex(), regex_loop_open, regex_loop_close, match_delimiter); - current_position = loop_match.end_position(); - std::string loop_command = inner_match_delimiter.str(0); - result += element(Type::Loop, {{"command", loop_command}, {"inner", loop_match.inner()}}); - } - // Include - else if (std::regex_match(delimiter_inner, inner_match_delimiter, regex_include)) { - std::string filename = inner_match_delimiter.str(1); - result += element(Type::Include, {{"filename", filename}}); - } - // Condition - else if (std::regex_match(delimiter_inner, inner_match_delimiter, regex_condition_open)) { - json condition_result = element(Parser::Type::Condition, {{"children", json::array()}}); - - Match condition_match = match_delimiter; - - MatchClosed else_if_match = search_closed_match_on_level(input, match_delimiter.regex(), regex_condition_open, regex_condition_close, regex_condition_else_if, condition_match); - while (else_if_match.found()) { - condition_match = else_if_match.close_match; - - condition_result["children"] += element(Type::ConditionBranch, {{"command", else_if_match.open_match.str(1)}, {"inner", else_if_match.inner()}}); - - else_if_match = search_closed_match_on_level(input, match_delimiter.regex(), regex_condition_open, regex_condition_close, regex_condition_else_if, condition_match); + current_position = loop_match.end_position(); + std::string loop_command = match_statement.str(0); + result += element(Type::Loop, {{"command", loop_command}, {"inner", loop_match.inner()}}); + break; } + case Statement::Condition: { + json condition_result = element(Parser::Type::Condition, {{"children", json::array()}}); - MatchClosed else_match = search_closed_match_on_level(input, match_delimiter.regex(), regex_condition_open, regex_condition_close, regex_condition_else, condition_match); - if (else_match.found()) { - condition_match = else_match.close_match; + Match condition_match = match_delimiter; - condition_result["children"] += element(Type::ConditionBranch, {{"command", else_match.open_match.str(1)}, {"inner", else_match.inner()}}); + MatchClosed else_if_match = search_closed_on_level(input, match_delimiter.regex(), regex_condition_open, regex_condition_close, regex_condition_else_if, condition_match); + while (else_if_match.found()) { + condition_match = else_if_match.close_match; + + condition_result["children"] += element(Type::ConditionBranch, {{"command", else_if_match.open_match.str(1)}, {"inner", else_if_match.inner()}}); + + else_if_match = search_closed_on_level(input, match_delimiter.regex(), regex_condition_open, regex_condition_close, regex_condition_else_if, condition_match); + } + + MatchClosed else_match = search_closed_on_level(input, match_delimiter.regex(), regex_condition_open, regex_condition_close, regex_condition_else, condition_match); + if (else_match.found()) { + condition_match = else_match.close_match; + + condition_result["children"] += element(Type::ConditionBranch, {{"command", else_match.open_match.str(1)}, {"inner", else_match.inner()}}); + } + + MatchClosed last_if_match = search_closed(input, match_delimiter.regex(), regex_condition_open, regex_condition_close, condition_match); + + condition_result["children"] += element(Type::ConditionBranch, {{"command", last_if_match.open_match.str(1)}, {"inner", last_if_match.inner()}}); + + current_position = last_if_match.end_position(); + result += condition_result; + break; } - - MatchClosed last_if_match = search_closed_match(input, match_delimiter.regex(), regex_condition_open, regex_condition_close, condition_match); - - condition_result["children"] += element(Type::ConditionBranch, {{"command", last_if_match.open_match.str(1)}, {"inner", last_if_match.inner()}}); - - current_position = last_if_match.end_position(); - result += condition_result; + case Statement::Include: { + std::string filename = match_statement.str(1); + result += element(Type::Include, {{"filename", filename}}); + break; + } + default: { throw std::runtime_error("Parser error: Unknown statement."); } } break; @@ -335,32 +385,34 @@ public: // Json Raw Data if ( json::accept(input) ) { return json::parse(input); } - Match match_function; - if (std::regex_match(input, match_function, parser.regex_function_upper)) { - json str = eval_variable(match_function.str(1), data); - if (not str.is_string()) { throw std::runtime_error("Argument in upper function is not a string."); } - std::string data = str.get(); - std::transform(data.begin(), data.end(), data.begin(), toupper); - return data; - } - else if (std::regex_match(input, match_function, parser.regex_function_lower)) { - json str = eval_variable(match_function.str(1), data); - if (not str.is_string()) { throw std::runtime_error("Argument in lower function is not a string."); } - std::string data = str.get(); - std::transform(data.begin(), data.end(), data.begin(), tolower); - return data; - } - else if (std::regex_match(input, match_function, parser.regex_function_range)) { - json number = eval_variable(match_function.str(1), data); - if (not number.is_number()) { throw std::runtime_error("Argument in range function is not a number."); } - std::vector result(number.get()); - std::iota(std::begin(result), std::end(result), 0); - return result; - } - else if (std::regex_match(input, match_function, parser.regex_function_length)) { - json list = eval_variable(match_function.str(1), data); - if (not list.is_array()) { throw std::runtime_error("Argument in length function is not a list."); } - return list.size(); + Match match_function = match(input, get_values(parser.regex_map_functions)); + switch ( static_cast(match_function.regex_number()) ) { + case Parser::Function::Upper: { + json str = eval_variable(match_function.str(1), data); + if (not str.is_string()) { throw std::runtime_error("Argument in upper function is not a string."); } + std::string data = str.get(); + std::transform(data.begin(), data.end(), data.begin(), toupper); + return data; + } + case Parser::Function::Lower: { + json str = eval_variable(match_function.str(1), data); + if (not str.is_string()) { throw std::runtime_error("Argument in lower function is not a string."); } + std::string data = str.get(); + std::transform(data.begin(), data.end(), data.begin(), tolower); + return data; + } + case Parser::Function::Range: { + json number = eval_variable(match_function.str(1), data); + if (not number.is_number()) { throw std::runtime_error("Argument in range function is not a number."); } + std::vector result(number.get()); + std::iota(std::begin(result), std::end(result), 0); + return result; + } + case Parser::Function::Length: { + json list = eval_variable(match_function.str(1), data); + if (not list.is_array()) { throw std::runtime_error("Argument in length function is not a list."); } + return list.size(); + } } if (input[0] != '/') { input.insert(0, "/"); } @@ -372,50 +424,52 @@ public: } bool eval_condition(std::string condition, json data) { - Match match_condition; - if (std::regex_match(condition, match_condition, parser.regex_condition_not)) { - return not eval_condition(match_condition.str(1), data); - } - else if (std::regex_match(condition, match_condition, parser.regex_condition_and)) { - return (eval_condition(match_condition.str(1), data) and eval_condition(match_condition.str(2), data)); - } - else if (std::regex_match(condition, match_condition, parser.regex_condition_or)) { - return (eval_condition(match_condition.str(1), data) or eval_condition(match_condition.str(2), data)); - } - else if (std::regex_match(condition, match_condition, parser.regex_condition_in)) { - json item = eval_variable(match_condition.str(1), data); - json list = eval_variable(match_condition.str(2), data); - return (std::find(list.begin(), list.end(), item) != list.end()); - } - else if (std::regex_match(condition, match_condition, parser.regex_condition_equal)) { - json comp1 = eval_variable(match_condition.str(1), data); - json comp2 = eval_variable(match_condition.str(2), data); - return comp1 == comp2; - } - else if (std::regex_match(condition, match_condition, parser.regex_condition_greater)) { - json comp1 = eval_variable(match_condition.str(1), data); - json comp2 = eval_variable(match_condition.str(2), data); - return comp1 > comp2; - } - else if (std::regex_match(condition, match_condition, parser.regex_condition_less)) { - json comp1 = eval_variable(match_condition.str(1), data); - json comp2 = eval_variable(match_condition.str(2), data); - return comp1 < comp2; - } - else if (std::regex_match(condition, match_condition, parser.regex_condition_greater_equal)) { - json comp1 = eval_variable(match_condition.str(1), data); - json comp2 = eval_variable(match_condition.str(2), data); - return comp1 >= comp2; - } - else if (std::regex_match(condition, match_condition, parser.regex_condition_less_equal)) { - json comp1 = eval_variable(match_condition.str(1), data); - json comp2 = eval_variable(match_condition.str(2), data); - return comp1 <= comp2; - } - else if (std::regex_match(condition, match_condition, parser.regex_condition_different)) { - json comp1 = eval_variable(match_condition.str(1), data); - json comp2 = eval_variable(match_condition.str(2), data); - return comp1 != comp2; + Match match_condition = match(condition, get_values(parser.regex_map_condition_operators)); + switch ( static_cast(match_condition.regex_number()) ) { + case Parser::ConditionOperators::Not: { + return not eval_condition(match_condition.str(1), data); + } + case Parser::ConditionOperators::And: { + return (eval_condition(match_condition.str(1), data) and eval_condition(match_condition.str(2), data)); + } + case Parser::ConditionOperators::Or: { + return (eval_condition(match_condition.str(1), data) or eval_condition(match_condition.str(2), data)); + } + case Parser::ConditionOperators::In: { + json item = eval_variable(match_condition.str(1), data); + json list = eval_variable(match_condition.str(2), data); + return (std::find(list.begin(), list.end(), item) != list.end()); + } + case Parser::ConditionOperators::Equal: { + json comp1 = eval_variable(match_condition.str(1), data); + json comp2 = eval_variable(match_condition.str(2), data); + return comp1 == comp2; + } + case Parser::ConditionOperators::Greater: { + json comp1 = eval_variable(match_condition.str(1), data); + json comp2 = eval_variable(match_condition.str(2), data); + return comp1 > comp2; + } + case Parser::ConditionOperators::Less: { + json comp1 = eval_variable(match_condition.str(1), data); + json comp2 = eval_variable(match_condition.str(2), data); + return comp1 < comp2; + } + case Parser::ConditionOperators::GreaterEqual: { + json comp1 = eval_variable(match_condition.str(1), data); + json comp2 = eval_variable(match_condition.str(2), data); + return comp1 >= comp2; + } + case Parser::ConditionOperators::LessEqual: { + json comp1 = eval_variable(match_condition.str(1), data); + json comp2 = eval_variable(match_condition.str(2), data); + return comp1 <= comp2; + } + case Parser::ConditionOperators::Different: { + json comp1 = eval_variable(match_condition.str(1), data); + json comp2 = eval_variable(match_condition.str(2), data); + return comp1 != comp2; + } } json var = eval_variable(condition, data, false); diff --git a/test/src/unit-parser.cpp b/test/src/unit-parser.cpp index 87911d6..5bb5b50 100644 --- a/test/src/unit-parser.cpp +++ b/test/src/unit-parser.cpp @@ -75,11 +75,11 @@ TEST_CASE("Parse structure") { } SECTION("Basic conditional") { - std::string test = "{% if true %}dfgh{% endif %}"; + std::string test = "{% if true %}Hello{% endif %}"; json result = { {{"type", Type::Condition}, {"children", { {{"type", Type::ConditionBranch}, {"command", "if true"}, {"children", { - {{"type", Type::String}, {"text", "dfgh"}} + {{"type", Type::String}, {"text", "Hello"}} }}} }}} }; diff --git a/test/src/unit-renderer.cpp b/test/src/unit-renderer.cpp index 83fa702..f6b2d3a 100644 --- a/test/src/unit-renderer.cpp +++ b/test/src/unit-renderer.cpp @@ -3,12 +3,11 @@ #include "inja.hpp" -using Environment = inja::Environment; using json = nlohmann::json; TEST_CASE("Renderer") { - Environment env = Environment(); + inja::Environment env = inja::Environment(); json data; data["name"] = "Peter"; data["city"] = "Brunswick"; diff --git a/test/src/unit-string-helper.cpp b/test/src/unit-string-helper.cpp index 1e1c8f2..eff0001 100644 --- a/test/src/unit-string-helper.cpp +++ b/test/src/unit-string-helper.cpp @@ -59,7 +59,7 @@ TEST_CASE("Search on level") { CHECK( open_match.end_position() == 8 ); CHECK( open_match.str(1) == "up" ); - inja::MatchClosed match = inja::search_closed_match_on_level(input, regex_statement, regex_level_up, regex_level_down, regex_search, open_match); + inja::MatchClosed match = inja::search_closed_on_level(input, regex_statement, regex_level_up, regex_level_down, regex_search, open_match); CHECK( match.position() == 0 ); CHECK( match.end_position() == 109 ); } @@ -71,7 +71,7 @@ TEST_CASE("Search on level") { CHECK( open_match.end_position() == 16 ); CHECK( open_match.str(1) == "up" ); - inja::MatchClosed match = inja::search_closed_match_on_level(input, regex_statement, regex_level_up, regex_level_down, regex_search, open_match); + inja::MatchClosed match = inja::search_closed_on_level(input, regex_statement, regex_level_up, regex_level_down, regex_search, open_match); CHECK( match.open_match.position() == 8 ); CHECK( match.open_match.end_position() == 16 );