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

@ -647,8 +647,6 @@ namespace chaiscript
/// Special type for returned values /// Special type for returned values
struct Return_Value { struct Return_Value {
Boxed_Value retval; 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 rhs = this->children[1]->eval(t_ss);
Boxed_Value lhs = this->children[0]->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() && if (m_oper != Operators::Opers::invalid && lhs.get_type_info().is_arithmetic() &&
rhs.get_type_info().is_arithmetic()) rhs.get_type_info().is_arithmetic())
{ {
try { try {
return Boxed_Number::do_oper(m_oper, lhs, rhs); return Boxed_Number::do_oper(m_oper, lhs, rhs);
} catch (const std::exception &) { } 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) { } else if (m_oper == Operators::Opers::assign) {
if (lhs.is_return_value()) {
throw exception::eval_error("Error, cannot assign to temporary value.");
}
try { try {
if (lhs.is_undef()) { if (lhs.is_undef()) {
@ -1141,10 +1144,10 @@ namespace chaiscript
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
if (!this->children.empty()) { 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 { else {
throw detail::Return_Value(void_var()); throw detail::Return_Value{void_var()};
} }
} }
}; };
@ -1201,6 +1204,10 @@ namespace chaiscript
// short circuit arithmetic operations // 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::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); return Boxed_Number::do_oper(m_oper, bv);
} else { } else {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);

View File

@ -356,7 +356,7 @@ namespace chaiscript {
const auto make_constant = [&node, &fun_name](auto val){ const auto make_constant = [&node, &fun_name](auto val){
const auto match = fun_name + "(" + node->children[1]->children[0]->text + ")"; 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") { 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 { try {
f(); f();
} catch (...) { } catch (const std::exception &e) {
return true; return e.what();
} }
return false; return "";
} }
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f) 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("Error: \"Error, cannot assign to constant value.\"", 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 = 2 } );

View File

@ -66,10 +66,10 @@ var group = group_guard.get_contained_functions();
assert_equal(true, group[0].has_guard()) assert_equal(true, group[0].has_guard())
assert_equal(false, group[1].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[group]() { group[1].get_guard(); } );
assert_throws("Function does not have a guard", fun() { without_guard.get_guard(); } ); assert_throws("Function does not have a guard", fun[without_guard]() { without_guard.get_guard(); } );
var guard = with_guard.get_guard(); var guard = with_guard.get_guard();
assert_equal(false, guard.has_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(3, j *= 1.5)
assert_equal(1.5, j /= 2) assert_equal(1.5, j /= 2)
assert_equal(2.5, j += 1) 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("Error: \"Error, cannot assign to constant value.\"", 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 = 2 } );

View File

@ -10,5 +10,7 @@ var o = MyClass();
assert_true(o.is_explicit()); 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(true, group[0].has_guard())
assert_equal(false, group[1].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[group]() { group[1].get_guard(); } );
assert_throws("Function does not have a guard", fun() { without_guard.get_guard(); } ); assert_throws("Function does not have a guard", fun[without_guard]() { without_guard.get_guard(); } );
auto guard = with_guard.get_guard(); auto guard = with_guard.get_guard();
assert_equal(false, guard.has_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(3, j *= 1.5)
assert_equal(1.5, j /= 2) assert_equal(1.5, j /= 2)
assert_equal(2.5, j += 1) 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(1, --j);
assert_equal(2, ++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()); 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 { try {

View File

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

View File

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