Merge branch 'master' into 2011-09-09-CxScript
Conflicts: CMakeLists.txt include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp
This commit is contained in:
@@ -204,6 +204,10 @@ if(BUILD_TESTING)
|
||||
target_link_libraries(cpp_lambda_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME cpp_lambda_test COMMAND cpp_lambda_test)
|
||||
|
||||
add_executable(expected_eval_errors_test unittests/expected_eval_errors_test.cpp)
|
||||
target_link_libraries(expected_eval_errors_test ${LIBS})
|
||||
add_test(NAME Expected_Eval_Errors_Test COMMAND expected_eval_errors_test)
|
||||
|
||||
|
||||
add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp
|
||||
unittests/multifile_test_module.cpp)
|
||||
|
@@ -423,6 +423,7 @@ namespace chaiscript
|
||||
m->add(fun(&Type_Info::is_void), "is_type_void");
|
||||
m->add(fun(&Type_Info::is_undef), "is_type_undef");
|
||||
m->add(fun(&Type_Info::is_pointer), "is_type_pointer");
|
||||
m->add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
|
||||
m->add(fun(&Type_Info::name), "cpp_name");
|
||||
m->add(fun(&Type_Info::bare_name), "cpp_bare_name");
|
||||
m->add(fun(&Type_Info::bare_equal), "bare_equal");
|
||||
|
@@ -25,7 +25,6 @@ namespace chaiscript
|
||||
|
||||
typedef std::shared_ptr<struct AST_Node> AST_NodePtr;
|
||||
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
/**
|
||||
@@ -558,14 +557,16 @@ namespace chaiscript
|
||||
class dispatch_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
dispatch_error(const std::vector<Boxed_Value> &t_bvs)
|
||||
: std::runtime_error("Error with function dispatch"), parameters(t_bvs)
|
||||
dispatch_error(const std::vector<Boxed_Value> &t_parameters,
|
||||
const std::vector<Const_Proxy_Function> &t_functions)
|
||||
: std::runtime_error("Error with function dispatch"), parameters(t_parameters), functions(t_functions)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~dispatch_error() noexcept {}
|
||||
|
||||
std::vector<Boxed_Value> parameters;
|
||||
std::vector<Const_Proxy_Function> functions;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -581,6 +582,7 @@ namespace chaiscript
|
||||
Boxed_Value dispatch(InItr begin, const InItr &end,
|
||||
const std::vector<Boxed_Value> &plist)
|
||||
{
|
||||
InItr orig(begin);
|
||||
while (begin != end)
|
||||
{
|
||||
try {
|
||||
@@ -599,7 +601,7 @@ namespace chaiscript
|
||||
++begin;
|
||||
}
|
||||
|
||||
throw exception::dispatch_error(plist);
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -69,18 +69,23 @@ namespace chaiscript
|
||||
File_Position start_position;
|
||||
File_Position end_position;
|
||||
std::string filename;
|
||||
std::string detail;
|
||||
std::vector<AST_NodePtr> call_stack;
|
||||
|
||||
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
|
||||
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
|
||||
std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_ss)),
|
||||
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname)
|
||||
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
||||
bool t_dot_notation,
|
||||
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
|
||||
std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)),
|
||||
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
|
||||
{}
|
||||
|
||||
eval_error(const std::string &t_why,
|
||||
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
|
||||
std::runtime_error(format(t_why, t_parameters, t_ss)),
|
||||
reason(t_why)
|
||||
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
||||
bool t_dot_notation,
|
||||
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
|
||||
std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)),
|
||||
reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss))
|
||||
{}
|
||||
|
||||
|
||||
@@ -94,29 +99,203 @@ namespace chaiscript
|
||||
reason(t_why)
|
||||
{}
|
||||
|
||||
std::string pretty_print() const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
|
||||
ss << what();
|
||||
if (call_stack.size() > 0) {
|
||||
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")" << std::endl;
|
||||
ss << std::endl << detail << std::endl;
|
||||
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
|
||||
for (size_t j = 1; j < call_stack.size(); ++j) {
|
||||
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
|
||||
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File)
|
||||
{
|
||||
ss << std::endl;
|
||||
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
|
||||
}
|
||||
}
|
||||
}
|
||||
ss << std::endl;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
virtual ~eval_error() noexcept {}
|
||||
|
||||
private:
|
||||
|
||||
template<typename T>
|
||||
static int id(const T& t)
|
||||
{
|
||||
return t->identifier;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string pretty(const T& t)
|
||||
{
|
||||
return t->pretty_print();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string fname(const T& t)
|
||||
{
|
||||
return *t->filename;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string startpos(const T& t)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << t->start.line << ", " << t->start.column;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static std::string format_why(const std::string &t_why)
|
||||
{
|
||||
return "Error: \"" + t_why + "\"";
|
||||
}
|
||||
|
||||
static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters,
|
||||
static std::string format_types(const Const_Proxy_Function &t_func,
|
||||
bool t_dot_notation,
|
||||
const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
{
|
||||
int arity = t_func->get_arity();
|
||||
std::vector<Type_Info> types = t_func->get_param_types();
|
||||
|
||||
std::string retval;
|
||||
if (arity == -1)
|
||||
{
|
||||
retval = "(...)";
|
||||
if (t_dot_notation)
|
||||
{
|
||||
retval = "(Object)." + retval;
|
||||
}
|
||||
} else if (types.size() <= 1) {
|
||||
retval = "()";
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
ss << "(";
|
||||
|
||||
std::string paramstr;
|
||||
|
||||
for (size_t index = 1;
|
||||
index != types.size();
|
||||
++index)
|
||||
{
|
||||
paramstr += (types[index].is_const()?"const ":"");
|
||||
paramstr += t_ss.get_type_name(types[index]);
|
||||
|
||||
if (index == 1 && t_dot_notation)
|
||||
{
|
||||
paramstr += ").(";
|
||||
if (types.size() == 2)
|
||||
{
|
||||
paramstr += ", ";
|
||||
}
|
||||
} else {
|
||||
paramstr += ", ";
|
||||
}
|
||||
}
|
||||
|
||||
ss << paramstr.substr(0, paramstr.size() - 2);
|
||||
|
||||
ss << ")";
|
||||
retval = ss.str();
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
|
||||
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
|
||||
|
||||
if (dynfun)
|
||||
{
|
||||
Proxy_Function f = dynfun->get_guard();
|
||||
|
||||
if (f)
|
||||
{
|
||||
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfunguard
|
||||
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
|
||||
if (dynfunguard)
|
||||
{
|
||||
retval += " : " + format_guard(dynfunguard->get_parse_tree());
|
||||
}
|
||||
}
|
||||
|
||||
retval += "\n Defined at " + format_location(dynfun->get_parse_tree());
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string format_guard(const T &t)
|
||||
{
|
||||
return t->pretty_print();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string format_location(const T &t)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "(" << *t->filename << " " << t->start.line << ", " << t->start.column << ")";
|
||||
|
||||
return oss.str();
|
||||
|
||||
}
|
||||
|
||||
static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
||||
bool t_dot_notation,
|
||||
const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "With parameters: (";
|
||||
if (t_functions.size() == 1)
|
||||
{
|
||||
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << std::endl;
|
||||
} else {
|
||||
ss << " " << t_functions.size() << " overloads available:" << std::endl;
|
||||
|
||||
for (std::vector<chaiscript::Const_Proxy_Function>::const_iterator itr = t_functions.begin();
|
||||
itr != t_functions.end();
|
||||
++itr)
|
||||
{
|
||||
ss << " " << format_types((*itr), t_dot_notation, t_ss) << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
|
||||
}
|
||||
|
||||
static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters,
|
||||
bool t_dot_notation,
|
||||
const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "(";
|
||||
|
||||
if (!t_parameters.empty())
|
||||
{
|
||||
std::string paramstr;
|
||||
|
||||
for (const Boxed_Value &bv: t_parameters)
|
||||
for (std::vector<Boxed_Value>::const_iterator itr = t_parameters.begin();
|
||||
itr != t_parameters.end();
|
||||
++itr)
|
||||
{
|
||||
paramstr += (bv.is_const()?"const ":"");
|
||||
paramstr += t_ss.type_name(bv);
|
||||
paramstr += ", ";
|
||||
paramstr += (itr->is_const()?"const ":"");
|
||||
paramstr += t_ss.type_name(*itr);
|
||||
|
||||
if (itr == t_parameters.begin() && t_dot_notation)
|
||||
{
|
||||
paramstr += ").(";
|
||||
if (t_parameters.size() == 1)
|
||||
{
|
||||
paramstr += ", ";
|
||||
}
|
||||
} else {
|
||||
paramstr += ", ";
|
||||
}
|
||||
}
|
||||
|
||||
ss << paramstr.substr(0, paramstr.size() - 2);
|
||||
@@ -148,14 +327,14 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
|
||||
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << format_why(t_why);
|
||||
ss << " ";
|
||||
|
||||
ss << format_parameters(t_parameters, t_ss);
|
||||
ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
|
||||
ss << " ";
|
||||
|
||||
ss << format_filename(t_fname);
|
||||
@@ -167,14 +346,16 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
static std::string format(const std::string &t_why,
|
||||
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
const std::vector<Boxed_Value> &t_parameters,
|
||||
bool t_dot_notation,
|
||||
const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << format_why(t_why);
|
||||
ss << " ";
|
||||
|
||||
ss << format_parameters(t_parameters, t_ss);
|
||||
ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
|
||||
ss << " ";
|
||||
|
||||
return ss.str();
|
||||
@@ -220,6 +401,19 @@ namespace chaiscript
|
||||
std::vector<AST_NodePtr> children;
|
||||
AST_NodePtr annotation;
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << text;
|
||||
|
||||
for (unsigned int j = 0; j < this->children.size(); ++j) {
|
||||
oss << this->children[j]->pretty_print();
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the contents of an AST node, including its children, recursively
|
||||
*/
|
||||
|
@@ -718,6 +718,8 @@ namespace chaiscript
|
||||
/// \tparam T Type to extract from the result value of the script execution
|
||||
/// \param[in] t_input Script to execute
|
||||
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
|
||||
/// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful
|
||||
/// in special cases where you are loading a file internally instead of using eval_file
|
||||
///
|
||||
/// \return result of the script execution
|
||||
///
|
||||
@@ -725,10 +727,10 @@ namespace chaiscript
|
||||
/// \throw chaiscript::exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
|
||||
/// to the requested type.
|
||||
template<typename T>
|
||||
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler())
|
||||
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
|
||||
{
|
||||
try {
|
||||
return boxed_cast<T>(do_eval(t_input));
|
||||
return boxed_cast<T>(do_eval(t_input, t_filename));
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv);
|
||||
@@ -741,14 +743,16 @@ namespace chaiscript
|
||||
///
|
||||
/// \param[in] t_input Script to execute
|
||||
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
|
||||
/// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful
|
||||
/// in special cases where you are loading a file internally instead of using eval_file
|
||||
///
|
||||
/// \return result of the script execution
|
||||
///
|
||||
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler())
|
||||
/// \throw exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
|
||||
{
|
||||
try {
|
||||
return do_eval(t_input);
|
||||
return do_eval(t_input, t_filename);
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv);
|
||||
|
@@ -50,6 +50,16 @@ namespace chaiscript
|
||||
this->children[2]->eval(t_ss));
|
||||
}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
if (children.size() == 3)
|
||||
{
|
||||
return "(" + this->children[0]->pretty_print() + " " + this->children[1]->text + " " + this->children[2]->pretty_print() + ")";
|
||||
} else {
|
||||
return "(" + this->children[0]->pretty_print() + " " + text + " " + this->children[1]->pretty_print() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_oper(chaiscript::detail::Dispatch_Engine &t_ss,
|
||||
Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
@@ -76,7 +86,7 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, t_ss);
|
||||
throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, t_ss);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -182,6 +192,11 @@ namespace chaiscript
|
||||
Eol_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Eol, const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||
virtual ~Eol_AST_Node() {}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
return "\n";
|
||||
}
|
||||
};
|
||||
|
||||
struct Fun_Call_AST_Node : public AST_Node {
|
||||
@@ -202,29 +217,55 @@ namespace chaiscript
|
||||
fpp.save_params(params);
|
||||
|
||||
|
||||
Boxed_Value fn = this->children[0]->eval(t_ss);
|
||||
try {
|
||||
Boxed_Value fn = this->children[0]->eval(t_ss);
|
||||
|
||||
try {
|
||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
||||
const Boxed_Value &retval = (*boxed_cast<const Const_Proxy_Function &>(fn))(params);
|
||||
return retval;
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, t_ss);
|
||||
}
|
||||
catch(detail::Return_Value &rv) {
|
||||
return rv.retval;
|
||||
}
|
||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
||||
const Boxed_Value &retval = (*boxed_cast<const Const_Proxy_Function &>(fn))(params);
|
||||
return retval;
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, t_ss);
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
|
||||
}
|
||||
catch(const exception::bad_boxed_cast &){
|
||||
try {
|
||||
Const_Proxy_Function f = boxed_cast<const Const_Proxy_Function &>(fn);
|
||||
// handle the case where there is only 1 function to try to call and dispatch fails on it
|
||||
std::vector<Const_Proxy_Function> funcs;
|
||||
funcs.push_back(f);
|
||||
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, funcs, false, t_ss);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
|
||||
}
|
||||
}
|
||||
catch(const exception::arity_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
|
||||
}
|
||||
catch(const exception::guard_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
|
||||
}
|
||||
catch(detail::Return_Value &rv) {
|
||||
return rv.retval;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
for (unsigned int j = 0; j < this->children.size(); ++j) {
|
||||
oss << this->children[j]->pretty_print();
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
oss << "(";
|
||||
}
|
||||
}
|
||||
|
||||
oss << ")";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Inplace_Fun_Call_AST_Node : public AST_Node {
|
||||
@@ -241,18 +282,53 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
Boxed_Value bv;
|
||||
Const_Proxy_Function fn;
|
||||
|
||||
try {
|
||||
return (*boxed_cast<const Const_Proxy_Function &>(this->children[0]->eval(t_ss)))(params);
|
||||
bv = this->children[0]->eval(t_ss);
|
||||
try {
|
||||
fn = boxed_cast<const Const_Proxy_Function &>(bv);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
|
||||
}
|
||||
return (*fn)(params);
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, t_ss);
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
|
||||
}
|
||||
catch(const exception::bad_boxed_cast &){
|
||||
// handle the case where there is only 1 function to try to call and dispatch fails on it
|
||||
std::vector<Const_Proxy_Function> funcs;
|
||||
funcs.push_back(fn);
|
||||
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, funcs, false, t_ss);
|
||||
}
|
||||
catch(const exception::arity_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
|
||||
}
|
||||
catch(const exception::guard_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
|
||||
}
|
||||
catch(detail::Return_Value &rv) {
|
||||
return rv.retval;
|
||||
}
|
||||
catch(...) {
|
||||
throw;
|
||||
}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
for (unsigned int j = 0; j < this->children.size(); ++j) {
|
||||
oss << this->children[j]->pretty_print();
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
oss << "(";
|
||||
}
|
||||
}
|
||||
|
||||
oss << ")";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
};
|
||||
@@ -262,6 +338,21 @@ namespace chaiscript
|
||||
Arg_List_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Arg_List, const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||
virtual ~Arg_List_AST_Node() {}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
for (unsigned int j = 0; j < this->children.size(); ++j) {
|
||||
if (j != 0)
|
||||
{
|
||||
oss << ", ";
|
||||
}
|
||||
|
||||
oss << this->children[j]->pretty_print();
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct Variable_AST_Node : public AST_Node {
|
||||
@@ -315,11 +406,11 @@ namespace chaiscript
|
||||
retval = t_ss.call_function(this->children[1]->text, lhs, retval);
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, t_ss);
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss);
|
||||
}
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, t_ss);
|
||||
throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, t_ss);
|
||||
}
|
||||
}
|
||||
else if (this->children[1]->text == ":=") {
|
||||
@@ -333,7 +424,7 @@ namespace chaiscript
|
||||
try {
|
||||
retval = t_ss.call_function(this->children[1]->text, lhs, retval);
|
||||
} catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, t_ss);
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,6 +457,11 @@ namespace chaiscript
|
||||
|
||||
}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
return "var " + this->children[0]->text;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Comparison_AST_Node : public Binary_Operator_AST_Node {
|
||||
@@ -377,7 +473,7 @@ namespace chaiscript
|
||||
|
||||
struct Addition_AST_Node : public Binary_Operator_AST_Node {
|
||||
public:
|
||||
Addition_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Addition,
|
||||
Addition_AST_Node(const std::string &t_ast_node_text = "+", int t_id = AST_Node_Type::Addition,
|
||||
const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(),
|
||||
int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||
Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||
@@ -389,7 +485,7 @@ namespace chaiscript
|
||||
|
||||
struct Subtraction_AST_Node : public Binary_Operator_AST_Node {
|
||||
public:
|
||||
Subtraction_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Subtraction,
|
||||
Subtraction_AST_Node(const std::string &t_ast_node_text = "-", int t_id = AST_Node_Type::Subtraction,
|
||||
const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0,
|
||||
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||
Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||
@@ -401,7 +497,7 @@ namespace chaiscript
|
||||
|
||||
struct Multiplication_AST_Node : public Binary_Operator_AST_Node {
|
||||
public:
|
||||
Multiplication_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Multiplication,
|
||||
Multiplication_AST_Node(const std::string &t_ast_node_text = "*", int t_id = AST_Node_Type::Multiplication,
|
||||
const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0,
|
||||
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||
Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||
@@ -413,7 +509,7 @@ namespace chaiscript
|
||||
|
||||
struct Division_AST_Node : public Binary_Operator_AST_Node {
|
||||
public:
|
||||
Division_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Division,
|
||||
Division_AST_Node(const std::string &t_ast_node_text = "/", int t_id = AST_Node_Type::Division,
|
||||
const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0,
|
||||
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||
Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||
@@ -425,7 +521,7 @@ namespace chaiscript
|
||||
|
||||
struct Modulus_AST_Node : public Binary_Operator_AST_Node {
|
||||
public:
|
||||
Modulus_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Modulus,
|
||||
Modulus_AST_Node(const std::string &t_ast_node_text = "%", int t_id = AST_Node_Type::Modulus,
|
||||
const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0,
|
||||
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||
Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||
@@ -460,12 +556,27 @@ namespace chaiscript
|
||||
throw exception::eval_error("Out of bounds exception");
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, t_ss );
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, t_ss );
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << this->children[0]->pretty_print();
|
||||
|
||||
for (size_t i = 1; i < this->children.size(); ++i)
|
||||
{
|
||||
oss << "[";
|
||||
oss << this->children[i]->pretty_print();
|
||||
oss << "]";
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct Dot_Access_AST_Node : public AST_Node {
|
||||
@@ -503,7 +614,12 @@ namespace chaiscript
|
||||
retval = t_ss.call_function(fun_name, params);
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " for function: " + fun_name, e.parameters, t_ss);
|
||||
if (e.functions.empty())
|
||||
{
|
||||
throw exception::eval_error("'" + fun_name + "' is not a function.");
|
||||
} else {
|
||||
throw exception::eval_error(std::string(e.what()) + " for function '" + fun_name + "'", e.parameters, e.functions, true, t_ss);
|
||||
}
|
||||
}
|
||||
catch(detail::Return_Value &rv) {
|
||||
retval = rv.retval;
|
||||
@@ -518,7 +634,7 @@ namespace chaiscript
|
||||
throw exception::eval_error("Out of bounds exception");
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, t_ss);
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, t_ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -540,6 +656,11 @@ namespace chaiscript
|
||||
return m_value;
|
||||
}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
return "\"" + text + "\"";
|
||||
}
|
||||
|
||||
private:
|
||||
Boxed_Value m_value;
|
||||
|
||||
@@ -555,6 +676,11 @@ namespace chaiscript
|
||||
return m_value;
|
||||
}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
return "'" + text + "'";
|
||||
}
|
||||
|
||||
private:
|
||||
Boxed_Value m_value;
|
||||
};
|
||||
@@ -938,7 +1064,7 @@ namespace chaiscript
|
||||
return const_var(retval);
|
||||
}
|
||||
catch (const exception::dispatch_error &e) {
|
||||
throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, t_ss);
|
||||
throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,7 +1146,7 @@ namespace chaiscript
|
||||
return t_ss.call_function(this->children[0]->text, bv);
|
||||
}
|
||||
} catch (const exception::dispatch_error &e) {
|
||||
throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, t_ss);
|
||||
throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1062,7 +1188,7 @@ namespace chaiscript
|
||||
this->children[0]->children[0]->children[1]->eval(t_ss));
|
||||
}
|
||||
catch (const exception::dispatch_error &e) {
|
||||
throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, t_ss);
|
||||
throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1392,6 +1518,11 @@ namespace chaiscript
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
return "(" + AST_Node::pretty_print() + ")";
|
||||
}
|
||||
};
|
||||
|
||||
struct Logical_Or_AST_Node : public AST_Node {
|
||||
@@ -1419,6 +1550,11 @@ namespace chaiscript
|
||||
return retval;
|
||||
}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
{
|
||||
return "(" + AST_Node::pretty_print() + ")";
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
13
src/main.cpp
13
src/main.cpp
@@ -233,18 +233,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
catch (const chaiscript::exception::eval_error &ee) {
|
||||
std::cout << ee.what();
|
||||
if (ee.call_stack.size() > 0) {
|
||||
std::cout << "during evaluation at (" << *(ee.call_stack[0]->filename) << " " << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")";
|
||||
for (size_t j = 1; j < ee.call_stack.size(); ++j) {
|
||||
if (ee.call_stack[j]->identifier != chaiscript::AST_Node_Type::Block
|
||||
&& ee.call_stack[j]->identifier != chaiscript::AST_Node_Type::File)
|
||||
{
|
||||
std::cout << std::endl;
|
||||
std::cout << " from " << *(ee.call_stack[j]->filename) << " (" << ee.call_stack[j]->start.line << ", " << ee.call_stack[j]->start.column << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << ee.pretty_print();
|
||||
std::cout << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
111
unittests/expected_eval_errors_test.cpp
Normal file
111
unittests/expected_eval_errors_test.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
// Tests to make sure no arity, dispatch or guard errors leak up past eval
|
||||
|
||||
#include <chaiscript/utility/utility.hpp>
|
||||
|
||||
int test_one(const int &)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(chaiscript::fun(&test_one), "test_fun");
|
||||
|
||||
chai.eval("def guard_fun(i) : i.get_type_info().is_type_arithmetic() {} ");
|
||||
|
||||
bool eval_error = true;
|
||||
|
||||
// Dot notation
|
||||
|
||||
try {
|
||||
// non-existant function
|
||||
chai.eval("\"test\".test_one()");
|
||||
eval_error = false;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
}
|
||||
|
||||
try {
|
||||
// wrong parameter type
|
||||
chai.eval("\"test\".test_fun()");
|
||||
eval_error = false;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
}
|
||||
|
||||
try {
|
||||
// wrong number of parameters
|
||||
chai.eval("\"test\".test_fun(1)");
|
||||
eval_error = false;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
}
|
||||
|
||||
try {
|
||||
// guard failure
|
||||
chai.eval("\"test\".guard_fun(1)");
|
||||
eval_error = false;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// regular notation
|
||||
|
||||
try {
|
||||
// non-existant function
|
||||
chai.eval("test_one(\"test\")");
|
||||
eval_error = false;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
}
|
||||
|
||||
try {
|
||||
// wrong parameter type
|
||||
chai.eval("test_fun(\"test\")");
|
||||
eval_error = false;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
}
|
||||
|
||||
try {
|
||||
// wrong number of parameters
|
||||
chai.eval("test_fun(\"test\")");
|
||||
eval_error = false;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
}
|
||||
|
||||
try {
|
||||
// guard failure
|
||||
chai.eval("guard_fun(\"test\")");
|
||||
eval_error = false;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
}
|
||||
|
||||
|
||||
// index operator
|
||||
try {
|
||||
chai.eval("var a = [1,2,3]; a[\"bob\"];");
|
||||
eval_error = false;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
}
|
||||
|
||||
// unary operator
|
||||
try {
|
||||
chai.eval("++\"bob\"");
|
||||
eval_error = false;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
}
|
||||
|
||||
// binary operator
|
||||
try {
|
||||
chai.eval("\"bob\" + 1");
|
||||
eval_error = false;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
}
|
||||
|
||||
|
||||
if (eval_error)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user