Allow typing of exception handlers
This commit is contained in:
@@ -393,41 +393,48 @@ namespace chaiscript
|
|||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string get_arg_name(const AST_NodePtr &t_node) {
|
||||||
|
if (t_node->children.empty())
|
||||||
|
{
|
||||||
|
return t_node->text;
|
||||||
|
} else if (t_node->children.size() == 1) {
|
||||||
|
return t_node->children[0]->text;
|
||||||
|
} else {
|
||||||
|
return t_node->children[1]->text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static std::vector<std::string> get_arg_names(const AST_NodePtr &t_node) {
|
static std::vector<std::string> get_arg_names(const AST_NodePtr &t_node) {
|
||||||
std::vector<std::string> retval;
|
std::vector<std::string> retval;
|
||||||
|
|
||||||
for (const auto &child : t_node->children)
|
for (const auto &node : t_node->children)
|
||||||
{
|
{
|
||||||
if (child->children.empty())
|
retval.push_back(get_arg_name(node));
|
||||||
{
|
|
||||||
retval.push_back(child->text);
|
|
||||||
} else if (child->children.size() == 1) {
|
|
||||||
retval.push_back(child->children[0]->text);
|
|
||||||
} else {
|
|
||||||
retval.push_back(child->children[1]->text);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::pair<std::string, Type_Info> get_arg_type(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss)
|
||||||
|
{
|
||||||
|
if (t_node->children.size() < 2)
|
||||||
|
{
|
||||||
|
return std::pair<std::string, Type_Info>();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return std::pair<std::string, Type_Info>(t_node->children[0]->text, t_ss.get_type(t_node->children[0]->text));
|
||||||
|
} catch (const std::range_error &t_err) {
|
||||||
|
return std::pair<std::string, Type_Info>(t_node->children[0]->text, Type_Info());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static dispatch::Param_Types get_arg_types(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss) {
|
static dispatch::Param_Types get_arg_types(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss) {
|
||||||
std::vector<std::pair<std::string, Type_Info>> retval;
|
std::vector<std::pair<std::string, Type_Info>> retval;
|
||||||
|
|
||||||
for (const auto &child : t_node->children)
|
for (const auto &child : t_node->children)
|
||||||
{
|
{
|
||||||
if (child->children.empty())
|
retval.push_back(get_arg_type(child, t_ss));
|
||||||
{
|
|
||||||
retval.emplace_back("", Type_Info());
|
|
||||||
} else if (child->children.size() == 1) {
|
|
||||||
retval.emplace_back("", Type_Info());
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
retval.emplace_back(child->children[0]->text, t_ss.get_type(child->children[0]->text));
|
|
||||||
} catch (const std::range_error &t_err) {
|
|
||||||
retval.emplace_back(child->children[0]->text, Type_Info());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dispatch::Param_Types(std::move(retval));
|
return dispatch::Param_Types(std::move(retval));
|
||||||
@@ -1247,11 +1254,74 @@ namespace chaiscript
|
|||||||
Try_AST_Node(const std::string &t_ast_node_text = "", 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) :
|
Try_AST_Node(const std::string &t_ast_node_text = "", 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, AST_Node_Type::Try, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
AST_Node(t_ast_node_text, AST_Node_Type::Try, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||||
virtual ~Try_AST_Node() {}
|
virtual ~Try_AST_Node() {}
|
||||||
|
|
||||||
|
Boxed_Value handle_exception(chaiscript::detail::Dispatch_Engine &t_ss, const Boxed_Value &t_except) const
|
||||||
|
{
|
||||||
|
Boxed_Value retval;
|
||||||
|
|
||||||
|
size_t end_point = this->children.size();
|
||||||
|
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||||
|
assert(end_point > 0);
|
||||||
|
end_point = this->children.size() - 1;
|
||||||
|
}
|
||||||
|
for (size_t i = 1; i < end_point; ++i) {
|
||||||
|
chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss);
|
||||||
|
AST_NodePtr catch_block = this->children[i];
|
||||||
|
|
||||||
|
if (catch_block->children.size() == 1) {
|
||||||
|
//No variable capture, no guards
|
||||||
|
retval = catch_block->children[0]->eval(t_ss);
|
||||||
|
break;
|
||||||
|
} else if (catch_block->children.size() == 2 || catch_block->children.size() == 3) {
|
||||||
|
const auto name = Arg_List_AST_Node::get_arg_name(catch_block->children[0]);
|
||||||
|
|
||||||
|
if (dispatch::Param_Types(
|
||||||
|
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)}
|
||||||
|
).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()))
|
||||||
|
{
|
||||||
|
t_ss.add_object(name, t_except);
|
||||||
|
|
||||||
|
if (catch_block->children.size() == 2) {
|
||||||
|
//Variable capture, no guards
|
||||||
|
retval = catch_block->children[1]->eval(t_ss);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (catch_block->children.size() == 3) {
|
||||||
|
//Variable capture, guards
|
||||||
|
|
||||||
|
bool guard = false;
|
||||||
|
try {
|
||||||
|
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) {
|
||||||
|
this->children.back()->children[0]->eval(t_ss);
|
||||||
|
}
|
||||||
|
throw exception::eval_error("Guard condition not boolean");
|
||||||
|
}
|
||||||
|
if (guard) {
|
||||||
|
retval = catch_block->children[2]->eval(t_ss);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||||
|
this->children.back()->children[0]->eval(t_ss);
|
||||||
|
}
|
||||||
|
throw exception::eval_error("Internal error: catch block size unrecognized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||||
Boxed_Value retval;
|
Boxed_Value retval;
|
||||||
|
|
||||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
retval = this->children[0]->eval(t_ss);
|
retval = this->children[0]->eval(t_ss);
|
||||||
}
|
}
|
||||||
@@ -1262,98 +1332,11 @@ namespace chaiscript
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (const std::exception &e) {
|
catch (const std::exception &e) {
|
||||||
Boxed_Value except(std::ref(e));
|
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
|
||||||
|
|
||||||
size_t end_point = this->children.size();
|
|
||||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
|
||||||
assert(end_point > 0);
|
|
||||||
end_point = this->children.size() - 1;
|
|
||||||
}
|
|
||||||
for (size_t i = 1; i < end_point; ++i) {
|
|
||||||
chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss);
|
|
||||||
AST_NodePtr catch_block = this->children[i];
|
|
||||||
|
|
||||||
if (catch_block->children.size() == 1) {
|
|
||||||
//No variable capture, no guards
|
|
||||||
retval = catch_block->children[0]->eval(t_ss);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (catch_block->children.size() == 2) {
|
|
||||||
//Variable capture, no guards
|
|
||||||
t_ss.add_object(catch_block->children[0]->text, except);
|
|
||||||
retval = catch_block->children[1]->eval(t_ss);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (catch_block->children.size() == 3) {
|
|
||||||
//Variable capture, no guards
|
|
||||||
t_ss.add_object(catch_block->children[0]->text, except);
|
|
||||||
|
|
||||||
bool guard = false;
|
|
||||||
try {
|
|
||||||
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) {
|
|
||||||
this->children.back()->children[0]->eval(t_ss);
|
|
||||||
}
|
|
||||||
throw exception::eval_error("Guard condition not boolean");
|
|
||||||
}
|
|
||||||
if (guard) {
|
|
||||||
retval = catch_block->children[2]->eval(t_ss);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
|
||||||
this->children.back()->children[0]->eval(t_ss);
|
|
||||||
}
|
|
||||||
throw exception::eval_error("Internal error: catch block size unrecognized");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Boxed_Value &except) {
|
catch (Boxed_Value &e) {
|
||||||
for (size_t i = 1; i < this->children.size(); ++i) {
|
retval = handle_exception(t_ss, e);
|
||||||
chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss);
|
|
||||||
const auto &catch_block = this->children[i];
|
|
||||||
|
|
||||||
if (catch_block->children.size() == 1) {
|
|
||||||
//No variable capture, no guards
|
|
||||||
retval = catch_block->children[0]->eval(t_ss);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (catch_block->children.size() == 2) {
|
|
||||||
//Variable capture, no guards
|
|
||||||
t_ss.add_object(catch_block->children[0]->text, except);
|
|
||||||
retval = catch_block->children[1]->eval(t_ss);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (catch_block->children.size() == 3) {
|
|
||||||
//Variable capture, guards
|
|
||||||
t_ss.add_object(catch_block->children[0]->text, except);
|
|
||||||
|
|
||||||
bool guard;
|
|
||||||
try {
|
|
||||||
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) {
|
|
||||||
this->children.back()->children[0]->eval(t_ss);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw exception::eval_error("Guard condition not boolean");
|
|
||||||
}
|
|
||||||
if (guard) {
|
|
||||||
retval = catch_block->children[2]->eval(t_ss);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
|
||||||
this->children.back()->children[0]->eval(t_ss);
|
|
||||||
}
|
|
||||||
throw exception::eval_error("Internal error: catch block size unrecognized");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||||
@@ -1362,6 +1345,7 @@ namespace chaiscript
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||||
retval = this->children.back()->children[0]->eval(t_ss);
|
retval = this->children.back()->children[0]->eval(t_ss);
|
||||||
}
|
}
|
||||||
|
@@ -1337,7 +1337,7 @@ namespace chaiscript
|
|||||||
if (Keyword("catch", false)) {
|
if (Keyword("catch", false)) {
|
||||||
const auto catch_stack_top = m_match_stack.size();
|
const auto catch_stack_top = m_match_stack.size();
|
||||||
if (Char('(')) {
|
if (Char('(')) {
|
||||||
if (!(Id(true) && Char(')'))) {
|
if (!(Arg() && Char(')'))) {
|
||||||
throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename);
|
throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename);
|
||||||
}
|
}
|
||||||
if (Char(':')) {
|
if (Char(':')) {
|
||||||
|
Reference in New Issue
Block a user