Fix up some error handling

This commit is contained in:
Jason Turner 2018-05-25 14:33:17 -06:00
parent e0f29e0f7c
commit 805e7c0917
24 changed files with 94 additions and 43 deletions

View File

@ -466,7 +466,7 @@ namespace chaiscript
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
m.add(fun(&Boxed_Number::to_string), "to_string");
bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<long double>("long_double", m);
bootstrap_pod_type<float>("float", m);
@ -495,7 +495,7 @@ namespace chaiscript
opers_arithmetic_pod(m);
m.add(fun(&Build_Info::version_major), "version_major");
m.add(fun(&Build_Info::version_minor), "version_minor");
m.add(fun(&Build_Info::version_patch), "version_patch");

View File

@ -647,8 +647,6 @@ namespace chaiscript
/// Special type for returned values
struct Return_Value {
Boxed_Value retval;
explicit Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { }
};

View File

@ -448,19 +448,22 @@ namespace chaiscript
Boxed_Value rhs = this->children[1]->eval(t_ss);
Boxed_Value lhs = this->children[0]->eval(t_ss);
if (lhs.is_return_value()) {
throw exception::eval_error("Error, cannot assign to temporary value.");
} else if (lhs.is_const()) {
throw exception::eval_error("Error, cannot assign to constant value.");
}
if (m_oper != Operators::Opers::invalid && lhs.get_type_info().is_arithmetic() &&
rhs.get_type_info().is_arithmetic())
{
try {
return Boxed_Number::do_oper(m_oper, lhs, rhs);
} catch (const std::exception &) {
throw exception::eval_error("Error with unsupported arithmetic assignment operation");
throw exception::eval_error("Error with unsupported arithmetic assignment operation.");
}
} else if (m_oper == Operators::Opers::assign) {
if (lhs.is_return_value()) {
throw exception::eval_error("Error, cannot assign to temporary value.");
}
try {
if (lhs.is_undef()) {
@ -470,7 +473,7 @@ namespace chaiscript
&& this->children[0]->children[0]->identifier == AST_Node_Type::Reference)
)
)
{
/// \todo This does not handle the case of an unassigned reference variable
/// being assigned outside of its declaration
@ -1141,10 +1144,10 @@ namespace chaiscript
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
if (!this->children.empty()) {
throw detail::Return_Value(this->children[0]->eval(t_ss));
throw detail::Return_Value{this->children[0]->eval(t_ss)};
}
else {
throw detail::Return_Value(void_var());
throw detail::Return_Value{void_var()};
}
}
};
@ -1201,6 +1204,10 @@ namespace chaiscript
// short circuit arithmetic operations
if (m_oper != Operators::Opers::invalid && m_oper != Operators::Opers::bitwise_and && bv.get_type_info().is_arithmetic())
{
if ((m_oper == Operators::Opers::pre_increment || m_oper == Operators::Opers::pre_decrement) && bv.is_const())
{
throw exception::eval_error("Error with prefix operator evaluation: cannot modify constant value.");
}
return Boxed_Number::do_oper(m_oper, bv);
} else {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
@ -1409,7 +1416,7 @@ namespace chaiscript
Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc),
std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
std::make_move_iterator(std::prev(t_children.end(), Def_AST_Node<T>::has_guard(t_children, 1)?2:1)))
),
m_body_node(Def_AST_Node<T>::get_body_node(std::move(t_children))),

View File

@ -356,7 +356,7 @@ namespace chaiscript {
const auto make_constant = [&node, &fun_name](auto val){
const auto match = fun_name + "(" + node->children[1]->children[0]->text + ")";
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(val));
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, const_var(val));
};
if (fun_name == "double") {

View File

@ -164,15 +164,15 @@ void help(int n) {
}
}
bool throws_exception(const std::function<void ()> &f)
std::string throws_exception(const std::function<void ()> &f)
{
try {
f();
} catch (...) {
return true;
} catch (const std::exception &e) {
return e.what();
}
return false;
return "";
}
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)

View File

@ -1,2 +1,2 @@
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 = 2 } );
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 + 2 = 2 } );
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 = 2 } );
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 + 2 = 2 } );

View File

@ -66,10 +66,10 @@ var group = group_guard.get_contained_functions();
assert_equal(true, group[0].has_guard())
assert_equal(false, group[1].has_guard())
assert_throws("Function does not have a guard", fun() { group[0].get_guard(); } );
assert_throws("Function does not have a guard", fun() { without_guard.get_guard(); } );
assert_throws("Function does not have a guard", fun[group]() { group[1].get_guard(); } );
assert_throws("Function does not have a guard", fun[without_guard]() { without_guard.get_guard(); } );
var guard = with_guard.get_guard();
assert_equal(false, guard.has_guard());
assert_throws("Function does not have a guard", fun() { guard.get_guard(); } );
assert_throws("Function does not have a guard", fun[guard]() { guard.get_guard(); } );

View File

@ -1 +1 @@
assert_throws("Illegal const function assignment", fun() { clone = `-` } );
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { clone = `-` } );

View File

@ -1 +1,2 @@
assert_throws("Invalid function reassignment", fun() { var x = 5; x = `-`; } );
assert_throws("Error: \"Unable to find appropriate'=' operator.\" With parameters: (int, const Function)", fun() { auto x = 5; x = `-`; } );

View File

@ -1,2 +1,8 @@
assert_throws("Parse failure", fun() { eval("[\"hello\":5,\"j\",\"k\"]") } );
try {
eval("[\"hello\":5,\"j\",\"k\"]");
assert_true(false);
} catch (eval_error ee) {
}

View File

@ -13,4 +13,4 @@ assert_equal(0, i -= i)
assert_equal(3, j *= 1.5)
assert_equal(1.5, j /= 2)
assert_equal(2.5, j += 1)
assert_throws("No modulus for float", fun() { k % 2 } );
assert_throws("Error: \"Error with numeric operator calling: %\"", fun[k]() { k % 2 } );

View File

@ -1,2 +1,2 @@
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 = 2 } );
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 + 2 = 2 } );
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 = 2 } );
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 + 2 = 2 } );

View File

@ -10,5 +10,7 @@ var o = MyClass();
assert_true(o.is_explicit());
assert_throws("error", fun[o](){o.x = 2})
assert_throws("Error: \"'x' is not a function.\"", fun[o](){o.x = 2})

View File

@ -66,10 +66,10 @@ auto group = group_guard.get_contained_functions();
assert_equal(true, group[0].has_guard())
assert_equal(false, group[1].has_guard())
assert_throws("Function does not have a guard", fun() { group[0].get_guard(); } );
assert_throws("Function does not have a guard", fun() { without_guard.get_guard(); } );
assert_throws("Function does not have a guard", fun[group]() { group[1].get_guard(); } );
assert_throws("Function does not have a guard", fun[without_guard]() { without_guard.get_guard(); } );
auto guard = with_guard.get_guard();
assert_equal(false, guard.has_guard());
assert_throws("Function does not have a guard", fun() { guard.get_guard(); } );
assert_throws("Function does not have a guard", fun[guard]() { guard.get_guard(); } );

View File

@ -1,2 +1,2 @@
assert_throws("Function already defined", fun(){ def foo(x) { x + 1 }; def foo(x) { x + 1 } } );
assert_throws("Error: \"Function redefined 'foo'\"", fun(){ def foo(x) { x + 1 }; def foo(x) { x + 1 } } );

View File

@ -1 +1 @@
assert_throws("Illegal const function assignment", fun() { clone = `-` } );
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { clone = `-` } );

View File

@ -1 +1,4 @@
assert_throws("Invalid function reassignment", fun() { auto x = 5; x = `-`; } );
assert_throws("Error: \"Unable to find appropriate'=' operator.\" With parameters: (int, const Function)", fun() { auto x = 5; x = `-`; } );

View File

@ -1,2 +1,8 @@
assert_throws("Parse failure", fun() { eval("[\"hello\":5,\"j\",\"k\"]") } );
try {
eval("[\"hello\":5,\"j\",\"k\"]");
assert_true(false);
} catch (eval_error ee) {
}

View File

@ -13,4 +13,6 @@ assert_equal(0, i -= i)
assert_equal(3, j *= 1.5)
assert_equal(1.5, j /= 2)
assert_equal(2.5, j += 1)
assert_throws("No modulus for float", fun() { k % 2 } );
assert_throws("Error: \"Error with numeric operator calling: %\"", fun[k]() { k % 2 } );

View File

@ -29,3 +29,13 @@ assert_equal(2, j += 1);
assert_equal(1, --j);
assert_equal(2, ++j);
assert_throws("Error: \"Error with prefix operator evaluation: cannot modify constant value.\"", fun() { ++4; });
assert_throws("Error: \"Error with prefix operator evaluation: cannot modify constant value.\"", fun() { --4; });
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 5 = 5; });
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { int(5) = 5; });

View File

@ -6,6 +6,20 @@ try {
print("Caught Error: " + e.what());
}
def get_value()
{
var i = 5;
return i;
}
def get_value_2()
{
return 5;
}
// TODO these should be fixed somehow
//assert_throws("Cannot assign to temporary", fun[](){ get_value() = 3; });
//assert_throws("Cannot assign to temporary", fun[](){ get_value_2() = 3; });
try {

View File

@ -8,8 +8,8 @@ assert_equal("Test\u2022Me", "Test•Me")
assert_equal("\xF0\x9F\x8D\x8C", "🍌")
assert_equal("\U0001F34C", "🍌")
assert_throws("Invalid 16 bit universal character", fun(){ parse("\"\\uD83C\""); });
assert_throws("Incomplete unicode escape sequence", fun(){ parse("\"\\uD83 \""); });
assert_throws("Error: \"Invalid 16 bit universal character\"", fun(){ parse("\"\\uD83C\""); });
assert_throws("Error: \"Incomplete unicode escape sequence\"", fun(){ parse("\"\\uD83 \""); });
assert_equal("\U00024B62", "𤭢")

View File

@ -42,12 +42,14 @@ def assert_not_equal(x, y)
def assert_throws(desc, x)
{
if (throws_exception(x))
auto result = trim(throws_exception(x));
if (result == desc)
{
// Passes
} else {
// Fails
print("assert_throws failure, function did not throw exception: " + to_string(desc));
print("assert_throws failed: got '${result}' expected '${desc}'");
exit(-1);
}
}

View File

@ -1,2 +1,2 @@
assert_throws("Variable already defined", fun() { auto y = 10; auto y = 20; })
assert_throws("Error: \"Variable redefined 'y'\"", fun() { auto y = 10; auto y = 20; })