working on templating
parent
4ef3fe7573
commit
ce7c1357e0
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue