diff --git a/cheatsheet.md b/cheatsheet.md index 3a22508e..2e2c218f 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -92,6 +92,7 @@ chai.add(chaiscript::user_type(), "MyClass"); User defined type conversions are possible, defined in either script or in C++. + ### ChaiScript Defined Conversions Function objects (including lambdas) can be used to add type conversions @@ -115,6 +116,21 @@ Calling a user defined type conversion that takes a lambda chai.add(chaiscript::type_conversion([](const TestBaseType &t_bt) { /* return converted thing */ })); ``` +### Class Hierarchies + +If you want objects to be convertable between base and derived classes, you must tell ChaiScritp about the relationship. + +``` +chai.add(chaiscript::base_class()); +``` + +If you have multiple classes in your inheritance graph, you will probably want to tell ChaiScript about all relationships. + +``` +chai.add(chaiscript::base_class()); +chai.add(chaiscript::base_class()); +chai.add(chaiscript::base_class()); +``` ### Helpers @@ -206,7 +222,7 @@ Conversion to `std::shared_ptr &` is supported for function calls, but if you ```cpp // ok this is supported, you can register it with chaiscript engine void nullify_shared_ptr(std::shared_ptr &t) { - t == nullptr + t = nullptr } ``` @@ -313,6 +329,15 @@ while (some_condition()) { /* do something */ } for (x : [1,2,3]) { print(i); } ``` +Each of the loop styles can be broken using the `break` statement. For example: + +``` +while (some_condition()) { + /* do something */ + if (another_condition()) { break; } +} +``` + ## Conditionals ``` diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index f8e512e1..b3fefc9e 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -65,7 +65,7 @@ /// int main() /// { /// chaiscript::ChaiScript chai; -/// chai.add(&function, "function"); +/// chai.add(chaiscript::fun(&function), "function"); /// /// double d = chai.eval("function(3, 4.75);"); /// } diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index 4d47b88f..ae8035c9 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -72,7 +72,7 @@ namespace chaiscript { { } - virtual void *data() override + void *data() override { return &m_data; } diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index d0b7c94b..8547b977 100644 --- a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -31,12 +31,12 @@ namespace chaiscript public: bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, std::string t_what) noexcept - : from(std::move(t_from)), to(&t_to), m_what(std::move(t_what)) + : from(t_from), to(&t_to), m_what(std::move(t_what)) { } bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) - : from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name()) + : from(t_from), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name()) { } @@ -46,10 +46,10 @@ namespace chaiscript } bad_boxed_cast(const bad_boxed_cast &) = default; - virtual ~bad_boxed_cast() noexcept = default; + ~bad_boxed_cast() noexcept override = default; /// \brief Description of what error occurred - virtual const char * what() const noexcept override + const char * what() const noexcept override { return m_what.c_str(); } diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 6f59ff07..e2ec267f 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -37,7 +37,7 @@ namespace chaiscript /// Bidir_Range, based on the D concept of ranges. /// \todo Update the Range code to base its capabilities on /// the user_typetraits of the iterator passed in - template + template struct Bidir_Range { typedef Container container_type; @@ -79,64 +79,6 @@ namespace chaiscript return (*m_begin); } - decltype(auto) back() const - { - if (empty()) - { - throw std::range_error("Range empty"); - } - typename Container::iterator pos = m_end; - --pos; - return (*(pos)); - } - - typename Container::iterator m_begin; - typename Container::iterator m_end; - }; - - template - struct Const_Bidir_Range - { - typedef const Container container_type; - typedef typename std::iterator_traits::reference const_reference_type; - - Const_Bidir_Range(const Container &c) - : m_begin(c.begin()), m_end(c.end()) - { - } - - bool empty() const - { - return m_begin == m_end; - } - - void pop_front() - { - if (empty()) - { - throw std::range_error("Range empty"); - } - ++m_begin; - } - - void pop_back() - { - if (empty()) - { - throw std::range_error("Range empty"); - } - --m_end; - } - - decltype(auto) front() const - { - if (empty()) - { - throw std::range_error("Range empty"); - } - return (*m_begin); - } - decltype(auto) back() const { if (empty()) @@ -148,8 +90,8 @@ namespace chaiscript return (*(pos)); } - typename Container::const_iterator m_begin; - typename Container::const_iterator m_end; + IterType m_begin; + IterType m_end; }; namespace detail { @@ -229,8 +171,8 @@ namespace chaiscript template void input_range_type(const std::string &type, Module& m) { - detail::input_range_type_impl >(type,m); - detail::input_range_type_impl >("Const_" + type, m); + detail::input_range_type_impl >(type,m); + detail::input_range_type_impl >("Const_" + type,m); } template ModulePtr input_range_type(const std::string &type) diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index 6347437e..4a0c3081 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -25,7 +25,7 @@ namespace chaiscript template T* throw_if_null(T *t) { - if (t) return t; + if (t) { return t; } throw std::runtime_error("Attempted to dereference null Boxed_Value"); } @@ -135,6 +135,39 @@ namespace chaiscript } }; + /// Cast_Helper_Inner for casting to a && type + template + struct Cast_Helper_Inner + { + static Result&& cast(const Boxed_Value &ob, const Type_Conversions_State *) + { + return std::move(*static_cast(verify_type(ob, typeid(Result), ob.get_ptr()))); + } + }; + + /// Cast_Helper_Inner for casting to a std::unique_ptr<> && type + /// \todo Fix the fact that this has to be in a shared_ptr for now + template + struct Cast_Helper_Inner &&> + { + static std::unique_ptr &&cast(const Boxed_Value &ob, const Type_Conversions_State *) + { + return std::move(*(ob.get().cast>>())); + } + }; + + /// Cast_Helper_Inner for casting to a std::unique_ptr<> & type + /// \todo Fix the fact that this has to be in a shared_ptr for now + template + struct Cast_Helper_Inner &> + { + static std::unique_ptr &cast(const Boxed_Value &ob, const Type_Conversions_State *) + { + return *(ob.get().cast>>()); + } + }; + + /// Cast_Helper_Inner for casting to a std::shared_ptr<> type template struct Cast_Helper_Inner > diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index 4517de28..7a7c875a 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -28,9 +28,9 @@ namespace chaiscript { struct arithmetic_error : std::runtime_error { - arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {} + explicit arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {} arithmetic_error(const arithmetic_error &) = default; - virtual ~arithmetic_error() noexcept = default; + ~arithmetic_error() noexcept override = default; }; } } diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 70a1b967..e6c669bd 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -54,7 +54,7 @@ namespace chaiscript if (rhs.m_attrs) { - m_attrs = std::unique_ptr>>(new std::map>(*rhs.m_attrs)); + m_attrs = std::make_unique>>(*rhs.m_attrs); } return *this; @@ -119,6 +119,8 @@ namespace chaiscript ); } + + template static auto get(T *t, bool t_return_value) { @@ -145,6 +147,19 @@ namespace chaiscript ); } + template + static auto get(std::unique_ptr &&obj, bool t_return_value) + { + auto ptr = obj.get(); + return std::make_shared( + detail::Get_Type_Info::get(), + chaiscript::detail::Any(std::make_shared>(std::move(obj))), + false, + ptr, + t_return_value + ); + } + template static auto get(T t, bool t_return_value) { @@ -302,7 +317,7 @@ namespace chaiscript { if (!m_data->m_attrs) { - m_data->m_attrs = std::unique_ptr>>(new std::map>()); + m_data->m_attrs = std::make_unique>>(); } auto &attr = (*m_data->m_attrs)[t_name]; @@ -319,7 +334,7 @@ namespace chaiscript { if (t_obj.m_data->m_attrs) { - m_data->m_attrs = std::unique_ptr>>(new std::map>(*t_obj.m_data->m_attrs)); + m_data->m_attrs = std::make_unique>>(*t_obj.m_data->m_attrs); } return *this; } @@ -342,8 +357,8 @@ namespace chaiscript // necessary to avoid hitting the templated && constructor of Boxed_Value struct Internal_Construction{}; - Boxed_Value(const std::shared_ptr &t_data, Internal_Construction) - : m_data(t_data) { + Boxed_Value(std::shared_ptr t_data, Internal_Construction) + : m_data(std::move(t_data)) { } std::shared_ptr m_data = Object_Data::get(); diff --git a/include/chaiscript/dispatchkit/callable_traits.hpp b/include/chaiscript/dispatchkit/callable_traits.hpp index 765e6d67..7bbfbd0b 100644 --- a/include/chaiscript/dispatchkit/callable_traits.hpp +++ b/include/chaiscript/dispatchkit/callable_traits.hpp @@ -25,7 +25,7 @@ namespace chaiscript { template struct Const_Caller { - Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {} + explicit Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {} template Ret operator()(const Class &o, Inner&& ... inner) const { @@ -38,7 +38,7 @@ namespace chaiscript { template struct Fun_Caller { - Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {} + explicit Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {} template Ret operator()(Inner&& ... inner) const { @@ -51,7 +51,7 @@ namespace chaiscript { template struct Caller { - Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {} + explicit Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {} template Ret operator()(Class &o, Inner&& ... inner) const { diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 41bf964a..c4dceacd 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -67,7 +67,7 @@ namespace chaiscript reserved_word_error(const reserved_word_error &) = default; - virtual ~reserved_word_error() noexcept = default; + ~reserved_word_error() noexcept override = default; std::string word() const { @@ -89,7 +89,7 @@ namespace chaiscript illegal_name_error(const illegal_name_error &) = default; - virtual ~illegal_name_error() noexcept = default; + ~illegal_name_error() noexcept override = default; std::string name() const { @@ -112,7 +112,7 @@ namespace chaiscript name_conflict_error(const name_conflict_error &) = default; - virtual ~name_conflict_error() noexcept = default; + ~name_conflict_error() noexcept override = default; std::string name() const { @@ -135,7 +135,7 @@ namespace chaiscript } global_non_const(const global_non_const &) = default; - virtual ~global_non_const() noexcept = default; + ~global_non_const() noexcept override = default; }; } @@ -147,7 +147,7 @@ namespace chaiscript public: Module &add(Type_Info ti, std::string name) { - m_typeinfos.emplace_back(std::move(ti), std::move(name)); + m_typeinfos.emplace_back(ti, std::move(name)); return *this; } @@ -266,7 +266,7 @@ namespace chaiscript class Dispatch_Function final : public dispatch::Proxy_Function_Base { public: - Dispatch_Function(std::vector t_funcs) + explicit Dispatch_Function(std::vector t_funcs) : Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)), m_funcs(std::move(t_funcs)) { @@ -356,7 +356,7 @@ namespace chaiscript ++begin; } - assert(type_infos.size() > 0 && " type_info vector size is < 0, this is only possible if something else is broken"); + assert(!type_infos.empty() && " type_info vector size is < 0, this is only possible if something else is broken"); if (size_mismatch) { @@ -447,7 +447,7 @@ namespace chaiscript Type_Name_Map m_types; }; - Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser) + explicit Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser) : m_stack_holder(this), m_parser(parser) { @@ -681,7 +681,7 @@ namespace chaiscript } t_loc = static_cast(Loc::located); - } else if (loc & static_cast(Loc::is_local)) { + } else if ((loc & static_cast(Loc::is_local)) != 0u) { auto &stack = get_stack_data(t_holder); return stack[stack.size() - 1 - ((loc & static_cast(Loc::stack_mask)) >> 16)][loc & static_cast(Loc::loc_mask)].second; @@ -698,9 +698,9 @@ namespace chaiscript // no? is it a function object? auto obj = get_function_object_int(name, loc); - if (obj.first != loc) t_loc = uint_fast32_t(obj.first); - return obj.second; + if (obj.first != loc) { t_loc = uint_fast32_t(obj.first); } + return obj.second; } @@ -763,7 +763,10 @@ namespace chaiscript { uint_fast32_t method_missing_loc = m_method_missing_loc; auto method_missing_funs = get_function("method_missing", method_missing_loc); - if (method_missing_funs.first != method_missing_loc) m_method_missing_loc = uint_fast32_t(method_missing_funs.first); + if (method_missing_funs.first != method_missing_loc) { + m_method_missing_loc = uint_fast32_t(method_missing_funs.first); + } + return std::move(method_missing_funs.second); } @@ -954,7 +957,7 @@ namespace chaiscript { uint_fast32_t loc = t_loc; const auto funs = get_function(t_name, loc); - if (funs.first != loc) t_loc = uint_fast32_t(funs.first); + if (funs.first != loc) { t_loc = uint_fast32_t(funs.first); } const auto do_attribute_call = [this](int l_num_params, const std::vector &l_params, const std::vector &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value @@ -1074,7 +1077,8 @@ namespace chaiscript { uint_fast32_t loc = t_loc; const auto funs = get_function(t_name, loc); - if (funs.first != loc) t_loc = uint_fast32_t(funs.first); + if (funs.first != loc) { t_loc = uint_fast32_t(funs.first); +} return dispatch::dispatch(*funs.second, params, t_conversions); } @@ -1206,7 +1210,7 @@ namespace chaiscript static void save_function_params(Stack_Holder &t_s, std::initializer_list t_params) { - t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(t_params)); + t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params); } static void save_function_params(Stack_Holder &t_s, std::vector &&t_params) @@ -1224,7 +1228,7 @@ namespace chaiscript void save_function_params(std::initializer_list t_params) { - save_function_params(*m_stack_holder, std::move(t_params)); + save_function_params(*m_stack_holder, t_params); } void save_function_params(std::vector &&t_params) @@ -1588,7 +1592,7 @@ namespace chaiscript class Dispatch_State { public: - Dispatch_State(Dispatch_Engine &t_engine) + explicit Dispatch_State(Dispatch_Engine &t_engine) : m_engine(t_engine), m_stack_holder(t_engine.get_stack_holder()), m_conversions(t_engine.conversions(), t_engine.conversions().conversion_saves()) diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index e89d3806..ee972320 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -25,7 +25,7 @@ namespace chaiscript namespace dispatch { struct option_explicit_set : std::runtime_error { - option_explicit_set(const std::string &t_param_name) + explicit option_explicit_set(const std::string &t_param_name) : std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") { @@ -33,13 +33,13 @@ namespace chaiscript option_explicit_set(const option_explicit_set &) = default; - virtual ~option_explicit_set() noexcept = default; + ~option_explicit_set() noexcept override = default; }; class Dynamic_Object { public: - Dynamic_Object(std::string t_type_name) + explicit Dynamic_Object(std::string t_type_name) : m_type_name(std::move(t_type_name)), m_option_explicit(false) { } diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index 41b22f2c..80c878a8 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -110,7 +110,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override + Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override { if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) { @@ -120,7 +120,7 @@ namespace chaiscript } } - virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override + bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override { return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); } @@ -162,7 +162,7 @@ namespace chaiscript bool dynamic_object_typename_match(const std::vector &bvs, const std::string &name, const std::unique_ptr &ti, const Type_Conversions_State &t_conversions) const { - if (bvs.size() > 0) + if (!bvs.empty()) { return dynamic_object_typename_match(bvs[0], name, ti, t_conversions); } else { @@ -226,7 +226,7 @@ namespace chaiscript bool operator==(const Proxy_Function_Base &f) const override { const Dynamic_Object_Constructor *dc = dynamic_cast(&f); - return dc && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); + return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); } bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const override diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index 8ed6115c..93e3e61c 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -33,7 +33,7 @@ namespace chaiscript static Ret call(const std::vector &t_funcs, const std::vector ¶ms, const Type_Conversions_State *t_conversions) { - if (t_conversions) { + if (t_conversions != nullptr) { return boxed_cast(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions); } else { Type_Conversions conv; @@ -52,7 +52,7 @@ namespace chaiscript static Ret call(const std::vector &t_funcs, const std::vector ¶ms, const Type_Conversions_State *t_conversions) { - if (t_conversions) { + if (t_conversions != nullptr) { return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as(); } else { Type_Conversions conv; @@ -72,7 +72,7 @@ namespace chaiscript static void call(const std::vector &t_funcs, const std::vector ¶ms, const Type_Conversions_State *t_conversions) { - if (t_conversions) { + if (t_conversions != nullptr) { dispatch::dispatch(t_funcs, params, *t_conversions); } else { Type_Conversions conv; diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 65267c86..fd7b6886 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -53,14 +53,14 @@ namespace chaiscript m_doti(user_type()) {} - Param_Types(const std::vector &t_types) + explicit Param_Types(const std::vector &t_types) : m_types(build_param_types(t_types)), m_has_types(false), m_doti(user_type()) { } - Param_Types(std::vector> t_types) + explicit Param_Types(std::vector> t_types) : m_types(std::move(t_types)), m_has_types(false), m_doti(user_type()) @@ -82,7 +82,7 @@ namespace chaiscript void push_front(std::string t_name, Type_Info t_ti) { - m_types.emplace(m_types.begin(), std::move(t_name), std::move(t_ti)); + m_types.emplace(m_types.begin(), std::move(t_name), t_ti); update_has_types(); } @@ -93,8 +93,8 @@ namespace chaiscript bool match(const std::vector &vals, const Type_Conversions_State &t_conversions) const { - if (!m_has_types) return true; - if (vals.size() != m_types.size()) return false; + if (!m_has_types) { return true; } + if (vals.size() != m_types.size()) { return false; } for (size_t i = 0; i < vals.size(); ++i) { @@ -301,7 +301,7 @@ namespace chaiscript guard_error(const guard_error &) = default; - virtual ~guard_error() noexcept = default; + ~guard_error() noexcept override = default; }; } @@ -333,18 +333,18 @@ namespace chaiscript } - virtual bool operator==(const Proxy_Function_Base &rhs) const override + bool operator==(const Proxy_Function_Base &rhs) const override { const Dynamic_Proxy_Function *prhs = dynamic_cast(&rhs); return this == &rhs - || (prhs + || ((prhs != nullptr) && this->m_arity == prhs->m_arity && !this->m_guard && !prhs->m_guard && this->m_param_types == prhs->m_param_types); } - virtual bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const override + bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const override { return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions))) && test_guard(vals, t_conversions); @@ -547,7 +547,7 @@ namespace chaiscript return retval; } - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override + Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override { return (*m_f)(build_param_list(params), t_conversions); } @@ -560,7 +560,7 @@ namespace chaiscript class Proxy_Function_Impl_Base : public Proxy_Function_Base { public: - Proxy_Function_Impl_Base(const std::vector &t_types) + explicit Proxy_Function_Impl_Base(const std::vector &t_types) : Proxy_Function_Base(t_types, static_cast(t_types.size()) - 1) { } @@ -581,7 +581,7 @@ namespace chaiscript class Proxy_Function_Callable_Impl final : public Proxy_Function_Impl_Base { public: - Proxy_Function_Callable_Impl(Callable f) + explicit Proxy_Function_Callable_Impl(Callable f) : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast(nullptr))), m_f(std::move(f)) { @@ -612,7 +612,7 @@ namespace chaiscript class Assignable_Proxy_Function : public Proxy_Function_Impl_Base { public: - Assignable_Proxy_Function(const std::vector &t_types) + explicit Assignable_Proxy_Function(const std::vector &t_types) : Proxy_Function_Impl_Base(t_types) { } @@ -668,7 +668,7 @@ namespace chaiscript class Attribute_Access final : public Proxy_Function_Base { public: - Attribute_Access(T Class::* t_attr) + explicit Attribute_Access(T Class::* t_attr) : Proxy_Function_Base(param_types(), 1), m_attr(t_attr) { @@ -773,7 +773,7 @@ namespace chaiscript dispatch_error(const dispatch_error &) = default; - virtual ~dispatch_error() noexcept = default; + ~dispatch_error() noexcept override = default; std::vector parameters; std::vector functions; @@ -790,7 +790,7 @@ namespace chaiscript { const std::vector &types = t_func->get_param_types(); - if (t_func->get_arity() == -1) return false; + if (t_func->get_arity() == -1) { return false; } assert(plist.size() == types.size() - 1); diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index 8258521d..f00eeef5 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -44,7 +44,7 @@ namespace chaiscript arity_error(const arity_error &) = default; - virtual ~arity_error() noexcept {} + ~arity_error() noexcept override = default; int got; int expected; diff --git a/include/chaiscript/dispatchkit/short_alloc.hpp b/include/chaiscript/dispatchkit/short_alloc.hpp index 3cb04223..e1cc9a96 100644 --- a/include/chaiscript/dispatchkit/short_alloc.hpp +++ b/include/chaiscript/dispatchkit/short_alloc.hpp @@ -84,12 +84,14 @@ arena::deallocate(char* p, std::size_t n) noexcept assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena"); if (pointer_in_buffer(p)) { - n = align_up(n); - if (p + n == ptr_) - ptr_ = p; + n = align_up(n); + if (p + n == ptr_) { + ptr_ = p; + } + } + else { + ::operator delete(p); } - else - ::operator delete(p); } template @@ -108,13 +110,13 @@ public: short_alloc(const short_alloc&) = default; short_alloc& operator=(const short_alloc&) = delete; - short_alloc(arena_type& a) noexcept : a_(a) + explicit short_alloc(arena_type& a) noexcept : a_(a) { static_assert(size % alignment == 0, "size N needs to be a multiple of alignment Align"); } template - short_alloc(const short_alloc& a) noexcept + explicit short_alloc(const short_alloc& a) noexcept : a_(a.a_) {} template struct rebind {using other = short_alloc<_Up, N, alignment>;}; diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 6660b25a..273544f2 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -39,14 +39,14 @@ namespace chaiscript { } - bad_boxed_dynamic_cast(const std::string &w) noexcept + explicit bad_boxed_dynamic_cast(const std::string &w) noexcept : bad_boxed_cast(w) { } bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default; - virtual ~bad_boxed_dynamic_cast() noexcept = default; + ~bad_boxed_dynamic_cast() noexcept override = default; }; class bad_boxed_type_cast : public bad_boxed_cast @@ -63,14 +63,14 @@ namespace chaiscript { } - bad_boxed_type_cast(const std::string &w) noexcept + explicit bad_boxed_type_cast(const std::string &w) noexcept : bad_boxed_cast(w) { } bad_boxed_type_cast(const bad_boxed_type_cast &) = default; - virtual ~bad_boxed_type_cast() noexcept = default; + ~bad_boxed_type_cast() noexcept override = default; }; } @@ -100,8 +100,8 @@ namespace chaiscript virtual ~Type_Conversion_Base() = default; protected: - Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from) - : m_to(t_to), m_from(t_from) + Type_Conversion_Base(Type_Info t_to, Type_Info t_from) + : m_to(std::move(t_to)), m_from(std::move(t_from)) { } @@ -286,7 +286,7 @@ namespace chaiscript { public: Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func) - : Type_Conversion_Base(std::move(t_to), std::move(t_from)), + : Type_Conversion_Base(t_to, t_from), m_func(std::move(t_func)) { } @@ -302,7 +302,7 @@ namespace chaiscript return m_func(t_from); } - virtual bool bidir() const override + bool bidir() const override { return false; } @@ -399,7 +399,7 @@ namespace chaiscript { try { Boxed_Value ret = get_conversion(user_type(), from.get_type_info())->convert(from); - if (t_saves.enabled) t_saves.saves.push_back(ret); + if (t_saves.enabled) { t_saves.saves.push_back(ret); } return ret; } catch (const std::out_of_range &) { throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion"); @@ -413,7 +413,7 @@ namespace chaiscript { try { Boxed_Value ret = get_conversion(to.get_type_info(), user_type())->convert_down(to); - if (t_saves.enabled) t_saves.saves.push_back(ret); + if (t_saves.enabled) { t_saves.saves.push_back(ret); } return ret; } catch (const std::out_of_range &) { throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion"); diff --git a/include/chaiscript/language/chaiscript_algebraic.hpp b/include/chaiscript/language/chaiscript_algebraic.hpp index 0338a029..36516dda 100644 --- a/include/chaiscript/language/chaiscript_algebraic.hpp +++ b/include/chaiscript/language/chaiscript_algebraic.hpp @@ -7,6 +7,8 @@ #ifndef CHAISCRIPT_ALGEBRAIC_HPP_ #define CHAISCRIPT_ALGEBRAIC_HPP_ +#include "../utility/fnv1a.hpp" + #include namespace chaiscript @@ -51,76 +53,39 @@ namespace chaiscript static Opers to_operator(const std::string &t_str, bool t_is_unary = false) { - if (t_str == "==") - { - return Opers::equals; - } else if (t_str == "<") { - return Opers::less_than; - } else if (t_str == ">") { - return Opers::greater_than; - } else if (t_str == "<=") { - return Opers::less_than_equal; - } else if (t_str == ">=") { - return Opers::greater_than_equal; - } else if (t_str == "!=") { - return Opers::not_equal; - } else if (t_str == "=") { - return Opers::assign; - } else if (t_str == "++") { - return Opers::pre_increment; - } else if (t_str == "--") { - return Opers::pre_decrement; - } else if (t_str == "*=") { - return Opers::assign_product; - } else if (t_str == "+=") { - return Opers::assign_sum; - } else if (t_str == "-=") { - return Opers::assign_difference; - } else if (t_str == "&=") { - return Opers::assign_bitwise_and; - } else if (t_str == "|=") { - return Opers::assign_bitwise_or; - } else if (t_str == "<<=") { - return Opers::assign_shift_left; - } else if (t_str == ">>=") { - return Opers::assign_shift_right; - } else if (t_str == "%=") { - return Opers::assign_remainder; - } else if (t_str == "^=") { - return Opers::assign_bitwise_xor; - } else if (t_str == "<<") { - return Opers::shift_left; - } else if (t_str == ">>") { - return Opers::shift_right; - } else if (t_str == "%") { - return Opers::remainder; - } else if (t_str == "&") { - return Opers::bitwise_and; - } else if (t_str == "|") { - return Opers::bitwise_or; - } else if (t_str == "^") { - return Opers::bitwise_xor; - } else if (t_str == "~") { - return Opers::bitwise_complement; - } else if (t_str == "+") { - if (t_is_unary) { - return Opers::unary_plus; - } else { - return Opers::sum; - } - } else if (t_str == "-") { - if (t_is_unary) { - return Opers::unary_minus; - } else { - return Opers::difference; - } - } else if (t_str == "/") { - return Opers::quotient; - } else if (t_str == "*") { - return Opers::product; - } else { - return Opers::invalid; - } + const auto op_hash = utility::fnv1a_32(t_str.c_str()); + switch (op_hash) { + case utility::fnv1a_32("=="): { return Opers::equals; } + case utility::fnv1a_32("<"): { return Opers::less_than; } + case utility::fnv1a_32(">"): { return Opers::greater_than; } + case utility::fnv1a_32("<="): { return Opers::less_than_equal; } + case utility::fnv1a_32(">="): { return Opers::greater_than_equal; } + case utility::fnv1a_32("!="): { return Opers::not_equal; } + case utility::fnv1a_32("="): { return Opers::assign; } + case utility::fnv1a_32("++"): { return Opers::pre_increment; } + case utility::fnv1a_32("--"): { return Opers::pre_decrement; } + case utility::fnv1a_32("*="): { return Opers::assign_product; } + case utility::fnv1a_32("+="): { return Opers::assign_sum; } + case utility::fnv1a_32("-="): { return Opers::assign_difference; } + case utility::fnv1a_32("&="): { return Opers::assign_bitwise_and; } + case utility::fnv1a_32("|="): { return Opers::assign_bitwise_or; } + case utility::fnv1a_32("<<="): { return Opers::assign_shift_left; } + case utility::fnv1a_32(">>="): { return Opers::assign_shift_right; } + case utility::fnv1a_32("%="): { return Opers::assign_remainder; } + case utility::fnv1a_32("^="): { return Opers::assign_bitwise_xor; } + case utility::fnv1a_32("<<"): { return Opers::shift_left; } + case utility::fnv1a_32(">>"): { return Opers::shift_right; } + case utility::fnv1a_32("%"): { return Opers::remainder; } + case utility::fnv1a_32("&"): { return Opers::bitwise_and; } + case utility::fnv1a_32("|"): { return Opers::bitwise_or; } + case utility::fnv1a_32("^"): { return Opers::bitwise_xor; } + case utility::fnv1a_32("~"): { return Opers::bitwise_complement; } + case utility::fnv1a_32("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; } + case utility::fnv1a_32("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; } + case utility::fnv1a_32("/"): { return Opers::quotient; } + case utility::fnv1a_32("*"): { return Opers::product; } + default: { return Opers::invalid; } + } } }; diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 7a70892f..1b16b31c 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -62,7 +62,7 @@ namespace chaiscript Array_Call, Dot_Access, Lambda, Block, Scopeless_Block, Def, While, If, For, Ranged_For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range, Inline_Range, Try, Catch, Finally, Method, Attr_Decl, - Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled + Logical_And, Logical_Or, Reference, Switch, Case, Default, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled }; enum class Operator_Precidence { Ternary_Cond, Logical_Or, @@ -72,7 +72,7 @@ namespace chaiscript namespace { /// Helper lookup to get the name of each node type - const char *ast_node_type_to_string(AST_Node_Type ast_node_type) { + inline const char *ast_node_type_to_string(AST_Node_Type ast_node_type) { 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", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", @@ -130,7 +130,7 @@ namespace chaiscript /// \brief Thrown if an error occurs while attempting to load a binary module struct load_module_error : std::runtime_error { - load_module_error(const std::string &t_reason) noexcept + explicit load_module_error(const std::string &t_reason) noexcept : std::runtime_error(t_reason) { } @@ -141,7 +141,7 @@ namespace chaiscript } load_module_error(const load_module_error &) = default; - virtual ~load_module_error() noexcept = default; + ~load_module_error() noexcept override = default; static std::string format_error(const std::string &t_name, const std::vector &t_errors) { @@ -188,7 +188,7 @@ namespace chaiscript reason(t_why), start_position(t_where), filename(t_fname) {} - eval_error(const std::string &t_why) noexcept + explicit eval_error(const std::string &t_why) noexcept : std::runtime_error("Error: \"" + t_why + "\" "), reason(t_why) {} @@ -200,7 +200,7 @@ namespace chaiscript std::ostringstream ss; ss << what(); - if (call_stack.size() > 0) { + if (!call_stack.empty()) { ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n"; ss << '\n' << detail << '\n'; ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'"; @@ -217,7 +217,7 @@ namespace chaiscript return ss.str(); } - virtual ~eval_error() noexcept = default; + ~eval_error() noexcept override = default; private: @@ -476,12 +476,12 @@ namespace chaiscript /// Errors generated when loading a file struct file_not_found_error : std::runtime_error { - file_not_found_error(const std::string &t_filename) noexcept + explicit file_not_found_error(const std::string &t_filename) noexcept : std::runtime_error("File Not Found: " + t_filename) { } file_not_found_error(const file_not_found_error &) = default; - virtual ~file_not_found_error() noexcept {} + ~file_not_found_error() noexcept override = default; }; } @@ -597,19 +597,19 @@ namespace chaiscript struct Return_Value { Boxed_Value retval; - Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { } + explicit Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { } }; /// Special type indicating a call to 'break' struct Break_Loop { - Break_Loop() { } + Break_Loop() = default; }; /// Special type indicating a call to 'continue' struct Continue_Loop { - Continue_Loop() { } + Continue_Loop() = default; }; @@ -621,7 +621,7 @@ namespace chaiscript Scope_Push_Pop(const Scope_Push_Pop &) = delete; Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete; - Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) + explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) : m_ds(t_ds) { m_ds->new_scope(m_ds.stack_holder()); @@ -645,7 +645,7 @@ namespace chaiscript Function_Push_Pop(const Function_Push_Pop &) = delete; Function_Push_Pop& operator=(const Function_Push_Pop &) = delete; - Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) + explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) : m_ds(t_ds) { m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); @@ -663,7 +663,7 @@ namespace chaiscript void save_params(std::initializer_list t_params) { - m_ds->save_function_params(std::move(t_params)); + m_ds->save_function_params(t_params); } @@ -679,7 +679,7 @@ namespace chaiscript Stack_Push_Pop(const Stack_Push_Pop &) = delete; Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete; - Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) + explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) : m_ds(t_ds) { m_ds->new_stack(m_ds.stack_holder()); diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 659014d0..f4550e8a 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -79,7 +79,7 @@ namespace chaiscript { try { const auto p = m_parser->parse(t_input, t_filename); - return p->eval(m_engine); + return p->eval(chaiscript::detail::Dispatch_State(m_engine)); } catch (chaiscript::eval::detail::Return_Value &rv) { return rv.retval; @@ -255,7 +255,7 @@ namespace chaiscript memset( &rInfo, 0, sizeof(rInfo) ); cast_union u; u.in_ptr = &ChaiScript_Basic::use; - if ( dladdr(static_cast(u.out_ptr), &rInfo) && rInfo.dli_fname ) { + if ( (dladdr(static_cast(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) { std::string dllpath(rInfo.dli_fname); const size_t lastslash = dllpath.rfind('/'); if (lastslash != std::string::npos) @@ -284,7 +284,7 @@ namespace chaiscript /// /// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module /// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file - ChaiScript_Basic(std::unique_ptr &&parser, + explicit ChaiScript_Basic(std::unique_ptr &&parser, std::vector t_module_paths = {}, std::vector t_use_paths = {}, const std::vector &t_opts = chaiscript::default_options()) @@ -307,11 +307,15 @@ namespace chaiscript } } + parser::ChaiScript_Parser_Base &get_parser() + { + return *m_parser; + } const Boxed_Value eval(const AST_NodePtr &t_ast) { try { - return t_ast->eval(m_engine); + return t_ast->eval(chaiscript::detail::Dispatch_State(m_engine)); } catch (const exception::eval_error &t_ee) { throw Boxed_Value(t_ee); } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 76706ff4..adc86ed4 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -64,7 +64,7 @@ namespace chaiscript }(); chaiscript::eval::detail::Stack_Push_Pop tpp(state); - if (thisobj) state.add_object("this", *thisobj); + if (thisobj) { state.add_object("this", *thisobj); } if (t_locals) { for (const auto &local : *t_locals) { @@ -91,11 +91,16 @@ namespace chaiscript { AST_Node_Impl(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc, std::vector> t_children = std::vector>()) - : AST_Node(std::move(t_ast_node_text), std::move(t_id), std::move(t_loc)), + : AST_Node(std::move(t_ast_node_text), t_id, std::move(t_loc)), children(std::move(t_children)) { } + static bool get_scoped_bool_condition(const AST_Node_Impl &node, const chaiscript::detail::Dispatch_State &t_ss) { + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + return get_bool_condition(node.eval(t_ss), t_ss); + } + std::vector get_children() const final { return {children.begin(), children.end()}; @@ -238,7 +243,7 @@ namespace chaiscript { } - Constant_AST_Node(Boxed_Value t_value) + explicit Constant_AST_Node(Boxed_Value t_value) : AST_Node_Impl("", AST_Node_Type::Constant, Parse_Location()), m_value(std::move(t_value)) { @@ -270,60 +275,13 @@ namespace chaiscript mutable std::atomic_uint_fast32_t m_loc = {0}; }; - 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 { + struct Fun_Call_AST_Node : AST_Node_Impl { 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::Fun_Call, std::move(t_loc), std::move(t_children)) { } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override + template + Boxed_Value do_eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); @@ -334,7 +292,9 @@ namespace chaiscript params.push_back(child->eval(t_ss)); } - fpp.save_params(params); + if (Save_Params) { + fpp.save_params(params); + } Boxed_Value fn(this->children[0]->eval(t_ss)); @@ -364,10 +324,28 @@ namespace chaiscript } } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override + { + return do_eval_internal(t_ss); + } }; + template + struct Unused_Return_Fun_Call_AST_Node final : Fun_Call_AST_Node { + Unused_Return_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : + Fun_Call_AST_Node(std::move(t_ast_node_text), std::move(t_loc), std::move(t_children)) { } + + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override + { + return this->template do_eval_internal(t_ss); + } + }; + + + + template struct Arg_AST_Node final : AST_Node_Impl { @@ -773,7 +751,7 @@ namespace chaiscript chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); try { - while (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) { + while (this->get_scoped_bool_condition(*this->children[0], t_ss)) { try { this->children[1]->eval(t_ss); } catch (detail::Continue_Loop &) { @@ -808,21 +786,6 @@ namespace chaiscript } }; - template - struct Ternary_Cond_AST_Node final : AST_Node_Impl { - Ternary_Cond_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::Ternary_Cond, std::move(t_loc), std::move(t_children)) - { assert(this->children.size() == 3); } - - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - if (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) { - return this->children[1]->eval(t_ss); - } else { - return this->children[2]->eval(t_ss); - } - } - }; - template struct If_AST_Node final : AST_Node_Impl { @@ -851,7 +814,7 @@ namespace chaiscript const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){ uint_fast32_t hint = t_hint; auto funs = t_ss->get_function(t_name, hint); - if (funs.first != hint) t_hint = uint_fast32_t(funs.first); + if (funs.first != hint) { t_hint = uint_fast32_t(funs.first); } return std::move(funs.second); }; @@ -931,7 +894,7 @@ namespace chaiscript try { for ( this->children[0]->eval(t_ss); - this->get_bool_condition(this->children[1]->eval(t_ss), t_ss); + this->get_scoped_bool_condition(*this->children[1], t_ss); this->children[2]->eval(t_ss) ) { try { @@ -1311,11 +1274,8 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (exception::eval_error &) { - if (this->children.back()->identifier == AST_Node_Type::Finally) { - this->children.back()->children[0]->eval(t_ss); - } - throw; + catch (const exception::eval_error &e) { + retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); } catch (const std::runtime_error &e) { retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); diff --git a/include/chaiscript/language/chaiscript_optimizer.hpp b/include/chaiscript/language/chaiscript_optimizer.hpp index 125782b7..54e1fdbc 100644 --- a/include/chaiscript/language/chaiscript_optimizer.hpp +++ b/include/chaiscript/language/chaiscript_optimizer.hpp @@ -17,7 +17,7 @@ namespace chaiscript { struct Optimizer : T... { Optimizer() = default; - Optimizer(T ... t) + explicit Optimizer(T ... t) : T(std::move(t))... { } @@ -165,7 +165,7 @@ namespace chaiscript { 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) + && !node->children.empty()) { for (size_t i = 0; i < node->children.size()-1; ++i) { auto child = node->children[i]; @@ -196,7 +196,7 @@ namespace chaiscript { struct If { template auto optimize(const eval::AST_Node_Impl_Ptr &node) { - if ((node->identifier == AST_Node_Type::If || node->identifier == AST_Node_Type::Ternary_Cond) + if ((node->identifier == AST_Node_Type::If) && node->children.size() >= 2 && node->children[0]->identifier == AST_Node_Type::Constant) { diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 7c694efb..a4199a35 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -23,6 +23,8 @@ #include "chaiscript_common.hpp" #include "chaiscript_optimizer.hpp" #include "chaiscript_tracer.hpp" +#include "../utility/fnv1a.hpp" +#include "../utility/static_string.hpp" #if defined(CHAISCRIPT_UTF16_UTF32) #include @@ -186,8 +188,8 @@ namespace chaiscript } - static const std::vector> &create_operator_matches() { - static const std::vector> operator_matches { + static const std::vector> &create_operator_matches() { + static const std::vector> operator_matches { {"?"}, {"||"}, {"&&"}, @@ -225,13 +227,38 @@ namespace chaiscript return operators; } - static constexpr const char * const m_multiline_comment_begin = "/*"; - static constexpr const char * const m_multiline_comment_end = "*/"; - static constexpr const char * const m_singleline_comment = "//"; - static constexpr const char * const m_annotation = "#"; + static const utility::Static_String &multiline_comment_end() + { + static const utility::Static_String s("*/"); + return s; + } + + static const utility::Static_String &multiline_comment_begin() + { + static const utility::Static_String s("/*"); + return s; + } + + static const utility::Static_String &singleline_comment() + { + static const utility::Static_String s("//"); + return s; + } + + static const utility::Static_String &annotation() + { + static const utility::Static_String s("#"); + return s; + } + + static const utility::Static_String &cr_lf() + { + static const utility::Static_String s("\r\n"); + return s; + } const std::array, detail::max_alphabet> &m_alphabet = create_alphabet(); - const std::vector> &m_operator_matches = create_operator_matches(); + const std::vector> &m_operator_matches = create_operator_matches(); const std::array &m_operators = create_operators(); std::shared_ptr m_filename; @@ -243,7 +270,7 @@ namespace chaiscript Position() = default; Position(std::string::const_iterator t_pos, std::string::const_iterator t_end) - : line(1), col(1), m_pos(std::move(t_pos)), m_end(std::move(t_end)), m_last_col(1) + : line(1), col(1), m_pos(t_pos), m_end(t_end), m_last_col(1) { } @@ -318,9 +345,10 @@ namespace chaiscript return static_cast(std::distance(m_pos, m_end)); } - char operator*() const { + const char& operator*() const { if (m_pos == m_end) { - return '\0'; + static const char ktmp ='\0'; + return ktmp; } else { return *m_pos; } @@ -355,6 +383,16 @@ namespace chaiscript m_match_stack.reserve(2); } + Tracer &get_tracer() + { + return m_tracer; + } + + Optimizer &get_optimizer() + { + return m_optimizer; + } + ChaiScript_Parser(const ChaiScript_Parser &) = default; ChaiScript_Parser &operator=(const ChaiScript_Parser &) = delete; ChaiScript_Parser(ChaiScript_Parser &&) = default; @@ -418,20 +456,36 @@ namespace chaiscript } + /// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace + inline auto Symbol_(const utility::Static_String &sym) + { + const auto len = sym.size(); + if (m_position.remaining() >= len) { + const char *file_pos = &(*m_position); + for (size_t pos = 0; pos < len; ++pos) + { + if (sym.c_str()[pos] != file_pos[pos]) { return false; } + } + m_position += len; + return true; + } + return false; + } + /// Skips any multi-line or single-line comment bool SkipComment() { - if (Symbol_(m_multiline_comment_begin)) { + if (Symbol_(multiline_comment_begin())) { while (m_position.has_more()) { - if (Symbol_(m_multiline_comment_end)) { + if (Symbol_(multiline_comment_end())) { break; } else if (!Eol_()) { ++m_position; } } return true; - } else if (Symbol_(m_singleline_comment)) { + } else if (Symbol_(singleline_comment())) { while (m_position.has_more()) { - if (Symbol_("\r\n")) { + if (Symbol_(cr_lf())) { m_position -= 2; break; } else if (Char_('\n')) { @@ -442,9 +496,9 @@ namespace chaiscript } } return true; - } else if (Symbol_(m_annotation)) { + } else if (Symbol_(annotation())) { while (m_position.has_more()) { - if (Symbol_("\r\n")) { + if (Symbol_(cr_lf())) { m_position -= 2; break; } else if (Char_('\n')) { @@ -823,74 +877,77 @@ namespace chaiscript const auto start = m_position; if (Id_()) { - const auto text = Position::str(start, m_position); + auto text = Position::str(start, m_position); + const auto text_hash = utility::fnv1a_32(text.c_str()); if (validate) { validate_object_name(text); } - if (text == "true") { - m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(true))); - } else if (text == "false") { - m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(false))); - } else if (text == "Infinity") { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(std::numeric_limits::infinity()))); - } else if (text == "NaN") { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(std::numeric_limits::quiet_NaN()))); - } else if (text == "__LINE__") { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(start.line))); - } else if (text == "__FILE__") { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(m_filename))); - } else if (text == "__FUNC__") { - const std::string fun_name = [&]()->std::string{ + switch (text_hash) { + case utility::fnv1a_32("true"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, const_var(true))); + } break; + case utility::fnv1a_32("false"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, const_var(false))); + } break; + case utility::fnv1a_32("Infinity"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(std::numeric_limits::infinity()))); + } break; + case utility::fnv1a_32("NaN"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(std::numeric_limits::quiet_NaN()))); + } break; + case utility::fnv1a_32("__LINE__"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(start.line))); + } break; + case utility::fnv1a_32("__FILE__"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(m_filename))); + } break; + case utility::fnv1a_32("__FUNC__"): { + std::string fun_name = "NOT_IN_FUNCTION"; for (size_t idx = m_match_stack.size() - 1; idx > 0; --idx) { if (m_match_stack[idx-1]->identifier == AST_Node_Type::Id && m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) { - return m_match_stack[idx-1]->text; + fun_name = m_match_stack[idx-1]->text; } } - return "NOT_IN_FUNCTION"; - }(); - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(std::move(fun_name)))); - } else if (text == "__CLASS__") { - const std::string fun_name = [&]()->std::string{ + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(fun_name))); + } break; + case utility::fnv1a_32("__CLASS__"): { + std::string fun_name = "NOT_IN_CLASS"; for (size_t idx = m_match_stack.size() - 1; idx > 1; --idx) { if (m_match_stack[idx-2]->identifier == AST_Node_Type::Id && m_match_stack[idx-1]->identifier == AST_Node_Type::Id && m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) { - return m_match_stack[idx-2]->text; + fun_name = m_match_stack[idx-2]->text; } } - return "NOT_IN_CLASS"; - }(); - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(std::move(fun_name)))); - } else if (text == "_") { - m_match_stack.push_back(make_node>(text, start.line, start.col, - Boxed_Value(std::make_shared()))); - } else { - m_match_stack.push_back(make_node>( - [&]()->std::string{ - if (*start == '`') { - // 'escaped' literal, like an operator name - return Position::str(start+1, m_position-1); - } else { - return text; - } - }(), - start.line, start.col)); + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(fun_name))); + } break; + case utility::fnv1a_32("_"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + Boxed_Value(std::make_shared()))); + } break; + default: { + std::string val = std::move(text); + if (*start == '`') { + // 'escaped' literal, like an operator name + val = Position::str(start+1, m_position-1); + } + m_match_stack.push_back(make_node>(val, start.line, start.col)); + } break; } - return true; } else { return false; @@ -999,7 +1056,7 @@ namespace chaiscript void process_hex() { - auto val = stoll(hex_matches, 0, 16); + auto val = stoll(hex_matches, nullptr, 16); match.push_back(char_type(val)); hex_matches.clear(); is_escaped = false; @@ -1009,7 +1066,7 @@ namespace chaiscript void process_octal() { - auto val = stoll(octal_matches, 0, 8); + auto val = stoll(octal_matches, nullptr, 8); match.push_back(char_type(val)); octal_matches.clear(); is_escaped = false; @@ -1019,7 +1076,7 @@ namespace chaiscript void process_unicode() { - auto val = stoll(hex_matches, 0, 16); + auto val = stoll(hex_matches, nullptr, 16); hex_matches.clear(); match += detail::Char_Parser_Helper::str_from_ll(val); is_escaped = false; @@ -1288,13 +1345,12 @@ namespace chaiscript } /// Reads a string from input if it matches the parameter, without skipping initial whitespace - bool Keyword_(const char *t_s) { - const auto len = strlen(t_s); - + bool Keyword_(const utility::Static_String &t_s) { + const auto len = t_s.size(); if (m_position.remaining() >= len) { auto tmp = m_position; for (size_t i = 0; tmp.has_more() && i < len; ++i) { - if (*tmp != t_s[i]) { + if (*tmp != t_s.c_str()[i]) { return false; } ++tmp; @@ -1307,7 +1363,7 @@ namespace chaiscript } /// Reads (and potentially captures) a string from input if it matches the parameter - bool Keyword(const char *t_s) { + bool Keyword(const utility::Static_String &t_s) { SkipWS(); const auto start = m_position; bool retval = Keyword_(t_s); @@ -1320,37 +1376,18 @@ namespace chaiscript return retval; } - /// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace - bool Symbol_(const char *t_s) { - const auto len = strlen(t_s); - - if (m_position.remaining() >= len) { - auto tmp = m_position; - for (size_t i = 0; m_position.has_more() && i < len; ++i) { - if (*tmp != t_s[i]) { - return false; - } - ++tmp; - } - m_position = tmp; - return true; - } - - return false; - } - bool is_operator(const std::string &t_s) const { return std::any_of(m_operator_matches.begin(), m_operator_matches.end(), - [t_s](const std::vector &opers) { + [t_s](const std::vector &opers) { return std::any_of(opers.begin(), opers.end(), - [t_s](const std::string &s) { - return s == t_s; + [t_s](const utility::Static_String &s) { + return t_s == s.c_str(); }); }); } /// Reads (and potentially captures) a symbol group from input if it matches the parameter - bool Symbol(const char *t_s, const bool t_disallow_prevention=false) { + bool Symbol(const utility::Static_String &t_s, const bool t_disallow_prevention=false) { SkipWS(); const auto start = m_position; bool retval = Symbol_(t_s); @@ -1372,7 +1409,7 @@ namespace chaiscript bool Eol_(const bool t_eos = false) { bool retval = false; - if (m_position.has_more() && (Symbol_("\r\n") || Char_('\n'))) { + if (m_position.has_more() && (Symbol_(cr_lf()) || Char_('\n'))) { retval = true; //++m_position.line; m_position.col = 1; @@ -1735,12 +1772,16 @@ namespace chaiscript } /// Reads a class block from input - bool Class() { + bool Class(const bool t_class_allowed) { bool retval = false; size_t prev_stack_top = m_match_stack.size(); if (Keyword("class")) { + if (!t_class_allowed) { + throw exception::eval_error("Class definitions only allowed at top scope", File_Position(m_position.line, m_position.col), *m_filename); + } + retval = true; if (!Id(true)) { @@ -2058,17 +2099,21 @@ namespace chaiscript /// \todo Work around for method calls until we have a better solution if (!m_match_stack.back()->children.empty()) { if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) { - if (m_match_stack.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); - if (m_match_stack.back()->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); + if (m_match_stack.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); +} + if (m_match_stack.back()->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); +} auto dot_access = m_match_stack.back()->children[0]; auto func_call = m_match_stack.back(); m_match_stack.pop_back(); func_call->children.erase(func_call->children.begin()); - if (dot_access->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); + if (dot_access->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); +} func_call->children.insert(func_call->children.begin(), dot_access->children.back()); dot_access->children.pop_back(); dot_access->children.push_back(std::move(func_call)); - if (dot_access->children.size() != 2) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); + if (dot_access->children.size() != 2) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); +} m_match_stack.push_back(std::move(dot_access)); } } @@ -2178,7 +2223,7 @@ namespace chaiscript if (!Char(']')) { throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_position.line, m_position.col), *m_filename); } - if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { + if ((prev_stack_top != m_match_stack.size()) && (!m_match_stack.back()->children.empty())) { if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { build_match>(prev_stack_top); } @@ -2218,18 +2263,25 @@ namespace chaiscript /// Reads a unary prefixed expression from input bool Prefix() { const auto prev_stack_top = m_match_stack.size(); - constexpr const std::array prefix_opers{{"++", "--", "-", "+", "!", "~"}}; + using SS = utility::Static_String; + constexpr const std::array prefix_opers{ + SS{"++"}, + SS{"--"}, + SS{"-"}, + SS{"+"}, + SS{"!"}, + SS{"~"}}; for (const auto &oper : prefix_opers) { - bool is_char = strlen(oper) == 1; - if ((is_char && Char(oper[0])) || (!is_char && Symbol(oper))) + const bool is_char = oper.size() == 1; + if ((is_char && Char(oper.c_str()[0])) || (!is_char && Symbol(oper))) { if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete prefix '" + std::string(oper) + "' expression", File_Position(m_position.line, m_position.col), *m_filename); + throw exception::eval_error("Incomplete prefix '" + std::string(oper.c_str()) + "' expression", File_Position(m_position.line, m_position.col), *m_filename); } - build_match>(prev_stack_top, oper); + build_match>(prev_stack_top, oper.c_str()); return true; } } @@ -2244,8 +2296,8 @@ namespace chaiscript bool Operator_Helper(const size_t t_precedence, std::string &oper) { for (auto & elem : m_operator_matches[t_precedence]) { - if (Symbol(elem.c_str())) { - oper = elem; + if (Symbol(elem)) { + oper = elem.c_str(); return true; } } @@ -2274,7 +2326,7 @@ namespace chaiscript throw exception::eval_error("Incomplete '" + oper + "' expression", File_Position(m_position.line, m_position.col), *m_filename); } - build_match>(prev_stack_top); + build_match>(prev_stack_top); } else { throw exception::eval_error("Incomplete '" + oper + "' expression", @@ -2373,8 +2425,10 @@ namespace chaiscript bool Equation() { const auto prev_stack_top = m_match_stack.size(); + using SS = utility::Static_String; + if (Operator()) { - for (const auto sym : {"=", ":=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=", "^=", "|="}) + for (const auto sym : {SS{"="}, SS{":="}, SS{"+="}, SS{"-="}, SS{"*="}, SS{"/="}, SS{"%="}, SS{"<<="}, SS{">>="}, SS{"&="}, SS{"^="}, SS{"|="}}) { if (Symbol(sym, true)) { SkipWS(true); @@ -2382,7 +2436,7 @@ namespace chaiscript throw exception::eval_error("Incomplete equation", File_Position(m_position.line, m_position.col), *m_filename); } - build_match>(prev_stack_top, sym); + build_match>(prev_stack_top, sym.c_str()); return true; } } @@ -2421,7 +2475,7 @@ namespace chaiscript } /// Top level parser, starts parsing of all known parses - bool Statements() { + bool Statements(const bool t_class_allowed = false) { bool retval = false; bool has_more = true; @@ -2429,7 +2483,7 @@ namespace chaiscript while (has_more) { const auto start = m_position; - if (Def() || Try() || If() || While() || Class() || For() || Switch()) { + if (Def() || Try() || If() || While() || Class(t_class_allowed) || For() || Switch()) { if (!saw_eol) { throw exception::eval_error("Two function definitions missing line separator", File_Position(start.line, start.col), *m_filename); } @@ -2492,7 +2546,7 @@ namespace chaiscript /// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) } - if (Statements()) { + if (Statements(true)) { if (m_position.has_more()) { throw exception::eval_error("Unparsed input", File_Position(m_position.line, m_position.col), t_fname); } else { @@ -2508,7 +2562,6 @@ namespace chaiscript } } - #if defined(CHAISCRIPT_MSVC) && defined(CHAISCRIPT_PUSHED_MIN_MAX) #undef CHAISCRIPT_PUSHED_MIN_MAX #pragma pop_macro("min") diff --git a/include/chaiscript/language/chaiscript_posix.hpp b/include/chaiscript/language/chaiscript_posix.hpp index c22fe87c..2ffcff70 100644 --- a/include/chaiscript/language/chaiscript_posix.hpp +++ b/include/chaiscript/language/chaiscript_posix.hpp @@ -15,10 +15,10 @@ namespace chaiscript { struct DLModule { - DLModule(const std::string &t_filename) + explicit DLModule(const std::string &t_filename) : m_data(dlopen(t_filename.c_str(), RTLD_NOW)) { - if (!m_data) + if (m_data == nullptr) { throw chaiscript::exception::load_module_error(dlerror()); } diff --git a/include/chaiscript/language/chaiscript_tracer.hpp b/include/chaiscript/language/chaiscript_tracer.hpp index 938b6670..4b27d2bf 100644 --- a/include/chaiscript/language/chaiscript_tracer.hpp +++ b/include/chaiscript/language/chaiscript_tracer.hpp @@ -10,10 +10,11 @@ namespace chaiscript { namespace eval { - struct Noop_Tracer + + struct Noop_Tracer_Detail { template - static void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl *) + void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl *) { } }; @@ -22,13 +23,13 @@ namespace chaiscript { struct Tracer : T... { Tracer() = default; - Tracer(T ... t) + explicit Tracer(T ... t) : T(std::move(t))... { } void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl> *node) { - (void)std::initializer_list{ (T::trace(ds, node), 0)... }; + (void)std::initializer_list{ (static_cast(*this).trace(ds, node), 0)... }; } static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl> *node) { @@ -36,6 +37,8 @@ namespace chaiscript { } }; + typedef Tracer Noop_Tracer; + } } diff --git a/include/chaiscript/language/chaiscript_windows.hpp b/include/chaiscript/language/chaiscript_windows.hpp index 049e3416..55f9af92 100644 --- a/include/chaiscript/language/chaiscript_windows.hpp +++ b/include/chaiscript/language/chaiscript_windows.hpp @@ -80,7 +80,7 @@ namespace chaiscript struct DLModule { - DLModule(const std::string &t_filename) + explicit DLModule(const std::string &t_filename) : m_data(LoadLibrary(to_proper_string(t_filename).c_str())) { if (!m_data) diff --git a/include/chaiscript/utility/fnv1a.hpp b/include/chaiscript/utility/fnv1a.hpp new file mode 100644 index 00000000..fcf9b1e9 --- /dev/null +++ b/include/chaiscript/utility/fnv1a.hpp @@ -0,0 +1,22 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + +#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_ +#define CHAISCRIPT_UTILITY_FNV1A_HPP_ + +#include + +namespace chaiscript +{ + namespace utility + { + static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) { + return (*s == 0) ? h : fnv1a_32(s+1, ((h ^ (*s)) * 0x01000193)); + } + } +} + +#endif diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index 561b93e5..96decc09 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -386,12 +386,12 @@ class JSON return "null"; case Class::Object: { std::string pad = ""; - for( long i = 0; i < depth; ++i, pad += tab ); + for( long i = 0; i < depth; ++i, pad += tab ) { } std::string s = "{\n"; bool skip = true; for( auto &p : *internal.Map ) { - if( !skip ) s += ",\n"; + if( !skip ) { s += ",\n"; } s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) ); skip = false; } @@ -402,7 +402,7 @@ class JSON std::string s = "["; bool skip = true; for( auto &p : *internal.List ) { - if( !skip ) s += ", "; + if( !skip ) { s += ", "; } s += p.dump( depth + 1, tab ); skip = false; } @@ -426,8 +426,8 @@ class JSON private: static std::string json_escape( const std::string &str ) { std::string output; - for( size_t i = 0; i < str.length(); ++i ) - switch( str[i] ) { + for(char i : str) { + switch( i ) { case '\"': output += "\\\""; break; case '\\': output += "\\\\"; break; case '\b': output += "\\b"; break; @@ -435,8 +435,9 @@ class JSON case '\n': output += "\\n"; break; case '\r': output += "\\r"; break; case '\t': output += "\\t"; break; - default : output += str[i]; break; + default : output += i; break; } +} return output; } @@ -462,7 +463,7 @@ struct JSONParser { } static void consume_ws( const std::string &str, size_t &offset ) { - while( isspace( str[offset] ) && offset <= str.size() ) ++offset; + while( isspace( str[offset] ) && offset <= str.size() ) { ++offset; } } static JSON parse_object( const std::string &str, size_t &offset ) { @@ -544,9 +545,9 @@ struct JSONParser { val += "\\u" ; for( size_t i = 1; i <= 4; ++i ) { c = str[offset+i]; - if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) + if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) { val += c; - else { + } else { throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'"); } } @@ -554,9 +555,9 @@ struct JSONParser { } break; default : val += '\\'; break; } - } - else + } else { val += c; + } } ++offset; return JSON(val); @@ -569,30 +570,35 @@ struct JSONParser { long exp = 0; for (; offset < str.size() ;) { c = str[offset++]; - if( (c == '-') || (c >= '0' && c <= '9') ) + if( (c == '-') || (c >= '0' && c <= '9') ) { val += c; - else if( c == '.' ) { + } else if( c == '.' ) { val += c; isDouble = true; - } - else + } else { break; + } } if( offset < str.size() && (c == 'E' || c == 'e' )) { c = str[ offset++ ]; - if( c == '-' ) { exp_str += '-';} - else if( c == '+' ) { } - else --offset; + if( c == '-' ) { + exp_str += '-'; + } else if( c == '+' ) { + // do nothing + } else { + --offset; + } for (; offset < str.size() ;) { c = str[ offset++ ]; - if( c >= '0' && c <= '9' ) + if( c >= '0' && c <= '9' ) { exp_str += c; - else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { + } else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'"); } - else + else { break; +} } exp = chaiscript::parse_num( exp_str ); } @@ -643,8 +649,9 @@ struct JSONParser { case 't' : case 'f' : return parse_bool( str, offset ); case 'n' : return parse_null( str, offset ); - default : if( ( value <= '9' && value >= '0' ) || value == '-' ) + default : if( ( value <= '9' && value >= '0' ) || value == '-' ) { return parse_number( str, offset ); + } } throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'"); } diff --git a/include/chaiscript/utility/static_string.hpp b/include/chaiscript/utility/static_string.hpp new file mode 100644 index 00000000..5a570041 --- /dev/null +++ b/include/chaiscript/utility/static_string.hpp @@ -0,0 +1,37 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + +#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_ +#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_ + +namespace chaiscript +{ + namespace utility + { + + struct Static_String + { + template + constexpr Static_String(const char (&str)[N]) + : m_size(N-1), data(&str[0]) + { + } + + constexpr size_t size() const { + return m_size; + } + + constexpr const char *c_str() const { + return data; + } + + const size_t m_size; + const char *data = nullptr; + }; + } +} + +#endif diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index fa2bbdbe..11262ff0 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -89,6 +89,29 @@ namespace chaiscript t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second); } } + + template + typename std::enable_if::value, void>::type + add_class(ModuleType &t_module, + const std::string &t_class_name, + const std::vector> &t_constants + ) + { + t_module.add(chaiscript::user_type(), t_class_name); + + t_module.add(chaiscript::constructor(), t_class_name); + t_module.add(chaiscript::constructor(), t_class_name); + + using namespace chaiscript::bootstrap::operators; + equal(t_module); + not_equal(t_module); + assign(t_module); + + for (const auto &constant : t_constants) + { + t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second); + } + } } } diff --git a/releasenotes.md b/releasenotes.md index 36220309..4300bd12 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -27,12 +27,17 @@ Current Version: 6.0.0 * Modular optimization system; this can be accessed via the ChaiScript_Basic interface * Execution tracing capability; also accessed via ChaiScript_Basic interface * range-based for loops `for( id : container ) { }` +* If-init expressions (ala C++17) +* Support for passing r-value references to functions +* Support for containing unique_ptr +* Add helpers for exposing enum classes to ChaiScript #### Improvements * Compile time improvements * Compile size improvements * Significant runtime improvements (see "Modular optimization system") +* Significant parser improvements, both with parse-time and parser initialization time (Thanks @niXman) #### Improvements Still Need To Be Made @@ -41,6 +46,9 @@ Current Version: 6.0.0 ### Changes since 5.8.5 * Optimize away `return` statements in lambdas also +* Allow conversions to bool in conditionals +* Don't allow `class` statements inside of scopes +* Properly error when a dynamic object non-function member is called ### Changes since 5.8.4 * Fix order of operations for prefix operators diff --git a/src/main.cpp b/src/main.cpp index 61ca7c11..ae2d4907 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,7 +25,7 @@ char *mystrdup (const char *s) { size_t len = strlen(s); // Space for length plus nul char *d = static_cast(malloc (len+1)); - if (d == nullptr) return nullptr; // No memory + if (d == nullptr) { return nullptr; } // No memory #ifdef CHAISCRIPT_MSVC strcpy_s(d, len+1, s); // Copy the characters #else @@ -44,7 +44,7 @@ char* readline(const char* p) } -void add_history(const char*){} +void add_history(const char* /*unused*/){} void using_history(){} #endif @@ -116,7 +116,7 @@ std::vector default_search_paths() { Dl_info rInfo; memset( &rInfo, 0, sizeof(rInfo) ); - if ( !dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname ) { + if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) { return paths; } @@ -184,7 +184,7 @@ std::string get_next_command() { std::string retval("quit"); if ( ! std::cin.eof() ) { char *input_raw = readline("eval> "); - if ( input_raw ) { + if ( input_raw != nullptr ) { add_history(input_raw); std::string val(input_raw); @@ -240,7 +240,7 @@ void interactive(chaiscript::ChaiScript_Basic& chai) } catch (const chaiscript::exception::eval_error &ee) { std::cout << ee.what(); - if (ee.call_stack.size() > 0) { + if ( !ee.call_stack.empty() ) { std::cout << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")"; } std::cout << '\n'; @@ -277,7 +277,7 @@ int main(int argc, char *argv[]) std::vector usepaths; usepaths.push_back(""); - if (usepath) + if (usepath != nullptr) { usepaths.push_back(usepath); } @@ -286,7 +286,7 @@ int main(int argc, char *argv[]) std::vector searchpaths = default_search_paths(); modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end()); modulepaths.push_back(""); - if (modulepath) + if (modulepath != nullptr) { modulepaths.push_back(modulepath); } @@ -308,7 +308,7 @@ int main(int argc, char *argv[]) ++i; } - std::string arg( i ? argv[i] : "--interactive" ); + std::string arg( i != 0 ? argv[i] : "--interactive" ); enum { eInteractive , eCommand @@ -319,9 +319,9 @@ int main(int argc, char *argv[]) if ( (i+1) >= argc ) { std::cout << "insufficient input following " << arg << '\n'; return EXIT_FAILURE; - } else { + } arg = argv[++i]; - } + } else if ( arg == "-" || arg == "--stdin" ) { arg = "" ; std::string line; diff --git a/unittests/class_inside_scope.chai b/unittests/class_inside_scope.chai new file mode 100644 index 00000000..27fe8060 --- /dev/null +++ b/unittests/class_inside_scope.chai @@ -0,0 +1,8 @@ + + +try { + parse("{ class C { var data; def C() {} } }") + assert_false(true) +} catch (e) { + assert_true(true) +} diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index f3bc1a21..a25670dd 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -990,6 +990,34 @@ TEST_CASE("Make sure ChaiScript object still compiles / executes") chaiscript::ChaiScript chai; } +struct Count_Tracer +{ + int count = 0; + template + void trace(const chaiscript::detail::Dispatch_State &, const chaiscript::eval::AST_Node_Impl *) + { + ++count; + } +}; + + +TEST_CASE("Test count tracer") +{ + typedef chaiscript::parser::ChaiScript_Parser< chaiscript::eval::Tracer, chaiscript::optimizer::Optimizer_Default > Parser_Type; + + chaiscript::ChaiScript_Basic chai(chaiscript::Std_Lib::library(), + std::make_unique()); + + Parser_Type &parser = dynamic_cast(chai.get_parser()); + + const auto count = parser.get_tracer().count; + + chai.eval(""); + + CHECK(parser.get_tracer().count > count); +} + + TEST_CASE("Test stdlib options") { const auto test_has_external_scripts = [](chaiscript::ChaiScript_Basic &chai) { @@ -1057,6 +1085,47 @@ TEST_CASE("Test stdlib options") test_has_external_scripts(chai); test_no_load_modules(chai); } +} + + +void uservalueref(int &&) +{ +} + +void usemoveonlytype(std::unique_ptr &&) +{ +} + + +TEST_CASE("Pass r-value reference to func") +{ + chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser()); + + chai.add(chaiscript::fun(&uservalueref), "uservalueref"); + chai.add(chaiscript::fun(&usemoveonlytype), "usemoveonlytype"); + + chai.add(chaiscript::var(std::make_unique(1)), "iptr"); + chai.eval("usemoveonlytype(iptr)"); +} + +TEST_CASE("Use unique_ptr") +{ + chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser()); + + chai.add(chaiscript::fun([](int &i){ ++i; }), "inci"); + chai.add(chaiscript::fun([](int i){ ++i; }), "copyi"); + chai.add(chaiscript::fun([](int *i){ ++(*i); }), "derefi"); + chai.add(chaiscript::var(std::make_unique(1)), "iptr"); + + + CHECK(chai.eval("iptr") == 1); + chai.eval("inci(iptr)"); + CHECK(chai.eval("iptr") == 2); + chai.eval("copyi(iptr)"); + CHECK(chai.eval("iptr") == 2); + chai.eval("derefi(iptr)"); + CHECK(chai.eval("iptr") == 3); + }