diff --git a/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp b/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp index f7e0627cb03acddf10e8b5d03dbb0699fdb6bd4a..ec499edb30589824b5578dbc0701db0b3639166b 100644 --- a/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp +++ b/src/language/ast/ASTNodeListAffectationExpressionBuilder.cpp @@ -9,6 +9,371 @@ #include <language/utils/AffectationMangler.hpp> #include <language/utils/OperatorRepository.hpp> +template <typename OperatorT, typename TupleContentType> +void +ASTNodeListAffectationExpressionBuilder::_buildListAffectationFromTupleProcessor( + ListAffectationFromTupleProcessor<OperatorT, TupleContentType>& list_affectation_processor) +{ + ASTNode& name_list_node = *m_node.children[0]; + for (size_t i = 0; i < name_list_node.children.size(); ++i) { + ASTNode& value_node = *name_list_node.children[i]; + if constexpr (std::is_same_v<TupleContentType, bool>) { + switch (value_node.m_data_type) { + case ASTNodeDataType::bool_t: { + list_affectation_processor.template add<bool>(value_node); + break; + } + case ASTNodeDataType::unsigned_int_t: { + list_affectation_processor.template add<uint64_t>(value_node); + break; + } + case ASTNodeDataType::int_t: { + list_affectation_processor.template add<int64_t>(value_node); + break; + } + case ASTNodeDataType::double_t: { + list_affectation_processor.template add<double>(value_node); + break; + } + case ASTNodeDataType::vector_t: { + if (value_node.m_data_type.dimension() == 1) { + list_affectation_processor.template add<TinyVector<1>>(value_node); + } else { + // LCOV_EXCL_START + throw UnexpectedError("invalid vector dimension"); + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::matrix_t: { + if ((value_node.m_data_type.numberOfRows() == 1) and (value_node.m_data_type.numberOfColumns() == 1)) { + list_affectation_processor.template add<TinyMatrix<1>>(value_node); + } else { + // LCOV_EXCL_START + throw UnexpectedError("invalid vector dimension"); + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::string_t: { + list_affectation_processor.template add<std::string>(value_node); + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("incompatible tuple types in affectation"); + } + // LCOV_EXCL_STOP + } + } else if constexpr ((std::is_same_v<TupleContentType, uint64_t>) or (std::is_same_v<TupleContentType, int64_t>)) { + switch (value_node.m_data_type) { + case ASTNodeDataType::unsigned_int_t: { + list_affectation_processor.template add<uint64_t>(value_node); + break; + } + case ASTNodeDataType::int_t: { + list_affectation_processor.template add<int64_t>(value_node); + break; + } + case ASTNodeDataType::double_t: { + list_affectation_processor.template add<double>(value_node); + break; + } + case ASTNodeDataType::vector_t: { + if (value_node.m_data_type.dimension() == 1) { + list_affectation_processor.template add<TinyVector<1>>(value_node); + } else { + // LCOV_EXCL_START + throw UnexpectedError("invalid vector dimension"); + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::matrix_t: { + if ((value_node.m_data_type.numberOfRows() == 1) and (value_node.m_data_type.numberOfColumns() == 1)) { + list_affectation_processor.template add<TinyMatrix<1>>(value_node); + } else { + // LCOV_EXCL_START + throw UnexpectedError("invalid vector dimension"); + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::string_t: { + list_affectation_processor.template add<std::string>(value_node); + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("incompatible tuple types in affectation"); + } + // LCOV_EXCL_STOP + } + } else if constexpr (std::is_same_v<TupleContentType, double>) { + switch (value_node.m_data_type) { + case ASTNodeDataType::double_t: { + list_affectation_processor.template add<double>(value_node); + break; + } + case ASTNodeDataType::vector_t: { + if (value_node.m_data_type.dimension() == 1) { + list_affectation_processor.template add<TinyVector<1>>(value_node); + } else { + // LCOV_EXCL_START + throw UnexpectedError("invalid vector dimension"); + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::matrix_t: { + if ((value_node.m_data_type.numberOfRows() == 1) and (value_node.m_data_type.numberOfColumns() == 1)) { + list_affectation_processor.template add<TinyMatrix<1>>(value_node); + } else { + // LCOV_EXCL_START + throw UnexpectedError("invalid vector dimension"); + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::string_t: { + list_affectation_processor.template add<std::string>(value_node); + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("incompatible tuple types in affectation"); + } + // LCOV_EXCL_STOP + } + } else if constexpr (is_tiny_vector_v<TupleContentType>) { + switch (value_node.m_data_type) { + case ASTNodeDataType::vector_t: { + if (value_node.m_data_type.dimension() == TupleContentType::Dimension) { + list_affectation_processor.template add<TupleContentType>(value_node); + } else { + // LCOV_EXCL_START + throw UnexpectedError("invalid vector dimension"); + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::string_t: { + list_affectation_processor.template add<std::string>(value_node); + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("incompatible tuple types in affectation"); + } + // LCOV_EXCL_STOP + } + } else if constexpr (is_tiny_matrix_v<TupleContentType>) { + switch (value_node.m_data_type) { + case ASTNodeDataType::matrix_t: { + if ((value_node.m_data_type.numberOfRows() == TupleContentType::NumberOfRows) and + (value_node.m_data_type.numberOfColumns() == TupleContentType::NumberOfColumns)) { + list_affectation_processor.template add<TupleContentType>(value_node); + } else { + // LCOV_EXCL_START + throw UnexpectedError("invalid vector dimension"); + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::string_t: { + list_affectation_processor.template add<std::string>(value_node); + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("incompatible tuple types in affectation"); + } + // LCOV_EXCL_STOP + } + } else if constexpr (std::is_same_v<std::string, TupleContentType>) { + if (value_node.m_data_type == ASTNodeDataType::string_t) { + list_affectation_processor.template add<std::string>(value_node); + } else { + // LCOV_EXCL_START + throw UnexpectedError("incompatible tuple types in affectation"); + // LCOV_EXCL_STOP + } + } else if constexpr (std::is_same_v<EmbeddedData, TupleContentType>) { + if (value_node.m_data_type == ASTNodeDataType::type_id_t) { + list_affectation_processor.template add<EmbeddedData>(value_node); + } else { + // LCOV_EXCL_START + throw UnexpectedError("incompatible tuple types in affectation"); + // LCOV_EXCL_STOP + } + } else { + // LCOV_EXCL_START + throw UnexpectedError("incompatible tuple types in affectation"); + // LCOV_EXCL_STOP + } + } +} + +template <typename OperatorT> +void +ASTNodeListAffectationExpressionBuilder::_buildListAffectationFromTupleProcessor() +{ + auto& rhs = *m_node.children[1]; + + Assert(rhs.m_data_type == ASTNodeDataType::tuple_t); + + const ASTNodeSubDataType tuple_content_type{rhs.m_data_type.contentType(), rhs}; + + for (auto&& child : m_node.children[0]->children) { + if (child->m_data_type == ASTNodeDataType::tuple_t) { + throw ParseError("cannot affect a tuple to a compound type made of tuples", std::vector{child->begin()}); + } + + ASTNodeNaturalConversionChecker<AllowRToR1Conversion>(tuple_content_type, child->m_data_type); + } + + switch (rhs.m_data_type.contentType()) { + case ASTNodeDataType::bool_t: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, bool>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + case ASTNodeDataType::unsigned_int_t: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, uint64_t>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + case ASTNodeDataType::int_t: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, int64_t>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + case ASTNodeDataType::double_t: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, double>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + case ASTNodeDataType::vector_t: { + switch (rhs.m_data_type.contentType().dimension()) { + case 1: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, TinyVector<1>>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + case 2: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, TinyVector<2>>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + case 3: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, TinyVector<3>>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid vector dimension"); + } + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::matrix_t: { + if (rhs.m_data_type.contentType().numberOfColumns() != rhs.m_data_type.contentType().numberOfRows()) { + // LCOV_EXCL_START + throw UnexpectedError("invalid matrix dimensions"); + // LCOV_EXCL_STOP + } + switch (rhs.m_data_type.contentType().numberOfColumns()) { + case 1: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, TinyMatrix<1>>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + case 2: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, TinyMatrix<2>>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + case 3: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, TinyMatrix<3>>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid matrix dimensions"); + } + // LCOV_EXCL_STOP + } + break; + } + case ASTNodeDataType::string_t: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, std::string>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + case ASTNodeDataType::type_id_t: { + std::unique_ptr list_affectation_processor = + std::make_unique<ListAffectationFromTupleProcessor<OperatorT, EmbeddedData>>(m_node); + + this->_buildListAffectationFromTupleProcessor(*list_affectation_processor); + + m_node.m_node_processor = std::move(list_affectation_processor); + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("undefined affectation type"); + } + // LCOV_EXCL_STOP + } +} + template <typename OperatorT> void ASTNodeListAffectationExpressionBuilder::_buildAffectationProcessor( @@ -905,9 +1270,14 @@ ASTNodeListAffectationExpressionBuilder::_buildListAffectationProcessor() ASTNodeListAffectationExpressionBuilder::ASTNodeListAffectationExpressionBuilder(ASTNode& node) : m_node(node) { if (node.children[1]->is_type<language::expression_list>() or - node.children[1]->is_type<language::function_evaluation>()) { + node.children[1]->is_type<language::function_evaluation>() or + (node.children[1]->m_data_type == ASTNodeDataType::tuple_t)) { if (node.is_type<language::eq_op>()) { - this->_buildListAffectationProcessor<language::eq_op>(); + if (node.children[1]->m_data_type == ASTNodeDataType::tuple_t) { + this->_buildListAffectationFromTupleProcessor<language::eq_op>(); + } else { + this->_buildListAffectationProcessor<language::eq_op>(); + } } else { throw ParseError("undefined affectation operator for lists", std::vector{node.begin()}); } diff --git a/src/language/ast/ASTNodeListAffectationExpressionBuilder.hpp b/src/language/ast/ASTNodeListAffectationExpressionBuilder.hpp index 50aaf94d27d364ecb5f40a3b125e09470c4b9d56..1cda4a94402b9d1803e0731484bf51a4eb8c2a14 100644 --- a/src/language/ast/ASTNodeListAffectationExpressionBuilder.hpp +++ b/src/language/ast/ASTNodeListAffectationExpressionBuilder.hpp @@ -4,6 +4,9 @@ #include <language/ast/ASTNode.hpp> #include <language/ast/ASTNodeSubDataType.hpp> +template <typename OperatorT, typename TupleType> +class ListAffectationFromTupleProcessor; + template <typename OperatorT> class ListAffectationProcessor; @@ -12,6 +15,12 @@ class ASTNodeListAffectationExpressionBuilder private: ASTNode& m_node; + template <typename OperatorT, typename TupleContentType> + void _buildListAffectationFromTupleProcessor(ListAffectationFromTupleProcessor<OperatorT, TupleContentType>&); + + template <typename OperatorT> + void _buildListAffectationFromTupleProcessor(); + template <typename OperatorT> void _buildAffectationProcessor(const ASTNodeSubDataType& rhs_node_sub_data_type, ASTNode& value_node, diff --git a/src/language/node_processor/AffectationProcessor.hpp b/src/language/node_processor/AffectationProcessor.hpp index 4aaace91aacd89b44eb2be5f6ce4e080c5420413..8fea3a7546b9f96298e97b0603a849c84915f47a 100644 --- a/src/language/node_processor/AffectationProcessor.hpp +++ b/src/language/node_processor/AffectationProcessor.hpp @@ -82,7 +82,7 @@ struct AffOp<language::minuseq_op> struct IAffectationExecutor { - virtual void affect(ExecutionPolicy& exec_policy, DataVariant&& rhs) = 0; + virtual void affect(DataVariant&& rhs) = 0; IAffectationExecutor(const IAffectationExecutor&) = delete; IAffectationExecutor(IAffectationExecutor&&) = delete; @@ -101,9 +101,7 @@ class AffectationExecutor final : public IAffectationExecutor 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 std::is_same_v<OperatorT, language::eq_op>; } return true; }()}; @@ -119,7 +117,7 @@ class AffectationExecutor final : public IAffectationExecutor } PUGS_INLINE void - affect(ExecutionPolicy&, DataVariant&& rhs) + affect(DataVariant&& rhs) { if constexpr (m_is_defined) { if constexpr (not std::is_same_v<DataT, ZeroType>) { @@ -459,7 +457,7 @@ class AffectationProcessor final : public INodeProcessor execute(ExecutionPolicy& exec_policy) { try { - m_affectation_executor->affect(exec_policy, m_rhs_node.execute(exec_policy)); + m_affectation_executor->affect(m_rhs_node.execute(exec_policy)); } catch (std::domain_error& e) { throw ParseError(e.what(), m_rhs_node.begin()); @@ -620,15 +618,6 @@ class AffectationToTupleFromListProcessor final : public AffectationToDataVarian 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) { @@ -727,15 +716,6 @@ class AffectationToTupleFromTupleProcessor final : public AffectationToDataVaria private: ASTNode& m_rhs_node; - template <typename T> - std::string - stringify(const T& value) - { - std::ostringstream os; - os << std::boolalpha << value; - return os.str(); - } - template <typename DataType> void _copyVector(const std::vector<DataType>& values) @@ -857,7 +837,7 @@ class ListAffectationProcessor final : public INodeProcessor Assert(m_affectation_executor_list.size() == children_values.size()); for (size_t i = 0; i < m_affectation_executor_list.size(); ++i) { try { - m_affectation_executor_list[i]->affect(exec_policy, std::move(children_values[i])); + m_affectation_executor_list[i]->affect(std::move(children_values[i])); } catch (std::domain_error& e) { throw ParseError(e.what(), m_node.children[1]->children[i]->begin()); @@ -869,4 +849,123 @@ class ListAffectationProcessor final : public INodeProcessor ListAffectationProcessor(ASTNode& node) : m_node{node} {} }; +struct IAffectationFromTupleExecutor +{ + virtual void affect(ExecutionPolicy& exec_policy, DataVariant&& rhs) = 0; + + IAffectationFromTupleExecutor(const IAffectationFromTupleExecutor&) = delete; + IAffectationFromTupleExecutor(IAffectationFromTupleExecutor&&) = delete; + + IAffectationFromTupleExecutor() = default; + + virtual ~IAffectationFromTupleExecutor() = default; +}; + +template <typename OperatorT, typename ValueT, typename DataT> +class AffectationFromTupleExecutor final : public IAffectationFromTupleExecutor +{ + private: + DataVariant& m_lhs; + ASTNode& m_node; + + static_assert(std::is_same_v<OperatorT, language::eq_op>); + + public: + AffectationFromTupleExecutor(ASTNode& node, DataVariant& lhs) : m_lhs{lhs}, m_node{node} {} + + PUGS_INLINE void + affect(ExecutionPolicy&, DataVariant&& rhs) final + { + if constexpr (std::is_same_v<DataT, ValueT>) { + m_lhs = rhs; + } else if constexpr (std::is_convertible_v<DataT, ValueT>) { + const DataT& v = std::get<DataT>(rhs); + if constexpr (std::is_same_v<int64_t, DataT> and std::is_same_v<uint64_t, ValueT>) { + if (v < 0) { + throw std::domain_error("trying to affect negative value (" + stringify(v) + ")"); + } + } + m_lhs = static_cast<ValueT>(v); + } else if constexpr ((std::is_same_v<ValueT, TinyVector<1>>)and(std::is_arithmetic_v<DataT>)) { + m_lhs = std::move(ValueT(std::get<DataT>(rhs))); + } else if constexpr ((std::is_same_v<ValueT, TinyMatrix<1>>)and(std::is_arithmetic_v<DataT>)) { + m_lhs = std::move(ValueT(std::get<DataT>(rhs))); + } else if constexpr (std::is_same_v<ValueT, std::string>) { + m_lhs = std::move(stringify(std::get<DataT>(rhs))); + } else { + // LCOV_EXCL_START + throw UnexpectedError("incompatible types in affectation from tuple"); + // LCOV_EXCL_STOP + } + } +}; + +template <typename OperatorT, typename TupleContentType> +class ListAffectationFromTupleProcessor final : public INodeProcessor +{ + public: + static_assert(not is_std_vector_v<TupleContentType>); + + private: + ASTNode& m_node; + + std::vector<std::unique_ptr<IAffectationFromTupleExecutor>> m_affectation_executor_list; + + public: + template <typename ValueT> + void + add(ASTNode& lhs_node) + { + using DataT = std::decay_t<TupleContentType>; + + using AffectationExecutorT = AffectationFromTupleExecutor<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, value)); + } else { + // LCOV_EXCL_START + throw UnexpectedError("invalid left hand side"); + // LCOV_EXCL_STOP + } + } + + DataVariant + execute(ExecutionPolicy& exec_policy) + { + using TupleType = std::vector<TupleContentType>; + + TupleType tuple_values = std::move(std::get<TupleType>(m_node.children[1]->execute(exec_policy))); + + if (m_affectation_executor_list.size() == tuple_values.size()) { + for (size_t i = 0; i < m_affectation_executor_list.size(); ++i) { + try { + m_affectation_executor_list[i]->affect(exec_policy, + DataVariant(static_cast<TupleContentType>(tuple_values[i]))); + } + catch (std::domain_error& e) { + throw ParseError(e.what(), m_node.children[1]->begin()); + } + } + } else { + std::ostringstream error_msg; + error_msg << "cannot affect a " << rang::fgB::yellow << dataTypeName(m_node.children[1]->m_data_type) + << rang::fg::reset << " of size " << tuple_values.size() << " to a " << rang::fgB::yellow + << dataTypeName(m_node.children[0]->m_data_type) << rang::fg::reset; + throw ParseError(error_msg.str(), m_node.children[1]->begin()); + } + return {}; + } + + ListAffectationFromTupleProcessor(ASTNode& node) : m_node{node} {} +}; + #endif // AFFECTATION_PROCESSOR_HPP diff --git a/tests/test_ASTNodeAffectationExpressionBuilder.cpp b/tests/test_ASTNodeAffectationExpressionBuilder.cpp index c20490e5a2d6e872ee4d0e6533a95fd839eccb65..36d82b038c4a8211ebfd28b9033b3aa2994751f9 100644 --- a/tests/test_ASTNodeAffectationExpressionBuilder.cpp +++ b/tests/test_ASTNodeAffectationExpressionBuilder.cpp @@ -171,7 +171,9 @@ const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const dou OperatorRepository::instance().reset(); \ } +#ifdef __clang__ #pragma clang optimize off +#endif // __clang__ // clazy:excludeall=non-pod-global-static @@ -2419,7 +2421,7 @@ let t : (builtin_t), t = a; let bt: builtin_t, bt = t; )"; - std::string_view result = R"( + std::string result = R"( (root:ASTNodeListProcessor) +-(language::eq_op:AffectationToTupleProcessor<EmbeddedData>) | +-(language::name:t:NameProcessor) @@ -7486,4 +7488,6 @@ let v :(R^3x3), v = bt; } } +#ifdef __clang__ #pragma clang optimize on +#endif // __clang__ diff --git a/tests/test_ASTNodeListAffectationExpressionBuilder.cpp b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp index 9a02c71a3068cd3bc59e91f800d746445a5d777d..3f71228607f80f2ac04ad69fc408258ced89b413 100644 --- a/tests/test_ASTNodeListAffectationExpressionBuilder.cpp +++ b/tests/test_ASTNodeListAffectationExpressionBuilder.cpp @@ -61,25 +61,37 @@ const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const dou REQUIRE(ast_output.str() == expected_output); \ } -#define CHECK_AST_THROWS_WITH(data, error) \ - { \ - static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ - static_assert(std::is_same_v<std::decay_t<decltype(error)>, std::string>); \ - \ - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \ - auto ast = ASTBuilder::build(input); \ - \ - ASTModulesImporter{*ast}; \ - ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ - \ - ASTSymbolTableBuilder{*ast}; \ - ASTNodeDataTypeBuilder{*ast}; \ - \ - ASTNodeDeclarationToAffectationConverter{*ast}; \ - ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ - \ - REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, error); \ +#define CHECK_AST_THROWS_WITH(data, error) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(error)>, std::string>); \ + \ + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + BasicAffectationRegisterFor<EmbeddedData>{ASTNodeDataType::build<ASTNodeDataType::type_id_t>("builtin_t")}; \ + \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + SymbolTable& symbol_table = *ast->m_symbol_table; \ + auto [i_symbol, success] = symbol_table.add(builtin_data_type.nameOfTypeId(), ast->begin()); \ + if (not success) { \ + throw UnexpectedError("cannot add '" + builtin_data_type.nameOfTypeId() + "' type for testing"); \ + } \ + \ + i_symbol->attributes().setDataType(ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>()); \ + i_symbol->attributes().setIsInitialized(); \ + i_symbol->attributes().value() = symbol_table.typeEmbedderTable().size(); \ + symbol_table.typeEmbedderTable().add(std::make_shared<TypeDescriptor>(builtin_data_type.nameOfTypeId())); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ + \ + REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, error); \ } // clazy:excludeall=non-pod-global-static @@ -1507,106 +1519,1607 @@ let (b0,b1): builtin_t*builtin_t, (b0,b1) = (b0,b1); } } - SECTION("Errors") + SECTION("list from tuple") { - SECTION("invalid affectation rhs") + SECTION("(B) -> list") { std::string_view data = R"( -let x:R; -let i:R; -(x,i) = 3; +let t : (B), t = (true, false, true, false, false, true, false); +let (b,n,z,r,x1,x11,s):B*N*Z*R*R^1*R^1x1*string, + (b,n,z,r,x1,x11,s) = t; )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid right hand side in list affectation"}); + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<bool>) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::true_kw:ValueProcessor) + | +-(language::false_kw:ValueProcessor) + | +-(language::true_kw:ValueProcessor) + | +-(language::false_kw:ValueProcessor) + | +-(language::false_kw:ValueProcessor) + | +-(language::true_kw:ValueProcessor) + | `-(language::false_kw:ValueProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, bool>) + +-(language::name_list:FakeProcessor) + | +-(language::name:b:NameProcessor) + | +-(language::name:n:NameProcessor) + | +-(language::name:z:NameProcessor) + | +-(language::name:r:NameProcessor) + | +-(language::name:x1:NameProcessor) + | +-(language::name:x11:NameProcessor) + | `-(language::name:s:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); } - SECTION("incompatible list sizes") + SECTION("(N) -> list") { std::string_view data = R"( -let (x,y) : R*R, (x,y) = (3, 3, 2); +let t : (N), t = (1, 3, 6, 2, 7, 1); +let (n,z,r,x1,x11,s):N*Z*R*R^1*R^1x1*string, + (n,z,r,x1,x11,s) = t; )"; - CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<unsigned long>) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:3:ValueProcessor) + | +-(language::integer:6:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | +-(language::integer:7:ValueProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, unsigned long>) + +-(language::name_list:FakeProcessor) + | +-(language::name:n:NameProcessor) + | +-(language::name:z:NameProcessor) + | +-(language::name:r:NameProcessor) + | +-(language::name:x1:NameProcessor) + | +-(language::name:x11:NameProcessor) + | `-(language::name:s:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); } - SECTION("incompatible list sizes 2") + SECTION("(Z) -> list") { std::string_view data = R"( -let (x,y,z):R*R*R, (x,y,z) = (1, 2); +let t : (Z), t = (1, 3, 6, 2, 7, 1); +let (n,z,r,x1,x11,s):N*Z*R*R^1*R^1x1*string, + (n,z,r,x1,x11,s) = t; )"; - CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<long>) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:3:ValueProcessor) + | +-(language::integer:6:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | +-(language::integer:7:ValueProcessor) + | `-(language::integer:1:ValueProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, long>) + +-(language::name_list:FakeProcessor) + | +-(language::name:n:NameProcessor) + | +-(language::name:z:NameProcessor) + | +-(language::name:r:NameProcessor) + | +-(language::name:x1:NameProcessor) + | +-(language::name:x11:NameProcessor) + | `-(language::name:s:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); } - SECTION("incompatible list sizes from function evaluation") + SECTION("(R) -> list") { std::string_view data = R"( -let f: R -> R, x -> x*x; -let(x,y) : R*R, (x,y) = f(3); +let t : (R), t = (6.2, -2.1, 7.2, 3); +let (r,x1,x11,s):R*R^1*R^1x1*string, + (r,x1,x11,s) = t; )"; - CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<double>) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::real:6.2:ValueProcessor) + | +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, double, double>) + | | `-(language::real:2.1:ValueProcessor) + | +-(language::real:7.2:ValueProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, double>) + +-(language::name_list:FakeProcessor) + | +-(language::name:r:NameProcessor) + | +-(language::name:x1:NameProcessor) + | +-(language::name:x11:NameProcessor) + | `-(language::name:s:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); } - SECTION("incompatible list sizes from function evaluation") + SECTION("(R^1) -> list") { std::string_view data = R"( -let(x,y):R*R,(x,y)=(2,3); -(x,y) += (1,4); +let t : (R^1), t = (6.2, [-2.1]); +let (x1,s):R^1*string, + (x1,s) = t; )"; - CHECK_AST_THROWS_WITH(data, std::string{"undefined affectation operator for lists"}); + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<TinyVector<1ul, double> >) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::real:6.2:ValueProcessor) + | `-(language::vector_expression:TinyVectorExpressionProcessor<1ul>) + | `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, double, double>) + | `-(language::real:2.1:ValueProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, TinyVector<1ul, double> >) + +-(language::name_list:FakeProcessor) + | +-(language::name:x1:NameProcessor) + | `-(language::name:s:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); } - SECTION("invalid operand type for affectation") + SECTION("(R^2) -> list") { std::string_view data = R"( -let f: R -> R, x -> x+1; -let (x,y) : R*R, (x,y) = (f,2); +let t : (R^2), t = ([6.2, -2.1], 0); +let (x2,s):R^2*string, + (x2,s) = t; )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: function -> R"}); + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<TinyVector<2ul, double> >) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::vector_expression:TinyVectorExpressionProcessor<2ul>) + | | +-(language::real:6.2:ValueProcessor) + | | `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, double, double>) + | | `-(language::real:2.1:ValueProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, TinyVector<2ul, double> >) + +-(language::name_list:FakeProcessor) + | +-(language::name:x2:NameProcessor) + | `-(language::name:s:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); } - SECTION("invalid operand type for string affectation") + SECTION("(R^3) -> list") { std::string_view data = R"( -let f: R -> R, x -> x+1; -let (s,n):string*N, (s,n) = (f,2); +let t : (R^3), t = ([6.2, -2.1, 0], [1, 2, 3]); +let (x3,s):R^3*string, + (x3,s) = t; )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: function -> string"}); + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<TinyVector<3ul, double> >) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::vector_expression:TinyVectorExpressionProcessor<3ul>) + | | +-(language::real:6.2:ValueProcessor) + | | +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, double, double>) + | | | `-(language::real:2.1:ValueProcessor) + | | `-(language::integer:0:ValueProcessor) + | `-(language::vector_expression:TinyVectorExpressionProcessor<3ul>) + | +-(language::integer:1:ValueProcessor) + | +-(language::integer:2:ValueProcessor) + | `-(language::integer:3:ValueProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, TinyVector<3ul, double> >) + +-(language::name_list:FakeProcessor) + | +-(language::name:x3:NameProcessor) + | `-(language::name:s:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); } - SECTION("invalid value type for affectation") + SECTION("(R^1x1) -> list") { std::string_view data = R"( -let f: R -> R, x -> x+1; -let x:R; +let t : (R^1x1), t = (6.2, [[-2.1]]); +let (x11,s):R^1x1*string, + (x11,s) = t; +)"; -(f,x) = (3,2); + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<TinyMatrix<1ul, 1ul, double> >) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::real:6.2:ValueProcessor) + | `-(language::matrix_expression:TinyMatrixExpressionProcessor<1ul, 1ul>) + | `-(language::row_expression:FakeProcessor) + | `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, double, double>) + | `-(language::real:2.1:ValueProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, TinyMatrix<1ul, 1ul, double> >) + +-(language::name_list:FakeProcessor) + | +-(language::name:x11:NameProcessor) + | `-(language::name:s:NameProcessor) + `-(language::name:t:NameProcessor) )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> function"}); + CHECK_AST(data, result); } - SECTION("invalid R^n -> R^m conversion") + SECTION("(R^2x2) -> list") { std::string_view data = R"( -let x:R^2, x = [1,2]; -let y:R^3, y = x; +let t : (R^2x2), t = ([[6.2, -2.1],[1, 2]], 0); +let (x22,s):R^2x2*string, + (x22,s) = t; )"; - CHECK_AST_THROWS_WITH(data, std::string{"undefined affectation type: R^3 = R^2"}); + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<TinyMatrix<2ul, 2ul, double> >) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::matrix_expression:TinyMatrixExpressionProcessor<2ul, 2ul>) + | | +-(language::row_expression:FakeProcessor) + | | | +-(language::real:6.2:ValueProcessor) + | | | `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, double, double>) + | | | `-(language::real:2.1:ValueProcessor) + | | `-(language::row_expression:FakeProcessor) + | | +-(language::integer:1:ValueProcessor) + | | `-(language::integer:2:ValueProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, TinyMatrix<2ul, 2ul, double> >) + +-(language::name_list:FakeProcessor) + | +-(language::name:x22:NameProcessor) + | `-(language::name:s:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); } - SECTION("invalid Z -> R^d conversion (non-zero)") + SECTION("(R^3x3) -> list") { std::string_view data = R"( -let x:R^2, x = 1; +let t : (R^3x3), t = ([[6.2, -2.1, 0], [1, 2, 3], [0, -2, 1]], 0); +let (x33,s):R^3x3*string, + (x33,s) = t; )"; - CHECK_AST_THROWS_WITH(data, std::string{"invalid integral value (0 is the solely valid value)"}); + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<TinyMatrix<3ul, 3ul, double> >) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::matrix_expression:TinyMatrixExpressionProcessor<3ul, 3ul>) + | | +-(language::row_expression:FakeProcessor) + | | | +-(language::real:6.2:ValueProcessor) + | | | +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, double, double>) + | | | | `-(language::real:2.1:ValueProcessor) + | | | `-(language::integer:0:ValueProcessor) + | | +-(language::row_expression:FakeProcessor) + | | | +-(language::integer:1:ValueProcessor) + | | | +-(language::integer:2:ValueProcessor) + | | | `-(language::integer:3:ValueProcessor) + | | `-(language::row_expression:FakeProcessor) + | | +-(language::integer:0:ValueProcessor) + | | +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) + | | | `-(language::integer:2:ValueProcessor) + | | `-(language::integer:1:ValueProcessor) + | `-(language::integer:0:ValueProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, TinyMatrix<3ul, 3ul, double> >) + +-(language::name_list:FakeProcessor) + | +-(language::name:x33:NameProcessor) + | `-(language::name:s:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("(string) -> list") + { + std::string_view data = R"( +let t : (string), t = ("foo", "bar", "foobar"); +let (s1,s2,s3):string*string*string, + (s1,s2,s3) = t; +)"; + + std::string result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<)" + + demangled_stdstring + R"( >) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::literal:"foo":ValueProcessor) + | +-(language::literal:"bar":ValueProcessor) + | `-(language::literal:"foobar":ValueProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, )" + + demangled_stdstring + R"( >) + +-(language::name_list:FakeProcessor) + | +-(language::name:s1:NameProcessor) + | +-(language::name:s2:NameProcessor) + | `-(language::name:s3:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + + SECTION("(builtin_t) -> list") + { + std::string_view data = R"( +let b: builtin_t, b = b; +let t: (builtin_t), t = (b,b,b); +let (b1,b2,b3): builtin_t*builtin_t*builtin_t, (b1,b2,b3) = t; +)"; + + std::string_view result = R"( +(root:ASTNodeListProcessor) + +-(language::eq_op:AffectationProcessor<language::eq_op, EmbeddedData, EmbeddedData>) + | +-(language::name:b:NameProcessor) + | `-(language::name:b:NameProcessor) + +-(language::eq_op:AffectationToTupleFromListProcessor<EmbeddedData>) + | +-(language::name:t:NameProcessor) + | `-(language::expression_list:ASTNodeExpressionListProcessor) + | +-(language::name:b:NameProcessor) + | +-(language::name:b:NameProcessor) + | `-(language::name:b:NameProcessor) + `-(language::eq_op:ListAffectationFromTupleProcessor<language::eq_op, EmbeddedData>) + +-(language::name_list:FakeProcessor) + | +-(language::name:b1:NameProcessor) + | +-(language::name:b2:NameProcessor) + | `-(language::name:b3:NameProcessor) + `-(language::name:t:NameProcessor) +)"; + + CHECK_AST(data, result); + } + } + + SECTION("Errors") + { + SECTION("invalid affectation rhs") + { + std::string_view data = R"( +let x:R; +let i:R; +(x,i) = 3; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid right hand side in list affectation"}); + } + + SECTION("incompatible list sizes") + { + std::string_view data = R"( +let (x,y) : R*R, (x,y) = (3, 3, 2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + } + + SECTION("incompatible list sizes 2") + { + std::string_view data = R"( +let (x,y,z):R*R*R, (x,y,z) = (1, 2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + } + + SECTION("incompatible list sizes from function evaluation") + { + std::string_view data = R"( +let f: R -> R, x -> x*x; +let(x,y) : R*R, (x,y) = f(3); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); + } + + SECTION("incompatible list sizes from function evaluation") + { + std::string_view data = R"( +let(x,y):R*R,(x,y)=(2,3); +(x,y) += (1,4); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"undefined affectation operator for lists"}); + } + + SECTION("invalid operand type for affectation") + { + std::string_view data = R"( +let f: R -> R, x -> x+1; +let (x,y) : R*R, (x,y) = (f,2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: function -> R"}); + } + + SECTION("invalid operand type for string affectation") + { + std::string_view data = R"( +let f: R -> R, x -> x+1; +let (s,n):string*N, (s,n) = (f,2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: function -> string"}); + } + + SECTION("invalid value type for affectation") + { + std::string_view data = R"( +let f: R -> R, x -> x+1; +let x:R; + +(f,x) = (3,2); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> function"}); + } + + SECTION("invalid R^n -> R^m conversion") + { + std::string_view data = R"( +let x:R^2, x = [1,2]; +let y:R^3, y = x; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"undefined affectation type: R^3 = R^2"}); + } + + SECTION("invalid Z -> R^d conversion (non-zero)") + { + std::string_view data = R"( +let x:R^2, x = 1; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid integral value (0 is the solely valid value)"}); + } + + SECTION("tuples -> list") + { + SECTION("bad cast") + { + SECTION("from (string)") + { + SECTION("string -> B") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (s,b) : string*B, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> B"}); + } + + SECTION("string -> N") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (s,n) : string*N, (s,n) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> N"}); + } + + SECTION("string -> Z") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (z,n) : Z*N, (z,n) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> Z"}); + } + + SECTION("string -> R") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (s,r) : string*R, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R"}); + } + + SECTION("string -> R^1") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (s,r) : string*R^1, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R^1"}); + } + + SECTION("string -> R^2") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (s,r) : string*R^2, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R^2"}); + } + + SECTION("string -> R^3") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (s,r) : string*R^3, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R^3"}); + } + + SECTION("string -> R^1x1") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (s,r) : string*R^1x1, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R^1x1"}); + } + + SECTION("string -> R^2x2") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (s,r) : string*R^2x2, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R^2x2"}); + } + + SECTION("string -> R^3x3") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (s,r) : string*R^3x3, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> R^3x3"}); + } + + SECTION("string -> builtin_t") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (s,r) : string*builtin_t, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> builtin_t"}); + } + } + + SECTION("from (builtin_t)") + { + SECTION("builtin_t -> B") + { + std::string_view data = R"( +let bt:builtin_t, bt = bt; +let t:(builtin_t), t = (bt, bt); +let (s,b) : builtin_t*B, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: builtin_t -> B"}); + } + + SECTION("builtin_t -> N") + { + std::string_view data = R"( +let bt:builtin_t, bt = bt; +let t:(builtin_t), t = (bt, bt); +let (s,n) : builtin_t*N, (s,n) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: builtin_t -> N"}); + } + + SECTION("builtin_t -> Z") + { + std::string_view data = R"( +let bt:builtin_t, bt = bt; +let t:(builtin_t), t = (bt, bt); +let (z,n) : Z*N, (z,n) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: builtin_t -> Z"}); + } + + SECTION("builtin_t -> R") + { + std::string_view data = R"( +let bt:builtin_t, bt = bt; +let t:(builtin_t), t = (bt, bt); +let (s,r) : builtin_t*R, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: builtin_t -> R"}); + } + + SECTION("builtin_t -> R^1") + { + std::string_view data = R"( +let bt:builtin_t, bt = bt; +let t:(builtin_t), t = (bt, bt); +let (s,r) : builtin_t*R^1, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: builtin_t -> R^1"}); + } + + SECTION("builtin_t -> R^2") + { + std::string_view data = R"( +let bt:builtin_t, bt = bt; +let t:(builtin_t), t = (bt, bt); +let (s,r) : builtin_t*R^2, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: builtin_t -> R^2"}); + } + + SECTION("builtin_t -> R^3") + { + std::string_view data = R"( +let bt:builtin_t, bt = bt; +let t:(builtin_t), t = (bt, bt); +let (s,r) : builtin_t*R^3, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: builtin_t -> R^3"}); + } + + SECTION("builtin_t -> R^1x1") + { + std::string_view data = R"( +let bt:builtin_t, bt = bt; +let t:(builtin_t), t = (bt, bt); +let (s,r) : builtin_t*R^1x1, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: builtin_t -> R^1x1"}); + } + + SECTION("builtin_t -> R^2x2") + { + std::string_view data = R"( +let bt:builtin_t, bt = bt; +let t:(builtin_t), t = (bt, bt); +let (s,r) : builtin_t*R^2x2, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: builtin_t -> R^2x2"}); + } + + SECTION("builtin_t -> R^3x3") + { + std::string_view data = R"( +let bt:builtin_t, bt = bt; +let t:(builtin_t), t = (bt, bt); +let (s,r) : builtin_t*R^3x3, (s,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: builtin_t -> R^3x3"}); + } + } + + SECTION("from (B)") + { + SECTION("B -> R^2") + { + std::string_view data = R"( +let t:(B), t = (true, false); +let (r,b) : R^2*B, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: B -> R^2"}); + } + + SECTION("B -> R^3") + { + std::string_view data = R"( +let t:(B), t = (true, false); +let (r,b) : R^3*B, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: B -> R^3"}); + } + + SECTION("B -> R^2x2") + { + std::string_view data = R"( +let t:(B), t = (true, false); +let (r,b) : R^2x2*B, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: B -> R^2x2"}); + } + + SECTION("B -> R^3x3") + { + std::string_view data = R"( +let t:(B), t = (true, false); +let (r,b) : R^3x3*B, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: B -> R^3x3"}); + } + + SECTION("B -> builtin_t") + { + std::string_view data = R"( +let t:(B), t = (true, false); +let (s,b) : string*builtin_t, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: B -> builtin_t"}); + } + } + + SECTION("from (N)") + { + SECTION("N -> B") + { + std::string_view data = R"( +let t:(N), t = (1, 3); +let (r,b) : B*N, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> B"}); + } + + SECTION("N -> R^2") + { + std::string_view data = R"( +let t:(N), t = (1, 3); +let (r,b) : R^2*N, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> R^2"}); + } + + SECTION("N -> R^3") + { + std::string_view data = R"( +let t:(N), t = (1, 3); +let (r,b) : R^3*N, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> R^3"}); + } + + SECTION("N -> R^2x2") + { + std::string_view data = R"( +let t:(N), t = (1, 3); +let (r,b) : R^2x2*N, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> R^2x2"}); + } + + SECTION("N -> R^3x3") + { + std::string_view data = R"( +let t:(N), t = (1, 3); +let (r,b) : R^3x3*N, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> R^3x3"}); + } + + SECTION("N -> builtin_t") + { + std::string_view data = R"( +let t:(N), t = (1, 3); +let (s,b) : string*builtin_t, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> builtin_t"}); + } + } + + SECTION("from (Z)") + { + SECTION("Z -> B") + { + std::string_view data = R"( +let t:(Z), t = (1, 3); +let (r,b) : B*Z, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> B"}); + } + + SECTION("Z -> R^2") + { + std::string_view data = R"( +let t:(Z), t = (1, 3); +let (r,b) : R^2*Z, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> R^2"}); + } + + SECTION("Z -> R^3") + { + std::string_view data = R"( +let t:(Z), t = (1, 3); +let (r,b) : R^3*Z, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> R^3"}); + } + + SECTION("Z -> R^2x2") + { + std::string_view data = R"( +let t:(Z), t = (1, 3); +let (r,b) : R^2x2*Z, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> R^2x2"}); + } + + SECTION("Z -> R^3x3") + { + std::string_view data = R"( +let t:(Z), t = (1, 3); +let (r,b) : R^3x3*Z, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> R^3x3"}); + } + + SECTION("Z -> builtin_t") + { + std::string_view data = R"( +let t:(Z), t = (1, 3); +let (s,b) : string*builtin_t, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> builtin_t"}); + } + } + + SECTION("from (R)") + { + SECTION("R -> B") + { + std::string_view data = R"( +let t:(R), t = (1.2, 3.2); +let (r,b) : R*B, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> B"}); + } + + SECTION("R -> N") + { + std::string_view data = R"( +let t:(R), t = (1.2, 3.2); +let (r,n) : R*N, (r,n) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> N"}); + } + + SECTION("R -> Z") + { + std::string_view data = R"( +let t:(R), t = (1.2, 3.2); +let (r,z) : R*Z, (r,z) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> Z"}); + } + + SECTION("R -> R^2") + { + std::string_view data = R"( +let t:(R), t = (1.2, 3.2); +let (x,r) : R^2*R, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> R^2"}); + } + + SECTION("R -> R^3") + { + std::string_view data = R"( +let t:(R), t = (1.2, 3.2); +let (x,r) : R^3*R, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> R^3"}); + } + + SECTION("R -> R^2x2") + { + std::string_view data = R"( +let t:(R), t = (1.2, 3.2); +let (x,r) : R^2x2*R, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> R^2x2"}); + } + + SECTION("R -> R^3x3") + { + std::string_view data = R"( +let t:(R), t = (1.2, 3.2); +let (x,r) : R^3x3*R, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> R^3x3"}); + } + + SECTION("R -> builtin_t") + { + std::string_view data = R"( +let t:(R), t = (1.2, 3.2); +let (s,b) : string*builtin_t, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> builtin_t"}); + } + } + + SECTION("from (R^1)") + { + SECTION("R^1 -> B") + { + std::string_view data = R"( +let t:(R^1), t = (1.2, 3.2); +let (r,b) : R^1*B, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1 -> B"}); + } + + SECTION("R^1 -> N") + { + std::string_view data = R"( +let t:(R^1), t = (1.2, 3.2); +let (r,n) : R^1*N, (r,n) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1 -> N"}); + } + + SECTION("R^1 -> Z") + { + std::string_view data = R"( +let t:(R^1), t = (1.2, 3.2); +let (r,z) : R^1*Z, (r,z) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1 -> Z"}); + } + + SECTION("R^1 -> R") + { + std::string_view data = R"( +let t:(R^1), t = (1.2, 3.2); +let (r,x) : R^1*R, (r,x) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1 -> R"}); + } + + SECTION("R^1 -> R^2") + { + std::string_view data = R"( +let t:(R^1), t = (1.2, 3.2); +let (x,r) : R^2*R^1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1 -> R^2"}); + } + + SECTION("R^1 -> R^3") + { + std::string_view data = R"( +let t:(R^1), t = (1.2, 3.2); +let (x,r) : R^3*R^1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1 -> R^3"}); + } + + SECTION("R^1 -> R^1x1") + { + std::string_view data = R"( +let t:(R^1), t = (1.2, 3.2); +let (x,r) : R^1x1*R^1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1 -> R^1x1"}); + } + + SECTION("R^1 -> R^2x2") + { + std::string_view data = R"( +let t:(R^1), t = (1.2, 3.2); +let (x,r) : R^2x2*R^1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1 -> R^2x2"}); + } + + SECTION("R^1 -> R^3x3") + { + std::string_view data = R"( +let t:(R^1), t = (1.2, 3.2); +let (x,r) : R^3x3*R^1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1 -> R^3x3"}); + } + + SECTION("R^1 -> builtin_t") + { + std::string_view data = R"( +let t:(R^1), t = (1.2, 3.2); +let (s,b) : string*builtin_t, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1 -> builtin_t"}); + } + } + + SECTION("from (R^2)") + { + SECTION("R^2 -> B") + { + std::string_view data = R"( +let t:(R^2), t = ([1.2, 3.2], 0); +let (r,b) : R^2*B, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2 -> B"}); + } + + SECTION("R^2 -> N") + { + std::string_view data = R"( +let t:(R^2), t = ([1.2, 3.2], 0); +let (r,n) : R^2*N, (r,n) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2 -> N"}); + } + + SECTION("R^2 -> Z") + { + std::string_view data = R"( +let t:(R^2), t = ([1.2, 3.2], 0); +let (r,z) : R^2*Z, (r,z) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2 -> Z"}); + } + + SECTION("R^2 -> R") + { + std::string_view data = R"( +let t:(R^2), t = ([1.2, 3.2], 0); +let (r,x) : R^2*R, (r,x) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2 -> R"}); + } + + SECTION("R^2 -> R^1") + { + std::string_view data = R"( +let t:(R^2), t = ([1.2, 3.2], 0); +let (x,r) : R^2*R^1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2 -> R^1"}); + } + + SECTION("R^2 -> R^3") + { + std::string_view data = R"( +let t:(R^2), t = ([1.2, 3.2], 0); +let (x,r) : R^3*R^2, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2 -> R^3"}); + } + + SECTION("R^2 -> R^1x1") + { + std::string_view data = R"( +let t:(R^2), t = ([1.2, 3.2], 0); +let (x,r) : R^1x1*R^1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2 -> R^1x1"}); + } + + SECTION("R^2 -> R^2x2") + { + std::string_view data = R"( +let t:(R^2), t = ([1.2, 3.2], 0); +let (x,r) : R^2x2*R^2, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2 -> R^2x2"}); + } + + SECTION("R^2 -> R^3x3") + { + std::string_view data = R"( +let t:(R^2), t = ([1.2, 3.2], 0); +let (x,r) : R^3x3*R^2, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2 -> R^3x3"}); + } + + SECTION("R^2 -> builtin_t") + { + std::string_view data = R"( +let t:(R^2), t = ([1.2, 3.2], 0); +let (s,b) : string*builtin_t, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2 -> builtin_t"}); + } + } + + SECTION("from (R^3)") + { + SECTION("R^3 -> B") + { + std::string_view data = R"( +let t:(R^3), t = ([1.2, 3.2, 1], 0); +let (r,b) : R^3*B, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> B"}); + } + + SECTION("R^3 -> N") + { + std::string_view data = R"( +let t:(R^3), t = ([1.2, 3.2, 1], 0); +let (r,n) : R^3*N, (r,n) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> N"}); + } + + SECTION("R^3 -> Z") + { + std::string_view data = R"( +let t:(R^3), t = ([1.2, 3.2, 1], 0); +let (r,z) : R^3*Z, (r,z) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> Z"}); + } + + SECTION("R^3 -> R") + { + std::string_view data = R"( +let t:(R^3), t = ([1.2, 3.2, 1], 0); +let (r,x) : R^3*R, (r,x) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> R"}); + } + + SECTION("R^3 -> R^1") + { + std::string_view data = R"( +let t:(R^3), t = ([1.2, 3.2, 1], 0); +let (x,r) : R^3*R^1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> R^1"}); + } + + SECTION("R^3 -> R^2") + { + std::string_view data = R"( +let t:(R^3), t = ([1.2, 3.2, 1], 0); +let (x,r) : R^3*R^2, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> R^2"}); + } + + SECTION("R^3 -> R^1x1") + { + std::string_view data = R"( +let t:(R^3), t = ([1.2, 3.2, 1], 0); +let (x,r) : R^1x1*R^3, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> R^1x1"}); + } + + SECTION("R^3 -> R^2x2") + { + std::string_view data = R"( +let t:(R^3), t = ([1.2, 3.2, 1], 0); +let (x,r) : R^2x2*R^3, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> R^2x2"}); + } + + SECTION("R^3 -> R^3x3") + { + std::string_view data = R"( +let t:(R^3), t = ([1.2, 3.2, 1], 0); +let (x,r) : R^3x3*R^2, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> R^3x3"}); + } + + SECTION("R^3 -> builtin_t") + { + std::string_view data = R"( +let t:(R^3), t = ([1.2, 3.2, 1], 0); +let (s,b) : string*builtin_t, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> builtin_t"}); + } + } + + SECTION("from (R^1x1)") + { + SECTION("R^1x1 -> B") + { + std::string_view data = R"( +let t:(R^1x1), t = (1.2, 3.2); +let (r,b) : R^1x1*B, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1x1 -> B"}); + } + + SECTION("R^1x1 -> N") + { + std::string_view data = R"( +let t:(R^1x1), t = (1.2, 3.2); +let (r,n) : R^1x1*N, (r,n) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1x1 -> N"}); + } + + SECTION("R^1x1 -> Z") + { + std::string_view data = R"( +let t:(R^1x1), t = (1.2, 3.2); +let (r,z) : R^1x1*Z, (r,z) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1x1 -> Z"}); + } + + SECTION("R^1x1 -> R") + { + std::string_view data = R"( +let t:(R^1x1), t = (1.2, 3.2); +let (r,x) : R^1x1*R, (r,x) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1x1 -> R"}); + } + + SECTION("R^1x1 -> R^2") + { + std::string_view data = R"( +let t:(R^1x1), t = (1.2, 3.2); +let (x,r) : R^2*R^1x1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1x1 -> R^2"}); + } + + SECTION("R^1x1 -> R^3") + { + std::string_view data = R"( +let t:(R^1x1), t = (1.2, 3.2); +let (x,r) : R^3*R^1x1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1x1 -> R^3"}); + } + + SECTION("R^1x1 -> R^1") + { + std::string_view data = R"( +let t:(R^1x1), t = (1.2, 3.2); +let (x,r) : R^1x1*R^1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1x1 -> R^1"}); + } + + SECTION("R^1x1 -> R^2x2") + { + std::string_view data = R"( +let t:(R^1x1), t = (1.2, 3.2); +let (x,r) : R^2x2*R^1x1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1x1 -> R^2x2"}); + } + + SECTION("R^1x1 -> R^3x3") + { + std::string_view data = R"( +let t:(R^1x1), t = (1.2, 3.2); +let (x,r) : R^3x3*R^1x1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1x1 -> R^3x3"}); + } + + SECTION("R^1x1 -> builtin_t") + { + std::string_view data = R"( +let t:(R^1x1), t = (1.2, 3.2); +let (s,b) : string*builtin_t, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^1x1 -> builtin_t"}); + } + } + + SECTION("from (R^2x2)") + { + SECTION("R^2x2 -> B") + { + std::string_view data = R"( +let t:(R^2x2), t = ([[1.2, 3.2],[2.1, -3.1]], 0); +let (r,b) : R^2x2*B, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2x2 -> B"}); + } + + SECTION("R^2x2 -> N") + { + std::string_view data = R"( +let t:(R^2x2), t = ([[1.2, 3.2],[2.1, -3.1]], 0); +let (r,n) : R^2x2*N, (r,n) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2x2 -> N"}); + } + + SECTION("R^2x2 -> Z") + { + std::string_view data = R"( +let t:(R^2x2), t = ([[1.2, 3.2],[2.1, -3.1]], 0); +let (r,z) : R^2x2*Z, (r,z) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2x2 -> Z"}); + } + + SECTION("R^2x2 -> R") + { + std::string_view data = R"( +let t:(R^2x2), t = ([[1.2, 3.2],[2.1, -3.1]], 0); +let (r,x) : R^2x2*R, (r,x) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2x2 -> R"}); + } + + SECTION("R^2x2 -> R^2") + { + std::string_view data = R"( +let t:(R^2x2), t = ([[1.2, 3.2],[2.1, -3.1]], 0); +let (x,r) : R^2*R^2x2, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2x2 -> R^2"}); + } + + SECTION("R^2x2 -> R^3") + { + std::string_view data = R"( +let t:(R^2x2), t = ([[1.2, 3.2],[2.1, -3.1]], 0); +let (x,r) : R^3*R^2x2, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2x2 -> R^3"}); + } + + SECTION("R^2x2 -> R^1") + { + std::string_view data = R"( +let t:(R^2x2), t = ([[1.2, 3.2],[2.1, -3.1]], 0); +let (x,r) : R^2x2*R^1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2x2 -> R^1"}); + } + + SECTION("R^2x2 -> R^1x1") + { + std::string_view data = R"( +let t:(R^2x2), t = ([[1.2, 3.2],[2.1, -3.1]], 0); +let (x,r) : R^2x2*R^1x1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2x2 -> R^1x1"}); + } + + SECTION("R^2x2 -> R^3x3") + { + std::string_view data = R"( +let t:(R^2x2), t = ([[1.2, 3.2],[2.1, -3.1]], 0); +let (x,r) : R^3x3*R^2x2, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2x2 -> R^3x3"}); + } + + SECTION("R^2x2 -> builtin_t") + { + std::string_view data = R"( +let t:(R^2x2), t = ([[1.2, 3.2],[2.1, -3.1]], 0); +let (s,b) : string*builtin_t, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^2x2 -> builtin_t"}); + } + } + + SECTION("from (R^3x3)") + { + SECTION("R^3x3 -> B") + { + std::string_view data = R"( +let t:(R^3x3), t = ([[1.2, 3.2, 0],[1, 2.1, -3.1],[3, -1, 7]], 0); +let (r,b) : R^3x3*B, (r,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3x3 -> B"}); + } + + SECTION("R^3x3 -> N") + { + std::string_view data = R"( +let t:(R^3x3), t = ([[1.2, 3.2, 0],[1, 2.1, -3.1],[3, -1, 7]], 0); +let (r,n) : R^3x3*N, (r,n) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3x3 -> N"}); + } + + SECTION("R^3x3 -> Z") + { + std::string_view data = R"( +let t:(R^3x3), t = ([[1.2, 3.2, 0],[1, 2.1, -3.1],[3, -1, 7]], 0); +let (r,z) : R^3x3*Z, (r,z) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3x3 -> Z"}); + } + + SECTION("R^3x3 -> R") + { + std::string_view data = R"( +let t:(R^3x3), t = ([[1.2, 3.2, 0],[1, 2.1, -3.1],[3, -1, 7]], 0); +let (r,x) : R^3x3*R, (r,x) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3x3 -> R"}); + } + + SECTION("R^3x3 -> R^2") + { + std::string_view data = R"( +let t:(R^3x3), t = ([[1.2, 3.2, 0],[1, 2.1, -3.1],[3, -1, 7]], 0); +let (x,r) : R^2*R^3x3, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3x3 -> R^2"}); + } + + SECTION("R^3x3 -> R^3") + { + std::string_view data = R"( +let t:(R^3x3), t = ([[1.2, 3.2, 0],[1, 2.1, -3.1],[3, -1, 7]], 0); +let (x,r) : R^3*R^3x3, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3x3 -> R^3"}); + } + + SECTION("R^3x3 -> R^1") + { + std::string_view data = R"( +let t:(R^3x3), t = ([[1.2, 3.2, 0],[1, 2.1, -3.1],[3, -1, 7]], 0); +let (x,r) : R^3x3*R^1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3x3 -> R^1"}); + } + + SECTION("R^3x3 -> R^1x1") + { + std::string_view data = R"( +let t:(R^3x3), t = ([[1.2, 3.2, 0],[1, 2.1, -3.1],[3, -1, 7]], 0); +let (x,r) : R^3x3*R^1x1, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3x3 -> R^1x1"}); + } + + SECTION("R^3x3 -> R^2x2") + { + std::string_view data = R"( +let t:(R^3x3), t = ([[1.2, 3.2, 0],[1, 2.1, -3.1],[3, -1, 7]], 0); +let (x,r) : R^3x3*R^2x2, (x,r) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3x3 -> R^2x2"}); + } + + SECTION("R^3x3 -> builtin_t") + { + std::string_view data = R"( +let t:(R^3x3), t = ([[1.2, 3.2, 0],[1, 2.1, -3.1],[3, -1, 7]], 0); +let (s,b) : string*builtin_t, (s,b) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3x3 -> builtin_t"}); + } + } + } + + SECTION("tuple -> list with tuple") + { + std::string_view data = R"( +let t:(N), t = (1, 2, 3, 4); +let (a,b,c,d) : R*N*(R)*Z, (a,b,c,d) = t; +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"cannot affect a tuple to a compound type made of tuples"}); + } } } } diff --git a/tests/test_DiscreteFunctionP0.cpp b/tests/test_DiscreteFunctionP0.cpp index 3253cd6fe4f3e419f81d1f051010ec787424e9f0..39b91c4de355c1a96feaa1f1b5e2a59bf9c494d8 100644 --- a/tests/test_DiscreteFunctionP0.cpp +++ b/tests/test_DiscreteFunctionP0.cpp @@ -4,7 +4,9 @@ #include <MeshDataBaseForTests.hpp> #include <scheme/DiscreteFunctionP0.hpp> +#ifdef __clang__ #pragma clang optimize off +#endif // __clang__ // clazy:excludeall=non-pod-global-static @@ -3437,7 +3439,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { const double x = xj[cell_id][0]; Ah[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, // - -0.2 * x - 1, 2 + x}; + -0.2 * x - 1, 2 + x}; }); { @@ -3459,7 +3461,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { const double x = xj[cell_id][0]; Ah[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, // - -0.2 * x - 1, 2 + x}; + -0.2 * x - 1, 2 + x}; }); { @@ -3481,7 +3483,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { const double x = xj[cell_id][0]; Ah[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, // - -0.2 * x - 1, 2 + x}; + -0.2 * x - 1, 2 + x}; }); { @@ -3503,7 +3505,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { const double x = xj[cell_id][0]; Ah[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, // - -0.2 * x - 1, 2 + x}; + -0.2 * x - 1, 2 + x}; }); { @@ -3700,4 +3702,6 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") #endif // NDEBUG } +#ifdef __clang__ #pragma clang optimize on +#endif // __clang__ diff --git a/tests/test_ListAffectationProcessor.cpp b/tests/test_ListAffectationProcessor.cpp index 219b9a2f16907f3d6010d3144b7d2b903455d6fa..2c28e6e0b0e6a8c8ae8c61d4b5778c8e3617af58 100644 --- a/tests/test_ListAffectationProcessor.cpp +++ b/tests/test_ListAffectationProcessor.cpp @@ -45,6 +45,25 @@ REQUIRE(value == expected_value); \ } +#define CHECK_AFFECTATION_THROW_WITH(data, error_message) \ + { \ + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + REQUIRE_THROWS_WITH(ast->execute(exec_policy), error_message); \ + } + // clazy:excludeall=non-pod-global-static TEST_CASE("ListAffectationProcessor", "[language]") @@ -738,4 +757,176 @@ let (s1,b2) : (string)*B, (s1,b2) = (s, false); } } } + + SECTION("list from tuple affectation") + { + SECTION("from (B)") + { + std::string_view data = R"( +let t:(B), t = (true, false, true, false, true, false, true); +let (b,n,z,r,r1,r11,s):B*N*Z*R*R^1*R^1x1*string, (b,n,z,r,r1,r11,s)=t; +)"; + + CHECK_AFFECTATION_RESULT(data, "b", (true)); + CHECK_AFFECTATION_RESULT(data, "n", (0ul)); + CHECK_AFFECTATION_RESULT(data, "z", (1l)); + CHECK_AFFECTATION_RESULT(data, "r", (double{0})); + CHECK_AFFECTATION_RESULT(data, "r1", (TinyVector<1>{1})); + CHECK_AFFECTATION_RESULT(data, "r11", (TinyMatrix<1>{0})); + CHECK_AFFECTATION_RESULT(data, "s", (std::string{stringify(true)})); + } + + SECTION("from (N)") + { + std::string_view data = R"( +let t:(N), t = (1, 2, 3, 4, 5, 6); +let (n,z,r,r1,r11,s):N*Z*R*R^1*R^1x1*string, (n,z,r,r1,r11,s)=t; +)"; + + CHECK_AFFECTATION_RESULT(data, "n", (1ul)); + CHECK_AFFECTATION_RESULT(data, "z", (2l)); + CHECK_AFFECTATION_RESULT(data, "r", (double{3})); + CHECK_AFFECTATION_RESULT(data, "r1", (TinyVector<1>{4})); + CHECK_AFFECTATION_RESULT(data, "r11", (TinyMatrix<1>{5})); + CHECK_AFFECTATION_RESULT(data, "s", (std::string{stringify(6ul)})); + } + + SECTION("from (Z)") + { + std::string_view data = R"( +let t:(Z), t = (1, -2, 3, -4, 5, 6); +let (n,z,r,r1,r11,s):N*Z*R*R^1*R^1x1*string, (n,z,r,r1,r11,s)=t; +)"; + + CHECK_AFFECTATION_RESULT(data, "n", (1ul)); + CHECK_AFFECTATION_RESULT(data, "z", (-2l)); + CHECK_AFFECTATION_RESULT(data, "r", (double{3})); + CHECK_AFFECTATION_RESULT(data, "r1", (TinyVector<1>{-4})); + CHECK_AFFECTATION_RESULT(data, "r11", (TinyMatrix<1>{5})); + CHECK_AFFECTATION_RESULT(data, "s", (std::string{stringify(6l)})); + } + + SECTION("from (R)") + { + std::string_view data = R"( +let t:(R), t = (1.2, -2.3, 7.3, -4.2); +let (r,r1,r11,s):R*R^1*R^1x1*string, (r,r1,r11,s)=t; +)"; + + CHECK_AFFECTATION_RESULT(data, "r", (double{1.2})); + CHECK_AFFECTATION_RESULT(data, "r1", (TinyVector<1>{-2.3})); + CHECK_AFFECTATION_RESULT(data, "r11", (TinyMatrix<1>{7.3})); + CHECK_AFFECTATION_RESULT(data, "s", (std::string{stringify(-4.2)})); + } + + SECTION("from (R^1)") + { + std::string_view data = R"( +let t:(R^1), t = (1.2, -[2.3]); +let (r1,s):R^1*string, (r1,s)=t; +)"; + + CHECK_AFFECTATION_RESULT(data, "r1", (TinyVector<1>{1.2})); + CHECK_AFFECTATION_RESULT(data, "s", (std::string{stringify(TinyVector<1>{-2.3})})); + } + + SECTION("from (R^2)") + { + std::string_view data = R"( +let t:(R^2), t = ([1.2, 2], [2.3, 0]); +let (r2,s):R^2*string, (r2,s)=t; +)"; + + CHECK_AFFECTATION_RESULT(data, "r2", (TinyVector<2>{1.2, 2})); + CHECK_AFFECTATION_RESULT(data, "s", (std::string{stringify(TinyVector<2>{2.3, 0})})); + } + + SECTION("from (R^3)") + { + std::string_view data = R"( +let t:(R^3), t = ([1.2, 2, -1], [2.3, 0, 2]); +let (r3,s):R^3*string, (r3,s)=t; +)"; + + CHECK_AFFECTATION_RESULT(data, "r3", (TinyVector<3>{1.2, 2, -1})); + CHECK_AFFECTATION_RESULT(data, "s", (std::string{stringify(TinyVector<3>{2.3, 0, 2})})); + } + + SECTION("from (R^1x1)") + { + std::string_view data = R"( +let t:(R^1x1), t = (1.2, -[[2.3]]); +let (r11,s):R^1x1*string, (r11,s)=t; +)"; + + CHECK_AFFECTATION_RESULT(data, "r11", (TinyMatrix<1>{1.2})); + CHECK_AFFECTATION_RESULT(data, "s", (std::string{stringify(TinyMatrix<1>{-2.3})})); + } + + SECTION("from (R^2x2)") + { + std::string_view data = R"( +let t:(R^2x2), t = ([[1.2, 2], [2.3, 0]], [[1.1, 2.2], [-1.3, 2]]); +let (r22,s):R^2x2*string, (r22,s)=t; +)"; + + CHECK_AFFECTATION_RESULT(data, "r22", (TinyMatrix<2>{1.2, 2, 2.3, 0})); + CHECK_AFFECTATION_RESULT(data, "s", (std::string{stringify(TinyMatrix<2>{1.1, 2.2, -1.3, 2})})); + } + + SECTION("from (R^3x3)") + { + std::string_view data = R"( +let t:(R^3x3), t = ([[1.2, 2, -1], [2.3, 0, 2], [1, 4, 5]], 0); +let (r33,s):R^3x3*string, (r33,s)=t; +)"; + + CHECK_AFFECTATION_RESULT(data, "r33", (TinyMatrix<3>{1.2, 2, -1, 2.3, 0, 2, 1, 4, 5})); + CHECK_AFFECTATION_RESULT(data, "s", (std::string{stringify(TinyMatrix<3>{zero})})); + } + + SECTION("from (string)") + { + std::string_view data = R"( +let t:(string), t = ("foo", "bar"); +let (s1,s2):string*string, (s1,s2)=t; +)"; + + CHECK_AFFECTATION_RESULT(data, "s1", (std::string{"foo"})); + CHECK_AFFECTATION_RESULT(data, "s2", (std::string{"bar"})); + } + + SECTION("errors") + { + SECTION("negative (Z) -> N") + { + std::string_view data = R"( +let t:(Z), t = (2, 3, -4, 5); +let (a,b,c,d):Z*N*N*R , (a,b,c,d)=t; +)"; + + CHECK_AFFECTATION_THROW_WITH(data, "trying to affect negative value (-4)"); + } + + SECTION("tuple too small") + { + std::string_view data = R"( +let t:(Z), t = (2, 3, 4); +let (a,b,c,d):Z*N*N*R , (a,b,c,d)=t; +)"; + + CHECK_AFFECTATION_THROW_WITH(data, "cannot affect a (Z) of size 3 to a Z*N*N*R"); + } + + SECTION("tuple too large") + { + std::string_view data = R"( +let t:(Z), t = (1, 2, 3, 4, 5); +let (a,b,c,d):Z*N*N*R , (a,b,c,d)=t; +)"; + + CHECK_AFFECTATION_THROW_WITH(data, "cannot affect a (Z) of size 5 to a Z*N*N*R"); + } + } + } }