Select Git revision
AffectationProcessor.hpp
-
Stéphane Del Pino authored
This is quite a stupid hack
Stéphane Del Pino authoredThis is quite a stupid hack
AffectationProcessor.hpp 25.08 KiB
#ifndef AFFECTATION_PROCESSOR_HPP
#define AFFECTATION_PROCESSOR_HPP
#include <language/PEGGrammar.hpp>
#include <language/node_processor/INodeProcessor.hpp>
#include <language/utils/ParseError.hpp>
#include <language/utils/SymbolTable.hpp>
#include <utils/Exceptions.hpp>
#include <utils/PugsTraits.hpp>
template <typename Op>
struct AffOp;
template <>
struct AffOp<language::multiplyeq_op>
{
template <typename A, typename B>
PUGS_INLINE void
eval(A& a, const B& b)
{
a *= b;
}
};
template <>
struct AffOp<language::divideeq_op>
{
template <typename A, typename B>
PUGS_INLINE void
eval(A& a, const B& b)
{
a /= b;
}
};
template <>
struct AffOp<language::pluseq_op>
{
template <typename A, typename B>
PUGS_INLINE void
eval(A& a, const B& b)
{
a += b;
}
};
template <>
struct AffOp<language::minuseq_op>
{
template <typename A, typename B>
PUGS_INLINE void
eval(A& a, const B& b)
{
a -= b;
}
};
struct IAffectationExecutor
{
virtual void affect(ExecutionPolicy& exec_policy, DataVariant&& rhs) = 0;
IAffectationExecutor(const IAffectationExecutor&) = delete;
IAffectationExecutor(IAffectationExecutor&&) = delete;
IAffectationExecutor() = default;
virtual ~IAffectationExecutor() = default;
};
template <typename OperatorT, typename ValueT, typename DataT>
class AffectationExecutor final : public IAffectationExecutor
{
private:
ValueT& m_lhs;
static inline const bool m_is_defined{[] {
if constexpr (std::is_same_v<std::decay_t<ValueT>, bool>) {
if constexpr (not std::is_same_v<OperatorT, language::eq_op>) {
return false;
}
}
return true;
}()};
template <typename T>
std::string
_stringify(const T& value)
{
std::ostringstream os;
os << std::boolalpha << value;
return os.str();
}
public:
AffectationExecutor(ASTNode& node, ValueT& lhs) : m_lhs(lhs)
{
// LCOV_EXCL_START
if constexpr (not m_is_defined) {
throw ParseError("unexpected error: invalid operands to affectation expression", std::vector{node.begin()});
}
// LCOV_EXCL_STOP
}
PUGS_INLINE void
affect(ExecutionPolicy&, DataVariant&& rhs)
{
if constexpr (m_is_defined) {
if constexpr (not std::is_same_v<DataT, ZeroType>) {
if constexpr (std::is_same_v<ValueT, std::string>) {
if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
if constexpr (std::is_same_v<std::string, DataT>) {
m_lhs = std::get<DataT>(rhs);
} else {
m_lhs = std::move(_stringify(std::get<DataT>(rhs)));
}
} else {
if constexpr (std::is_same_v<std::string, DataT>) {
m_lhs += std::get<std::string>(rhs);
} else {
m_lhs += std::move(_stringify(std::get<DataT>(rhs)));
}
}
} else {
if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
if constexpr (std::is_convertible_v<DataT, ValueT>) {
m_lhs = std::get<DataT>(rhs);
} else if constexpr (std::is_same_v<TinyVector<1>, ValueT>) {
std::visit(
[&](auto&& v) {
using Vi_T = std::decay_t<decltype(v)>;
if constexpr (std::is_convertible_v<Vi_T, double>) {
m_lhs = TinyVector<1>(v);
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected rhs type in affectation");
// LCOV_EXCL_STOP
}
},
rhs);
} else if constexpr (std::is_same_v<TinyMatrix<1>, ValueT>) {
std::visit(
[&](auto&& v) {
using Vi_T = std::decay_t<decltype(v)>;
if constexpr (std::is_convertible_v<Vi_T, double>) {
m_lhs = TinyMatrix<1>(v);
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected rhs type in affectation");
// LCOV_EXCL_STOP
}
},
rhs);
} else if constexpr (is_std_vector_v<ValueT> and is_std_vector_v<DataT>) {
using ValueContentT = typename ValueT::value_type;
using DataContentT = typename DataT::value_type;
static_assert(not std::is_same_v<ValueContentT, DataContentT>,
"the case should have been treated previously");
if constexpr (std::is_convertible_v<DataContentT, ValueContentT>) {
m_lhs.resize(std::get<DataT>(rhs).size());
std::visit(
[&](auto&& v) {
using Vi_T = std::decay_t<decltype(v)>;
if constexpr (is_std_vector_v<Vi_T>) {
if constexpr (std::is_arithmetic_v<typename Vi_T::value_type>) {
for (size_t i = 0; i < v.size(); ++i) {
m_lhs[i] = v[i];
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected rhs type in affectation");
// LCOV_EXCL_STOP
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected rhs type in affectation");
// LCOV_EXCL_STOP
}
},
rhs);
} else if constexpr (std::is_same_v<ValueContentT, std::string>) {
m_lhs.resize(std::get<DataT>(rhs).size());
std::visit(
[&](auto&& v) {
using V_T = std::decay_t<decltype(v)>;
if constexpr (is_std_vector_v<V_T>) {
for (size_t i = 0; i < v.size(); ++i) {
if constexpr (std::is_same_v<typename V_T::value_type, bool>) {
// Ugly workaround to allow compilation with libstdc++-9
bool v_i = v[i];
m_lhs[i] = std::move(_stringify(v_i));
} else {
m_lhs[i] = std::move(_stringify(v[i]));
}
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected rhs type in affectation");
// LCOV_EXCL_STOP
}
},
rhs);
} else if constexpr (is_tiny_vector_v<ValueContentT>) {
static_assert(not std::is_same_v<DataContentT, ValueContentT>, "should have been treated before");
static_assert(ValueContentT::Dimension == 1,
"conversions are only allowed for dimension 1 TinyVector's");
m_lhs.resize(std::get<DataT>(rhs).size());
std::visit(
[&](auto&& v) {
if constexpr (is_std_vector_v<std::decay_t<decltype(v)>>) {
using Vi_T = typename std::decay_t<decltype(v)>::value_type;
for (size_t i = 0; i < v.size(); ++i) {
if constexpr (std::is_arithmetic_v<Vi_T>) {
m_lhs[i][0] = v[i];
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected rhs type in affectation");
// LCOV_EXCL_STOP
}
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected rhs type in affectation");
// LCOV_EXCL_STOP
}
},
rhs);
} else if constexpr (is_tiny_matrix_v<ValueContentT>) {
static_assert(not std::is_same_v<DataContentT, ValueContentT>, "should have been treated before");
static_assert(ValueContentT::Dimension == 1, "conversions are only allowed for 1x1 TinyMatrix's");
m_lhs.resize(std::get<DataT>(rhs).size());
std::visit(
[&](auto&& v) {
if constexpr (is_std_vector_v<std::decay_t<decltype(v)>>) {
using Vi_T = typename std::decay_t<decltype(v)>::value_type;
for (size_t i = 0; i < v.size(); ++i) {
if constexpr (std::is_arithmetic_v<Vi_T>) {
m_lhs[i](0, 0) = v[i];
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected rhs type in affectation");
// LCOV_EXCL_STOP
}
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected rhs type in affectation");
// LCOV_EXCL_STOP
}
},
rhs);
} else {
// LCOV_EXCL_START
throw UnexpectedError("invalid value type");
// LCOV_EXCL_STOP
}
} else if constexpr (is_std_vector_v<ValueT> and std::is_same_v<DataT, AggregateDataVariant>) {
using ValueContentT = typename ValueT::value_type;
const AggregateDataVariant& children_values = std::get<AggregateDataVariant>(rhs);
m_lhs.resize(children_values.size());
auto& tuple_value = m_lhs;
for (size_t i = 0; i < children_values.size(); ++i) {
std::visit(
[&](auto&& child_value) {
using T = std::decay_t<decltype(child_value)>;
if constexpr (std::is_same_v<T, ValueContentT>) {
tuple_value[i] = child_value;
} else if constexpr (std::is_arithmetic_v<ValueContentT> and
std::is_convertible_v<T, ValueContentT>) {
tuple_value[i] = static_cast<ValueContentT>(child_value);
} else if constexpr (std::is_same_v<std::string, ValueContentT>) {
tuple_value[i] = std::move(_stringify(child_value));
} else if constexpr (is_tiny_vector_v<ValueContentT>) {
if constexpr (std::is_arithmetic_v<T>) {
if constexpr (std::is_same_v<ValueContentT, TinyVector<1>>) {
tuple_value[i][0] = child_value;
} else {
// in this case a 0 is given
Assert(child_value == 0);
tuple_value[i] = ZeroType{};
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected error: unexpected right hand side type in affectation");
// LCOV_EXCL_STOP
}
} else if constexpr (is_tiny_matrix_v<ValueContentT>) {
if constexpr (std::is_arithmetic_v<T>) {
if constexpr (std::is_same_v<ValueContentT, TinyMatrix<1>>) {
tuple_value[i](0, 0) = child_value;
} else {
// in this case a 0 is given
Assert(child_value == 0);
tuple_value[i] = ZeroType{};
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected error: unexpected right hand side type in affectation");
// LCOV_EXCL_STOP
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected error: unexpected right hand side type in affectation");
// LCOV_EXCL_STOP
}
},
children_values[i]);
}
} else if constexpr (is_std_vector_v<ValueT>) {
using ValueContentT = typename ValueT::value_type;
m_lhs.resize(1);
auto& tuple_value = m_lhs;
std::visit(
[&](auto&& child_value) {
using T = std::decay_t<decltype(child_value)>;
if constexpr (std::is_same_v<T, ValueContentT>) {
tuple_value[0] = child_value;
} else if constexpr (std::is_arithmetic_v<ValueContentT> and
std::is_convertible_v<T, ValueContentT>) {
tuple_value[0] = static_cast<ValueContentT>(child_value);
} else if constexpr (std::is_same_v<std::string, ValueContentT>) {
tuple_value[0] = std::move(_stringify(child_value));
} else if constexpr (is_tiny_vector_v<ValueContentT>) {
if constexpr (std::is_arithmetic_v<T>) {
if constexpr (std::is_same_v<ValueContentT, TinyVector<1>>) {
tuple_value[0][0] = child_value;
} else {
// in this case a 0 is given
Assert(child_value == 0);
tuple_value[0] = ZeroType{};
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected error: unexpected right hand side type in affectation");
// LCOV_EXCL_STOP
}
} else if constexpr (is_tiny_matrix_v<ValueContentT>) {
if constexpr (std::is_arithmetic_v<T>) {
if constexpr (std::is_same_v<ValueContentT, TinyMatrix<1>>) {
tuple_value[0](0, 0) = child_value;
} else {
// in this case a 0 is given
Assert(child_value == 0);
tuple_value[0] = ZeroType{};
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected error: unexpected right hand side type in affectation");
// LCOV_EXCL_STOP
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected error: unexpected right hand side type in affectation");
// LCOV_EXCL_STOP
}
},
rhs);
} else {
// LCOV_EXCL_START
throw UnexpectedError("invalid value type");
// LCOV_EXCL_STOP
}
} else {
AffOp<OperatorT>().eval(m_lhs, std::get<DataT>(rhs));
}
}
} else if (std::is_same_v<OperatorT, language::eq_op>) {
m_lhs = ValueT{zero};
} else {
static_assert(std::is_same_v<OperatorT, language::eq_op>, "unexpected operator type");
}
}
}
};
template <typename OperatorT, typename ValueT, typename DataT>
class AffectationProcessor final : public INodeProcessor
{
private:
ASTNode& m_rhs_node;
std::unique_ptr<IAffectationExecutor> m_affectation_executor;
std::unique_ptr<IAffectationExecutor>
_buildAffectationExecutor(ASTNode& lhs_node)
{
if (lhs_node.is_type<language::name>()) {
const std::string& symbol = lhs_node.string();
auto [i_symbol, found] = lhs_node.m_symbol_table->find(symbol, lhs_node.begin());
Assert(found);
DataVariant& value = i_symbol->attributes().value();
if (not std::holds_alternative<ValueT>(value)) {
value = ValueT{};
}
using AffectationExecutorT = AffectationExecutor<OperatorT, ValueT, DataT>;
return std::make_unique<AffectationExecutorT>(lhs_node, std::get<ValueT>(value));
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: invalid lhs", std::vector{lhs_node.begin()});
// LCOV_EXCL_STOP
}
}
public:
DataVariant
execute(ExecutionPolicy& exec_policy)
{
m_affectation_executor->affect(exec_policy, m_rhs_node.execute(exec_policy));
return {};
}
AffectationProcessor(ASTNode& lhs_node, ASTNode& rhs_node)
: m_rhs_node{rhs_node}, m_affectation_executor{this->_buildAffectationExecutor(lhs_node)}
{}
};
class AffectationToDataVariantProcessorBase : public INodeProcessor
{
protected:
DataVariant* m_lhs;
public:
AffectationToDataVariantProcessorBase(ASTNode& lhs_node)
{
const std::string& symbol = lhs_node.string();
auto [i_symbol, found] = lhs_node.m_symbol_table->find(symbol, lhs_node.begin());
Assert(found);
m_lhs = &i_symbol->attributes().value();
}
virtual ~AffectationToDataVariantProcessorBase() = default;
};
template <typename ValueT>
class AffectationToTupleProcessor final : public AffectationToDataVariantProcessorBase
{
private:
ASTNode& m_rhs_node;
template <typename T>
std::string
_stringify(const T& value)
{
std::ostringstream os;
os << std::boolalpha << value;
return os.str();
}
public:
DataVariant
execute(ExecutionPolicy& exec_policy)
{
DataVariant value = m_rhs_node.execute(exec_policy);
std::visit(
[&](auto&& v) {
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<T, ValueT>) {
*m_lhs = std::vector{std::move(v)};
} else if constexpr (std::is_arithmetic_v<ValueT> and std::is_convertible_v<T, ValueT>) {
*m_lhs = std::vector{std::move(static_cast<ValueT>(v))};
} else if constexpr (std::is_same_v<std::string, ValueT>) {
*m_lhs = std::vector{std::move(_stringify(v))};
} else if constexpr (is_tiny_vector_v<ValueT> or is_tiny_matrix_v<ValueT>) {
if constexpr (std::is_same_v<ValueT, TinyVector<1>> and std::is_arithmetic_v<T>) {
*m_lhs = std::vector<TinyVector<1>>{TinyVector<1>{static_cast<double>(v)}};
} else if constexpr (std::is_same_v<ValueT, TinyMatrix<1>> and std::is_arithmetic_v<T>) {
*m_lhs = std::vector<TinyMatrix<1>>{TinyMatrix<1>{static_cast<double>(v)}};
} else if constexpr (std::is_same_v<T, int64_t>) {
Assert(v == 0);
*m_lhs = std::vector<ValueT>{ValueT{zero}};
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in affectation", m_rhs_node.begin());
// LCOV_EXCL_STOP
}
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in affectation", m_rhs_node.begin());
// LCOV_EXCL_STOP
}
},
value);
return {};
}
AffectationToTupleProcessor(ASTNode& lhs_node, ASTNode& rhs_node)
: AffectationToDataVariantProcessorBase(lhs_node), m_rhs_node{rhs_node}
{}
};
template <typename ValueT>
class AffectationToTupleFromListProcessor final : public AffectationToDataVariantProcessorBase
{
private:
ASTNode& m_rhs_node;
template <typename T>
std::string
_stringify(const T& value)
{
std::ostringstream os;
os << std::boolalpha << value;
return os.str();
}
void
_copyAggregateDataVariant(const AggregateDataVariant& children_values)
{
std::vector<ValueT> tuple_value(children_values.size());
for (size_t i = 0; i < children_values.size(); ++i) {
std::visit(
[&](auto&& child_value) {
using T = std::decay_t<decltype(child_value)>;
if constexpr (std::is_same_v<T, ValueT>) {
tuple_value[i] = child_value;
} else if constexpr (std::is_arithmetic_v<ValueT> and std::is_convertible_v<T, ValueT>) {
tuple_value[i] = static_cast<ValueT>(child_value);
} else if constexpr (std::is_same_v<std::string, ValueT>) {
tuple_value[i] = std::move(_stringify(child_value));
} else if constexpr (is_tiny_vector_v<ValueT>) {
if constexpr (std::is_arithmetic_v<T>) {
if constexpr (std::is_same_v<ValueT, TinyVector<1>>) {
tuple_value[i][0] = child_value;
} else {
// in this case a 0 is given
Assert(child_value == 0);
tuple_value[i] = ZeroType{};
}
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in affectation",
m_rhs_node.children[i]->begin());
// LCOV_EXCL_STOP
}
} else if constexpr (is_tiny_matrix_v<ValueT>) {
if constexpr (std::is_arithmetic_v<T>) {
if constexpr (std::is_same_v<ValueT, TinyMatrix<1>>) {
tuple_value[i](0, 0) = child_value;
} else {
// in this case a 0 is given
Assert(child_value == 0);
tuple_value[i] = ZeroType{};
}
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in affectation",
m_rhs_node.children[i]->begin());
// LCOV_EXCL_STOP
}
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in affectation",
m_rhs_node.children[i]->begin());
// LCOV_EXCL_STOP
}
},
children_values[i]);
}
*m_lhs = std::move(tuple_value);
}
template <typename DataType>
void
_copyVector(const std::vector<DataType>& values)
{
std::vector<ValueT> v(values.size());
if constexpr (std::is_same_v<ValueT, DataType>) {
for (size_t i = 0; i < values.size(); ++i) {
v[i] = values[i];
}
} else if constexpr (std::is_arithmetic_v<ValueT> and std::is_convertible_v<DataType, ValueT>) {
for (size_t i = 0; i < values.size(); ++i) {
v[i] = static_cast<DataType>(values[i]);
}
} else if constexpr (std::is_same_v<ValueT, std::string>) {
for (size_t i = 0; i < values.size(); ++i) {
v[i] = std::move(_stringify(values[i]));
}
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in tuple affectation", m_rhs_node.begin());
// LCOV_EXCL_STOP
}
*m_lhs = std::move(v);
}
public:
DataVariant
execute(ExecutionPolicy& exec_policy)
{
std::visit(
[&](auto&& value_list) {
using ValueListT = std::decay_t<decltype(value_list)>;
if constexpr (std::is_same_v<AggregateDataVariant, ValueListT>) {
this->_copyAggregateDataVariant(value_list);
} else if constexpr (is_std_vector_v<ValueListT>) {
this->_copyVector(value_list);
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: invalid lhs (expecting list or tuple)", std::vector{m_rhs_node.begin()});
// LCOV_EXCL_STOP
}
},
m_rhs_node.execute(exec_policy));
return {};
}
AffectationToTupleFromListProcessor(ASTNode& lhs_node, ASTNode& rhs_node)
: AffectationToDataVariantProcessorBase(lhs_node), m_rhs_node{rhs_node}
{}
};
template <typename ValueT>
class AffectationFromZeroProcessor final : public AffectationToDataVariantProcessorBase
{
public:
DataVariant
execute(ExecutionPolicy&)
{
*m_lhs = ValueT{zero};
return {};
}
AffectationFromZeroProcessor(ASTNode& lhs_node) : AffectationToDataVariantProcessorBase(lhs_node) {}
};
template <typename OperatorT>
class ListAffectationProcessor final : public INodeProcessor
{
private:
ASTNode& m_node;
std::vector<std::unique_ptr<IAffectationExecutor>> m_affectation_executor_list;
public:
template <typename ValueT, typename DataT>
void
add(ASTNode& lhs_node)
{
using AffectationExecutorT = AffectationExecutor<OperatorT, ValueT, DataT>;
if (lhs_node.is_type<language::name>()) {
const std::string& symbol = lhs_node.string();
auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->end());
Assert(found);
DataVariant& value = i_symbol->attributes().value();
if (not std::holds_alternative<ValueT>(value)) {
value = ValueT{};
}
m_affectation_executor_list.emplace_back(std::make_unique<AffectationExecutorT>(m_node, std::get<ValueT>(value)));
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: invalid left hand side", std::vector{lhs_node.begin()});
// LCOV_EXCL_STOP
}
}
DataVariant
execute(ExecutionPolicy& exec_policy)
{
AggregateDataVariant children_values = std::get<AggregateDataVariant>(m_node.children[1]->execute(exec_policy));
Assert(m_affectation_executor_list.size() == children_values.size());
for (size_t i = 0; i < m_affectation_executor_list.size(); ++i) {
m_affectation_executor_list[i]->affect(exec_policy, std::move(children_values[i]));
}
return {};
}
ListAffectationProcessor(ASTNode& node) : m_node{node} {}
};
#endif // AFFECTATION_PROCESSOR_HPP