diff --git a/src/language/node_processor/BuiltinFunctionProcessor.hpp b/src/language/node_processor/BuiltinFunctionProcessor.hpp index 4e5583adb2d269e7552ff3cccf7dfcbe811b0791..7e5a112b46f32792cf2fda652379a4a5f2f064aa 100644 --- a/src/language/node_processor/BuiltinFunctionProcessor.hpp +++ b/src/language/node_processor/BuiltinFunctionProcessor.hpp @@ -52,14 +52,25 @@ class BuiltinFunctionProcessor : public INodeProcessor ExecutionPolicy context_exec_policy{exec_policy, ExecutionPolicy::Context{-1, std::make_shared<ExecutionPolicy::Context::Values>( m_argument_converters.size())}}; + if (m_argument_converters.size() == 1) { - m_argument_converters[0]->convert(context_exec_policy, m_argument_node.execute(context_exec_policy)); + try { + m_argument_converters[0]->convert(context_exec_policy, m_argument_node.execute(context_exec_policy)); + } + catch (std::domain_error& e) { + throw ParseError(e.what(), m_argument_node.begin()); + } } else { AggregateDataVariant argument_values{ std::get<AggregateDataVariant>(m_argument_node.execute(context_exec_policy))}; for (size_t i = 0; i < m_argument_converters.size(); ++i) { - m_argument_converters[i]->convert(context_exec_policy, std::move(argument_values[i])); + try { + m_argument_converters[i]->convert(context_exec_policy, std::move(argument_values[i])); + } + catch (std::domain_error& e) { + throw ParseError(e.what(), m_argument_node.children[i]->begin()); + } } } diff --git a/src/language/node_processor/FunctionArgumentConverter.hpp b/src/language/node_processor/FunctionArgumentConverter.hpp index 3f7b941af98887136af60b4415640d8694bd3ed6..769bcd9ef92d8379064e9d56d491942e48501f24 100644 --- a/src/language/node_processor/FunctionArgumentConverter.hpp +++ b/src/language/node_processor/FunctionArgumentConverter.hpp @@ -222,6 +222,11 @@ class FunctionTupleArgumentConverter final : public IFunctionArgumentConverter } } else if constexpr (std::is_convertible_v<ValueT, ContentType> and not is_tiny_vector_v<ContentType> and not is_tiny_matrix_v<ContentType>) { + if constexpr (std::is_same_v<ContentType, uint64_t> and std::is_same_v<ValueT, int64_t>) { + if (v < 0) { + throw std::domain_error("trying to convert negative value (" + std::to_string(v) + ")"); + } + } exec_policy.currentContext()[m_argument_id] = std::move(TupleType{static_cast<ContentType>(v)}); } else { throw UnexpectedError(std::string{"cannot convert '"} + demangle<ValueT>() + "' to '" + diff --git a/tests/test_BuiltinFunctionProcessor.cpp b/tests/test_BuiltinFunctionProcessor.cpp index bbc5ac52e1a6e8034b68b591adff83c1d8701ff5..1cdfec95e1f47101762816680f9dca65fab9158e 100644 --- a/tests/test_BuiltinFunctionProcessor.cpp +++ b/tests/test_BuiltinFunctionProcessor.cpp @@ -368,5 +368,34 @@ runtimeError(); CHECK_AST_THROWS_WITH(data, error); } + + SECTION("negative Z to N conversion") + { + std::string_view data = R"( +NtoR(3); +NtoR(-4); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"trying to convert negative value (-4)"}); + } + + SECTION("negative Z in list to (N) conversion") + { + std::string_view data = R"( +tuple_NtoR(2); +tuple_NtoR(-1); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"trying to convert negative value (-1)"}); + } + + SECTION("negative Z in list to (N) conversion") + { + std::string_view data = R"( +tuple_NtoR((3, 2, -3, 2)); +)"; + + CHECK_AST_THROWS_WITH(data, std::string{"trying to convert negative value (-3)"}); + } } }