diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 17a74925..27453736 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -32,7 +32,7 @@ namespace chaiscript /// Types of AST nodes available to the parser and eval - enum class AST_Node_Type { Id, Fun_Call, Arg_List, Equation, Var_Decl, + enum class AST_Node_Type { Id, Fun_Call, Unused_Return_Fun_Call, Arg_List, Equation, Var_Decl, Array_Call, Dot_Access, Lambda, Block, Scopeless_Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range, Inline_Range, Try, Catch, Finally, Method, Attr_Decl, @@ -45,7 +45,7 @@ namespace chaiscript { /// Helper lookup to get the name of each node type const char *ast_node_type_to_string(AST_Node_Type ast_node_type) { - static const char * const ast_node_types[] = { "Id", "Fun_Call", "Arg_List", "Equation", "Var_Decl", + static const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Array_Call", "Dot_Access", "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl", diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 1fb42404..779d13df 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -219,7 +219,7 @@ namespace chaiscript std::vector t_modulepaths = std::vector(), std::vector t_usepaths = std::vector()) : m_module_paths(std::move(t_modulepaths)), m_use_paths(std::move(t_usepaths)), - m_parser(std::make_unique>>()), + m_parser(std::make_unique>>()), m_engine(*m_parser) { @@ -246,7 +246,7 @@ namespace chaiscript ChaiScript( std::vector t_modulepaths = std::vector(), std::vector t_usepaths = std::vector()) : m_module_paths(std::move(t_modulepaths)), m_use_paths(std::move(t_usepaths)), - m_parser(std::make_unique>>()), + m_parser(std::make_unique>>()), m_engine(*m_parser) { if (m_module_paths.empty()) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index c3c473b3..be37c658 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -270,6 +270,52 @@ namespace chaiscript }; + template + struct Unused_Return_Fun_Call_AST_Node final : AST_Node_Impl { + Unused_Return_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : + AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Unused_Return_Fun_Call, std::move(t_loc), std::move(t_children)) { } + + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override + { + chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + + std::vector params; + + params.reserve(this->children[1]->children.size()); + for (const auto &child : this->children[1]->children) { + params.push_back(child->eval(t_ss)); + } + + Boxed_Value fn(this->children[0]->eval(t_ss)); + + try { + return (*t_ss->boxed_cast(fn))(params, t_ss.conversions()); + } + catch(const exception::dispatch_error &e){ + 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 = t_ss->boxed_cast(fn); + // handle the case where there is only 1 function to try to call and dispatch fails on it + throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, 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; + } + } + }; + + template struct Fun_Call_AST_Node final : AST_Node_Impl { diff --git a/include/chaiscript/language/chaiscript_optimizer.hpp b/include/chaiscript/language/chaiscript_optimizer.hpp index 92f4ad13..aa4f0a24 100644 --- a/include/chaiscript/language/chaiscript_optimizer.hpp +++ b/include/chaiscript/language/chaiscript_optimizer.hpp @@ -125,6 +125,39 @@ namespace chaiscript { } }; + struct Unused_Return { + template + auto optimize(const eval::AST_Node_Impl_Ptr &node) { + if ((node->identifier == AST_Node_Type::Block + || node->identifier == AST_Node_Type::Scopeless_Block) + && node->children.size() > 0) + { + for (size_t i = 0; i < node->children.size()-1; ++i) { + auto child = node->children[i]; + if (child->identifier == AST_Node_Type::Fun_Call) { + node->children[i] = chaiscript::make_shared, eval::Unused_Return_Fun_Call_AST_Node>(child->text, child->location, std::move(child->children)); + } + } + } else if ((node->identifier == AST_Node_Type::For + || node->identifier == AST_Node_Type::While) + && child_count(node) > 0) { + auto child = child_at(node, child_count(node) - 1); + if (child->identifier == AST_Node_Type::Block + || child->identifier == AST_Node_Type::Scopeless_Block) + { + auto num_sub_children = child_count(child); + for (size_t i = 0; i < num_sub_children; ++i) { + auto sub_child = child_at(child, i); + if (sub_child->identifier == AST_Node_Type::Fun_Call) { + child->children[i] = chaiscript::make_shared, eval::Unused_Return_Fun_Call_AST_Node>(sub_child->text, sub_child->location, std::move(sub_child->children)); + } + } + } + } + return node; + } + }; + struct If { template auto optimize(const eval::AST_Node_Impl_Ptr &node) {