From 14a280713f23d598a76f08a81adb21b91586b09d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 11 Jun 2014 15:15:51 -0600 Subject: [PATCH 01/18] Update version to 5.3.2 --- CMakeLists.txt | 2 +- include/chaiscript/chaiscript_defines.hpp | 2 +- releasenotes.md | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 352089ba..fbc59258 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,7 @@ set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt" set(CPACK_PACKAGE_VERSION_MAJOR 5) set(CPACK_PACKAGE_VERSION_MINOR 3) -set(CPACK_PACKAGE_VERSION_PATCH 1) +set(CPACK_PACKAGE_VERSION_PATCH 2) set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_VENDOR "ChaiScript.com") diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 0fd6fc51..cacb8bfb 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -46,7 +46,7 @@ namespace chaiscript { static const int version_major = 5; static const int version_minor = 3; - static const int version_patch = 1; + static const int version_patch = 2; } #endif diff --git a/releasenotes.md b/releasenotes.md index 4b7447d4..a60227ec 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,6 +1,8 @@ Notes: ======= -Current Version: 5.3.1 +Current Version: 5.3.2 + +### Changes since 5.3.1 ### Changes since 5.3.0 * Add automatic conversion of arithmetic return types, following the same From c5f6c549ec5cd196dde7b825f3b9cf2f5690b41d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 15 Aug 2014 20:14:15 -0600 Subject: [PATCH 02/18] Reduce compiled size with template reductions --- .../dispatchkit/proxy_functions.hpp | 59 ++++++++++++------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 9a05106c..4f9f471d 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -440,34 +440,26 @@ namespace chaiscript int m_arity; }; - /** - * The standard typesafe function call implementation of Proxy_Function - * It takes a std::function<> object and performs runtime - * type checking of Boxed_Value parameters, in a type safe manner - */ - template - class Proxy_Function_Impl : public Proxy_Function_Base + class Proxy_Function_Impl_Base : public Proxy_Function_Base { public: - Proxy_Function_Impl(std::function f) - : Proxy_Function_Base(detail::build_param_type_list(static_cast(nullptr))), - m_f(std::move(f)), m_dummy_func(nullptr) + Proxy_Function_Impl_Base(std::vector t_types) + : Proxy_Function_Base(std::move(t_types)) { } - virtual ~Proxy_Function_Impl() {} - - virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE - { - const Proxy_Function_Impl *pimpl = dynamic_cast *>(&t_func); - return pimpl != nullptr; - } + virtual ~Proxy_Function_Impl_Base() {} virtual int get_arity() const CHAISCRIPT_OVERRIDE { return static_cast(m_types.size()) - 1; } + virtual std::string annotation() const CHAISCRIPT_OVERRIDE + { + return ""; + } + virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { if (int(vals.size()) != get_arity()) @@ -475,12 +467,37 @@ namespace chaiscript return false; } - return compare_types(m_types, vals) || detail::compare_types_cast(m_dummy_func, vals, t_conversions); + return compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions); } - virtual std::string annotation() const CHAISCRIPT_OVERRIDE + virtual bool compare_types_with_cast(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0; + }; + + /** + * The standard typesafe function call implementation of Proxy_Function + * It takes a std::function<> object and performs runtime + * type checking of Boxed_Value parameters, in a type safe manner + */ + template + class Proxy_Function_Impl : public Proxy_Function_Impl_Base + { + public: + Proxy_Function_Impl(std::function f) + : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast(nullptr))), + m_f(std::move(f)), m_dummy_func(nullptr) { - return ""; + } + + virtual ~Proxy_Function_Impl() {} + + virtual bool compare_types_with_cast(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + { + return detail::compare_types_cast(m_dummy_func, vals, t_conversions); + } + + virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE + { + return dynamic_cast *>(&t_func) != nullptr; } std::function internal_function() const @@ -489,7 +506,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const { return detail::Do_Call::result_type>::go(m_f, params, t_conversions); } From 5692dfc58acf3fb27707807ca5bdadb3184df5a2 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 15 Aug 2014 20:38:35 -0600 Subject: [PATCH 03/18] Move to unique_ptr for Any implemenation Speed and size improvements --- include/chaiscript/dispatchkit/any.hpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index 16c9217e..6704bb39 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -47,7 +47,7 @@ namespace chaiscript { virtual ~Data() {} virtual void *data() = 0; virtual const std::type_info &type() const = 0; - virtual std::shared_ptr clone() const = 0; + virtual std::unique_ptr clone() const = 0; }; template @@ -71,9 +71,9 @@ namespace chaiscript { return m_type; } - std::shared_ptr clone() const CHAISCRIPT_OVERRIDE + std::unique_ptr clone() const CHAISCRIPT_OVERRIDE { - return std::shared_ptr(new Data_Impl(m_data)); + return std::unique_ptr(new Data_Impl(m_data)); } Data_Impl &operator=(const Data_Impl&) = delete; @@ -82,7 +82,7 @@ namespace chaiscript { T m_data; }; - std::shared_ptr m_data; + std::unique_ptr m_data; public: // construct/copy/destruct @@ -100,7 +100,7 @@ namespace chaiscript { template Any(const ValueType &t_value) - : m_data(std::shared_ptr(new Data_Impl(t_value))) + : m_data(std::unique_ptr(new Data_Impl(t_value))) { } @@ -114,7 +114,7 @@ namespace chaiscript { template Any & operator=(const ValueType &t_value) { - m_data = std::shared_ptr(new Data_Impl(t_value)); + m_data = std::unique_ptr(new Data_Impl(t_value)); return *this; } @@ -138,9 +138,7 @@ namespace chaiscript { // modifiers Any & swap(Any &t_other) { - std::shared_ptr data = t_other.m_data; - t_other.m_data = m_data; - m_data = data; + std::swap(t_other.m_data, m_data); return *this; } From 3a775097dd402840c83cbf893baf0d040db78b01 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 17 Aug 2014 06:52:11 -0600 Subject: [PATCH 04/18] Reduce size of Any template wrapper. --- include/chaiscript/dispatchkit/any.hpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index 6704bb39..c0748984 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -44,17 +44,27 @@ namespace chaiscript { private: struct Data { + Data(const std::type_info &t_type) + : m_type(t_type) + { + } + virtual ~Data() {} virtual void *data() = 0; - virtual const std::type_info &type() const = 0; + const std::type_info &type() const + { + return m_type; + } + virtual std::unique_ptr clone() const = 0; + const std::type_info &m_type; }; template struct Data_Impl : Data { Data_Impl(T t_type) - : m_type(typeid(T)), + : Data(typeid(T)), m_data(std::move(t_type)) { } @@ -66,19 +76,13 @@ namespace chaiscript { return &m_data; } - const std::type_info &type() const CHAISCRIPT_OVERRIDE - { - return m_type; - } - std::unique_ptr clone() const CHAISCRIPT_OVERRIDE { return std::unique_ptr(new Data_Impl(m_data)); } Data_Impl &operator=(const Data_Impl&) = delete; - - const std::type_info &m_type; + T m_data; }; @@ -127,7 +131,6 @@ namespace chaiscript { } else { throw chaiscript::detail::exception::bad_any_cast(); } - } From cb1c7730cf5065c708eaea3d151fb9c8682cfce5 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 17 Aug 2014 09:05:29 -0600 Subject: [PATCH 05/18] Add the ability to look up user defined typenames Closes #124 --- CMakeLists.txt | 4 ++++ .../chaiscript/language/chaiscript_engine.hpp | 12 ++++++++++ unittests/type_name_test.cpp | 22 +++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 unittests/type_name_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fbc59258..f6183c1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,6 +275,10 @@ if(BUILD_TESTING) target_link_libraries(type_info_test ${LIBS}) add_test(NAME Type_Info_Test COMMAND type_info_test) + add_executable(type_name_test unittests/type_name_test.cpp) + target_link_libraries(type_name_test ${LIBS}) + add_test(NAME Type_Name_Test COMMAND type_name_test) + add_executable(eval_catch_exception_test unittests/eval_catch_exception_test.cpp) target_link_libraries(eval_catch_exception_test ${LIBS}) add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test) diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 336e03ab..81b6cb83 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -503,6 +503,18 @@ namespace chaiscript return ss.str(); } + std::string get_type_name(const Type_Info &ti) const + { + return m_engine.get_type_name(ti); + } + + template + std::string get_type_name() const + { + return get_type_name(user_type()); + } + + /// \brief Loads and parses a file. If the file is already, it is not reloaded /// The use paths specified at ChaiScript construction time are searched for the /// requested file. diff --git a/unittests/type_name_test.cpp b/unittests/type_name_test.cpp new file mode 100644 index 00000000..e8373039 --- /dev/null +++ b/unittests/type_name_test.cpp @@ -0,0 +1,22 @@ +// Tests to make sure that the order in which function dispatches occur is correct + +#include +#include + +class MyClass +{ +}; + +int main() +{ + chaiscript::ChaiScript chai; + auto type = chaiscript::user_type(); + chai.add(type, "MyClass"); + + if (chai.get_type_name(type) == "MyClass" && chai.get_type_name() == "MyClass") + { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } +} From fa1f4b795b83eccfe4f99b1288eb8567eae0e78b Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 22 Aug 2014 21:11:49 -0600 Subject: [PATCH 06/18] Add `class` keyword for easier user defined types. Issue #118 --- .../chaiscript/dispatchkit/dispatchkit.hpp | 13 ++ .../chaiscript/language/chaiscript_common.hpp | 20 +-- .../chaiscript/language/chaiscript_engine.hpp | 1 + .../chaiscript/language/chaiscript_eval.hpp | 59 ++++++--- .../chaiscript/language/chaiscript_parser.hpp | 116 +++++++++++++++++- unittests/class.chai | 27 ++++ 6 files changed, 205 insertions(+), 31 deletions(-) create mode 100644 unittests/class.chai diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 72a38fb4..8c4a7f59 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -736,6 +736,19 @@ namespace chaiscript return functions.find(name) != functions.end(); } + /// \returns All values in the local thread state in the parent scope, or if it doesn't exist, + /// the current scope. + std::map get_parent_locals() const + { + StackData &stack = get_stack_data(); + if (stack.size() > 1) + { + return stack[1]; + } else { + return stack[0]; + } + } + /// \returns All values in the local thread state, added through the add() function std::map get_locals() const { diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 63fe16ce..ec006d0e 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -37,7 +37,7 @@ namespace chaiscript Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String, Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range, Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or, - Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop + Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class }; }; @@ -510,6 +510,9 @@ namespace chaiscript /// Creates a new scope then pops it on destruction struct Scope_Push_Pop { + Scope_Push_Pop(const Scope_Push_Pop &) = delete; + Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete; + Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) : m_de(t_de) { @@ -523,9 +526,6 @@ namespace chaiscript private: - // explicitly unimplemented copy and assignment - Scope_Push_Pop(const Scope_Push_Pop &); - Scope_Push_Pop& operator=(const Scope_Push_Pop &); chaiscript::detail::Dispatch_Engine &m_de; }; @@ -533,6 +533,9 @@ namespace chaiscript /// Creates a new function call and pops it on destruction struct Function_Push_Pop { + Function_Push_Pop(const Function_Push_Pop &) = delete; + Function_Push_Pop& operator=(const Function_Push_Pop &) = delete; + Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) : m_de(t_de) { @@ -551,9 +554,6 @@ namespace chaiscript private: - // explicitly unimplemented copy and assignment - Function_Push_Pop(const Function_Push_Pop &); - Function_Push_Pop& operator=(const Function_Push_Pop &); chaiscript::detail::Dispatch_Engine &m_de; }; @@ -561,6 +561,9 @@ namespace chaiscript /// Creates a new scope then pops it on destruction struct Stack_Push_Pop { + Stack_Push_Pop(const Stack_Push_Pop &) = delete; + Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete; + Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) : m_de(t_de) { @@ -574,9 +577,6 @@ namespace chaiscript private: - // explicitly unimplemented copy and assignment - Stack_Push_Pop(const Stack_Push_Pop &); - Stack_Push_Pop& operator=(const Stack_Push_Pop &); chaiscript::detail::Dispatch_Engine &m_de; }; diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 81b6cb83..0513194a 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -330,6 +330,7 @@ namespace chaiscript m_engine.add_reserved_word("break"); m_engine.add_reserved_word("true"); m_engine.add_reserved_word("false"); + m_engine.add_reserved_word("class"); m_engine.add_reserved_word("_"); if (t_lib) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 56a20d91..f2e2391d 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -856,7 +856,23 @@ namespace chaiscript return Boxed_Value(); } + }; + struct Class_AST_Node : public AST_Node { + public: + Class_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(t_ast_node_text, AST_Node_Type::Class, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Class_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + + // put class name in current scope so it can be looked up by the attrs and methods + t_ss.add_object("_current_class_name", const_var(this->children[0]->text)); + + this->children[1]->eval(t_ss); + + return Boxed_Value(); + } }; struct Ternary_Cond_AST_Node : public AST_Node { @@ -1400,23 +1416,29 @@ namespace chaiscript std::vector t_param_names; AST_NodePtr guardnode; + auto d = t_ss.get_parent_locals(); + auto itr = d.find("_current_class_name"); + int class_offset = 0; + if (itr != d.end()) class_offset = -1; + const std::string & class_name = (itr != d.end())?std::string(boxed_cast(itr->second)):this->children[0]->text; + //The first param of a method is always the implied this ptr. t_param_names.push_back("this"); - if ((this->children.size() > 3) && (this->children[2]->identifier == AST_Node_Type::Arg_List)) { - for (size_t i = 0; i < this->children[2]->children.size(); ++i) { - t_param_names.push_back(this->children[2]->children[i]->text); + if ((this->children.size() > (3 + class_offset)) && (this->children[(2 + class_offset)]->identifier == AST_Node_Type::Arg_List)) { + for (size_t i = 0; i < this->children[(2 + class_offset)]->children.size(); ++i) { + t_param_names.push_back(this->children[(2 + class_offset)]->children[i]->text); } - if (this->children.size() > 4) { - guardnode = this->children[3]; + if (this->children.size() > (4 + class_offset)) { + guardnode = this->children[(3 + class_offset)]; } } else { //no parameters - if (this->children.size() > 3) { - guardnode = this->children[2]; + if (this->children.size() > (3 + class_offset)) { + guardnode = this->children[(2 + class_offset)]; } } @@ -1432,8 +1454,9 @@ namespace chaiscript try { const std::string & l_annotation = this->annotation?this->annotation->text:""; - const std::string & class_name = this->children[0]->text; - const std::string & function_name = this->children[1]->text; + + const std::string & function_name = this->children[(1 + class_offset)]->text; + if (function_name == class_name) { t_ss.add(Proxy_Function (new dispatch::detail::Dynamic_Object_Constructor(class_name, Proxy_Function @@ -1478,22 +1501,28 @@ namespace chaiscript Attr_Decl_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Attr_Decl, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Attr_Decl_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ - try { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE + { + const auto &d = t_ss.get_parent_locals(); + const auto itr = d.find("_current_class_name"); + int class_offset = 0; + if (itr != d.end()) class_offset = -1; + std::string class_name = (itr != d.end())?std::string(boxed_cast(itr->second)):this->children[0]->text; + try { t_ss.add(Proxy_Function (new dispatch::detail::Dynamic_Object_Function( - this->children[0]->text, + class_name, fun(std::function(std::bind(&dispatch::Dynamic_Object::get_attr, std::placeholders::_1, - this->children[1]->text + this->children[(1 + class_offset)]->text ))) ) - ), this->children[1]->text); + ), this->children[(1 + class_offset)]->text); } catch (const exception::reserved_word_error &) { - throw exception::eval_error("Reserved word used as attribute '" + this->children[1]->text + "'"); + throw exception::eval_error("Reserved word used as attribute '" + this->children[(1 + class_offset)]->text + "'"); } catch (const exception::name_conflict_error &e) { throw exception::eval_error("Attribute redefined '" + e.name() + "'"); } diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 06d53fa9..6efd8d08 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -1358,7 +1358,7 @@ namespace chaiscript /** * Reads a function definition from input */ - bool Def() { + bool Def(bool t_class_context = false) { bool retval = false; bool is_annotated = false; AST_NodePtr annotation; @@ -1410,7 +1410,7 @@ namespace chaiscript throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); } - if (is_method) { + if (is_method || t_class_context) { build_match(AST_NodePtr(new eval::Method_AST_Node()), prev_stack_top); } else { @@ -1555,6 +1555,35 @@ namespace chaiscript return retval; } + /** + * Reads a class block from input + */ + bool Class() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("class")) { + retval = true; + + if (!Id(true)) { + throw exception::eval_error("Missing class name in definition", File_Position(m_line, m_col), *m_filename); + } + + + while (Eol()) {} + + if (!Class_Block()) { + throw exception::eval_error("Incomplete 'class' block", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Class_AST_Node()), prev_stack_top); + } + + return retval; + } + + /** * Reads a while block from input */ @@ -1737,6 +1766,28 @@ namespace chaiscript } + /** + * Reads a curly-brace C-style class block from input + */ + bool Class_Block() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Char('{')) { + retval = true; + + Class_Statements(); + if (!Char('}')) { + throw exception::eval_error("Incomplete class block", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Block_AST_Node()), prev_stack_top); + } + + return retval; + } + /** * Reads a curly-brace C-style block from input */ @@ -1875,12 +1926,20 @@ namespace chaiscript /** * Reads a variable declaration from input */ - bool Var_Decl() { + bool Var_Decl(bool t_class_context = false) { bool retval = false; size_t prev_stack_top = m_match_stack.size(); - if (Keyword("auto") || Keyword("var")) { + if (t_class_context && (Keyword("attr") || Keyword("auto") || Keyword("var"))) { + retval = true; + + if (!Id(true)) { + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Attr_Decl_AST_Node()), prev_stack_top); + } else if (Keyword("auto") || Keyword("var")) { retval = true; if (!(Reference() || Id(true))) { @@ -1888,8 +1947,7 @@ namespace chaiscript } build_match(AST_NodePtr(new eval::Var_Decl_AST_Node()), prev_stack_top); - } - else if (Keyword("attr")) { + } else if (Keyword("attr")) { retval = true; if (!Id(true)) { @@ -2262,6 +2320,44 @@ namespace chaiscript return retval; } + /** + * Parses statements allowed inside of a class block + */ + bool Class_Statements() { + bool retval = false; + + bool has_more = true; + bool saw_eol = true; + + while (has_more) { + int prev_line = m_line; + int prev_col = m_col; + if (Def(true)) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } else if (Var_Decl(true)) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } else if (Eol()) { + has_more = true; + retval = true; + saw_eol = true; + } else { + has_more = false; + } + } + + return retval; + } + /** * Top level parser, starts parsing of all known parses */ @@ -2306,6 +2402,14 @@ namespace chaiscript retval = true; saw_eol = true; } + else if (Class()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } else if (For()) { if (!saw_eol) { throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); diff --git a/unittests/class.chai b/unittests/class.chai new file mode 100644 index 00000000..8936436c --- /dev/null +++ b/unittests/class.chai @@ -0,0 +1,27 @@ + +class Vector3 +{ + // you can use attr, auto or var in this context + attr x + auto y + var z + + def Vector3(x,y,z) + { + this.x = x + this.y = y + this.z = z + } + + def doSomething(mult) + { + return this.x * this.y * this.z * mult + } + +} + + +auto v = Vector3(1,2,3) +assert_equal(1, v.x) +assert_equal(v.doSomething(2), 12) + From f546e46582736805c7cbaf360bf7aa62d9493082 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 22 Aug 2014 21:29:14 -0600 Subject: [PATCH 07/18] Update to cppcheck 1.66 --- contrib/codeanalysis/runcppcheck.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/codeanalysis/runcppcheck.sh b/contrib/codeanalysis/runcppcheck.sh index c39cc655..5e79737a 100755 --- a/contrib/codeanalysis/runcppcheck.sh +++ b/contrib/codeanalysis/runcppcheck.sh @@ -1,9 +1,9 @@ #!/bin/bash pushd .. -wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.64/cppcheck-1.65.tar.bz2 -tar -xvf cppcheck-1.65.tar.bz2 -cd cppcheck-1.65 +wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.66/cppcheck-1.66.tar.bz2 +tar -xvf cppcheck-1.66.tar.bz2 +cd cppcheck-1.66 make -j2 popd ../cppcheck-1.65/cppcheck --enable=all -I include --inline-suppr --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output From 9b7e4d2e7828797bd3bbfa79ba2a21deadd18fca Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 26 Aug 2014 08:51:02 -0600 Subject: [PATCH 08/18] Let a subscript out of range be catchable from chaiscript --- include/chaiscript/language/chaiscript_eval.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index f2e2391d..f40a9fc9 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -584,9 +584,6 @@ namespace chaiscript params.clear(); retval = t_ss.call_function("[]", retval, p1); } - catch(std::out_of_range &) { - throw exception::eval_error("Out of bounds exception"); - } catch(const exception::dispatch_error &e){ throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, t_ss ); } @@ -662,9 +659,6 @@ namespace chaiscript try { retval = t_ss.call_function("[]", retval, this->children[i]->children[j]->eval(t_ss)); } - catch(std::out_of_range &) { - throw exception::eval_error("Out of bounds exception"); - } catch(const exception::dispatch_error &e){ throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, t_ss); } From 6a3f19d575419a42632cc7e5da88e3b6ee0c2ab2 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 26 Aug 2014 09:28:51 -0600 Subject: [PATCH 09/18] Add copy constructor for Type_Info --- include/chaiscript/dispatchkit/bootstrap.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 9b6de9ae..5a929480 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -412,6 +412,7 @@ namespace chaiscript m->add(fun(&Boxed_Value::get_type_info), "get_type_info"); m->add(user_type(), "Type_Info"); + m->add(constructor(), "Type_Info"); operators::equal(m); From a6e3fd5b42ca9397334f5a583a4a80f3bb1f6ea3 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 27 Aug 2014 12:05:03 -0600 Subject: [PATCH 10/18] Make reflection API part of stdlib removes the reflection module completely. Reflection and the ability to catch eval errors is too useful. --- CMakeLists.txt | 6 +- include/chaiscript/dispatchkit/bootstrap.hpp | 102 +++++++++++++- .../chaiscript/dispatchkit/bootstrap_stl.hpp | 7 +- src/reflection.cpp | 129 ------------------ unittests/3.x/eval_error.chai | 1 - unittests/3.x/reflection_test.chai | 1 - unittests/eval_error.chai | 1 - unittests/operator_scoping.chai | 1 - unittests/reflection_test.chai | 1 - 9 files changed, 109 insertions(+), 140 deletions(-) delete mode 100644 src/reflection.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f6183c1a..1f463b45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ else() endif() -option(BUILD_MODULES "Build Extra Modules (stl, reflection)" TRUE) +option(BUILD_MODULES "Build Extra Modules (stl)" TRUE) option(BUILD_SAMPLES "Build Samples Folder" FALSE) @@ -210,9 +210,7 @@ if(BUILD_MODULES) add_library(stl_extra MODULE src/stl_extra.cpp) target_link_libraries(stl_extra ${LIBS}) - add_library(reflection MODULE src/reflection.cpp) - target_link_libraries(reflection ${LIBS}) - set(MODULES stl_extra reflection) + set(MODULES stl_extra) endif() file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 5a929480..c31b68c6 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -32,6 +32,8 @@ #include "proxy_functions_detail.hpp" #include "register_function.hpp" #include "type_info.hpp" +#include "../utility/utility.hpp" +#include "../language/chaiscript_common.hpp" namespace chaiscript { @@ -357,12 +359,48 @@ namespace chaiscript return vbv; } + + static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) + { + std::shared_ptr pf + = std::dynamic_pointer_cast(t_pf); + if (pf) + { + if (pf->get_parse_tree()) + { + return true; + } else { + return false; + } + } else { + return false; + } + } + + static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) + { + std::shared_ptr pf + = std::dynamic_pointer_cast(t_pf); + if (pf) + { + if (pf->get_parse_tree()) + { + return pf->get_parse_tree(); + } else { + throw std::runtime_error("Function does not have a parse tree"); + } + } else { + throw std::runtime_error("Function does not have a parse tree"); + } + } + template static std::function (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f) { return std::bind(&do_return_boxed_value_vector, f, std::placeholders::_1); } + public: /// \brief perform all common bootstrap functions for std::string, void and POD types /// \param[in,out] m Module to add bootstrapped functions to @@ -380,7 +418,7 @@ namespace chaiscript m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation"); m->add(fun(&dispatch::Proxy_Function_Base::operator==), "=="); - + m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types"); m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions"); @@ -473,6 +511,68 @@ namespace chaiscript m->add(fun(&Boxed_Value::type_match), "type_match"); + + m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); + m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree"); + + m->add(chaiscript::base_class()); + +// chaiscript::bootstrap::standard_library::vector_type > >("AST_NodeVector", m); + + + chaiscript::utility::add_class(*m, + "eval_error", + { }, + { {fun(&chaiscript::exception::eval_error::reason), "reason"}, + {fun(std::function (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) { + std::vector retval; + std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(), + std::back_inserter(retval), + &chaiscript::var>); + return retval; + })), "call_stack"} } + ); + + + chaiscript::utility::add_class(*m, + "File_Position", + { constructor(), + constructor() }, + { {fun(&File_Position::line), "line"}, + {fun(&File_Position::column), "column"} } + ); + + + chaiscript::utility::add_class(*m, + "AST_Node", + { }, + { {fun(&AST_Node::text), "text"}, + {fun(&AST_Node::identifier), "identifier"}, + {fun(&AST_Node::filename), "filename"}, + {fun(&AST_Node::start), "start"}, + {fun(&AST_Node::end), "end"}, + {fun(&AST_Node::internal_to_string), "internal_to_string"}, + {fun(std::function (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) { + std::vector retval; + std::transform(t_node.children.begin(), t_node.children.end(), + std::back_inserter(retval), + &chaiscript::var>); + return retval; + })), "children"}, + {fun(&AST_Node::replace_child), "replace_child"} + } + ); + + + chaiscript::utility::add_class(*m, + "ChaiScript_Parser", + { constructor() }, + { {fun(&parser::ChaiScript_Parser::parse), "parse"}, + {fun(&parser::ChaiScript_Parser::ast), "ast"} } + ); + + + return m; } }; diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index ecf3743c..6797e5d0 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -185,7 +185,7 @@ namespace chaiscript copy_constructor(type + "_Range", m); - m->add(constructor(), "range"); + m->add(constructor(), "range_internal"); m->add(fun(&Bidir_Type::empty), "empty"); m->add(fun(&Bidir_Type::pop_front), "pop_front"); @@ -348,10 +348,12 @@ namespace chaiscript ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = ModulePtr(new Module())) { typedef typename ContainerType::reference (ContainerType::*frontptr)(); + typedef typename ContainerType::const_reference (ContainerType::*constfrontptr)() const; typedef void (ContainerType::*pushptr)(typename ContainerType::const_reference); typedef void (ContainerType::*popptr)(); m->add(fun(static_cast(&ContainerType::front)), "front"); + m->add(fun(static_cast(&ContainerType::front)), "front"); std::string push_front_name; if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) @@ -475,7 +477,10 @@ namespace chaiscript m->add(user_type(), type); typedef typename VectorType::reference (VectorType::*frontptr)(); + typedef typename VectorType::const_reference (VectorType::*constfrontptr)() const; + m->add(fun(static_cast(&VectorType::front)), "front"); + m->add(fun(static_cast(&VectorType::front)), "front"); back_insertion_sequence_type(type, m); diff --git a/src/reflection.cpp b/src/reflection.cpp deleted file mode 100644 index cb369f25..00000000 --- a/src/reflection.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// This file is distributed under the BSD License. -// See "license.txt" for details. -// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2014, Jason Turner (jason@emptycrate.com) -// http://www.chaiscript.com - - -#include -#include -#include -#include -#include - - -// MSVC doesn't like that we are using C++ return types from our C declared module -// but this is the best way to do it for cross platform compatibility -#ifdef CHAISCRIPT_MSVC -#pragma warning(push) -#pragma warning(disable : 4190) -#endif - - -bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) -{ - std::shared_ptr pf - = std::dynamic_pointer_cast(t_pf); - if (pf) - { - if (pf->get_parse_tree()) - { - return true; - } else { - return false; - } - } else { - return false; - } -} - -chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) -{ - std::shared_ptr pf - = std::dynamic_pointer_cast(t_pf); - if (pf) - { - if (pf->get_parse_tree()) - { - return pf->get_parse_tree(); - } else { - throw std::runtime_error("Function does not have a parse tree"); - } - } else { - throw std::runtime_error("Function does not have a parse tree"); - } -} - - -#ifdef __llvm__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" -#endif - - -CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflection() -{ - chaiscript::ModulePtr m(new chaiscript::Module()); - - m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); - m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree"); - - m->add(chaiscript::base_class()); - - chaiscript::bootstrap::standard_library::vector_type > >("AST_NodeVector", m); - - using namespace chaiscript; - - chaiscript::utility::add_class(*m, - "eval_error", - { }, - { {fun(&chaiscript::exception::eval_error::reason), "reason"}, - {fun(&chaiscript::exception::eval_error::call_stack), "call_stack"} } - ); - - - chaiscript::utility::add_class(*m, - "File_Position", - { constructor(), - constructor() }, - { {fun(&File_Position::line), "line"}, - {fun(&File_Position::column), "column"} } - ); - - - chaiscript::utility::add_class(*m, - "AST_Node", - { }, - { {fun(&AST_Node::text), "text"}, - {fun(&AST_Node::identifier), "identifier"}, - {fun(&AST_Node::filename), "filename"}, - {fun(&AST_Node::start), "start"}, - {fun(&AST_Node::end), "end"}, - {fun(&AST_Node::internal_to_string), "internal_to_string"}, - {fun(&AST_Node::children), "children"}, - {fun(&AST_Node::replace_child), "replace_child"} - } - ); - - - chaiscript::utility::add_class(*m, - "ChaiScript_Parser", - { constructor() }, - { {fun(&parser::ChaiScript_Parser::parse), "parse"}, - {fun(&parser::ChaiScript_Parser::ast), "ast"} } - ); - - - - return m; -} - -#ifdef __llvm__ -#pragma clang diagnostic pop -#endif - - - -#ifdef CHAISCRIPT_MSVC -#pragma warning(pop) -#endif diff --git a/unittests/3.x/eval_error.chai b/unittests/3.x/eval_error.chai index d63ad759..39a6541e 100644 --- a/unittests/3.x/eval_error.chai +++ b/unittests/3.x/eval_error.chai @@ -1,4 +1,3 @@ -load_module("reflection") def deep() { diff --git a/unittests/3.x/reflection_test.chai b/unittests/3.x/reflection_test.chai index 88b39ccc..25a24168 100644 --- a/unittests/3.x/reflection_test.chai +++ b/unittests/3.x/reflection_test.chai @@ -1,4 +1,3 @@ -load_module("reflection") var parser := ChaiScript_Parser() var parse_success = parser.parse("3 + 4", "INPUT") var a := parser.ast() diff --git a/unittests/eval_error.chai b/unittests/eval_error.chai index b2737a11..fde7847b 100644 --- a/unittests/eval_error.chai +++ b/unittests/eval_error.chai @@ -1,4 +1,3 @@ -load_module("reflection") def deep() { diff --git a/unittests/operator_scoping.chai b/unittests/operator_scoping.chai index 5718bd59..56210171 100644 --- a/unittests/operator_scoping.chai +++ b/unittests/operator_scoping.chai @@ -1,4 +1,3 @@ -load_module("reflection") try { eval("def `+`(x, y) \n { \n print(i); \n } \n \n var i = 10; \n \"1\" + 1;\n") diff --git a/unittests/reflection_test.chai b/unittests/reflection_test.chai index 42566bc1..16ef7e9f 100644 --- a/unittests/reflection_test.chai +++ b/unittests/reflection_test.chai @@ -1,4 +1,3 @@ -load_module("reflection") auto& parser = ChaiScript_Parser() auto parse_success = parser.parse("3 + 4", "INPUT") auto& a = parser.ast() From 9c05779fac9325ec4734aabb996560b448a78331 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 27 Aug 2014 12:15:47 -0600 Subject: [PATCH 11/18] Add failing range test Crash occurs if the user attempts to use a range and the source of the range has gone out of scope. #132 --- unittests/range.chai | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/unittests/range.chai b/unittests/range.chai index 97a430b1..db4a1a9f 100644 --- a/unittests/range.chai +++ b/unittests/range.chai @@ -2,3 +2,9 @@ auto x = [1, 2, 3, 4] auto r = range(x) r.pop_front() assert_equal(2, r.front()); + +// test with temporary vector for range +auto q = range([1, 2, 3, 4]) +q.pop_front() +assert_equal(2, q.front()); + From 3fe80d70c64a0f6e4a4f0d024736063d3f39059a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 27 Aug 2014 12:24:46 -0600 Subject: [PATCH 12/18] Roll back name of range class, it's half baked from the range fix --- include/chaiscript/dispatchkit/bootstrap_stl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 6797e5d0..0811faa2 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -185,7 +185,7 @@ namespace chaiscript copy_constructor(type + "_Range", m); - m->add(constructor(), "range_internal"); + m->add(constructor(), "range"); m->add(fun(&Bidir_Type::empty), "empty"); m->add(fun(&Bidir_Type::pop_front), "pop_front"); From a71903f1856ac0aac9cc1c88d26a58ebed127430 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 30 Aug 2014 13:36:36 -0600 Subject: [PATCH 13/18] Add strong reference to range objects #132 --- include/chaiscript/dispatchkit/bootstrap.hpp | 2 ++ .../chaiscript/dispatchkit/bootstrap_stl.hpp | 2 +- .../dispatchkit/boxed_cast_helper.hpp | 17 +++++++++++- .../chaiscript/dispatchkit/boxed_value.hpp | 27 +++++++++++++++++++ .../language/chaiscript_prelude.chai | 16 ++++++++--- src/main.cpp | 6 ++--- 6 files changed, 61 insertions(+), 9 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index c31b68c6..fbe2fd7d 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -447,6 +447,8 @@ namespace chaiscript m->add(fun(&Boxed_Value::is_ref), "is_var_reference"); m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer"); m->add(fun(&Boxed_Value::is_type), "is_type"); + m->add(fun(&Boxed_Value::get_attr), "get_var_attr"); + m->add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs"); m->add(fun(&Boxed_Value::get_type_info), "get_type_info"); m->add(user_type(), "Type_Info"); diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 0811faa2..6797e5d0 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -185,7 +185,7 @@ namespace chaiscript copy_constructor(type + "_Range", m); - m->add(constructor(), "range"); + m->add(constructor(), "range_internal"); m->add(fun(&Bidir_Type::empty), "empty"); m->add(fun(&Bidir_Type::pop_front), "pop_front"); diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index 39a6948a..a9c3c846 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -205,10 +205,25 @@ namespace chaiscript static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) { - return ob; + return ob; } }; + /** + * Cast_Helper_Inner for casting to a Boxed_Value & type + */ + template<> + struct Cast_Helper_Inner + { + typedef Boxed_Value& Result_Type; + + static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + { + return const_cast(ob); + } + }; + + /** * Cast_Helper_Inner for casting to a const Boxed_Value & type */ diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 006815bd..8b5f8fee 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -51,9 +51,16 @@ namespace chaiscript m_data_ptr = rhs.m_data_ptr; m_const_data_ptr = rhs.m_const_data_ptr; + if (rhs.m_attrs) + { + m_attrs = std::unique_ptr>(new std::map(*rhs.m_attrs)); + } + return *this; } + Data(const Data &) = delete; + ~Data() { } @@ -63,6 +70,7 @@ namespace chaiscript void *m_data_ptr; const void *m_const_data_ptr; bool m_is_ref; + std::unique_ptr> m_attrs; }; struct Object_Data @@ -231,6 +239,25 @@ namespace chaiscript return m_data->m_const_data_ptr; } + Boxed_Value get_attr(const std::string &t_name) + { + if (!m_data->m_attrs) + { + m_data->m_attrs = std::unique_ptr>(new std::map()); + } + + return (*m_data->m_attrs)[t_name]; + } + + void copy_attrs(const Boxed_Value &t_obj) + { + if (t_obj.m_data->m_attrs) + { + m_data->m_attrs = std::unique_ptr>(new std::map(*t_obj.m_data->m_attrs)); + } + } + + /// \returns true if the two Boxed_Values share the same internal type static bool type_match(Boxed_Value l, Boxed_Value r) { diff --git a/include/chaiscript/language/chaiscript_prelude.chai b/include/chaiscript/language/chaiscript_prelude.chai index 7af9a619..5d8dce3e 100644 --- a/include/chaiscript/language/chaiscript_prelude.chai +++ b/include/chaiscript/language/chaiscript_prelude.chai @@ -41,8 +41,10 @@ def new(x) { } def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x) -{ - eval(type_name(x))(x); +{ + var c := eval(type_name(x))(x); + c.copy_var_attrs(x); + return c; } @@ -147,10 +149,16 @@ def reverse(container) { # Return a range from a range def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r) -{ - return clone(r); +{ + clone(r); } +def range(r) : call_exists(range_internal, r) +{ + var ri := range_internal(r); + ri.get_var_attr("internal_obj") := r; + return ri; +} # The retro attribute that contains the underlying range attr retro::m_range; diff --git a/src/main.cpp b/src/main.cpp index ce1afcb9..a3735f8a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,15 +17,15 @@ #else char *mystrdup (const char *s) { - size_t len = strlen(s) + 1; // Space for length plus nul - char *d = static_cast(malloc (len)); + size_t len = strlen(s); // Space for length plus nul + char *d = static_cast(malloc (len+1)); if (d == nullptr) return nullptr; // No memory #ifdef CHAISCRIPT_MSVC strcpy_s(d, len, s); // Copy the characters #else strncpy(d,s,len); // Copy the characters - d[len] = '\0'; #endif + d[len] = '\0'; return d; // Return the new string } From 4ee9ba9c96886cc892964ba636c478812144840c Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 30 Aug 2014 14:49:31 -0600 Subject: [PATCH 14/18] Make up some of the performance losses #132 --- .../chaiscript/dispatchkit/boxed_value.hpp | 3 +- .../language/chaiscript_prelude.chai | 72 +++++++++---------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 8b5f8fee..861a2f7c 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -249,12 +249,13 @@ namespace chaiscript return (*m_data->m_attrs)[t_name]; } - void copy_attrs(const Boxed_Value &t_obj) + Boxed_Value ©_attrs(const Boxed_Value &t_obj) { if (t_obj.m_data->m_attrs) { m_data->m_attrs = std::unique_ptr>(new std::map(*t_obj.m_data->m_attrs)); } + return *this; } diff --git a/include/chaiscript/language/chaiscript_prelude.chai b/include/chaiscript/language/chaiscript_prelude.chai index 5d8dce3e..426dc3b3 100644 --- a/include/chaiscript/language/chaiscript_prelude.chai +++ b/include/chaiscript/language/chaiscript_prelude.chai @@ -40,11 +40,9 @@ def new(x) { eval(type_name(x))(); } -def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x) +def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x) { - var c := eval(type_name(x))(x); - c.copy_var_attrs(x); - return c; + eval(type_name(x))(x).copy_var_attrs(x); } @@ -138,8 +136,8 @@ def insert_at(container, pos, x) # Returns the reverse of the given container def reverse(container) { - auto retval = new(container); - auto r = range(container); + auto retval := new(container); + auto r := range(container); while (!r.empty()) { retval.push_back(r.back()); r.pop_back(); @@ -157,7 +155,7 @@ def range(r) : call_exists(range_internal, r) { var ri := range_internal(r); ri.get_var_attr("internal_obj") := r; - return ri; + ri; } # The retro attribute that contains the underlying range @@ -208,19 +206,19 @@ def retro::empty() # Performs the second value function over the container first value def for_each(container, func) : call_exists(range, container) { - var t_range = range(container); + var t_range := range(container); while (!t_range.empty()) { func(t_range.front()); t_range.pop_front(); } } -def back_inserter(container) { - bind(push_back, container, _); +def back_inserter(container) { + bind(push_back, container, _); } def contains(container, item, compare_func) : call_exists(range, container) { - auto t_range = range(container); + auto t_range := range(container); while (!t_range.empty()) { if ( compare_func(t_range.front(), item) ) { return true; @@ -228,15 +226,15 @@ def contains(container, item, compare_func) : call_exists(range, container) { t_range.pop_front(); } - return false; + false; } def contains(container, item) { - return contains(container, item, eq) + contains(container, item, eq) } def map(container, func, inserter) : call_exists(range, container) { - auto range = range(container); + auto range := range(container); while (!range.empty()) { inserter(func(range.front())); range.pop_front(); @@ -245,7 +243,7 @@ def map(container, func, inserter) : call_exists(range, container) { # Performs the second value function over the container first value. Creates a new container with the results def map(container, func) { - auto retval = new(container); + auto retval := new(container); map(container, func, back_inserter(retval)); retval; } @@ -253,7 +251,7 @@ def map(container, func) { # Performs the second value function over the container first value. Starts with initial and continues with each element. def foldl(container, func, initial) : call_exists(range, container){ auto retval = initial; - auto range = range(container); + auto range := range(container); while (!range.empty()) { retval = (func(range.front(), retval)); range.pop_front(); @@ -274,8 +272,8 @@ def product(container) { # Returns a new container with the elements of the first value concatenated with the elements of the second value def concat(x, y) : call_exists(clone, x) { auto retval = x; - auto inserter = back_inserter(retval); - auto range = range(y); + auto inserter := back_inserter(retval); + auto range := range(y); while (!range.empty()) { inserter(range.front()); range.pop_front(); @@ -285,7 +283,7 @@ def concat(x, y) : call_exists(clone, x) { def take(container, num, inserter) : call_exists(range, container) { - auto r = range(container); + auto r := range(container); auto i = num; while ((i > 0) && (!r.empty())) { inserter(r.front()); @@ -297,14 +295,14 @@ def take(container, num, inserter) : call_exists(range, container) { # Returns a new container with the given number of elements taken from the container def take(container, num) { - auto retval = new(container); + auto retval := new(container); take(container, num, back_inserter(retval)); retval; } def take_while(container, f, inserter) : call_exists(range, container) { - auto r = range(container); + auto r := range(container); while ((!r.empty()) && f(r.front())) { inserter(r.front()); r.pop_front(); @@ -314,14 +312,14 @@ def take_while(container, f, inserter) : call_exists(range, container) { # Returns a new container with the given elements match the second value function def take_while(container, f) { - auto retval = new(container); + auto retval := new(container); take_while(container, f, back_inserter(retval)); retval; } def drop(container, num, inserter) : call_exists(range, container) { - auto r = range(container); + auto r := range(container); auto i = num; while ((i > 0) && (!r.empty())) { r.pop_front(); @@ -336,14 +334,14 @@ def drop(container, num, inserter) : call_exists(range, container) { # Returns a new container with the given number of elements dropped from the given container def drop(container, num) { - auto retval = new(container); + auto retval := new(container); drop(container, num, back_inserter(retval)); retval; } def drop_while(container, f, inserter) : call_exists(range, container) { - auto r = range(container); + auto r := range(container); while ((!r.empty())&& f(r.front())) { r.pop_front(); } @@ -356,7 +354,7 @@ def drop_while(container, f, inserter) : call_exists(range, container) { # Returns a new container with the given elements dropped that match the second value function def drop_while(container, f) { - auto retval = new(container); + auto retval := new(container); drop_while(container, f, back_inserter(retval)); retval; } @@ -364,7 +362,7 @@ def drop_while(container, f) { # Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements. def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { - auto r = range(container); + auto r := range(container); auto retval = r.front(); r.pop_front(); retval = func(retval, r.front()); @@ -380,7 +378,7 @@ def reduce(container, func) : container.size() >= 2 && call_exists(range, contai # Returns a string of the elements in container delimited by the second value string def join(container, delim) { auto retval = ""; - auto range = range(container); + auto range := range(container); if (!range.empty()) { retval += to_string(range.front()); range.pop_front(); @@ -395,7 +393,7 @@ def join(container, delim) { def filter(container, f, inserter) : call_exists(range, container) { - auto r = range(container); + auto r := range(container); while (!r.empty()) { if (f(r.front())) { inserter(r.front()); @@ -407,7 +405,7 @@ def filter(container, f, inserter) : call_exists(range, container) { # Returns a new Vector which match the second value function def filter(container, f) { - auto retval = new(container); + auto retval := new(container); filter(container, f, back_inserter(retval)); retval; } @@ -424,7 +422,7 @@ def generate_range(x, y, inserter) { # Returns a new Vector which represents the range from the first value to the second value def generate_range(x, y) { - auto retval = Vector(); + auto retval := Vector(); generate_range(x,y,back_inserter(retval)); retval; } @@ -437,8 +435,8 @@ def collate(x, y) { def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) { - auto r_x = range(x); - auto r_y = range(y); + auto r_x := range(x); + auto r_y := range(y); while (!r_x.empty() && !r_y.empty()) { inserter(f(r_x.front(), r_y.front())); r_x.pop_front(); @@ -449,7 +447,7 @@ def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) # Returns a new Vector which joins matching elements of the second and third value with the first value function def zip_with(f, x, y) { - auto retval = Vector(); + auto retval := Vector(); zip_with(f,x,y,back_inserter(retval)); retval; } @@ -513,7 +511,7 @@ def string::trim() { def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") { - auto range = range(container); + auto range := range(container); while (!range.empty()) { if (compare_func(range.front(), value)) { return range; @@ -521,12 +519,12 @@ def find(container, value, compare_func) : call_exists(range, container) && is_t range.pop_front(); } } - return range; + range; } def find(container, value) { - return find(container, value, eq) + find(container, value, eq) } From 251790f14445a0ef7e4cd3e92353e015c40ec5c7 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 31 Aug 2014 12:04:02 -0600 Subject: [PATCH 15/18] Fix some MSVC warnings --- include/chaiscript/dispatchkit/any.hpp | 2 ++ include/chaiscript/language/chaiscript_parser.hpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index c0748984..ce76175e 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -49,6 +49,8 @@ namespace chaiscript { { } + Data &operator=(const Data &) = delete; + virtual ~Data() {} virtual void *data() = 0; const std::type_info &type() const diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 6efd8d08..e50a5d0a 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -1127,7 +1127,7 @@ namespace chaiscript } retval = true; m_input_pos = tmp; - m_col += len; + m_col += static_cast(len); } return retval; @@ -1175,7 +1175,7 @@ namespace chaiscript } retval = true; m_input_pos = tmp; - m_col += len; + m_col += static_cast(len); } return retval; From 6bea42c1c09f3ad4111411ff3928ec07688f34ac Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 31 Aug 2014 16:03:42 -0600 Subject: [PATCH 16/18] Speed up to_string performance by relying on C++ versions Addresses #134, fixing issues introduced by #132 --- include/chaiscript/dispatchkit/bootstrap.hpp | 6 +++--- include/chaiscript/language/chaiscript_common.hpp | 6 +----- include/chaiscript/language/chaiscript_prelude.chai | 5 ----- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index fbe2fd7d..32aa9391 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -472,8 +472,8 @@ namespace chaiscript operators::assign(m); operators::equal(m); - m->add(fun(&to_string), "internal_to_string"); - m->add(fun(&Bootstrap::bool_to_string), "internal_to_string"); + m->add(fun(&to_string), "to_string"); + m->add(fun(&Bootstrap::bool_to_string), "to_string"); m->add(fun(&unknown_assign), "="); m->add(fun(&throw_exception), "throw"); m->add(fun(&what), "what"); @@ -553,7 +553,7 @@ namespace chaiscript {fun(&AST_Node::filename), "filename"}, {fun(&AST_Node::start), "start"}, {fun(&AST_Node::end), "end"}, - {fun(&AST_Node::internal_to_string), "internal_to_string"}, + {fun(&AST_Node::to_string), "to_string"}, {fun(std::function (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) { std::vector retval; std::transform(t_node.children.begin(), t_node.children.end(), diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index ec006d0e..09987fa1 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -430,17 +430,13 @@ namespace chaiscript oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " << this->text << " : " << this->start.line << ", " << this->start.column << std::endl; - + for (size_t j = 0; j < this->children.size(); ++j) { oss << this->children[j]->to_string(t_prepend + " "); } return oss.str(); } - std::string internal_to_string() { - return to_string(); - } - Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) { try { diff --git a/include/chaiscript/language/chaiscript_prelude.chai b/include/chaiscript/language/chaiscript_prelude.chai index 426dc3b3..b4c0bc41 100644 --- a/include/chaiscript/language/chaiscript_prelude.chai +++ b/include/chaiscript/language/chaiscript_prelude.chai @@ -56,11 +56,6 @@ def to_string(x) : call_exists(range, x) && !x.is_type("string"){ "[" + x.join(", ") + "]"; } -# Basic to_string function -def to_string(x) { - internal_to_string(x); -} - # Prints to console with no carriage return def puts(x) { print_string(x.to_string()); From 6692607507499ee9b7fd8d74324e68098ebbd7aa Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 31 Aug 2014 19:45:07 -0600 Subject: [PATCH 17/18] Update version number to 5.4.0, update releasenotes --- CMakeLists.txt | 4 ++-- include/chaiscript/chaiscript_defines.hpp | 4 ++-- releasenotes.md | 10 +++++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f463b45..cefe9ecb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,8 +54,8 @@ set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt") set(CPACK_PACKAGE_VERSION_MAJOR 5) -set(CPACK_PACKAGE_VERSION_MINOR 3) -set(CPACK_PACKAGE_VERSION_PATCH 2) +set(CPACK_PACKAGE_VERSION_MINOR 4) +set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_VENDOR "ChaiScript.com") diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index cacb8bfb..59e302ee 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -45,8 +45,8 @@ namespace chaiscript { static const int version_major = 5; - static const int version_minor = 3; - static const int version_patch = 2; + static const int version_minor = 4; + static const int version_patch = 0; } #endif diff --git a/releasenotes.md b/releasenotes.md index a60227ec..5a2d8bfc 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,8 +1,16 @@ Notes: ======= -Current Version: 5.3.2 +Current Version: 5.4.0 ### Changes since 5.3.1 +* Decreased compile time and build size +* Make "reflection" module built in (losing some of the time / build size gains) +* Add new "class" syntax for ChaiScript defined methods and attributes see: [unittests/class.chai](unittests/class.chai) for examples +* Minor performance enhancements +* major to_string performance enhancements +* Provide API for retrieving registered type name #124 +* Added strong reference to container to range object #132 + ### Changes since 5.3.0 * Add automatic conversion of arithmetic return types, following the same From bb08cc3699635a8448f6eec74e732cf3a4eb4ebb Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 31 Aug 2014 19:54:43 -0600 Subject: [PATCH 18/18] Add documenation for "class" keyword --- include/chaiscript/chaiscript.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index 903eb382..d5413656 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -497,6 +497,21 @@ /// print(rect.area()) /// ~~~~~~~~~ /// +/// Since ChaiScript 5.4.0 it has been possible to use the "class" keyword to simplify this code. +/// +/// ~~~~~~~~~ +/// class Rectangle { +/// attr height +/// attr width +/// def Rectangle() { this.height = 10; this.width = 20 } +/// def area() { this.height * this.width } +/// } +/// +/// var rect = Rectangle() +/// rect.height = 30 +/// print(rect.area()) +/// ~~~~~~~~~ +/// /// @sa @ref keywordattr /// @sa @ref keyworddef