Select Git revision
PugsParser.cpp
FunctionArgumentConverter.hpp 16.75 KiB
#ifndef FUNCTION_ARGUMENT_CONVERTER_HPP
#define FUNCTION_ARGUMENT_CONVERTER_HPP
#include <language/node_processor/ExecutionPolicy.hpp>
#include <language/utils/DataVariant.hpp>
#include <utils/Demangle.hpp>
#include <utils/Exceptions.hpp>
#include <utils/PugsTraits.hpp>
#include <sstream>
class IFunctionArgumentConverter
{
public:
virtual DataVariant convert(ExecutionPolicy& exec_policy, DataVariant&& value) = 0;
IFunctionArgumentConverter() = default;
IFunctionArgumentConverter(const IFunctionArgumentConverter&) = delete;
IFunctionArgumentConverter(IFunctionArgumentConverter&&) = delete;
virtual ~IFunctionArgumentConverter() = default;
};
class FunctionArgumentToStringConverter final : public IFunctionArgumentConverter
{
private:
size_t m_argument_id;
public:
DataVariant
convert(ExecutionPolicy& exec_policy, DataVariant&& value)
{
std::visit(
[&](auto&& v) {
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_arithmetic_v<T>) {
exec_policy.currentContext()[m_argument_id] = std::to_string(v);
} else if constexpr (std::is_same_v<T, std::string>) {
exec_policy.currentContext()[m_argument_id] = v;
} else {
std::ostringstream sout;
sout << value;
exec_policy.currentContext()[m_argument_id] = sout.str();
}
},
value);
return {};
}
FunctionArgumentToStringConverter(size_t argument_id) : m_argument_id{argument_id} {}
};
template <typename ExpectedValueType, typename ProvidedValueType>
class FunctionArgumentConverter final : public IFunctionArgumentConverter
{
private:
size_t m_argument_id;
public:
DataVariant
convert(ExecutionPolicy& exec_policy, DataVariant&& value)
{
static_assert(not std::is_same_v<ExpectedValueType, std::string>, "use FunctionArgumentToStringConverter");
if constexpr (std::is_same_v<ExpectedValueType, ProvidedValueType>) {
exec_policy.currentContext()[m_argument_id] = std::move(value);
} else {
exec_policy.currentContext()[m_argument_id] =
std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value)));
}
return {};
}
FunctionArgumentConverter(size_t argument_id) : m_argument_id{argument_id} {}
};
template <typename ExpectedValueType, typename ProvidedValueType>
class FunctionTinyVectorArgumentConverter final : public IFunctionArgumentConverter
{
private:
size_t m_argument_id;
public:
DataVariant
convert(ExecutionPolicy& exec_policy, DataVariant&& value)
{
if constexpr (std::is_same_v<ExpectedValueType, ProvidedValueType>) {
std::visit(
[&](auto&& v) {
using ValueT = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<ValueT, ExpectedValueType>) {
exec_policy.currentContext()[m_argument_id] = std::move(value);
} else if constexpr (std::is_same_v<ValueT, AggregateDataVariant>) {
ExpectedValueType vector_value{};
for (size_t i = 0; i < vector_value.dimension(); ++i) {
std::visit(
[&](auto&& v_i) {
using Vi_T = std::decay_t<decltype(v_i)>;
if constexpr (std::is_arithmetic_v<Vi_T>) {
vector_value[i] = v_i;
} else {
throw UnexpectedError(demangle<Vi_T>() + " unexpected aggregate value type");
}
},
v[i]);
}
exec_policy.currentContext()[m_argument_id] = std::move(vector_value);
}
},
value);
} else if constexpr (std::is_same_v<ProvidedValueType, ZeroType>) {
exec_policy.currentContext()[m_argument_id] = ExpectedValueType{ZeroType::zero};
} else {
static_assert(std::is_same_v<ExpectedValueType, TinyVector<1>>);
exec_policy.currentContext()[m_argument_id] =
std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value)));
}
return {};
}
FunctionTinyVectorArgumentConverter(size_t argument_id) : m_argument_id{argument_id} {}
};
template <typename ExpectedValueType, typename ProvidedValueType>
class FunctionTinyMatrixArgumentConverter final : public IFunctionArgumentConverter
{
private:
size_t m_argument_id;
public:
DataVariant
convert(ExecutionPolicy& exec_policy, DataVariant&& value)
{
if constexpr (std::is_same_v<ExpectedValueType, ProvidedValueType>) {
std::visit(
[&](auto&& v) {
using ValueT = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<ValueT, ExpectedValueType>) {
exec_policy.currentContext()[m_argument_id] = std::move(value);
} else if constexpr (std::is_same_v<ValueT, AggregateDataVariant>) {
ExpectedValueType matrix_value{};
for (size_t i = 0, l = 0; i < matrix_value.numberOfRows(); ++i) {
for (size_t j = 0; j < matrix_value.numberOfColumns(); ++j, ++l) {
std::visit(
[&](auto&& A_ij) {
using Vi_T = std::decay_t<decltype(A_ij)>;
if constexpr (std::is_arithmetic_v<Vi_T>) {
matrix_value(i, j) = A_ij;
} else {
throw UnexpectedError(demangle<Vi_T>() + " unexpected aggregate value type");
}
},
v[l]);
}
}
exec_policy.currentContext()[m_argument_id] = std::move(matrix_value);
}
},
value);
} else if constexpr (std::is_same_v<ProvidedValueType, ZeroType>) {
exec_policy.currentContext()[m_argument_id] = ExpectedValueType{ZeroType::zero};
} else {
static_assert(std::is_same_v<ExpectedValueType, TinyMatrix<1>>);
exec_policy.currentContext()[m_argument_id] =
std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value)));
}
return {};
}
FunctionTinyMatrixArgumentConverter(size_t argument_id) : m_argument_id{argument_id} {}
};
template <typename ContentType, typename ProvidedValueType>
class FunctionTupleArgumentConverter final : public IFunctionArgumentConverter
{
private:
size_t m_argument_id;
public:
DataVariant
convert(ExecutionPolicy& exec_policy, DataVariant&& value)
{
using TupleType = std::vector<ContentType>;
if constexpr (std::is_convertible_v<ProvidedValueType, ContentType>) {
std::visit(
[&](auto&& v) {
using ValueT = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<ValueT, ContentType>) {
exec_policy.currentContext()[m_argument_id] = std::move(TupleType{std::move(v)});
} else if constexpr (is_std_vector_v<ValueT>) {
using ContentT = typename ValueT::value_type;
if constexpr (std::is_same_v<ContentT, ContentType>) {
TupleType list_value;
list_value.reserve(v.size());
for (size_t i = 0; i < v.size(); ++i) {
list_value.emplace_back(std::move(v[i]));
}
exec_policy.currentContext()[m_argument_id] = std::move(list_value);
} else if constexpr ((std::is_convertible_v<ContentT, ContentType>)and not is_tiny_vector_v<ContentType> and
not is_tiny_matrix_v<ContentType>) {
TupleType list_value;
list_value.reserve(v.size());
for (size_t i = 0; i < v.size(); ++i) {
list_value.push_back(static_cast<ContentType>(v[i]));
}
exec_policy.currentContext()[m_argument_id] = std::move(list_value);
} else {
// LCOV_EXCL_START
throw UnexpectedError(std::string{"cannot convert '"} + demangle<ValueT>() + "' to '" +
demangle<ContentType>() + "'");
// LCOV_EXCL_STOP
}
} else if constexpr (std::is_convertible_v<ValueT, ContentType> and not is_tiny_vector_v<ContentType> and
not is_tiny_matrix_v<ContentType>) {
exec_policy.currentContext()[m_argument_id] = std::move(TupleType{static_cast<ContentType>(v)});
} else {
throw UnexpectedError(std::string{"cannot convert '"} + demangle<ValueT>() + "' to '" +
demangle<ContentType>() + "'");
}
},
value);
} else if constexpr (std::is_same_v<std::string, ContentType>) {
std::visit(
[&](auto&& v) {
using ValueT = std::decay_t<decltype(v)>;
Assert(not std::is_same_v<ValueT, ContentType>, "should have been treated before");
if constexpr (is_std_vector_v<ValueT>) {
using ContentT = typename ValueT::value_type;
if constexpr (std::is_same_v<ContentT, ContentType>) {
TupleType list_value;
list_value.reserve(v.size());
for (size_t i = 0; i < v.size(); ++i) {
list_value.emplace_back(std::move(v[i]));
}
exec_policy.currentContext()[m_argument_id] = std::move(list_value);
} else if constexpr (not is_shared_ptr_v<ContentT>) {
TupleType list_value;
list_value.reserve(v.size());
for (size_t i = 0; i < v.size(); ++i) {
std::ostringstream os;
const ContentT& content = v[i]; // useless helper for clang10
os << content;
list_value.push_back(std::move(os.str()));
}
exec_policy.currentContext()[m_argument_id] = std::move(list_value);
} else {
// LCOV_EXCL_START
throw UnexpectedError(std::string{"cannot convert '"} + demangle<ValueT>() + "' to '" +
demangle<ContentType>() + "'");
// LCOV_EXCL_STOP
}
} else if constexpr (not is_shared_ptr_v<ContentType>) {
std::ostringstream os;
os << v;
exec_policy.currentContext()[m_argument_id] = std::move(TupleType{std::move(os.str())});
} else {
// LCOV_EXCL_START
throw UnexpectedError(std::string{"cannot convert '"} + demangle<ValueT>() + "' to '" +
demangle<ContentType>() + "'");
// LCOV_EXCL_STOP
}
},
value);
} else {
// LCOV_EXCL_START
throw UnexpectedError(std::string{"cannot convert '"} + demangle<ProvidedValueType>() + "' to '" +
demangle<ContentType>() + "'");
// LCOV_EXCL_STOP
}
return {};
}
FunctionTupleArgumentConverter(size_t argument_id) : m_argument_id{argument_id} {}
};
template <typename ContentType, typename ProvidedValueType>
class FunctionListArgumentConverter final : public IFunctionArgumentConverter
{
private:
size_t m_argument_id;
public:
DataVariant
convert(ExecutionPolicy& exec_policy, DataVariant&& value)
{
static_assert(not std::is_same_v<ContentType, FunctionSymbolId>);
using TupleType = std::vector<ContentType>;
if constexpr (std::is_same_v<ContentType, ProvidedValueType>) {
std::visit(
[&](auto&& v) {
using ValueT = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<ValueT, AggregateDataVariant>) {
TupleType list_value;
list_value.reserve(v.size());
for (size_t i = 0; i < v.size(); ++i) {
std::visit(
[&](auto&& vi) {
using Vi_T = std::decay_t<decltype(vi)>;
if constexpr (std::is_same_v<Vi_T, ContentType>) {
list_value.emplace_back(vi);
} else if constexpr (is_tiny_vector_v<ContentType> or is_tiny_matrix_v<ContentType>) {
// LCOV_EXCL_START
throw UnexpectedError(std::string{"invalid conversion of '"} + demangle<Vi_T>() + "' to '" +
demangle<ContentType>() + "'");
// LCOV_EXCL_STOP
} else if constexpr (std::is_convertible_v<Vi_T, ContentType>) {
list_value.emplace_back(vi);
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected types");
// LCOV_EXCL_STOP
}
},
(v[i]));
}
exec_policy.currentContext()[m_argument_id] = std::move(list_value);
} else if constexpr (is_std_vector_v<ValueT>) {
using ContentT = typename ValueT::value_type;
if constexpr (std::is_same_v<ContentT, ContentType>) {
exec_policy.currentContext()[m_argument_id] = v;
} else {
// LCOV_EXCL_START
throw UnexpectedError(std::string{"invalid conversion of '"} + demangle<ContentT>() + "' to '" +
demangle<ContentType>() + "'");
// LCOV_EXCL_STOP
}
} else if constexpr (std::is_same_v<ValueT, ContentType>) {
exec_policy.currentContext()[m_argument_id] = std::move(TupleType{v});
} else if constexpr (std::is_convertible_v<ValueT, ContentType> and not is_tiny_vector_v<ValueT> and
not is_tiny_vector_v<ContentType> and not is_tiny_matrix_v<ValueT> and
not is_tiny_matrix_v<ContentType>) {
exec_policy.currentContext()[m_argument_id] = std::move(TupleType{static_cast<ContentType>(v)});
} else {
// LCOV_EXCL_START
throw UnexpectedError(demangle<ValueT>() + " unexpected value type");
// LCOV_EXCL_STOP
}
},
value);
}
static_assert(std::is_same_v<ContentType, ProvidedValueType>, "conversion is not implemented");
return {};
}
FunctionListArgumentConverter(size_t argument_id) : m_argument_id{argument_id} {}
};
template <>
class FunctionListArgumentConverter<FunctionSymbolId, FunctionSymbolId> final : public IFunctionArgumentConverter
{
private:
size_t m_argument_id;
std::shared_ptr<SymbolTable> m_symbol_table;
public:
DataVariant
convert(ExecutionPolicy& exec_policy, DataVariant&& value)
{
using TupleType = std::vector<FunctionSymbolId>;
std::visit(
[&](auto&& v) {
using ValueT = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<ValueT, AggregateDataVariant>) {
TupleType list_value;
list_value.reserve(v.size());
for (size_t i = 0; i < v.size(); ++i) {
std::visit(
[&](auto&& vi) {
using Vi_T = std::decay_t<decltype(vi)>;
if constexpr (std::is_same_v<Vi_T, uint64_t>) {
list_value.emplace_back(FunctionSymbolId{vi, m_symbol_table});
} else {
// LCOV_EXCL_START
throw UnexpectedError(std::string{"invalid conversion of '"} + demangle<Vi_T>() + "' to '" +
demangle<FunctionSymbolId>() + "'");
// LCOV_EXCL_STOP
}
},
(v[i]));
}
exec_policy.currentContext()[m_argument_id] = std::move(list_value);
} else {
// LCOV_EXCL_START
throw UnexpectedError(std::string{"invalid conversion of '"} + demangle<ValueT>() + "' to '" +
demangle<FunctionSymbolId>() + "' list");
// LCOV_EXCL_STOP
}
},
value);
return {};
}
FunctionListArgumentConverter(size_t argument_id, const std::shared_ptr<SymbolTable>& symbol_table)
: m_argument_id{argument_id}, m_symbol_table{symbol_table}
{}
};
class FunctionArgumentToFunctionSymbolIdConverter final : public IFunctionArgumentConverter
{
private:
size_t m_argument_id;
std::shared_ptr<SymbolTable> m_symbol_table;
public:
DataVariant
convert(ExecutionPolicy& exec_policy, DataVariant&& value)
{
exec_policy.currentContext()[m_argument_id] = FunctionSymbolId{std::get<uint64_t>(value), m_symbol_table};
return {};
}
FunctionArgumentToFunctionSymbolIdConverter(size_t argument_id, const std::shared_ptr<SymbolTable>& symbol_table)
: m_argument_id{argument_id}, m_symbol_table{symbol_table}
{}
};
class FunctionArgumentToTupleFunctionSymbolIdConverter final : public IFunctionArgumentConverter
{
private:
size_t m_argument_id;
std::shared_ptr<SymbolTable> m_symbol_table;
public:
DataVariant
convert(ExecutionPolicy& exec_policy, DataVariant&& value)
{
exec_policy.currentContext()[m_argument_id] =
std::vector{FunctionSymbolId{std::get<uint64_t>(value), m_symbol_table}};
return {};
}
FunctionArgumentToTupleFunctionSymbolIdConverter(size_t argument_id, const std::shared_ptr<SymbolTable>& symbol_table)
: m_argument_id{argument_id}, m_symbol_table{symbol_table}
{}
};
#endif // FUNCTION_ARGUMENT_CONVERTER_HPP