Select Git revision
MeshModule.cpp
-
Stéphane Del Pino authoredStéphane Del Pino authored
AffectationProcessor.hpp 35.74 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;
}()};
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 if constexpr (std::is_arithmetic_v<DataT>) {
m_lhs = std::to_string(std::get<DataT>(rhs));
} else {
std::ostringstream os;
os << std::get<DataT>(rhs);
m_lhs = os.str();
}
} else {
if constexpr (std::is_same_v<std::string, DataT>) {
m_lhs += std::get<std::string>(rhs);
} else if constexpr (std::is_arithmetic_v<DataT>) {
m_lhs += std::to_string(std::get<DataT>(rhs));
} else {
std::ostringstream os;
os << std::get<DataT>(rhs);
m_lhs += os.str();
}
}
} else {
if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
if constexpr (std::is_convertible_v<ValueT, DataT>) {
m_lhs = std::get<DataT>(rhs);
} else if constexpr (std::is_same_v<DataT, AggregateDataVariant>) {
const AggregateDataVariant& v = std::get<AggregateDataVariant>(rhs);
static_assert(is_tiny_vector_v<ValueT>, "expecting lhs TinyVector");
for (size_t i = 0; i < m_lhs.dimension(); ++i) {
std::visit(
[&](auto&& vi) {
using Vi_T = std::decay_t<decltype(vi)>;
if constexpr (std::is_convertible_v<Vi_T, double>) {
m_lhs[i] = vi;
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected rhs type in affectation");
// LCOV_EXCL_STOP
}
},
v[i]);
}
} 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 = 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 = v;
} else {
// LCOV_EXCL_START
throw UnexpectedError("unexpected rhs type in affectation");
// LCOV_EXCL_STOP
}
},
rhs);
} else {
throw UnexpectedError("invalid value type");
}
} 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 ArrayT, typename ValueT, typename DataT>
class MatrixComponentAffectationExecutor final : public IAffectationExecutor
{
private:
ArrayT& m_lhs_array;
ASTNode& m_index0_expression;
ASTNode& m_index1_expression;
static inline const bool m_is_defined{[] {
if constexpr (not std::is_same_v<typename ArrayT::data_type, ValueT>) {
return false;
} else 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;
}()};
public:
MatrixComponentAffectationExecutor(ASTNode& node,
ArrayT& lhs_array,
ASTNode& index0_expression,
ASTNode& index1_expression)
: m_lhs_array{lhs_array}, m_index0_expression{index0_expression}, m_index1_expression{index1_expression}
{
// 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& exec_policy, DataVariant&& rhs)
{
if constexpr (m_is_defined) {
auto get_index_value = [&](DataVariant&& value_variant) -> int64_t {
int64_t index_value = 0;
std::visit(
[&](auto&& value) {
using IndexValueT = std::decay_t<decltype(value)>;
if constexpr (std::is_integral_v<IndexValueT>) {
index_value = value;
} else {
// LCOV_EXCL_START
throw UnexpectedError("invalid index type");
// LCOV_EXCL_STOP
}
},
value_variant);
return index_value;
};
const int64_t index0_value = get_index_value(m_index0_expression.execute(exec_policy));
const int64_t index1_value = get_index_value(m_index1_expression.execute(exec_policy));
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_array(index0_value, index1_value) = std::get<DataT>(rhs);
} else {
m_lhs_array(index0_value, index1_value) = std::to_string(std::get<DataT>(rhs));
}
} else {
if constexpr (std::is_same_v<std::string, DataT>) {
m_lhs_array(index0_value, index1_value) += std::get<std::string>(rhs);
} else {
m_lhs_array(index0_value, index1_value) += std::to_string(std::get<DataT>(rhs));
}
}
} else {
if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
if constexpr (std::is_same_v<ValueT, DataT>) {
m_lhs_array(index0_value, index1_value) = std::get<DataT>(rhs);
} else {
m_lhs_array(index0_value, index1_value) = static_cast<ValueT>(std::get<DataT>(rhs));
}
} else {
AffOp<OperatorT>().eval(m_lhs_array(index0_value, index1_value), std::get<DataT>(rhs));
}
}
}
}
};
template <typename OperatorT, typename ArrayT, typename ValueT, typename DataT>
class VectorComponentAffectationExecutor final : public IAffectationExecutor
{
private:
ArrayT& m_lhs_array;
ASTNode& m_index_expression;
static inline const bool m_is_defined{[] {
if constexpr (not std::is_same_v<typename ArrayT::data_type, ValueT>) {
return false;
} else 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;
}()};
public:
VectorComponentAffectationExecutor(ASTNode& node, ArrayT& lhs_array, ASTNode& index_expression)
: m_lhs_array{lhs_array}, m_index_expression{index_expression}
{
// 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& exec_policy, DataVariant&& rhs)
{
if constexpr (m_is_defined) {
const int64_t index_value = [&](DataVariant&& value_variant) -> int64_t {
int64_t index_value = 0;
std::visit(
[&](auto&& value) {
using IndexValueT = std::decay_t<decltype(value)>;
if constexpr (std::is_integral_v<IndexValueT>) {
index_value = value;
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: invalid index type", std::vector{m_index_expression.begin()});
// LCOV_EXCL_STOP
}
},
value_variant);
return index_value;
}(m_index_expression.execute(exec_policy));
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_array[index_value] = std::get<DataT>(rhs);
} else {
m_lhs_array[index_value] = std::to_string(std::get<DataT>(rhs));
}
} else {
if constexpr (std::is_same_v<std::string, DataT>) {
m_lhs_array[index_value] += std::get<std::string>(rhs);
} else {
m_lhs_array[index_value] += std::to_string(std::get<DataT>(rhs));
}
}
} else {
if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
if constexpr (std::is_same_v<ValueT, DataT>) {
m_lhs_array[index_value] = std::get<DataT>(rhs);
} else {
m_lhs_array[index_value] = static_cast<ValueT>(std::get<DataT>(rhs));
}
} else {
AffOp<OperatorT>().eval(m_lhs_array[index_value], std::get<DataT>(rhs));
}
}
}
}
};
template <typename OperatorT, typename ValueT, typename DataT>
class AffectationProcessor final : public INodeProcessor
{
private:
ASTNode& m_node;
std::unique_ptr<IAffectationExecutor> m_affectation_executor;
public:
DataVariant
execute(ExecutionPolicy& exec_policy)
{
m_affectation_executor->affect(exec_policy, m_node.children[1]->execute(exec_policy));
return {};
}
AffectationProcessor(ASTNode& node) : m_node{node}
{
if (node.children[0]->is_type<language::name>()) {
const std::string& symbol = m_node.children[0]->string();
auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin());
Assert(found);
DataVariant& value = i_symbol->attributes().value();
if (not std::holds_alternative<ValueT>(value)) {
value = ValueT{};
}
using AffectationExecutorT = AffectationExecutor<OperatorT, ValueT, DataT>;
m_affectation_executor = std::make_unique<AffectationExecutorT>(m_node, std::get<ValueT>(value));
} else if (node.children[0]->is_type<language::subscript_expression>()) {
auto& array_subscript_expression = *node.children[0];
auto& array_expression = *array_subscript_expression.children[0];
Assert(array_expression.is_type<language::name>());
const std::string& symbol = array_expression.string();
auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, array_subscript_expression.begin());
Assert(found);
DataVariant& value = i_symbol->attributes().value();
if (array_expression.m_data_type == ASTNodeDataType::vector_t) {
Assert(array_subscript_expression.children.size() == 2);
auto& index_expression = *array_subscript_expression.children[1];
switch (array_expression.m_data_type.dimension()) {
case 1: {
using ArrayTypeT = TinyVector<1>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = VectorComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor =
std::make_unique<AffectationExecutorT>(node, std::get<ArrayTypeT>(value), index_expression);
break;
}
case 2: {
using ArrayTypeT = TinyVector<2>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = VectorComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor =
std::make_unique<AffectationExecutorT>(node, std::get<ArrayTypeT>(value), index_expression);
break;
}
case 3: {
using ArrayTypeT = TinyVector<3>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = VectorComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor =
std::make_unique<AffectationExecutorT>(node, std::get<ArrayTypeT>(value), index_expression);
break;
}
// LCOV_EXCL_START
default: {
throw ParseError("unexpected error: invalid vector dimension",
std::vector{array_subscript_expression.begin()});
}
// LCOV_EXCL_STOP
}
} else if (array_expression.m_data_type == ASTNodeDataType::matrix_t) {
Assert(array_subscript_expression.children.size() == 3);
Assert(array_expression.m_data_type.nbRows() == array_expression.m_data_type.nbColumns());
auto& index0_expression = *array_subscript_expression.children[1];
auto& index1_expression = *array_subscript_expression.children[2];
switch (array_expression.m_data_type.nbRows()) {
case 1: {
using ArrayTypeT = TinyMatrix<1>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = MatrixComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor = std::make_unique<AffectationExecutorT>(node, std::get<ArrayTypeT>(value),
index0_expression, index1_expression);
break;
}
case 2: {
using ArrayTypeT = TinyMatrix<2>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = MatrixComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor = std::make_unique<AffectationExecutorT>(node, std::get<ArrayTypeT>(value),
index0_expression, index1_expression);
break;
}
case 3: {
using ArrayTypeT = TinyMatrix<3>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = MatrixComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor = std::make_unique<AffectationExecutorT>(node, std::get<ArrayTypeT>(value),
index0_expression, index1_expression);
break;
}
// LCOV_EXCL_START
default: {
throw ParseError("unexpected error: invalid vector dimension",
std::vector{array_subscript_expression.begin()});
}
// LCOV_EXCL_STOP
}
} else {
// LCOV_EXCL_START
throw UnexpectedError("invalid subscript expression");
// LCOV_EXCL_STOP
}
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: invalid lhs", std::vector{node.children[0]->begin()});
// LCOV_EXCL_STOP
}
}
};
template <typename OperatorT, typename ValueT>
class AffectationToTinyVectorFromListProcessor final : public INodeProcessor
{
private:
ASTNode& m_node;
DataVariant* m_lhs;
public:
DataVariant
execute(ExecutionPolicy& exec_policy)
{
AggregateDataVariant children_values = std::get<AggregateDataVariant>(m_node.children[1]->execute(exec_policy));
static_assert(std::is_same_v<OperatorT, language::eq_op>, "forbidden affection operator for list to vectors");
ValueT v;
for (size_t i = 0; i < v.dimension(); ++i) {
std::visit(
[&](auto&& child_value) {
using T = std::decay_t<decltype(child_value)>;
if constexpr (std::is_same_v<T, bool> or std::is_same_v<T, uint64_t> or std::is_same_v<T, int64_t> or
std::is_same_v<T, double>) {
v[i] = child_value;
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in affectation", m_node.begin());
// LCOV_EXCL_STOP
}
},
children_values[i]);
}
*m_lhs = v;
return {};
}
AffectationToTinyVectorFromListProcessor(ASTNode& node) : m_node{node}
{
const std::string& symbol = m_node.children[0]->string();
auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin());
Assert(found);
m_lhs = &i_symbol->attributes().value();
}
};
template <typename OperatorT, typename ValueT>
class AffectationToTinyMatrixFromListProcessor final : public INodeProcessor
{
private:
ASTNode& m_node;
DataVariant* m_lhs;
public:
DataVariant
execute(ExecutionPolicy& exec_policy)
{
AggregateDataVariant children_values = std::get<AggregateDataVariant>(m_node.children[1]->execute(exec_policy));
static_assert(std::is_same_v<OperatorT, language::eq_op>, "forbidden affection operator for list to vectors");
ValueT v;
for (size_t i = 0, l = 0; i < v.nbRows(); ++i) {
for (size_t j = 0; j < v.nbColumns(); ++j, ++l) {
std::visit(
[&](auto&& child_value) {
using T = std::decay_t<decltype(child_value)>;
if constexpr (std::is_same_v<T, bool> or std::is_same_v<T, uint64_t> or std::is_same_v<T, int64_t> or
std::is_same_v<T, double>) {
v(i, j) = child_value;
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in affectation", m_node.begin());
// LCOV_EXCL_STOP
}
},
children_values[l]);
}
}
*m_lhs = v;
return {};
}
AffectationToTinyMatrixFromListProcessor(ASTNode& node) : m_node{node}
{
const std::string& symbol = m_node.children[0]->string();
auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin());
Assert(found);
m_lhs = &i_symbol->attributes().value();
}
};
template <typename ValueT>
class AffectationToTupleProcessor final : public INodeProcessor
{
private:
ASTNode& m_node;
DataVariant* m_lhs;
public:
DataVariant
execute(ExecutionPolicy& exec_policy)
{
DataVariant value = m_node.children[1]->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>) {
if constexpr (std::is_arithmetic_v<T>) {
*m_lhs = std::vector{std::move(std::to_string(v))};
} else {
std::ostringstream os;
os << v;
*m_lhs = std::vector<std::string>{os.str()};
}
} 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_node.begin());
// LCOV_EXCL_STOP
}
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in affectation", m_node.begin());
// LCOV_EXCL_STOP
}
},
value);
return {};
}
AffectationToTupleProcessor(ASTNode& node) : m_node{node}
{
const std::string& symbol = m_node.children[0]->string();
auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin());
Assert(found);
m_lhs = &i_symbol->attributes().value();
}
};
template <typename ValueT>
class AffectationToTupleFromListProcessor final : public INodeProcessor
{
private:
ASTNode& m_node;
DataVariant* m_lhs;
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>) {
if constexpr (std::is_arithmetic_v<T>) {
tuple_value[i] = std::to_string(child_value);
} else {
std::ostringstream os;
os << child_value;
tuple_value[i] = os.str();
}
} else if constexpr (is_tiny_vector_v<ValueT>) {
if constexpr (std::is_same_v<T, AggregateDataVariant>) {
ValueT& v = tuple_value[i];
Assert(ValueT::Dimension == child_value.size());
for (size_t j = 0; j < ValueT::Dimension; ++j) {
std::visit(
[&](auto&& vj) {
using Ti = std::decay_t<decltype(vj)>;
if constexpr (std::is_convertible_v<Ti, typename ValueT::data_type>) {
v[j] = vj;
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in affectation",
m_node.children[1]->children[i]->begin());
// LCOV_EXCL_STOP
}
},
child_value[j]);
}
} else 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_node.children[1]->children[i]->begin());
// LCOV_EXCL_STOP
}
} else if constexpr (is_tiny_matrix_v<ValueT>) {
if constexpr (std::is_same_v<T, AggregateDataVariant>) {
ValueT& A = tuple_value[i];
Assert(A.nbRows() * A.nbColumns() == child_value.size());
for (size_t j = 0, l = 0; j < A.nbRows(); ++j) {
for (size_t k = 0; k < A.nbColumns(); ++k, ++l) {
std::visit(
[&](auto&& Ajk) {
using Ti = std::decay_t<decltype(Ajk)>;
if constexpr (std::is_convertible_v<Ti, typename ValueT::data_type>) {
A(j, k) = Ajk;
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in affectation",
m_node.children[1]->children[i]->begin());
// LCOV_EXCL_STOP
}
},
child_value[l]);
}
}
} else 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_node.children[1]->children[i]->begin());
// LCOV_EXCL_STOP
}
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in affectation",
m_node.children[1]->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>) {
if constexpr (std::is_arithmetic_v<DataType>) {
for (size_t i = 0; i < values.size(); ++i) {
v[i] = std::to_string(values[i]);
}
} else {
for (size_t i = 0; i < values.size(); ++i) {
std::ostringstream sout;
sout << values[i];
v[i] = sout.str();
}
}
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: unexpected right hand side type in tuple affectation",
m_node.children[1]->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_node.children[1]->begin()});
// LCOV_EXCL_STOP
}
},
m_node.children[1]->execute(exec_policy));
return {};
}
AffectationToTupleFromListProcessor(ASTNode& node) : m_node{node}
{
const std::string& symbol = m_node.children[0]->string();
auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin());
Assert(found);
m_lhs = &i_symbol->attributes().value();
}
};
template <typename ValueT>
class AffectationFromZeroProcessor final : public INodeProcessor
{
private:
ASTNode& m_node;
DataVariant* m_lhs;
public:
DataVariant
execute(ExecutionPolicy&)
{
*m_lhs = ValueT{zero};
return {};
}
AffectationFromZeroProcessor(ASTNode& node) : m_node{node}
{
const std::string& symbol = m_node.children[0]->string();
auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, m_node.children[0]->begin());
Assert(found);
m_lhs = &i_symbol->attributes().value();
}
};
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 if (lhs_node.is_type<language::subscript_expression>()) {
auto& array_subscript_expression = lhs_node;
auto& array_expression = *array_subscript_expression.children[0];
Assert(array_expression.is_type<language::name>());
const std::string& symbol = array_expression.string();
auto [i_symbol, found] = m_node.m_symbol_table->find(symbol, array_subscript_expression.begin());
Assert(found);
DataVariant& value = i_symbol->attributes().value();
if (array_expression.m_data_type == ASTNodeDataType::vector_t) {
Assert(array_subscript_expression.children.size() == 2);
auto& index_expression = *array_subscript_expression.children[1];
switch (array_expression.m_data_type.dimension()) {
case 1: {
using ArrayTypeT = TinyVector<1>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = VectorComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor_list.emplace_back(
std::make_unique<AffectationExecutorT>(lhs_node, std::get<ArrayTypeT>(value), index_expression));
break;
}
case 2: {
using ArrayTypeT = TinyVector<2>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = VectorComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor_list.emplace_back(
std::make_unique<AffectationExecutorT>(lhs_node, std::get<ArrayTypeT>(value), index_expression));
break;
}
case 3: {
using ArrayTypeT = TinyVector<3>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = VectorComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor_list.emplace_back(
std::make_unique<AffectationExecutorT>(lhs_node, std::get<ArrayTypeT>(value), index_expression));
break;
}
// LCOV_EXCL_START
default: {
throw ParseError("unexpected error: invalid vector dimension",
std::vector{array_subscript_expression.begin()});
}
// LCOV_EXCL_STOP
}
} else if (array_expression.m_data_type == ASTNodeDataType::matrix_t) {
Assert(array_subscript_expression.children.size() == 3);
auto& index0_expression = *array_subscript_expression.children[1];
auto& index1_expression = *array_subscript_expression.children[2];
Assert(array_expression.m_data_type.nbRows() == array_expression.m_data_type.nbColumns());
switch (array_expression.m_data_type.nbRows()) {
case 1: {
using ArrayTypeT = TinyMatrix<1>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = MatrixComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor_list.emplace_back(
std::make_unique<AffectationExecutorT>(lhs_node, std::get<ArrayTypeT>(value), index0_expression,
index1_expression));
break;
}
case 2: {
using ArrayTypeT = TinyMatrix<2>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = MatrixComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor_list.emplace_back(
std::make_unique<AffectationExecutorT>(lhs_node, std::get<ArrayTypeT>(value), index0_expression,
index1_expression));
break;
}
case 3: {
using ArrayTypeT = TinyMatrix<3>;
if (not std::holds_alternative<ArrayTypeT>(value)) {
value = ArrayTypeT{};
}
using AffectationExecutorT = MatrixComponentAffectationExecutor<OperatorT, ArrayTypeT, ValueT, DataT>;
m_affectation_executor_list.emplace_back(
std::make_unique<AffectationExecutorT>(lhs_node, std::get<ArrayTypeT>(value), index0_expression,
index1_expression));
break;
}
// LCOV_EXCL_START
default: {
throw ParseError("unexpected error: invalid vector dimension",
std::vector{array_subscript_expression.begin()});
}
// LCOV_EXCL_STOP
}
}
} 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