diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e04563..c694dc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.20) include(cmake/color.cmake) -set(BLT_VERSION 0.16.23) +set(BLT_VERSION 0.16.24) set(BLT_TEST_VERSION 0.0.1) set(BLT_TARGET BLT) diff --git a/include/blt/parse/templating.h b/include/blt/parse/templating.h index 814140a..37217ff 100644 --- a/include/blt/parse/templating.h +++ b/include/blt/parse/templating.h @@ -31,6 +31,7 @@ namespace blt { + template class template_consumer_base_t { @@ -79,6 +80,7 @@ namespace blt { //STRING, // A string of characters not $ { or } IDENT, // $ + ADD, // + CURLY_OPEN, // { CURLY_CLOSE, // } IF, // IF @@ -143,6 +145,8 @@ namespace blt return "[COMMA]"; case template_token_t::PERIOD: return "[PERIOD]"; + case template_token_t::ADD: + return "[ADD]"; } } @@ -155,8 +159,18 @@ namespace blt enum class template_parser_failure_t { + SUBSTITUTION_NOT_FOUND, TOKENIZER_FAILURE, - NO_MATCHING_CURLY + NO_MATCHING_CURLY, + MISSING_IDENT_BRACES, + FUNCTION_EXPECTED_STRING, + FUNCTION_NOT_FOUND, + FUNCTION_DISCARD, + STRING_EXPECTED_CONCAT, + IF_EXPECTED_PAREN, + BOOL_EXPECTED_PAREN, + UNKNOWN_STATEMENT_ERROR, + UNKNOWN_ERROR }; struct template_token_data_t @@ -198,10 +212,15 @@ namespace blt return ""; auto token = storage[getPreviousIndex()]; auto len = (&token.token.back() - &raw_string.front()) - last_read_index; - auto str = std::string_view(&raw_string[last_read_index], len); + auto str = std::string_view(&raw_string[lasomt_read_index], len); last_read_index += len; return str; } + + void back() + { + current_index--; + } private: size_t last_read_index = 0; @@ -211,27 +230,181 @@ namespace blt { public: using estring = blt::expected; + using ebool = blt::expected; + template_parser_t(blt::hashmap_t& substitutions, template_token_consumer_t& consumer): substitutions(substitutions), consumer(consumer) {} estring parse() { - consumer.advance(2); - auto str = statement(); - if (!str) + auto next = consumer.consume(); + if (next.type == template_token_t::IDENT && consumer.next().type == template_token_t::CURLY_OPEN) + { + consumer.advance(); + auto str = statement(); + consumer.advance(); return str; - // should never occur - if (consumer.hasNext() && consumer.next().type != template_token_t::CURLY_CLOSE) - return blt::unexpected(template_parser_failure_t::NO_MATCHING_CURLY); - consumer.advance(); - return str; + } + return blt::unexpected(template_parser_failure_t::MISSING_IDENT_BRACES); } private: estring statement() { + auto next = consumer.consume(); + if (next.type == template_token_t::STRING || next.type == template_token_t::QUOTE) + { + consumer.back(); + return string(); + } else if (next.type == template_token_t::FUNCTION) + { + return function(); + } else if (next.type == template_token_t::IDENT && consumer.hasNext() && consumer.next().type == template_token_t::CURLY_OPEN) + { + consumer.advance(); + auto stmt = statement(); + // should never occur + if (consumer.hasNext() && consumer.next().type != template_token_t::CURLY_CLOSE) + return blt::unexpected(template_parser_failure_t::NO_MATCHING_CURLY); + consumer.advance(); + return stmt; + } else if (next.type == template_token_t::IF) + { + return if_func(); + } + return blt::unexpected(template_parser_failure_t::UNKNOWN_STATEMENT_ERROR); + } + estring function() + { + auto str = consumer.consume(); + if (str.type != template_token_t::STRING) + return blt::unexpected(template_parser_failure_t::FUNCTION_EXPECTED_STRING); + if (str.token == "DISCARD") + return blt::unexpected(template_parser_failure_t::FUNCTION_DISCARD); + return blt::unexpected(template_parser_failure_t::FUNCTION_NOT_FOUND); + } + + estring if_func() + { + // IF( + if (consumer.consume().type != template_token_t::PAR_OPEN) + return blt::unexpected(template_parser_failure_t::IF_EXPECTED_PAREN); + // (statement) + auto bool_eval = bool_statement(); + if (!bool_eval) + return blt::unexpected(bool_eval.error()); + if (consumer.consume().type != template_token_t::PAR_CLOSE) + return blt::unexpected(template_parser_failure_t::IF_EXPECTED_PAREN); + auto true_statement = statement(); + estring false_statement = blt::unexpected(template_parser_failure_t::UNKNOWN_ERROR); + if (consumer.next().type == template_token_t::ELSE) + { + consumer.advance(); + false_statement = statement(); + } + if (bool_eval.value()) + { + return true_statement; + } else + { + if (false_statement) + return false_statement; + return ""; + } + } + + estring string() + { + auto next = consumer.consume(); + if (next.type == template_token_t::STRING) + { + if (!substitutions.contains(next.token)) + return blt::unexpected(template_parser_failure_t::SUBSTITUTION_NOT_FOUND); + if (consumer.next().type == template_token_t::SEMI) + { + consumer.advance(); + return substitutions[next.token]; + } + if (consumer.next().type != template_token_t::ADD) + return blt::unexpected(template_parser_failure_t::STRING_EXPECTED_CONCAT); + consumer.advance(); + auto str = string(); + if (str) + return substitutions[next.token] + str.value(); + else + return str; + } else + { + if (consumer.next().type == template_token_t::SEMI) + { + consumer.advance(); + return std::string(next.token); + } + auto str = string(); + if (str) + return std::string(next.token) + str.value(); + else + return str; + } + } + + ebool bool_statement() + { + auto next = consumer.next(); + if (next.type == template_token_t::PAR_OPEN) + { + consumer.advance(); + auto b = bool_statement(); + if (consumer.consume().type != template_token_t::PAR_CLOSE) + return blt::unexpected(template_parser_failure_t::BOOL_EXPECTED_PAREN); + return b; + } + return bool_expression(); + } + + ebool bool_expression() + { + auto next = consumer.next(); + if (next.type == template_token_t::PAR_OPEN) + return bool_statement(); + consumer.advance(); + if (next.type == template_token_t::NOT) + { + auto b = bool_statement(); + if (b) + return !b.value(); + else + return b; + } else if (next.type == template_token_t::STRING) + { + auto bool_val = next.token.empty(); + next = consumer.next(); + if (next.type == template_token_t::PAR_CLOSE) + return bool_val; + consumer.advance(); + if (next.type == template_token_t::AND) + { + auto other_val = bool_expression(); + if (!other_val) + return other_val; + return bool_val && other_val.value(); + } else if (next.type == template_token_t::OR) + { + auto other_val = bool_expression(); + if (!other_val) + return other_val; + return bool_val || other_val.value(); + } else if (next.type == template_token_t::XOR) + { + auto other_val = bool_expression(); + if (!other_val) + return other_val; + return bool_val ^ other_val.value(); + } + } + return unexpected(template_parser_failure_t::UNKNOWN_ERROR); } blt::hashmap_t& substitutions; diff --git a/include/blt/std/expected.h b/include/blt/std/expected.h index b2700af..3fa4f9a 100644 --- a/include/blt/std/expected.h +++ b/include/blt/std/expected.h @@ -142,6 +142,7 @@ namespace blt expected& operator=(const expected& copy) { v = copy.v; + return *this; } constexpr expected(expected&& move) noexcept: v(std::move(move.v)) @@ -150,6 +151,7 @@ namespace blt expected& operator=(expected&& move) { std::swap(v, move.v); + return *this; } /* diff --git a/libraries/parallel-hashmap b/libraries/parallel-hashmap index 7ef2e73..1036816 160000 --- a/libraries/parallel-hashmap +++ b/libraries/parallel-hashmap @@ -1 +1 @@ -Subproject commit 7ef2e733416953b222851f9a360d7fc72d068ee5 +Subproject commit 10368163ab1f4367d2f0685b5928b1c973ebd1ec diff --git a/src/blt/parse/templating.cpp b/src/blt/parse/templating.cpp index ff6ad0b..68af339 100644 --- a/src/blt/parse/templating.cpp +++ b/src/blt/parse/templating.cpp @@ -40,6 +40,7 @@ namespace blt case ',': case '.': case '|': + case '+': return true; default: return false; @@ -123,6 +124,9 @@ namespace blt case ',': tokens.emplace_back(template_token_t::COMMA, level, consumer.from(current_start, current_start + 1)); break; + case '+': + tokens.emplace_back(template_token_t::ADD, level, consumer.from(current_start, current_start + 1)); + break; case '.': tokens.emplace_back(template_token_t::PERIOD, level, consumer.from(current_start, current_start + 1)); break; @@ -207,18 +211,25 @@ namespace blt while (consumer.hasNext()) { + BLT_TRACE("Running with next %d", static_cast(consumer.next().type)); while (consumer.hasNext(2)) { - if (consumer.next().type == template_token_t::IDENT && consumer.next().type == template_token_t::CURLY_OPEN) + if (consumer.next().type == template_token_t::IDENT && consumer.next(1).type == template_token_t::CURLY_OPEN) { + BLT_TRACE("From Last: %s", std::string(consumer.from_last(str)).c_str()); return_str += consumer.from_last(str); break; } + consumer.advance(); } if (auto result = parser.parse()) return_str += result.value(); else + { + if (result.error() == template_parser_failure_t::FUNCTION_DISCARD) + continue; return result; + } } return return_str;