Brett 2024-05-09 21:53:08 -04:00
parent b857bc96ef
commit fa979a2fd4
5 changed files with 199 additions and 13 deletions

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
include(cmake/color.cmake) 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_TEST_VERSION 0.0.1)
set(BLT_TARGET BLT) set(BLT_TARGET BLT)

View File

@ -31,6 +31,7 @@
namespace blt namespace blt
{ {
template<typename Storage, typename Consumable> template<typename Storage, typename Consumable>
class template_consumer_base_t class template_consumer_base_t
{ {
@ -79,6 +80,7 @@ namespace blt
{ {
//STRING, // A string of characters not $ { or } //STRING, // A string of characters not $ { or }
IDENT, // $ IDENT, // $
ADD, // +
CURLY_OPEN, // { CURLY_OPEN, // {
CURLY_CLOSE, // } CURLY_CLOSE, // }
IF, // IF IF, // IF
@ -143,6 +145,8 @@ namespace blt
return "[COMMA]"; return "[COMMA]";
case template_token_t::PERIOD: case template_token_t::PERIOD:
return "[PERIOD]"; return "[PERIOD]";
case template_token_t::ADD:
return "[ADD]";
} }
} }
@ -155,8 +159,18 @@ namespace blt
enum class template_parser_failure_t enum class template_parser_failure_t
{ {
SUBSTITUTION_NOT_FOUND,
TOKENIZER_FAILURE, 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 struct template_token_data_t
@ -198,10 +212,15 @@ namespace blt
return ""; return "";
auto token = storage[getPreviousIndex()]; auto token = storage[getPreviousIndex()];
auto len = (&token.token.back() - &raw_string.front()) - last_read_index; 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; last_read_index += len;
return str; return str;
} }
void back()
{
current_index--;
}
private: private:
size_t last_read_index = 0; size_t last_read_index = 0;
@ -211,27 +230,181 @@ namespace blt
{ {
public: public:
using estring = blt::expected<std::string, template_parser_failure_t>; using estring = blt::expected<std::string, template_parser_failure_t>;
using ebool = blt::expected<bool, template_parser_failure_t>;
template_parser_t(blt::hashmap_t<std::string, std::string>& substitutions, template_token_consumer_t& consumer): template_parser_t(blt::hashmap_t<std::string, std::string>& substitutions, template_token_consumer_t& consumer):
substitutions(substitutions), consumer(consumer) substitutions(substitutions), consumer(consumer)
{} {}
estring parse() estring parse()
{ {
consumer.advance(2); auto next = consumer.consume();
auto str = statement(); if (next.type == template_token_t::IDENT && consumer.next().type == template_token_t::CURLY_OPEN)
if (!str) {
consumer.advance();
auto str = statement();
consumer.advance();
return str; return str;
// should never occur }
if (consumer.hasNext() && consumer.next().type != template_token_t::CURLY_CLOSE) return blt::unexpected(template_parser_failure_t::MISSING_IDENT_BRACES);
return blt::unexpected(template_parser_failure_t::NO_MATCHING_CURLY);
consumer.advance();
return str;
} }
private: private:
estring statement() 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<std::string, std::string>& substitutions; blt::hashmap_t<std::string, std::string>& substitutions;

View File

@ -142,6 +142,7 @@ namespace blt
expected& operator=(const expected& copy) expected& operator=(const expected& copy)
{ {
v = copy.v; v = copy.v;
return *this;
} }
constexpr expected(expected&& move) noexcept: v(std::move(move.v)) constexpr expected(expected&& move) noexcept: v(std::move(move.v))
@ -150,6 +151,7 @@ namespace blt
expected& operator=(expected&& move) expected& operator=(expected&& move)
{ {
std::swap(v, move.v); std::swap(v, move.v);
return *this;
} }
/* /*

@ -1 +1 @@
Subproject commit 7ef2e733416953b222851f9a360d7fc72d068ee5 Subproject commit 10368163ab1f4367d2f0685b5928b1c973ebd1ec

View File

@ -40,6 +40,7 @@ namespace blt
case ',': case ',':
case '.': case '.':
case '|': case '|':
case '+':
return true; return true;
default: default:
return false; return false;
@ -123,6 +124,9 @@ namespace blt
case ',': case ',':
tokens.emplace_back(template_token_t::COMMA, level, consumer.from(current_start, current_start + 1)); tokens.emplace_back(template_token_t::COMMA, level, consumer.from(current_start, current_start + 1));
break; break;
case '+':
tokens.emplace_back(template_token_t::ADD, level, consumer.from(current_start, current_start + 1));
break;
case '.': case '.':
tokens.emplace_back(template_token_t::PERIOD, level, consumer.from(current_start, current_start + 1)); tokens.emplace_back(template_token_t::PERIOD, level, consumer.from(current_start, current_start + 1));
break; break;
@ -207,18 +211,25 @@ namespace blt
while (consumer.hasNext()) while (consumer.hasNext())
{ {
BLT_TRACE("Running with next %d", static_cast<int>(consumer.next().type));
while (consumer.hasNext(2)) 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); return_str += consumer.from_last(str);
break; break;
} }
consumer.advance();
} }
if (auto result = parser.parse()) if (auto result = parser.parse())
return_str += result.value(); return_str += result.value();
else else
{
if (result.error() == template_parser_failure_t::FUNCTION_DISCARD)
continue;
return result; return result;
}
} }
return return_str; return return_str;