working on templating

v1
Brett 2024-05-10 12:56:48 -04:00
parent 4ef3fe7573
commit ce7c1357e0
3 changed files with 207 additions and 86 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.26) set(BLT_VERSION 0.17.0)
set(BLT_TEST_VERSION 0.0.1) set(BLT_TEST_VERSION 0.0.1)
set(BLT_TARGET BLT) set(BLT_TARGET BLT)

View File

@ -33,6 +33,8 @@
namespace blt namespace blt
{ {
class template_engine_t;
template<typename Storage, typename Consumable> template<typename Storage, typename Consumable>
class template_consumer_base_t class template_consumer_base_t
{ {
@ -170,6 +172,7 @@ namespace blt
STRING_EXPECTED_CONCAT, STRING_EXPECTED_CONCAT,
IF_EXPECTED_PAREN, IF_EXPECTED_PAREN,
BOOL_EXPECTED_PAREN, BOOL_EXPECTED_PAREN,
BOOL_TYPE_NOT_FOUND,
UNKNOWN_STATEMENT_ERROR, UNKNOWN_STATEMENT_ERROR,
UNKNOWN_ERROR UNKNOWN_ERROR
}; };
@ -204,17 +207,26 @@ namespace blt
class template_token_consumer_t : public template_consumer_base_t<std::vector<template_token_data_t>, template_token_data_t> class template_token_consumer_t : public template_consumer_base_t<std::vector<template_token_data_t>, template_token_data_t>
{ {
public: public:
explicit template_token_consumer_t(const std::vector<template_token_data_t>& statement): template_consumer_base_t(statement) explicit template_token_consumer_t(const std::vector<template_token_data_t>& statement, std::string_view raw_string):
template_consumer_base_t(statement), raw_string(raw_string)
{} {}
std::string_view from_last(std::string_view raw_string) void set_marker()
{ {
if (current_index == 0) // when setting the marker, we need to go from the last closing brace
return ""; auto index = storage.begin() + getCurrentIndex();
auto token = storage[getPreviousIndex()]; while (index->type != template_token_t::CURLY_CLOSE)
auto len = (&token.token.back() - &raw_string.front()) - last_read_index; index--;
last_read_index = ((&index->token.front() + index->token.size()) - &raw_string[last_read_index]);
}
std::string_view from_last()
{
if (!hasNext())
return std::string_view(&raw_string[last_read_index], raw_string.size() - last_read_index);
auto token = storage[getCurrentIndex()];
auto len = ((&token.token.back()) - &raw_string[last_read_index]);
auto str = std::string_view(&raw_string[last_read_index], len); auto str = std::string_view(&raw_string[last_read_index], len);
last_read_index += len;
return str; return str;
} }
@ -224,17 +236,55 @@ namespace blt
} }
private: private:
std::string_view raw_string;
size_t last_read_index = 0; size_t last_read_index = 0;
}; };
class template_engine_t
{
public:
inline std::string& operator[](const std::string& key)
{
return substitutions[key];
}
inline std::string& operator[](std::string_view key)
{
return substitutions[key];
}
inline template_engine_t& set(std::string_view key, std::string_view replacement)
{
substitutions[key] = replacement;
return *this;
}
inline bool contains(std::string_view token)
{
return substitutions.contains(token);
}
inline auto get(std::string_view token)
{
return evaluate(substitutions[token]);
}
static blt::expected<std::vector<template_token_data_t>, template_tokenizer_failure_t> process_string(std::string_view str);
blt::expected<std::string, template_parser_failure_t> evaluate(std::string_view str);
private:
blt::hashmap_t<std::string, std::string> substitutions;
};
class template_parser_t class template_parser_t
{ {
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>; 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(template_engine_t& engine, template_token_consumer_t& consumer):
substitutions(substitutions), consumer(consumer) engine(engine), consumer(consumer)
{} {}
estring parse() estring parse()
@ -321,25 +371,25 @@ namespace blt
auto next = consumer.consume(); auto next = consumer.consume();
if (next.type == template_token_t::STRING) if (next.type == template_token_t::STRING)
{ {
BLT_TRACE(next.token); if (!engine.contains(next.token))
while (consumer.hasNext())
BLT_TRACE(consumer.consume().token);
if (!substitutions.contains(next.token))
return blt::unexpected(template_parser_failure_t::SUBSTITUTION_NOT_FOUND); return blt::unexpected(template_parser_failure_t::SUBSTITUTION_NOT_FOUND);
if (consumer.next().type == template_token_t::SEMI || consumer.next().type == template_token_t::ELSE) if (consumer.next().type == template_token_t::SEMI || consumer.next().type == template_token_t::ELSE ||
consumer.next().type == template_token_t::CURLY_CLOSE)
{ {
consumer.advance(); consumer.advance();
return substitutions[next.token]; return engine.get(next.token);
} }
if (consumer.next().type != template_token_t::ADD) if (consumer.next().type != template_token_t::ADD)
return blt::unexpected(template_parser_failure_t::STRING_EXPECTED_CONCAT); return blt::unexpected(template_parser_failure_t::STRING_EXPECTED_CONCAT);
consumer.advance(); consumer.advance();
auto str = string(); auto str = string();
if (str) if (!str)
return substitutions[next.token] + str.value();
else
return str; return str;
auto sub = engine.get(next.token);
if (!sub)
return sub;
return sub.value() + str.value();
} else } else
{ {
if (consumer.next().type == template_token_t::SEMI) if (consumer.next().type == template_token_t::SEMI)
@ -364,85 +414,149 @@ namespace blt
auto b = bool_statement(); auto b = bool_statement();
if (consumer.consume().type != template_token_t::PAR_CLOSE) if (consumer.consume().type != template_token_t::PAR_CLOSE)
return blt::unexpected(template_parser_failure_t::BOOL_EXPECTED_PAREN); return blt::unexpected(template_parser_failure_t::BOOL_EXPECTED_PAREN);
consumer.advance();
return b; return b;
} }
return bool_expression(); return bool_expression();
} }
ebool bool_expression() ebool bool_value()
{ {
bool b1;
auto next = consumer.next(); auto next = consumer.next();
if (next.type == template_token_t::PAR_OPEN) if (next.type == template_token_t::PAR_OPEN)
return bool_statement();
consumer.advance();
if (next.type == template_token_t::NOT)
{ {
auto b = bool_statement(); auto b = bool_statement();
if (b) if (!b)
return !b.value();
else
return b; return b;
} else if (next.type == template_token_t::STRING) b1 = b.value();
} else
{ {
auto bool_val = next.token.empty(); bool invert = false;
// prefixes
if (next.type == template_token_t::NOT)
{
invert = true;
consumer.advance();
}
if (consumer.next().type == template_token_t::PAR_OPEN)
{
auto b = bool_statement();
if (!b)
return b;
b1 = b.value();
} else
{
auto b = statement();
if (!b)
return blt::unexpected(b.error());
b1 = !b.value().empty();
}
if (invert)
b1 = !b1;
}
return b1;
}
ebool bool_expression()
{
// this whole thing is just bad. please redo. TODO
std::vector<int> values;
while (consumer.next().type != template_token_t::PAR_CLOSE)
{
auto next = consumer.next();
auto bv = bool_value();
if (!bv)
return bv;
values.push_back(bv.value());
if (values.size() == 2)
{
auto b1 = values[0];
auto b2 = values[1];
values.pop_back();
values.pop_back();
switch (next.type)
{
case template_token_t::AND:
values.push_back(b1 && b2);
break;
case template_token_t::OR:
values.push_back(b1 || b2);
break;
case template_token_t::XOR:
values.push_back(b1 ^ b2);
break;
default:
return blt::unexpected(template_parser_failure_t::BOOL_TYPE_NOT_FOUND);
}
}
next = consumer.next(); next = consumer.next();
if (next.type == template_token_t::PAR_CLOSE) if (next.type == template_token_t::PAR_CLOSE)
return bool_val; break;
consumer.advance(); consumer.advance();
if (next.type == template_token_t::AND) // bv = bool_value();
{ // if (!bv)
auto other_val = bool_expression(); // return bv;
if (!other_val) // values.push_back(bv.value());
return other_val; //
return bool_val && other_val.value(); // switch (next.type)
} else if (next.type == template_token_t::OR) // {
{ // case template_token_t::AND:
auto other_val = bool_expression(); // ret =
if (!other_val) // case template_token_t::OR:
return other_val; // break;
return bool_val || other_val.value(); // case template_token_t::XOR:
} else if (next.type == template_token_t::XOR) // break;
{ // default:
auto other_val = bool_expression(); // return blt::unexpected(template_parser_failure_t::BOOL_TYPE_NOT_FOUND);
if (!other_val) // }
return other_val;
return bool_val ^ other_val.value();
}
} }
return unexpected(template_parser_failure_t::UNKNOWN_ERROR); if (values.empty())
BLT_WARN("This is not possible!");
return values[0];
// 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; template_engine_t& engine;
template_token_consumer_t& consumer; template_token_consumer_t& consumer;
}; };
class template_engine_t
{
public:
inline std::string& operator[](const std::string& key)
{
return substitutions[key];
}
inline std::string& operator[](std::string_view key)
{
return substitutions[key];
}
inline template_engine_t& set(std::string_view key, std::string_view replacement)
{
substitutions[key] = replacement;
return *this;
}
static blt::expected<std::vector<template_token_data_t>, template_tokenizer_failure_t> process_string(std::string_view str);
blt::expected<std::string, template_parser_failure_t> evaluate(std::string_view str);
private:
blt::hashmap_t<std::string, std::string> substitutions;
};
} }
#endif //BLT_TEMPLATING_H #endif //BLT_TEMPLATING_H

View File

@ -154,7 +154,9 @@ namespace blt
default: default:
// do not add whitespace to anything // do not add whitespace to anything
if (std::isspace(c)) if (std::isspace(c))
{
break; break;
}
if (start == -1) if (start == -1)
start = current_start; start = current_start;
if (consumer.hasNext() && (isNonStringNext(consumer.next()) || std::isspace(consumer.next()))) if (consumer.hasNext() && (isNonStringNext(consumer.next()) || std::isspace(consumer.next())))
@ -203,36 +205,41 @@ namespace blt
} }
std::string return_str; std::string return_str;
return_str.reserve(str.size()); //return_str.reserve(str.size());
template_token_consumer_t consumer{tokens.value()}; template_token_consumer_t consumer{tokens.value(), str};
template_parser_t parser(substitutions, consumer); template_parser_t parser(*this, consumer);
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(1).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();
return_str += consumer.from_last(str);
break; break;
} }
consumer.advance(); consumer.advance();
} }
if (!consumer.hasNext(2))
break;
if (auto result = parser.parse()) if (auto result = parser.parse())
{
BLT_DEBUG("Result parser: %s", result.value().c_str());
return_str += result.value(); return_str += result.value();
else }else
{ {
if (result.error() == template_parser_failure_t::FUNCTION_DISCARD) if (result.error() == template_parser_failure_t::FUNCTION_DISCARD)
continue; continue;
return result; return result;
} }
consumer.set_marker();
} }
while(consumer.hasNext())
BLT_TRACE(return_str); consumer.advance();
return_str += consumer.from_last();
return return_str; return return_str;
} }