From 962bdf4b3c8d566058784e6dcbd9b172c9c48c01 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 6 Apr 2015 13:17:41 -0600 Subject: [PATCH] Reduce exceptions on startup to minimum This still has some exceptions thrown during the loading of modules since I have no way of knowing where the operating system `dlopen` and `LoadLibrary` functions will search for me to pre-check it. Closes #158 --- include/chaiscript/dispatchkit/bootstrap.hpp | 9 ++-- .../chaiscript/dispatchkit/bootstrap_stl.hpp | 3 +- .../chaiscript/dispatchkit/dispatchkit.hpp | 16 +++++++- .../dispatchkit/dynamic_object_detail.hpp | 2 +- .../chaiscript/language/chaiscript_engine.hpp | 4 +- .../chaiscript/language/chaiscript_eval.hpp | 41 ++++++------------- 6 files changed, 39 insertions(+), 36 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index f7177f4..32c11c1 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -136,10 +136,14 @@ namespace chaiscript ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module())) { m->add(user_type(), name); - m->add(constructor(), name); + m->add(constructor(), name); construct_pod(name, m); - m->add(fun(&to_string), "to_string"); + auto to_s = fun(&to_string); + + if (!m->has_function(to_s, "to_string")) { + m->add(to_s, "to_string"); + } m->add(fun(&parse_string), "to_" + name); return m; } @@ -471,7 +475,6 @@ namespace chaiscript m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree"); - m->add(chaiscript::user_type(), "eval_error"); m->add(chaiscript::base_class()); m->add(chaiscript::user_type(), "arithmetic_error"); diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index d1330c9..cc4219c 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -267,7 +267,7 @@ namespace chaiscript template ModulePtr assignable_type(const std::string &type, ModulePtr m = ModulePtr(new Module())) { - basic_constructors(type, m); + copy_constructor(type, m); operators::assign(m); return m; } @@ -443,6 +443,7 @@ namespace chaiscript m->add(fun(static_cast(&MapType::operator[])), "[]"); container_type(type, m); + default_constructible_type(type, m); assignable_type(type, m); unique_associative_container_type(type, m); pair_associative_container_type(type, m); diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index cb4233d..46155ca 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -199,6 +199,14 @@ namespace chaiscript { } + bool has_function(const Proxy_Function &new_f, const std::string &name) + { + return std::any_of(m_funcs.begin(), m_funcs.end(), [&](const std::pair &existing_f) { + return existing_f.second == name && *(existing_f.first) == *(new_f); + }); + } + + private: std::vector > m_typeinfos; std::vector > m_funcs; @@ -580,7 +588,7 @@ namespace chaiscript } /// Returns the type info for a named type - Type_Info get_type(const std::string &name) const + Type_Info get_type(const std::string &name, bool t_throw = true) const { chaiscript::detail::threading::shared_lock l(m_mutex); @@ -591,7 +599,11 @@ namespace chaiscript return itr->second; } - throw std::range_error("Type Not Known"); + if (t_throw) { + throw std::range_error("Type Not Known"); + } else { + return Type_Info(); + } } /// Returns the registered name of a known type_info object diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index 36e8dff..67c9543 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -57,7 +57,7 @@ namespace chaiscript const Proxy_Function &t_func, const Type_Info &t_ti) : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()), - m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type()) + m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(t_ti.is_undef()?nullptr:new Type_Info(t_ti)), m_doti(user_type()) { assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index a266bc6..b4e5269 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -353,7 +353,9 @@ namespace chaiscript m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type, std::ref(m_engine)), "type"); - m_engine.add(fun &)> ( + m_engine.add(fun([this](const std::string &t_type_name){ return this->m_engine.get_type(t_type_name, true); }), "type"); + + m_engine.add(fun &)>( [=](const Type_Info &t_from, const Type_Info &t_to, const std::function &t_func) { m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func)); } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 0f7f63a..0b1c564 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -517,11 +517,7 @@ namespace chaiscript { return std::pair(); } else { - try { - return std::pair(t_node->children[0]->text, t_ss.get_type(t_node->children[0]->text)); - } catch (const std::range_error &) { - return std::pair(t_node->children[0]->text, Type_Info()); - } + return std::pair(t_node->children[0]->text, t_ss.get_type(t_node->children[0]->text, false)); } } @@ -1484,30 +1480,19 @@ namespace chaiscript static_cast(numparams), this->children.back(), param_types, l_annotation, guard)), function_name); - } - else { - try { - // Do know type name (if this line fails, the catch block is called and the - // other version is called, with no Type_Info object known) - auto type = t_ss.get_type(class_name); - param_types.push_front(class_name, type); + } else { - t_ss.add( - std::make_shared(class_name, - std::make_shared(std::bind(chaiscript::eval::detail::eval_function, - std::ref(t_ss), this->children.back(), - t_param_names, std::placeholders::_1, std::map()), static_cast(numparams), this->children.back(), - param_types, l_annotation, guard), type), function_name); - } catch (const std::range_error &) { - param_types.push_front(class_name, Type_Info()); - // Do not know type name - t_ss.add( - std::make_shared(class_name, - std::make_shared(std::bind(chaiscript::eval::detail::eval_function, - std::ref(t_ss), this->children.back(), - t_param_names, std::placeholders::_1, std::map()), static_cast(numparams), this->children.back(), - param_types, l_annotation, guard)), function_name); - } + // if the type is unknown, then this generates a function that looks up the type + // at runtime. Defining the type first before this is called is better + auto type = t_ss.get_type(class_name, false); + param_types.push_front(class_name, type); + + t_ss.add( + std::make_shared(class_name, + std::make_shared(std::bind(chaiscript::eval::detail::eval_function, + std::ref(t_ss), this->children.back(), + t_param_names, std::placeholders::_1, std::map()), static_cast(numparams), this->children.back(), + param_types, l_annotation, guard), type), function_name); } } catch (const exception::reserved_word_error &e) {