Enhance eval error stack reporting

Use OOP to avoid code duplication for eval error tracking. This results
in much more robust stack error reporting and 400 LOC less.
This commit is contained in:
Jason Turner
2011-03-27 21:03:24 -06:00
parent de5822873b
commit 79e8af4f6e
6 changed files with 260 additions and 504 deletions

View File

@@ -8,6 +8,7 @@
#define CHAISCRIPT_COMMON_HPP_
#include <chaiscript/dispatchkit/dispatchkit.hpp>
#include <boost/enable_shared_from_this.hpp>
namespace chaiscript
{
@@ -57,65 +58,6 @@ namespace chaiscript
typedef boost::shared_ptr<struct AST_Node> AST_NodePtr;
/**
* The struct that doubles as both a parser ast_node and an AST node
*/
struct AST_Node {
public:
const std::string text;
const int identifier;
boost::shared_ptr<const std::string> filename;
File_Position start, end;
std::vector<AST_NodePtr> children;
AST_NodePtr annotation;
/**
* Prints the contents of an AST node, including its children, recursively
*/
std::string to_string(std::string t_prepend = "") {
std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
<< this->text << " : " << this->start.line << ", " << this->start.column << std::endl;
for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->to_string(t_prepend + " ");
}
return oss.str();
}
std::string internal_to_string() {
return to_string();
}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &)
{
throw std::runtime_error("Undispatched ast_node (internal error)");
}
void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child)
{
std::replace(children.begin(), children.end(), t_child, t_new_child);
}
protected:
AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr<std::string> &t_fname,
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
text(t_ast_node_text), identifier(t_id), filename(t_fname),
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
{
}
AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr<std::string> &t_fname) :
text(t_ast_node_text), identifier(t_id), filename(t_fname) {}
virtual ~AST_Node() {}
};
namespace exception
{
/**
@@ -157,6 +99,76 @@ namespace chaiscript
}
/**
* The struct that doubles as both a parser ast_node and an AST node
*/
struct AST_Node : boost::enable_shared_from_this<AST_Node> {
public:
const std::string text;
const int identifier;
boost::shared_ptr<const std::string> filename;
File_Position start, end;
std::vector<AST_NodePtr> children;
AST_NodePtr annotation;
/**
* Prints the contents of an AST node, including its children, recursively
*/
std::string to_string(std::string t_prepend = "") {
std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
<< this->text << " : " << this->start.line << ", " << this->start.column << std::endl;
for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->to_string(t_prepend + " ");
}
return oss.str();
}
std::string internal_to_string() {
return to_string();
}
Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e)
{
try {
return eval_internal(t_e);
} catch (exception::eval_error &ee) {
ee.call_stack.push_back(shared_from_this());
throw ee;
}
}
void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child)
{
std::replace(children.begin(), children.end(), t_child, t_new_child);
}
protected:
AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr<std::string> &t_fname,
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
text(t_ast_node_text), identifier(t_id), filename(t_fname),
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
{
}
AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr<std::string> &t_fname) :
text(t_ast_node_text), identifier(t_id), filename(t_fname) {}
virtual ~AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &)
{
throw std::runtime_error("Undispatched ast_node (internal error)");
}
};
namespace detail
{
/**

View File

@@ -28,9 +28,6 @@ namespace chaiscript
return t_node->eval(t_ss);
} catch (const detail::Return_Value &rv) {
return rv.retval;
} catch (exception::eval_error &ee) {
ee.call_stack.push_back(t_node);
throw;
}
}
@@ -42,16 +39,10 @@ namespace chaiscript
Binary_Operator_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Bitwise_Xor, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Binary_Operator_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
Boxed_Value retval;
try {
retval = this->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
for (size_t i = 1; i < this->children.size(); i += 2) {
try {
@@ -60,10 +51,6 @@ namespace chaiscript
catch(const exception::dispatch_error &){
throw exception::eval_error("Can not find appropriate '" + this->children[i]->text + "'");
}
catch(exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i+1]);
throw;
}
}
return retval;
@@ -85,7 +72,7 @@ namespace chaiscript
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_value(const_var(int(atoi(this->text.c_str())))) { }
virtual ~Int_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){
return m_value;
}
@@ -100,7 +87,7 @@ namespace chaiscript
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_value(const_var(double(atof(this->text.c_str())))) { }
virtual ~Float_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){
return m_value;
}
@@ -114,7 +101,7 @@ namespace chaiscript
Id_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Id, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Id_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
if (this->text == "true") {
return const_var(true);
}
@@ -164,19 +151,13 @@ namespace chaiscript
Fun_Call_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Fun_Call, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Fun_Call_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
dispatch::Param_List_Builder plb;
if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
for (size_t i = 0; i < this->children[1]->children.size(); ++i) {
try {
plb << this->children[1]->children[i]->eval(t_ss);
}
catch(exception::eval_error &ee) {
ee.call_stack.push_back(this->children[1]->children[i]);
throw;
}
}
}
chaiscript::detail::Dispatch_Engine::Stack prev_stack = t_ss.get_stack();
@@ -205,9 +186,8 @@ namespace chaiscript
}
}
catch(exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
t_ss.set_stack(prev_stack);
throw exception::eval_error(ee.reason);
throw;
}
}
@@ -219,22 +199,15 @@ namespace chaiscript
Inplace_Fun_Call_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inplace_Fun_Call, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Inplace_Fun_Call_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
dispatch::Param_List_Builder plb;
if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
for (size_t i = 0; i < this->children[1]->children.size(); ++i) {
try {
plb << this->children[1]->children[i]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[1]->children[i]);
throw;
}
}
}
try {
Boxed_Value fn = this->children[0]->eval(t_ss);
try {
@@ -250,12 +223,6 @@ namespace chaiscript
throw;
}
}
catch(exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw exception::eval_error(ee.reason);
}
}
};
@@ -278,20 +245,12 @@ namespace chaiscript
Equation_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Equation, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Equation_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
Boxed_Value retval;
try {
retval = this->children.back()->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children.back());
throw;
}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
Boxed_Value retval = this->children.back()->eval(t_ss);
if (this->children.size() > 1) {
for (int i = static_cast<int>(this->children.size())-3; i >= 0; i -= 2) {
if (this->children[i+1]->text == "=") {
try {
Boxed_Value lhs = this->children[i]->eval(t_ss);
try {
@@ -311,37 +270,20 @@ namespace chaiscript
throw exception::eval_error("Can not clone right hand side of equation");
}
}
catch(exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i]);
throw;
}
}
else if (this->children[i+1]->text == ":=") {
try {
Boxed_Value lhs = this->children[i]->eval(t_ss);
if (lhs.is_undef() || type_match(lhs, retval)) {
lhs.assign(retval);
}
else {
} else {
throw exception::eval_error("Mismatched types in equation");
}
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i]);
throw;
}
}
else {
try {
retval = t_ss.call_function(this->children[i+1]->text, this->children[i]->eval(t_ss), retval);
}
catch(const exception::dispatch_error &){
} catch(const exception::dispatch_error &){
throw exception::eval_error("Can not find appropriate '" + this->children[i+1]->text + "'");
}
catch(exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i]);
throw;
}
}
}
}
@@ -354,7 +296,7 @@ namespace chaiscript
Var_Decl_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Var_Decl, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Var_Decl_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
try {
t_ss.add_object(this->children[0]->text, Boxed_Value());
}
@@ -392,16 +334,8 @@ namespace chaiscript
Array_Call_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Array_Call, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Array_Call_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
Boxed_Value retval;
try {
retval = this->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
Boxed_Value retval = this->children[0]->eval(t_ss);
for (size_t i = 1; i < this->children.size(); ++i) {
try {
@@ -413,10 +347,6 @@ namespace chaiscript
catch(const exception::dispatch_error &){
throw exception::eval_error("Can not find appropriate array lookup '[]' ");
}
catch(exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i]);
throw;
}
}
return retval;
@@ -428,15 +358,8 @@ namespace chaiscript
Dot_Access_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Dot_Access, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Dot_Access_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
Boxed_Value retval;
try {
retval = this->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
Boxed_Value retval = this->children[0]->eval(t_ss);
if (this->children.size() > 1) {
for (size_t i = 2; i < this->children.size(); i+=2) {
@@ -445,14 +368,8 @@ namespace chaiscript
if (this->children[i]->children.size() > 1) {
for (size_t j = 0; j < this->children[i]->children[1]->children.size(); ++j) {
try {
plb << this->children[i]->children[1]->children[j]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i]->children[1]->children[j]);
throw;
}
}
}
std::string fun_name;
@@ -494,10 +411,6 @@ namespace chaiscript
catch(const exception::dispatch_error &){
throw exception::eval_error("Can not find appropriate array lookup '[]' ");
}
catch(exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i]->children[j]);
throw;
}
}
}
}
@@ -514,7 +427,7 @@ namespace chaiscript
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_value(const_var(this->text)) { }
virtual ~Quoted_String_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &) {
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) {
return m_value;
}
@@ -529,7 +442,7 @@ namespace chaiscript
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_value(const_var(char(this->text[0]))) { }
virtual ~Single_Quoted_String_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){
return m_value;
}
@@ -542,7 +455,7 @@ namespace chaiscript
Lambda_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Lambda, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Lambda_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
std::vector<std::string> t_param_names;
size_t numparams = 0;
@@ -570,7 +483,7 @@ namespace chaiscript
Block_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Block, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Block_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
const size_t num_children = this->children.size();
detail::Scope_Push_Pop spp(t_ss);
@@ -587,10 +500,6 @@ namespace chaiscript
catch (const chaiscript::detail::Return_Value &) {
throw;
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i]);
throw;
}
}
return Boxed_Value();
@@ -603,7 +512,7 @@ namespace chaiscript
Def_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Def, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Def_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
std::vector<std::string> t_param_names;
size_t numparams = 0;
AST_NodePtr guardnode;
@@ -657,7 +566,7 @@ namespace chaiscript
While_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::While, const boost::shared_ptr<std::string> &t_fname=boost::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 ~While_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss) {
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
bool cond;
detail::Scope_Push_Pop spp(t_ss);
@@ -668,19 +577,9 @@ namespace chaiscript
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("While condition not boolean");
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
while (cond) {
try {
try {
this->children[1]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[1]);
throw;
}
try {
cond = boxed_cast<bool>(this->children[0]->eval(t_ss));
@@ -688,10 +587,6 @@ namespace chaiscript
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("While condition not boolean");
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
}
catch (detail::Break_Loop &) {
cond = false;
@@ -707,7 +602,7 @@ namespace chaiscript
If_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::If, const boost::shared_ptr<std::string> &t_fname=boost::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 ~If_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
bool cond;
try {
cond = boxed_cast<bool>(this->children[0]->eval(t_ss));
@@ -715,33 +610,17 @@ namespace chaiscript
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("If condition not boolean");
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
if (cond) {
try {
return this->children[1]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[1]);
throw;
}
}
else {
if (this->children.size() > 2) {
size_t i = 2;
while ((!cond) && (i < this->children.size())) {
if (this->children[i]->text == "else") {
try {
return this->children[i+1]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i+1]);
throw;
}
}
else if (this->children[i]->text == "else if") {
try {
cond = boxed_cast<bool>(this->children[i+1]->eval(t_ss));
@@ -749,19 +628,9 @@ namespace chaiscript
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("'else if' condition not boolean");
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i+1]);
throw;
}
if (cond) {
try {
return this->children[i+2]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i+2]);
throw;
}
}
}
i = i + 3;
}
@@ -778,38 +647,19 @@ namespace chaiscript
For_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::For, const boost::shared_ptr<std::string> &t_fname=boost::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 ~For_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
bool cond;
detail::Scope_Push_Pop spp(t_ss);
try {
if (this->children.size() == 4) {
try {
this->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
try {
cond = boxed_cast<bool>(this->children[1]->eval(t_ss));
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[1]);
throw;
}
}
else {
try {
} else {
cond = boxed_cast<bool>(this->children[0]->eval(t_ss));
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
}
}
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("For condition not boolean");
@@ -817,55 +667,18 @@ namespace chaiscript
while (cond) {
try {
if (this->children.size() == 4) {
try {
this->children[3]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[3]);
throw;
}
try {
this->children[2]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[2]);
throw;
}
try {
cond = boxed_cast<bool>(this->children[1]->eval(t_ss));
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[1]);
throw;
}
}
else {
try {
this->children[2]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[2]);
throw;
}
try {
this->children[1]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[1]);
throw;
}
try {
cond = boxed_cast<bool>(this->children[0]->eval(t_ss));
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
}
}
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("For condition not boolean");
@@ -884,18 +697,12 @@ namespace chaiscript
Inline_Array_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Array, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Inline_Array_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
std::vector<Boxed_Value> vec;
if (this->children.size() > 0) {
for (size_t i = 0; i < this->children[0]->children.size(); ++i) {
try {
vec.push_back(this->children[0]->children[i]->eval(t_ss));
}
catch(exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]->children[i]);
throw;
}
}
}
return const_var(vec);
@@ -908,19 +715,13 @@ namespace chaiscript
Inline_Map_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Map, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Inline_Map_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
try {
std::map<std::string, Boxed_Value> retval;
for (size_t i = 0; i < this->children[0]->children.size(); ++i) {
try {
retval[boxed_cast<std::string>(this->children[0]->children[i]->children[0]->eval(t_ss))]
= t_ss.call_function("clone", this->children[0]->children[i]->children[1]->eval(t_ss));
}
catch(exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]->children[i]);
throw;
}
}
return const_var(retval);
}
catch (const exception::dispatch_error &) {
@@ -935,16 +736,10 @@ namespace chaiscript
Return_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Return, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Return_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
if (this->children.size() > 0) {
try {
throw detail::Return_Value(this->children[0]->eval(t_ss));
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
}
else {
throw detail::Return_Value(Boxed_Value());
}
@@ -957,20 +752,14 @@ namespace chaiscript
File_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::File, const boost::shared_ptr<std::string> &t_fname=boost::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 ~File_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss) {
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
const size_t size = this->children.size();
for (size_t i = 0; i < size; ++i) {
try {
const Boxed_Value &retval = this->children[i]->eval(t_ss);
if (i + 1 == size) {
return retval;
}
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i]);
throw;
}
}
return Boxed_Value();
}
};
@@ -980,14 +769,9 @@ namespace chaiscript
Prefix_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Prefix, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Prefix_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
try {
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
return t_ss.call_function(this->children[0]->text, this->children[1]->eval(t_ss));
}
catch(std::exception &){
throw exception::eval_error("Can not find appropriate unary '" + this->children[0]->text + "'");
}
}
};
@@ -996,7 +780,7 @@ namespace chaiscript
Break_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Break, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Break_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){
throw detail::Break_Loop();
}
};
@@ -1020,7 +804,7 @@ namespace chaiscript
Inline_Range_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Range, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Inline_Range_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
try {
return t_ss.call_function("generate_range",
this->children[0]->children[0]->children[0]->eval(t_ss),
@@ -1029,10 +813,6 @@ namespace chaiscript
catch (const exception::dispatch_error &) {
throw exception::eval_error("Unable to generate range vector");
}
catch(exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]->children[0]);
throw;
}
}
};
@@ -1049,7 +829,7 @@ namespace chaiscript
Try_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Try, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Try_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
Boxed_Value retval;
detail::Scope_Push_Pop spp(t_ss);
@@ -1058,16 +838,9 @@ namespace chaiscript
retval = this->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
if (this->children.back()->identifier == AST_Node_Type::Finally) {
try {
this->children.back()->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee2) {
ee2.call_stack.push_back(this->children.back()->children[0]);
throw;
}
}
throw;
}
catch (const std::exception &e) {
@@ -1083,25 +856,13 @@ namespace chaiscript
if (catch_block->children.size() == 1) {
//No variable capture, no guards
try {
retval = catch_block->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(catch_block->children[0]);
throw;
}
break;
}
else if (catch_block->children.size() == 2) {
//Variable capture, no guards
t_ss.add_object(catch_block->children[0]->text, except);
try {
retval = catch_block->children[1]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(catch_block->children[1]);
throw;
}
break;
}
@@ -1114,38 +875,19 @@ namespace chaiscript
guard = boxed_cast<bool>(catch_block->children[1]->eval(t_ss));
} catch (const exception::bad_boxed_cast &) {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
try {
this->children.back()->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children.back()->children[0]);
throw;
}
}
throw exception::eval_error("Guard condition not boolean");
}
if (guard) {
try {
retval = catch_block->children[2]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(catch_block->children[2]);
throw;
}
break;
}
}
else {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
try {
this->children.back()->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children.back()->children[0]);
throw;
}
}
throw exception::eval_error("Internal error: catch block size unrecognized");
}
}
@@ -1156,27 +898,13 @@ namespace chaiscript
if (catch_block->children.size() == 1) {
//No variable capture, no guards
try {
retval = catch_block->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(catch_block->children[0]);
throw;
}
break;
}
else if (catch_block->children.size() == 2) {
//Variable capture, no guards
t_ss.add_object(catch_block->children[0]->text, except);
try {
retval = catch_block->children[1]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(catch_block->children[1]);
throw;
}
break;
}
else if (catch_block->children.size() == 3) {
@@ -1189,68 +917,34 @@ namespace chaiscript
}
catch (const exception::bad_boxed_cast &) {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
try {
this->children.back()->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children.back()->children[0]);
throw;
}
}
throw exception::eval_error("Guard condition not boolean");
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(catch_block->children[1]);
throw;
}
if (guard) {
try {
retval = catch_block->children[2]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(catch_block->children[2]);
throw;
}
break;
}
}
else {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
try {
this->children.back()->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children.back()->children[0]);
throw;
}
}
throw exception::eval_error("Internal error: catch block size unrecognized");
}
}
}
catch (...) {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
try {
this->children.back()->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children.back()->children[0]);
throw;
}
}
throw;
}
if (this->children.back()->identifier == AST_Node_Type::Finally) {
try {
retval = this->children.back()->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children.back()->children[0]);
throw;
}
}
return retval;
}
@@ -1276,7 +970,7 @@ namespace chaiscript
Method_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Method, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Method_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
std::vector<std::string> t_param_names;
AST_NodePtr guardnode;
@@ -1353,7 +1047,7 @@ namespace chaiscript
Attr_Decl_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Attr_Decl, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Attr_Decl_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
try {
t_ss.add(fun(boost::function<Boxed_Value (dispatch::Dynamic_Object &)>(boost::bind(&dispatch::detail::Dynamic_Object_Attribute::func, this->children[0]->text,
this->children[1]->text, _1))), this->children[1]->text);
@@ -1407,15 +1101,8 @@ namespace chaiscript
Logical_And_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Logical_And, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Logical_And_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
Boxed_Value retval;
try {
retval = this->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
Boxed_Value retval = this->children[0]->eval(t_ss);
if (this->children.size() > 1) {
for (size_t i = 1; i < this->children.size(); i += 2) {
@@ -1427,14 +1114,8 @@ namespace chaiscript
throw exception::eval_error("Condition not boolean");
}
if (lhs) {
try {
retval = this->children[i+1]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i+1]);
throw;
}
}
else {
retval = Boxed_Value(false);
}
@@ -1449,38 +1130,21 @@ namespace chaiscript
Logical_Or_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Logical_Or, const boost::shared_ptr<std::string> &t_fname=boost::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 ~Logical_Or_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
Boxed_Value retval;
try {
retval = this->children[0]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[0]);
throw;
}
if (this->children.size() > 1) {
for (size_t i = 1; i < this->children.size(); i += 2) {
bool lhs;
try {
lhs = boxed_cast<bool>(retval);
}
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("Condition not boolean");
}
bool lhs = boxed_cast<bool>(retval);
if (lhs) {
retval = Boxed_Value(true);
}
else {
try {
retval = this->children[i+1]->eval(t_ss);
}
catch (exception::eval_error &ee) {
ee.call_stack.push_back(this->children[i+1]);
throw;
}
}
}
}
return retval;

View File

@@ -63,6 +63,17 @@ bool throws_exception(const boost::function<void ()> &f)
return false;
}
chaiscript::exception::eval_error get_eval_error(const boost::function<void ()> &f)
{
try {
f();
} catch (const chaiscript::exception::eval_error &e) {
return e;
}
throw std::runtime_error("no exception throw");
}
std::string get_next_command() {
std::string retval("quit");
if ( ! std::cin.eof() ) {
@@ -158,6 +169,7 @@ int main(int argc, char *argv[])
chai.add(chaiscript::fun(&help), "help");
chai.add(chaiscript::fun(&version), "version");
chai.add(chaiscript::fun(&throws_exception), "throws_exception");
chai.add(chaiscript::fun(&get_eval_error), "get_eval_error");
for (int i = 0; i < argc; ++i) {
if ( i == 0 && argc > 1 ) {
@@ -209,11 +221,15 @@ int main(int argc, char *argv[])
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 (unsigned int j = 1; j < ee.call_stack.size(); ++j) {
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 << std::endl;
return EXIT_FAILURE;
}

View File

@@ -52,6 +52,13 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect
chaiscript::bootstrap::standard_library::vector_type<std::vector<boost::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
CHAISCRIPT_CLASS( m,
chaiscript::exception::eval_error,
,
((reason))
((call_stack))
);
CHAISCRIPT_CLASS( m,
chaiscript::File_Position,
(chaiscript::File_Position())

39
unittests/eval_error.chai Normal file
View File

@@ -0,0 +1,39 @@
load_module("reflection")
def deep()
{
try {
} catch {
} finally {
if (2)
{
}
}
}
def func()
{
deep();
}
def doing()
{
for (var i = 0; i < 10; ++i)
{
func();
}
}
def while_doing()
{
while (true)
{
doing();
}
}
var f = fun() { while_doing(); }
assert_equal(get_eval_error(f).call_stack.size(), 16)

View File

@@ -10,6 +10,24 @@ def assert_equal(x, y)
}
}
def assert_false(f)
{
if (f)
{
print("assert_false failure");
exit(-1);
}
}
def assert_true(f)
{
if (!f)
{
print("assert_false failure");
exit(-1);
}
}
def assert_not_equal(x, y)
{
if (!(x == y))