From 9a0a12d230fb6a8d9a4e2f037c43ba581a531836 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 20 Jul 2015 19:49:45 -0600 Subject: [PATCH 001/131] Bump version number to 5.7.2 --- CMakeLists.txt | 2 +- include/chaiscript/chaiscript_defines.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59c33a3..58841b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,7 @@ set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt" set(CPACK_PACKAGE_VERSION_MAJOR 5) set(CPACK_PACKAGE_VERSION_MINOR 7) -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 5b3bea5..c28e9a5 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -65,7 +65,7 @@ namespace chaiscript { static const int version_major = 5; static const int version_minor = 7; - static const int version_patch = 1; + static const int version_patch = 2; template inline std::shared_ptr make_shared(Arg && ... arg) From a2ff672b349800c18eb7540c88ce851e44bdf27f Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 22 Jul 2015 11:13:10 -0600 Subject: [PATCH 002/131] Memory error fixes * prevent recognizing . as a number * do all checked iterator operations for incrementing through input stream * Verify that all is as expected when building up a dot notation call --- .../chaiscript/language/chaiscript_eval.hpp | 3 +- .../chaiscript/language/chaiscript_parser.hpp | 106 ++++++++++-------- 2 files changed, 61 insertions(+), 48 deletions(-) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index c14a156..0478452 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -118,7 +118,7 @@ namespace chaiscript public: Int_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_bv) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, std::move(t_loc)), - m_value(std::move(t_bv)) { } + m_value(std::move(t_bv)) { assert(text != ""); } virtual ~Int_AST_Node() {} virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{ return m_value; @@ -629,6 +629,7 @@ namespace chaiscript virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + Boxed_Value retval = children[0]->eval(t_ss); std::vector params{retval}; diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index ddc484f..4ba2f54 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -60,6 +60,8 @@ namespace chaiscript std::vector> m_operator_matches; std::vector m_operators; + void increment_pos(std::string::const_iterator &itr) { if (itr != m_input_end) ++itr; } + public: ChaiScript_Parser() : m_line(-1), m_col(-1), @@ -167,17 +169,16 @@ namespace chaiscript } /// test a char in an m_alphabet - bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast(c)]; } + bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast(c)]; } /// Prints the parsed ast_nodes as a tree - /* - void debug_print(AST_NodePtr t, std::string prepend = "") { - std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << '\n'; - for (unsigned int j = 0; j < t->children.size(); ++j) { - debug_print(t->children[j], prepend + " "); - } - } - */ + void debug_print(AST_NodePtr t, std::string prepend = "") { + std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start().line << ", " << t->start().column << '\n'; + for (unsigned int j = 0; j < t->children.size(); ++j) { + debug_print(t->children[j], prepend + " "); + } + } + /// Shows the current stack of matched ast_nodes void show_match_stack() const { @@ -326,7 +327,7 @@ namespace chaiscript break; } else if (!Eol_()) { ++m_col; - ++m_input_pos; + increment_pos(m_input_pos); } } return true; @@ -340,7 +341,7 @@ namespace chaiscript break; } else { ++m_col; - ++m_input_pos; + increment_pos(m_input_pos); } } return true; @@ -365,13 +366,14 @@ namespace chaiscript if(*(m_input_pos) == '\r') { // discards lf - ++m_input_pos; + increment_pos(m_input_pos); } } else { ++m_col; } - ++m_input_pos; + + increment_pos(m_input_pos); retval = true; } @@ -388,15 +390,15 @@ namespace chaiscript bool read_exponent_and_suffix() { // Support a form of scientific notation: 1e-5, 35.5E+8, 0.01e19 if (has_more_input() && (std::tolower(*m_input_pos) == 'e')) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; if (has_more_input() && ((*m_input_pos == '-') || (*m_input_pos == '+'))) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } auto exponent_pos = m_input_pos; while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } if (m_input_pos == exponent_pos) { @@ -408,7 +410,7 @@ namespace chaiscript // Parse optional float suffix while (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_suffix_alphabet)) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } @@ -420,7 +422,7 @@ namespace chaiscript bool Float_() { if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) { while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } @@ -429,11 +431,11 @@ namespace chaiscript return read_exponent_and_suffix(); } else if (has_more_input() && (*m_input_pos == '.')) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet)) { while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } @@ -451,20 +453,20 @@ namespace chaiscript /// Reads a hex value from input, without skipping initial whitespace bool Hex_() { if (has_more_input() && (*m_input_pos == '0')) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::x_alphabet) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet)) { while (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet)) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } @@ -488,7 +490,7 @@ namespace chaiscript void IntSuffix_() { while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet)) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } } @@ -496,15 +498,15 @@ namespace chaiscript /// Reads a binary value from input, without skipping initial whitespace bool Binary_() { if (has_more_input() && (*m_input_pos == '0')) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::b_alphabet) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { while (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } return true; @@ -738,9 +740,11 @@ namespace chaiscript auto bv = buildInt(std::oct, match); m_match_stack.push_back(make_node(std::move(match), prev_line, prev_col, std::move(bv))); } - else { + else if (!match.empty()) { auto bv = buildInt(std::dec, match); m_match_stack.push_back(make_node(std::move(match), prev_line, prev_col, std::move(bv))); + } else { + return false; } return true; } @@ -755,14 +759,14 @@ namespace chaiscript bool Id_() { if (has_more_input() && char_in_alphabet(*m_input_pos, detail::id_alphabet)) { while (has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } return true; } else if (has_more_input() && (*m_input_pos == '`')) { ++m_col; - ++m_input_pos; + increment_pos(m_input_pos); const auto start = m_input_pos; while (has_more_input() && (*m_input_pos != '`')) { @@ -770,7 +774,7 @@ namespace chaiscript throw exception::eval_error("Carriage return in identifier literal", File_Position(m_line, m_col), *m_filename); } else { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } } @@ -783,7 +787,7 @@ namespace chaiscript } ++m_col; - ++m_input_pos; + increment_pos(m_input_pos); return true; } @@ -850,7 +854,7 @@ namespace chaiscript } else { ++m_col; - ++m_input_pos; + increment_pos(m_input_pos); } } } while (Symbol("#")); @@ -868,7 +872,7 @@ namespace chaiscript bool Quoted_String_() { if (has_more_input() && (*m_input_pos == '\"')) { char prev_char = *m_input_pos; - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; while (has_more_input() && ((*m_input_pos != '\"') || ((*m_input_pos == '\"') && (prev_char == '\\')))) { @@ -878,13 +882,13 @@ namespace chaiscript } else { prev_char = *m_input_pos; } - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } } if (has_more_input()) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } else { throw exception::eval_error("Unclosed quoted string", File_Position(m_line, m_col), *m_filename); @@ -1021,7 +1025,7 @@ namespace chaiscript if (has_more_input() && (*m_input_pos == '\'')) { retval = true; char prev_char = *m_input_pos; - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { @@ -1031,13 +1035,13 @@ namespace chaiscript } else { prev_char = *m_input_pos; } - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } } if (m_input_pos != m_input_end) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } else { throw exception::eval_error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename); @@ -1097,7 +1101,7 @@ namespace chaiscript /// Reads a char from input if it matches the parameter, without skipping initial whitespace bool Char_(const char c) { if (has_more_input() && (*m_input_pos == c)) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; return true; } else { @@ -1130,11 +1134,11 @@ namespace chaiscript if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { auto tmp = m_input_pos; - for (size_t i = 0; i < len; ++i) { + for (size_t i = 0; tmp != m_input_end && i < len; ++i) { if (*tmp != t_s[i]) { return false; } - ++tmp; + increment_pos(tmp); } m_input_pos = tmp; m_col += static_cast(len); @@ -1171,11 +1175,11 @@ namespace chaiscript if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { auto tmp = m_input_pos; - for (size_t i = 0; i < len; ++i) { + for (size_t i = 0; tmp != m_input_end && i < len; ++i) { if (*tmp != t_s[i]) { return false; } - ++tmp; + increment_pos(tmp); } m_input_pos = tmp; m_col += static_cast(len); @@ -1895,13 +1899,17 @@ 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_line, m_col), *m_filename); + if (m_match_stack.back()->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename); AST_NodePtr dot_access = m_match_stack.back()->children[0]; AST_NodePtr 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_line, m_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() != 3) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename); m_match_stack.push_back(std::move(dot_access)); } } @@ -1917,9 +1925,12 @@ namespace chaiscript else if (Symbol(".", true)) { has_more = true; if (!(Id())) { - throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename); } + if ( std::distance(m_match_stack.begin() + static_cast(prev_stack_top), m_match_stack.end()) != 3) { + throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename); + } build_match(prev_stack_top); } } @@ -2307,7 +2318,7 @@ namespace chaiscript if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { while ((m_input_pos != m_input_end) && (!Eol())) { - ++m_input_pos; + increment_pos(m_input_pos); } /// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) } @@ -2317,6 +2328,7 @@ namespace chaiscript throw exception::eval_error("Unparsed input", File_Position(m_line, m_col), t_fname); } else { build_match(0); + //debug_print(ast()); return true; } } else { From 8239206ec5e283e525d91a8f2fe72cb91e541a5e Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 22 Jul 2015 15:42:31 -0600 Subject: [PATCH 003/131] Update fuzzy_tests now with more parser fixes in --- unittests/fuzzy_tests-2015-07-16.tar.bz2 | Bin 85207 -> 84531 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/unittests/fuzzy_tests-2015-07-16.tar.bz2 b/unittests/fuzzy_tests-2015-07-16.tar.bz2 index d150daae59ddad453dd5b1b71777d1319a293a4c..6f29612d24bbb8abf8d33580b0cb274d6fb403a2 100644 GIT binary patch literal 84531 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 F+PIumkAVOH literal 85207 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


3O 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 Date: Thu, 23 Jul 2015 15:21:39 -0600 Subject: [PATCH 004/131] Parse in-string eval at regular parse time - don't delay and overcomplicate with an eval --- include/chaiscript/language/chaiscript_parser.hpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 4ba2f54..089ed7f 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -954,15 +954,14 @@ namespace chaiscript const auto ev_stack_top = m_match_stack.size(); - /// \todo can we evaluate this in place and save the runtime cost of evaluating with each execution of the node? - m_match_stack.push_back(make_node("eval", prev_line, prev_col)); + try { + ChaiScript_Parser parser; + parser.parse(eval_match, "instr eval"); + m_match_stack.push_back(parser.ast()); + } catch (const exception::eval_error &e) { + throw exception::eval_error(e.what(), File_Position(prev_line, prev_col), *m_filename); + } - const auto arg_stack_top = m_match_stack.size(); - - m_match_stack.push_back(make_node(eval_match, prev_line, prev_col)); - - build_match(arg_stack_top); - build_match(ev_stack_top); build_match(ev_stack_top); build_match(tostr_stack_top); build_match(prev_stack_top, "+"); From 3cae2aed1d936b3149430612030f3866e0cb5973 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 23 Jul 2015 15:34:45 -0600 Subject: [PATCH 005/131] Remove unused Inplace Eval ast node --- .../chaiscript/language/chaiscript_common.hpp | 4 +- .../chaiscript/language/chaiscript_eval.hpp | 67 ------------------- 2 files changed, 2 insertions(+), 69 deletions(-) diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 3a46c96..259946f 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -34,7 +34,7 @@ namespace chaiscript /// Types of AST nodes available to the parser and eval class AST_Node_Type { public: - enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl, + enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl, 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, @@ -47,7 +47,7 @@ namespace chaiscript /// Helper lookup to get the name of each node type const char *ast_node_type_to_string(int ast_node_type) { - const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl", + const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl", "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", diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 0478452..b3cc017 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -286,73 +286,6 @@ namespace chaiscript - /// Used in the context of in-string ${} evals, so that no new scope is created - struct Inplace_Fun_Call_AST_Node : public AST_Node { - public: - Inplace_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : - AST_Node(t_ast_node_text, AST_Node_Type::Inplace_Fun_Call, std::move(t_loc), std::move(t_children)) - { assert(children.size() == 2); } - - virtual ~Inplace_Fun_Call_AST_Node() {} - virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_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)); - } - - - Const_Proxy_Function fn; - try { - Boxed_Value bv = this->children[0]->eval(t_ss); - try { - fn = t_ss->boxed_cast(bv); - } catch (const exception::bad_boxed_cast &) { - throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function."); - } - return (*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 &){ - // 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, {fn}, false, *t_ss); - } - 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; - } - } - - virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE - { - std::ostringstream oss; - int count = 0; - for (const auto &child : this->children) { - oss << child->pretty_print(); - - if (count == 0) - { - oss << "("; - } - ++count; - } - - oss << ")"; - - return oss.str(); - } - - }; - struct Arg_AST_Node : public AST_Node { public: Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : From b3d2350f33ad9bb72151b67c395678add8bb2a19 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 24 Jul 2015 11:49:23 -0600 Subject: [PATCH 006/131] Add test for order of operations --- unittests/order_of_operations.chai | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 unittests/order_of_operations.chai diff --git a/unittests/order_of_operations.chai b/unittests/order_of_operations.chai new file mode 100644 index 0000000..c07ce79 --- /dev/null +++ b/unittests/order_of_operations.chai @@ -0,0 +1,7 @@ + + +var s = "" + +s += to_string(fun[s](){ s += "3"; 3}() % fun[s](){ s += "2"; 2}()); + +assert_equal(s, "321"); From 22339d10db533a02416cff6b1c994c122e9c64a1 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 24 Jul 2015 12:07:46 -0600 Subject: [PATCH 007/131] Make order of params eval well defined --- include/chaiscript/language/chaiscript_eval.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index b3cc017..0597385 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -73,9 +73,9 @@ namespace chaiscript virtual ~Binary_Operator_AST_Node() {} virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { - return do_oper(t_ss, m_oper, text, - this->children[0]->eval(t_ss), - this->children[1]->eval(t_ss)); + auto lhs = this->children[0]->eval(t_ss); + auto rhs = this->children[1]->eval(t_ss); + return do_oper(t_ss, m_oper, text, lhs, rhs); } virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE @@ -1182,9 +1182,10 @@ namespace chaiscript virtual ~Inline_Range_AST_Node() {} virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ try { + auto oper1 = children[0]->children[0]->children[0]->eval(t_ss); + auto oper2 = children[0]->children[0]->children[1]->eval(t_ss); return t_ss->call_function("generate_range", - children[0]->children[0]->children[0]->eval(t_ss), - children[0]->children[0]->children[1]->eval(t_ss)); + oper1, oper2); } catch (const exception::dispatch_error &e) { throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss); From b946af42cc0dbf932428823c390ed1471006aed3 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 24 Jul 2015 12:09:20 -0600 Subject: [PATCH 008/131] Update fuzzy_tests to take into acount parsing fixes --- unittests/fuzzy_tests-2015-07-16.tar.bz2 | Bin 84531 -> 85787 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/unittests/fuzzy_tests-2015-07-16.tar.bz2 b/unittests/fuzzy_tests-2015-07-16.tar.bz2 index 6f29612d24bbb8abf8d33580b0cb274d6fb403a2..9768b8e44cf430b648631185558eafa1c3cb0e86 100644 GIT binary patch literal 85787 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

liu&@TP{c7cs8itvBEn#x8XyqG*e06l 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 LML1B9&Hfv}kIA*K literal 84531 zcmV)fK&8JzT4*^jL0KkKSwsM~GXd6KfB*mg|NsC0|NsC0|NsC0|NsC0|NsC0|Ns8~ z|NsC0|Nr3yt=9lh60iUtee-tg-PwEK0002zy}$qf^cL?lY4ce8i6cEW%aMp1Fn?fXsT!^6gAM* zC_3Km1rK4|)bR6m+Nc+>8^)+M0z=-iowWjm4Yu2CJKoj9-KM$5s-EoYZC;AeXvF{; zF7@wqS9iO|b+lpupgQj7zyJUP=YlE*00006zyK}Z5C8xG0{Tz@e4SPeueZj9?xx_o ztSA6=&%6Kt0Cn2TtpHlLg8T1}z6IX+cHdo6fCh!NGqd6B_LcSb&!grCqX|PsMJD%n zqrRzu@1H4304N@Icq;eTIw}AIKp$KKb=(L#003_H+y}jZfT8t39qr*%6#{@exzQ+B zdt4X+=Z^poFRUofXG_(d<`k0WpaanL=3&(vU2yj5s^OlfkgnM2-JPbcg>(UTa+gB` zyH@PEnvjEc4wr4L^JlgIqMq!K=uvi{rtRA(lcJpmK$f?615Ubg(9lY9&@@rEyQC1I zr&f1YO$M5-+l`a~rmd(0ZPQIUI+3iM9PC?nYuNWa+5n(aS^+`O0BWn3qu$y)fCo<9 z&DpI3M^r_JW>lfbbkWh!6zIiQt3IQRb7%YJ*e4 z1xkoXsp&ING}<5xnGH14Lq?d50MIlVG}90RLn9z)0Kov$KmY?n5HKc<0g<2p4H{@^ zk%1V10zwf4B26_io|=fCs%NTtjq0ADdLYwBq|200Toopa1{>0000Q z000000004?XaI#GLIDCX1obD0p{YMq{YrjR|5ZOmk$@&s%6gkA>KjS54^LD#sM30k zq-gXLY6j8(Xf!-f0017KGyu`+XaH!?8Uxe-8UO-nl0q~f8btImO&CowX`-L1en5lO zHY922F(-r(nqp`H8K4s;CR5WxYMGIuVK9u+o6#qTHK6Jq=i$y;Qr{FbuK zMKCTn-86m#-C9m?exvvlM&gC(ty$B0{6Ixi@pIZ7`dJocb;UO6$m4CmaD}8|y^pOk zy>NJYocFt|e^1Rxq`-sX8_7NQ6IS#?*`C=7S7)}dW3hZF1Pd1-PGPFstfqA4jS*rR zgSBrO+O4|=5iiu!ape<O2_UJY39DTtXzl)gaN)&!?vgWnL z!=$Xm)pLBN4~)8uwHXOgo5Be*QU_<6LdiT+$(B$d4$I4zfgB8_W5B%#A6^=^CS|80 z;dkR_h!_u<1Q19_6pAT?%D~(QXJ%Y4$HW{Xx(5U|UaDnXq8JiD7zWbdXG#yqiX?$eH#QJY ziZF%978+@J5lFp8woU4W!UGm#tD$6DpJWHOw!X;Q&B-fOH@r21rq@$ z1R}p@ARnpc)R(1*{H!YVHq<|#kUczAJxnLH#7~;a7GX;7@}HT?=+118jDVGZ7Gog) zE9VFZ(^+lLZ9VQqI`3d@^AfU2%@Yd36EZo`0K7I!VWZ?;;clV<00N5%cy&Y1YUV5=bIbU%o^n@Kq9+)26@?k@F*piBX{iep1D|k>(WFt0L z5U@Z`bmns{dz_LLO@pr5n${p%HCm?FblXwd(dr?B55~g0)1>)~c^=K?zGu4lyS+W&XCC%?Yu(=Go7Hdo%ko+Xr>4NX z?1Cff>-DNhejnxkF8@#b#D9Zi{KWkmd)8w$nWE}S*0))r$(1VAq7Ao4*NKCG)?_v8 z2ql4eN`)M@up6a>q-?{4ON%keHFk+ldE+?7huq)6*q9@ z$1znqyTf7=RN=V@f(vfw(!o~kVa&u`44|W`M1d(gbS;*qTX>1Amkw46R8eku#AFbg z7Y!4cMckGn7%C|3VydVRmzS8EwH-XF!%)ycKQ=|$D(>MKRLoFeMuD-Jh(cp83(1#6 zQKbmVGW}-m(GIBFSeby)yo5KEc!*bU6?k2n#vpf>c;J4#R8Tp9h=MB(#;N00l`J=T z0whL+bxOj!N|mvas#OzM>&Bz6RW+1d<)-1xs+R7qQ8!kVqCuqVE~%AyLR7UeQ7a09 z95-U^3TWbCDA|JX`b(6PR++Ow7E`;UJaMrdh8`FcwB};VX5Lk|gtW2C$nY_CU0S@6 zytP${BCjC3C_1Z2k|WH^RVuQnWgxQ!O2K0?=3UZ~uo+n1V|j-aOu9!ERn#jAlyT)z zsyOaSxT!-_$Z_S14zA4%%pzfRUV{Y-7EHKR;35)o0V%;~U7X7C4OEySth<=$nI;(E zyJ@T_%&Nex(#WvKkcz@v_BnTiysWa_niVPFc4^9_a`9cKjw)B>1tS~GCb7v55iQcg zX4$1MsGESxD-3mZWX9X8j;Q4fp#{Tj;(1Z3PUQ@N&U`TuG>IgYR+`f#GQ8LkKJxT_ zD_%AmC+=L4fXlG^!;D4}$6{c@_WuFPE*M@E*(77JAjoDim^t9gW@342Jv9=SsfeKS z-iF!gVN+P8OS_aE>?)=6erGYp95KT)l#-X9Hy>G{_N!(5-A+-vaE)0mhUMrmJ3ujy zF13(KwoxUyQs`D3Qy4Ov%DfXVFEUkyam;WvVK+d=MX4y&2Tj5gOx@g4*@Y5wF6%O~ z;t~e%Rt%WtURuW<3e2%~n=dSf$~=H%)*=qLH8=f_NV~thtV})GSlRQ9`1-%DjQ5uBJa4ZUJm5 zW~#7R!+34HHI$xM#RQFIJZWYWoXnN#R?!8O5^h0sgRlw}XuKAE9Sl>@TDun}3x+Ia zfOOa?ChmI_MbSknyF!Ipq7#upm4fYgGR7>SAsEuhJw1`tSA&3qc?A(uF5pHrKw8Cx z<#NP@q!?CKD9|5xBg=VFU@tfUgK$ zgX)w8dfiCvTB?yR7J;X8*4r|S6Tt!}qk`PAO-ivsF=Fl+VtG|n-?AcRT*+4vHYw7w z@Uwo)Lj_ofBWi`>5m7+A4S1nUK}xB;v13Im$#`Kc;i;|6cxbvej%h*atTKebaUm_( zPXnWNU{BKJM=Y}HT?(wZSVYUJu#A@Fpzegis^}`OW<0~0epU^(5}3?_fsWYlW>lk2 z#$Ftaw+T2>PL@!jQ!-?CO94ixTPX+U117Bt$3R(LN{l#Y8APQNc~Bn^4U`K^)z(#R z8F!{fn!_#2H)g9<_=`wF{e2%-SLpXpx`kj?C5jn|EM-V6#2@~3OH`P|`xa35F*fme ze~Gd?+*bvA+y~k=?X%dxZu-)-cn~0>$S+wTdse_^W5Z}zHk{IXzzGvfY-Yk4AtaJI zCi$Ko+Jv&Cm${4{Uwd(}SSz3MyH)<2eCn$7>-vnl9XGJ%6(0+0o~&rK>{$z|k>%vq zOTcwG{2}v=Hx>UYl-a0rbgl;=LQM>4P-W29ES~|08wVigiGr)Lm2UUy1#P?)=+9IFs8iJPH1!ihaIUjgek8f~xo#1LW9` zRom5b;IG}}N~ev8zqydU*9(4J-z!V)y&V##HyaVxE`$-aWB~&RLJ)0DyzRklqkpcD z@IP%Fj(#0Fj$a!++*|0M-mq}!xX1Nw$^7gU5er&U#M!}L4FsJN^j81&HjD-_{?eAmj_~EMWuG&#cQ@yjia8H-F6ibbO=g>3iIJJ~HOm1dVpXTe*_%mo7z$cpMLBmFIdL^>1N$qmp_) ztxT%FH!$jJTY2v0vehv#we>}H7vk_hau1j8wiuoE47?5|>+n>m)Fc7ff))G#2?*pQ zAGG~o(XDGRpiMcnvo)s`Xtd&vn7&pfBvldZSrKS6RU<8lRayDW#19&H@MWnI{98W5 z{F~#(VAMmMI%XkewX70^iWQ*A3vIP=l>aS6Y2-~v)R3{TB$X5^^?AEkC!S2IM~iZq z5vwA~)qxR4MT1llqZ#aLMv%k#YxJAOLM_cqrzis@k;yG>SV3ONTT$lhfYI)^oyhC@e+%^+cK4Is46 zv|849X!s*>(oR#VxoXW(Ib#k@2oV6W^ssyfq*Zs0Y+5NG=Y+e8B&!>bGp{s60Ks2 z-Mwu$fz230T2R;~`60b4O-#j^vJGPD%jCcssRLj<4r-++0<<7O3ble`1mltYKz`2x zkFAN&Rw_iGEBSB}r!mo!@vdm)A_rSYIa@l^G@*(cX*KwMukbecA6M{p7x=%UsvB#f zyIo6KEM@jPHc+=vf}Ld6)VVr32xXl2F*)Z(5z zDVdnGrNNty8h9nwSCw%^_}1m1^c>^}Z3k<>1SBcp#5jSPX$_uK0_{`pqKaObfx%pG zsl6rNljdPdWlflid`w4q(y+0)a@UV8DQKWtl)J0)$&*Fb8`E^F;iqYAc>L%L6G*t zL(|TF`{;h}%fry-y%IEt9aRGDK+4Q*<*g`rhE)&s@NQfvGWYNd$RLJcZul{Z(G`n^ zaYi6_5r-EpLP`g_yTmo@Gk62>TF@TB!Bpy4G(r17A{X3&`aLbDLbow%DU7aNTwEM` zxs}QwKz0a0fyPi$gXWVWpW_7sXgE59lEb9}OwVchz%(UnG}mjK#qj~=K!t(2A}{iP%{F7pc0x90)izdLE4~pCG3MrxX zAQU&k2w*F?9ZDGkLeM$^4Pc;qgP>0v#?YoAp$9~o)kBH`dF5Xg$68E^;6ylCQSOCW z1ni7}C=!<;HgP2_2}prMLqN3CR0RM%KmnxW#wL{9fuumw1|S40>`K)Pnm5H6iW*oA zIy2HKEG#M=D-%Jm8C$W3PHe*5Y;t#F(GM+ zHXN`PqCRm1tMAG88dfHNrj_I6 zcyiM7jQXbQ&|~pg)gg-nQnqC$cUZ2Z4y&>oSmf#`S2d1GxdBMJgg6j;)12YOtSlsS zVxT)WJg~${0@8&7QlY@0LaW}05PG zPb3dyK)@V=kf5Y$l&+W^z9U};!N(+|L;oquMNXUn3{?Ls7=Pn zF%X4eh~nvjVi3f|?REk(%8Uyls*DJ|#1cGck_ZQ<518V^C?>{U&}X*v-R5#>aJfcGxR-8Wx8*lt#)bG z*3UhW)og5K2M6G|4*#@vw-v8G{h#InC>@4$X&*#fv&uLIVRa{Y|<;Dl!nv zkx0Ct?1d-{kO>4XW-9dxoj~J)bZ>93p~clWFC*^Y{D{rf@ z@556KB`T=J5>rAN@XRL3z!W(`AK1+zFSYrRuX{U${4B5y?8_<2^)wo=EFS)p3271p0y8aQtuXps>8v;z7xr79FsqGIxz z8fGeA9|>&iekN9_n|gG_uSbV>)_8sv7^7{MikWUkzJt|>`tRmMbo$ZH=kGklyXErn>^RwQGzm|s zeRpZ6%h~HF0rIq*eZS!PksM{=;371v#aMcJ9F-THeeVvrMe9U+6;JAYexI4_#Crz7 zJwWU5y3j&%zrf9WGtSH`aF2Tp1W}+X(T-m2zfX6{;oIYg*|i)#cZqkRI;Unaom!Ow z2fd&`gA+Emj0j1=2H7PTk_as6Rebxr<;vUPO87jH8h0V>JVB}+O*D>PmycZJI~Z{9 z!m4>{cYoK5N!&ZJGa_3?ZEph-O{NgO)w@+QrkeMD>e?FeTjuFG|Dq7ce@#rZtd2l@OO;66fY@5 zfa4=BRY{5&7Fl%e*EP_t6%WRVjkLF?mv5`HituzmByT*9p~tI4IzkjJ8(Pk~!3UI6ckLI4SCOT~0r)HqVgH_9};9kCro%xue3&m$RnR#U=* zqzz?8_I)V%6&a7bJBoQCI8;8)-ARbXC+A{y=a{BvtySDOo+evV9TDRhzdvWbWZ9;J zS+g3TwjpZN*b7QVWY}uAE(=@=x?`Ac(~(9lBzqQIO6j#w(^j>3RqR32dpWS{;-j5L zwBjbUXyJ6xcoaOS^3=oC&HQyv#V+f!ZtlT|V;5Sz_A95Lw?$lzwBtJ#nubceGZbdL zU9U?%jP6j~ChOLr)sxlD{dk=YqsHfTX8vjAb;q~qs+SCz(9req7Abjz=%&PC%B9%f z;r$(P?(aY2dR=FqzSp}KV!Ky$F6BdZ8z|oQKDKL><->=O5$WDt*R$;WXk||QmGEqV z@O)RUP~q(G-5F8aes5y1!h8C&4e?=3Zg))s_*0OkIB2#9624gM~2WZN-o# z$9rhUWjZK!6xj{(vQL}N_1`(^5}J^;x2LzY*Tb6Q>vZd?l6WPD^gknQj`V%Ll>ID< z`q>A~HomP;0xPhn^ zf6&K|uY=f*Ts_YjJs6Lb7sSbXiXIgXrzr60!*verp7zV|em9H0@#LwMce^myFD_Wd zU_WhR!()^@KO<@#vbzSI(y>+#N2R|lNLyqZ#4nen#cf)qmaA5+C!42w+s2{HK0l9_ zC!)f+G6j3tK+6KJ4^LK9Z8v7+z_l`9$XcS_+HGucn5zaZ-h~de4NHfY^ZcW&Q{!T$ zySv@x4t3$9x7Bt0_k+g6Sx~uBFQUq-c#N5omg83}jxm2DZZPW-Z}Aka-ZL4InO4Xh zbTL;=4J}P9)jGOW5r40sg(cESD8VHkM|u4ARw|%e)T|1e)DQ^)dG8V)#wzjjJb5ol zyR+CFdix{7@ax3+$~*BFM#>iewPabZT` z2-RdIW8v4E)9sPbM*Zgj81FI;Aq*41b$GmLA0p%GhftT9Lg!yGzjvCRoizEN3M!hS zhJa}zC}~Ne2#O?+l2$7CS1uSPzR46DQd8R=1-O2PD&nH4JczIJVgv4(4mhX zV~U5sq2fyUc1axwIj96jKJJPL9w`#vsO#*0WPF<@%th8&lZ8X3FsW`-WJWl6MoMHE zDU4Lg$Qdk*(%7SeV{N1H)INK>Lt(b2opj7BCY+<3nEPB>-^%ZGcD>vudS|_cVl|Ml z;Gx1-4U2ytM#>)(PX=&l>FdPXeZRA(LFMu3ZE$^0V56YqhiC4O0HR?Dy`gjE(LHv8{1b;i{*XD0BIqpQz%vaKYysHFBzRQ1jI`APfZ< zR9^y0A{C*bC=Zk8?dYMZZX^1ARF|Y)Li1K(;_jyYDi|j_D=@3PrKwizd(O0u^J(LO z!Vu^Y!{|lK`Tr{UeeS5ABU%&9%|oPY_?BI=ufD;_9jW!aN*@2Cf3nF8&ozHZLMd$<}Ok&lSDaIp*_M@3^JA6mToaj zkqKV1MU(~907OkI23d`|>j#sU%XfFXa>)oWSA(}38Fw|sGbE_p^)tyd$-v-eddW=z3NlVuLh|2$H6x{Y^dPcOyExNygdod&!ey7BuGmoP0$<>f|XCS?VErdg3a z-aLVjIddd)cG{Nqsis- zsst#>Oh^}O5qiJd?o>_C!krjh-B(bJ7euTVwSzLXdVICm!*RsbetVC2rsTUNp9~NjtJllW6+KmYWNm zs!09)C?sbtb1KHx`9-Mhv{y#LAI4uqW7 z&vUEdWuH=yKK`0`Jo+mwT7zZnX357W)=4x*Tt9ZV{XEgOQJVv48Y#L)HL5VfDmVkf z7PMq$C(~#&Sen!~*vyw0W~^>lxs>enWN)Y5HaYfR)q>dGAF3_0D zU$g#XND2T)5Aa&HF+(6_-(_5E{a?t}JUHV~AE6QbrbqIm(=3kXp zu^2~$enxZ!bx=eq4kMu7>KzWw55*(rXxqK#P=FOSQ{-p~0VrA24w_ggF$g`e7}3N) zgOWC1)Xt*?)QxF2 zvef?mk1CA4D6BEC2fKdAPQdGL9;)ZNok_4nLIz$*F(i!~^u?X^&UK|^vjs|%=plt{ zZ3T%&pv0Pmdbv0i#b3Gdd2g46(NBX%MJm2|Fnj&wsPuC%g7W2)X^)zd+0pEY#*MzS zulnl0Z}0WJVu3KB`=49YqOGufDHlgmQe$iIBxwvh;;QSYT(dWr|${YT;gS!1e{59>* z_;6Ct`s4;ka6ugKEn$taJaezIFH#OLb-~dWhP#CO>z{=0gTI8B$u6U)-9qbhu~^F< z7&$=sR!0DqWw!+6BcKiEU3?m#+r_PL_de$*UEtjAs!o3e;p|lEd$@Jt?JZVb3~d21?W#1|Yy%2*@=CW);@N(tV~0 zwQAjL+-|JUy*&B5ZZxJ0G9;5!2MYm0A%G-+m>CwsD>N%ST5S_oVnNPQ5xWr3Xhzt? z_tE9doVy}JDoG!eV7rFdiR@uANC~1qG`H>r6Ly&0MJO0*47ui`69bLohYIF@#$$_S z1HqQovO|^QB70p)N*dbnW!S|SMo%VQvlPFJ`lhKLz0~ynDtSoB%596KLP1k-s9TMb z`TETSpxDourfVWkU}Cs{Xvi5YL~4N4ADqiF+1g^-(n|u3<5q~;0|=Zl5vVYOSsv_y zU?Opg1ZXD=pAKXb;o(*(zfmrk^e@@lE43Js2dlRyB!=6wt(YVI_rZwT;hH2!`u98G z;)G^RFui61tdmqQkz(TzLm__k1W*u_$Y2a7MVjH+(F;lljd{tx-8|+zNDd511{)s7 z3-r9QSEz7+qt@35-vUZ~fh(ZeO^xnh>kqWiqeY8nFO|2co@|GAt@g>m?mZOtl*hHn z*`0D1OH!IqkTFgn!VvA_YT0gRrwY<#Lt+_F#lFEB5%}~i6|oIL^EEbG!xI;{*0`+| zlLkxR%3DFQmrH8b7N=f)P3fV<2U1SHU3bZ~11YmmG2pIA*gCMY5#keigX_rA8DZ7W zl+!err$KR`J^8?_(QV3}b!w%`g5X3M>;}d=(y!{Y$VdSu00HjtIfk4a@_VQMt z(UD~|L!Si=*4U;A&UM}oJtqT)%sHrSr7~5tha!WThEk@0z!!o-)Q5kA0cv#Car%2h zf}KIFXyFynHk>BL+ikW*Sc=RRU=}3|ND2~QsR{=uDS;@iP49TMw7tQ@hcB|a60{S7 zMnzdeD&vzenM`ENDQZSkIPlW!mq;Bv6M|zide-q?3M-=tM+Ws{2qHJYHFns(xbsQ-P=l5#oO0nXI$azvT4!mem z%h8*tr$$tw)*S1G!-cvU@^XJ$Ywoc2~OCh+oo!h38nbYBK_UsR*| z`^*Q;=kn~$z`_9=uuF6^GFudc%u@zPhB|}4y|MV`m2+H$B=>yBuWAUf?Yc+ZW+{HR zx~a_b%w=hn?EwbqejQb7Qlp?7NK2raYMNt}Ud(84D&CB4o}f>#D8Aghu?U)~r@2yz z*U?h{(bYZgUxky`$Kn83jN_&k*9^`Ejr9XWGL^+@=t~z-h&M4K=3uOWrlrOiNZ=;V z(5kR{1nKrOHg@mJvX~>G4iM6^FAN%wsE&-gwtjoF7>)wHAg+%N#C>qLb`-bno0D!2 z#P7_DSUC|;)5!qw4_}y2JczA`)AXtx&(0drV*Runoyomrh#m3S=dnA$9pG|ipkR*g{$0CwJ zHzZ?Tx}o`;op~cleNDn}^E)Xu2^WnXo|5{V8ug_Jr z&{R7K4(_d2IOKKt&mrRUAn>O}c)kzD&=#OxOna~|UrqftKF%k1d(35JmSJa( z&o`Ub^7=u4G8GRGTkLCt0YIy#r#ZZRFF4r`V=D29te5PH+^>HrbW_wF386X&>8jA4 z5jR(wok06{B0xxGNeqBBhU$vGphS=v_lP+W*e(E8FTMDlk5c3$z~~=f zyb&uE8xJ~cj;(0zar9MenKPI=Cr~<|+0j+Hx5Z;Eb~6Ry#CGca#CB}}JpF)ohc?@i z96}&t_Rx7XWOrj%-{W(WdX=R{h|4jk=F0d``NE4|i)i<1ROsN?bF=1(&!wywkPJc; z2uAD|vyXRlJ^)-7FE(`pz&r5kTVLD9d|*GS@-uSRd2A09ecd8V$r-q8U_Ej1+{ zKTe)}_|K@%%Z2U_C?I5h{=Ixk)aN0R91K++y35Jr;m^|cHsL0#V$j(pA(575BCj-S zy)i?_z{~C3X?jlvbJ@$Is?)k;+XEI(uXyLQk4pylb*5D~To>p5hu!ltjs+DR(5mqD;BuIe_2%W(oZ)>7;tpAvI5;SL+VvDXDcfB8b-@B#CxJNY(p&V&kq&AS<2F(!lsaa6e4dOaiE2ou1 ziVcW$Q9H0JnwL#Oi4HOyMN_0lOjeXQ5b2#LEe1t$7#k-ZIdxvaV1_1$3IU!bhY{a zJ^dOH7=6)6A|ceOe>RA$f*Ou0q$0Sz~oOn znP(@hE=vxBu2rRBfxu@6)6JFahv+-TXNS9Hjk5UM6Y;z718CfP8Rqo+n&Z>*_qXJA zx<02?x82nBTFy!3jK%|#z_H;wb?NYmuKp=EFwDK4a<=`P_8Cr~l0}#t2tdHdNKC>; zd%2At9a)n5>EhWV*~b@-SF7CXpM`{PiLmzAv0LO$n*lDY1c{&&cO%dx%wZ%fwnxfj zllCzqdk@pfgYWWG`B*BBjJ@1aLi*L zTtWV!#;Y2e=U5S}VaM4*N8vC4`-voY2*$tHyNT)(n6a2jg@fMiG`T+6F_n*}@zsmOa z&6UPd`%H?v`4Hlvx{Q>)T$1+IIWJ4roMWsEs#(HDsn}yO=;f?I(NN=CN!(>cl!T>1 zN<|)%qUizczPH*v(Cbc*%jnMgw54w%ZzrmMj;B@^Q}TN$``jht>$*I7 zyY3c|I&h4{uDpjM-zENTM+~lq4(8e4fz#%r$3f$#jyxgNiDprlOE6NYUdT^bAzeq+ z$P|l^1CWE@DX5@`ssL(~Qx|FLBB>$Mj;zB~PvLUST>M5yWWROlz70ZcF#l)kr;NGg8 zhF27uwotq37w)&F(O~GJ_cajN1oL?PZaKd#Q;x}$hcyh4^mSA=@WgXOcw#ctM|5yb zN^SWcV!9tey|SP|0%bBOXP>Q1RmXE}P`bEhbc=-@ARlS;D!>G0)VA0=Fl z0dTZKB&?9^5tTzw$6nP8sCa}tqB$VjX|zYJxHT7UO3X8-a_ErHzvgkOK0Ln~gQ7=G zWa@UPYLLYY>YM6^HUlvw=`71Z>+ix;O`?oiz5=ZJWz z%AMqCF~<rb+EUk8(#l}hARK~lS2+Q~a!+a=w?b8%^pm5GIroeJAMShiOa zr&fDL>)bnglbg%1&tD*WELQ~R;eCXzX$jW~vioy{QZAcQ7gq|H997x7mA0np zy33`~?)X;)&mlZTr=8AgLG**2oyEN1@Z5H{v~fLdg@A}8lEras;4Q0QA86x>b>FLo zpHb+91sP&s!PYlmBW%QLs67yo;vzcz1{I|Ua9k!hc^t0KWsMbmtS+pmF3^qR&o-tn zE=!i|Il{t@@2h2LW9o_Z%0rqY+u|JO*$f4qx@vRlci9JZ zPzeH^x>-mQf7b_^X};ZmE&Y zx)Y@e#doY-jltT3q+e|I(=#^r<%Hm?_(I&a{(Ls;eoRm;Llx~(KPWE}Et*?6-kgej z`19rA@0GtZ138G1wMcD-V)H*DB0;B`vDX-Fwnncvtycxsmk;+qU$Zne+8D&fgqkmi zQQefO65=7%Sw)RBo>`=Fb4ELKm^hjYmIBPka!HFYi;ZAtASgCVnsX*JVj8GTW;j4a z5rjAr(Uc(~;2OkqG8#e%z?WKFNHtL5tjNt_qjp=&CuM|0WdKkRL0M}P5H(6NpbC@@r@)j(GuNMw~5YR3ZB z^|IPyI5RHYX0tE`>VjKW9h3~Tnt?2`?H5w0fl8HztVn99H8F%5T4K=Z(E*TAQ3V(d zjB``1CQkDmlIHV7njK;}8p3cbj*~$V4)>&qE$!a*CfJAqx3t!VlUO*ljbphqnSqpP zw%Mo~>{_hY^EI5Yo!MD+l?(&FibX?cPhbZpGDZ>~iZCZ&=H_%5BBYVZ35 zce$C{y7sAV>Pm)9Q>$)CF(|JkXW@dIR!I_rYFvFR( zn@6veo8HUpyW6|0she9#T~@i3-JP~Rv6yo1vi@|xhdxcuopIy%MP$sgD!B&!W-INd zbf$`vGdEslT@$Fwmlti;$y}BxmbX=9c6E-s>$TC=>-k&rdp;*m=1Ftm!ZRgmRsb_V z%)jd2%Bhvh<*K{*oYC>a^Cs1N?(U3ou}bRhADX^Owy-b60?&C}iPUAft{%3Ha6 z+}>T?+sW0XW%9`Cvjt_!-G@~buVBmF4)o&W3~zFt;v3AM^79RM4%fVmB>R<-RFUfC zs?}W3mr2ZbD|^-NceJ!7&@{klplECxLuH9*DxwAzrUDSEM247(NhS#hmI#WXl1QMW ziXvJFp@|8JA_-!OqH0K)h>A!e0z#r0sUjpIW-5wGhA4t5mYIqQWSEGmsG6XH3SwZW ziI{?FkZ7hxnnsB!q^c5$LRuOMN(n-gD42qpNQ$BohN&u&h=L*_sGul{f(QVJ2$?8m z5{gQKsv?OY1`vWuQVA#^rGjc`lv!z_ib#Q`0vTB#m;!*N2nHphB`69in1YFfWgwtp z5}Ki=D2S%1B5GP9Ws-tneZK#EuWp0%55|2fFO$Iq;asD~pIVPKccvQ+I=^jKx~jgb zz1kE4?>}_EDXp$xMQ6jkeC03Lh6tx5fVlTelQL!iW<=XrX4T#9!*zF}{&kS%=)sVJ z^nTNh^L(BE$p24&%Kld!s*hp#C3Ok(a+6!J6=%fjlKTuxbiA!n(N_!@Vd&2DDP%lr zH~gGqM)4ggU)y4+WCXIg4g{l6Mv+_X5P~rvE4=~- z=tks^V*Q>`mDj#~teULp@wv|j8aAj@@=$^y0f!DZDtKXh+!*J;78ZGod|7sJzC8e7hw6i>a=lE7QE&N{!d%TOE6Eo#W!u373r=jls z4KF_CWiR&rukYV|+S~g+`fq>fPX1nt8~$*}z2jtcnEL7%{P*Rd#H*!?`Fow*lP@My z%(nc~x@^yxsWSg36B6oL9&h;KcAj7FU;18V+NV+Zt5Io|*xeWL@IQLy`#auvQ~v$e_S^q=$Ik3}X?<49 zvRmR$zk>I3CA}ToU%`35-(PWQbeZ*gdN-Sj`uBaSu9~l_gK?nijx1E|BIo4L)_$G$ z*xBKH%}gwMyiTU#*SzicT@8tURmScO?a5z>LND3b^jR_EUf|`>=Xe#X(WkzfeaiTl z8=utFB<#E==-j_YE{0#&r~I$~U(KPmzv^N(HrNz&rLWI^F8hz6-1c@L_xC-%HigB0 z!+lqw+-Un6-zt^oBLkOv{Wd>m)cV{lNqeTggSh$mn4g8(T~(&~pUTSQ_4s%m9Gx9) z#;*>p>mzre-&p!yZ*^z-czBlWu(scJl`HCQv$frIr&}EitbTXs@ApMJGj;j1s8#%4 zw#!!DWu^UF_&Ob|p99>~i^2HZY#S2N`G0H4(dYM@kGa~-ySBZ%^g4)Vc0aS9$k#;| z2F5?*g!{Pg?B(iuoDV0H{!?SycGV|0d#vnm`O^#Eohh{5v>yX;(M5arIMcnCu;F9m zYwFFdrEA_>L|OlJLbl%TH|aoNMeOF_{;w+vwA-s{+kIL- z%R9A?tiFT3=(~M9J*DLS4gW>=|5l#5lv~TkV$rqrql@x4n*OT~#o_Aha;475rSLTI zooR7|-p3BBXF=CrUjA;A4jau`n3}L=+I7A4XnrGf`;M!p`d*Kt=5lG>_IVx8yY7Ae z@A=kwIX|=g`~42C|A*{8#J{h|@$b3+AEVb?@UpPz_p>%tAHwMTh zuH%`S*F^3&xqZ!UMjy-Tt#oN{wp1V4`Ic(tTybmSKVv(_#HVwz%KOz~7^osTXrIXARc7E}y;aB(24#{&`wc`M(X` zww6~t2MTXl=N&eG`0w3wbtlm5c@(-id(Q#)dd`OD2b;9B{26?&2>S8jco?}H9!=%- z-uqWOJL21Dx2KPzk>CF&H*d(h&*5{{X}kEM_xlK@+IO3r&U7$h8qC>RbWqzn%4|Ls z56F^V>+$!INhi0+==3uC?@Fgly2Rt%ZM_YL9xnHH2kOGQ{$0LCgK($cT|dl?{k>gF zEv38G=;ZQy?(Wmyc%JhQ@X-2=HkH-QukvU37+Wq~NqIARX}rsNGDdBFnIw$V0sI0$^gm~=EBOvwR$?wyTYscA3AvQCs@%NX z`+i|w-j-NB0-W1LZ?9*#n;n$8G-jgRCsszneb!a@-#boucF=rpv#LwIi7(<=hfN>i z_jBR=SKjOsu%-iR`8`*cep`muVoMcUrU_Ms*T>@j4S1p5UOSJ@@~M(?b|e1QOo7!= z{$?t(mLk8oGPZUHL(=`n_9<6V;^yT2Ms>;8jPY$%>0_7jWzs?V|JM_qR4+6Rxzzs? zC)?!p@yXPUC+T4;nJ&zh+i90a9yA=Pf7!}thWdj8rxjU}S&QprTvRwv zXx~C~MmL4NbU2SWhob#+PVu9|Tx%wDbFPghiQBwasg*{Gj=T$WTq>W~%I?LDztWCw zg-5IC1JGeFSIj&9R(I=~t_o~P(vr3E1pU-fM3fOL!tlJG_w(NQNOlkj*zDOG=ZJCiRD12l!3V72Hg+u^-%4&W@ z03=2SqCMy@Pq{#vfmN9^1bjohI#RI@HXB>oDX&%EDX~Sm0AvVYVE`X{{WY_HuiwOL zw<617SNYbD1E*W29!AaD74ARB-9u~zd>K(%q)4d!N6|lUo9fOu!#%$b0OS1u;40*? zA_N~JcrOmdWEpy)7y!^4s)t}?t3Y;2x-G+Df}u*FSTE3xA^2i}A=Nxe0kNc99S5g> znR{Gi#u$fOjbslv&!LCRx4ANz&mXm}$iN;l zwR}uLpN=@J;iB-2zYaNKHn{3~y%co}OGbqoY z0u4$xbb_Lx@;*|{D8<0pid>ZL1X8sSA`ewl4mj%Rkk!)=My0nw-71ZFGFyJKEjpo8 zqX9xFF!HNaIg>PPL_(z%D(M0eNgEPC0)RyASVR*>OjM0nC0X<&u?jw3B!W#JLg@!h zfUek~1rcOk8oFm2Xsj~jnxfK*-Z+=}+v=rHj%u^3jAKg~O>+er7M2U#s;2JyZtFH}%-r1Uz2}nB$L?|R zKzK-B)q-CUAo+PmFWBc3p5#-O6BUxWurytF#L|9z%y5Ak5LrU0+Is|Eu>;bELfHxu$Cqis?{n$+L4-d zP;nJdMncLo$*TznRQebk+m;i+QfUnajNvfGUh0x00s{*iaWs@d8_(@Z)rjH)S0peRompeKB83i)RDZ_28vesQnJ&XhYm+^m>wGRGD zyorTR9#iTPs$n65RZJttfN#nj#6e|H)&W_8W>BWR9)L{~B1-`hAqMaaW=Ljc2}lTK zf|wQ{V1a5Pa&efHf^S5atP(`)92kiRBqbq$h-rX`hGLwW!U{I zLP?mIWR?gBfSLsrQX+<;2?_{?WFVG`S_Xisp`?hI>786)YziV|rsE7DvJ6OMBw{3@ zN?3@bqKF`aFfd3Ufg)rGq9lR~7{G!O2$&?Gh(O02nu&r6CUS5SFfbNoNFXLEXCnzz zRU#=!nkFI$A|{CdfGYOc8pkfSj0)ZfkS`H9d%BUhFsHz$*Spj5Z z#1j-SQ)j714NDMAMza<>C3ItFOU#3jHa`3z?DsvEYC zu9Gz{9dUPLYhd=si0SEwj-_@=A-EH^O~8$9nxVEv?s}qag+y9$ZaHQ)$C&tTft=p* z&}Hv(u1g|##E_ChqZk>Hb7LV)Vw7VMA(56LB#~kOCPpHlmH=|kvBZ3c= zW^ooy2Ii7RA+X3Efi46edeBju-&29|?^gT6ga}6lK_t=!B$&h{*V?7wtZSrirx!g% zLypYQ)jO>>MsHQ4RZqMtFI-73>KuFl0z!v`1L`0(%@TyKZUY!~1rb9+FlbPrF1o21 z2}^AYMmQv?p|NbOWfs(iW@{w6eP06FV46uV7)C&O5sg*D3Q!XF1iIf{Ym2Jmo9eZN zF@;^^lu@HVIMFy_*^1j6;NQzdKCU6cL535n0R+T; z&M`}@&wS@%9Rz+~=IHozwK@LAY7^{d;#fkq$b8%<+GhOTJoIz%NcbW>woSZ?CC+;p{z?3IdW;M`nMUk27aEpoAIhH4sG#JN2D!^pMixjdTS5mU*sFn%>%vYI8qw*!-IhRFd3Mtf(rh_9K45(U3JC-dP zB801eL@b7VcLO4quD|aUQ$^is8R}}}q+X9<5nGsd$&Ji*g7UD93Wz2|rybFhS{+Mj zqkv3=s7uPslQJ@k;l%h}oj`%}iC9Q;pZDt2xROLCupxlh0_ZjTJ3CjBrrepeo)*rs zPO&qy<2MP^!7Nnwe%DK4?dDdLILt&gu!_SW`WR2Q^7?*PN4}AjBcdbOQ%14{kotO} z+hj(nsWpy=Zd|7J@J>ReA`Uc&3>(CKp8mgU+q<~qk1uBYx(6nsTZ~p5VT2C0VM%HG zR#~xTrO1fFg2!S-xrYXZvRGBpjo#Za1wC@k5HvIyUBS8+YcDVgHJtDD{||V3*WbPF za{4>ye=aB8vnq=sI|nc5s;#`E1w}-{Sl8P3D{~plUmf&*dFi!B2DP!ojcC?`3r}D3jzNuC-!+(d5KB(nJI4- z-6yufZ;3oe-CN?Cd#>O}REn%yAg%uuV6PMbRjm^~7qG%}D5io7ue9J8#J}qSo*mf0^VGpk zDMNEj%sjCp5XNq|6#f==A zwmzTu8Y^p;OO(!fMvGV`(@aSvneA%OBGHCEj0^-|aE60GOBN4?4wxc$%YcE>X<~^b z5PE`DH-5UQ95J?+{%Ne9o= z5%cGs?DF`xpuFXIi0cz)kR5E z0O@Re>0&7!K?x*^jL@xuH)6W7f{>8>F&(6R2?o868SCfs&Z6d|8K#kioG=Os zO$V?eglH`s<2yK9Q{T4|g?8xnN4DPqL6 zN}V3%#5H$Hi$Z`wa3C#%8^9wNS%8@E#8Ql1kc-@3OzV)(OVQbou5_UsMnSeuZ~=Vm zNgmc881>wu*?e^;Rq*dM74z(J#-MpITR}_yH(=AeZ6%hAByL2vUGV6hWpSr5kWclqC!bQX?+POyH%%4{QS zBS+5t4tvq>u6MsIv(8JgF0#A*_Kj&xHPNzcx>__sqN+i+eiq#aOb!W$jP=BRPnSoo zV2v%M%$@;V_whab{pnu?+?spcZ!WK;HEjeQworIP+k|o zg0WZ~y(D!<&D&5iiVa};ADvk1d@5bRgJ3bB$ch4p4Fh7z!zQ(-MvdMabn1Qt9r`1& zV)GsblQNBGJcsRel212suMJnd%)VrUf;J4urhM5@iiktXfnL3F!!uSMLY|onm)Jf> zC)3T#z|;yUZPBpjQ+YX@aEHyruntDr5zqoZ4}A04)8~m!>}Pv5gfeNUnQk_cX?c`U zO$?PmM1sbvEIRT+fyYhdSxVhP6(2JhiIht55rkq%C?R2=72#}DSAtYdl)She7$7JT zEHb}u8V!acRbJggPMaf08c8<2M2T-u^1XO#Xty*Y!L;ewIz-D#7X+N)#SS#KngYAr^u5nFDG!rBHWd%{EkJyb z1oQ`)Mf84byaA;aPbZhi_b$BE;=(QiMmh75Bz^TQYT5FB+k9usiN;e|uBXnDLP-$& z_5%vM_wjEH{yEZQ`*3$r_n>u_5( z*@$Cp1SgEiY1f6mH>m6}=5lxv@kMMctFrANp%lb4&{bRAnISp0p#p{jlwy>OlFI~yL%A_xNRmK=m4-$cf|$rWcpcq2XgVpbUEPh{7dKE& z_9biv(jyTZY4uWt7}!YyHq&V!o;=wWG#1l!g_Ct_E%eVKU57=8pj}~u20@81)pLS` zccEuG#0arnP=rz{ibxpH3uQzq0sSb`( zO$nwACDB+J!NL?S_Ts6zPW|oR+6@5GE3I162pMTKVybAv5t(UTMz(1c+)By?s;d*} zcH`q{d@;(Vn#{PHpePH8l9%uQzvG$Fr(oK}Ts(RX|Zz7hz@CJF2HeRNGW1 ziX*}^DGpq#6Pl+IQ4(w_LoUwB?ux>0ywWG0dh>W)%P*6(kTBFxXpKn{k_kt)Mv@qH z#Xb!&_0Kj*e9rg;9bpV+f;zEH1oiR^;3js4IVZxZp5h(qhnAv(fuNw~rm^z}v|^{+ zMD&FD3sH(4NgZeC@OUWULBpm`G$LLIf zi!iz2L_YzzsNOLc2Q-1hS&~ zs|7Jn76<&R zBlD=1BcB%O`HMIhZ{<@Ro0np;`(55DuwGuZ zYgz58n|rtNx^?WmsP3gYrJGaC{cqYwfcm}wH{ur_`5|ZOMkk?!qDU-LDU?cdDLI@B z=Ro9qgY%;1No!=#Xp@)|*g_v2zciSQ%Ka%;uN=5S_JISJ$5 z-&?#Fxkt$Qdoc0ZsGB^#dGY5jFYo?ty93=)5dvi-d!g}x-Nb;&f}|r?6eu7}y9*1{ z2rG-om%nXD$4;0CcX#)>Wp!Br!N`*v2njNkBiy;{ZJKs5?WG3Pakf7ht!v5WvK%d| z6{+Z;ja0l7u)h)JDkugUH>umVL_t9t$46exEK@>1CvY~}uCTt;@`YN8Z&Z+GCY9eP>{;vzQF zD0_T#bvWJOD)-r}s5@TFOw6M(#Ue^vLNJqcwRS|0Fo;&g3>bIDaJ(bMGsC9KDqTcO z-;;QRY~F}Ad2%dw-M)3K&10^`v~)DQg_Nmk$w{GL#BP*AEmm1z5v>%W(+yPx1sbul zPY*ZFchz56*LiuRmCr$gYfz($WduxE)-+Lvn2>d@H=OB@8HYV?v`rd1eML%*M9Bf_oPVsuipi-3n$Oa{Gp7vYrF(!I!_R=-)4copTg8);fG%D>i6u(aBp{ z;#Ty=+S$lwJPg*j&=k^5i=Y+rd)`}tOQuk1CY@QPotA^3(jto{3Zr7hDE=vw5^Z8I zH)&a>v3kJDL72s~>N#fRI$>26S7tbAu}HFfZpD9dI*0Wpe`a`oppRfBk zi#x9~>@TSN8}Mh&!+$h$&K1I$SC^ufY1(>2y2K!@KO{XsKZ-mAd{9ohlS`+0(MyS3 zarXm@$Iji=ciwTE>Skft#~th|byYj%=V;lwtk|mTswKv2z7WEs_~|P+6AfyawoM`YIQEW*-T>_ZH*RC;~Qvsa{rTnlsH? z^DVqv;*0L@AAEY)9x5G>h;$cRIx1VHMnu`ui8d7xL!?KWL+Tn%i5DzVW|qckyS}r% zZSSsW;?}RdiT&gSxTu|rEM))bOu!ll`11Gtle53mxIbNJvwSs zaknX=lT^i3mi7kN7}wkqT1g9ik&Jgx2GEVM>t}nzm#xtckdSRIPSjUQAn?o?O#_Y# z5HT-Pr0jNb;7z(!d~;)Mw_n?Y`_C+YeRhgr+v z*EOX!7u!hCk0k{Nsvt!O0~%hD2!VyA7E~5NSXmCnx(qa8Xz26Sf}SR#V`E`#o^n2b@?@REZ#?P9h>)QL83o=SzU=jU%JWJTbJxa7(5U?n9b5 zF03afK(@`Mw@plaFv61^-yte+vfI9GbHKO;G@l$ow;*IAas&_I{edbMxCsBh3a6zF zN2aNc{GP|bt-7*ThY`1De$EVaw8`oGQRm(9jr>&{RBvl#QOjo0ua7q6PGcmW2jRms zaTOePYoQVyvJY{FS3lTPXb zYUzm&ib{xHv2|oRtg1E~j*19`D3-y*g%X982)Ziir&6v2?MeX(5c%%EXUbW0GoPUoVOS*Q_+L>Pxmkii;Jhb$VR zA_^ZGAqul(-9w_|lhC7jjr6BHpx(9?vfxw;f`*U@J*>CMQObkyE(Bl`gf)^|jukBp z7RHn<*_^t2xJX{$wjlyNlKd{cyq^wVZIZlSznQKMGUzyZb@k7Uq`Ouy$1fLDk$JNj zeU|aCX#jS4k#P+^7EG0qPz4qpdk=&GK6Aqlv$m&)nBE_;nOE_)_cve3?(1p4pFVs& zuLbokW~%FEM_XF^w?*!%?5fV*XkpR2xu+@R-(p`YJ~zug74ml}UGZ&IGIH^6KwWNB z&M{TF^LRcJyQ_17LywsI5L6<(os>J(8J z-2jA=N7v`TXjDl8iZxMn1!XIwHUr`;Au4GqH5*UXorMzv4urbv^H!uV{Ou6=rGI-7#vYl zq*Cq(VVqxYh=x>(M;wu+GKw2+G)Pra?bPV;>t1}_-z+eE6~5eSiyd_jA{F^4s-RRb z@}wA87nZK-g19P`nbjr2HNFu^>K#sG8mQcH)ilA8N}_amM+=Rm7{)M8wc&5GTp^qn z&o=V7w={O2h$znxGKp#zN+vBtjv7#)} zX2-%%ZyF%y&>*ksb<^1p)8>3Dr}jV zf%aI210MZ@>;O(^`x4j^@2pUJUcOm`=;!L!Lg5n>g4k`@uvn%+?uNn)3nG{Nxs5KER!oWZPu{_TQZGFOtlu+3;RKm#WP`tG*n>xy#wVI{UTi zzOK9JY4J*3X75_=>N!YK(wnw-K7!c{P7(hV^NCSP-p z4uCZo7)~Fjl+Ya{PSbd%;X;7q>lH*asffGzB#q{g zxy-(vT}(hhs%UIOXlzt1N^PL7 zAX5g!qaz5!QX?KE+RhgDF_hI@t2wR`yy|n&>dr9bn%5k49HpmgvoVdWNDYmlw0g_3 z-JvN?nl!@;h0vm&F3TSVU~^e?HC9uin}#vWDWOnXn^@}It`g!cNp$>5%B+magm5C! z(mYc*Zw_vjsk^#-aB1*$mt=5nZWxu9*{3;%ZIz+k1}oXZd)`kF zsKHYrw0KkJ6)C=mRD}wl=a!Jl;q1&n@#*o5<)$*ywgX_x-1+&yDf9A0R=UU2>zh`! zARv~!YbsQ5VPehQw7o{Wg;lVsQ%VA``vi>9!s^p!Dy|9-7FHQbtsfwWye*`JChgr- zo3$mIK$lF*r(|PTB`*~a%RjPMOxYG>LK1!FQk*w1iZ5jTNBxi43=YFk0_1P9cB&HW&H)tydJTD+Z&A@k^` zxAkhYlWFbpq+X1va%eDV%>#(Mty!&`G4@IdRQo${L%gWz1dobC(ki``dT2s)3|}VM zC>nEbFR@+&wb?7XjMRH}?{4kh?cQYFUEee3%TU(Wa=YzU@*CF;T$7L`F3Gov(0NFF z0sW`o_q+!WA0WrW0sD)h>NO@U*&1?+BGU?6d<`Fz_VMY%ausZh@<9$5zivuF=kh!M0)PFccVc}_vVSSwM#-&d#idhw~TEeo-G5AvT&5LKd`ho%bd2-(OBJt7%u5yy5iVxt9J*nDVX$p4Iko ziM>0Uow;}2*J}@V#&YrlpBKZ^=3v7~*v9@;-p;JCrRmJQ%hqp>OD>1nec|u6f$x6M zec^sR@OR~QA9OBb_1WTh;jMGa%DgiH1fFqqS$w~Z1|80~*~7-N-gdgF)n%Kdz%<&d z0WfuAL+gDZGsjc;@WppL^y~oNz;H@jVK|wUjIKF&P?Fm;&Y9UpS$W>{ZPT-Fnb#Rp zj3lnI!&d^f6s1shxLjV%~BH zv5F?to8~Th>6u7q>N=VD;6FHg_@aO)2g>M?^&g;_^OE@`6|2(}DhX9drO1cISoPj< z+v|rL>AmMgtmxBP)*eDT9v>jDt0t8D{ExlID16pm1H&9=#(7azfZ^2-0qet9z6$Y+Ujdf)~eOXxq}@9GbgA zXHKkpnOT){s`RS;hU#lt&GGno;JVWM$IX=N)Xd5omB!IqmDMA)Gv*(bg)OPW<+@kZ z3c|h(zH!;QlWw==>y9-{FE(6* zjX~8Z5}$f;kDYonH^*mPZ@pdfEz#3vIhk#{DW2bVvN|`Q^p75FeC2iB-xtZOixSzS zt-5ltL|Yyx+9tQUtkuFAXxx8U>MfQVIPZg{)yl_LHJQ9wrMuy1;vLZt*w(rA-gT9H z@xnAccU^0%yz6B$Gg69M6((nCWsk0;eZD&3*D~KZXH4oe8>*m*VPTH+ZPupy%e)9S zwTbMrVGLnQigbjjS96n|AxM2bt2a95SXtL6IXl@A$8|W=IwvV`k?YX`vz;_dnK}uq z;$!FDIG-G3M8t;+ueI5urgfW)=Sab9$aRE*VjJM^$OEty{+&QuW=PgCsiD;F2xd~f ztCQep+FO?_SKMV@WVQyiUnpO0VfP;kocsm&?XB63*Wg6&ZgooE_*#RB*9Po^Dfv9= zIrUM!C8t9|jsI)-nhR`8Fr9tZ(gA+(KK)=NNRmQGhLVJdAcc{ZNdid{LJ0_2W*8zC z2?$_h0vIKMWC|FRlptnSVTnj(2$hLKBqW&$P#~HTCX|U}A%I{?W(FA&B$#4Ifh3|- zrjUV=hzJN`Kq>-gpok)tLL@0#Xar^yNl|Ao~r0Ko8=PMkRq!@c=B}b@)>ebF3xe(Jq`frCV=a zN>!0Ht)z`Y-5Uxq2{eSz)QJd%GwAuz-EW|JD{1Ctx^C^~SUc7;?hx;Gxf)05_AiUH zhDY6S@k)7Bc`?M7V)d~zkJsOP8xKz<3?su7PLo0&1*lP#d_ZT`bUbl3SBn*DsnEsY zm{Y{B9uv$AQM|WnD2EJMZaS%(N89-{_F3W2a#HVo9fx{5u8=-1e+Zq?oshppQ^~Ch z+on`VGPT^q@uUF}%~px4Ww;WeG;(0QB#4Va!-RVfW4;|HHt;%N3VN?(l-PE?Mu(W0 zNHT~*zKDvz|3T3;?xQ%!V@r+m={2uj`nuq%Z6(73Z4c?c@dp?B>UP9 zV^SZDg%8?r9@;)~mPy9&^x%@Xsag2LQ^n}nB|Oh7xp)2FL$9mHhuB|tcUn)km32^` zE<*CgU zRAd%G^qIh9EJG;979UBZoU`$;;Wwo)u*DkEzeb}JTN;ILnH;6ka zIlrkv4IqZ6XGBLWLs>^8H=AkChPd!f)lO64&fT|>u#PBcp)plXc$E4(V%_)@pr6e` z3Ip}fqMEu$#03i-5W}*W5nnv0yi7o-9SIk>WxB`q+-J44Gd?4SkK{fMUG_XX^GKa| zrHn!J@eAj&dTNtD*3Jn%MpQIaG^%b@X?-WT@SMNg^%#5Q@(Zk3z_pt5aLV1100`1R zJ<7^ui)OE-HW?5gWDGEY2jOm2ss6@3XIqpqm&5Z}C%C>n< z(wO(J&ezE05D^w|orMCo5Y6ARcj|8Glg4HeLP!72<2?g~z+y>UZccd3BY~Q;x&YV? zK?D0hDP1t%wqb_S`MtwKP=LvGp3n_GXn)>GN8Cajt%A`XIMkru$#*ZP7hsTG!s%Ut>y1C4Z?i7g)3o7A?g!klDDr9OSnmS&0LlO=G%X zPE}kSu`ouW7S(|hLsl7)G8<6|YL1Q_wE}c_0AUdw+i!Mzs#5VGA0S)xTVgWY!Vh^F zlMV*nI)|6$_`WaD(i}2JG^71;{twK@&8kmp`4qG2%CbZxW%BQ?yGX2UQoa~NCP-#X zGcdydK_vx51tkzkN)kl_K|>=5&;=1K5i(RMN2&cc@=De{?EUdW?B0%r9_d5WM85xl z*vuK-&E)H+FGG@slsFpxH>*kiKL`o%CPD$4Fc<&_EssBM!Y5j5%kxs>3mSB_yUsov z6V0Zp!ugut9_E(vr4|3(p<5dFA+aSISTruM3cNN(& zU#9ifR-V+arj5XFb=VITO9u)7l^P%<0@DCUYIY%tgGTc%pPuJ_KmFc6wc%F_H)4ET z3ifj=EQgT9eOpfs?+-40?XydXUujwd`J0D^0ES5eFo6hrWH3cQp|E1SBrH)WaEFB= zrvDg{A!*9rjdU5Ap3+J6sWAS+K1F$#K@@EW)hfFOn_26a@`(#y>FV5X_**%_qsN$m z1Cl`MhJ~R$YC=ii+4bX(Vh)7IIlrTyXOaLKVEd7U7UdStJ8@ow}5Hl2)vF>fCz0nho+%Ev} zMGit-bAZD!AQn@ZB4`j05p}W52&rk}Ud83-TK>Kr?m-WOqtsobS~A?QisBQHl3+-1 z%`pA2`Gxx6MPgZy7*LQBVjMJKN6Ye!yh38UnfY7mi-YW8nEkI#|DA78`YS3&fO(_f zf_BXfD@o6bgadMc!{0l)*4oLI*lqmG-9Hl?OR72^Q5_Nv6b>o@>_9rjO@wUQyxzLL zO0P|MYm6NvH9?{pYOmmCWfozXgq1@}RFO2akpV(6D@~*_L!mT-N*(@M*G^|58=~Oh z0zr->Tyvg99McYA#kE2wO2Cmhg4vNv;=6pvMO2ndJv-AffNXxIe7&?iH2b>Z_D5rd zr!ePXT*F|k(COGTp{rsxJ(C*#vaT~3K0H^Kw=di_=)j@7?;(Zuv4vx&5r#ZXL*KqDdnZ&u|GO za0Ve}EXcR^e`9+4JH3w0O1yDn_B_fyJwstde~tNnq0iLMbL#%jI*A)$Bd-rD(*8t; zQHZ_G!iNs!YbdbL3n|{kN1}c?>3Vy(kEzXmJ~Iw@8`*>PF*n#sp1&aEG6h>KiY2Ns z1%$}0W?`9_l_S{7K|Gj?c~xR4#DgeQ#YQPed}V23S`&svz6<{c4}bjS>^?^e?zyEs zL>nbuqfvIVVJgfOSg6UF3XX(|$&yz#8tO$RNe?=QokL0*32FwYGQt@lnWkvWyHI$m ziMN|a;%0<%)Q!d~jZ7Mpyp=LD@ekM7h;dP5_;5?jj?8f3u2)53TlN)fY%a*Ir$I3H zn2MF|Fj2-+`Te)!vs&-zn$gnu`$kxv*7A1Thv*^c=!EHH5{)gGthsygP zim5Uym)2$I{Xb@e-V5JhRChc6PED1Fd-drMxTtKhkkW<}W?NS?Mj2?v7?~q5;a;fO z28!aL_hKh|Aj~S7NOX6M*W#D{{QX>4yVT%_>ckpGj?jp$9$brj3~jjhR3#T+qP}nv&Xjg*tTukwr%aPZQVIJ$$h%H>!GV(YIUkpNp-LM z>;KkGL~Hnh14zap4Y~DPX^<-<)H{iVfYiW;<{A-0T|FHVqiH0)Iy+vTR`w!eWuS=9 zmOv6A%m^@{t;f71RdSNWtO5^rVD(2PpkweP(3pSS)FrjJWmV$e9&l-rY{rnSq5QTj zyov|_w-n$F(rR8z6?#)8He=kB0!u0BFAnm=nUG<0>cRJ415--_1%&uGwG?Gw0}4V}7{%HCn35ik38ww}-YJ<;RBR#vYigK6IvbIn9!eZU#E%5TpB)h#508zQ zqFRVzNr?#TCn4-1Mv)L(2c;N7#z#~#q6`PXq!mw7P0yp5pLd_AI~ zN9d9gYTK&!JVkb4d3(%+$E~EwbC3#fIjC-DFRZV2-BJnNSMRnGXFH6_U1D^m>NT&0Z=!g2S@$2 zrASn;)xKc1r>F}e2=xvO4%?}>F~~FodB&u~=cj}jYJ{rTh2YN(ii{+|^bgtpBNi_u zs=!Af0RO(nra&`gRL&V6?^7d5pP#G`2U%57v1bsKhMIt>IG<@Ki=w2IAwmGcPFF<; z%nVdHpd2p?aXcoAsZ{7{Hwsx$78X_#NJ2pgCnTlFP)Ibv01}P>3bq`8(3cDp1S*qp zJ;fxPR7+W;uyglM0U*=KA5j21dV(X_$hSo9m9v<5=E-s z6grqZc__i##CG;NyngYlnP$Sy^v5Da)c2xp?t2uHHL~I%B0C_zSQlkKND4g{78Wl=1t?m8=pWN`t zk@5}io%>Dk(O$cz3iU!s04!Mwt^AK_kwBhM5NffMVjf7|-+V}Z{=#zMw?DpYQdm_9 z8q5R_D&3ihYfHM2d`$7x$alqY_R6R%rVRc3*{J~0CGkmHcLr9La!mZO<-*e!3$V_n z{2h~{I92aUZ=;hvQ4;%PFc=dUEgWeKNHP*hz%)aGWxC)bxCod;?pZYHJI^MZa1h`C zQW!%dbXme6*<`_WLv=&r_0cTj1@rj>vI#0i?TC)R9J+`#kkExz4)zlxcC#+;+@-k} zJ78YD=1Wj7$%c9z-sJ?=OpDMp>%8E>|F-n(j<@g27vPdN-@v(`s)Dqc5al!sMr=gw zEr~Y~6M@)PzF;Yqh5C8kE%6h5f1dO(pndyletcR{($5WB>{DvJP;3a@ zYVHd4_^ZmpEstXEUfuEdvcf8aKbh2y0-x}6f{Xs4rR& zKJErDNpx{1F@jGER-04>BA7Ii7>Zsa+ zIAyi2Zp6qpzwbM8e2A3tNioZvI{2MXXgOw3`=jef(jNH}{^$z{1d z?I_VprRB9&51r3T^$#A9)sC3JR8?LBB1t`1Y5O3LdRR-{l<4=@26agcP)aWesUU`v zAw|S;BdQ80DueU?!}@&WgG4MXOZqQr+z|^bg^Dr6Xyv9*RAp@a@Bv^TWEPT#?8~<` zT)}%wNk=NF-f4h%9YVM$>72Hjqv6F~XWZ@b^@fhCyc5Ef3T}3&KTnH5kV8N~Kc{Tw z^By2$5=25dy+8{6)+|q>ymM1wW8L2FUWJL+LOzhCh6;z{>Zx8hLA<P(m#r8aa1Qsg&kyYWY$~^9MMf2F0&gZ{-HaZT zcWuf-huxO>;@KC^*?F0+hRYfCzrz+0?N8g>Q;#+to;>%mSIh_5;Ptniyks6UEkIkP*K0pS0RY=|S2l1(sb$nvfx& ztXEVQ)R5OdZ@n+*ARY~swN~IZcb?xdKg#BU9#P~L+l#!D^zH)#5sYzv$s`Ec`Xo@% zFZ0(1NHQqC-QG7`1mhh0LOQP?ld)AyqAq4$Gi7Z5JiVjP<}4qs0f`fdK_L)GT0G3j z5cZoPJY^Ds%oA`r*|2P{i*Nh*%4fHYUY}Y~o=US#XBfv#hZ@AWnt-)O>N0(uAwUL^ zsWL)7-Eqvn)8*PNT_2scyI64%bGch*kO?E{?rUG!>Hz2B;b4cm)hd=li)sb-6o=b% zx~?quJDT`{Ut30&64;b#E>jmoy^0MF*2#X~2!&o8>7W7kT6))bz38ia=Ox!yrE71uB`}AestJ5#2nHMWq?pnwT4TlC|=qrz7mA>`|?dF&`vyIjl;n zGNw$n=~Q`W`rAp+ryA9Y`;HOYYt%l7`IzggM*61Gq$XM*Lw)IC;PBT$nPe<&%4C@- zu!pIIX|SVNScTjRg(YsHrlJA00z+YpX@Ev4#n50_jKZ)JR?{8ADjHu%Mw~~!A{1^p zwY+??Cvi1kaBV2jMeLsCPE`}dgZWprx5G|9^0iI3PWMmGNS?aL15a37sSGIs1!3rg zP{LIjJfODcd9iBe9v1r=W~H4>P$(LOfY20LQO+c}k-!-sq3B7kqA&sEmdJgYnB4i$7 z^%we3C6!f=wAg7ue6UV-mqVutw-!UZ`_j5oT3B`=Ot4Q`CGC52LISBIh51J$0YJZ{ zvsBD~#vWm#Pfz|tbX6#b%9VfzlgdYiX#bA4)s?p6%k~Q#Ap6^SwLQeHfF4fDCX8mv zgwowXr4$sVWsH_;bfWJ=UR~TTrg1H%+xf6{ZClu6IhVNVcpF?jblcvbRRXxi6~gl@ z1p+XgkR&so=4WsC`1AnRP3q0?{%+$cpH3C z2!SbMQqhG8PBD`$Ilf?-|eFJ5zvaxi5=%AT1vd-X89aFJrI@Hg)l zo*d)BW0S(Vnsy?Jg|#G4h;=DqPjfDi9Z@eRn4YLWO;Mqmmy-;qb-N9v_&YFat3S zD><%SKG;oE$-UsEL*hlE^oNix5iTNrd%p`+({cw7kcC#?Pq)9%%s(3I| z@Q>eHDtdBt%0->M`*fPVzLw7A8Q}{P-iAlyz-tuVGBY#T+`c!xN^{pc?U~S&t`6Pk z9Vmrj#yyr!^ruZVB1}ys0Cx)^1e1EN&n1C8RyO2Zc4LEDW4dAsh4P}|r3&)v>Zd(n zDyPyQE4hxi$}s99yT6YJhcai)IO2{-*;>)36f;$uy$yt}BE#lmo7cj9%&nl zOhk}0SIG=#f6*=bAxD82328lkaKSIeZ&Xpn#yDktRku1nqcpwBBxe|VEa*s@mBsG)LD7|JLWQehI*?LV<_ z&j%voPuE{TNRsf~Upl|#m^kU*;*-X1(`LOwsWcI|uCsnXtk+GYl5K>)as<6$D0}-Q ze@shCKGcIJYC+kJ$rD5Bv7w6V1D!QUd8ncPz2G5KWy|vFtsQPP%jIrNCJwH)o7Jz* z^$Hk}yyu7-_I0~x%IQHr*;g}F2uuBY|mP(sFb}E-FmG^2Y*yyr-;eK_*Ko z0;pl=XJ%9;fzr!ZvM7cwAb5p9LM{eb;*J0(&Cja zBCt^TiaN}f3Z{kN210HS&$1P96ekc0hEgeLi;BYuBw>OYca)-p5(^6?{bM0elZu3u z4DJyIO11~CSgueE6kiaOS3_goGA3}w-oB^b^hCTht``h1VeZzem-gmit!*HW2B|L3 z=Q~U<7g;_bm-S^K;`|IP{{6aN7lEkwUz zTu5>E&v%oe&07z#WS%C%XQo*T$%y#m#WzJ&`#V6lT5&URVL#2&I^g$5DxIp4m=QCc z8O1^JxAA{cgs)y|=Tpa5f7V_1r{$BkhGrZNBV&8;L(}i$?jMhypg_4G-^vMq&&h$2 zMZ3}6cWY{?iAOzL?MbhyaFN};i@Z5_rd@f8Xsme#sl}*;y@@V5D$J6#kx8h9k zeji!^PHXS181~tIQLh)9=PFk}3tdS4?T%=!&I?mnQ z2jsu{)=E!;e<6Syt;Ki3%F)=VvA@r)OOhzF(-wbzCvBSSx^MH=qJ5N5Z zGP#I!^c4-ustBWf$oyZXjAB#il9kVfILzMQvB7Sk$QOP0GP&WQ{|B%B7`=J)TbDQS zFnIz!QgRjQD=+Rlu2g5M#&fbj*L|0rUX5S<&eOl60uPBdwq`6@MgyiQ(X(%TPkMN} zg)6A?9_7~_33mnDwQ}7jdlz<~w+u5n0Zl2WW7<%oyn&c+saFlBS$EAViZMX6#i6Xz+` zsW@0tHCe7F(_cQk^q9DK@BUAHytrRG*ZfYji4Lbtq5<&Un8#ejw!qWqp;oFP}%R8?V$I)f&39Ol?+QgJxwoHT4Rd{ zq?no@F6A#)d8{j0@@P4o@F&a$wOujoF}>n|Vb^K^AxTg72N3Hf4otTvi5?n@QhAgK z>fIi*0IR?UO{f~Sww`aqdw)!^@P^8!-nB=dZz+O~oqRYIr>|I6ed8_n(5oHGi4Ow1 zSKVJ?{UfY_7L+Plk+Q5?MVh36rnw6J!*z+bGA|fJ5K|anKO*SEh6vMFOMz0*6Btc? zGL!{kKxyV>Etd<98d%uk{52)}f>|mu_E7_upA={8e@M<8%JG+A5Hn(00>FSPETL{T zyHIYL`v^9)raaDbz-~Nkay$*k-A@(!LeVD#I5#%;?u3NhD#km1906YhrW7iTXgg@a zNXks2Jdzp>Ni{ek#HdW&3OELkUzq}bbg0PpC`=uP$Zh7SoA``?= zL=!;itdb%{o`SJ7Qo#s;Y2fJWue%lgLs3_tGb3D7tdUi0)CE7x=$($sqbGlIxbj5T z7JsPS3vNz)^W^P@&dYw2e0N_56{iyHkNrKW?Kj!@%|cq4nYXXYxBkKRE^a;!;qzLu z$DQlbx&NET9jWd}jmJnxzAbrtP^_tmxH=WDk90D%!oRA(QqPsAS*hrd&Ah!acHo%S zR3$uKsb)`8u;ZWF+#WyhQVlA;MOZ4ILz%X7a3@_LgWUsrXP>1wzGtxKr zH#W!TkJx5jU8`lHz_(Wgy@cH4hF)1dt8vc8xP$JpifvP{ma~GAx8=8J5${h>4wn|- zP$Wfk4JrmUgFXS@i|lXfxH3kGPL(~p*vEzZ1QJGOAcnATBq-i$Ezb(&g2Vh?-Z>vK zM1A2^-Nk}($5HwXTL&IhBl6ZE<=I@JmB?FUYG~E1>;juUw#P z-ko=<{aKxSr{L+z#$fMnQe7D-?YJ%(lp#dkFwk`X1*Ju)dBG`hwqkyEjx-r^JF{hl z@5Iw*f8P*9eE5J`b|TqcU?KL8B(BiLUJM;VIcRryx0*k&06i3_%Loi;+Y|UgjjEQRQ^!0J2Qr+-CTy=F^OCGOxL!GGKydxF+a(7LuUfj+V zpSt~w*SF72#4Ye!kwKou&KEpNKsk2(-gC#^elS~ldhw3!N79bJ7yDa8Dst$i-af$C z5R2jYR&zg7e!mo9kB8wAHYCfwV!_4h-={@d4RoXCVH8Fm>ZGMG;upWH zmtf)yWXqV!qsmN$DHx!dj|K()Oa&5<^yFs7%6&O$AL0j8?MnvG{99Mz{r4QA_*pfg z7hUnS`P`oUuNLyOg1!M2uV!YBLHQs~2NkwrG7)%qEDI>-hf>*DH60GVFAJ#L@oD&r zrZSR>zpxZGiBo4$O0C&KYel%;KT+BREi!7qYSNxDLO(E<*#P~Qe01g)kfp*^md0ht zNzfm9w7Yr6#h~)L0h z$B#?8AGi)~TL`a2#FLc1vaEeUS6Ix=op<)x*IZRNSQv#&^%1ierkEaKUTX+{@A0hR z_Q=MB`w`bQzD0FHm<(dfXn>i#v4$M)&HM=O5wxH=i&%%jR{mn+&&952aHDBLxa z!osRSKeGjDaI!}P2cMU#H$+i8F6|)@LTC{kUpy~OLDNNe)yR>;cMk>p%8OEWR>@Mp z67ecl5w1ppmj|ToWng^-=W@SB7g9Z}eJiOKM>v}?z@E-$%#|0BcL0M7G8GeX*i!7( z+a0oH3=pQj$j-w!CBo={c{t#*G3SD|QnS4DIAgIW8$yzN|GrHqT7y3J3m54(U$eqd z0IR_yVH!iPN5PWw=^~Z96$HLZF4)q;Mi?bTQLnTKAmdpSgmD)y?-5?x*dg5ueR2}N zMK(S~v7gt@{Q_?}-jtY4;gG(mV;92P=5>3uabtQ;-=noTa^uCC77i{4|eipt1Nk})``H)VWMI+7AO=N zbaw1x?F^486fPPCH`=FmaP=Bg<(ZB&_uA!)KX`KiQ>Da-q0KriGJgPDj3^-jsoaal z%J)<%xAiT&>V_lY=3h*f$_moEn1m*yXI6XG`_BtrTUm|oW>UCS^*xC;k!K|L*F^D+ zz1m`J9Ix4XE&PSomvCtVIiKA#qf3Cd9WCNvg>d1{4|bF@W6nxEt@PR?!;S0ST(mRl zic#^P34`7q15N@GM1BMZ11(D018G>Z3%jTs#6!)ouEaq&x3fFr!h0^UX0D(x^bJ>U ze(SRvSBn3bbrItcI489iCVKCq0La-rbRKOJ=eZf^mU3Abp2`i_o=a&a=w^VaIC37QE=E90>S- zKD;O#T}01aF?FR<()r8`BO@6n>Va97(z-zF)2ju6Jx3BP~ z=1a&JiZA;$eXuS8L)v$$DN#k{r`QDYeHuBmHOjbeD0Fz+vK$N>P0F^%w;6hOrw$#C z7P3(k@Ck-gbtExg3rl|-CV65))Iz}U9~i+953@pvfwv7cn(4BXdqXeWr0s@mpVJ?{ z!rGC~<;_E>$@&V6x0#YLcbdmta3ypN{}3mC7f5(No>8oeOr zsZbl`(TGepOL12svdE6f;a3q?O7)pO^y+yx`oPm28wI*r@w=*UrK6jdHXHHSK-shR zO;~%9?P|Oc^*z(gVIZ%~Wsy%h<8Ji*!+YWKbExc3(O`cri(nayMvRF!%B#a ztr-yyFRCm|egv45NpKWShs(+S!mHl#&LRqj)9@Fp)nJV_%rMN5zA~kd^S?4bWA?wE z?s8jgCfnyyFvo8|ObM^jZ|hhJ6`yn{H9Q@6uKjd7LNQVHw-9gc`V%u-3U?;)&PJkd zZ#SmhxTNzUw)(|!c=+sMRC-@Z_+rJLDG-?s?p$_V##hXCfzeg2u}}7)r;DJ?Px$G6 z<}gqB-kbmjrZJ=r=CjckS%E?j8=W~2|3)^Bo+yc+;B=%<4`e)HAjCPSj6bZjp zlmeSWOi7Ach$x=g0(jL#a!Qb5Wdt zVrE&Zq6s9?t>5PjYzc;5&`S#T=A#&)TlwTw70i@<$@amFQ3?Z0j@V+u$RL|yO{K8-nP(e6;km(h(}pK!V3XKQx7Nm$ z=(DrYN*hn&urS4*7!^+`2QI)}`3FH6`=dIYDA1~aPH#p9ZKAq2LJ=#s3TNtw5$@Wr=McmOAr6bx$LEzg=T)PT0e2LhpvuSeBfoAtrhlP zc-lO?!*L<$u9mHA5{D~xaAEhXlfEC0&ey4qC>&(PIskj9)&2V;`K4=0{Znd1GOz(-UBI*%$ z6)N!Sny5Y)QEVtExLvBETf^aT5X}TR=D=Z#O5+9Dd-lT^gny=TzwMU!9 zw5mEGV?bp`qf(X5Iv{!PF5RzF&d5#=9`@Yyo2qi~)%6uq z()Wwc+?Tli+gIG#+X>n1AGd7JT-zabxr>|2^_7=-!Mplx)FqZu`-}B`VXd8#!8ayv zxs{^&^+JC4xnfBG4IwZpMe7jrOM(c&$UhamM$^kvz=8E4kt|TUyY^i$9SvEga8tJ& z6h@(}b-v4g^*Ruek074Uh#nH*)Q_~lzRti{-&PzulUSDf2vY$*IGmSut9SgT1@OY`G>#(9IFz zFpeX^|55!21a;2T*vp@|j96+Olj~UY6^-Fa{(A9kN(c879sHD6F8p(GNUlzEhFDF2 zlmC?G3)_B#iEsJu^&losNC&v=E`rNl`%JmN)=kHC>1ZO*Oid?=hlj$u>XS~(dBRg3 z$`l_9qeS27$w$>Y>U?-Z{MeG`9~!y(%a3_f_S#eqHs~Nhxx^s>9uejc*Z!!I zg7pM38w=3zXO|W4C%!y-B83R&k))Tq%GJ0^&j<<*HN>z+0?!*EErpSyTvSm>L(lBp zW_WLu8O6SXRN`!~lD)P`+H{5(O)3TyXm|wA;ek^zlUK}*XU3+crMa@_ z(q>ofub=Y7J00vi4a)Isd|1x6sD97j^2Fm$2sdRT^PwL&?lNqFpH(t!K9heu-?*HxRds&nJJn)Xp;Q_P6Afi4jAhaYtbve-dQw(@CkI`BsF?5UIN+`970oJ*nMh zZhWJsEiYZ!yEHcyb2J4uDU?Z?Vk*x}uu4O9Rn!i7`qZRpz(Na*6ht^8QXyl^O$2n$ zu-)Fiq0yIn=f+EF4Jy`odvHl??VNWH9?!5}yx*>~)JcWOG|Bfqxgx11a1xz$k%p0& zVw#i*>Uf&`Ht}2eO)8G#6uDgogUCnMQ!{ut&U^>5^Jt)T>d?A#;9i3Ah*_c_1VSvVYvK5Q z!F)T7%0B2Du}m5mdT_KQYQ4}t5su>$W{R9%?^)JCgJ=I()Y)G-5nLpulNe#jLZ~;# zDjsw*rpGKJ+6aSy5DG+CAff&Z3LrxLx-Nr{ z4xPPTkYG1OvLA86u%sBI#BF!ECiY2Z#yt1PwV87hQ>^U)ylNXLvfzRr5M>^{nWNYWWfcl=<_fVaF!Bm-YofuFf_%4c7ig&p1PWqDS z=f-6GOYVm95v84i>XAlIcK7hx7;hB!%oKM(VHf~I6-miJ>fXaCPp_W|_9zZFob%mJ z_0S#DW!v&g*GbUhF&zN(!fE#2t-HIni{RgRS@w*3DJeP{;WciO6?=3uZ{M<0x+kgpC>zU$SNf_!UJ${jx< zIZm)Bn-df#O$e+jo$sT{o;l{Nk=vo6OhNc9+|q(OH5}5a3Rgys76x!v;rU>~Ezs(S z6G&YJ)h__&8VKwWTQ^4yTXCB2Kd~x&Dju`KN(|}EvembCzWVO0f(AUdE$ru(`OMis zde`N;7ECMJ8#BQm{+hVHTun(Af_A59$_K($!A9856E|{vgHg_p96o>aR*$AHk`u93GL?s! zDsV%he8~{iZuL0~jI+=hzaj?#GWX&-sXBZ8X#eqfz6gbP+{anb!AmVv#K&h%WJDZ% zc!Jj_(O(`WY3I;;XpNmXmv}m`A=^QUR)*qJIK8g+;#jh|_Ibiuivq&{lWM47G#bIF z{E|zOu)-vCZJ=*jgjl3MI6K)}v0uir&$^?P;Irw>?}rKGxd1I{zygP{47Bm|o% z3FP;j@LU3Ab3*KfL|TVg@_~iQ=SqmD9O_f&^i&19DTnHGd!fLfven@_{`u^d0!A3J z_xmsszhtAs%%h_hKX#0R1c&iY4?%)IBkAuhAB%`_;{oA~&5Ugt=MZt6C$@82o+-BS zrNn9d1iL*?d&aJdK3rgVAWRQ{pkF5f)LKMxn9t#!zDC{UPtMVoqVF7|Umw=H}hol1roz?M-l6;osxpeGb)VxcKxsQ@br$cs`d!5S_P#-=co=OeHVsO~eMz`_Z{ zRv9zELljB^lv03B>@q8f%Qif%x9m#25FAKFZAE~^`j1va2MXp!j#46e_g

}Nch*WJot{Y}E6`ZAyxWw*m6^;34)7maX(0Yj>hx_InKK;6uh9pAbP%jT-PseGbPiMkyEe_5u7 zmJzl_|46mB5C$H!)Be^MtJo*bFJ;PaY>D^7GNd`o&~ zo#3Y6MD!8dzJj@W6oMddHe)c4aYytv?a|*PW+kYWT3sO4OdLpq#{)r%pqzoymhR{eKH*qiF)}z{s;rP=Sr@r%HQhsC52|aul4C1vUCjzN|MV{4!SKZxbyM-RtJ7L$3Esv9 zLf~&rUo=!-viLb77vAcVkD+=xk9h&F+~BDF%xUlHz-r&xZFTH==qCt4()3f@de*ZZ zCA95=X-+{1xiSp5f2ucmxcTvRJOj8gzZoWv8{T+@_uuvD6r|w|ZasxYA4Y*P`eJuw z`)aP1fL!=it2_~h=N+ZK0=Ix*)B#d?BU`@g2_wz1%H@QELg_*e+n=mB_qwI&pmP?W zYl&|*zhjN;N>DN{R0=ps=ISrMYxCjfV$RJWkGO7FANYABj8ahtS31X@H{uA67;BAx z&^$dA$iUma_`~7AK%H;grapD`@5H?Rp83I)>v8ma=6s`L_v%*$DiPxCHGRI3?n9Yy zaM@`?6>oX{ygMO&qleqLa;IjkAR$Sjh?yQSZg}cnK(VgOfEY0ueYLZ8Ye-)D)#?oP zfUaAI=C9E|O+|kYxBuWuU%Wr4v-WdsfCP+4&M^8NqcOUK#si^~Z?|Kw*YgN5x5kpg z#MZFB@x17p>NO29>LyPT`K<GH~N zGFdOMeQU>N|9C9H)b_WYRzDW#gm-*jSbN52_%<+*L2`&cI9|JRdeLm@hkA?~?=^_V zgnHgxI|ly3yJ%YM_h?cLnBcS+V&c zWqyiuJC#y1-z~PIRL~& zzvS)%q*DLencCbL3cTkXCkX)Wk%3y8_^>C9r~ht#qek;{Iqi*Iz_p2R!UEXL9N3H5 zGM?OiZATEgkZCWo}xFhc*w|uet{L<)#n1G`;S#VX@^RV6S z;?^QOy34g@Rek;90vt;Z-$6i!iL|fgG+FWk{0Q7Eqa8aOZPi(;cd*1Wv&1AG_qBsy(Fe*{Q zKS8yC4OV*B`=AP&)@mius%n#_ptR{gNf6!ucrTIb5=~&*O!`_Xsl}M|*b1aVft8)h zmvD70b5G?c3Q{5C3?f##&5IPp7oY$E)jka$2?8yx8b%pN%^#2G)=FH)dlqtJ_K;uCf7{IdcI^{l_{I+KXkcxl5#?+1Vfr z?ONifxx|~ArJr%Oy(f^gvm$-Y#;-$SjKr-SS;k{DBnv<00hR%(=u{$lAf4M`IVQRD zdF6)@OV2aO3da*AJabq|&vTX@OUqlzo=YUpeI?H-JSx0YMwZ4;^ODApRT4;9{PE%d z09gL>>i^Gx1PKe0@?aG!J;KYgU@Ty<$N(|`kO3KEfw5ru^9vB^0|1yq=o9n@nKLoM z$Y5EN#YhVQStJ+~002l_mK4cQ#v=IRN%;E+lmDiN{T;CWd;7mvr33A#alXkui~Zz^kP`)8KWDI3w2<*bHej;tsXf{{_2c8AHNbzL{I?kEwD!k1sv4FP;F z5=}kn;f8G}a@qTf%MvD~j&2lPh9hE^0*gMy_B=PG$aM5bivHjpxWQM}M8 z8FDc)rNZX;gw*r>sd#fab$CT}T#4!m*+NPt1y7ar=~`v`b(c$wpLb?MsarL;HeI!R zt8=l$;wV~7&oW^nLM;PZQph+#yxAu>K$1d>jAY5nNj1T6v;|G6{F=6DXs6+eGrzgI zU9(gCNdNNkn>dY@6gHRhdy>Ky;g(dSY!biZ4<3GMyWu=2s2L@79K4z%xa&VK;g=_3 zrJ=mH^v~*NVN5VYB|$)h7b30zzr5r27X_N}>|p6I{VWn3N83Y7iBNrKpljiOQXolD z@n}E0mlU0G%qQnx8jJ+i|FzZc9PZ8%y(H^Yn4Q3Dq%hoByCK9T^eV?8HNe7(6XT)m zu-4ynD-K8k0aXGCHcaSMbxl45^U5ryF0-?zy|AA*oL}8l%XG9?nY9+O*;yVto-VtW zZ8U3l%IaRJ+L$SACA5@l$SNyDG&m+!uTN{Xrm0!kxpZ_CVp(UEG*}FyT2X8(XSTK% zA7j+mcNQm>tF9MsW;9%#wKimzqnAhuSCY>Z_#{+SjWc?oUGp@ZK#iA=YrAN@z)pxx zl%ou$p)%T9AH-KpG-#@(EibRoRwgSGRf*~y8)}p7Czy8pF&*X_4%W)H!lQcDY<1Gx zoRl;*dYswbPnM8bGCSB(O$}G6X7rf9=*Y#ZCFNG)sbBh6bd**p(N!~9YJWc5?#0%#Jg+fr z(OH?fm>l;|OROIHy2?mByR&SOmR)Z(FI=y(?WUAHqLC^orJZe<%5o`Tb{y!YKb#tvijWnXhR3@WRqEJ)NiP@e9I`$_S+TvmUMVl7 zlgTWr>{U>@4Pu|3G}s=e2|`bA_UYR|eFK zn<7eKz{MXq+dkP1xy^Ge$jgow6j`E+mZ{`+eQ30>Oy886R*{Q!a?xXz#%0MSHocNF zc1|+F>yS!bKF|BpN~$0`U)8X&az*77R*lP4aj42_L#e7M&r&{Lj+BZTajXL^*-_a( zFsVY3?9@)IUVOQ7sIsJt-HKguw7jD#cWj2DENj+Ly}{08Y04;5njoF-xzoAyeBoT` zq;+4(c4MZTU9pN8g6`&O;pSk4x^o1J%3aXR4DFDlI&xf1wQM!8;ia?^E~|THOH^_QBB!NZhTlPML(Wq!K8EE!U2eaga& zQafboc)qMbBqQ95%5;XexzT8AQFXgKx=UHl(Vym#f%{{{V&-TT>Y|$ zWmwvpD66Q--!NMdc37=&V|r9OV&-TSNYiMfg;13KkrHBN$H|d1ONMLOz_rIQ<(fiyBK0VyQdwxZ{1WLnw| zum_3PFP0=8MUV3!t{7D&hC1v^s*rod3Q#7502po*iY3&o-mU06xxar+QNAnC$+zHQzR0STI!O`@!CNI}`dZLi@P||5x0yZz>NQ6ma8zu}OO(OR>X){Ga zh~3x#e08@AFQhBYoY$cgRUr41k&oo?daXWtR``y|^PBNT4$EH@P`SEh^Nj)G18!Z` zKxk3$g5ceLyq`S=zU<0Q zji=zopqQdX32m>el6u6^c7mhA(p1a~2# zoM=jX&;UBvJhzgqPR%`0FR$hJi81VgNXP@oeZSH3*U1VJzh*wwN=s=C znL>-w6QP_?0TNXz0ONZz^vZ1^>7&yUWq*_oQ4S|O&xq9|6vy)|9doK5OBAY%h$EOb zFjHWQ!#J2&ljRF1T53I!DJ!aXh_6eAY6F}Dkwp0e0lvSKN9yZ%zw+;GI!uPWv`Rfq zZg|2s-x9t&vfYWB;}P^>0Vvy7I3ECD9yFy-Nx%sP8*C;_M50E`Ia}w%bfr3K&9Ww2 zb)9a!QRQz#Xx%1e)PSIc>a~>97s{U@ghUnvdUPPRc&xuH5CgY{q-+RvBfx(o3awLR z5|PE$R2IEA$xN}NL2VJCB8DKq+$u$Y5gFO0QX8#>E^a&dnTrcINLX~A6ZM!9Q zM%R;AVHDf$)ciDDHFrWuL>fSViYnx_9Ja*0rAuko%{!M!kf7g3Qb`bPpmw71RV_&5 znZQgdQ>1`VXb6*PN&XK2Wk8z0?ND6+J207sNf{Xe zKtHlN;GO|&t{Ema28au)JBus6^kPVg$N?e*h9@BhF_;-TlY~vIQ!Ew1$4NE^bhve2 z%;%b}0@^1@EhSw_n^SG5YZhggX4z`^Qe||p6|8~Zfs<$rCM4lW^?;QG;KkH3heRLH z-Br>Faj7ycJ#7@RF;UM7>%v{mDX3OqTVzwgipph8qXub8?Ew$37hqzqekNV>sx1g_ z4rF#0AYw8g+A=C^0Tr?~2YOlH>k+FL19G-TDNxiNezxH30hEDL23)1)99qps7ri05 zEqTjzGUQad_v;^0SGVc8aK)75h#hw5LwCZ(=7~b5AOR9Xogj}uL`Nlo`q-yVLO&M) z&THe}R#(Rn(%pP_2g2T`tK@*=Vl1##Mo!O6taj!y zo}H`!5D`rxt639BtGOS`iWeJRXhPXV6>DNZJaiNxmKvvv)ksn-I}?radT}px0*Ic2qZ~rH^&^T#76|Ti$rCW7@OmK z+^aKmwNnvgj3v!264<4*wI(ei7VOL#hQ*lDVumDY#Jrm=qiU(4zDjDLiiXvySgdum zt)+ysd_d4EE9yj|LUl=*p`K{ulX4>!)B+$`B1DDBfOL(88yj7zGt!ZBi51B-sfF}U zIOa0V47(@{vx!Qb$clV!Rir$5W+klZMA90BXetQv1p)Aecj`z=UQ)#}Ng!IN!Z{+- zhF)7`y|P%O%DhQpEmh-N&mLE1B>!)bX0dKSy;u;DH$$N5pr{;Emet_n z=-uYiZPw3cLT38I6#%pa44&W*4m6u-rhF!tp(tcKS-M6+WRVb($UJ5cyrclSHkt;> zVy9LaW@BaEmZEP{Ir7cI#GY;bE?9^Ow#h;*KpSCEEdx2>E2l2c9q_i+=}}sv8x|tSV+MC}`u=m{qNH4LNmsIy^jmU4w0u;31J22@*m^Ng+7Z zA?ICQ+>%KoS{MkHDy313R!VdGT*wC4B>mqne{x++1LsiL=O_mKGD4|LnFe9kX3f^y zJ=-2R=2v1~687c8VrD#J4S0(Uxlzbr{iQBWudJ zmd?yGDm3R<8vr9p==V$5J3*hC_U2l{QFB$$+)_3M18RhWZXOKz4ARbKSBLFv}>yB|(--1VjAmHxPxVB~;~TxJSg(Je?R1AtAMzJp*Uhco$CMmx+b?dXBkIa=x=2!C!fBsKw1K_7t8IdJ@aX z+jo!OvXd~>eMW1}q~BwVP6?|KaB1iEK&UOx`=phRE4JKpq*C}&Bq6mt{aCsf&@3G- z4J6r-B$Br$!=LpcLd=I6+%4CzcZd?v>v47){ zAt2PZwbjpPhzx`XC)dA(1OoY-hUGzya$zz~&sh2B=ZU-;IW^(k9AhV6+HfzlZIyF8d1!u?CGO>!D95bV8v4SAkThrk1)AX?yuPe+Oz;fgFTz znj=y?`Xg2m+%r^zG7skDmZ^2&8vXt=6la)3EmEp~bvC~MrneK@929XR?t z{)S$Ul<)P;=a;iG%cnv#tOdzL=z^!C-4z@^kz!{U()h8)nI5(`4XfY4Sjq$-boTi1 zk3f4@@mWKF7k-JA4~mft;+4-Tw8(AnYv7l&WB38f+$Xs$@Z1vHa`^qmrlHsn z0-aCd12AaA&k|y&qNu4N5AWbFWIJ$?K0NKg{)!#=h2kAq(VyZ|P#@AuM01W=V!*E9 zUp5~X_;jF>DEDBi-ifqO58^;Rz4a|5of4Dybm5t=%;NyidKlhr@g83>LAbm~o(n-m_KO1{4;Eu4h*y$RQL6RO}%6Vy0%d=tO3 zjTbkQwdL&a`Z7G^&e?aFEV7f;+?}+l9klHJk~FlVNvmlY3yxL$tQ*(@Ph^K2_rQ2Z zX~4hf&7AVSvpQ)wSAC{m1HI`WR9@6W z;lTKjHHcatVg_)>nMvwQq8de!0FWvINRA=)(O2%GC_In=ezZ^Ye$79L7rWg%wjNeT z!2xL`fOro9&wETZm!0Gn>tLSwE@^ve=Tg-KQb77X9h0Fj3H>03LSvJ_`LOdmJazUr z(#7JJ*VEbjO&>SWrQ*TQA;$^imR>2jF-@ULv1cQr$<2mNe?+H$HkHtJo;z*RrzX4} z7(Q>U-aHBSck@O&HI;2I@F5a&v z9*#*)1xK%x4Ex+D{l)~^DgmBbBWshr!0Nz<+3kiVNvFJ1`-%Y-@7{KP!HOoGx1^gZ zZMeB{)`Ss?c9H;cLcr@fHA6u*1SmeO>Sxur+G#cvwM3F6@bM9Pj@$>_jF~lAi zAUvR(m*qvu^ps!NVpFdxw=2_M6jQjVx8mO_KWO$U_2A;K*2H$E>M+Xni`u7*fpMh; z!n|TJBMBbYo^gdRfDhKnY*n^AAZn4e({5V`+oTo%%HGwoNi7+!N@V$z- zMy{R^^CMc|jcVwr;FqC!)*UzLWu1OP+Ht^}czYEmK&Co-XDf8PmeY~KoYgW?u)fDa zUO9TR*{j+Q;0Brt5_q~hIQYA7W%#dh#l#TWAnK{qMv>iEQ@ys{F8)V7cPm|e8aQ$G zQMz-R!=|OFbDn~Fb)sp{&Gb6Bukif-e@C=(F39S$_}!lm$&!GacyCm6^wj=7LKTvu z7D5%GTiO018w_AcGD#-v<{g*YWvPSp(QRxw+e(lT-rH0QnIS-X8TL+DIUKuWGwJB=P{7 zARFKcd=XWC2-+db_Pv(;C`?YP1$}W$Rc4+n*+wOaJ9{|ubwxZ=nomtc^7M*zdeLj1 zYI*xPfr_nqCvC}@SFxAwawm2j_-0+Wo;-tW2S!a~xMf@9Kf=TIm=6r2yAk-fzpMK? zmvvPhk5w=7dLr-k=N?;bmmO*Me(ib{rc}_kcv#Zl z5;xn@5!6SOcI!>xG0(~)xjGizY)IM%)@4=Qn;YrEbgB2_$emF`IHrU#1 zvqXQc?|wEOc=dZLo{~FaJYCxQ&koIxG!CenPS$wm$2^|0Qk?uYhibq5KInA7@PXcp zs=I3JDd@y{nfKmLf7SBqg0J#Dzc0tsUoCO;LE2m@CI@xw`cn4&GpdQy02wE5ss@9e zXG}>3L1cuI5R8&WL?}TrMj{d_Q$yqA<@0jO%om<=q2kaNj~sJ~``~ZJ?%B8ikUWuj zp~frB2%Hrt5k3hAzq|1MH{kDSt^~%&8MEEwX;N$mlB}VN=YQ!Z9SJQ zyh5j~w%g>EYDsF&NhXes?MW_5W6Mc+V!3`>iLHAllzSDTeO^QJrQPQ=qa5sIn>sew z@h(-Xbh;?&Z9tG(^Yzm`=^`_IUW#6-x|3!Y(JLnWtGf5xZfnkj@nWA(n@N+nQt5SP zwApmJ>YX%g!-uz=I+ zGhSnYjL{dy`$e^0+N^~g-xp5*5Ot|N(HkOas?`h`R+2HSsf}Dt6L0z390J< zXshad1*0#GwvE#DJ1Tu{%h{b+uLgIzT`6=WqFWNgx)R+kq`Q?IV&N8YKXZ<~&EleG zsqjGVMZ$)x1hfGnr|l0$Q=Ti@#d`RzB*%{LTj`+0VP*_imRM%fa(3%v+P`-Xx6ww% z*1Lt2<7k1XF=VkhX5n7fr`_T!$B3QW`!oPLyW5`^hidX%+9U}`XVuRrh7fz9&WzbL!$}glhY>AwN-wZKFJ@f z2+ag?K@pbrj^#pXr<~y%h6GX&QUpqt$?6l}C-JD*vv(5BrK|?2>v(l{a9f$?EreDj#x$;hqBeoB|-P(?tZ`C)J#qvcp3xrd&DU^-X6+j7)Tt_Ty z3a6_B&@ChUoBr!HON;bt=#xoeqfPj)L$B`))*ky_p5XxEDmTI@Xk~ ztbeemgu=aJtyvb}^F2uMYtk{Tb1X&wa*yXL$PWr3Jq{$}I zO!!?r>3I9NoLzIBDY&h~MbC#SwLC__^UwT+9J)U$+2^TUgEtMN@5FHb!$D$%#X)Z2k z&g$g)RMoOkKE@jNG-mW3=yf%}sV%9*x4vEuczzXmUXbB>w|%s>ttxP<9iLJ87;?i! z#RG&=>SO~dq(Up2IgP5z3O7xso55R-HN&lEop!Boj0S-nz>qOOev~0vLxpEv+_lA! z3&7SQ0capdiJD%Nq(ReYG6e&?mtg_QOsUFR+R1H=w>5B#csRMqT-TRO*6SYGjn|jC zS6!uuIpmEhhLLCk^|%nSmzUf+0nLk9G0{BE?`Mmya?IGRoJXgl8!zULG zK!Nq(pLLmx%7lV?F(d`Q#WrO6mm*Z%oU%tz0sF`=L=*1diE!@!brI4nvoea;n@MVJ z%UiTLIKuY#(GasxFr4<+0yX^Ry=?Fp*W)?b51L}>lRi2XF{7yH=UBTgltk($D*%n_ zI>v<}`$H*Jd(-jsEG9^{KT|lu(PHUU^IBL;6PBJKk~E;RTYo~MQ=cU0fK`x-Qy2N& zo7JL}-~!%HcfHq^B<@dFo5O<{=bq^#?56cTH>>L7DI}6UcOQp4JqP?OgUou!&S4*B zVs2#o%*;EhEfHVFg0Hu{F^H1?CU|ZY?4Wt#9>|W=ZSA@%z6|6kJGwSLcI(Aq(Pk?> zye(lmal0`|Gu!>riPrXSi{(l8tzwxBV@WdMPH%G|f5gg#ta|-u@}mgy!+b`OvN?Rr zW@8Y<$}qFB)ao5;JGwsqt>OnLn4O zIpW(f!yUQm-rRfg<1YDo73X;<^Yc)j1XV!&WOKj^i0zi$^Z?#FhIhjC@?8|C1xA`? z?r?j6;oAPYRbM&b)$8+j6u%Far_bwF*^g@-XJZ~4e84%>vL;cM5tzgi@AV^8Pm|(< zo?(Av%4SUXfv7xpEmd*(X3l0M_OMq^Cl@R%7^p9usvi8k+MqxRPvh%cGOJRzaybMbz zytOP#w?lRzx(sV2ytS%UW;fBbTDLdcV8ul6MYI?JDxkrMj2Oh*dn&fgG-xHWF=l2J zMkca?0u78nLB}CJMTJhZc@I_;Jv{UP)9PVC&VU|1lluCHHf`6)j6!&X#OLN_hYk^Y z!Jy)^bNz+APg>z^fX8xK?aM~9b{+Y)_$7+C)g^}{w1f7`Wuwl}8X^av+d6%rP<4D|LHn2R9$Z;xOP$&8qR?i2H; zY$k_KRjh>G02GQs36!Q*r0&TxE6at(qIcW2xNk#lCdQg0c(WE&W@OEfYK^jAp;55o z!vU>qKSvGb>w-=d&9he1S{WJcYSST%R#cl%l&X6(pW&3EzgAuXA!sOM>CHiHp{&rq z^_$J|A(BV}MR5gHqLl;*420Gg1cu(qy^zp&BD~dVuTIXRpC*_ZWk1Y@$$(KLK_HNf zcd#=faLj9a_wMs`W>T`xWh|P50_Qac9n#)g3x`SbWp7VO$t*2YoKns-rzEfqqM1s& zplBVn7`h{hdX(0-fz78j%u6J*2$}@MDh5DC2_<<8CEnw7*`7~SE^C$%#*-4oFlm{T znk=Q&Sh86TO+^lPh)uxm%$XQeOq5W$xyciuEyCYntFErfvo#>(1D#u|nuC%GMI0Eu zEv8iOGT@0KgctB)Kb=2+KORW0&yU!F`+sok?e;Kv!3>kNA*7~7@^9?zB{)U2w3AcE zq=ojX^(w7SWMr&HLDOwBMA#WH&6!u^bE}%Z_s+vc-tuQTW~ig?kUv|N?p^5tQqR00 z6Hs=U8b|zW)K`8|jZbkIa*mv>>DWg`$>5A#GR~(s9E#hLtjlSzmM2NuUsqqtn)z-ugo z_+av85wdjwlCF&8UGQ)%>YGK9%64L-G7pu&yMXgxQ6Q>?|vu!aOL%x7+KzS zO!zo2SuNg#ERYewv<{Zh?s#Np>E@kV$tJ3Lg~ zWNQR%#!-tVE&$3_M8+mOd2!r8>*$@6UKF?l`D?}xBqJdpPPW^4(+%z%yj`xZB{!Up z2p;4QXb#Sv&bN175=`d!Kt^=u3vNf1K#h<)P$U^1>rG{5AKsC`j=AHUnn$4>qe!M8 z>|znw{UWxN@P#b01B%b^ZUFJD(;4*Akze55{JJMyinj8-rV0`<f^#<`bY+SERyg6NqK5!%q z>e9i=@qeL!xCPA`&GM zGDe^p<|h(R3*_prXD+;hbQ0|&^byS+{jmMoJY6MTB(kLQ%jU&3Dr8f-Zo^|TcUC92 zJJ}&5DHJLKfPLgYhtG-b{y9;4RN#V=+rz4jwjIRs*1GdvT;(S0>zkvFCy<3%C|Z<( z6U9=A2vqZ=PW-g0py{|^&NO9J<2^G(weeP`S#T}^w*A^mKQ?-)YUPRK;RD)I?uYm! z@4~zCTxyOfc;LV^mfI!u(%W`O=kN<+uIBS9$(og@!l}(JQs`1@DfRb(yfqC9aA1Mf z9cfC3E!BY);|p|$Mz$U@w_att$WCbE4kXx}1j2hXVK*k^=x|2lwvUglR4mbvjjAIFp$Uv!FAVhW84Fhx8p3Ew&QJ{HwxRoD;|O9GY`?l zBvcc+of(HeT9iEiW3t_lm;$ z_pQA5*Zrrf$EB#O##eRlK}Br+G{V0F3VvGx@%t@) z8|WWN^m9J@-#7Sjv5#c(Xl8tdjEWj8YlA?xgGOWxVWQx)JVR7uK|(MzN07Qqt%>0m z4u_j-DxFwa?!%#U#WTXb{pCxxc+SZ>GNZo``^*`EMYLnrK!p{nQ_V~ zu#RZCz*ZU~1aVlF`Bi;H-1uO6Jw@N$g zXlhCQQXqObSS1LV1aucwcCrxf}qy5Hm6Tp~Nf^!MToui$ZnasIU zfi)W@RpphsX2rJhvWpdFbAuIY6kyEM9H8of;0|$3XnC=gW=kwBi@#EiUPBei+Ap_0 z>RhSN&cv{mCG7h-XG?WM%66r7MV4W;P|rrAz0wSamEgA}x8Czoc;^$t*>67KC*vvv z*PCL^x{h<39J1iXpo7|ohFsv%s}x?yfvBP2=1fG)4*}+RN<7`$-NpI*%j|Z{)ac9= z=j-4K}b&^d_;6DAw=^LEx+iY)=Wy@{0$s&?T z2^*EY%*iJkugz_|DY*lK4$h>U=X1CN0ALMvj`OpZZ)vn)ORR6fz7d=)@>}D^(`m_` zGX(P2qFLqXTp`f^1cQNeCsLe(Cq;*p~skGGl4_|7?oIiG&_k3CF z?j36R%tMcl$@==q!k!9W8SgpcP z)JD=&=M!XR?c0?y^dV@N5)jZ_h`PEEk~(E+Z0tB24wjl;X*rlYgr-zZ-M3X&GjU?3 zkX}Ka$SxvxbsGgzS&@u!GNxx{YL!g77d!U8eNa^-khB(54uM8kQ>?lt*H{#^x}>KM zB^ZRcCFGDfAh%{3lq8Z86dms6Tmr6grj;~dX1kn}Lk5^O3}D7PHK=2ATg*(@#*nmO zGjk=ZEh(w&r8wTzS96fZ$0?0^mT{VSH*K`G^usePwySQ;*xAx%+-yp2Qdi#Ggqkys zdzO<;<~gr6%2^2|0u&(vK&7_YJmE~wnrf!~YcDiLn4zR05}!+%q9r9V`z>3V+BGgG zUeQ+@r4PwsM4_fOR+9E*=1+^2evNg$t?TOU)s(XqEQiFE6j43J#NDFn(D*xa-6xg? zZeeO3-kh-CCAxX)cb=Neo2BTO@g@mcYc5NMUaF66UE4&>=3QjhJ1g7Uo0aOVrMr&} z%)S~ded)g2y^n9CZ#?AboA!uv?%AF76)o>`%B_}8Mz~i#+J0-rzfRAj+2X2DQ;gmI z6od5OArb&W1EfcJ5o1%{u0C;J{36Sd~nHWE&zN*fkZT zQIu@DL7c8-&K%>NZPjHthU<=Qh|4s?3PGlz;NAs}#+)c&aXgWdI6#7EXlb;DJcNxF zh)^=o$Rto`2Xx8>ajMpYnk#J}Xn34WCeYbIh`Q7*VJt=opwcmf2G9|tLmX6ub{H9| zVr}ZTpwPX-WKm2gjRfuVfe?bmF_I*!Hrq6ekZ93@nW?6+36-U`78HUhvjveNutYU>>wv68=bKcd48gYK3*+xxg zbC(o$nbV%)eTTD$eVKV(bMFXB-1BaCIZ3*Es(YJr-b;kaCw1jlDMSI;yI;nol@Z z%{*~F<8nzj@paUV@spF|hcQ<7JkC5_okbjVOHRBj_nYX?Llz?mIO7i76nx82RYIPOckn|yBfB{STYa$Ir5l1V2VcN}pgBC5FvXB>Fqj4slv?&dN3 z-7_=M-QC^XZ*${>cXbmpWX$p1+ufO&nVsF;-R@hx(>>f#MHOD-$Gz?kc`ZCy#~wJ+ z%ko{NoN`;m*u!wcOD1A))~M6OoyGgxn{QUmG}PNH!ps@s#!*qklxG@I<4&zfnqgEe zIAR&3nQ39Anqw$DN!FJdSZQSpW?@dwIOAD`V6dJvy6;ZVi{oFfxUTBGwA+2%yE8Lh zI6|W_DKos=qH{UaB zPM&>TyN;gcPrY+6eb~YQ5L( z+4Wv;Dc^h7bJH`Iw^w;t+cV4F*~(q&hw7Sl=f_U-s{|y7Ng-I)inO$*%BH5atY`?C z7}6SwHL_I5s$oWD1`!Yq3L`X-%L%Bgl1!5&5;A2)NXW@mShQ_oj7(y~R)cL?$jPLn zY|W)HZA4TS#x^ZeBSmbQQZ2DX0$Rmw2F0;r)f$aOi4%#AG?H#dXX9Uo_{a+hgx*UeQ;fH?!T2n3jB8+xM(wa%A~rUoAruy=9=uoWnn>No zOWpJCkBRdem~=cx{mrk zGv4>#a{syPpw#}u+yLVAA>6xcY#SLp5bzCU&NB+1=b_I!639=pD`{5ZVa{&PS7UMD~3LxY)-km^+FMJwxCyVCm^ z`%J&!+h|XzUKoG!&G(;Lu4l&T@$KK-;^5}PnOOAfSh(+N*uDQco2!{yE4ee`;5%a_ zpSxy*^>Xb=)ZEI%`V{!k_B;(6>K3eTZ+E{RF9VCA)mZ2JtzKEV`5d{o`wR_E2E&2U z@ACKc^L;sM`u=2oO`pH(R{T2ZUA`0kbbsT6n;yHjckE_$ntQHY&aX#p?d4;0H0j&b ziq59d+g9xRyIqb1R5O0{j@$I_<&LHvuLhRS-S0LU9pAyZ*iGp7nOxiqS-ks{r&s>Y zo8d)%aUJ%keNJXq^Xm7wxg9MZ>B9dfM}f}hx${SVizQ0>zYnGD?`xy`|C*+xz0~ZB z6}DYYUnfWW*jzq}zw}h;F;D52;@ zO2b6s!(&mXb$9tbWL(}0t$ru)qI^M0Dqe4z_>T^0J6?{Qf1bZ?@*Ccz^5;5r7c2(( zEi*l$^6SL~%DIm^v|NcG|B2GRmf{{Y-KG@D?ZImpy=%)<`m3oy>MT_)O?3 zwVYsbT^}{X{|XPyvg^LnijihMPdeYLi5En~dA=>L>TlfJ$02R5GEuG849Z*K_fML)BamMgm}>81Yfo4w{c>e9=fGfd5=dGD)$=hfBdA%*$+C&^*d zx`-ZIakrT-q{_Umc80&6@H0IqNMqyr53jcN-_mG1V`{7ae!H;CZolK%^5*k2BT$%5)Le{TzE&c|=o_u4&#RrU@scN0G*p2i%DF3yuZt?h0<-|K!CsP~k% z5HP8`fh7;S3_7^iprrgxy3$d0*FP2c?X2Ew6*ux!g_b|Uj<-7x90a~f1H1tF%zcr1 za3Y|R2>f^=KJIXbAM;_Vte8e4`k0&VVXl(fwN~|&wXN%`ZTIVayiIxkXF7#R5l84Q zG|k5(Mq!f#QLNxzO}0NwO)X)Q)Bb7`@dtodZ;zTAQt&pKzqD6 zuc~3q_Gc)W2l{^I49QO8=#TTNOsO*UiuKdIo1 z)T0p}=hG^(=IH)VqsW*C8V0e?{t$KP{@oUABI)u(H0UiQJh4vQ=MEk;#3tU9|6k(j z4v#*z@5FOUwmj~7ixG8UarISN6|z<{S;YDD$xbxZMZqmoVP=xsYON%4OEpV*V6vT6 z%L#Eyac_{n$F`+!{RQpWezo$o+SKto7CH3F#aup5569WRBwh55+}TT}8k?z7$FZ}7Tk zcRdV4Kh_0rmZ$!*{{Mdd>(1qv}uNYJU-?!}ucP+Hv=6N~^=lt#$*X1k!Mm|q?)7ce6%N0ZD^z14K zw;)6G^kT{22I-u5*~KoL6H=Vl>1?A@R2>8H{5!!2|}X z1cZg|c%=al+m$9F5IFirK%pGC6MMg#ms{d$p!^iB;FajgVvia;y;>BhnGOiD1Nwv^ zfk*ie{EkeyIS=R~A~YfT@|5_{ZGld6!yP1VI0uy)rm{vjJUAM9i^JMK2a@WW5@A_L z>4)_TqPj6&Zick;pz$LR)CmH=ue6q0#w)7ZY6BFB5JC{ao zqw)SClw*ndkMa|R5pasylh(^x3<1B6PLxn>A}%BC2SMPxv53UQ1_4pw0Z|L*NwBZw z8RDiu$}WCYP1l@?qry%{HpVPpD$DiNHlYk>*Pq(vT7!~^uMr;je2BU}yaip_yD%X} zf=#vADO+2>yDore1MGk2qnc-)SzHTmpra~;D2CCJzN*DPb(t1A>Y~(!WnIa4^;Cy$ zLBsnlg}(2i%mq2Q!Kx!5msf#iO(jac--ojgl!H67wP$9_LCGNP~jO+7)nYa_DH+1E}u?OOmLB4z(7Is zTdmJKNlW_ZGoCBwg7bH9OnP$pfg}sfgJT!@AHyDg zAt%d(ysBmP@E(jbl|u?Hcq+_GN>vP@MzTxRqM?YYcH)Swq#%+AeWrJNs9rH7VKq%A z*)++f*|upl7Rj2MW><*kHcf16QM8(5(v>wzRyAo#oz7cE;)|CjE1HsHCetaFOlsS0 zQKZJ%noBcmr4=e*$uMFuGE5muBPD}2*5s|qv9gB^Q zmT9v_+ly{ysb;B~tkR22)@fHRX3VK`EmoG1qb8GBO-yE4C23(8z*=I1QGtyxXt36- zO`1}bnrclcrpiWTt+uF5WYj5@DYi;bQe>pc$y$oqDVCiWsbS$B`Lj||V!aIq5@`03JGYnKyE2oO_YXjyBsPYL?vEP-%dy7%K>?FF=){NTHq5 z?r>#ptIZ-RUx6n841nTWF09jkb+- zEFgu{&~9L&X&k{~u?YtG(1rp5c-n#pJOU2I!Xb2PW(?qGFr_Q&Z$MQ7h=~+%&i_6ecp?#jfJ%-f$G+W4CN~&kusf zE%eZq+S)hIQrDQbvfD?=oAQ=aven$)_@Tn9&35+oQ!cGC)XPp~qFSdJR@J7;5opZP zNkXKa)#kHi+^w}@-P_$*vaU$|+NymslE$dXsYTmXt;R?(Z#F zjWdSz4ZSHnf6aLOAb%O36!;nzkU#yj4ngX$xg96~Qj(*GHA1QwfX{IY1!%?#3>eEf z)ilmufl3Bq5>PAe3K1wm2>J;X1mfdygR6mk>bjtsf=<}5YE@V;lLW~XyAiv7p38ZD z0NfR%0FgI4xIBi`c8g;A+HvL67IC3`>@|xTLWh`#Bi8p&*_v_VupWwDUQ-Xm!~_vN zqBQmh(~K~~;f9_*7uGlE-+DU=zBu)siv%-CJQ^VqX-1o=X~vz$iK4XAjX9nf#T!PN zVWtT2g$2#gCY)x7ZvQ70b4Slrx+lBab?1tuzB&$ETE`|kJvsA_4)QWQY>pWNWM)T| z8e%$rKf>iidY|az`I$N89?V^c*bp*dVGgd~bRBedyD(x(LajM33&XEe%rc~WPy>kW zKsOt^U0NN3XdGzBy`fxq7c=0ui1wqy#HdgO$bLxx!yaV?K(wa&pZAM6B5Ych25E&! z0I)^Hh@!(m0IbwdGX$Ve(9jSXNJ2coY^eY?I5;$T*6r^sz!s@%8A4vF95I#24vOb_ zwB{kWb2ha?G+@-)=4G`)xV$sI@M_y@YHr-=;^N}Cn8ciTn8g@1jzEyg?pZXK!f}}w zaNxMHAuj2GlLv;Ah;bJAUXs`q(ytlqJ&RnTrP@V*_j>Ym(!+5N3m= z#?6<4ilApncOk?J+%5&}WXh1?W|9uiH*rg*yqnFQcRa35Wrz5E<(tNTVX|lKM@%QniytHz=EMf2pnZ9 z1|)7Mg{{CSq$@|55ew19zZEeUfr1XYbYZZ4=AU9L6hiyYNvX7i4m{@bdU1id)EWYd zQq_|_znK-orMa}ywhO-l!%b+04P6Efn6xCqEH~b+M3UyYCU1h~SnrPtxyaT90bq;7`!83usn)*gC*kokes)Iz+5F}X>Wg6mn<_gHWsdGzM z#bbzoOQ^cqgBq9_P&kGeSi!Nvr1Lka#?6$*8G^Kk+#ns@0AUf?FD(LcbQ^>>?xi^_ zTT0)$^bEXeNW2#?bk>Hr;u;#}T(JujT5V#E8Ev0zS5XLT9EVR8qAjzvmWU0lYbdIL z3ZBBz{ypAo71!u-Ve-=vPanY+rjm|;HT_s%3Dr7+&t>U zA{23rgSSU#aBtiduDBiI#jZKs)G-irgEOZyOXa4v&rv7o*r8Ap(o~oI|SQ})b9YqUfZ60P^1m)x;N2*$Ucr3hM zy@kY~5c|Oot_Kg^D>z_&l1c8m^C2@&;3MR^c7RL@BwY7XrtuHW?Q;{axLczAP&*)6 z0YJo?2dExRaZ2NfMux;x!Z)?(Pj(qKi{4)OLelhU+Of!{@QS=Szzg^UOUEtX)p-%8 z7#q(Fr#ii9a#q&X)PIeT{l+slvRTGvNM;wN4pkdN)Zc28Dj1fOGb+-y+ID#!HkxR8 zFB6H{>L+SCA~vOMQmx69lUsapUr#7+)#mED(Ua7BEjSOM(5#Gqaesc=_m_)DkIfkj zBMd}k5F}y=C7aaiVO&M?p#p+NP$^LGPGypor%;nOSwa!0y=IcXH;4*4Gx6iT2xXoy z_-V(&>_^dO&yV9~)A&g{5`5-J%qaK1aG?@-qpVzUCmM0*B;kgfavAQNH{Ell6nL%i z#FlPjV;J+B?>g}+p5D@#_TJA%g}}c7|GI!bFGLXoQ4Z{FiT*xHdGT9e@@=S@i1>0( zyv2RYi;g+ul;ed@IpxR9Bj!`!lo+@^*)P`JMr#k{kAT7s4b;8gf&}6Eh!qq5>R6th23J`)k;z2`> zc$*-INQ`NnDD6oiqwz!#X8l417$$l|VI-b7qKBEChoQ&RAYeNP852x~OsFl1N{9-y z7l49|F8nr_$B$aVyccXhklInK#j9`^uv=Kya*g~AO=%6-)sMA0m@%9av@T4&$0>Kh zB{B=h!@o&j9qg)`@4ITM@ZG-c(M`77YIWrC7@XN5#NWKL!M@leSU}Q)Eia2}C8(iC zpeM$K5+M>fE>CUzBccYpD1o8}Hs+FTlv_8_L9-%k-&0r#aw`bpil9P_V&GXAwjxt` zaZQ;`B(9p~Vv@;;NQ3A6xr*ixnK2xVMg7cP^^z$dgAHs}0zYj0i}=EjFRC5s(IINR_3OAQ6X;!ip?@4({WzddlK!Y@I5ytL0ZMIOv+PZMO4)&T4H9jEdh2Wygzg zlV&1A?NuPgSEwk0;_pj>;ERj6b^vfdkH1)OS`|YW$jpr2Ev=<#qd>?mAwcW|FTCYe z)<>DBb@%=ZC0;m5s5%B42tKSOdZWy=VsYP$}xgFAetUHC*K z9NL3+&9W|M`~nJ&qz9v;&jA)#q;apSVFT>7@>t zDkE1R9+@Qx7XB7l#}-+~!{P8nQANiHXM5V&gyBGjY3@0m5Q#M6jyUN&X~(=tMQ)|; z1W8>d9yq}giJ3e}f+@}zc5i(7@b8|P_n(E=x8?_gd}B55&d7JZsCp5v!ELFw?M$yP zm$S9qX{@TMs^KcQ*CAZRtQOGH2yzH>8b_4O&^HwAMHz0?L#RRmK@FNe2m)H}w4sD$ zSGSK{<1~gyv{ZE{6c0^eN@BtYh-f9oTrq*wAP%{}Y>@Bo@8?F^W2BAL)P4jX5s9{O z#G#NFKzRH?_<}qy5uHeAxzcrdq9-+tjdfTA?-nRFfsHgUSECVuy=efjRH}fQ2AHTU z2#Pj?MhRM!5r&Ld*_vq@GZ_OS<%Sb+#S&d2=oGHJGS7U<5}^v|LRg$CBl6k%a|A)g zfgpXt5)eWNL8piCqEX?4#ww){eb9jMVF+X@Gjv!T1%fpL!-0UbK@kTVRZ$LP6H1Dm z!2<&r#vzalN)-u=7!ZmOf)9Wbo#fq`>%Wanb<1^Bh2*&n=GlzXSE1hL9r{f0ay6%c z3LT5rMeDT=N}Hg-h)Wh+%C*!I1;R9>7_4G2$gshx)uB0QZO;zcwrmjw#>Vn9PCXex zv?`2(4N~C|bpnK=bw-*V`ZaBer_*jUtdWMJ8lj3(7$M&pzn zsu2@oU51-%1~MWjG8R)wn6WdvMr(T7z(EZu9fdU0k+?B;@*TSskdeyjVp)3J2N-P|n9!btIz!x$A)b66Q&q$uFiBN&;6>6rLzdVST#Ovu*A zmqCd(CU7{gt7R@?;a(M^eAR7R!#Xofg-n`BlxV@@FnBds_Z3kqECQxJCmRNL%I3JM zL)np2h-Sv0bZH9gkErmAiSa~={O8j+zP<%WRSpj1%*2eVHPz83 zBA9}v+pV_eQZ{xhT-xQUK}|p}8W`i^MmVSftwHf|;)X6H@n!4{K_0G#T`V-gwzoEx zX{qySJz?c1O@Zq9y-UxzZuy?IRlts1Klh{6BW;IX7{3tbk1DaElc%J&bv9J%%(cU( zJLlC5JbuPZL)-Q%p9nzgf1({x=_7ftGz z)lCDW>FOj&Bwk#l7i=*@MIfAJ7eyF7o0=xFMxdO@)s4!WWvECsMk8i*Eh6fzRNiC< z-2>MugoVB)#aSWg#JG7i%lI(@eI)@qy<@&W%L1lx7n! zHt*Bz{Ch`|rYPQH)Y{Yz$Ztn;JUnj?6EVTG;JY!InK_l-7IFC}P(wro2th+X3Jar; zg`YwSBR%E6j4b?V3H*SMc zS8kA(g=gl`1bY6F<4=df=(FMUeH>Ya7&7|K;`6d|WRr9sj2C!s#E52^QKpRJ4;iGC zQKt7oE~_p{vjkCw5_%2Ni#XDRX~%`(%-uhew_i2eNuJir6dm=w!>kD%G7U7XDySsh z?D*pAETs_8bQB6cpgu|QTH?o}J~0Twir+*>8>{j!xbSWayorQ3OXTu@i4CIld4A}-PIsY1?}oOM%^NI;md`>o{I&!W>3Fs689 zFwTR=v_f(eTwxH^AW&kYfX5`n{YiBYc#QamsaaU9cI{&!{lNbGC{iv|o96nU+Bb&9vnbq6<%{lCpcUqqwAT21Vc@5pWO%h(PPIHdWXqu<|_GaaWI zv?=4vYV!0eZ1ahWr!miM3-o7WAjX;1?WM4vM+HBbc5Eo`zH+={o$7OQN6jpECX{Wx zoXy#z7EYl_cXDDvNwZ;9T+Q9ntfIFZs7o8VF=Ij#duC&0TEbh@YgFplk1}SZ{r2Ms|mklVw`RnGOv3mbn@({ct^FUj~ zA4&>ixjVhi*#h+|v#Sqmz3Tn@)>+=ynU8Z7mL+2;t%64rdD`A@K%2xUMwL;tvzA+9 zgBZs#e+{1(o2Lh%XZSd|UiCzcjNrkc2lGXM=fi zg4WX_TYVWY5otDl3a$-d2#^O5k!fHjMyVc&CN@5&)Jl-?jowVvPbk|PP7El*%q-In z9yq+i4JZ@MZ;LcX471Rp-x_#BG}Fh7IK#$iMrnL>AY&P4hF`D5nqk8%(@Z4aE4G&I z*_HFs*sJB7DJa*U%)p01%!t%f4bTK1zsXsa;^mUHlnzL|SWszf#AD2p&%Nw0FT~_z z(B-!Jy;$Qga^4CoKpFLy_)ML9^!@L`{4P8^JX4DK_3*wNN5lccD6sUwa#A(pF+{p* z+>l$&I`s-lbHk9vn}FDgL$%c*x#H}O1cZ5Zdo0mEdHe@mk zP#R=N%DOCD=#L5zfL}+ZT}k#p==@#>A4|ge{2x_pg#tie_^-h+_j-;f@g>vyN7=ao zNfGmYO+rjVfEa=tUy;reQ*mo1Y6e{)V?eqkgep7MQwk_L!T`l^~DCO8G??eWoQJ3ERg5zo89`LP-H5V^9>1A+YUEHtzoG zOX6CImr*c_z}=HaN?Vpmqlql)LrpD@wbcxTlt*72SPbiks5W%%*<{4n>YcxplYaaP z{@x_gNid;(hX#rdh;xCsLE>K`>v)$gLNF$UR%Yvl4F$qJiawSfUGX+JDpYWkcvj%r zhEXm}N-HokmxVxV0CR&UImlEweM{g%^iP9rxWh|MTs%nG8B?aCNNme}Jhsgx$#M!d zfbz%8fccU2;Q5dhyiA}Nf*yQO2?9ark1R~0jDV_VGm0V67tMnFh)Mi-#5oCREN&+2_0;AxEp&)i3n%Km zBqV6YlBeJxomtD9_=)v zOBp>zj7P)AktCixGscYL4m6WV%{{^qx=x#(rb)z}G-s_CGtaQ&k1>yp8CBmE_rpFP zJ>Mqs>#T4DLzZ^qk% zl@D~gd$25tG4T}Pk#m?#?(2?Apln(bD?CCM;bwhU%rs?^%10p~Bu0uq1VKpM_?NN6 zuNI7p|IB=WtO# zfmMkUk%%}TBt(6_;eiBl17M+?Sse_@)UkYwi&`#(HY222wKjt#h{z=oH&A)PxD04Y z%Cwaz3AID#-xjvkVsK7}EQHMMixYnUe_^vLmJb4bOBEI5Z#u>LETL{j@%fY{e4y&wL0+} zq9H^g3j3Nb)$DjlNmMlm8h?tP5^oqXjVQwph8l76AIy^rtJCG4sVm%d7Gdzxix7=B z!oBhE5YHYNW{lHM8c6KZPjVLNFW$3@FtO2;jWqV2JlBmjsGpaPnMGWyI{kHq@&_sz%PD63T zZ_QfM9*zQ01QuE{L_|?xV>sC;&z}!_MhKTOOi6;?@%PC);^DM3(sbnei~D^Xqa!{Z zCO*R^?cw$p*_9K>-02qbWu`Znmb-!m3MhufjSa*uV(N;ZeCf7_0*rMak#t>+Oqc(T(NJ5p6yC+n%i30XrTvAP|YkoF;gRrcVOfTqU&Ud!{5*%cH z0*!#h5K)B`BRqVfejg%6S{To0A8HSTLiQQ-Aw;Jm0MtwrCahi)Di$)m@2-`2skop( zD1tI3u@xb~K@XF5?449*EvBGp5=byj@(luG$-+W`Q z2y4G5fkxYM5gW|L)EwHHf*J@?kCqCf?L(%+h0TnN%#Fr|B3JQJaNMrryP2UI^^2&wbM;4Qxf*& z%o>L12RCg{@~9MiUq;)vcC;RDFyE2Hh4@hdaJG;{3kI~QnRMklp$I&9;rt{d;zhL2 zA}BbbLK+MiUB1E>H8}%{A zn@u^H#ksl2omed$PM1PSVGQ93B$3Erb9f%lr|?AtN5kX>W@e-fjL1>3Z3kVzM*tGY zySCPyhf_0XVg(xzzU_wzhyfjuCAV(Ww9(AyNO6P=D(ecW-&!S5JJl$`Gg~3fIpMpL z8f%{;o}0oG5#VxqvzCgYMh5QkF^$zD9EbkzfJu%d3fm^VIW7l{9N(7+Htnd~qe1VTK%W#uD(cvDWX6H`XJDZj5H0Je^6)$VU`$K1&Z8QR9yd*`}Ss z5k2j9bYROkvO^viVY+ddC6aotKOve%?kV>C`D=aeo;)DL7;xBt;q&wA4B$;|r4kU_ zLqY``8_Us}hVlb4K>(2eoE%Ch@3N1@Sa?Ul9}X(-sNRslMF!bezZWY+)ZT9dxDY}R zSVK8-p-5cR+87{iGh;|D;t6;%Pak85KFBkf;RG0vp+X@fqf-~gGBCtog9$zn^YSdR zPzj^t=f!8k;2|)CBra@TLOB`iQDaVAlVTeZNU64jiIFkR1}`31DB?+z3H!eC$kGAeLO@40L;{5X zG?kU=BqXz{jx$crMM}jwj>7T~C=RQKDkgXx#=G~~%-w<~z=UxSKoDUkJW1)EE>4v7 z=n^W?b1ZIMmPWirA*R!lpyTdPP1>@WIvhG%I_wqla%6%iLfjIf}4krVJB zM4umChwCTRwerEeA7%)B<{)v|T;&-zA3vq3vShcUJPB4$UQgPY%5L zxPikg&8_0LtG)Du)RBtHQe_in%`;7@S#2t1X{of$rqPsTrIko*sM=dqn|JG1Gg6fn zsL8RYnKqin#ba5SEfuttrCGHtO)RWdqNyyV$!RoNERb7b(rZ@HZL3MEXxdq})-AT8 z){SdLEWpgAGRr6w@r6aZ+KcYxYAV@OvZ=IW22q$y1-7XT6-^+*YGy3RVMUZo1*kGu z#5^$;)?tbGN^M71|ReJzF2h#aC`qb0miqSXYpkDQhZEz+_ovM)*ly z=gLO}(rR+5-6fa*Ih8L{vll45Dde zL}vjeko8A}IZdfe*tL-P!)&clZ?UCwIL!7os{OZ$)ITaYV0ZIBd6f+qbB;Vx{z-PQ zzdEYkk9jT?LsdrQ$5_VFp%j3rRUwFP&WtcAoDaM1+1w8)J=A=hhfjlKBoOxE;0Xlx zy8*7^GU&}HH?JsBtt?(xt>KA@n~KOkzRE=VcJTPEeKdtNluQrm@CF> z(7(<*4qXi%k3=&cIbiNh)(4mk4G<29obVy$X=4#bl*Ju#g3u?E zB3m?oRRLc@nM#s-PX`k@#fY}GXbC(^67%Hwxm4gzj;*SWjz5dRdZYOzhfgoh>CrRC zqJJkF6E%7mQMMrbOY_O#{B1sV1TQ{n`tcKJ5+aS13q)E;_t6?0>OlvlB9#5bQ3Wkj ztM}0)m)IvlIivDPrkg)6gIL*b{clk>gh3((79$aYNRIex5cXp=qU5$;sSOi!emOR@ z-ODJ(2MnfTF^sb2~tyLo_Z!AWVmx~G-%2wD&@XEO5Byq(n z!xELlF%xttkdNpf)KNhBaaH7k1cHhi41^Q!8QZ0uw9?Jm>OJp#m?pMv=Bp2{m9?po z#C0E79a<-Z(T|nQYX-<@8k!0Jm6mui4VLz2>X|tYo?RRWN$ZM-$%n*Mead|QIRn%r zh^Mu4d`$D9exyCPopYLduu**APTcMEbT&l7ex`~=IeXpyaHW@26=E3%xmQ>wI*o>a z;CC|)QYolvM3&g3t3*f8^+cJOygl{Xgn@)fOz2}e88hqDe?NM0ZP`$^&)-lp%x6oI z;E{dCSF^97P>xy-21LCbN|o*El1uWsF0p3L+b8DmCU}uB$oJ_0lRmDza|`j@0M@m) zdKTNyCk~V>;?lKR-{VUA=Eom}&Kt-ss}VZk`ibiB3wqhEAPW>vln>a~S9kLIx>lS& zr>_EA3iW*zzwWoH{OjxC2E_qj-Z^x1_V#MeNeiLE(BFay#Br-YCscY7)lg5OA?QF*EXX>KTn0I(E4`yDaQD<$dFL(kj7{Y3-jR^{@*x^ZsyvhRRl7V=xhKbq<)n z3w{$6zP-hv`>yw9ll7kA&dw@z+;A*GHU>HkH+!m{^y$TAxI+<$C7k>@$`2Ayn0$F$r5IbC94{vNVS_Z)M=YhQfS#07MRLLn3Tkc5vi7n zEu$9DV$^9c7}UbW02s4Cw8@FG&4gvV*Tio-ZEtP_ErvLQatKp|kXaxbZpP64%OY=o zMPqJc5T~WZuTVx;2opmH1d^WgUl}4%197}m;w@}Q>#{SEt>SkS9UK$*b?G1GDiqxtn?i7 z@^S1nBbAV&F<7DufC0H^I%a&#tj(;Zw3h?Y`#ZZkcA80Xs8?fZlG^ zRNX8=U>HqqA9zcM;T(c4#eiM5D5(bb zW>Gq;#B`1EA-{;A!oy;qx+-?*J5y-+OCTeem9m*!jQf15Rr7P62VT#!LcA*F@*}DZ zz^V83O;}$)(BvcQBN*cd(&g>wu7}V#Y{y&Zd3B2#K) zRt70cFrZ*8l(Lk<7WkG=rJd0(Kuy2)G#z|daG?q&wSgmYiQiUKF1bnyj7XFiA{9{pg)6~b z7ccf9AcTY(Krc({>4%kFu306nl{oL6XcR!+^kKpq?;CA1ufi&aKJAqz`&6q)kGq6N zCqACu^U+Th%C1RmHK0Zy#ab<58nR3RlK!pMqIDVJ)_XdwTtLDMt<1mHRQ}30IDEmti__9_;DHz7iC-iYYXK7a? z%naw8Z;xdg#km^9qKhIeKvwz$Mk;;BOr==_EC|RfRDw5hg6e07WA_+pTAn(`O+9;hJ=zpVRZ$xc=VH`NT`AS%U zgoO#FQaAg^p}H#Ag4|F&*pdo+cu8v?(#2N%8i?N!re#(@ow^2r)~QdAvr)4$%vfeZ%!0CID!kaLa3sizZ81vBl~}BWGMHUb{^N3!_At2OgW1Ij z*BvpE4^j5g``kt3nKTt2k4y&>(JJ+EB44b!AoHNTo={CxZLd|;)R})j7lteQf86R5 z@$ySDBgu%J*?uNp*W#f5{}f)&eLWtZ-qe2WE-!QPKZ-Acr=uf9`+T*CaZ6oN+lOAg zGqROK1NJhfJUxuB@G(7He+L0vaYfOGt};GMsWAifF-6frPMhBqTULh;lP|dxdXy!@ zZs%enp&C{(t&z*UR0nHi=fKzK4<~@Hw|?s!{BzR5;4>sJHu>tGA;z zP&JBpp#H8Wx4x89k_w)r_BYT7S|R<`B{-~*-zJt%1{*M}85RvDh=BsuELEaF2xOTt zButs23^OY*vnaO67pDMSSxUEJQ-y+qf|CV&8CGC3C{36wVoU~0uPZXrvZ^(WnVA-_ z))2mua7{|8+Zn!UGY%6Kscf|?Hk2wiX40**RuvYqJ2kCkMzx|w(#tU04YIU>g%(ON zGPCwQ7lUdY3ldw8-)CaJAp}x^abg>A00M2=-;Q?@q zvS(df7C_*XMLLg?(3rveEbj7r4tnM|B7R~VK!S`zz$jO#VG}QJqtDaa@jP9Y&zbG? ztIy2g^&gGLiNGdB55vhc!)>dk){I8B<(8>7)w63DOBWKdOoqMuCFD)oRb@)kl`&pgWMS!Cq0!3KXjZ$hXVar>_TU4^B$hPM7C3iHo%3tSVRQdT8^5sXr zlZ8?-UYZS4y0UGR*678lH^VTV-dtd1^5Ho%5gCad&M$(%kKB3wB^1)@m!Oe1{3G!W z--Z-5RU#6Ks5C4H!lgi?2*@5K#havxVPpn^kr6m5*(+(WjM9y$&P5iv7E!wqwotEM0nR4V*nV!rno02AIb&&!_M36kSP=O!^YwbNuyTF7} zMxZF80i;A}u@;SJG$8^Qpa@7Y7J#U&0Thx#5-5<~BN_L6dFe*T zz5mHymo1DcXe04H^stY!u#bw)!d6TMe#Y_+YK-s)4Kw@Cmu=8~4-RvEYm%d(iE9%4 zeHs$+)m$bqwla5@pAA)0nMMJHy);fDT>yM5-^ykS*2y|iybQdc0SZNU!*< zxQwnMCW-AG(=_?tnYcCZeszPY=$P-PAHB^+7beT)CWm%Yx8`LYoKM@O%gw~?i>)oHyh&#Oc>cF!Q=gEHL&mY0 zn9R&%-w~i-^TSIJ<=$L9sAKtkNGX87w{SIfq&>_RwqRc_16X05Z8f4yjOp<$J#@RQ zm@x*z#JeJx4pTsG^3{#WTN5=hNYJ8PFY&e1D22&ry%7{Vs{~?235H^9%zI5suhcE& zZ6wSGD#Rx`V*cO5iEQH&0%KnwML1E(NdSS_X%4ErK^a-GUyID?!rNjxLA@J^*)GaX*8s`he(GdO~R{5nJG{z6*V|NPGBEZJ%4#*R<-uIl`Dp?^TqRy`sKN zqt}_kDN25IK{C>;sm~=|q{uoia~XzWNaYC$0C6hRqLMJc!l4xkvRP>jEjz)3f#VOa z$QX}$9`tP(LzlVhe9VLCM8B~B16eHVh_9|8lYwy*PhzzF%@^80t#IWk& zOKA=aZJ6oNSgRoSKVKhi4jNB!`8OgrVIPU%(Yuv=9b6}}VcpPP*#s2*=c`JEhqKJL zd+LE$7!JPonJUWZgh%c&DmIJgvZRj%X;#+eP5Qx@@w^8Hn8k z+bd&ZN{lPCHbe2Y>z}p5b7r-viG(<%ki?aRVv&tHR-e?t{s;AxmqdrB75{6+bUg@; zy*}a!pj$h)#quL!gN)`<3bq@j_xX?a8gV(X-pg{w?l7`OKp2A`Cx@X=;^!<*c%m-* z4ZM}qsFktzHoEXfTEHRfBSnItIarfH;uD7Mb2^wA41-0Ie9WIu68gFOoXu!!D81Z4 ztfpj+n{kM@f>rG+YUxmF>3Hi~bp?=+Nd;sv7U+i*VM>8=D7&?wZC3M8+X~EAt%)|6 zCfTu8>9s^{V{37!)m#;3q9Y?B6DENJ%!fz+olj(boispz?Ha)zr`k&=jZ5o(<4U6T zFsXi~MqytMP4ss5qq}-a%fAgEaH@*~5M)qd3?#8&+;PJCdi-xlkbtN|?q)Qk8>1qs z{8%Gz&(J@$hymoEtbzFQQt~=KDe`WWU1og!>PLQl^Eb!Gy(>zN|Lo{aAB@53C&P>1 z$wp!+$Q+cOj1MkVy#EKfB>R+=%J)8h?CJG>_k|37O#Zt3{eS-8c>$DLey{TM^9lHs zI87GXr+m*sMH@B0>iJfpyXHu%LHqoa@$*NN=9WEeE4pAkye|CzqmrYSL!r^Sr|29S z#I&XZPyN_b9YYBr9Wp|pk|erzNd;OCnWSCps&5Zkw7MC6W=+iwt4nr3JvcM=CpG_d z@jeXH6Rw1z0n#cAhvh6AQ4pGY_Y~jd4?4nRftWFWH7b}msgr25jftw87F#nij$fau zKaGOhqo0n1@%eZDQgZdV9mB~FXr`v=4pWcKysueNEBN*GCwtHC!#H@lBi5@j`-@45 ziTT;;`Cgqkb>1j>|0euv-Kiyae*3u(FhTp=s(N6|B**abR+1zx^@#J*8uyWS=Ebr; zc~*Q`+Bsf$sw)mL_3jyE0nLid{+K#-b;?k<~U% zIkHuja%AzM<^0#E`RRS#O4Mc$%cvShwTAle+m_`tgl1@rK zybPtmISxfyGHzFaZD{J-k7%rClhd%? zo{RuLVJ#GqBvl=vi9$X_Ys0a8Ple{`Sd3C_i%@NNF6X21)o<~&igMHJqs0f*NPuhh za3Fs#0x3;S6YcBf)#@co34=a%6+fGtA~EYq$y8Dgvndgl{jd)z)%(wZ5J#7L7!hIe zGiK$&LZFDlSjUp90uZm*5G{Hl1mvuv1bxzdB4|y%&w$&YxnEv?JB2ET^XXJR%vALA z@9}*nMmPV#^|k&+d2^;r4qrq3-;Vr0>~xZGCSpB&rJ(zA9vc#P_6^nNEUVNk*^g4~ zY9_zfrPPPj+F378$#mb!vBEwq zf&I=x5AQKjdNbC`8tQG!BpFupr}jcTzt?{Y_&3avh{hzxk0YVc>yrB-9zSodDH%-c zR|2>;LO)X#ep0fEd}!oaLy3f$wXuz=v1dg_3VIcEa7cZ)2M(@pgYy=eXF0=#1&Ss^ zTfViMzjCX{lI+DK6Hhwoqw2sDwUO!76$+GQmM^Bjmv$CeP|9Sa@?p~?eC_nZi^QO)x&C$LhwQIZnrZH>KNSEW*UhMr8V#6X2{=t7`&`&ptdV9O+_}=AO3d zH;+rLJ?ccIMI;1O@Z(-?)CY6)l%*c1hVj&^gKBUrMR1j6Qt!o?GZxTqqTTzv(Plpj z2s%(-dDXEF9_YU_2V~{s7adOB>a`NqVnn zL`D*GRk3DjCJkcLhLcJ(Wl^$fS_6iX_qI3N@wU`!me0@S5j$|V<58|Sm}Q>!k*#ZF zu`*((=H|50J$^fjWV$r&Wf$mSx>%O{G?oQ1R@E_60f}J{p;SWf8HEgLj30l%P5L%; z^&jq^LC_945Jg6z6Vp953_o4fN>Eo*OnEriV;;TTdV58U#9^5JVYuWj?iC`5k^Hn#Ou(L?tA(wKegYt zV!HKHRI?VOMw;8Ur*!ssNmtSP9N`!?<$(Cg%ABK~M;MtiyAu4okhy2(WlLCQP><5d ze+wxi*~wQ;kYd9YOS)Mutj1A)KYcf-`(3e5rxe7CoKL{iK3a~*X^HRq9WJFRn3gJq zk}k;AOE_z3b)}nS{0t|~u?G-jz+z09B;tg@FIOE|zE_t4@MIU!$Mu+AjFw|8%=v|2 zpF^qBUxbp6FXNC5w?hbQzD=W|F*>d1i4a(7bSb-=>Ox4RH5rC)T*6{(dFu{Cy5N+R!^prNA}a(kqrqnpcms z)4iAG_(wVIReh+jN}=ud0bcB6lznz1;6iz5m*e6*qw8nzvuDYg22}8?r=XBs1%2iv z-$G&)zt-`d$JAVMUM`b(M&F>QmFnNK&%4;wMfS3mG3cIu$k|_qlag@PavG}l@=Xb5 z-(MeN-PL;;A7AV{=oycZzOmBBP9OYp#}ujMd}$Z)MTtD~G#Ba-LclJa&weeZnkEeW zL|g!NcrFRr+;{8krpc0|{YW__;+E78K2lZZ%C1R$EQ;}$QPz;c zc4hH&^>$VF-WSh`RN(p3ogP|$gTv?bZ;B8Vk>HUPXay&keJE)y>Qf?$@N{ny0WyWfG@z$Y{KnGF<=U!gv< zzL#VSr6~SZJsG#x*O%k>)e^d>NyfbXw%cP#FjaiD716nhb4lbtbBt2LV3UoK46;Yc zYrYq&oJWx(wlS7cPMCb@DteTDj!^lzOV&A|`UIpmL>dM#B$6Q`?$8Ky@vlg=er6Q7 zmKGKYVPXxl^)TBXQ`FVd(7%DRS(%4|US~e(?pp(nRR8CcDE>AGevb(LCVcFwhw0*; zsU`10+Z2A({%%?Xy*Y8}_(~nyd(}kS74i8iis4Ux3cw$cl$^MfJ@A*{Kpn`UvMT#< zI-sbT@zZwy#gDNCXo8s~k-j)ZN@X?bY?raT8pq3(<7BG%vI_0Us`2EN--SrN_bQ~V zut9d@9T{4|k8!OcUFw2OMTm=Q7TVR~R;W*J5Y{iEx7NG(!L&=wiQ$Qulm^dl7I#!3 zA*McT#qnN-T>p*0^Zp*($idYV(MUqP2TOc&gENeS5>%-XfbGr(V~c`Ac82U#?fsR z5NM1=8X_YQV#YR&V_G6HpuvbE1OWyh&;$@f0YL;%5dj1QV2B_f3_$^i2!JApG*JKm z07L`;5I_+G000000000$00co0Mgs-{0Dv$>0RaJk01N;@h`>Mu0RRvH5MZFef&u^l z2nYxwAOHveAc6n@001ySg9KtRj8TZi6aYj40g56F5kN#>)J6!w1VIEqKwy9 zA}mG)*u-pTA_GRm6a)qWfB*mupbCw1obSB2^AJ%|2-|i)8^?0kLG=EP zd&7cGP!#A}Q%M}*Uk>Kh)l<*P^IR+%`oTaHJmcUlX^L6L0YNjx5NgWRc%8r7d}ZjF?@R3CktJ zEX606D5?JY5>*|zP>w*#N$X&T9F1gy^RlWpd-$tE`&@XuU!ALDJCdt6{LR0K<#-i$ zN|bpDvG_`fU6Hgt=1J5z%$|+9Q=&w-mAEs8we9iwD!P=a8Ny$^NO5(lC2*CjUWz73 zjG}vZMzWOq8D>txNTC~q85rDSkd8GHUg7WCvXNfSDoNRbk;4HUc_}ODYnYD9te*oW-~#d9@&RA)lNv^ z$mOc;-8^Y?HmI4)`nNJ3|@ zg{6tBw}1!&DS%U`*^6zZmAi&>Xd{Bi=zSv< z`JbNbwI27rT9@!VNDzg>NWVV`bj*Zy=+wgN!io0rNjkCt ze+Lv1xsu4j7TASaODdIFk(?^-X^Cxm!Upn}HAdT66Jk;N*tG}2iiaFjSG|i#cPcV^ zEO{)mE>Siiy`Juc7pJhw`Ya>$HjMS9q(bz~W| z9g4d5&in>?y`2$v22ABnhnoY3;Wd>pFN%eN$%>;Cr_%Qu3b;j3@YiojbX1?F?}|LR z#fppuWhw1s{tI~1qNh$YRl_p_;lom}u`|`ts;pKO)$q0hhKTDGFK_|inup#x+iG8K z=OzrC0;U+&K+qi?r7Mu8@lh|O&nJI~9VyEW3|@~$Rbe*TQ?nDFgiK5I{bZ=dbvtX10b3D+A6Ij zh*Im#XZpWCtM{Deo=2QVJYZrNj3W_<#9}s8s*i&vVzU%2@HfkTirmH0Rp+AMTxGj| zhvsZG2Zdxaz$YlDl1tAqLA5Mn1!SycB>f&Isk^BzYQM_D%w{QF8B&Klk&BlOT%U^M zy|yUKE(?FOdxpz(E`iiiEYw`C(GFZzoGczV*NR?`7t*sYz zs=Ix?y+ZQ7#Btt)jGO`rcEx~?+r=*ckQFebxr!>P%qlbrCRm|F?Qaf%>O=_vA3Fp` zs4|_@va5s@K(;yih5YJKYqov&VMK}Bh%5SNk2DYmulwpl%f`5<{5#9O64F{#lok~-EF{cmvMnW*USFZzy!qI6d49*FP1197B82P% zu5{Ba7DCKO?rpi5?9cL0J*>wE)EVL<f z%hKxQ@5v&?8)apdu&HWhl8t2BN=#{EM3XW{UdZ?{TN|;LQ9PuS_AlK_Bl{cy!;K^c zM134jupwjY^R@8+=efFj*lq30S!?SPx$tA($urqAv79~6xd8zy2-NrD0G_H)JreWS z^`+&eRWg_BOUu+zzAgHEzG+ux23b-3oB;ayNL^Fn%F#>o@elmJeWbsS{0$`iX)MZ# zf|C)HQ{}1dUr*EBV=f+*516x6ItTxu4%UT5BA>rilA0qIGmARg*5}=dmcdfMvC^?5-!m_$spU@r311S zhlW>w_!Y!d{VY|k@S(wiy2$l%R8zksk;HNRE~8NM{9l9iH`zqOcgNb;M28dYmAhl*04b+j7;1rLOQBBoEV zbS^}MFXWj(y!f?d)A`!)&W+!t_`WmBB5{zPTM;kkVGgWyhzTkfSM?E6!azix2rGHa zaCmubdNFfS=2nppHdwMz5%=IU=!r=qE=?=c-3~|gynOu+z*LL4`xkO#Y-x4_GH5S^+MH8VQ{jm!u z$K6pVM~OS2gZnsvL(GI%q2F(I;Idvi>HBM2d@-a3n_;RhRt)!^xv&Ek#{7 z39#kSq?(^syT!S4oDzz2$?@?`c`~ZRR0F*Q6a$#)_x=q1ec-)>4s=*I#emz)-+B9N z+a&$7=+>(BWtbvG6$>sWKQ(*~;+9)(pqo$oR6OmL(iR;QgkpjLb~R#SF58 z2pGc_FWY!b+S*(LHpIg+VOqGg>nM7YK3RcRcK}iC(q(Xs;OLwdS2jbYTb|Tr5 z5+pmn1%gf%P&zY(FT=B=^#45#7~73erQ3w?nlw?*YHSS zI5b1mtDf8xjd1LR6wdw`10ctQDC2)a^iX1d0pj_tme{hw*R;WIlH} zk3RoG#bD*5dA#v#06j2xs(Cy4jgQq&dd6FAUu`>fiCW~s@Qx&L|p7aiQ`6A~5-xRzTDE<6bceP7s8ApT>Dg=r$2P`>g z1bgrS;sGMJfE&JrWZrelc`r~$d_>_l&%xTc;)p&dsQkDGYA@Zye8NEJ{wehH&^^_j z4Z!|K^r8dE$K<#Xae^iw3~BUp<%<`@e1Uv4DNnhGKO&XM+*L%Ag;zRM zB7x3EPAhx2I?v;36HoqVa(?ak8tY_^lTS&GLmsQ{_K@f+%@-aeL$MrZzY#|VlCy=a z7JVC-63Grbv19TgpbTTRR``t#@&LjN<<411jN;FARb*wWxYI%7T2HL#WB#vgZEhq>xi|`5D9Nyayz2$k8Z33;8mQD zrEQ(vc8(GVOyD!OdQZped_p(?bG~c?ukSLxe2B()^AZXTx}&#G1ZZ;H2fAX@53=og z47X2h&4(6v3$ZBv(upJK_HGq-lino5B#qoXM~MRy{)q7%Q-enSZo4KydW-`a9El(# zewCH$U_lNixIyRd96jeJ)KwxAh1K={0s{GZ&Z-ofeXQE&f*$7xh(VaxsZtz+J-NjJ zFN3c7{sWAu4{)5pe_Pxfz{E&dQM;#N^iDP%W01k&njfhPdtZBypC_P{2Oq$#>|f_G zi9dVzb)rQP0K;GeKX~W}{G9VFs30;t5uM(*KzlA2joSan;g8M5abf~NX|p>{bboBm zG2FXW*w(!4E}4y$)~_k)HD)+jw5RqRRCV}yCnHsK(*%S|&LA+%cR<4mgy`--5a8I| z8F(|G$(2(_cj7?SV;E;0`+1B5|BD^gd2T4!Sl)3QSq~0N@!0)MX!M*06NfKD1Bu;0 zU%;3IAus62&v7OX%P31vwRiuR;<7g;o_NP~46;QwAs^JCN1mlXf_yOJrwgn$G3 F+PIumkAVOH From 0d4e4090a0332a1e5314f787f6b463e43a805e00 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 30 Jul 2015 16:53:27 -0600 Subject: [PATCH 009/131] Massive reorg of file position tracking - Should make iterator errors almost impossible in the future - Fixes tracking of current line number --- .../chaiscript/language/chaiscript_parser.hpp | 659 +++++++++--------- 1 file changed, 340 insertions(+), 319 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 089ed7f..a2fd4b1 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -48,8 +48,6 @@ namespace chaiscript class ChaiScript_Parser { - std::string::const_iterator m_input_pos, m_input_end; - int m_line, m_col; std::string m_multiline_comment_begin; std::string m_multiline_comment_end; std::string m_singleline_comment; @@ -60,12 +58,110 @@ namespace chaiscript std::vector> m_operator_matches; std::vector m_operators; - void increment_pos(std::string::const_iterator &itr) { if (itr != m_input_end) ++itr; } + struct Position + { + Position() + : line(-1), col(-1), m_last_col(-1) {} + + 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) + { + } + + static std::string str(const Position &t_begin, const Position &t_end) { + return std::string(t_begin.m_pos, t_end.m_pos); + } + + Position &operator++() { + if (m_pos != m_end) { + if (*m_pos == '\n') { + ++line; + m_last_col = col; + col = 1; + } else { + ++col; + } + + ++m_pos; + } + return *this; + } + + Position &operator--() { + --m_pos; + if (*m_pos == '\n') { + --line; + col = m_last_col; + } else { + --col; + } + return *this; + } + + Position &operator+=(size_t t_distance) { + *this = (*this) + t_distance; + return *this; + } + + Position operator+(size_t t_distance) const { + Position ret(*this); + for (size_t i = 0; i < t_distance; ++i) { + ++ret; + } + return ret; + } + + Position &operator-=(size_t t_distance) { + *this = (*this) - t_distance; + return *this; + } + + Position operator-(size_t t_distance) const { + Position ret(*this); + for (size_t i = 0; i < t_distance; ++i) { + --ret; + } + return ret; + } + + bool operator==(const Position &t_rhs) const { + return m_pos == t_rhs.m_pos; + } + + bool operator!=(const Position &t_rhs) const { + return m_pos != t_rhs.m_pos; + } + + bool has_more() const { + return m_pos != m_end; + } + + size_t remaining() const { + return std::distance(m_pos, m_end); + } + + char operator*() const { + if (m_pos == m_end) { + return '\0'; + } else { + return *m_pos; + } + } + + int line; + int col; + + private: + std::string::const_iterator m_pos; + std::string::const_iterator m_end; + int m_last_col; + }; + + Position m_position; public: ChaiScript_Parser() - : m_line(-1), m_col(-1), - m_multiline_comment_begin("/*"), + : m_multiline_comment_begin("/*"), m_multiline_comment_end("*/"), m_singleline_comment("//") { @@ -284,16 +380,16 @@ namespace chaiscript m_filename, m_match_stack[t_match_start]->location.start.line, m_match_stack[t_match_start]->location.start.column, - m_line, - m_col + m_position.line, + m_position.col ); } else { return Parse_Location( m_filename, - m_line, - m_col, - m_line, - m_col + m_position.line, + m_position.col, + m_position.line, + m_position.col ); } }(); @@ -314,34 +410,28 @@ namespace chaiscript std::move(new_children))); } - /// Check to see if there is more text parse - inline bool has_more_input() const { - return (m_input_pos != m_input_end); - } /// Skips any multi-line or single-line comment bool SkipComment() { if (Symbol_(m_multiline_comment_begin.c_str())) { - while (m_input_pos != m_input_end) { + while (m_position.has_more()) { if (Symbol_(m_multiline_comment_end.c_str())) { break; } else if (!Eol_()) { - ++m_col; - increment_pos(m_input_pos); + ++m_position; } } return true; } else if (Symbol_(m_singleline_comment.c_str())) { - while (m_input_pos != m_input_end) { + while (m_position.has_more()) { if (Symbol_("\r\n")) { - m_input_pos -= 2; + m_position -= 2; break; } else if (Char_('\n')) { - --m_input_pos; + --m_position; break; } else { - ++m_col; - increment_pos(m_input_pos); + ++m_position; } } return true; @@ -355,25 +445,19 @@ namespace chaiscript bool SkipWS(bool skip_cr=false) { bool retval = false; - while (has_more_input()) { - auto end_line = (*m_input_pos != 0) && ((*m_input_pos == '\n') || (*m_input_pos == '\r' && *(m_input_pos+1) == '\n')); + while (m_position.has_more()) { + auto end_line = (*m_position != 0) && ((*m_position == '\n') || (*m_position == '\r' && *(m_position+1) == '\n')); - if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) || (skip_cr && end_line)) { + if ( char_in_alphabet(*m_position,detail::white_alphabet) || (skip_cr && end_line)) { if(end_line) { - m_col = 1; - ++m_line; - - if(*(m_input_pos) == '\r') { + if(*m_position == '\r') { // discards lf - increment_pos(m_input_pos); + ++m_position; } } - else { - ++m_col; - } - increment_pos(m_input_pos); + ++m_position; retval = true; } @@ -389,29 +473,25 @@ namespace chaiscript /// Reads the optional exponent (scientific notation) and suffix for a Float bool read_exponent_and_suffix() { // Support a form of scientific notation: 1e-5, 35.5E+8, 0.01e19 - if (has_more_input() && (std::tolower(*m_input_pos) == 'e')) { - increment_pos(m_input_pos); - ++m_col; - if (has_more_input() && ((*m_input_pos == '-') || (*m_input_pos == '+'))) { - increment_pos(m_input_pos); - ++m_col; + if (m_position.has_more() && (std::tolower(*m_position) == 'e')) { + ++m_position; + if (m_position.has_more() && ((*m_position == '-') || (*m_position == '+'))) { + ++m_position; } - auto exponent_pos = m_input_pos; - while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { - increment_pos(m_input_pos); - ++m_col; + auto exponent_pos = m_position; + while (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet) ) { + ++m_position; } - if (m_input_pos == exponent_pos) { + if (m_position == exponent_pos) { // Require at least one digit after the exponent return false; } } // Parse optional float suffix - while (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_suffix_alphabet)) + while (m_position.has_more() && char_in_alphabet(*m_position, detail::float_suffix_alphabet)) { - increment_pos(m_input_pos); - ++m_col; + ++m_position; } return true; @@ -420,30 +500,26 @@ namespace chaiscript /// Reads a floating point value from input, without skipping initial whitespace bool Float_() { - if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) { - while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { - increment_pos(m_input_pos); - ++m_col; + if (m_position.has_more() && char_in_alphabet(*m_position,detail::float_alphabet) ) { + while (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet) ) { + ++m_position; } - if (has_more_input() && (std::tolower(*m_input_pos) == 'e')) { + if (m_position.has_more() && (std::tolower(*m_position) == 'e')) { // The exponent is valid even without any decimal in the Float (1e8, 3e-15) return read_exponent_and_suffix(); } - else if (has_more_input() && (*m_input_pos == '.')) { - increment_pos(m_input_pos); - ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet)) { - while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { - increment_pos(m_input_pos); - ++m_col; + else if (m_position.has_more() && (*m_position == '.')) { + ++m_position; + if (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet)) { + while (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet) ) { + ++m_position; } // After any decimal digits, support an optional exponent (3.7e3) return read_exponent_and_suffix(); } else { - --m_input_pos; - --m_col; + --m_position; } } } @@ -452,34 +528,28 @@ namespace chaiscript /// Reads a hex value from input, without skipping initial whitespace bool Hex_() { - if (has_more_input() && (*m_input_pos == '0')) { - increment_pos(m_input_pos); - ++m_col; + if (m_position.has_more() && (*m_position == '0')) { + ++m_position; - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::x_alphabet) ) { - increment_pos(m_input_pos); - ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet)) { - while (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet) ) { - increment_pos(m_input_pos); - ++m_col; + if (m_position.has_more() && char_in_alphabet(*m_position, detail::x_alphabet) ) { + ++m_position; + if (m_position.has_more() && char_in_alphabet(*m_position, detail::hex_alphabet)) { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::hex_alphabet) ) { + ++m_position; } - while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet)) + while (m_position.has_more() && char_in_alphabet(*m_position, detail::int_suffix_alphabet)) { - increment_pos(m_input_pos); - ++m_col; + ++m_position; } return true; } else { - --m_input_pos; - --m_col; + --m_position; } } else { - --m_input_pos; - --m_col; + --m_position; } } @@ -488,35 +558,29 @@ namespace chaiscript /// Reads an integer suffix void IntSuffix_() { - while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet)) + while (m_position.has_more() && char_in_alphabet(*m_position, detail::int_suffix_alphabet)) { - increment_pos(m_input_pos); - ++m_col; + ++m_position; } } /// Reads a binary value from input, without skipping initial whitespace bool Binary_() { - if (has_more_input() && (*m_input_pos == '0')) { - increment_pos(m_input_pos); - ++m_col; + if (m_position.has_more() && (*m_position == '0')) { + ++m_position; - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::b_alphabet) ) { - increment_pos(m_input_pos); - ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { - while (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { - increment_pos(m_input_pos); - ++m_col; + if (m_position.has_more() && char_in_alphabet(*m_position, detail::b_alphabet) ) { + ++m_position; + if (m_position.has_more() && char_in_alphabet(*m_position, detail::bin_alphabet) ) { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::bin_alphabet) ) { + ++m_position; } return true; } else { - --m_input_pos; - --m_col; + --m_position; } } else { - --m_input_pos; - --m_col; + --m_position; } } @@ -680,7 +744,7 @@ namespace chaiscript template std::shared_ptr make_node(std::string t_match, const int t_prev_line, const int t_prev_col, Param && ...param) { - return chaiscript::make_shared(std::move(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_line, m_col), std::forward(param)...); + return chaiscript::make_shared(std::move(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), std::forward(param)...); } /// Reads a number from the input, detecting if it's an integer or floating point @@ -690,19 +754,17 @@ namespace chaiscript if (!t_capture) { return Hex_() || Float_(); } else { - const auto start = m_input_pos; - const auto prev_col = m_col; - const auto prev_line = m_line; - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_alphabet) ) { + const auto start = m_position; + if (m_position.has_more() && char_in_alphabet(*m_position, detail::float_alphabet) ) { if (Hex_()) { - std::string match(start, m_input_pos); + auto match = Position::str(start, m_position); auto bv = buildInt(std::hex, match); - m_match_stack.emplace_back(make_node(std::move(match), prev_line, prev_col, std::move(bv))); + m_match_stack.emplace_back(make_node(std::move(match), start.line, start.col, std::move(bv))); return true; } if (Binary_()) { - std::string match(start, m_input_pos); + auto match = Position::str(start, m_position); int64_t temp_int = 0; size_t pos = 0; const auto end = match.length(); @@ -724,25 +786,25 @@ namespace chaiscript } }(); - m_match_stack.push_back(make_node(std::move(match), prev_line, prev_col, std::move(i))); + m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(i))); return true; } if (Float_()) { - std::string match(start, m_input_pos); + auto match = Position::str(start, m_position); auto bv = buildFloat(match); - m_match_stack.push_back(make_node(std::move(match), prev_line, prev_col, std::move(bv))); + m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); return true; } else { IntSuffix_(); - std::string match(start, m_input_pos); + auto match = Position::str(start, m_position); if (!match.empty() && (match[0] == '0')) { auto bv = buildInt(std::oct, match); - m_match_stack.push_back(make_node(std::move(match), prev_line, prev_col, std::move(bv))); + m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); } else if (!match.empty()) { auto bv = buildInt(std::dec, match); - m_match_stack.push_back(make_node(std::move(match), prev_line, prev_col, std::move(bv))); + m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); } else { return false; } @@ -757,37 +819,33 @@ namespace chaiscript /// Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace bool Id_() { - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::id_alphabet)) { - while (has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { - increment_pos(m_input_pos); - ++m_col; + if (m_position.has_more() && char_in_alphabet(*m_position, detail::id_alphabet)) { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::keyword_alphabet) ) { + ++m_position; } return true; - } else if (has_more_input() && (*m_input_pos == '`')) { - ++m_col; - increment_pos(m_input_pos); - const auto start = m_input_pos; + } else if (m_position.has_more() && (*m_position == '`')) { + ++m_position; + const auto start = m_position; - while (has_more_input() && (*m_input_pos != '`')) { + while (m_position.has_more() && (*m_position != '`')) { if (Eol()) { - throw exception::eval_error("Carriage return in identifier literal", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Carriage return in identifier literal", File_Position(m_position.line, m_position.col), *m_filename); } else { - increment_pos(m_input_pos); - ++m_col; + ++m_position; } } - if (start == m_input_pos) { - throw exception::eval_error("Missing contents of identifier literal", File_Position(m_line, m_col), *m_filename); + if (start == m_position) { + throw exception::eval_error("Missing contents of identifier literal", File_Position(m_position.line, m_position.col), *m_filename); } - else if (m_input_pos == m_input_end) { - throw exception::eval_error("Incomplete identifier literal", File_Position(m_line, m_col), *m_filename); + else if (!m_position.has_more()) { + throw exception::eval_error("Incomplete identifier literal", File_Position(m_position.line, m_position.col), *m_filename); } - ++m_col; - increment_pos(m_input_pos); + ++m_position; return true; } @@ -798,20 +856,18 @@ namespace chaiscript bool Id() { SkipWS(); - const auto start = m_input_pos; - const auto prev_col = m_col; - const auto prev_line = m_line; + const auto start = m_position; if (Id_()) { m_match_stack.push_back(make_node( [&]()->std::string{ if (*start == '`') { //Id Literal - return std::string(start+1, m_input_pos-1); + return Position::str(start+1, m_position-1); } else { - return std::string(start, m_input_pos); + return Position::str(start, m_position); } }(), - prev_line, prev_col)); + start.line, start.col)); return true; } else { return false; @@ -843,24 +899,21 @@ namespace chaiscript /// Checks for a node annotation of the form "#" bool Annotation() { SkipWS(); - const auto start = m_input_pos; - const auto prev_col = m_col; - const auto prev_line = m_line; + const auto start = m_position; if (Symbol_("#")) { do { - while (m_input_pos != m_input_end) { + while (m_position.has_more()) { if (Eol_()) { break; } else { - ++m_col; - increment_pos(m_input_pos); + ++m_position; } } } while (Symbol("#")); - std::string match(start, m_input_pos); - m_match_stack.push_back(make_node(std::move(match), prev_line, prev_col)); + auto match = Position::str(start, m_position); + m_match_stack.push_back(make_node(std::move(match), start.line, start.col)); return true; } else { @@ -870,28 +923,25 @@ namespace chaiscript /// Reads a quoted string from input, without skipping initial whitespace bool Quoted_String_() { - if (has_more_input() && (*m_input_pos == '\"')) { - char prev_char = *m_input_pos; - increment_pos(m_input_pos); - ++m_col; + if (m_position.has_more() && (*m_position == '\"')) { + char prev_char = *m_position; + ++m_position; - while (has_more_input() && ((*m_input_pos != '\"') || ((*m_input_pos == '\"') && (prev_char == '\\')))) { + while (m_position.has_more() && ((*m_position != '\"') || ((*m_position == '\"') && (prev_char == '\\')))) { if (!Eol_()) { if (prev_char == '\\') { prev_char = 0; } else { - prev_char = *m_input_pos; + prev_char = *m_position; } - increment_pos(m_input_pos); - ++m_col; + ++m_position; } } - if (has_more_input()) { - increment_pos(m_input_pos); - ++m_col; + if (m_position.has_more()) { + ++m_position; } else { - throw exception::eval_error("Unclosed quoted string", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Unclosed quoted string", File_Position(m_position.line, m_position.col), *m_filename); } return true; @@ -906,9 +956,7 @@ namespace chaiscript if (!t_capture) { return Quoted_String_(); } else { - const auto start = m_input_pos; - const auto prev_col = m_col; - const auto prev_line = m_line; + const auto start = m_position; if (Quoted_String_()) { std::string match; @@ -917,7 +965,7 @@ namespace chaiscript bool saw_interpolation_marker = false; const auto prev_stack_top = m_match_stack.size(); - std::string::const_iterator s = start + 1, end = m_input_pos - 1; + auto s = start + 1, end = m_position - 1; while (s != end) { if (saw_interpolation_marker) { @@ -926,11 +974,11 @@ namespace chaiscript if (is_interpolated) { //If we've seen previous interpolation, add on instead of making a new one - m_match_stack.push_back(make_node(match, prev_line, prev_col)); + m_match_stack.push_back(make_node(match, start.line, start.col)); build_match(prev_stack_top, "+"); } else { - m_match_stack.push_back(make_node(match, prev_line, prev_col)); + m_match_stack.push_back(make_node(match, start.line, start.col)); } //We've finished with the part of the string up to this point, so clear it @@ -950,7 +998,7 @@ namespace chaiscript const auto tostr_stack_top = m_match_stack.size(); - m_match_stack.push_back(make_node("to_string", prev_line, prev_col)); + m_match_stack.push_back(make_node("to_string", start.line, start.col)); const auto ev_stack_top = m_match_stack.size(); @@ -959,14 +1007,14 @@ namespace chaiscript parser.parse(eval_match, "instr eval"); m_match_stack.push_back(parser.ast()); } catch (const exception::eval_error &e) { - throw exception::eval_error(e.what(), File_Position(prev_line, prev_col), *m_filename); + throw exception::eval_error(e.what(), File_Position(start.line, start.col), *m_filename); } build_match(ev_stack_top); build_match(tostr_stack_top); build_match(prev_stack_top, "+"); } else { - throw exception::eval_error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename); + throw exception::eval_error("Unclosed in-string eval", File_Position(start.line, start.col), *m_filename); } } else { match.push_back('$'); @@ -991,7 +1039,7 @@ namespace chaiscript case ('\'') : match.push_back('\''); break; case ('\"') : match.push_back('\"'); break; case ('$') : match.push_back('$'); break; - default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); + default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(start.line, start.col), *m_filename); } } else if (*s == '$') { saw_interpolation_marker = true; @@ -1005,11 +1053,11 @@ namespace chaiscript } if (is_interpolated) { - m_match_stack.push_back(make_node(match, prev_line, prev_col)); + m_match_stack.push_back(make_node(match, start.line, start.col)); build_match(prev_stack_top, "+"); } else { - m_match_stack.push_back(make_node(match, prev_line, prev_col)); + m_match_stack.push_back(make_node(match, start.line, start.col)); } return true; } else { @@ -1021,29 +1069,26 @@ namespace chaiscript /// Reads a character group from input, without skipping initial whitespace bool Single_Quoted_String_() { bool retval = false; - if (has_more_input() && (*m_input_pos == '\'')) { + if (m_position.has_more() && (*m_position == '\'')) { retval = true; - char prev_char = *m_input_pos; - increment_pos(m_input_pos); - ++m_col; + char prev_char = *m_position; + ++m_position; - while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { + while (m_position.has_more() && ((*m_position != '\'') || ((*m_position == '\'') && (prev_char == '\\')))) { if (!Eol_()) { if (prev_char == '\\') { prev_char = 0; } else { - prev_char = *m_input_pos; + prev_char = *m_position; } - increment_pos(m_input_pos); - ++m_col; + ++m_position; } } - if (m_input_pos != m_input_end) { - increment_pos(m_input_pos); - ++m_col; + if (m_position.has_more()) { + ++m_position; } else { - throw exception::eval_error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Unclosed single-quoted string", File_Position(m_position.line, m_position.col), *m_filename); } } return retval; @@ -1056,13 +1101,11 @@ namespace chaiscript if (!t_capture) { return Single_Quoted_String_(); } else { - const auto start = m_input_pos; - const auto prev_col = m_col; - const auto prev_line = m_line; + const auto start = m_position; if (Single_Quoted_String_()) { std::string match; bool is_escaped = false; - for (auto s = start + 1, end = m_input_pos - 1; s != end; ++s) { + for (auto s = start + 1, end = m_position - 1; s != end; ++s) { if (*s == '\\') { if (is_escaped) { match.push_back('\\'); @@ -1080,7 +1123,7 @@ namespace chaiscript case ('t') : match.push_back('\t'); break; case ('\'') : match.push_back('\''); break; case ('\"') : match.push_back('\"'); break; - default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); + default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(start.line, start.col), *m_filename); } } else { match.push_back(*s); @@ -1088,7 +1131,7 @@ namespace chaiscript is_escaped = false; } } - m_match_stack.push_back(make_node(match, prev_line, prev_col)); + m_match_stack.push_back(make_node(match, start.line, start.col)); return true; } else { @@ -1099,9 +1142,8 @@ namespace chaiscript /// Reads a char from input if it matches the parameter, without skipping initial whitespace bool Char_(const char c) { - if (has_more_input() && (*m_input_pos == c)) { - increment_pos(m_input_pos); - ++m_col; + if (m_position.has_more() && (*m_position == c)) { + ++m_position; return true; } else { return false; @@ -1115,11 +1157,9 @@ namespace chaiscript if (!t_capture) { return Char_(t_c); } else { - const auto start = m_input_pos; - const auto prev_col = m_col; - const auto prev_line = m_line; + const auto start = m_position; if (Char_(t_c)) { - m_match_stack.push_back(make_node(std::string(start, m_input_pos), prev_line, prev_col)); + m_match_stack.push_back(make_node(Position::str(start, m_position), start.line, start.col)); return true; } else { return false; @@ -1131,16 +1171,15 @@ namespace chaiscript bool Keyword_(const char *t_s) { const auto len = strlen(t_s); - if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { - auto tmp = m_input_pos; - for (size_t i = 0; tmp != m_input_end && i < len; ++i) { + 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]) { return false; } - increment_pos(tmp); + ++tmp; } - m_input_pos = tmp; - m_col += static_cast(len); + m_position = tmp; return true; } @@ -1150,20 +1189,16 @@ namespace chaiscript /// Reads (and potentially captures) a string from input if it matches the parameter bool Keyword(const char *t_s, bool t_capture = false) { SkipWS(); - const auto start = m_input_pos; - const auto prev_col = m_col; - const auto prev_line = m_line; + const auto start = m_position; bool retval = Keyword_(t_s); // ignore substring matches - if ( retval && has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { - m_input_pos = start; - m_col = prev_col; - m_line = prev_line; + if ( retval && m_position.has_more() && char_in_alphabet(*m_position, detail::keyword_alphabet) ) { + m_position = start; retval = false; } if ( t_capture && retval ) { - m_match_stack.push_back(make_node(std::string(start, m_input_pos), prev_line, prev_col)); + m_match_stack.push_back(make_node(Position::str(start, m_position), start.line, start.col)); } return retval; } @@ -1172,16 +1207,15 @@ namespace chaiscript bool Symbol_(const char *t_s) { const auto len = strlen(t_s); - if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { - auto tmp = m_input_pos; - for (size_t i = 0; tmp != m_input_end && i < len; ++i) { + 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; } - increment_pos(tmp); + ++tmp; } - m_input_pos = tmp; - m_col += static_cast(len); + m_position = tmp; return true; } @@ -1191,21 +1225,17 @@ namespace chaiscript /// Reads (and potentially captures) a symbol group from input if it matches the parameter bool Symbol(const char *t_s, const bool t_capture = false, const bool t_disallow_prevention=false) { SkipWS(); - const auto start = m_input_pos; - const auto prev_col = m_col; - const auto prev_line = m_line; + const auto start = m_position; bool retval = Symbol_(t_s); // ignore substring matches - if (retval && has_more_input() && (t_disallow_prevention == false) && char_in_alphabet(*m_input_pos,detail::symbol_alphabet)) { - m_input_pos = start; - m_col = prev_col; - m_line = prev_line; + if (retval && m_position.has_more() && (t_disallow_prevention == false) && char_in_alphabet(*m_position,detail::symbol_alphabet)) { + m_position = start; retval = false; } if ( t_capture && retval ) { - m_match_stack.push_back(make_node(std::string(start, m_input_pos), prev_line, prev_col)); + m_match_stack.push_back(make_node(Position::str(start, m_position), start.line, start.col)); } return retval; @@ -1215,11 +1245,11 @@ namespace chaiscript bool Eol_(const bool t_eos = false) { bool retval = false; - if (has_more_input() && (Symbol_("\r\n") || Char_('\n'))) { + if (m_position.has_more() && (Symbol_("\r\n") || Char_('\n'))) { retval = true; - ++m_line; - m_col = 1; - } else if (has_more_input() && !t_eos && Char_(';')) { + //++m_position.line; + m_position.col = 1; + } else if (m_position.has_more() && !t_eos && Char_(';')) { retval = true; } @@ -1254,7 +1284,7 @@ namespace chaiscript do { while (Eol()) {} if (!Arg(false)) { - throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename); } } while (Char(',')); } @@ -1280,7 +1310,7 @@ namespace chaiscript do { while (Eol()) {} if (!Arg()) { - throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename); } } while (Char(',')); } @@ -1307,7 +1337,7 @@ namespace chaiscript do { while (Eol()) {} if (!Equation()) { - throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename); } } while (Char(',')); } @@ -1337,7 +1367,7 @@ namespace chaiscript do { while (Eol()) {} if (!Map_Pair()) { - throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename); } } while (Char(',')); } @@ -1349,7 +1379,7 @@ namespace chaiscript do { while (Eol()) {} if (!Operator()) { - throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename); } } while (Char(',')); } @@ -1373,7 +1403,7 @@ namespace chaiscript if (Char('[')) { Id_Arg_List(); if (!Char(']')) { - throw exception::eval_error("Incomplete anonymous function bind", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete anonymous function bind", File_Position(m_position.line, m_position.col), *m_filename); } } else { // make sure we always have the same number of nodes @@ -1383,17 +1413,17 @@ namespace chaiscript if (Char('(')) { Decl_Arg_List(); if (!Char(')')) { - throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete anonymous function", File_Position(m_position.line, m_position.col), *m_filename); } } else { - throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete anonymous function", File_Position(m_position.line, m_position.col), *m_filename); } while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete anonymous function", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -1419,7 +1449,7 @@ namespace chaiscript retval = true; if (!Id()) { - throw exception::eval_error("Missing function name in definition", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Missing function name in definition", File_Position(m_position.line, m_position.col), *m_filename); } bool is_method = false; @@ -1429,14 +1459,14 @@ namespace chaiscript is_method = true; if (!Id()) { - throw exception::eval_error("Missing method name in definition", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Missing method name in definition", File_Position(m_position.line, m_position.col), *m_filename); } } if (Char('(')) { Decl_Arg_List(); if (!Char(')')) { - throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete function definition", File_Position(m_position.line, m_position.col), *m_filename); } } @@ -1444,13 +1474,13 @@ namespace chaiscript if (Char(':')) { if (!Operator()) { - throw exception::eval_error("Missing guard expression for function", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Missing guard expression for function", File_Position(m_position.line, m_position.col), *m_filename); } } while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete function definition", File_Position(m_position.line, m_position.col), *m_filename); } if (is_method || t_class_context) { @@ -1479,7 +1509,7 @@ namespace chaiscript while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'try' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'try' block", File_Position(m_position.line, m_position.col), *m_filename); } bool has_matches = true; @@ -1490,11 +1520,11 @@ namespace chaiscript const auto catch_stack_top = m_match_stack.size(); if (Char('(')) { if (!(Arg() && Char(')'))) { - throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_position.line, m_position.col), *m_filename); } if (Char(':')) { if (!Operator()) { - throw exception::eval_error("Missing guard expression for catch", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Missing guard expression for catch", File_Position(m_position.line, m_position.col), *m_filename); } } } @@ -1502,7 +1532,7 @@ namespace chaiscript while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'catch' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'catch' block", File_Position(m_position.line, m_position.col), *m_filename); } build_match(catch_stack_top); has_matches = true; @@ -1515,7 +1545,7 @@ namespace chaiscript while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'finally' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'finally' block", File_Position(m_position.line, m_position.col), *m_filename); } build_match(finally_stack_top); } @@ -1536,17 +1566,17 @@ namespace chaiscript retval = true; if (!Char('(')) { - throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'if' expression", File_Position(m_position.line, m_position.col), *m_filename); } if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'if' expression", File_Position(m_position.line, m_position.col), *m_filename); } while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'if' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'if' block", File_Position(m_position.line, m_position.col), *m_filename); } bool has_matches = true; @@ -1560,24 +1590,24 @@ namespace chaiscript chaiscript::make_shared("else if", back->location, back->children); m_match_stack.back()->annotation = back->annotation; if (!Char('(')) { - throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_position.line, m_position.col), *m_filename); } if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_position.line, m_position.col), *m_filename); } while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'else if' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'else if' block", File_Position(m_position.line, m_position.col), *m_filename); } has_matches = true; } else { while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'else' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'else' block", File_Position(m_position.line, m_position.col), *m_filename); } has_matches = true; } @@ -1600,14 +1630,14 @@ namespace chaiscript retval = true; if (!Id()) { - throw exception::eval_error("Missing class name in definition", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Missing class name in definition", File_Position(m_position.line, m_position.col), *m_filename); } while (Eol()) {} if (!Class_Block()) { - throw exception::eval_error("Incomplete 'class' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'class' block", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -1627,17 +1657,17 @@ namespace chaiscript retval = true; if (!Char('(')) { - throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'while' expression", File_Position(m_position.line, m_position.col), *m_filename); } if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'while' expression", File_Position(m_position.line, m_position.col), *m_filename); } while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'while' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'while' block", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -1653,7 +1683,7 @@ namespace chaiscript { if (!Eol()) { - throw exception::eval_error("'for' loop initial statment missing", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("'for' loop initial statment missing", File_Position(m_position.line, m_position.col), *m_filename); } else { m_match_stack.push_back(chaiscript::make_shared()); } @@ -1663,7 +1693,7 @@ namespace chaiscript { if (!Eol()) { - throw exception::eval_error("'for' loop condition missing", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("'for' loop condition missing", File_Position(m_position.line, m_position.col), *m_filename); } else { m_match_stack.push_back(chaiscript::make_shared()); } @@ -1687,17 +1717,17 @@ namespace chaiscript retval = true; if (!Char('(')) { - throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'for' expression", File_Position(m_position.line, m_position.col), *m_filename); } if (!(For_Guards() && Char(')'))) { - throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'for' expression", File_Position(m_position.line, m_position.col), *m_filename); } while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'for' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'for' block", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -1716,17 +1746,17 @@ namespace chaiscript retval = true; if (!Char('(')) { - throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'case' expression", File_Position(m_position.line, m_position.col), *m_filename); } if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'case' expression", File_Position(m_position.line, m_position.col), *m_filename); } while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'case' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'case' block", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -1734,7 +1764,7 @@ namespace chaiscript while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'default' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'default' block", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -1751,11 +1781,11 @@ namespace chaiscript if (Keyword("switch")) { if (!Char('(')) { - throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_position.line, m_position.col), *m_filename); } if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_position.line, m_position.col), *m_filename); } while (Eol()) {} @@ -1770,11 +1800,11 @@ namespace chaiscript while (Eol()) { } // eat if (!Char('}')) { - throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete block", File_Position(m_position.line, m_position.col), *m_filename); } } else { - throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete block", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -1798,7 +1828,7 @@ namespace chaiscript Class_Statements(); if (!Char('}')) { - throw exception::eval_error("Incomplete class block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete class block", File_Position(m_position.line, m_position.col), *m_filename); } if (m_match_stack.size() == prev_stack_top) { @@ -1822,7 +1852,7 @@ namespace chaiscript Statements(); if (!Char('}')) { - throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete block", File_Position(m_position.line, m_position.col), *m_filename); } if (m_match_stack.size() == prev_stack_top) { @@ -1891,24 +1921,24 @@ namespace chaiscript Arg_List(); if (!Char(')')) { - throw exception::eval_error("Incomplete function call", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete function call", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); /// \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_line, m_col), *m_filename); - if (m_match_stack.back()->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_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); AST_NodePtr dot_access = m_match_stack.back()->children[0]; AST_NodePtr 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_line, m_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() != 3) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename); + if (dot_access->children.size() != 3) 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)); } } @@ -1916,7 +1946,7 @@ namespace chaiscript has_more = true; if (!(Operator() && Char(']'))) { - throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete array access", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -1924,11 +1954,11 @@ namespace chaiscript else if (Symbol(".", true)) { has_more = true; if (!(Id())) { - throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); } if ( std::distance(m_match_stack.begin() + static_cast(prev_stack_top), m_match_stack.end()) != 3) { - throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); } @@ -1948,7 +1978,7 @@ namespace chaiscript retval = true; if (!Id()) { - throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -1956,7 +1986,7 @@ namespace chaiscript retval = true; if (!(Reference() || Id())) { - throw exception::eval_error("Incomplete variable declaration", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete variable declaration", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -1964,7 +1994,7 @@ namespace chaiscript retval = true; if (!(Reference() || Id())) { - throw exception::eval_error("Incomplete global declaration", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete global declaration", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -1972,13 +2002,13 @@ namespace chaiscript retval = true; if (!Id()) { - throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename); } if (!Symbol("::", false)) { - throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename); } if (!Id()) { - throw exception::eval_error("Missing attribute name in definition", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Missing attribute name in definition", File_Position(m_position.line, m_position.col), *m_filename); } @@ -1992,10 +2022,10 @@ namespace chaiscript bool Paren_Expression() { if (Char('(')) { if (!Operator()) { - throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete expression", File_Position(m_position.line, m_position.col), *m_filename); } if (!Char(')')) { - throw exception::eval_error("Missing closing parenthesis ')'", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Missing closing parenthesis ')'", File_Position(m_position.line, m_position.col), *m_filename); } return true; } else { @@ -2011,7 +2041,7 @@ namespace chaiscript Container_Arg_List(); if (!Char(']')) { - throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_line, m_col), *m_filename); + 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 (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { @@ -2040,7 +2070,7 @@ namespace chaiscript if (Symbol("&", false)) { if (!Id()) { - throw exception::eval_error("Incomplete '&' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete '&' expression", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -2061,7 +2091,7 @@ namespace chaiscript if ((is_char && Char(oper[0], true)) || (!is_char && Symbol(oper.c_str(), true))) { if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete prefix '" + oper + "' expression", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete prefix '" + oper + "' expression", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -2099,7 +2129,7 @@ namespace chaiscript if (!Operator(t_precedence+1)) { throw exception::eval_error("Incomplete " + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", - File_Position(m_line, m_col), *m_filename); + File_Position(m_position.line, m_position.col), *m_filename); } AST_NodePtr oper = m_match_stack.at(m_match_stack.size()-2); @@ -2112,14 +2142,14 @@ namespace chaiscript if (!Operator(t_precedence+1)) { throw exception::eval_error("Incomplete " + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", - File_Position(m_line, m_col), *m_filename); + File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); } else { throw exception::eval_error("Incomplete " + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", - File_Position(m_line, m_col), *m_filename); + File_Position(m_position.line, m_position.col), *m_filename); } break; @@ -2144,7 +2174,7 @@ namespace chaiscript break; default: - throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_position.line, m_position.col), *m_filename); } } while (Operator_Helper(t_precedence)); } @@ -2162,21 +2192,19 @@ namespace chaiscript bool retval = false; const auto prev_stack_top = m_match_stack.size(); - const auto prev_pos = m_input_pos; - const auto prev_col = m_col; + const auto prev_pos = m_position; if (Operator()) { if (Symbol(":")) { retval = true; if (!Operator()) { - throw exception::eval_error("Incomplete map pair", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete map pair", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); } else { - m_input_pos = prev_pos; - m_col = prev_col; + m_position = prev_pos; while (prev_stack_top != m_match_stack.size()) { m_match_stack.pop_back(); } @@ -2191,21 +2219,19 @@ namespace chaiscript bool retval = false; const auto prev_stack_top = m_match_stack.size(); - const auto prev_pos = m_input_pos; - const auto prev_col = m_col; + const auto prev_pos = m_position; if (Operator()) { if (Symbol("..")) { retval = true; if (!Operator()) { - throw exception::eval_error("Incomplete value range", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete value range", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); } else { - m_input_pos = prev_pos; - m_col = prev_col; + m_position = prev_pos; while (prev_stack_top != m_match_stack.size()) { m_match_stack.pop_back(); } @@ -2229,7 +2255,7 @@ namespace chaiscript Symbol("&=", true, true) || Symbol("^=", true, true) || Symbol("|=", true, true)) { SkipWS(true); if (!Equation()) { - throw exception::eval_error("Incomplete equation", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete equation", File_Position(m_position.line, m_position.col), *m_filename); } build_match(prev_stack_top); @@ -2247,11 +2273,10 @@ namespace chaiscript bool saw_eol = true; while (has_more) { - const auto prev_line = m_line; - const auto prev_col = m_col; + const auto start = m_position; if (Def(true) || Var_Decl(true)) { if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + throw exception::eval_error("Two function definitions missing line separator", File_Position(start.line, start.col), *m_filename); } has_more = true; retval = true; @@ -2276,11 +2301,10 @@ namespace chaiscript bool saw_eol = true; while (has_more) { - int prev_line = m_line; - int prev_col = m_col; + const auto start = m_position; if (Def() || Try() || If() || While() || Class() || For() || Switch()) { if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + throw exception::eval_error("Two function definitions missing line separator", File_Position(start.line, start.col), *m_filename); } has_more = true; retval = true; @@ -2288,7 +2312,7 @@ namespace chaiscript } else if (Return() || Break() || Continue() || Equation()) { if (!saw_eol) { - throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + throw exception::eval_error("Two expressions missing line separator", File_Position(start.line, start.col), *m_filename); } has_more = true; retval = true; @@ -2309,22 +2333,19 @@ namespace chaiscript /// Parses the given input string, tagging parsed ast_nodes with the given m_filename. bool parse(const std::string &t_input, std::string t_fname) { - m_input_pos = t_input.begin(); - m_input_end = t_input.end(); - m_line = 1; - m_col = 1; + m_position = Position(t_input.begin(), t_input.end()); m_filename = std::make_shared(std::move(t_fname)); if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { - while ((m_input_pos != m_input_end) && (!Eol())) { - increment_pos(m_input_pos); + while (m_position.has_more() && (!Eol())) { + ++m_position; } /// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) } if (Statements()) { - if (m_input_pos != m_input_end) { - throw exception::eval_error("Unparsed input", File_Position(m_line, m_col), t_fname); + if (m_position.has_more()) { + throw exception::eval_error("Unparsed input", File_Position(m_position.line, m_position.col), t_fname); } else { build_match(0); //debug_print(ast()); From 31b3195c17b492c7b9b8da49d235925e4812c8f5 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 30 Jul 2015 20:23:34 -0600 Subject: [PATCH 010/131] Don't allow conversion to std::function on arity mismatch --- include/chaiscript/dispatchkit/callable_traits.hpp | 11 +++++++++++ include/chaiscript/dispatchkit/function_call.hpp | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/chaiscript/dispatchkit/callable_traits.hpp b/include/chaiscript/dispatchkit/callable_traits.hpp index 9954eea..cc1b2e7 100644 --- a/include/chaiscript/dispatchkit/callable_traits.hpp +++ b/include/chaiscript/dispatchkit/callable_traits.hpp @@ -61,6 +61,17 @@ namespace chaiscript { Ret (Class::*m_func)(Param...); }; + template + struct Arity + { + }; + + template + struct Arity + { + static const size_t arity = sizeof...(Params); + }; + template struct Function_Signature diff --git a/include/chaiscript/dispatchkit/function_call.hpp b/include/chaiscript/dispatchkit/function_call.hpp index 3c8e3c5..5692e34 100644 --- a/include/chaiscript/dispatchkit/function_call.hpp +++ b/include/chaiscript/dispatchkit/function_call.hpp @@ -14,6 +14,7 @@ #include "boxed_cast.hpp" #include "function_call_detail.hpp" #include "proxy_functions.hpp" +#include "callable_traits.hpp" namespace chaiscript { class Boxed_Value; @@ -37,6 +38,15 @@ namespace chaiscript std::function functor(const std::vector &funcs, const Type_Conversions *t_conversions) { + const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(), + [](const Const_Proxy_Function &f) { + return f->get_arity() == -1 || f->get_arity() == chaiscript::dispatch::detail::Arity::arity; + }); + + if (!has_arity_match) { + throw exception::bad_boxed_cast(user_type(), typeid(std::function)); + } + FunctionType *p=nullptr; return detail::build_function_caller_helper(p, funcs, t_conversions); } From 9d17b18f262bebf3b0206100df5cdde3771ec0c2 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 1 Aug 2015 10:04:42 -0600 Subject: [PATCH 011/131] add failing tests for #198 1<-1 fails to parse --- unittests/operator_parsing.chai | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 unittests/operator_parsing.chai diff --git a/unittests/operator_parsing.chai b/unittests/operator_parsing.chai new file mode 100644 index 0000000..59d2314 --- /dev/null +++ b/unittests/operator_parsing.chai @@ -0,0 +1,4 @@ +assert_true(2>-1); +assert_false(3<-2); +assert_true(-1==-1); + From 0c4951d7424ef6a413ec53dac623768f36a5a21a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 1 Aug 2015 10:05:38 -0600 Subject: [PATCH 012/131] Fix parsing of operators * Only parse valid operators * Don't swallow a symbol if it would produce an invalid operator Closes #198 --- .../chaiscript/language/chaiscript_parser.hpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index a2fd4b1..6aef050 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -1222,6 +1222,16 @@ namespace chaiscript 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) { + return std::any_of(opers.begin(), opers.end(), + [t_s](const std::string &s) { + return s == t_s; + }); + }); + } + /// Reads (and potentially captures) a symbol group from input if it matches the parameter bool Symbol(const char *t_s, const bool t_capture = false, const bool t_disallow_prevention=false) { SkipWS(); @@ -1230,8 +1240,12 @@ namespace chaiscript // ignore substring matches if (retval && m_position.has_more() && (t_disallow_prevention == false) && char_in_alphabet(*m_position,detail::symbol_alphabet)) { - m_position = start; - retval = false; + if (*m_position != '=' && is_operator(Position::str(start, m_position)) && !is_operator(Position::str(start, m_position+1))) { + // don't throw this away, it's a good match and the next is not + } else { + m_position = start; + retval = false; + } } if ( t_capture && retval ) { From 913d2fd20f979250242d4f54fe5065025e4c36e9 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 1 Aug 2015 11:03:55 -0600 Subject: [PATCH 013/131] Add test for variable scope in functor calls For bug #191 --- unittests/compiled_tests.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index c856e9a..9e344cc 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -743,3 +743,37 @@ TEST_CASE("Test Derived->Base with non-polymorphic classes") chai.add(chaiscript::fun(&myfunction), "myfunction"); CHECK(chai.eval("myfunction(d)") == 2); } + + +struct TestCppVariableScope +{ + void print() + { + std::cout << "Printed" << std::endl; + } +}; + +TEST_CASE("Variable Scope When Calling From C++") +{ + chaiscript::ChaiScript chai; + chai.add(chaiscript::user_type(), "Test"); + chai.add(chaiscript::constructor(), "Test"); + chai.add(chaiscript::fun(&TestCppVariableScope::print), "print"); + chai.eval(R"(var t := Test(); + + def func() + { + t.print(); + } + + )"); + + CHECK_THROWS(chai.eval("func()")); + + chai.eval("dump_object(t)"); + + auto func = chai.eval>("func"); + CHECK_THROWS(func()); +} + + From 535055eff8b67dc8ca7fb0283872cb91bd6dd07a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 1 Aug 2015 12:44:22 -0600 Subject: [PATCH 014/131] Add test to see how many exceptions are during simple use --- samples/test_num_exceptions.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 samples/test_num_exceptions.cpp diff --git a/samples/test_num_exceptions.cpp b/samples/test_num_exceptions.cpp new file mode 100644 index 0000000..371d7f1 --- /dev/null +++ b/samples/test_num_exceptions.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +int main( int argc , char * argv[] ) +{ + chaiscript::ChaiScript ch( chaiscript::Std_Lib::library( ) ); + + static const char script[ ] = + R""( + + class Rectangle + { + def Rectangle() { } + } + + var rect = Rectangle( ); + + )""; + + try + { + ch.eval( script ); + } + catch ( std::exception e ) + { + printf( " >>> Exception thrown: %s \n" , e.what( ) ); + } + + return 1; +} From 8bdd2deb199ad92568aca122925b2b8cd774db66 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 1 Aug 2015 12:47:43 -0600 Subject: [PATCH 015/131] Add exceptions test to cmakelist --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58841b7..2380e06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -253,6 +253,8 @@ add_dependencies(chai chaiscript_stdlib-${CHAI_VERSION}) if(BUILD_SAMPLES) add_executable(example samples/example.cpp) target_link_libraries(example ${LIBS}) + add_executable(test_num_exceptions samples/test_num_exceptions.cpp) + target_link_libraries(test_num_exceptions ${LIBS}) add_executable(memory_leak_test samples/memory_leak_test.cpp) target_link_libraries(memory_leak_test ${LIBS}) add_executable(inheritance samples/inheritance.cpp) From 8931346230e7da276b02a36b89309d89a4abfd4a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 1 Aug 2015 13:47:25 -0600 Subject: [PATCH 016/131] Eradicate internal exceptions during object clone --- include/chaiscript/dispatchkit/bootstrap.hpp | 8 +++++++- include/chaiscript/dispatchkit/proxy_functions.hpp | 9 +++------ include/chaiscript/language/chaiscript_prelude.chai | 12 +++++++----- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 1624e02..0f57528 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -450,7 +450,13 @@ namespace chaiscript m->add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), "[]"); m->add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), "[]"); - m->eval("def Dynamic_Object::clone() { auto &new_o = Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }"); + m->eval(R""( + def Dynamic_Object::clone() { + auto &new_o = Dynamic_Object(this.get_type_name()); + for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } ); + new_o; + } + )""); m->add(fun(&has_guard), "has_guard"); m->add(fun(&get_guard), "get_guard"); diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 1eee060..156831f 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -248,7 +248,7 @@ namespace chaiscript } - static bool compare_types(const std::vector &tis, const std::vector &bvs) + static bool compare_types(const std::vector &tis, const std::vector &bvs, const Type_Conversions &t_conversions) { if (tis.size() - 1 != bvs.size()) { @@ -257,10 +257,7 @@ namespace chaiscript const size_t size = bvs.size(); for (size_t i = 0; i < size; ++i) { - if (!(tis[i+1].bare_equal(bvs[i].get_type_info()) && tis[i+1].is_const() >= bvs[i].get_type_info().is_const() )) - { - return false; - } + if (!compare_type_to_param(tis[i + 1], bvs[i], t_conversions)) { return false; } } } return true; @@ -578,7 +575,7 @@ namespace chaiscript virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - return static_cast(vals.size()) == get_arity() && (compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions)); + return static_cast(vals.size()) == get_arity() && (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions)); } virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions &t_conversions) const = 0; diff --git a/include/chaiscript/language/chaiscript_prelude.chai b/include/chaiscript/language/chaiscript_prelude.chai index 0fe2a5a..acb8407 100644 --- a/include/chaiscript/language/chaiscript_prelude.chai +++ b/include/chaiscript/language/chaiscript_prelude.chai @@ -145,11 +145,6 @@ def reverse(container) { retval; } -# 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) -{ - clone(r); -} def range(r) : call_exists(range_internal, r) { @@ -158,6 +153,13 @@ def range(r) : call_exists(range_internal, r) ri; } +# 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) +{ + clone(r); +} + + # The retro attribute that contains the underlying range attr retro::m_range; From 38ba00e55cd5262fe57f25362ad962a382e4444a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 2 Aug 2015 16:52:43 -0600 Subject: [PATCH 017/131] Get MSVC2015 quieted down on warnings re @arBmind --- include/chaiscript/dispatchkit/boxed_cast_helper.hpp | 8 ++++---- samples/test_num_exceptions.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index 8f478bf..0e8870d 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -166,11 +166,11 @@ namespace chaiscript template<> struct Cast_Helper_Inner { - typedef const Boxed_Value & Result_Type; + typedef std::reference_wrapper Result_Type; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { - return ob; + return std::cref(ob); } }; @@ -178,11 +178,11 @@ namespace chaiscript template<> struct Cast_Helper_Inner { - typedef Boxed_Value& Result_Type; + typedef std::reference_wrapper Result_Type; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { - return const_cast(ob); + return std::ref(const_cast(ob)); } }; diff --git a/samples/test_num_exceptions.cpp b/samples/test_num_exceptions.cpp index 371d7f1..ba97f7a 100644 --- a/samples/test_num_exceptions.cpp +++ b/samples/test_num_exceptions.cpp @@ -3,7 +3,7 @@ #include #include -int main( int argc , char * argv[] ) +int main( int /*argc*/ , char * /*argv*/[] ) { chaiscript::ChaiScript ch( chaiscript::Std_Lib::library( ) ); From 04e2256c928afe3fec5e60511b3b2c63fbf36091 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 2 Aug 2015 18:21:48 -0600 Subject: [PATCH 018/131] Fix error caused by last fix --- include/chaiscript/dispatchkit/boxed_cast_helper.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index 0e8870d..d8df9be 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -166,11 +166,11 @@ namespace chaiscript template<> struct Cast_Helper_Inner { - typedef std::reference_wrapper Result_Type; + typedef Boxed_Value Result_Type; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { - return std::cref(ob); + return ob; } }; From 5aa0bfcea4d4e864da42adeb00b108d4d5aaa309 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 11 Aug 2015 19:20:18 -0600 Subject: [PATCH 019/131] Add some convenience functions for parsing --- include/chaiscript/dispatchkit/bootstrap.hpp | 15 ++++---- .../chaiscript/language/chaiscript_engine.hpp | 34 ++++++++++++++----- unittests/parser_test.chai | 10 ++++++ 3 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 unittests/parser_test.chai diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 0f57528..25f9f43 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -562,13 +562,14 @@ namespace chaiscript "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 { - 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"} } + {fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"}, + {fun(std::function (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector { + 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"} } ); diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index a6a604a..7080277 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -284,14 +284,7 @@ namespace chaiscript - const Boxed_Value internal_eval_ast(const AST_NodePtr &t_ast) - { - try { - return t_ast->eval(m_engine); - } catch (const exception::eval_error &t_ee) { - throw Boxed_Value(t_ee); - } - } + /// Evaluates the given file and looks in the 'use' paths const Boxed_Value internal_eval_file(const std::string &t_filename) { @@ -396,7 +389,8 @@ namespace chaiscript m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use"); m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file"); m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval"); - m_engine.add(fun([this](const AST_NodePtr &t_ast){ return internal_eval_ast(t_ast); }), "eval"); + m_engine.add(fun([this](const AST_NodePtr &t_ast){ return eval(t_ast); }), "eval"); + m_engine.add(fun(&parse), "parse"); m_engine.add(fun(&ChaiScript::version_major), "version_major"); m_engine.add(fun(&ChaiScript::version_minor), "version_minor"); @@ -517,6 +511,28 @@ namespace chaiscript build_eval_system(ModulePtr()); } + + const Boxed_Value eval(const AST_NodePtr &t_ast) + { + try { + return t_ast->eval(m_engine); + } catch (const exception::eval_error &t_ee) { + throw Boxed_Value(t_ee); + } + } + + static AST_NodePtr parse(const std::string &t_input) + { + parser::ChaiScript_Parser parser; + if (parser.parse(t_input, "PARSE")) { + //parser.show_match_stack(); + return parser.optimized_ast(); + } else { + throw chaiscript::exception::eval_error("Unknown error while parsing"); + } + } + + static int version_major() { return chaiscript::version_major; diff --git a/unittests/parser_test.chai b/unittests/parser_test.chai new file mode 100644 index 0000000..05c2014 --- /dev/null +++ b/unittests/parser_test.chai @@ -0,0 +1,10 @@ +auto p = parse("5 + 4"); + +try { + assert_equal(eval(p), 9) +} catch (e) { + print(e.pretty_print()); + assert_true(false); +} + + From 3a595ef9123ce35975964312d032a8b1c903bf66 Mon Sep 17 00:00:00 2001 From: msbroadf Date: Thu, 13 Aug 2015 13:45:33 +1000 Subject: [PATCH 020/131] Update chaiscript_engine.hpp --- include/chaiscript/language/chaiscript_engine.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index a6a604a..9fbdd4c 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -36,7 +36,9 @@ #else #ifdef CHAISCRIPT_WINDOWS #define VC_EXTRA_LEAN +#if !defined(WIN32_LEAN_AND_MEAN) #define WIN32_LEAN_AND_MEAN +#endif #include #endif #endif From 8f98e16e5ead0209766e803ca0a87e1bf5e1cece Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 13 Aug 2015 13:45:31 -0600 Subject: [PATCH 021/131] Reset return value flag on reference assignment --- include/chaiscript/language/chaiscript_eval.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 0597385..12b0ea9 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -436,6 +436,7 @@ namespace chaiscript else if (this->children[1]->text == ":=") { if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) { lhs.assign(rhs); + lhs.reset_return_value(); } else { throw exception::eval_error("Mismatched types in equation"); } From 781d62d3a532788e945adb768f42d9d617e0112e Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 15 Aug 2015 07:29:07 -0600 Subject: [PATCH 022/131] Make result of dynamic constructor marked as return value --- include/chaiscript/dispatchkit/dynamic_object_detail.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index 9d501ae..f1e20a1 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -232,7 +232,7 @@ namespace chaiscript protected: virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - auto bv = var(Dynamic_Object(m_type_name)); + auto bv = Boxed_Value(Dynamic_Object(m_type_name), true); std::vector new_params{bv}; new_params.insert(new_params.end(), params.begin(), params.end()); From 179eaefafe371ef71c01febb8050df8de964f51a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 25 Aug 2015 17:10:45 -0600 Subject: [PATCH 023/131] Add failing test for functor scope --- unittests/compiled_tests.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 9e344cc..9d1df58 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -776,4 +776,12 @@ TEST_CASE("Variable Scope When Calling From C++") CHECK_THROWS(func()); } +TEST_CASE("Variable Scope When Calling From C++ 2") +{ + chaiscript::ChaiScript chai; + chai.eval("var obj = 2;"); + auto func = chai.eval>("fun(){ return obj; }"); + CHECK_THROWS(func()); +} + From 800c7fb37be5b4842b09dbc68f4044723ccec756 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 26 Aug 2015 13:18:42 -0600 Subject: [PATCH 024/131] Fix functor scope - break magic 'this' --- include/chaiscript/language/chaiscript_eval.hpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 12b0ea9..5581fc1 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -46,6 +46,9 @@ namespace chaiscript /// Helper function that will set up the scope around a function call, including handling the named function parameters static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector &t_param_names, const std::vector &t_vals, const std::map &t_locals=std::map()) { chaiscript::detail::Dispatch_State state(t_ss); + + chaiscript::eval::detail::Stack_Push_Pop tpp(state); + if (!t_vals.empty()) t_ss.add_object("this", t_vals[0]); chaiscript::eval::detail::Scope_Push_Pop spp(state); for (const auto &local : t_locals) { @@ -101,7 +104,6 @@ namespace chaiscript } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); fpp.save_params({t_lhs, t_rhs}); - chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); return t_ss->call_function(t_oper_string, t_lhs, t_rhs); } } @@ -236,7 +238,6 @@ namespace chaiscript Boxed_Value fn(this->children[0]->eval(t_ss)); try { - chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); return (*t_ss->boxed_cast(fn))(params, t_ss->conversions()); } catch(const exception::dispatch_error &e){ @@ -525,7 +526,6 @@ namespace chaiscript std::vector params{children[0]->eval(t_ss), children[1]->eval(t_ss)}; try { - chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); fpp.save_params(params); return t_ss->call_function("[]", params); } @@ -578,8 +578,7 @@ namespace chaiscript fpp.save_params(params); try { - chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); - t_ss->add_object("this", retval); +// t_ss->add_object("this", retval); retval = t_ss->call_member(m_fun_name, std::move(params), has_function_params); } catch(const exception::dispatch_error &e){ @@ -1112,7 +1111,6 @@ namespace chaiscript return Boxed_Number::do_oper(m_oper, bv); } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); fpp.save_params({bv}); return t_ss->call_function(children[0]->text, std::move(bv)); } From c9625b09b0e0b0ff89ef452dc103914f95f125fb Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 26 Aug 2015 18:41:46 -0600 Subject: [PATCH 025/131] Fix magic 'this' values --- .../chaiscript/dispatchkit/dispatchkit.hpp | 62 +++++++++++++------ .../chaiscript/language/chaiscript_eval.hpp | 40 +++++++----- 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 43cb7b1..4557870 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -482,24 +482,31 @@ namespace chaiscript add_object(name, std::move(obj)); } + /// Adds a named object to the current scope + /// \warning This version does not check the validity of the name + /// it is meant for internal use only + void add_object(const std::string &t_name, Boxed_Value obj, Stack_Holder &t_holder) + { + auto &stack_elem = get_stack_data(t_holder).back(); + + if (std::any_of(stack_elem.begin(), stack_elem.end(), + [&](const std::pair &o) { + return o.first == t_name; + })) + { + throw chaiscript::exception::name_conflict_error(t_name); + } + + get_stack_data(t_holder).back().emplace_back(t_name, std::move(obj)); + } + /// Adds a named object to the current scope /// \warning This version does not check the validity of the name /// it is meant for internal use only void add_object(const std::string &name, Boxed_Value obj) { - auto &stack_elem = get_stack_data().back(); - - if (std::any_of(stack_elem.begin(), stack_elem.end(), - [&](const std::pair &o) { - return o.first == name; - })) - { - throw chaiscript::exception::name_conflict_error(name); - } - - get_stack_data().back().emplace_back(name, std::move(obj)); - + add_object(name, std::move(obj), get_stack_holder()); } /// Adds a new global shared object, between all the threads @@ -896,7 +903,7 @@ namespace chaiscript #pragma warning(push) #pragma warning(disable : 4715) #endif - Boxed_Value call_member(const std::string &t_name, const std::vector ¶ms, bool t_has_params) const + Boxed_Value call_member(const std::string &t_name, const std::vector ¶ms, bool t_has_params) { const auto funs = get_function(t_name); @@ -904,17 +911,31 @@ namespace chaiscript [this](int l_num_params, const std::vector &l_params, const std::vector &l_funs, const Type_Conversions &l_conversions)->Boxed_Value { std::vector attr_params{l_params.begin(), l_params.begin() + l_num_params}; - std::vector remaining_params{l_params.begin() + l_num_params, l_params.end()}; Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions); - if (!remaining_params.empty() || bv.get_type_info().bare_equal(user_type())) { + if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type())) { + struct This_Foist { + This_Foist(Dispatch_Engine &e, const Boxed_Value &t_bv) : m_e(e) { + m_e.get().new_scope(); + m_e.get().add_object("__this", t_bv); + } + + ~This_Foist() { + m_e.get().pop_scope(); + } + + std::reference_wrapper m_e; + }; + + This_Foist fi(*this, l_params.front()); + auto func = boxed_cast>(bv); try { - return (*func)(remaining_params, l_conversions); + return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions); } catch (const chaiscript::exception::bad_boxed_cast &) { } catch (const chaiscript::exception::arity_error &) { } catch (const chaiscript::exception::guard_error &) { } - throw chaiscript::exception::dispatch_error(remaining_params, std::vector{func}); + throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, std::vector{func}); } else { return bv; } @@ -1205,7 +1226,6 @@ namespace chaiscript return *m_stack_holder; } - private: /// Returns the current stack /// make const/non const versions const StackData &get_stack_data() const @@ -1223,6 +1243,8 @@ namespace chaiscript return m_stack_holder->stacks.back(); } + private: + const std::map &get_boxed_functions_int() const { return m_state.m_boxed_functions; @@ -1440,6 +1462,10 @@ namespace chaiscript return m_stack_holder.get(); } + void add_object(const std::string &t_name, Boxed_Value obj) const { + m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get()); + } + private: std::reference_wrapper m_engine; std::reference_wrapper m_stack_holder; diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 5581fc1..53d8e41 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -44,19 +44,32 @@ namespace chaiscript namespace detail { /// Helper function that will set up the scope around a function call, including handling the named function parameters - static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector &t_param_names, const std::vector &t_vals, const std::map &t_locals=std::map()) { + static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector &t_param_names, const std::vector &t_vals, const std::map *t_locals=nullptr) { chaiscript::detail::Dispatch_State state(t_ss); + const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{ + auto &stack = t_ss.get_stack_data(state.stack_holder()).back(); + if (!stack.empty() && stack.back().first == "__this") { + return &stack.back().second; + } else if (!t_vals.empty()) { + return &t_vals[0]; + } else { + return nullptr; + } + }(); + chaiscript::eval::detail::Stack_Push_Pop tpp(state); - if (!t_vals.empty()) t_ss.add_object("this", t_vals[0]); + if (thisobj) state.add_object("this", *thisobj); chaiscript::eval::detail::Scope_Push_Pop spp(state); - for (const auto &local : t_locals) { - t_ss.add_object(local.first, local.second); + if (t_locals) { + for (const auto &local : *t_locals) { + state.add_object(local.first, local.second); + } } for (size_t i = 0; i < t_param_names.size(); ++i) { - t_ss.add_object(t_param_names[i], t_vals[i]); + state.add_object(t_param_names[i], t_vals[i]); } try { @@ -495,7 +508,7 @@ namespace chaiscript try { Boxed_Value bv; - t_ss->add_object(idname, bv); + t_ss.add_object(idname, bv); return bv; } catch (const exception::reserved_word_error &) { @@ -578,7 +591,6 @@ namespace chaiscript fpp.save_params(params); try { -// t_ss->add_object("this", retval); retval = t_ss->call_member(m_fun_name, std::move(params), has_function_params); } catch(const exception::dispatch_error &e){ @@ -679,7 +691,7 @@ namespace chaiscript dispatch::make_dynamic_proxy_function( [engine, lambda_node, param_names, captures](const std::vector &t_params) { - return detail::eval_function(engine, lambda_node, param_names, t_params, captures); + return detail::eval_function(engine, lambda_node, param_names, t_params, &captures); }, static_cast(numparams), lambda_node, param_types ) @@ -810,7 +822,7 @@ namespace chaiscript /// \todo do this better // 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(children[0]->text)); + t_ss.add_object("_current_class_name", const_var(children[0]->text)); children[1]->eval(t_ss); @@ -1082,7 +1094,7 @@ namespace chaiscript virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ try { Boxed_Value bv; - t_ss->add_object(this->children[0]->text, bv); + t_ss.add_object(this->children[0]->text, bv); return bv; } catch (const exception::reserved_word_error &) { @@ -1230,7 +1242,7 @@ namespace chaiscript std::vector>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)} ).match(std::vector{t_except}, t_ss->conversions())) { - t_ss->add_object(name, t_except); + t_ss.add_object(name, t_except); if (catch_block->children.size() == 2) { //Variable capture, no guards @@ -1367,7 +1379,7 @@ namespace chaiscript if (guardnode) { guard = dispatch::make_dynamic_proxy_function( [engine, t_param_names, guardnode](const std::vector &t_params) { - return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params, std::map()); + return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params); }, static_cast(numparams), guardnode); } @@ -1384,7 +1396,7 @@ namespace chaiscript std::make_shared(class_name, dispatch::make_dynamic_proxy_function( [engine, t_param_names, node](const std::vector &t_params) { - return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map()); + return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params); }, static_cast(numparams), node, param_types, l_annotation, guard ) @@ -1400,7 +1412,7 @@ namespace chaiscript t_ss->add(std::make_shared(class_name, dispatch::make_dynamic_proxy_function( [engine, t_param_names, node](const std::vector &t_params) { - return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map()); + return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params); }, static_cast(numparams), node, param_types, l_annotation, guard), type), function_name); From 08935beaf34ec57f353d92541c4b611405f90c48 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 27 Aug 2015 15:23:36 -0600 Subject: [PATCH 026/131] Add tests for pushing move only values --- unittests/list_push_back.chai | 6 ++++++ unittests/list_push_front.chai | 5 +++++ unittests/vector_push_back.chai | 7 +++++++ 3 files changed, 18 insertions(+) diff --git a/unittests/list_push_back.chai b/unittests/list_push_back.chai index 19d17e1..5a058fc 100644 --- a/unittests/list_push_back.chai +++ b/unittests/list_push_back.chai @@ -6,3 +6,9 @@ x.push_back("A") assert_equal(3, x.front()); assert_equal("A", x.back()); + + +// push_back newly constructed return value that's non-copyable +x.push_back(async(fun(){})) + + diff --git a/unittests/list_push_front.chai b/unittests/list_push_front.chai index fe31821..b07c273 100644 --- a/unittests/list_push_front.chai +++ b/unittests/list_push_front.chai @@ -6,3 +6,8 @@ x.push_front("A") assert_equal("A", x.front()); assert_equal(3, x.back()); + +// push_back newly constructed return value that's non-copyable +x.push_front(async(fun(){})) + + diff --git a/unittests/vector_push_back.chai b/unittests/vector_push_back.chai index eea34b7..176e1ce 100644 --- a/unittests/vector_push_back.chai +++ b/unittests/vector_push_back.chai @@ -11,3 +11,10 @@ auto uint16v = u16vector(); uint16v.push_back(1u); assert_equal(1, uint16v.front()); + +// push_back newly constructed return value that's non-copyable + +var v = [] +v.push_back(async(fun(){})) + + From 0a143d1cd358f5ad469dda0d66b6989e3aa8a54e Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 27 Aug 2015 15:30:02 -0600 Subject: [PATCH 027/131] Make push_* consistant with inplace vector --- include/chaiscript/dispatchkit/bootstrap.hpp | 1 + include/chaiscript/dispatchkit/bootstrap_stl.hpp | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 25f9f43..d81edd5 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -466,6 +466,7 @@ namespace chaiscript m->add(fun(&Boxed_Value::is_const), "is_var_const"); 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_return_value), "is_var_return_value"); 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"); diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 1a03888..2504f00 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -334,7 +334,11 @@ namespace chaiscript "# Pushes the second value onto the container while making a clone of the value\n" "def push_back(" + type + " container, x)\n" "{ \n" - " container.push_back_ref(clone(x)) \n" + " if (x.is_var_return_value()) {\n" + " container.push_back_ref(x) \n" + " } else { \n" + " container.push_back_ref(clone(x)); \n" + " }\n" "} \n" ); @@ -370,7 +374,11 @@ namespace chaiscript "# Pushes the second value onto the front of container while making a clone of the value\n" "def push_front(" + type + " container, x)\n" "{ \n" - " container.push_front_ref(clone(x)) \n" + " if (x.is_var_return_value()) {\n" + " container.push_front_ref(x) \n" + " } else { \n" + " container.push_front_ref(clone(x)); \n" + " }\n" "} \n" ); return "push_front_ref"; From e21c8f87b49688e33bd29eaa1177e1b3a82829f5 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 28 Aug 2015 10:33:26 -0600 Subject: [PATCH 028/131] Add profile test for cpp call perf --- contrib/codeanalysis/profile_cpp_calls.chai | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 contrib/codeanalysis/profile_cpp_calls.chai diff --git a/contrib/codeanalysis/profile_cpp_calls.chai b/contrib/codeanalysis/profile_cpp_calls.chai new file mode 100644 index 0000000..8b7d484 --- /dev/null +++ b/contrib/codeanalysis/profile_cpp_calls.chai @@ -0,0 +1,21 @@ + +var test_str = "bob was a string"; + +for( var i = 0; i < 200000; ++i) +{ + test_str.size(); +// test_str.find("a", i); + test_str.c_str(); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str.erase_at(1); + test_str = "bob was a string"; +} From 9f362608b7324533d3e0de575f9c03b60e70de5a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 28 Aug 2015 21:19:00 -0600 Subject: [PATCH 029/131] Eliminate extra unneeded scope --- contrib/codeanalysis/profile_cpp_calls.chai | 15 ++++++++++----- include/chaiscript/language/chaiscript_eval.hpp | 5 +++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/contrib/codeanalysis/profile_cpp_calls.chai b/contrib/codeanalysis/profile_cpp_calls.chai index 8b7d484..011f9a1 100644 --- a/contrib/codeanalysis/profile_cpp_calls.chai +++ b/contrib/codeanalysis/profile_cpp_calls.chai @@ -12,10 +12,15 @@ for( var i = 0; i < 200000; ++i) test_str.erase_at(1); test_str.erase_at(1); test_str.erase_at(1); - test_str.erase_at(1); - test_str.erase_at(1); - test_str.erase_at(1); - test_str.erase_at(1); - test_str.erase_at(1); + + size(test_str); +// test_str.find("a", i); + c_str(test_str); + erase_at(test_str, 1); + erase_at(test_str, 1); + erase_at(test_str, 1); + erase_at(test_str, 1); + erase_at(test_str, 1); + erase_at(test_str, 1); test_str = "bob was a string"; } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 53d8e41..6f28008 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -60,7 +60,6 @@ namespace chaiscript chaiscript::eval::detail::Stack_Push_Pop tpp(state); if (thisobj) state.add_object("this", *thisobj); - chaiscript::eval::detail::Scope_Push_Pop spp(state); if (t_locals) { for (const auto &local : *t_locals) { @@ -69,7 +68,9 @@ namespace chaiscript } for (size_t i = 0; i < t_param_names.size(); ++i) { - state.add_object(t_param_names[i], t_vals[i]); + if (t_param_names[i] != "this") { + state.add_object(t_param_names[i], t_vals[i]); + } } try { From 15eb78bd8f9fd85b235506412c17975d73bccbff Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 31 Aug 2015 08:41:47 -0600 Subject: [PATCH 030/131] Move to indexed function storage --- .../chaiscript/dispatchkit/dispatchkit.hpp | 141 +++++++++++------- 1 file changed, 87 insertions(+), 54 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 4557870..3ded2df 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -417,9 +417,9 @@ namespace chaiscript struct State { - std::map > m_functions; - std::map m_function_objects; - std::map m_boxed_functions; + std::vector>>> m_functions; + std::vector> m_function_objects; + std::vector> m_boxed_functions; std::map m_global_objects; Type_Name_Map m_types; std::set m_reserved_words; @@ -518,7 +518,7 @@ namespace chaiscript throw chaiscript::exception::global_non_const(); } - chaiscript::detail::threading::unique_lock l(m_global_object_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) { @@ -533,7 +533,7 @@ namespace chaiscript { validate_object_name(name); - chaiscript::detail::threading::unique_lock l(m_global_object_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); const auto itr = m_state.m_global_objects.find(name); if (itr == m_state.m_global_objects.end()) @@ -551,7 +551,7 @@ namespace chaiscript { validate_object_name(name); - chaiscript::detail::threading::unique_lock l(m_global_object_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) { @@ -648,19 +648,18 @@ namespace chaiscript return stack[stack.size() - 1 - ((loc & static_cast(Loc::stack_mask)) >> 16)][loc & static_cast(Loc::loc_mask)].second; } - // Is the value we are looking for a global? - { - chaiscript::detail::threading::shared_lock l(m_global_object_mutex); + // Is the value we are looking for a global or function? + chaiscript::detail::threading::shared_lock l(m_mutex); - const auto itr = m_state.m_global_objects.find(name); - if (itr != m_state.m_global_objects.end()) - { - return itr->second; - } + const auto itr = m_state.m_global_objects.find(name); + if (itr != m_state.m_global_objects.end()) + { + return itr->second; } - // If all that failed, then check to see if it's a function - return get_function_object(name); + // no? is it a function object? + return get_function_object_int(name); + } /// Registers a new named type @@ -719,19 +718,19 @@ namespace chaiscript } /// Return a function by name - std::vector< Proxy_Function > get_function(const std::string &t_name) const + std::shared_ptr> get_function(const std::string &t_name) const { chaiscript::detail::threading::shared_lock l(m_mutex); const auto &funs = get_functions_int(); - auto itr = funs.find(t_name); + auto itr = find_keyed_value(funs, t_name); if (itr != funs.end()) { return itr->second; } else { - return std::vector(); + return std::make_shared>(); } } @@ -739,12 +738,19 @@ namespace chaiscript /// \throws std::range_error if it does not Boxed_Value get_function_object(const std::string &t_name) const { -// std::cout << "Getting function object: " << t_name << '\n'; chaiscript::detail::threading::shared_lock l(m_mutex); + return get_function_object_int(t_name); + } + + /// \returns a function object (Boxed_Value wrapper) if it exists + /// \throws std::range_error if it does not + /// \warn does not obtain a mutex lock. \sa get_function_object for public version + Boxed_Value get_function_object_int(const std::string &t_name) const + { const auto &funs = get_boxed_functions_int(); - auto itr = funs.find(t_name); + auto itr = find_keyed_value(funs, t_name); if (itr != funs.end()) { @@ -754,13 +760,14 @@ namespace chaiscript } } + /// Return true if a function exists bool function_exists(const std::string &name) const { chaiscript::detail::threading::shared_lock l(m_mutex); const auto &functions = get_functions_int(); - return functions.find(name) != functions.end(); + return find_keyed_value(functions, name) != functions.end(); } /// \returns All values in the local thread state in the parent scope, or if it doesn't exist, @@ -817,11 +824,8 @@ namespace chaiscript } // add the global values - { - chaiscript::detail::threading::shared_lock l(m_global_object_mutex); - - retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end()); - } + chaiscript::detail::threading::shared_lock l(m_mutex); + retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end()); return retval; } @@ -858,7 +862,7 @@ namespace chaiscript for (const auto & function : functions) { - for (const auto & internal_func : function.second) + for (const auto & internal_func : *function.second) { rets.emplace_back(function.first, internal_func); } @@ -941,14 +945,14 @@ namespace chaiscript } }; - if (is_attribute_call(funs, params, t_has_params)) { - return do_attribute_call(1, params, funs, m_conversions); + if (is_attribute_call(*funs, params, t_has_params)) { + return do_attribute_call(1, params, *funs, m_conversions); } else { std::exception_ptr except; - if (!funs.empty()) { + if (!funs->empty()) { try { - return dispatch::dispatch(funs, params, m_conversions); + return dispatch::dispatch(*funs, params, m_conversions); } catch(chaiscript::exception::dispatch_error&) { except = std::current_exception(); } @@ -960,7 +964,8 @@ namespace chaiscript const auto functions = [&]()->std::vector { std::vector fs; - for (const auto &f : get_function("method_missing")) + const auto method_missing_funs = get_function("method_missing"); + for (const auto &f : *method_missing_funs) { if(f->compare_first_type(params[0], m_conversions)) { fs.push_back(f); @@ -996,7 +1001,7 @@ namespace chaiscript if (except) { std::rethrow_exception(except); } else { - throw chaiscript::exception::dispatch_error(params, std::vector(funs.begin(), funs.end())); + throw chaiscript::exception::dispatch_error(params, std::vector(funs->begin(), funs->end())); } } } @@ -1008,7 +1013,8 @@ namespace chaiscript Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) const { - Boxed_Value bv = dispatch::dispatch(get_function(t_name), params, m_conversions); + const auto funs = get_function(t_name); + Boxed_Value bv = dispatch::dispatch(*funs, params, m_conversions); // the result of a clone is never to be marked as a return_value if (t_name == "clone") { bv.reset_return_value(); @@ -1140,7 +1146,6 @@ namespace chaiscript State get_state() const { chaiscript::detail::threading::shared_lock l(m_mutex); - chaiscript::detail::threading::shared_lock l2(m_global_object_mutex); return m_state; } @@ -1148,7 +1153,6 @@ namespace chaiscript void set_state(const State &t_state) { chaiscript::detail::threading::unique_lock l(m_mutex); - chaiscript::detail::threading::unique_lock l2(m_global_object_mutex); m_state = t_state; } @@ -1245,32 +1249,32 @@ namespace chaiscript private: - const std::map &get_boxed_functions_int() const + const std::vector> &get_boxed_functions_int() const { return m_state.m_boxed_functions; } - std::map &get_boxed_functions_int() + std::vector> &get_boxed_functions_int() { return m_state.m_boxed_functions; } - const std::map &get_function_objects_int() const + const std::vector> &get_function_objects_int() const { return m_state.m_function_objects; } - std::map &get_function_objects_int() + std::vector> &get_function_objects_int() { return m_state.m_function_objects; } - const std::map > &get_functions_int() const + const std::vector>>> &get_functions_int() const { return m_state.m_functions; } - std::map > &get_functions_int() + std::vector>>> &get_functions_int() { return m_state.m_functions; } @@ -1384,6 +1388,38 @@ namespace chaiscript } } + template + static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value) + { + auto itr = find_keyed_value(t_c, t_key); + + if (itr == t_c.end()) { + t_c.emplace_back(t_key, std::forward(t_value)); + } else { + typedef typename Container::value_type value_type; + *itr = value_type(t_key, std::forward(t_value)); + } + } + + template + static typename Container::iterator find_keyed_value(Container &t_c, const Key &t_key) + { + return std::find_if(t_c.begin(), t_c.end(), + [&t_key](const typename Container::value_type &o) { + return o.first == t_key; + }); + } + + template + static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key) + { + return std::find_if(t_c.begin(), t_c.end(), + [&t_key](const typename Container::value_type &o) { + return o.first == t_key; + }); + } + + /// Implementation detail for adding a function. /// \throws exception::name_conflict_error if there's a function matching the given one being added void add_function(const Proxy_Function &t_f, const std::string &t_name) @@ -1392,16 +1428,13 @@ namespace chaiscript auto &funcs = get_functions_int(); - auto itr = funcs.find(t_name); - - auto &func_objs = get_function_objects_int(); - auto &boxed_funcs = get_boxed_functions_int(); + auto itr = find_keyed_value(funcs, t_name); Proxy_Function new_func = [&]() -> Proxy_Function { if (itr != funcs.end()) { - auto &vec = itr->second; + auto vec = *itr->second; for (const auto &func : vec) { if ((*t_f) == *(func)) @@ -1412,26 +1445,26 @@ namespace chaiscript vec.push_back(t_f); std::stable_sort(vec.begin(), vec.end(), &function_less_than); - return std::make_shared(vec); + itr->second = std::make_shared>(vec); + return std::make_shared(std::move(vec)); } else if (t_f->has_arithmetic_param()) { // if the function is the only function but it also contains // arithmetic operators, we must wrap it in a dispatch function // to allow for automatic arithmetic type conversions std::vector vec({t_f}); - funcs.insert(std::make_pair(t_name, vec)); + funcs.emplace_back(t_name, std::make_shared>(vec)); return std::make_shared(std::move(vec)); } else { - funcs.insert(std::make_pair(t_name, std::vector{t_f})); + funcs.emplace_back(t_name, std::make_shared>(std::initializer_list({t_f}))); return t_f; } }(); - boxed_funcs[t_name] = const_var(new_func); - func_objs[t_name] = std::move(new_func); + add_keyed_value(get_boxed_functions_int(), t_name, const_var(new_func)); + add_keyed_value(get_function_objects_int(), t_name, std::move(new_func)); } mutable chaiscript::detail::threading::shared_mutex m_mutex; - mutable chaiscript::detail::threading::shared_mutex m_global_object_mutex; Type_Conversions m_conversions; From f06e5cdcd6b044dc8b7e0571ff3d58c278abfc4c Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 31 Aug 2015 09:44:47 -0600 Subject: [PATCH 031/131] Cache function lookups --- .../chaiscript/dispatchkit/dispatchkit.hpp | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 3ded2df..14571cf 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -658,7 +658,10 @@ namespace chaiscript } // no? is it a function object? - return get_function_object_int(name); + auto obj = get_function_object_int(name, loc); + if (obj.first != loc) t_loc.store(obj.first); + return obj.second; + } @@ -740,21 +743,21 @@ namespace chaiscript { chaiscript::detail::threading::shared_lock l(m_mutex); - return get_function_object_int(t_name); + return get_function_object_int(t_name, 0).second; } /// \returns a function object (Boxed_Value wrapper) if it exists /// \throws std::range_error if it does not /// \warn does not obtain a mutex lock. \sa get_function_object for public version - Boxed_Value get_function_object_int(const std::string &t_name) const + std::pair get_function_object_int(const std::string &t_name, const size_t t_hint) const { const auto &funs = get_boxed_functions_int(); - auto itr = find_keyed_value(funs, t_name); + auto itr = find_keyed_value(funs, t_name, t_hint); if (itr != funs.end()) { - return itr->second; + return std::make_pair(std::distance(funs.begin(), itr), itr->second); } else { throw std::range_error("Object not found: " + t_name); } @@ -1419,6 +1422,16 @@ namespace chaiscript }); } + template + static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint) + { + if (t_c.size() > t_hint && t_c[t_hint].first == t_key) { + return t_c.begin() + t_hint; + } else { + return find_keyed_value(t_c, t_key); + } + } + /// Implementation detail for adding a function. /// \throws exception::name_conflict_error if there's a function matching the given one being added From 52e11bf0015b5835dde38a6863702b06364c53a6 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 31 Aug 2015 11:00:56 -0600 Subject: [PATCH 032/131] Fun location caching phase2 This shows ~25% performance over develop --- .../chaiscript/dispatchkit/dispatchkit.hpp | 61 ++++++++++--------- .../chaiscript/language/chaiscript_eval.hpp | 39 ++++++++---- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 14571cf..b1cef9a 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -659,7 +659,7 @@ namespace chaiscript // no? is it a function object? auto obj = get_function_object_int(name, loc); - if (obj.first != loc) t_loc.store(obj.first); + if (obj.first != loc) t_loc.store(obj.first, std::memory_order_relaxed); return obj.second; @@ -720,20 +720,29 @@ namespace chaiscript return std::vector >(m_state.m_types.begin(), m_state.m_types.end()); } + std::shared_ptr> get_method_missing_functions() const + { + uint_fast32_t method_missing_loc = m_method_missing_loc.load(std::memory_order_relaxed); + auto method_missing_funs = get_function("method_missing", method_missing_loc); + if (method_missing_funs.first != method_missing_loc) m_method_missing_loc.store(method_missing_funs.first, std::memory_order_relaxed); + return std::move(method_missing_funs.second); + } + + /// Return a function by name - std::shared_ptr> get_function(const std::string &t_name) const + std::pair>> get_function(const std::string &t_name, const size_t t_hint) const { chaiscript::detail::threading::shared_lock l(m_mutex); const auto &funs = get_functions_int(); - auto itr = find_keyed_value(funs, t_name); + auto itr = find_keyed_value(funs, t_name, t_hint); if (itr != funs.end()) { - return itr->second; + return std::make_pair(std::distance(funs.begin(), itr), itr->second); } else { - return std::make_shared>(); + return std::make_pair(size_t(0), std::make_shared>()); } } @@ -910,9 +919,11 @@ namespace chaiscript #pragma warning(push) #pragma warning(disable : 4715) #endif - Boxed_Value call_member(const std::string &t_name, const std::vector ¶ms, bool t_has_params) + Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms, bool t_has_params) { - const auto funs = get_function(t_name); + uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); + const auto funs = get_function(t_name, loc); + if (funs.first != loc) t_loc.store(funs.first, std::memory_order_relaxed); const auto do_attribute_call = [this](int l_num_params, const std::vector &l_params, const std::vector &l_funs, const Type_Conversions &l_conversions)->Boxed_Value @@ -948,14 +959,14 @@ namespace chaiscript } }; - if (is_attribute_call(*funs, params, t_has_params)) { - return do_attribute_call(1, params, *funs, m_conversions); + if (is_attribute_call(*funs.second, params, t_has_params)) { + return do_attribute_call(1, params, *funs.second, m_conversions); } else { std::exception_ptr except; - if (!funs->empty()) { + if (!funs.second->empty()) { try { - return dispatch::dispatch(*funs, params, m_conversions); + return dispatch::dispatch(*funs.second, params, m_conversions); } catch(chaiscript::exception::dispatch_error&) { except = std::current_exception(); } @@ -967,7 +978,8 @@ namespace chaiscript const auto functions = [&]()->std::vector { std::vector fs; - const auto method_missing_funs = get_function("method_missing"); + const auto method_missing_funs = get_method_missing_functions(); + for (const auto &f : *method_missing_funs) { if(f->compare_first_type(params[0], m_conversions)) { @@ -1004,7 +1016,7 @@ namespace chaiscript if (except) { std::rethrow_exception(except); } else { - throw chaiscript::exception::dispatch_error(params, std::vector(funs->begin(), funs->end())); + throw chaiscript::exception::dispatch_error(params, std::vector(funs.second->begin(), funs.second->end())); } } } @@ -1014,10 +1026,12 @@ namespace chaiscript - Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) const + Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms) const { - const auto funs = get_function(t_name); - Boxed_Value bv = dispatch::dispatch(*funs, params, m_conversions); + uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); + const auto funs = get_function(t_name, loc); + if (funs.first != loc) t_loc.store(funs.first, std::memory_order_relaxed); + Boxed_Value bv = dispatch::dispatch(*funs.second, params, m_conversions); // the result of a clone is never to be marked as a return_value if (t_name == "clone") { bv.reset_return_value(); @@ -1025,20 +1039,6 @@ namespace chaiscript return bv; } - Boxed_Value call_function(const std::string &t_name) const - { - return call_function(t_name, std::vector()); - } - - Boxed_Value call_function(const std::string &t_name, Boxed_Value p1) const - { - return call_function(t_name, std::vector({std::move(p1)})); - } - - Boxed_Value call_function(const std::string &t_name, Boxed_Value p1, Boxed_Value p2) const - { - return call_function(t_name, std::vector({std::move(p1), std::move(p2)})); - } /// Dump object info to stdout void dump_object(const Boxed_Value &o) const @@ -1483,6 +1483,7 @@ namespace chaiscript Type_Conversions m_conversions; chaiscript::detail::threading::Thread_Storage m_stack_holder; + mutable std::atomic_uint_fast32_t m_method_missing_loc; State m_state; }; diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 6f28008..f6fde40 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -118,7 +118,7 @@ namespace chaiscript } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); fpp.save_params({t_lhs, t_rhs}); - return t_ss->call_function(t_oper_string, t_lhs, t_rhs); + return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs}); } } catch(const exception::dispatch_error &e){ @@ -128,6 +128,7 @@ namespace chaiscript private: Operators::Opers m_oper; + mutable std::atomic_uint_fast32_t m_loc; }; struct Int_AST_Node : public AST_Node { @@ -396,6 +397,8 @@ namespace chaiscript { assert(children.size() == 3); } Operators::Opers m_oper; + mutable std::atomic_uint_fast32_t m_loc; + mutable std::atomic_uint_fast32_t m_clone_loc; virtual ~Equation_AST_Node() {} virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { @@ -431,14 +434,14 @@ namespace chaiscript } else { if (!rhs.is_return_value()) { - rhs = t_ss->call_function("clone", rhs); + rhs = t_ss->call_function("clone", m_clone_loc, {rhs}); } rhs.reset_return_value(); } } try { - return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs); + return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss); @@ -458,7 +461,7 @@ namespace chaiscript } else { try { - return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs); + return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss); } @@ -541,7 +544,7 @@ namespace chaiscript try { fpp.save_params(params); - return t_ss->call_function("[]", params); + return t_ss->call_function("[]", m_loc, params); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss ); @@ -563,6 +566,8 @@ namespace chaiscript return oss.str(); } + + mutable std::atomic_uint_fast32_t m_loc; }; struct Dot_Access_AST_Node : public AST_Node { @@ -592,7 +597,7 @@ namespace chaiscript fpp.save_params(params); try { - retval = t_ss->call_member(m_fun_name, std::move(params), has_function_params); + retval = t_ss->call_member(m_fun_name, m_loc, std::move(params), has_function_params); } catch(const exception::dispatch_error &e){ if (e.functions.empty()) @@ -608,7 +613,7 @@ namespace chaiscript if (this->children[2]->identifier == AST_Node_Type::Array_Call) { try { - retval = t_ss->call_function("[]", retval, this->children[2]->children[1]->eval(t_ss)); + retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[2]->children[1]->eval(t_ss)}); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss); @@ -619,6 +624,8 @@ namespace chaiscript } private: + mutable std::atomic_uint_fast32_t m_loc; + mutable std::atomic_uint_fast32_t m_array_loc; std::string m_fun_name; }; @@ -932,7 +939,7 @@ namespace chaiscript if (this->children[currentCase]->identifier == AST_Node_Type::Case) { //This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here. try { - if (hasMatched || boxed_cast(t_ss->call_function("==", match_value, this->children[currentCase]->children[0]->eval(t_ss)))) { + if (hasMatched || boxed_cast(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}))) { this->children[currentCase]->eval(t_ss); hasMatched = true; } @@ -953,6 +960,8 @@ namespace chaiscript } return Boxed_Value(); } + + mutable std::atomic_uint_fast32_t m_loc; }; struct Case_AST_Node : public AST_Node { @@ -999,7 +1008,7 @@ namespace chaiscript for (const auto &child : children[0]->children) { auto obj = child->eval(t_ss); if (!obj.is_return_value()) { - vec.push_back(t_ss->call_function("clone", obj)); + vec.push_back(t_ss->call_function("clone", m_loc, {obj})); } else { vec.push_back(std::move(obj)); } @@ -1016,6 +1025,8 @@ namespace chaiscript { return "[" + AST_Node::pretty_print() + "]"; } + + mutable std::atomic_uint_fast32_t m_loc; }; struct Inline_Map_AST_Node : public AST_Node { @@ -1030,7 +1041,7 @@ namespace chaiscript for (const auto &child : children[0]->children) { auto obj = child->children[1]->eval(t_ss); if (!obj.is_return_value()) { - obj = t_ss->call_function("clone", obj); + obj = t_ss->call_function("clone", m_loc, {obj}); } retval[t_ss->boxed_cast(child->children[0]->eval(t_ss))] = std::move(obj); @@ -1043,6 +1054,7 @@ namespace chaiscript } } + mutable std::atomic_uint_fast32_t m_loc; }; struct Return_AST_Node : public AST_Node { @@ -1125,7 +1137,7 @@ namespace chaiscript } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); fpp.save_params({bv}); - return t_ss->call_function(children[0]->text, std::move(bv)); + return t_ss->call_function(children[0]->text, m_loc, {std::move(bv)}); } } catch (const exception::dispatch_error &e) { throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, *t_ss); @@ -1134,6 +1146,7 @@ namespace chaiscript private: Operators::Opers m_oper; + mutable std::atomic_uint_fast32_t m_loc; }; struct Break_AST_Node : public AST_Node { @@ -1196,14 +1209,14 @@ namespace chaiscript try { auto oper1 = children[0]->children[0]->children[0]->eval(t_ss); auto oper2 = children[0]->children[0]->children[1]->eval(t_ss); - return t_ss->call_function("generate_range", - oper1, oper2); + return t_ss->call_function("generate_range", m_loc, {oper1, oper2}); } catch (const exception::dispatch_error &e) { throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss); } } + mutable std::atomic_uint_fast32_t m_loc; }; struct Annotation_AST_Node : public AST_Node { From f3dbb7ed8738b592e64f8c4d64fd49a3305e450f Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 31 Aug 2015 11:09:03 -0600 Subject: [PATCH 033/131] Control how fast global vectors grow --- include/chaiscript/dispatchkit/dispatchkit.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index b1cef9a..4798876 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -1397,6 +1397,7 @@ namespace chaiscript auto itr = find_keyed_value(t_c, t_key); if (itr == t_c.end()) { + t_c.reserve(t_c.size() + 1); // tightly control growth of memory usage here t_c.emplace_back(t_key, std::forward(t_value)); } else { typedef typename Container::value_type value_type; @@ -1456,6 +1457,7 @@ namespace chaiscript } } + vec.reserve(vec.size() + 1); // tightly control vec growth vec.push_back(t_f); std::stable_sort(vec.begin(), vec.end(), &function_less_than); itr->second = std::make_shared>(vec); From aabe53c934454f5078cd174f9673441b6ed2879e Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 12 Sep 2015 22:21:05 -0600 Subject: [PATCH 034/131] Make var work with move-only types --- include/chaiscript/dispatchkit/bootstrap.hpp | 4 ++-- include/chaiscript/dispatchkit/boxed_value.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index d81edd5..0cd7bab 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -568,7 +568,7 @@ namespace chaiscript std::vector retval; std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(), std::back_inserter(retval), - &chaiscript::var>); + &chaiscript::var &>); return retval; })), "call_stack"} } ); @@ -596,7 +596,7 @@ namespace chaiscript std::vector retval; std::transform(t_node.children.begin(), t_node.children.end(), std::back_inserter(retval), - &chaiscript::var>); + &chaiscript::var &>); return retval; })), "children"}, {fun(&AST_Node::replace_child), "replace_child"} diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index a6d9c5b..ae21382 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -330,9 +330,9 @@ namespace chaiscript /// /// @sa @ref adding_objects template - Boxed_Value var(T t) + Boxed_Value var(T &&t) { - return Boxed_Value(t); + return Boxed_Value(std::forward(t)); } namespace detail { From e1a80fb5ceec23af39cdee27c568469a2579175d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 16 Sep 2015 10:28:05 -0600 Subject: [PATCH 035/131] A couple of MSVC fixes --- include/chaiscript/chaiscript_defines.hpp | 2 +- include/chaiscript/dispatchkit/dispatchkit.hpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index c28e9a5..5c54051 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -52,7 +52,7 @@ #define CHAISCRIPT_MODULE_EXPORT extern "C" #endif -#ifdef CHAISCRIPT_MSVC +#ifdef CHAISCRIPT_MSVC_12 #define CHAISCRIPT_NOEXCEPT throw() #define CHAISCRIPT_CONSTEXPR #else diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 4798876..de2caa0 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -659,7 +659,7 @@ namespace chaiscript // no? is it a function object? auto obj = get_function_object_int(name, loc); - if (obj.first != loc) t_loc.store(obj.first, std::memory_order_relaxed); + if (obj.first != loc) t_loc.store(uint_fast32_t(obj.first), std::memory_order_relaxed); return obj.second; @@ -724,7 +724,7 @@ namespace chaiscript { uint_fast32_t method_missing_loc = m_method_missing_loc.load(std::memory_order_relaxed); auto method_missing_funs = get_function("method_missing", method_missing_loc); - if (method_missing_funs.first != method_missing_loc) m_method_missing_loc.store(method_missing_funs.first, std::memory_order_relaxed); + if (method_missing_funs.first != method_missing_loc) m_method_missing_loc.store(uint_fast32_t(method_missing_funs.first), std::memory_order_relaxed); return std::move(method_missing_funs.second); } @@ -923,7 +923,7 @@ namespace chaiscript { uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); const auto funs = get_function(t_name, loc); - if (funs.first != loc) t_loc.store(funs.first, std::memory_order_relaxed); + if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed); const auto do_attribute_call = [this](int l_num_params, const std::vector &l_params, const std::vector &l_funs, const Type_Conversions &l_conversions)->Boxed_Value @@ -1030,7 +1030,7 @@ namespace chaiscript { uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); const auto funs = get_function(t_name, loc); - if (funs.first != loc) t_loc.store(funs.first, std::memory_order_relaxed); + if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed); Boxed_Value bv = dispatch::dispatch(*funs.second, params, m_conversions); // the result of a clone is never to be marked as a return_value if (t_name == "clone") { From f9f1d5807a296f723bdd8b01592d54872bb85be7 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 20 Sep 2015 15:35:53 -0600 Subject: [PATCH 036/131] Basic support for parsing of JSON objects --- include/chaiscript/chaiscript_stdlib.hpp | 3 + .../chaiscript/dispatchkit/dynamic_object.hpp | 10 + include/chaiscript/utility/json.hpp | 652 ++++++++++++++++++ include/chaiscript/utility/json_wrap.hpp | 74 ++ 4 files changed, 739 insertions(+) create mode 100644 include/chaiscript/utility/json.hpp create mode 100644 include/chaiscript/utility/json_wrap.hpp diff --git a/include/chaiscript/chaiscript_stdlib.hpp b/include/chaiscript/chaiscript_stdlib.hpp index c07e64c..4b38f2c 100644 --- a/include/chaiscript/chaiscript_stdlib.hpp +++ b/include/chaiscript/chaiscript_stdlib.hpp @@ -19,6 +19,7 @@ #include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/boxed_value.hpp" #include "language/chaiscript_prelude.chai" +#include "utility/json_wrap.hpp" #ifndef CHAISCRIPT_NO_THREADS #include @@ -51,6 +52,8 @@ namespace chaiscript lib->add(chaiscript::fun([](const std::function &t_func){ return std::async(std::launch::async, t_func);}), "async"); #endif + lib->add(json_wrap::library()); + lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ ); return lib; diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 5a9ccaa..9ea827c 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -41,6 +41,16 @@ namespace chaiscript return m_type_name; } + const Boxed_Value &operator[](const std::string &t_attr_name) const + { + return get_attr(t_attr_name); + } + + Boxed_Value &operator[](const std::string &t_attr_name) + { + return get_attr(t_attr_name); + } + const Boxed_Value &get_attr(const std::string &t_attr_name) const { auto a = m_attrs.find(t_attr_name); diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp new file mode 100644 index 0000000..dbdf886 --- /dev/null +++ b/include/chaiscript/utility/json.hpp @@ -0,0 +1,652 @@ +// From github.com/nbsdx/SimpleJSON. +// Released under the DWTFYW PL +// + + +#pragma once + +#ifndef SIMPLEJSON_HPP +#define SIMPLEJSON_HPP + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace json { + +using std::map; +using std::deque; +using std::string; +using std::enable_if; +using std::initializer_list; +using std::is_same; +using std::is_convertible; +using std::is_integral; +using std::is_floating_point; + +namespace { + string json_escape( const string &str ) { + string output; + for( unsigned i = 0; i < str.length(); ++i ) + switch( str[i] ) { + case '\"': output += "\\\""; break; + case '\\': output += "\\\\"; break; + case '\b': output += "\\b"; break; + case '\f': output += "\\f"; break; + case '\n': output += "\\n"; break; + case '\r': output += "\\r"; break; + case '\t': output += "\\t"; break; + default : output += str[i]; break; + } + return output; + } +} + +class JSON +{ + union BackingData { + BackingData( double d ) : Float( d ){} + BackingData( long l ) : Int( l ){} + BackingData( bool b ) : Bool( b ){} + BackingData( string s ) : String( new string( s ) ){} + BackingData() : Int( 0 ){} + + deque *List; + map *Map; + string *String; + double Float; + long Int; + bool Bool; + } Internal; + + public: + enum class Class { + Null, + Object, + Array, + String, + Floating, + Integral, + Boolean + }; + + template + class JSONWrapper { + Container *object; + + public: + JSONWrapper( Container *val ) : object( val ) {} + JSONWrapper( std::nullptr_t ) : object( nullptr ) {} + + typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); } + typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); } + typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); } + typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); } + }; + + template + class JSONConstWrapper { + const Container *object; + + public: + JSONConstWrapper( const Container *val ) : object( val ) {} + JSONConstWrapper( std::nullptr_t ) : object( nullptr ) {} + + typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); } + typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); } + }; + + JSON() : Internal(), Type( Class::Null ){} + + explicit JSON(Class type) + : JSON() + { + SetType( type ); + } + + JSON( initializer_list list ) + : JSON() + { + SetType( Class::Object ); + for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) + operator[]( i->ToString() ) = *std::next( i ); + } + + JSON( JSON&& other ) + : Internal( other.Internal ) + , Type( other.Type ) + { other.Type = Class::Null; other.Internal.Map = nullptr; } + + JSON& operator=( JSON&& other ) { + Internal = other.Internal; + Type = other.Type; + other.Internal.Map = nullptr; + other.Type = Class::Null; + return *this; + } + + JSON( const JSON &other ) { + switch( other.Type ) { + case Class::Object: + Internal.Map = + new map( other.Internal.Map->begin(), + other.Internal.Map->end() ); + break; + case Class::Array: + Internal.List = + new deque( other.Internal.List->begin(), + other.Internal.List->end() ); + break; + case Class::String: + Internal.String = + new string( *other.Internal.String ); + break; + default: + Internal = other.Internal; + } + Type = other.Type; + } + + JSON& operator=( const JSON &other ) { + if (&other == this) return *this; + + switch( other.Type ) { + case Class::Object: + Internal.Map = + new map( other.Internal.Map->begin(), + other.Internal.Map->end() ); + break; + case Class::Array: + Internal.List = + new deque( other.Internal.List->begin(), + other.Internal.List->end() ); + break; + case Class::String: + Internal.String = + new string( *other.Internal.String ); + break; + default: + Internal = other.Internal; + } + Type = other.Type; + return *this; + } + + ~JSON() { + switch( Type ) { + case Class::Array: + delete Internal.List; + break; + case Class::Object: + delete Internal.Map; + break; + case Class::String: + delete Internal.String; + break; + default:; + } + } + + template + JSON( T b, typename enable_if::value>::type* = 0 ) : Internal( b ), Type( Class::Boolean ){} + + template + JSON( T i, typename enable_if::value && !is_same::value>::type* = 0 ) : Internal( (long)i ), Type( Class::Integral ){} + + template + JSON( T f, typename enable_if::value>::type* = 0 ) : Internal( (double)f ), Type( Class::Floating ){} + + template + JSON( T s, typename enable_if::value>::type* = 0 ) : Internal( string( s ) ), Type( Class::String ){} + + JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){} + + static JSON Make( Class type ) { + return JSON(type); + } + + static JSON Load( const string & ); + + template + void append( T arg ) { + SetType( Class::Array ); Internal.List->emplace_back( arg ); + } + + template + void append( T arg, U... args ) { + append( arg ); append( args... ); + } + + template + typename enable_if::value, JSON&>::type operator=( T b ) { + SetType( Class::Boolean ); Internal.Bool = b; return *this; + } + + template + typename enable_if::value && !is_same::value, JSON&>::type operator=( T i ) { + SetType( Class::Integral ); Internal.Int = i; return *this; + } + + template + typename enable_if::value, JSON&>::type operator=( T f ) { + SetType( Class::Floating ); Internal.Float = f; return *this; + } + + template + typename enable_if::value, JSON&>::type operator=( T s ) { + SetType( Class::String ); *Internal.String = string( s ); return *this; + } + + JSON& operator[]( const string &key ) { + SetType( Class::Object ); return Internal.Map->operator[]( key ); + } + + JSON& operator[]( unsigned index ) { + SetType( Class::Array ); + if( index >= Internal.List->size() ) Internal.List->resize( index + 1 ); + return Internal.List->operator[]( index ); + } + + JSON &at( const string &key ) { + return operator[]( key ); + } + + const JSON &at( const string &key ) const { + return Internal.Map->at( key ); + } + + JSON &at( unsigned index ) { + return operator[]( index ); + } + + const JSON &at( unsigned index ) const { + return Internal.List->at( index ); + } + + int length() const { + if( Type == Class::Array ) + return static_cast(Internal.List->size()); + else + return -1; + } + + bool hasKey( const string &key ) const { + if( Type == Class::Object ) + return Internal.Map->find( key ) != Internal.Map->end(); + return false; + } + + int size() const { + if( Type == Class::Object ) + return static_cast(Internal.Map->size()); + else if( Type == Class::Array ) + return static_cast(Internal.List->size()); + else + return -1; + } + + Class JSONType() const { return Type; } + + /// Functions for getting primitives from the JSON object. + bool IsNull() const { return Type == Class::Null; } + + string ToString() const { bool b; return ToString( b ); } + string ToString( bool &ok ) const { + ok = (Type == Class::String); + return ok ? std::move( json_escape( *Internal.String ) ): string(""); + } + + double ToFloat() const { bool b; return ToFloat( b ); } + double ToFloat( bool &ok ) const { + ok = (Type == Class::Floating); + return ok ? Internal.Float : 0.0; + } + + long ToInt() const { bool b; return ToInt( b ); } + long ToInt( bool &ok ) const { + ok = (Type == Class::Integral); + return ok ? Internal.Int : 0; + } + + bool ToBool() const { bool b; return ToBool( b ); } + bool ToBool( bool &ok ) const { + ok = (Type == Class::Boolean); + return ok ? Internal.Bool : false; + } + + JSONWrapper> ObjectRange() { + if( Type == Class::Object ) + return JSONWrapper>( Internal.Map ); + return JSONWrapper>( nullptr ); + } + + JSONWrapper> ArrayRange() { + if( Type == Class::Array ) + return JSONWrapper>( Internal.List ); + return JSONWrapper>( nullptr ); + } + + JSONConstWrapper> ObjectRange() const { + if( Type == Class::Object ) + return JSONConstWrapper>( Internal.Map ); + return JSONConstWrapper>( nullptr ); + } + + + JSONConstWrapper> ArrayRange() const { + if( Type == Class::Array ) + return JSONConstWrapper>( Internal.List ); + return JSONConstWrapper>( nullptr ); + } + + string dump( int depth = 1, string tab = " ") const { + switch( Type ) { + case Class::Null: + return "null"; + case Class::Object: { + string pad = ""; + for( int i = 0; i < depth; ++i, pad += tab ); + + string s = "{\n"; + bool skip = true; + for( auto &p : *Internal.Map ) { + if( !skip ) s += ",\n"; + s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) ); + skip = false; + } + s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ; + return s; + } + case Class::Array: { + string s = "["; + bool skip = true; + for( auto &p : *Internal.List ) { + if( !skip ) s += ", "; + s += p.dump( depth + 1, tab ); + skip = false; + } + s += "]"; + return s; + } + case Class::String: + return "\"" + json_escape( *Internal.String ) + "\""; + case Class::Floating: + return std::to_string( Internal.Float ); + case Class::Integral: + return std::to_string( Internal.Int ); + case Class::Boolean: + return Internal.Bool ? "true" : "false"; + default: + return ""; + } + } + + friend std::ostream& operator<<( std::ostream&, const JSON & ); + + private: + void SetType( Class type ) { + if( type == Type ) + return; + + switch( Type ) { + case Class::Object: delete Internal.Map; break; + case Class::Array: delete Internal.List; break; + case Class::String: delete Internal.String; break; + default:; + } + + switch( type ) { + case Class::Null: Internal.Map = nullptr; break; + case Class::Object: Internal.Map = new map(); break; + case Class::Array: Internal.List = new deque(); break; + case Class::String: Internal.String = new string(); break; + case Class::Floating: Internal.Float = 0.0; break; + case Class::Integral: Internal.Int = 0; break; + case Class::Boolean: Internal.Bool = false; break; + } + + Type = type; + } + + private: + + Class Type = Class::Null; +}; + +JSON Array() { + return JSON::Make( JSON::Class::Array ); +} + +template +JSON Array( T... args ) { + JSON arr = JSON::Make( JSON::Class::Array ); + arr.append( args... ); + return arr; +} + +JSON Object() { + return JSON::Make( JSON::Class::Object ); +} + +std::ostream& operator<<( std::ostream &os, const JSON &json ) { + os << json.dump(); + return os; +} + +namespace { + JSON parse_next( const string &, size_t & ); + + void consume_ws( const string &str, size_t &offset ) { + while( isspace( str[offset] ) ) ++offset; + } + + JSON parse_object( const string &str, size_t &offset ) { + JSON Object = JSON::Make( JSON::Class::Object ); + + ++offset; + consume_ws( str, offset ); + if( str[offset] == '}' ) { + ++offset; return Object; + } + + for (;;) { + JSON Key = parse_next( str, offset ); + consume_ws( str, offset ); + if( str[offset] != ':' ) { + std::cerr << "Error: Object: Expected colon, found '" << str[offset] << "'\n"; + break; + } + consume_ws( str, ++offset ); + JSON Value = parse_next( str, offset ); + Object[Key.ToString()] = Value; + + consume_ws( str, offset ); + if( str[offset] == ',' ) { + ++offset; continue; + } + else if( str[offset] == '}' ) { + ++offset; break; + } + else { + std::cerr << "ERROR: Object: Expected comma, found '" << str[offset] << "'\n"; + break; + } + } + + return Object; + } + + JSON parse_array( const string &str, size_t &offset ) { + JSON Array = JSON::Make( JSON::Class::Array ); + unsigned index = 0; + + ++offset; + consume_ws( str, offset ); + if( str[offset] == ']' ) { + ++offset; return Array; + } + + for (;;) { + Array[index++] = parse_next( str, offset ); + consume_ws( str, offset ); + + if( str[offset] == ',' ) { + ++offset; continue; + } + else if( str[offset] == ']' ) { + ++offset; break; + } + else { + std::cerr << "ERROR: Array: Expected ',' or ']', found '" << str[offset] << "'\n"; + return JSON::Make( JSON::Class::Array ); + } + } + + return Array; + } + + JSON parse_string( const string &str, size_t &offset ) { + string val; + for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) { + if( c == '\\' ) { + switch( str[ ++offset ] ) { + case '\"': val += '\"'; break; + case '\\': val += '\\'; break; + case '/' : val += '/' ; break; + case 'b' : val += '\b'; break; + case 'f' : val += '\f'; break; + case 'n' : val += '\n'; break; + case 'r' : val += '\r'; break; + case 't' : val += '\t'; break; + case 'u' : { + val += "\\u" ; + for( unsigned i = 1; i <= 4; ++i ) { + c = str[offset+i]; + if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) + val += c; + else { + std::cerr << "ERROR: String: Expected hex character in unicode escape, found '" << c << "'\n"; + return JSON::Make( JSON::Class::String ); + } + } + offset += 4; + } break; + default : val += '\\'; break; + } + } + else + val += c; + } + ++offset; + return JSON(val); + } + + JSON parse_number( const string &str, size_t &offset ) { + JSON Number; + string val, exp_str; + char c; + bool isDouble = false; + long exp = 0; + for (;;) { + c = str[offset++]; + if( (c == '-') || (c >= '0' && c <= '9') ) + val += c; + else if( c == '.' ) { + val += c; + isDouble = true; + } + else + break; + } + if( c == 'E' || c == 'e' ) { + c = str[ offset++ ]; + if( c == '-' ){ ++offset; exp_str += '-';} + for (;;) { + c = str[ offset++ ]; + if( c >= '0' && c <= '9' ) + exp_str += c; + else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { + std::cerr << "ERROR: Number: Expected a number for exponent, found '" << c << "'\n"; + return JSON::Make( JSON::Class::Null ); + } + else + break; + } + exp = std::stol( exp_str ); + } + else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { + std::cerr << "ERROR: Number: unexpected character '" << c << "'\n"; + return JSON::Make( JSON::Class::Null ); + } + --offset; + + if( isDouble ) + Number = std::stod( val ) * std::pow( 10, exp ); + else { + if( !exp_str.empty() ) + Number = std::stol( val ) * std::pow( 10, exp ); + else + Number = std::stol( val ); + } + return Number; + } + + JSON parse_bool( const string &str, size_t &offset ) { + JSON Bool; + if( str.substr( offset, 4 ) == "true" ) + Bool = true; + else if( str.substr( offset, 5 ) == "false" ) + Bool = false; + else { + std::cerr << "ERROR: Bool: Expected 'true' or 'false', found '" << str.substr( offset, 5 ) << "'\n"; + return JSON::Make( JSON::Class::Null ); + } + offset += (Bool.ToBool() ? 4 : 5); + return Bool; + } + + JSON parse_null( const string &str, size_t &offset ) { + if( str.substr( offset, 4 ) != "null" ) { + std::cerr << "ERROR: Null: Expected 'null', found '" << str.substr( offset, 4 ) << "'\n"; + return JSON::Make( JSON::Class::Null ); + } + offset += 4; + return JSON(); + } + + JSON parse_next( const string &str, size_t &offset ) { + char value; + consume_ws( str, offset ); + value = str[offset]; + switch( value ) { + case '[' : return parse_array( str, offset ); + case '{' : return parse_object( str, offset ); + case '\"': return parse_string( str, offset ); + case 't' : + case 'f' : return parse_bool( str, offset ); + case 'n' : return parse_null( str, offset ); + default : if( ( value <= '9' && value >= '0' ) || value == '-' ) + return parse_number( str, offset ); + } + std::cerr << "ERROR: Parse: Unknown starting character '" << value << "'\n"; + return JSON(); + } +} + +JSON JSON::Load( const string &str ) { + size_t offset = 0; + return parse_next( str, offset ); +} + +} // End Namespace json + + +#endif diff --git a/include/chaiscript/utility/json_wrap.hpp b/include/chaiscript/utility/json_wrap.hpp new file mode 100644 index 0000000..55c32fe --- /dev/null +++ b/include/chaiscript/utility/json_wrap.hpp @@ -0,0 +1,74 @@ +#ifndef CHAISCRIPT_SIMPLEJSON_WRAP_HPP +#define CHAISCRIPT_SIMPLEJSON_WRAP_HPP + +#include "json.hpp" + +namespace chaiscript +{ + class json_wrap + { + public: + + static ModulePtr library(ModulePtr m = std::make_shared()) + { + + m->add(chaiscript::fun([](const std::string &t_str) { return json_wrap::from_json(t_str); }), "from_json"); +// m->add(chaiscript::fun(&json_wrap::to_json), "to_json"); + + return m; + + } + + private: + + static Boxed_Value from_json(const json::JSON &t_json) + { + switch( t_json.JSONType() ) { + case json::JSON::Class::Null: + return Boxed_Value(); + case json::JSON::Class::Object: + { + std::map m; + + for (const auto &p : t_json.ObjectRange()) + { + m.emplace(p.first, from_json(p.second)); + } + + return Boxed_Value(m); + } + case json::JSON::Class::Array: + { + std::vector vec; + + for (const auto &p : t_json.ArrayRange()) + { + vec.emplace_back(from_json(p)); + } + + return Boxed_Value(vec); + } + case json::JSON::Class::String: + return Boxed_Value(t_json.ToString()); + case json::JSON::Class::Floating: + return Boxed_Value(t_json.ToFloat()); + case json::JSON::Class::Integral: + return Boxed_Value(t_json.ToInt()); + case json::JSON::Class::Boolean: + return Boxed_Value(t_json.ToBool()); + } + + throw std::runtime_error("Unknown JSON type"); + } + + static Boxed_Value from_json(const std::string &t_json) + { + return from_json( json::JSON::Load(t_json) ); + } + + }; + + +} + +#endif From 8024edeadf751fde53d7e75192f027a7e949867d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 20 Sep 2015 15:46:05 -0600 Subject: [PATCH 037/131] Fix some JSON parsing bug with short strings --- include/chaiscript/utility/json.hpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index dbdf886..9b1c659 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -457,7 +457,7 @@ namespace { ++offset; return Object; } - for (;;) { + for (;offset= '0' && c <= '9') ) val += c; @@ -566,7 +566,7 @@ namespace { else break; } - if( c == 'E' || c == 'e' ) { + if( offset < str.size() && (c == 'E' || c == 'e' )) { c = str[ offset++ ]; if( c == '-' ){ ++offset; exp_str += '-';} for (;;) { @@ -582,7 +582,7 @@ namespace { } exp = std::stol( exp_str ); } - else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { + else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) { std::cerr << "ERROR: Number: unexpected character '" << c << "'\n"; return JSON::Make( JSON::Class::Null ); } @@ -601,15 +601,16 @@ namespace { JSON parse_bool( const string &str, size_t &offset ) { JSON Bool; - if( str.substr( offset, 4 ) == "true" ) + if( str.substr( offset, 4 ) == "true" ) { + offset += 4; Bool = true; - else if( str.substr( offset, 5 ) == "false" ) + } else if( str.substr( offset, 5 ) == "false" ) { + offset += 5; Bool = false; - else { + } else { std::cerr << "ERROR: Bool: Expected 'true' or 'false', found '" << str.substr( offset, 5 ) << "'\n"; return JSON::Make( JSON::Class::Null ); } - offset += (Bool.ToBool() ? 4 : 5); return Bool; } From 85ac1052dd1e457c790b495ba90449b7ac739287 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 20 Sep 2015 16:19:11 -0600 Subject: [PATCH 038/131] Initial support for export to JSON --- .../chaiscript/dispatchkit/boxed_number.hpp | 16 ++++ include/chaiscript/utility/json.hpp | 4 +- include/chaiscript/utility/json_wrap.hpp | 78 +++++++++++++++++++ 3 files changed, 96 insertions(+), 2 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index c953886..07a1103 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -100,6 +100,7 @@ namespace chaiscript :(Common_Types::t_uint64); } + static Common_Types get_common_type(const Boxed_Value &t_bv) { const Type_Info &inp_ = t_bv.get_type_info(); @@ -513,6 +514,21 @@ namespace chaiscript validate_boxed_number(bv); } + static bool is_floating_point(const Boxed_Value &t_bv) + { + const Type_Info &inp_ = t_bv.get_type_info(); + + if (inp_ == typeid(double)) { + return true; + } else if (inp_ == typeid(long double)) { + return true; + } else if (inp_ == typeid(float)) { + return true; + } else { + return false; + } + } + Boxed_Number get_as(const Type_Info &inp_) const { if (inp_.bare_equal_type_info(typeid(int))) { diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index 9b1c659..ef3fd34 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -199,10 +199,10 @@ class JSON JSON( T b, typename enable_if::value>::type* = 0 ) : Internal( b ), Type( Class::Boolean ){} template - JSON( T i, typename enable_if::value && !is_same::value>::type* = 0 ) : Internal( (long)i ), Type( Class::Integral ){} + JSON( T i, typename enable_if::value && !is_same::value>::type* = 0 ) : Internal( long(i) ), Type( Class::Integral ){} template - JSON( T f, typename enable_if::value>::type* = 0 ) : Internal( (double)f ), Type( Class::Floating ){} + JSON( T f, typename enable_if::value>::type* = 0 ) : Internal( double(f) ), Type( Class::Floating ){} template JSON( T s, typename enable_if::value>::type* = 0 ) : Internal( string( s ) ), Type( Class::String ){} diff --git a/include/chaiscript/utility/json_wrap.hpp b/include/chaiscript/utility/json_wrap.hpp index 55c32fe..cf843f0 100644 --- a/include/chaiscript/utility/json_wrap.hpp +++ b/include/chaiscript/utility/json_wrap.hpp @@ -66,6 +66,84 @@ namespace chaiscript return from_json( json::JSON::Load(t_json) ); } + static json::JSON to_json_object(const Boxed_Value &t_bv) + { + try { + const std::map m = chaiscript::boxed_cast &>(t_bv); + + json::JSON obj; + for (const auto &o : m) + { + obj[o.first] = to_json_object(o.second); + } + return obj; + } catch (const chaiscript::exception::bad_boxed_cast &) { + // not a map + } + + try { + const std::vector v = chaiscript::boxed_cast &>(t_bv); + + json::JSON obj; + for (size_t i = 0; i < v.size(); ++i) + { + obj[i] = to_json_object(v[i]); + } + return obj; + } catch (const chaiscript::exception::bad_boxed_cast &) { + // not a vector + } + + + try { + Boxed_Number bn(t_bv); + json::JSON obj; + if (Boxed_Number::is_floating_point(t_bv)) + { + obj = bn.get_as(); + } else { + obj = bn.get_as(); + } + } catch (const chaiscript::detail::exception::bad_any_cast &) { + // not a number + } + + try { + bool b = boxed_cast(t_bv); + json::JSON obj; + obj = b; + return obj; + } catch (const chaiscript::exception::bad_boxed_cast &) { + // not a bool + } + + try { + std::string s = boxed_cast(t_bv); + json::JSON obj; + obj = s; + return obj; + } catch (const chaiscript::exception::bad_boxed_cast &) { + // not a string + } + + + try { + const chaiscript::dispatch::Dynamic_Object &o = boxed_cast(t_bv); + + json::JSON obj; + for (const auto &attr : o.get_attrs()) + { + obj[attr.first] = to_json_object(attr.second); + } + return obj; + } catch (const chaiscript::exception::bad_boxed_cast &) { + // not a dynamic object + } + + throw std::runtime_error("Unknown object type to convert to JSON"); + } + + }; From e62a38b39f1ccc8a246b765aca9ecc034ccc16a9 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 21 Sep 2015 09:27:23 -0600 Subject: [PATCH 039/131] JSON output working --- include/chaiscript/utility/json_wrap.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/utility/json_wrap.hpp b/include/chaiscript/utility/json_wrap.hpp index cf843f0..b7e3ca1 100644 --- a/include/chaiscript/utility/json_wrap.hpp +++ b/include/chaiscript/utility/json_wrap.hpp @@ -13,7 +13,7 @@ namespace chaiscript { m->add(chaiscript::fun([](const std::string &t_str) { return json_wrap::from_json(t_str); }), "from_json"); -// m->add(chaiscript::fun(&json_wrap::to_json), "to_json"); + m->add(chaiscript::fun(&json_wrap::to_json), "to_json"); return m; @@ -66,6 +66,11 @@ namespace chaiscript return from_json( json::JSON::Load(t_json) ); } + static std::string to_json(const Boxed_Value &t_bv) + { + return to_json_object(t_bv).dump(); + } + static json::JSON to_json_object(const Boxed_Value &t_bv) { try { @@ -104,6 +109,7 @@ namespace chaiscript } else { obj = bn.get_as(); } + return obj; } catch (const chaiscript::detail::exception::bad_any_cast &) { // not a number } From 681f18ee620da6919f63ddb4735fd60cb6f22a5b Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 21 Sep 2015 12:27:33 -0600 Subject: [PATCH 040/131] backport JSON for G++4.6 --- include/chaiscript/dispatchkit/function_call.hpp | 2 +- include/chaiscript/utility/json.hpp | 6 +++--- include/chaiscript/utility/json_wrap.hpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/chaiscript/dispatchkit/function_call.hpp b/include/chaiscript/dispatchkit/function_call.hpp index 5692e34..c5b950a 100644 --- a/include/chaiscript/dispatchkit/function_call.hpp +++ b/include/chaiscript/dispatchkit/function_call.hpp @@ -40,7 +40,7 @@ namespace chaiscript { const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(), [](const Const_Proxy_Function &f) { - return f->get_arity() == -1 || f->get_arity() == chaiscript::dispatch::detail::Arity::arity; + return f->get_arity() == -1 || size_t(f->get_arity()) == chaiscript::dispatch::detail::Arity::arity; }); if (!has_arity_match) { diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index ef3fd34..82a1dac 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -107,13 +107,13 @@ class JSON JSON() : Internal(), Type( Class::Null ){} explicit JSON(Class type) - : JSON() + : Internal(), Type(Class::Null) { SetType( type ); } JSON( initializer_list list ) - : JSON() + : Internal(), Type(Class::Null) { SetType( Class::Object ); for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) @@ -418,7 +418,7 @@ class JSON private: - Class Type = Class::Null; + Class Type; }; JSON Array() { diff --git a/include/chaiscript/utility/json_wrap.hpp b/include/chaiscript/utility/json_wrap.hpp index b7e3ca1..1b0631d 100644 --- a/include/chaiscript/utility/json_wrap.hpp +++ b/include/chaiscript/utility/json_wrap.hpp @@ -32,7 +32,7 @@ namespace chaiscript for (const auto &p : t_json.ObjectRange()) { - m.emplace(p.first, from_json(p.second)); + m.insert(std::make_pair(p.first, from_json(p.second))); } return Boxed_Value(m); From ca35128503062f9e5163eb347ef58295bb266702 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 30 Sep 2015 06:32:34 -0600 Subject: [PATCH 041/131] Add failing test for long long conversions --- unittests/compiled_tests.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 9d1df58..da7eb7c 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -784,4 +784,21 @@ TEST_CASE("Variable Scope When Calling From C++ 2") CHECK_THROWS(func()); } +void ulonglong(unsigned long long i) { + std::cout << i << '\n'; +} + + +void longlong(long long i) { + std::cout << i << '\n'; +} + +TEST_CASE("Test long long dispatch") +{ + chaiscript::ChaiScript chai; + chai.add(chaiscript::fun(&longlong), "longlong"); + chai.add(chaiscript::fun(&ulonglong), "ulonglong"); + chai.eval("longlong(15)"); + chai.eval("ulonglong(15)"); +} From b4ffcd594d80896ccf56e0b442869a26304849f9 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 30 Sep 2015 06:49:03 -0600 Subject: [PATCH 042/131] Fix long long type usage Closes #208 --- include/chaiscript/dispatchkit/boxed_number.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index c953886..8c5440e 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -120,8 +120,12 @@ namespace chaiscript return get_common_type(sizeof(unsigned int), false); } else if (inp_ == typeid(long)) { return get_common_type(sizeof(long), true); + } else if (inp_ == typeid(long long)) { + return get_common_type(sizeof(long long), true); } else if (inp_ == typeid(unsigned long)) { return get_common_type(sizeof(unsigned long), false); + } else if (inp_ == typeid(unsigned long long)) { + return get_common_type(sizeof(unsigned long long), false); } else if (inp_ == typeid(std::int8_t)) { return Common_Types::t_int8; } else if (inp_ == typeid(std::int16_t)) { @@ -537,8 +541,12 @@ namespace chaiscript return Boxed_Number(get_as()); } else if (inp_.bare_equal_type_info(typeid(long))) { return Boxed_Number(get_as()); + } else if (inp_.bare_equal_type_info(typeid(long long))) { + return Boxed_Number(get_as()); } else if (inp_.bare_equal_type_info(typeid(unsigned long))) { return Boxed_Number(get_as()); + } else if (inp_.bare_equal_type_info(typeid(unsigned long long))) { + return Boxed_Number(get_as()); } else if (inp_.bare_equal_type_info(typeid(int8_t))) { return Boxed_Number(get_as()); } else if (inp_.bare_equal_type_info(typeid(int16_t))) { From ba30d4f48388adaf4691c24e8688cfc1adeb1bde Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 30 Sep 2015 08:57:36 -0600 Subject: [PATCH 043/131] Add support for == for Map --- .../chaiscript/dispatchkit/bootstrap_stl.hpp | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 2504f00..186ccba 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -468,6 +468,30 @@ namespace chaiscript m->add(fun(static_cast(&MapType::at)), "at"); m->add(fun(static_cast(&MapType::at)), "at"); + if (typeid(MapType) == typeid(std::map)) + { + m->eval(R"( + def Map::`==`(Map rhs) { + if ( rhs.size() != this.size() ) { + return false; + } else { + auto r1 = range(this); + auto r2 = range(rhs); + while (!r1.empty()) + { + if (!eq(r1.front().first, r2.front().first) || !eq(r1.front().second, r2.front().second)) + { + return false; + } + r1.pop_front(); + r2.pop_front(); + } + true; + } + } )" + ); + } + container_type(type, m); default_constructible_type(type, m); assignable_type(type, m); @@ -523,7 +547,7 @@ namespace chaiscript if (typeid(VectorType) == typeid(std::vector)) { m->eval(R"( - def Vector::`==`(rhs) : type_match(rhs, this) { + def Vector::`==`(Vector rhs) { if ( rhs.size() != this.size() ) { return false; } else { From b434d26a5d2c9a9e1b8d12e410e94832c384e230 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 30 Sep 2015 14:24:56 -0600 Subject: [PATCH 044/131] Add json tests --- include/chaiscript/utility/json.hpp | 36 ++++++++++++----------------- unittests/json_1.chai | 3 +++ unittests/json_10.chai | 1 + unittests/json_11.chai | 14 +++++++++++ unittests/json_12.chai | 1 + unittests/json_13.chai | 1 + unittests/json_2.chai | 3 +++ unittests/json_3.chai | 1 + unittests/json_4.chai | 1 + unittests/json_5.chai | 1 + unittests/json_6.chai | 1 + unittests/json_7.chai | 4 ++++ unittests/json_8.chai | 1 + unittests/json_9.chai | 2 ++ 14 files changed, 49 insertions(+), 21 deletions(-) create mode 100644 unittests/json_1.chai create mode 100644 unittests/json_10.chai create mode 100644 unittests/json_11.chai create mode 100644 unittests/json_12.chai create mode 100644 unittests/json_13.chai create mode 100644 unittests/json_2.chai create mode 100644 unittests/json_3.chai create mode 100644 unittests/json_4.chai create mode 100644 unittests/json_5.chai create mode 100644 unittests/json_6.chai create mode 100644 unittests/json_7.chai create mode 100644 unittests/json_8.chai create mode 100644 unittests/json_9.chai diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index 82a1dac..e8cae19 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -301,7 +301,7 @@ class JSON string ToString() const { bool b; return ToString( b ); } string ToString( bool &ok ) const { ok = (Type == Class::String); - return ok ? std::move( json_escape( *Internal.String ) ): string(""); + return ok ? *Internal.String : string(""); } double ToFloat() const { bool b; return ToFloat( b ); } @@ -461,8 +461,7 @@ namespace { JSON Key = parse_next( str, offset ); consume_ws( str, offset ); if( str[offset] != ':' ) { - std::cerr << "Error: Object: Expected colon, found '" << str[offset] << "'\n"; - break; + throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str[offset] + "'\n"); } consume_ws( str, ++offset ); JSON Value = parse_next( str, offset ); @@ -476,8 +475,7 @@ namespace { ++offset; break; } else { - std::cerr << "ERROR: Object: Expected comma, found '" << str[offset] << "'\n"; - break; + throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str[offset] + "'\n"); } } @@ -505,8 +503,7 @@ namespace { ++offset; break; } else { - std::cerr << "ERROR: Array: Expected ',' or ']', found '" << str[offset] << "'\n"; - return JSON::Make( JSON::Class::Array ); + throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str[offset] + "'\n"); } } @@ -533,8 +530,7 @@ namespace { if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) val += c; else { - std::cerr << "ERROR: String: Expected hex character in unicode escape, found '" << c << "'\n"; - return JSON::Make( JSON::Class::String ); + throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'"); } } offset += 4; @@ -568,14 +564,16 @@ namespace { } if( offset < str.size() && (c == 'E' || c == 'e' )) { c = str[ offset++ ]; - if( c == '-' ){ ++offset; exp_str += '-';} - for (;;) { + if( c == '-' ) { exp_str += '-';} + else if( c == '+' ) { } + else --offset; + + for (; offset < str.size() ;) { c = str[ offset++ ]; if( c >= '0' && c <= '9' ) exp_str += c; else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { - std::cerr << "ERROR: Number: Expected a number for exponent, found '" << c << "'\n"; - return JSON::Make( JSON::Class::Null ); + throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'"); } else break; @@ -583,8 +581,7 @@ namespace { exp = std::stol( exp_str ); } else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) { - std::cerr << "ERROR: Number: unexpected character '" << c << "'\n"; - return JSON::Make( JSON::Class::Null ); + throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'"); } --offset; @@ -608,16 +605,14 @@ namespace { offset += 5; Bool = false; } else { - std::cerr << "ERROR: Bool: Expected 'true' or 'false', found '" << str.substr( offset, 5 ) << "'\n"; - return JSON::Make( JSON::Class::Null ); + throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'"); } return Bool; } JSON parse_null( const string &str, size_t &offset ) { if( str.substr( offset, 4 ) != "null" ) { - std::cerr << "ERROR: Null: Expected 'null', found '" << str.substr( offset, 4 ) << "'\n"; - return JSON::Make( JSON::Class::Null ); + throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'"); } offset += 4; return JSON(); @@ -637,8 +632,7 @@ namespace { default : if( ( value <= '9' && value >= '0' ) || value == '-' ) return parse_number( str, offset ); } - std::cerr << "ERROR: Parse: Unknown starting character '" << value << "'\n"; - return JSON(); + throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'"); } } diff --git a/unittests/json_1.chai b/unittests/json_1.chai new file mode 100644 index 0000000..63277b3 --- /dev/null +++ b/unittests/json_1.chai @@ -0,0 +1,3 @@ + + +assert_true(from_json("null").is_var_null()) diff --git a/unittests/json_10.chai b/unittests/json_10.chai new file mode 100644 index 0000000..f19c7cf --- /dev/null +++ b/unittests/json_10.chai @@ -0,0 +1 @@ +assert_equal(from_json("\"This is a\\n\\nMultiline string\""), "This is a\n\nMultiline string") diff --git a/unittests/json_11.chai b/unittests/json_11.chai new file mode 100644 index 0000000..f11db38 --- /dev/null +++ b/unittests/json_11.chai @@ -0,0 +1,14 @@ +assert_equal(from_json( +"{\n" + +" \"T1\" : \"Value With a Quote : \\\"\",\n" + +" \"T2\" : \"Value With a Rev Solidus : \\/\",\n" + +" \"T3\" : \"Value with a Solidus : \\\\\",\n" + +" \"T4\" : \"Value with a Backspace : \\b\",\n" + +" \"T5\" : \"Value with a Formfeed : \\f\",\n" + +" \"T6\" : \"Value with a Newline : \\n\",\n" + +" \"T7\" : \"Value with a Carriage Return : \\r\",\n" + +" \"T8\" : \"Value with a Horizontal Tab : \\t\"\n" + +"}"), [ "T1" : "Value With a Quote : \"", "T2" : "Value With a Rev Solidus : /", "T3" : "Value with a Solidus : \\", "T4" : "Value with a Backspace : \b", "T5" : "Value with a Formfeed : \f", "T6" : "Value with a Newline : \n", "T7" : "Value with a Carriage Return : \r", "T8" : "Value with a Horizontal Tab : \t" ]); + + + diff --git a/unittests/json_12.chai b/unittests/json_12.chai new file mode 100644 index 0000000..a93211d --- /dev/null +++ b/unittests/json_12.chai @@ -0,0 +1 @@ +assert_equal(from_json("\"\""), "") diff --git a/unittests/json_13.chai b/unittests/json_13.chai new file mode 100644 index 0000000..3f9fa00 --- /dev/null +++ b/unittests/json_13.chai @@ -0,0 +1 @@ +assert_equal(from_json("1.20E+2"), 1.20e2) diff --git a/unittests/json_2.chai b/unittests/json_2.chai new file mode 100644 index 0000000..0f779bd --- /dev/null +++ b/unittests/json_2.chai @@ -0,0 +1,3 @@ + +assert_true(from_json("true")) + diff --git a/unittests/json_3.chai b/unittests/json_3.chai new file mode 100644 index 0000000..d3f222e --- /dev/null +++ b/unittests/json_3.chai @@ -0,0 +1 @@ +assert_equal(from_json("100"), 100) diff --git a/unittests/json_4.chai b/unittests/json_4.chai new file mode 100644 index 0000000..22d388c --- /dev/null +++ b/unittests/json_4.chai @@ -0,0 +1 @@ +assert_equal(from_json("1.234"), 1.234) diff --git a/unittests/json_5.chai b/unittests/json_5.chai new file mode 100644 index 0000000..9ad2ca2 --- /dev/null +++ b/unittests/json_5.chai @@ -0,0 +1 @@ +assert_equal(from_json("\"StringTest\""), "StringTest") diff --git a/unittests/json_6.chai b/unittests/json_6.chai new file mode 100644 index 0000000..8c33bff --- /dev/null +++ b/unittests/json_6.chai @@ -0,0 +1 @@ +assert_equal(from_json("{}"), Map()) diff --git a/unittests/json_7.chai b/unittests/json_7.chai new file mode 100644 index 0000000..b2c6efa --- /dev/null +++ b/unittests/json_7.chai @@ -0,0 +1,4 @@ +assert_equal(from_json("\n" + +"{\n" + +" \"Key\" : \"Value\"\n" + +"}\n"), ["Key":"Value"]) diff --git a/unittests/json_8.chai b/unittests/json_8.chai new file mode 100644 index 0000000..104c8bc --- /dev/null +++ b/unittests/json_8.chai @@ -0,0 +1 @@ +assert_equal(from_json("[]"), []) diff --git a/unittests/json_9.chai b/unittests/json_9.chai new file mode 100644 index 0000000..1512738 --- /dev/null +++ b/unittests/json_9.chai @@ -0,0 +1,2 @@ +assert_equal(from_json("[1,2,3]"), [1,2,3]) + From d9fa5605ac98f9ab724199efef8be33680116264 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 1 Oct 2015 09:39:03 -0600 Subject: [PATCH 045/131] Add operator overload tests --- unittests/operator_overload3.chai | 7 +++++++ unittests/operator_overload4.chai | 6 ++++++ 2 files changed, 13 insertions(+) create mode 100644 unittests/operator_overload3.chai create mode 100644 unittests/operator_overload4.chai diff --git a/unittests/operator_overload3.chai b/unittests/operator_overload3.chai new file mode 100644 index 0000000..90b81cd --- /dev/null +++ b/unittests/operator_overload3.chai @@ -0,0 +1,7 @@ + + +def string::`/=`(double d) { this = "${this}/=${d}"; return this; } + +var s = "Hello World" +s /= 2 + diff --git a/unittests/operator_overload4.chai b/unittests/operator_overload4.chai new file mode 100644 index 0000000..832d984 --- /dev/null +++ b/unittests/operator_overload4.chai @@ -0,0 +1,6 @@ + + +def string::`*`(double d) { return "${this} * ${d}"; } + +"Hello World" * 2 + From 5a651e2b8a0d5000e4c994ae2fa0a3fe6bf1fdc6 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 1 Oct 2015 09:56:53 -0600 Subject: [PATCH 046/131] Fix numeric overload resolution Closes #209 --- include/chaiscript/dispatchkit/dispatchkit.hpp | 1 + include/chaiscript/dispatchkit/proxy_functions.hpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index de2caa0..806abae 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -1033,6 +1033,7 @@ namespace chaiscript if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed); Boxed_Value bv = dispatch::dispatch(*funs.second, params, m_conversions); // the result of a clone is never to be marked as a return_value + // \todo see if we can eliminate this comparison if (t_name == "clone") { bv.reset_return_value(); } diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 156831f..d9da2e6 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -211,7 +211,7 @@ namespace chaiscript if (ti.is_undef() || ti.bare_equal(user_type()) || (!bv.get_type_info().is_undef() - && (ti.bare_equal(user_type()) + && ( (ti.bare_equal(user_type()) && bv.get_type_info().is_arithmetic()) || ti.bare_equal(bv.get_type_info()) || bv.get_type_info().bare_equal(user_type >()) || t_conversions.converts(ti, bv.get_type_info()) From 6a4647af43040db97b33aa16f4b2dbb5be11566d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 2 Oct 2015 08:12:50 -0600 Subject: [PATCH 047/131] Add last test for json support Closes #207 --- unittests/json_roundtrip.chai | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 unittests/json_roundtrip.chai diff --git a/unittests/json_roundtrip.chai b/unittests/json_roundtrip.chai new file mode 100644 index 0000000..94682e5 --- /dev/null +++ b/unittests/json_roundtrip.chai @@ -0,0 +1,6 @@ + +var m = ["a" : 1, "b" : [ 1, 2, 3 ], "c" : [1, "a string", ["d" : 15.4]]] + +assert_equal(from_json(to_json(m)), m) + + From 8d9dc2b0a3637bb3eafe0eb522ec364b427e4676 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 2 Oct 2015 10:35:37 -0600 Subject: [PATCH 048/131] Reduce redundant escape code parsing #211 --- .../chaiscript/language/chaiscript_parser.hpp | 124 +++++++++--------- 1 file changed, 64 insertions(+), 60 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 6aef050..9e075ee 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -949,6 +949,57 @@ namespace chaiscript return false; } + struct Char_Parser + { + bool is_escaped; + bool is_interpolated; + bool saw_interpolation_marker; + const bool interpolation_allowed; + + Char_Parser(const bool t_interpolation_allowed) + : is_escaped(false), + is_interpolated(false), + saw_interpolation_marker(false), + interpolation_allowed(t_interpolation_allowed) + { + } + + void parse(std::string &t_match, const char t_char, const int line, const int col, const std::string &filename) { + if (t_char == '\\') { + if (is_escaped) { + t_match.push_back('\\'); + is_escaped = false; + } else { + is_escaped = true; + } + } else { + if (is_escaped) { + switch (t_char) { + case ('\'') : t_match.push_back('\''); break; + case ('\"') : t_match.push_back('\"'); break; + case ('?') : t_match.push_back('?'); break; + case ('a') : t_match.push_back('\a'); break; + case ('b') : t_match.push_back('\b'); break; + case ('f') : t_match.push_back('\f'); break; + case ('n') : t_match.push_back('\n'); break; + case ('r') : t_match.push_back('\r'); break; + case ('t') : t_match.push_back('\t'); break; + case ('v') : t_match.push_back('\v'); break; + case ('$') : t_match.push_back('$'); break; + default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(line, col), filename); + } + } else if (interpolation_allowed && t_char == '$') { + saw_interpolation_marker = true; + } else { + t_match.push_back(t_char); + } + is_escaped = false; + } + } + + }; + + /// Reads (and potentially captures) a quoted string from input. Translates escaped sequences. bool Quoted_String(const bool t_capture = false) { SkipWS(); @@ -960,19 +1011,19 @@ namespace chaiscript if (Quoted_String_()) { std::string match; - bool is_escaped = false; - bool is_interpolated = false; - bool saw_interpolation_marker = false; + + Char_Parser cparser(true); + const auto prev_stack_top = m_match_stack.size(); auto s = start + 1, end = m_position - 1; while (s != end) { - if (saw_interpolation_marker) { + if (cparser.saw_interpolation_marker) { if (*s == '{') { //We've found an interpolation point - if (is_interpolated) { + if (cparser.is_interpolated) { //If we've seen previous interpolation, add on instead of making a new one m_match_stack.push_back(make_node(match, start.line, start.col)); @@ -993,7 +1044,7 @@ namespace chaiscript } if (*s == '}') { - is_interpolated = true; + cparser.is_interpolated = true; ++s; const auto tostr_stack_top = m_match_stack.size(); @@ -1019,40 +1070,14 @@ namespace chaiscript } else { match.push_back('$'); } - saw_interpolation_marker = false; + cparser.saw_interpolation_marker = false; } else { - if (*s == '\\') { - if (is_escaped) { - match.push_back('\\'); - is_escaped = false; - } else { - is_escaped = true; - } - } else { - if (is_escaped) { - switch (*s) { - case ('b') : match.push_back('\b'); break; - case ('f') : match.push_back('\f'); break; - case ('n') : match.push_back('\n'); break; - case ('r') : match.push_back('\r'); break; - case ('t') : match.push_back('\t'); break; - case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; - case ('$') : match.push_back('$'); break; - default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(start.line, start.col), *m_filename); - } - } else if (*s == '$') { - saw_interpolation_marker = true; - } else { - match.push_back(*s); - } - is_escaped = false; - } + cparser.parse(match, *s, start.line, start.col, *m_filename); ++s; } } - if (is_interpolated) { + if (cparser.is_interpolated) { m_match_stack.push_back(make_node(match, start.line, start.col)); build_match(prev_stack_top, "+"); @@ -1104,33 +1129,12 @@ namespace chaiscript const auto start = m_position; if (Single_Quoted_String_()) { std::string match; - bool is_escaped = false; + Char_Parser cparser(false); + for (auto s = start + 1, end = m_position - 1; s != end; ++s) { - if (*s == '\\') { - if (is_escaped) { - match.push_back('\\'); - is_escaped = false; - } else { - is_escaped = true; - } - } else { - if (is_escaped) { - switch (*s) { - case ('b') : match.push_back('\b'); break; - case ('f') : match.push_back('\f'); break; - case ('n') : match.push_back('\n'); break; - case ('r') : match.push_back('\r'); break; - case ('t') : match.push_back('\t'); break; - case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; - default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(start.line, start.col), *m_filename); - } - } else { - match.push_back(*s); - } - is_escaped = false; - } + cparser.parse(match, *s, start.line, start.col, *m_filename); } + m_match_stack.push_back(make_node(match, start.line, start.col)); return true; } From 41e9027d9a8a0e8944900529b7ca2b44c9f79212 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 2 Oct 2015 11:45:28 -0600 Subject: [PATCH 049/131] Octal escape codes supported #211 --- CMakeLists.txt | 2 +- .../chaiscript/language/chaiscript_parser.hpp | 205 +++++++++++------- include/chaiscript/utility/json.hpp | 4 +- 3 files changed, 128 insertions(+), 83 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2380e06..07ae809 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,7 +174,7 @@ else() add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG}) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - add_definitions(-Weverything -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors) + add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors) else() add_definitions(-Wnoexcept) endif() diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 9e075ee..ebb8bfc 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -951,49 +951,88 @@ namespace chaiscript struct Char_Parser { + std::string &match; bool is_escaped; bool is_interpolated; bool saw_interpolation_marker; + bool is_octal; const bool interpolation_allowed; - Char_Parser(const bool t_interpolation_allowed) - : is_escaped(false), + std::string octal_matches; + + Char_Parser(std::string &t_match, const bool t_interpolation_allowed) + : match(t_match), + is_escaped(false), is_interpolated(false), saw_interpolation_marker(false), + is_octal(false), interpolation_allowed(t_interpolation_allowed) { } - void parse(std::string &t_match, const char t_char, const int line, const int col, const std::string &filename) { + ~Char_Parser(){ + if (is_octal) { + process_octal(); + } + } + + void process_octal() + { + int val = stoi(octal_matches, 0, 8); + match.push_back(char(val)); + octal_matches.clear(); + is_escaped = false; + is_octal = false; + } + + void parse(const char t_char, const int line, const int col, const std::string &filename) { if (t_char == '\\') { if (is_escaped) { - t_match.push_back('\\'); + match.push_back('\\'); is_escaped = false; } else { is_escaped = true; } } else { if (is_escaped) { - switch (t_char) { - case ('\'') : t_match.push_back('\''); break; - case ('\"') : t_match.push_back('\"'); break; - case ('?') : t_match.push_back('?'); break; - case ('a') : t_match.push_back('\a'); break; - case ('b') : t_match.push_back('\b'); break; - case ('f') : t_match.push_back('\f'); break; - case ('n') : t_match.push_back('\n'); break; - case ('r') : t_match.push_back('\r'); break; - case ('t') : t_match.push_back('\t'); break; - case ('v') : t_match.push_back('\v'); break; - case ('$') : t_match.push_back('$'); break; - default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(line, col), filename); + bool is_octal_char = t_char >= '0' && t_char <= '7'; + + if (is_octal) { + if (is_octal_char) { + octal_matches.push_back(t_char); + + if (octal_matches.size() == 3) { + process_octal(); + } + } else { + process_octal(); + match.push_back(t_char); + } + } else if (is_octal_char) { + is_octal = true; + octal_matches.push_back(t_char); + } else { + switch (t_char) { + case ('\'') : match.push_back('\''); break; + case ('\"') : match.push_back('\"'); break; + case ('?') : match.push_back('?'); break; + case ('a') : match.push_back('\a'); break; + case ('b') : match.push_back('\b'); break; + case ('f') : match.push_back('\f'); break; + case ('n') : match.push_back('\n'); break; + case ('r') : match.push_back('\r'); break; + case ('t') : match.push_back('\t'); break; + case ('v') : match.push_back('\v'); break; + case ('$') : match.push_back('$'); break; + default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(line, col), filename); + } + is_escaped = false; } } else if (interpolation_allowed && t_char == '$') { saw_interpolation_marker = true; } else { - t_match.push_back(t_char); + match.push_back(t_char); } - is_escaped = false; } } @@ -1011,73 +1050,77 @@ namespace chaiscript if (Quoted_String_()) { std::string match; - - Char_Parser cparser(true); - const auto prev_stack_top = m_match_stack.size(); - auto s = start + 1, end = m_position - 1; + bool is_interpolated = [&]() { + Char_Parser cparser(match, true); - while (s != end) { - if (cparser.saw_interpolation_marker) { - if (*s == '{') { - //We've found an interpolation point - if (cparser.is_interpolated) { - //If we've seen previous interpolation, add on instead of making a new one - m_match_stack.push_back(make_node(match, start.line, start.col)); + auto s = start + 1, end = m_position - 1; - build_match(prev_stack_top, "+"); - } else { - m_match_stack.push_back(make_node(match, start.line, start.col)); - } + while (s != end) { + if (cparser.saw_interpolation_marker) { + if (*s == '{') { + //We've found an interpolation point - //We've finished with the part of the string up to this point, so clear it - match.clear(); + if (cparser.is_interpolated) { + //If we've seen previous interpolation, add on instead of making a new one + m_match_stack.push_back(make_node(match, start.line, start.col)); - std::string eval_match; - - ++s; - while ((s != end) && (*s != '}')) { - eval_match.push_back(*s); - ++s; - } - - if (*s == '}') { - cparser.is_interpolated = true; - ++s; - - const auto tostr_stack_top = m_match_stack.size(); - - m_match_stack.push_back(make_node("to_string", start.line, start.col)); - - const auto ev_stack_top = m_match_stack.size(); - - try { - ChaiScript_Parser parser; - parser.parse(eval_match, "instr eval"); - m_match_stack.push_back(parser.ast()); - } catch (const exception::eval_error &e) { - throw exception::eval_error(e.what(), File_Position(start.line, start.col), *m_filename); + build_match(prev_stack_top, "+"); + } else { + m_match_stack.push_back(make_node(match, start.line, start.col)); } - build_match(ev_stack_top); - build_match(tostr_stack_top); - build_match(prev_stack_top, "+"); - } else { - throw exception::eval_error("Unclosed in-string eval", File_Position(start.line, start.col), *m_filename); - } - } else { - match.push_back('$'); - } - cparser.saw_interpolation_marker = false; - } else { - cparser.parse(match, *s, start.line, start.col, *m_filename); - ++s; - } - } + //We've finished with the part of the string up to this point, so clear it + match.clear(); - if (cparser.is_interpolated) { + std::string eval_match; + + ++s; + while ((s != end) && (*s != '}')) { + eval_match.push_back(*s); + ++s; + } + + if (*s == '}') { + cparser.is_interpolated = true; + ++s; + + const auto tostr_stack_top = m_match_stack.size(); + + m_match_stack.push_back(make_node("to_string", start.line, start.col)); + + const auto ev_stack_top = m_match_stack.size(); + + try { + ChaiScript_Parser parser; + parser.parse(eval_match, "instr eval"); + m_match_stack.push_back(parser.ast()); + } catch (const exception::eval_error &e) { + throw exception::eval_error(e.what(), File_Position(start.line, start.col), *m_filename); + } + + build_match(ev_stack_top); + build_match(tostr_stack_top); + build_match(prev_stack_top, "+"); + } else { + throw exception::eval_error("Unclosed in-string eval", File_Position(start.line, start.col), *m_filename); + } + } else { + match.push_back('$'); + } + cparser.saw_interpolation_marker = false; + } else { + cparser.parse(*s, start.line, start.col, *m_filename); + ++s; + } + } + + return cparser.is_interpolated; + }(); + + if (is_interpolated) { m_match_stack.push_back(make_node(match, start.line, start.col)); build_match(prev_stack_top, "+"); @@ -1129,10 +1172,14 @@ namespace chaiscript const auto start = m_position; if (Single_Quoted_String_()) { std::string match; - Char_Parser cparser(false); - for (auto s = start + 1, end = m_position - 1; s != end; ++s) { - cparser.parse(match, *s, start.line, start.col, *m_filename); + { + // scope for cparser destrutor + Char_Parser cparser(match, false); + + for (auto s = start + 1, end = m_position - 1; s != end; ++s) { + cparser.parse(*s, start.line, start.col, *m_filename); + } } m_match_stack.push_back(make_node(match, start.line, start.col)); diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index e8cae19..e5ba4f7 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -384,8 +384,6 @@ class JSON return std::to_string( Internal.Int ); case Class::Boolean: return Internal.Bool ? "true" : "false"; - default: - return ""; } } @@ -548,7 +546,7 @@ namespace { JSON parse_number( const string &str, size_t &offset ) { JSON Number; string val, exp_str; - char c; + char c = '\0'; bool isDouble = false; long exp = 0; for (; offset < str.size() ;) { From 18e5ee0ba213dca0608810e4942c90bd7b58c10a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 2 Oct 2015 12:16:44 -0600 Subject: [PATCH 050/131] Wrap up generic string escape support Closes #211 --- .../chaiscript/language/chaiscript_parser.hpp | 50 +++++++++++++++---- unittests/hex_escapes.chai | 6 +++ unittests/octal_escapes.chai | 6 +++ 3 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 unittests/hex_escapes.chai create mode 100644 unittests/octal_escapes.chai diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index ebb8bfc..bd902f1 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -949,23 +949,28 @@ namespace chaiscript return false; } + template struct Char_Parser { - std::string &match; + string_type &match; + using char_type = typename string_type::value_type; bool is_escaped; bool is_interpolated; bool saw_interpolation_marker; bool is_octal; + bool is_hex; const bool interpolation_allowed; - std::string octal_matches; + string_type octal_matches; + string_type hex_matches; - Char_Parser(std::string &t_match, const bool t_interpolation_allowed) + Char_Parser(string_type &t_match, const bool t_interpolation_allowed) : match(t_match), is_escaped(false), is_interpolated(false), saw_interpolation_marker(false), is_octal(false), + is_hex(false), interpolation_allowed(t_interpolation_allowed) { } @@ -974,18 +979,32 @@ namespace chaiscript if (is_octal) { process_octal(); } + + if (is_hex) { + process_hex(); + } } + void process_hex() + { + auto val = stoll(hex_matches, 0, 16); + match.push_back(char_type(val)); + hex_matches.clear(); + is_escaped = false; + is_hex = false; + } + + void process_octal() { - int val = stoi(octal_matches, 0, 8); - match.push_back(char(val)); + auto val = stoll(octal_matches, 0, 8); + match.push_back(char_type(val)); octal_matches.clear(); is_escaped = false; is_octal = false; } - void parse(const char t_char, const int line, const int col, const std::string &filename) { + void parse(const char_type t_char, const int line, const int col, const std::string &filename) { if (t_char == '\\') { if (is_escaped) { match.push_back('\\'); @@ -995,7 +1014,7 @@ namespace chaiscript } } else { if (is_escaped) { - bool is_octal_char = t_char >= '0' && t_char <= '7'; + const bool is_octal_char = t_char >= '0' && t_char <= '7'; if (is_octal) { if (is_octal_char) { @@ -1008,9 +1027,22 @@ namespace chaiscript process_octal(); match.push_back(t_char); } + } else if (is_hex) { + const bool is_hex_char = (t_char >= '0' && t_char <= '9') + || (t_char >= 'a' && t_char <= 'f') + || (t_char >= 'A' && t_char <= 'F'); + + if (is_hex_char) { + hex_matches.push_back(t_char); + } else { + process_hex(); + match.push_back(t_char); + } } else if (is_octal_char) { is_octal = true; octal_matches.push_back(t_char); + } else if (t_char == 'x') { + is_hex = true; } else { switch (t_char) { case ('\'') : match.push_back('\''); break; @@ -1053,7 +1085,7 @@ namespace chaiscript const auto prev_stack_top = m_match_stack.size(); bool is_interpolated = [&]() { - Char_Parser cparser(match, true); + Char_Parser cparser(match, true); auto s = start + 1, end = m_position - 1; @@ -1175,7 +1207,7 @@ namespace chaiscript { // scope for cparser destrutor - Char_Parser cparser(match, false); + Char_Parser cparser(match, false); for (auto s = start + 1, end = m_position - 1; s != end; ++s) { cparser.parse(*s, start.line, start.col, *m_filename); diff --git a/unittests/hex_escapes.chai b/unittests/hex_escapes.chai new file mode 100644 index 0000000..283ef87 --- /dev/null +++ b/unittests/hex_escapes.chai @@ -0,0 +1,6 @@ + +assert_equal("\x39", "9") +assert_equal("\x039", "9") +assert_equal("\x39g", "9g") +assert_equal("b\x39g", "b9g") + diff --git a/unittests/octal_escapes.chai b/unittests/octal_escapes.chai new file mode 100644 index 0000000..83b5392 --- /dev/null +++ b/unittests/octal_escapes.chai @@ -0,0 +1,6 @@ + +assert_equal("\71", "9") +assert_equal("\071", "9") +assert_equal("\71a", "9a") +assert_equal("b\71a", "b9a") + From 9d183603334662bf58a81a37f76ac4a9ff126e9b Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 2 Oct 2015 12:46:50 -0600 Subject: [PATCH 051/131] Older compiler backport issues --- include/chaiscript/language/chaiscript_parser.hpp | 4 ++-- include/chaiscript/utility/json.hpp | 4 +++- include/chaiscript/utility/json_wrap.hpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index bd902f1..ddc2111 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -953,7 +953,7 @@ namespace chaiscript struct Char_Parser { string_type &match; - using char_type = typename string_type::value_type; + typedef typename string_type::value_type char_type; bool is_escaped; bool is_interpolated; bool saw_interpolation_marker; @@ -1084,7 +1084,7 @@ namespace chaiscript std::string match; const auto prev_stack_top = m_match_stack.size(); - bool is_interpolated = [&]() { + bool is_interpolated = [&]()->bool { Char_Parser cparser(match, true); diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index e5ba4f7..893f7bf 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -249,7 +249,7 @@ class JSON SetType( Class::Object ); return Internal.Map->operator[]( key ); } - JSON& operator[]( unsigned index ) { + JSON& operator[]( const size_t index ) { SetType( Class::Array ); if( index >= Internal.List->size() ) Internal.List->resize( index + 1 ); return Internal.List->operator[]( index ); @@ -385,6 +385,8 @@ class JSON case Class::Boolean: return Internal.Bool ? "true" : "false"; } + + throw std::runtime_error("Unhandled JSON type"); } friend std::ostream& operator<<( std::ostream&, const JSON & ); diff --git a/include/chaiscript/utility/json_wrap.hpp b/include/chaiscript/utility/json_wrap.hpp index 1b0631d..d15528f 100644 --- a/include/chaiscript/utility/json_wrap.hpp +++ b/include/chaiscript/utility/json_wrap.hpp @@ -12,7 +12,7 @@ namespace chaiscript static ModulePtr library(ModulePtr m = std::make_shared()) { - m->add(chaiscript::fun([](const std::string &t_str) { return json_wrap::from_json(t_str); }), "from_json"); + m->add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json"); m->add(chaiscript::fun(&json_wrap::to_json), "to_json"); return m; From beedf13d01696bfd05a6ecbc825b4270646ddb49 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 3 Oct 2015 16:38:41 -0600 Subject: [PATCH 052/131] Make binary literals sized like other integer types --- include/chaiscript/dispatchkit/bootstrap.hpp | 2 + .../chaiscript/language/chaiscript_parser.hpp | 126 +++++++----------- unittests/integer_literal_test.cpp | 3 +- unittests/number_suffixes.chai | 4 +- 4 files changed, 55 insertions(+), 80 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 0cd7bab..ef5a94b 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -509,6 +509,8 @@ namespace chaiscript bootstrap_pod_type("long", m); bootstrap_pod_type("unsigned_int", m); bootstrap_pod_type("unsigned_long", m); + bootstrap_pod_type("long_long", m); + bootstrap_pod_type("unsigned_long_long", m); bootstrap_pod_type("size_t", m); bootstrap_pod_type("char", m); bootstrap_pod_type("wchar_t", m); diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index ddc2111..a05129a 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -621,8 +621,7 @@ namespace chaiscript - template - static Boxed_Value buildInt(const IntType &t_type, const std::string &t_val) + static Boxed_Value buildInt(const int base, const std::string &t_val, const bool prefixed) { bool unsigned_ = false; bool long_ = false; @@ -649,52 +648,57 @@ namespace chaiscript } } - std::stringstream ss(t_val.substr(0, i)); - ss >> t_type; - std::stringstream testu(t_val.substr(0, i)); - uint64_t u; - testu >> t_type >> u; - - bool unsignedrequired = false; - - if ((u >> (sizeof(int) * 8)) > 0) - { - //requires something bigger than int - long_ = true; - } + const auto val = prefixed?std::string(t_val.begin()+2,t_val.end()):t_val; static_assert(sizeof(long) == sizeof(uint64_t) || sizeof(long) * 2 == sizeof(uint64_t), "Unexpected sizing of integer types"); + bool unsignedrequired = false; - if ((sizeof(long) < sizeof(uint64_t)) - && (u >> ((sizeof(uint64_t) - sizeof(long)) * 8)) > 0) - { - //requires something bigger than long - longlong_ = true; - } + try { + auto u = std::stoll(val,nullptr,base); - - const size_t size = [&]()->size_t{ - if (longlong_) + if ((u >> (sizeof(int) * 8)) > 0) { - return sizeof(int64_t) * 8; - } else if (long_) { - return sizeof(long) * 8; - } else { - return sizeof(int) * 8; + //requires something bigger than int + long_ = true; } - }(); - if ( (u >> (size - 1)) > 0) - { + if ((sizeof(long) < sizeof(uint64_t)) + && (u >> ((sizeof(uint64_t) - sizeof(long)) * 8)) > 0) + { + //requires something bigger than long + longlong_ = true; + } + + const size_t size = [&]()->size_t{ + if (longlong_) + { + return sizeof(int64_t) * 8; + } else if (long_) { + return sizeof(long) * 8; + } else { + return sizeof(int) * 8; + } + }(); + + if ( (u >> (size - 1)) > 0) + { + unsignedrequired = true; + } + } catch (const std::out_of_range &) { + // it cannot fit in a signed long long... + std::cout << "forcing long long for '" << val << "'\n"; unsignedrequired = true; + + long_ = sizeof(unsigned long long) == sizeof(unsigned long); + longlong_ = sizeof(unsigned long long) != sizeof(unsigned long); } if (unsignedrequired && !unsigned_) { - if (t_type == &std::hex || t_type == &std::oct) + if (base != 10) { - // with hex and octal we are happy to just make it unsigned + // with bin, hex and oct we are happy to just make it unsigned unsigned_ = true; } else { // with decimal we must bump it up to the next size @@ -711,32 +715,20 @@ namespace chaiscript { if (longlong_) { - uint64_t val; - ss >> val; - return const_var(val); + return const_var(stoull(val,nullptr,base)); } else if (long_) { - unsigned long val; - ss >> val; - return const_var(val); + return const_var(stoul(val,nullptr,base)); } else { - unsigned int val; - ss >> val; - return const_var(val); + return const_var(static_cast(stoul(val,nullptr,base))); } } else { if (longlong_) { - int64_t val; - ss >> val; - return const_var(val); + return const_var(stoll(val,nullptr,base)); } else if (long_) { - long val; - ss >> val; - return const_var(val); + return const_var(stol(val,nullptr,base)); } else { - int val; - ss >> val; - return const_var(val); + return const_var(stoi(val,nullptr,base)); } } } @@ -758,35 +750,15 @@ namespace chaiscript if (m_position.has_more() && char_in_alphabet(*m_position, detail::float_alphabet) ) { if (Hex_()) { auto match = Position::str(start, m_position); - auto bv = buildInt(std::hex, match); + auto bv = buildInt(16, match, true); m_match_stack.emplace_back(make_node(std::move(match), start.line, start.col, std::move(bv))); return true; } if (Binary_()) { auto match = Position::str(start, m_position); - int64_t temp_int = 0; - size_t pos = 0; - const auto end = match.length(); - - while ((pos < end) && (pos < (2 + sizeof(int) * 8))) { - temp_int <<= 1; - if (match[pos] == '1') { - temp_int += 1; - } - ++pos; - } - - Boxed_Value i = [&]()->Boxed_Value{ - if (match.length() <= sizeof(int) * 8) - { - return const_var(static_cast(temp_int)); - } else { - return const_var(temp_int); - } - }(); - - m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(i))); + auto bv = buildInt(2, match, true); + m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); return true; } if (Float_()) { @@ -799,11 +771,11 @@ namespace chaiscript IntSuffix_(); auto match = Position::str(start, m_position); if (!match.empty() && (match[0] == '0')) { - auto bv = buildInt(std::oct, match); + auto bv = buildInt(8, match, false); m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); } else if (!match.empty()) { - auto bv = buildInt(std::dec, match); + auto bv = buildInt(10, match, false); m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); } else { return false; diff --git a/unittests/integer_literal_test.cpp b/unittests/integer_literal_test.cpp index ecaff8a..9a02c20 100644 --- a/unittests/integer_literal_test.cpp +++ b/unittests/integer_literal_test.cpp @@ -5,9 +5,10 @@ template bool test_literal(T val, const std::string &str) { + std::cout << "Comparing : " << val; chaiscript::ChaiScript chai; T val2 = chai.eval(str); - std::cout << "Comparing : " << val << " " << val2 << '\n'; + std::cout << " " << val2 << '\n'; return val == val2; } diff --git a/unittests/number_suffixes.chai b/unittests/number_suffixes.chai index 99ac03f..b8fd1f5 100644 --- a/unittests/number_suffixes.chai +++ b/unittests/number_suffixes.chai @@ -2,8 +2,8 @@ assert_equal(true, int_type.bare_equal(1.get_type_info())) assert_equal(true, unsigned_int_type.bare_equal(1u.get_type_info())) assert_equal(true, unsigned_long_type.bare_equal(1lu.get_type_info())) assert_equal(true, long_type.bare_equal(1l.get_type_info())) -assert_equal(true, int64_t_type.bare_equal(1ll.get_type_info())) -assert_equal(true, uint64_t_type.bare_equal(1ull.get_type_info())) +assert_equal(true, long_long_type.bare_equal(1ll.get_type_info())) +assert_equal(true, unsigned_long_long_type.bare_equal(1ull.get_type_info())) assert_equal(true, double_type.bare_equal(1.6.get_type_info())) assert_equal(true, float_type.bare_equal(1.6f.get_type_info())) From e221ceaa4c3fd8254ff730ec96e9010105936471 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 3 Oct 2015 17:11:03 -0600 Subject: [PATCH 053/131] Greatly simplify integer sizing code --- .../chaiscript/language/chaiscript_parser.hpp | 87 ++++--------------- 1 file changed, 17 insertions(+), 70 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index a05129a..c995f7d 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -648,87 +648,34 @@ namespace chaiscript } } - const auto val = prefixed?std::string(t_val.begin()+2,t_val.end()):t_val; - static_assert(sizeof(long) == sizeof(uint64_t) || sizeof(long) * 2 == sizeof(uint64_t), "Unexpected sizing of integer types"); - bool unsignedrequired = false; +// static_assert(sizeof(long) == sizeof(uint64_t) || sizeof(long) * 2 == sizeof(uint64_t), "Unexpected sizing of integer types"); try { auto u = std::stoll(val,nullptr,base); - if ((u >> (sizeof(int) * 8)) > 0) - { - //requires something bigger than int - long_ = true; + if (!unsigned_ && !long_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { + return const_var(static_cast(u)); + } else if ((unsigned_ || base != 10) && !long_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { + return const_var(static_cast(u)); + } else if (!unsigned_ && !longlong_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { + return const_var(static_cast(u)); + } else if ((unsigned_ || base != 10) && !longlong_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { + return const_var(static_cast(u)); + } else if (!unsigned_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { + return const_var(static_cast(u)); + } else { + return const_var(static_cast(u)); } - if ((sizeof(long) < sizeof(uint64_t)) - && (u >> ((sizeof(uint64_t) - sizeof(long)) * 8)) > 0) - { - //requires something bigger than long - longlong_ = true; - } - - const size_t size = [&]()->size_t{ - if (longlong_) - { - return sizeof(int64_t) * 8; - } else if (long_) { - return sizeof(long) * 8; - } else { - return sizeof(int) * 8; - } - }(); - - if ( (u >> (size - 1)) > 0) - { - unsignedrequired = true; - } } catch (const std::out_of_range &) { - // it cannot fit in a signed long long... - std::cout << "forcing long long for '" << val << "'\n"; - unsignedrequired = true; + auto u = std::stoull(val,nullptr,base); - long_ = sizeof(unsigned long long) == sizeof(unsigned long); - longlong_ = sizeof(unsigned long long) != sizeof(unsigned long); - } - - if (unsignedrequired && !unsigned_) - { - if (base != 10) - { - // with bin, hex and oct we are happy to just make it unsigned - unsigned_ = true; + if (u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { + return const_var(static_cast(u)); } else { - // with decimal we must bump it up to the next size - if (long_) - { - longlong_ = true; - } else if (!long_ && !longlong_) { - long_ = true; - } - } - } - - if (unsigned_) - { - if (longlong_) - { - return const_var(stoull(val,nullptr,base)); - } else if (long_) { - return const_var(stoul(val,nullptr,base)); - } else { - return const_var(static_cast(stoul(val,nullptr,base))); - } - } else { - if (longlong_) - { - return const_var(stoll(val,nullptr,base)); - } else if (long_) { - return const_var(stol(val,nullptr,base)); - } else { - return const_var(stoi(val,nullptr,base)); + return const_var(static_cast(u)); } } } From d2cf12f94849c453927fbb840451158ace649207 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 3 Oct 2015 21:01:52 -0600 Subject: [PATCH 054/131] Add tests for binary literals --- .../chaiscript/language/chaiscript_parser.hpp | 12 +++++-- unittests/integer_literal_test.cpp | 33 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index c995f7d..f582ab1 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -650,11 +650,14 @@ namespace chaiscript const auto val = prefixed?std::string(t_val.begin()+2,t_val.end()):t_val; -// static_assert(sizeof(long) == sizeof(uint64_t) || sizeof(long) * 2 == sizeof(uint64_t), "Unexpected sizing of integer types"); - try { auto u = std::stoll(val,nullptr,base); +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" +#endif + if (!unsigned_ && !long_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { return const_var(static_cast(u)); } else if ((unsigned_ || base != 10) && !long_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { @@ -669,6 +672,11 @@ namespace chaiscript return const_var(static_cast(u)); } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + + } catch (const std::out_of_range &) { auto u = std::stoull(val,nullptr,base); diff --git a/unittests/integer_literal_test.cpp b/unittests/integer_literal_test.cpp index 9a02c20..58e954a 100644 --- a/unittests/integer_literal_test.cpp +++ b/unittests/integer_literal_test.cpp @@ -75,6 +75,39 @@ int main() && TEST_LITERAL(177777777777777777) && TEST_LITERAL(1777777777777777777) + && test_literal(0xF, "0b1111") + && test_literal(0xFF, "0b11111111") + && test_literal(0xFFF, "0b111111111111") + && test_literal(0xFFFF, "0b1111111111111111") + && test_literal(0xFFFFF, "0b11111111111111111111") + && test_literal(0xFFFFFF, "0b111111111111111111111111") + && test_literal(0xFFFFFFF, "0b1111111111111111111111111111") + && test_literal(0xFFFFFFFF, "0b11111111111111111111111111111111") + && test_literal(0xFFFFFFFFF, "0b111111111111111111111111111111111111") + && test_literal(0xFFFFFFFFFF, "0b1111111111111111111111111111111111111111") + && test_literal(0xFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111") + && test_literal(0xFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111") + && test_literal(0xFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111") + && test_literal(0xFFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111") + && test_literal(0xFFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111") + && test_literal(0xFFFFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111111111111") + + && test_literal(0x7, "0b111") + && test_literal(0x7F, "0b1111111") + && test_literal(0x7FF, "0b11111111111") + && test_literal(0x7FFF, "0b111111111111111") + && test_literal(0x7FFFF, "0b1111111111111111111") + && test_literal(0x7FFFFF, "0b11111111111111111111111") + && test_literal(0x7FFFFFF, "0b111111111111111111111111111") + && test_literal(0x7FFFFFFF, "0b1111111111111111111111111111111") + && test_literal(0x7FFFFFFFF, "0b11111111111111111111111111111111111") + && test_literal(0x7FFFFFFFFF, "0b111111111111111111111111111111111111111") + && test_literal(0x7FFFFFFFFFF, "0b1111111111111111111111111111111111111111111") + && test_literal(0x7FFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111") + && test_literal(0x7FFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111") + && test_literal(0x7FFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111") + && test_literal(0x7FFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111111") + && test_literal(0x7FFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111111") ) { return EXIT_SUCCESS; From 14b3870efb4eb25a49d5af34636de6ab3060cb40 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 4 Oct 2015 08:53:22 -0600 Subject: [PATCH 055/131] Fix integer overflow and bad numeric parses --- .../chaiscript/language/chaiscript_parser.hpp | 80 +++++++++++-------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index f582ab1..57387d3 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -676,14 +676,19 @@ namespace chaiscript #pragma GCC diagnostic pop #endif - } catch (const std::out_of_range &) { - auto u = std::stoull(val,nullptr,base); + // too big to be signed + try { + auto u = std::stoull(val,nullptr,base); - if (u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { - return const_var(static_cast(u)); - } else { - return const_var(static_cast(u)); + if (u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { + return const_var(static_cast(u)); + } else { + return const_var(static_cast(u)); + } + } catch (const std::out_of_range &) { + // it's just simply too big + return const_var(std::numeric_limits::max()); } } } @@ -703,39 +708,44 @@ namespace chaiscript } else { const auto start = m_position; if (m_position.has_more() && char_in_alphabet(*m_position, detail::float_alphabet) ) { - if (Hex_()) { - auto match = Position::str(start, m_position); - auto bv = buildInt(16, match, true); - m_match_stack.emplace_back(make_node(std::move(match), start.line, start.col, std::move(bv))); - return true; - } + try { + if (Hex_()) { + auto match = Position::str(start, m_position); + auto bv = buildInt(16, match, true); + m_match_stack.emplace_back(make_node(std::move(match), start.line, start.col, std::move(bv))); + return true; + } - if (Binary_()) { - auto match = Position::str(start, m_position); - auto bv = buildInt(2, match, true); - m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); - return true; - } - if (Float_()) { - auto match = Position::str(start, m_position); - auto bv = buildFloat(match); - m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); - return true; - } - else { - IntSuffix_(); - auto match = Position::str(start, m_position); - if (!match.empty() && (match[0] == '0')) { - auto bv = buildInt(8, match, false); + if (Binary_()) { + auto match = Position::str(start, m_position); + auto bv = buildInt(2, match, true); m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); + return true; } - else if (!match.empty()) { - auto bv = buildInt(10, match, false); - m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); - } else { - return false; + if (Float_()) { + auto match = Position::str(start, m_position); + auto bv = buildFloat(match); + m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); + return true; } - return true; + else { + IntSuffix_(); + auto match = Position::str(start, m_position); + if (!match.empty() && (match[0] == '0')) { + auto bv = buildInt(8, match, false); + m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); + } + else if (!match.empty()) { + auto bv = buildInt(10, match, false); + m_match_stack.push_back(make_node(std::move(match), start.line, start.col, std::move(bv))); + } else { + return false; + } + return true; + } + } catch (const std::invalid_argument &) { + // error parsing number passed in to buildFloat/buildInt + return false; } } else { From 1add4c4b0f05a355158f2b2e0bfc36329bc9c8e8 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 4 Oct 2015 14:32:23 -0600 Subject: [PATCH 056/131] Fix issues with integer parsing on MSVC See #212 --- .../chaiscript/language/chaiscript_parser.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 57387d3..11a2d04 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -17,9 +17,19 @@ #include + #include "../dispatchkit/boxed_value.hpp" #include "chaiscript_common.hpp" + +#if defined(CHAISCRIPT_MSVC) && defined(max) && defined(min) +#pragma push_macro("max") // Why Microsoft? why? This is worse than bad +#undef max +#pragma push_macro("min") +#undef min +#endif + + namespace chaiscript { /// \brief Classes and functions used during the parsing process. @@ -912,6 +922,8 @@ namespace chaiscript { } + Char_Parser &operator=(const Char_Parser &) = delete; + ~Char_Parser(){ if (is_octal) { process_octal(); @@ -2393,5 +2405,12 @@ namespace chaiscript } } + +#ifdef CHAISCRIPT_MSVC +#pragma pop_macro("min") +#pragma pop_macro("max") +#endif + + #endif /* CHAISCRIPT_PARSER_HPP_ */ From 3e62a99f821433f690ee69a0ffa00b28ff70208f Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 7 Oct 2015 09:55:15 -0600 Subject: [PATCH 057/131] Add factory example with scripted callbacks --- CMakeLists.txt | 2 + samples/factory.cpp | 103 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 samples/factory.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 07ae809..417f74a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -259,6 +259,8 @@ if(BUILD_SAMPLES) target_link_libraries(memory_leak_test ${LIBS}) add_executable(inheritance samples/inheritance.cpp) target_link_libraries(inheritance ${LIBS}) + add_executable(factory samples/factory.cpp) + target_link_libraries(factory ${LIBS}) add_executable(fun_call_performance samples/fun_call_performance.cpp) target_link_libraries(fun_call_performance ${LIBS}) endif() diff --git a/samples/factory.cpp b/samples/factory.cpp new file mode 100644 index 0000000..ac8eb47 --- /dev/null +++ b/samples/factory.cpp @@ -0,0 +1,103 @@ +#include +#include + +class Entity +{ + public: + int width; + int height; + int x; + int y; + std::string name; + + std::function updater; + + Entity(const int t_width, const int t_height, const int t_x, const int t_y, std::string t_name) + : width(t_width), height(t_height), x(t_x), y(t_y), name(std::move(t_name)) + { + } +}; + +class Factory +{ + public: + // we may as well pass the parameters for the entity to the factory method, this does the initialization + // in one step. + Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name) + { + auto entity = entities.insert({name, Entity{width, height, x, y, name}}); + return &(entity.first->second); + } + + Entity *get_entity(const std::string &name) + { + return &entities.at(name); + } + + + // loop over all entities and all their updater function (if it exists) + void update_entities() + { + for (auto &entity : entities) + { + if (entity.second.updater) { + entity.second.updater(entity.second); + } + } + } + + + private: + // we cannot store the entities in a std::vector if we want to return a pointer to them, + // because a vector automatically resizing itself can invalidate the pointer that was returned. + // using a map guarantees that the memory assigned to the entity will never change, plus + // lets us easily look up an entity by name + std::map entities; +}; + +int main() +{ + chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); + + chai.add(chaiscript::fun(&Entity::width), "width"); + chai.add(chaiscript::fun(&Entity::height), "height"); + chai.add(chaiscript::fun(&Entity::x), "x"); + chai.add(chaiscript::fun(&Entity::y), "y"); + chai.add(chaiscript::fun(&Entity::name), "name"); + chai.add(chaiscript::fun(&Entity::updater), "updater"); + chai.add(chaiscript::user_type(), "Entity"); // this isn't strictly necessary but makes error messages nicer + + chai.add(chaiscript::fun(&Factory::make_entity), "make_entity"); + chai.add(chaiscript::fun(&Factory::get_entity), "get_entity"); + chai.add(chaiscript::fun(&Factory::update_entities), "update_entities"); + chai.add(chaiscript::user_type(), "Factory"); // this isn't strictly necessary but makes error messages nicer + + + Factory f; + chai.add(chaiscript::var(&f), "f"); + + std::string script = R""( + f.make_entity(10,10,1,1,"entity1").updater = fun(e){ e.x += 1; e.y += 1 }; + f.make_entity(10,10,10,10,"entity2").updater = fun(e){ e.x += 2; e.y += 2 }; + f.make_entity(10,10,20,20,"entity3"); + + print(f.get_entity("entity1").x == 1) + print(f.get_entity("entity2").x == 10) + print(f.get_entity("entity3").x == 20) + + f.update_entities(); // this runs the function objects we set in the previous lines + // we should now see the updated values + + print(f.get_entity("entity1").x == 2) + print(f.get_entity("entity2").x == 12) + print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same + )""; + + + chai.eval(script); + + + +} + + From 84e2d449b9e51863db0edbe305feceb6a331e38a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 15 Oct 2015 15:02:49 -0600 Subject: [PATCH 058/131] Support `default` case in the non-last position --- .../chaiscript/language/chaiscript_eval.hpp | 2 +- .../chaiscript/language/chaiscript_parser.hpp | 2 ++ unittests/switch_default_2.chai | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 unittests/switch_default_2.chai diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index f6fde40..aa01de9 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -950,7 +950,7 @@ namespace chaiscript } else if (this->children[currentCase]->identifier == AST_Node_Type::Default) { this->children[currentCase]->eval(t_ss); - breaking = true; + hasMatched = true; } } catch (detail::Break_Loop &) { diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 11a2d04..d012e26 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -1807,6 +1807,8 @@ namespace chaiscript build_match(prev_stack_top); } else if (Keyword("default")) { + retval = true; + while (Eol()) {} if (!Block()) { diff --git a/unittests/switch_default_2.chai b/unittests/switch_default_2.chai new file mode 100644 index 0000000..5082ab6 --- /dev/null +++ b/unittests/switch_default_2.chai @@ -0,0 +1,18 @@ +var total = 0; + +switch(2) { + case (1) { + total += 1; + } + default { + total += 16; + } + case (3) { + total += 4; + } + case (4) { + total += 8; + } +} + +assert_equal(total, 28) From b11ebf9e8fe25db5d3ded4b834f3263be66ba978 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 15 Oct 2015 21:13:17 -0600 Subject: [PATCH 059/131] Add failing test for vector assignment operations --- unittests/vector_assignment.chai | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 unittests/vector_assignment.chai diff --git a/unittests/vector_assignment.chai b/unittests/vector_assignment.chai new file mode 100644 index 0000000..f3abc04 --- /dev/null +++ b/unittests/vector_assignment.chai @@ -0,0 +1,16 @@ +var v = [] +v.push_back(3.4, 1, "bob"); + +assert_true(v[0] == 3.4) +assert_true(v[1] == 1) +assert_true(v[2] == "bob") + +v[0] = 2.9 +v[1] = 3 +v[2] = "tom" + +assert_true(v[0] == 2.9) +assert_true(v[1] == 3) +assert_true(v[2] == "tom") + + From 36765df3c0f6a002536e035994d96111a2a20cb7 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 15 Oct 2015 21:20:12 -0600 Subject: [PATCH 060/131] Fix vector element assignment issues --- include/chaiscript/dispatchkit/bootstrap.hpp | 1 + include/chaiscript/dispatchkit/boxed_value.hpp | 7 +++++++ include/chaiscript/dispatchkit/dispatchkit.hpp | 8 +------- include/chaiscript/language/chaiscript_prelude.chai | 10 +++++----- unittests/vector_assignment.chai | 4 +++- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index ef5a94b..7e0fd6b 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -470,6 +470,7 @@ namespace chaiscript 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::clone_attrs), "clone_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/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index ae21382..1c2ebe7 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -297,6 +297,13 @@ namespace chaiscript return *this; } + Boxed_Value &clone_attrs(const Boxed_Value &t_obj) + { + copy_attrs(t_obj); + reset_return_value(); + return *this; + } + /// \returns true if the two Boxed_Values share the same internal type static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 806abae..305de99 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -1031,13 +1031,7 @@ namespace chaiscript uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); const auto funs = get_function(t_name, loc); if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed); - Boxed_Value bv = dispatch::dispatch(*funs.second, params, m_conversions); - // the result of a clone is never to be marked as a return_value - // \todo see if we can eliminate this comparison - if (t_name == "clone") { - bv.reset_return_value(); - } - return bv; + return dispatch::dispatch(*funs.second, params, m_conversions); } diff --git a/include/chaiscript/language/chaiscript_prelude.chai b/include/chaiscript/language/chaiscript_prelude.chai index acb8407..55514bb 100644 --- a/include/chaiscript/language/chaiscript_prelude.chai +++ b/include/chaiscript/language/chaiscript_prelude.chai @@ -41,25 +41,25 @@ def new(x) { } def clone(double x) { - double(x).copy_var_attrs(x) + double(x).clone_var_attrs(x) } def clone(string x) { - string(x).copy_var_attrs(x) + string(x).clone_var_attrs(x) } def clone(vector x) { - vector(x).copy_var_attrs(x) + vector(x).clone_var_attrs(x) } def clone(int x) { - int(x).copy_var_attrs(x) + int(x).clone_var_attrs(x) } def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x) { - eval(type_name(x))(x).copy_var_attrs(x); + eval(type_name(x))(x).clone_var_attrs(x); } diff --git a/unittests/vector_assignment.chai b/unittests/vector_assignment.chai index f3abc04..8646105 100644 --- a/unittests/vector_assignment.chai +++ b/unittests/vector_assignment.chai @@ -1,5 +1,7 @@ var v = [] -v.push_back(3.4, 1, "bob"); +v.push_back(3.4); +v.push_back(1); +v.push_back("bob"); assert_true(v[0] == 3.4) assert_true(v[1] == 1) From 84554ed0a501d8b586554f9050487b94955972f9 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 15 Oct 2015 21:32:16 -0600 Subject: [PATCH 061/131] Add another vector assignment test --- unittests/vector_assignment_3.chai | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 unittests/vector_assignment_3.chai diff --git a/unittests/vector_assignment_3.chai b/unittests/vector_assignment_3.chai new file mode 100644 index 0000000..61d4b58 --- /dev/null +++ b/unittests/vector_assignment_3.chai @@ -0,0 +1,5 @@ + +var v = [] +v.push_back(int(1)); +v[0] = 3; + From ad69bf7d38dc3511a0ffbb009e0b3be766c24df9 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 15 Oct 2015 21:42:25 -0600 Subject: [PATCH 062/131] Get vector push_back_ref working as expected --- include/chaiscript/dispatchkit/bootstrap.hpp | 1 + include/chaiscript/dispatchkit/bootstrap_stl.hpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 7e0fd6b..c063ca8 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -467,6 +467,7 @@ 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_return_value), "is_var_return_value"); + m->add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value"); 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"); diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 186ccba..8b55981 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -335,6 +335,7 @@ namespace chaiscript "def push_back(" + type + " container, x)\n" "{ \n" " if (x.is_var_return_value()) {\n" + " x.reset_var_return_value() \n" " container.push_back_ref(x) \n" " } else { \n" " container.push_back_ref(clone(x)); \n" @@ -375,6 +376,7 @@ namespace chaiscript "def push_front(" + type + " container, x)\n" "{ \n" " if (x.is_var_return_value()) {\n" + " x.reset_var_return_value() \n" " container.push_front_ref(x) \n" " } else { \n" " container.push_front_ref(clone(x)); \n" From 5aecb7f17b42928b1780986419423532258257c7 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 15 Oct 2015 21:59:46 -0600 Subject: [PATCH 063/131] Add boolean comparison tests #217 --- unittests/bool_comparisons.chai | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 unittests/bool_comparisons.chai diff --git a/unittests/bool_comparisons.chai b/unittests/bool_comparisons.chai new file mode 100644 index 0000000..6fdea7a --- /dev/null +++ b/unittests/bool_comparisons.chai @@ -0,0 +1,12 @@ + +assert_true(true == true) +assert_false(true == false) +assert_true(true != false) +assert_true(false != true) +assert_true(false || true) +assert_true(true || false) +assert_false(true && false) +assert_false(false && true) +assert_true(!false) +assert_false(!true) + From 985b62705f448accd2843665e7674a5905ec3579 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 15 Oct 2015 22:06:06 -0600 Subject: [PATCH 064/131] Add support for != bools closes #217 --- 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 c063ca8..ac8c5dc 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -494,6 +494,7 @@ namespace chaiscript basic_constructors("bool", m); operators::assign(m); operators::equal(m); + operators::not_equal(m); m->add(fun([](const std::string &s) -> std::string { return s; }), "to_string"); m->add(fun(&Bootstrap::bool_to_string), "to_string"); From 3a675bf379cc38c4b7c3902ccd603b9272cdb910 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 16 Oct 2015 18:21:49 -0600 Subject: [PATCH 065/131] Add config option for compiling with gprof output --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07ae809..0b67b72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,13 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(LINKER_FLAGS "${LINKER_FLAGS} -flto") endif() + option(GPROF_OUTPUT "Generate profile data" FALSE) + if (GPROF_OUTPUT) + add_definitions(-pg) + set(LINKER_FLAGS "${LINKER_FLAGS} -pg") + endif() + + option(PROFILE_GENERATE "Generate profile data" FALSE) if (PROFILE_GENERATE) add_definitions(-fprofile-generate) From 38b98c55ccd97ef38d941ab019c1aace5e33e9f2 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 16 Oct 2015 18:37:02 -0600 Subject: [PATCH 066/131] Add test for dynamic object option explicit --- .../dynamic_object_dynamic_attrs_explicit.chai | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 unittests/dynamic_object_dynamic_attrs_explicit.chai diff --git a/unittests/dynamic_object_dynamic_attrs_explicit.chai b/unittests/dynamic_object_dynamic_attrs_explicit.chai new file mode 100644 index 0000000..b26b610 --- /dev/null +++ b/unittests/dynamic_object_dynamic_attrs_explicit.chai @@ -0,0 +1,14 @@ + +class MyClass { + def MyClass() + { + this.set_explicit(true); + } +}; + +var o = MyClass(); + +assert_true(o.is_explicit()); + +assert_throws(fun[o](){o.x = 2}) + From 882cbf2dfbe0bd50a03c8a5056754f18d1d63300 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 16 Oct 2015 18:47:26 -0600 Subject: [PATCH 067/131] Add option explicit code, but don't throw yet Work towards #218 --- include/chaiscript/dispatchkit/bootstrap.hpp | 2 ++ include/chaiscript/dispatchkit/dynamic_object.hpp | 15 +++++++++++++-- .../dynamic_object_dynamic_attrs_explicit.chai | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index ac8c5dc..7e3a301 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -440,6 +440,8 @@ namespace chaiscript m->add(constructor(), "Dynamic_Object"); m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name"); m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs"); + m->add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit"); + m->add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit"); m->add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), "get_attr"); m->add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), "get_attr"); diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 9ea827c..7df1abf 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -28,14 +28,24 @@ namespace chaiscript { public: Dynamic_Object(std::string t_type_name) - : m_type_name(std::move(t_type_name)) + : m_type_name(std::move(t_type_name)), m_option_explicit(false) { } - Dynamic_Object() : m_type_name("") + Dynamic_Object() : m_type_name(""), m_option_explicit(false) { } + bool is_explicit() const + { + return m_option_explicit; + } + + void set_explicit(const bool t_explicit) + { + m_option_explicit = t_explicit; + } + std::string get_type_name() const { return m_type_name; @@ -85,6 +95,7 @@ namespace chaiscript private: std::string m_type_name; + bool m_option_explicit; std::map m_attrs; }; diff --git a/unittests/dynamic_object_dynamic_attrs_explicit.chai b/unittests/dynamic_object_dynamic_attrs_explicit.chai index b26b610..b37dc0f 100644 --- a/unittests/dynamic_object_dynamic_attrs_explicit.chai +++ b/unittests/dynamic_object_dynamic_attrs_explicit.chai @@ -10,5 +10,5 @@ var o = MyClass(); assert_true(o.is_explicit()); -assert_throws(fun[o](){o.x = 2}) +assert_throws("error", fun[o](){o.x = 2}) From 7ba7b81a5cd6ded8788d94040d9d66322aecb109 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 16 Oct 2015 21:41:54 -0600 Subject: [PATCH 068/131] Implement option explicit for dynamic objects. Closes #218 --- cheatsheet.md | 12 ++++++++++++ include/chaiscript/dispatchkit/dispatchkit.hpp | 17 +++++++++++------ .../chaiscript/dispatchkit/dynamic_object.hpp | 18 ++++++++++++++++++ .../chaiscript/dispatchkit/proxy_functions.hpp | 8 ++++++++ 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/cheatsheet.md b/cheatsheet.md index 9ff4ad4..841cb92 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -354,6 +354,18 @@ o.f = fun(y) { print(this.x + y); } o.f(10); // prints 13 ``` +### Option Explicit + +If you want to disable dynamic parameter definitions, you can `set_explicit`. + +``` +class My_Class { + def My_Class() { + this.set_explicit(true); + this.x = 2; // this would fail with explicit set to true + } +}; + ## method_missing A function of the signature `method_missing(object, name, param1, param2, param3)` will be called if an appropriate diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 305de99..aa09486 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -1002,12 +1002,17 @@ namespace chaiscript }(); if (!functions.empty()) { - if (is_no_param) { - std::vector tmp_params(params); - tmp_params.insert(tmp_params.begin() + 1, var(t_name)); - return do_attribute_call(2, tmp_params, functions, m_conversions); - } else { - return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector(params.begin()+1, params.end()))}, m_conversions); + try { + if (is_no_param) { + std::vector tmp_params(params); + tmp_params.insert(tmp_params.begin() + 1, var(t_name)); + return do_attribute_call(2, tmp_params, functions, m_conversions); + } else { + return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector(params.begin()+1, params.end()))}, m_conversions); + } + } catch (const dispatch::option_explicit_set &e) { + throw chaiscript::exception::dispatch_error(params, std::vector(funs.second->begin(), funs.second->end()), + e.what()); } } diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 7df1abf..eaabf9b 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -24,6 +24,16 @@ namespace chaiscript { namespace dispatch { + struct option_explicit_set : std::runtime_error { + option_explicit_set(const std::string &t_param_name) + : std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") + { + + } + + virtual ~option_explicit_set() CHAISCRIPT_NOEXCEPT {} + }; + class Dynamic_Object { public: @@ -79,11 +89,19 @@ namespace chaiscript Boxed_Value &method_missing(const std::string &t_method_name) { + if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) { + throw option_explicit_set(t_method_name); + } + return get_attr(t_method_name); } const Boxed_Value &method_missing(const std::string &t_method_name) const { + if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) { + throw option_explicit_set(t_method_name); + } + return get_attr(t_method_name); } diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index d9da2e6..6214b4d 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -760,6 +760,14 @@ namespace chaiscript { } + dispatch_error(std::vector t_parameters, + std::vector t_functions, + const std::string &t_desc) + : std::runtime_error(t_desc), parameters(std::move(t_parameters)), functions(std::move(t_functions)) + { + } + + dispatch_error(const dispatch_error &) = default; virtual ~dispatch_error() CHAISCRIPT_NOEXCEPT {} From 09748275db98e2d75964307e78b9c20a72beb81b Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 17 Oct 2015 09:22:13 -0600 Subject: [PATCH 069/131] Fix warnings from clang --- .decent_ci-Linux.yaml | 2 +- .../chaiscript/dispatchkit/dynamic_object.hpp | 2 ++ .../chaiscript/language/chaiscript_parser.hpp | 17 ++++++++++------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.decent_ci-Linux.yaml b/.decent_ci-Linux.yaml index 24990bd..246241a 100644 --- a/.decent_ci-Linux.yaml +++ b/.decent_ci-Linux.yaml @@ -12,7 +12,7 @@ compilers: build_tag: AddressSanitizer version: "3.6" skip_packaging: true - cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON + cmake_extra_flags: -DRUN_FUZZY_TESTS:BOOL=TRUE -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON - name: "clang" build_tag: ThreadSanitizer version: "3.6" diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index eaabf9b..1e79eea 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -31,6 +31,8 @@ namespace chaiscript } + option_explicit_set(const option_explicit_set &) = default; + virtual ~option_explicit_set() CHAISCRIPT_NOEXCEPT {} }; diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index d012e26..a9b9311 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -660,14 +660,16 @@ namespace chaiscript const auto val = prefixed?std::string(t_val.begin()+2,t_val.end()):t_val; - try { - auto u = std::stoll(val,nullptr,base); - #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wtautological-compare" #endif + try { + auto u = std::stoll(val,nullptr,base); + + if (!unsigned_ && !long_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { return const_var(static_cast(u)); } else if ((unsigned_ || base != 10) && !long_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { @@ -682,10 +684,6 @@ namespace chaiscript return const_var(static_cast(u)); } -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - } catch (const std::out_of_range &) { // too big to be signed try { @@ -701,6 +699,11 @@ namespace chaiscript return const_var(std::numeric_limits::max()); } } + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + } template From bc388e59da50c56cb813927b3b2e0ba2e1127634 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 17 Oct 2015 09:23:05 -0600 Subject: [PATCH 070/131] Fix style warning from cppcheck --- samples/test_num_exceptions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/test_num_exceptions.cpp b/samples/test_num_exceptions.cpp index ba97f7a..36bbb75 100644 --- a/samples/test_num_exceptions.cpp +++ b/samples/test_num_exceptions.cpp @@ -23,7 +23,7 @@ int main( int /*argc*/ , char * /*argv*/[] ) { ch.eval( script ); } - catch ( std::exception e ) + catch ( const std::exception &e ) { printf( " >>> Exception thrown: %s \n" , e.what( ) ); } From 8496a860432615cbee02b0ac28bc100dae4f1a06 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 20 Oct 2015 18:14:42 -0600 Subject: [PATCH 071/131] Use a bitset instead of bools for type_info flags --- include/chaiscript/dispatchkit/type_info.hpp | 38 ++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 0d5c5f3..105440b 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace chaiscript { @@ -32,17 +33,17 @@ namespace chaiscript CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void, bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti) : m_type_info(t_ti), m_bare_type_info(t_bare_ti), - m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer), - m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic), - m_is_undef(false) + m_flags((t_is_const << is_const_flag) + + (t_is_reference << is_reference_flag) + + (t_is_pointer << is_pointer_flag) + + (t_is_void << is_void_flag) + + (t_is_arithmetic << is_arithmetic_flag)) { } CHAISCRIPT_CONSTEXPR Type_Info() : m_type_info(nullptr), m_bare_type_info(nullptr), - m_is_const(false), m_is_reference(false), m_is_pointer(false), - m_is_void(false), m_is_arithmetic(false), - m_is_undef(true) + m_flags(1 << is_undef_flag) { } @@ -83,12 +84,12 @@ namespace chaiscript && (*m_bare_type_info) == ti; } - CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_is_const; } - CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; } - CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; } - CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; } - CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef; } - CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; } + CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_flags[is_const_flag]; } + CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_flags[is_reference_flag]; } + CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_flags[is_void_flag]; } + CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_flags[is_arithmetic_flag]; } + CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_flags[is_undef_flag]; } + CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_flags[is_pointer_flag]; } std::string name() const { @@ -118,12 +119,13 @@ namespace chaiscript private: const std::type_info *m_type_info; const std::type_info *m_bare_type_info; - bool m_is_const; - bool m_is_reference; - bool m_is_pointer; - bool m_is_void; - bool m_is_arithmetic; - bool m_is_undef; + std::bitset<6> m_flags; + static const int is_const_flag = 0; + static const int is_reference_flag = 1; + static const int is_pointer_flag = 2; + static const int is_void_flag = 3; + static const int is_arithmetic_flag = 4; + static const int is_undef_flag = 5; }; namespace detail From c9a5bf6f83ce60be005dd720375e30b98481f87d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 20 Oct 2015 18:19:03 -0600 Subject: [PATCH 072/131] fix warning from GCC for unknown flag --- include/chaiscript/chaiscript_defines.hpp | 6 +++++- include/chaiscript/language/chaiscript_parser.hpp | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 5c54051..c2ba4ae 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -39,7 +39,11 @@ #define CHAISCRIPT_GCC_4_6 #endif -#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(__llvm__) +#if defined(__llvm__) +#define CHAISCRIPT_CLANG +#endif + +#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(CHAISCRIPT_CLANG) #define CHAISCRIPT_OVERRIDE override #else #define CHAISCRIPT_OVERRIDE diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index a9b9311..37b717f 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -663,7 +663,11 @@ namespace chaiscript #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" + +#ifdef CHAISCRIPT_CLANG #pragma GCC diagnostic ignored "-Wtautological-compare" +#endif + #endif try { From 40b1549b3bdd53503bf4170465d2df132185aabe Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 21 Oct 2015 09:30:22 -0600 Subject: [PATCH 073/131] Fix use of broken bitset implementation in g++ --- include/chaiscript/dispatchkit/type_info.hpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 105440b..5be3a2e 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -11,7 +11,6 @@ #include #include #include -#include namespace chaiscript { @@ -84,12 +83,12 @@ namespace chaiscript && (*m_bare_type_info) == ti; } - CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_flags[is_const_flag]; } - CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_flags[is_reference_flag]; } - CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_flags[is_void_flag]; } - CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_flags[is_arithmetic_flag]; } - CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_flags[is_undef_flag]; } - CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_flags[is_pointer_flag]; } + CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_const_flag); } + CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_reference_flag); } + CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_void_flag); } + CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_arithmetic_flag); } + CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_undef_flag); } + CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_pointer_flag); } std::string name() const { @@ -119,7 +118,7 @@ namespace chaiscript private: const std::type_info *m_type_info; const std::type_info *m_bare_type_info; - std::bitset<6> m_flags; + unsigned int m_flags; static const int is_const_flag = 0; static const int is_reference_flag = 1; static const int is_pointer_flag = 2; From 0806df11d2ddfd5cece49636af8994ba2ab56649 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 23 Oct 2015 16:25:16 -0600 Subject: [PATCH 074/131] Performance test reorg to run automatically --- CMakeLists.txt | 30 +++-- cmake/CheckCXX11Features.cmake | 103 ------------------ cmake/c++11-test-__func__-N2340.cpp | 8 -- cmake/c++11-test-auto-N2546.cpp | 12 -- cmake/c++11-test-constexpr-N2235.cpp | 19 ---- cmake/c++11-test-cstdint.cpp | 10 -- cmake/c++11-test-decltype-N2343.cpp | 11 -- cmake/c++11-test-lambda-N2927.cpp | 5 - cmake/c++11-test-long_long-N1811.cpp | 7 -- cmake/c++11-test-nullptr-N2431.cpp | 5 - .../c++11-test-nullptr-N2431_fail_compile.cpp | 5 - cmake/c++11-test-rvalue_references-N2118.cpp | 15 --- cmake/c++11-test-sizeof_member-N2253.cpp | 14 --- cmake/c++11-test-static_assert-N1720.cpp | 5 - ...-test-static_assert-N1720_fail_compile.cpp | 5 - cmake/c++11-test-variadic_templates-N2555.cpp | 23 ---- .../heterogenous_array_loop.chai | 0 .../is_prime.chai | 0 .../profile.chai | 0 .../profile_cpp_calls.chai | 0 .../profile_math.chai | 0 .../type_conversions.chai | 0 22 files changed, 19 insertions(+), 258 deletions(-) delete mode 100644 cmake/CheckCXX11Features.cmake delete mode 100644 cmake/c++11-test-__func__-N2340.cpp delete mode 100644 cmake/c++11-test-auto-N2546.cpp delete mode 100644 cmake/c++11-test-constexpr-N2235.cpp delete mode 100644 cmake/c++11-test-cstdint.cpp delete mode 100644 cmake/c++11-test-decltype-N2343.cpp delete mode 100644 cmake/c++11-test-lambda-N2927.cpp delete mode 100644 cmake/c++11-test-long_long-N1811.cpp delete mode 100644 cmake/c++11-test-nullptr-N2431.cpp delete mode 100644 cmake/c++11-test-nullptr-N2431_fail_compile.cpp delete mode 100644 cmake/c++11-test-rvalue_references-N2118.cpp delete mode 100644 cmake/c++11-test-sizeof_member-N2253.cpp delete mode 100644 cmake/c++11-test-static_assert-N1720.cpp delete mode 100644 cmake/c++11-test-static_assert-N1720_fail_compile.cpp delete mode 100644 cmake/c++11-test-variadic_templates-N2555.cpp rename {contrib/codeanalysis => performance_tests}/heterogenous_array_loop.chai (100%) rename {contrib/codeanalysis => performance_tests}/is_prime.chai (100%) rename {contrib/codeanalysis => performance_tests}/profile.chai (100%) rename {contrib/codeanalysis => performance_tests}/profile_cpp_calls.chai (100%) rename {contrib/codeanalysis => performance_tests}/profile_math.chai (100%) rename {contrib/codeanalysis => performance_tests}/type_conversions.chai (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 00f5658..8025748 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,16 +122,12 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile) include(CTest) include(CPack) -include(cmake/CheckCXX11Features.cmake) - if(NOT MINGW) find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib) endif() -if(HAS_CXX11_VARIADIC_TEMPLATES) - message(STATUS "Variadic Template support detected") -else() - message(SEND_ERROR "The selected compiler does not support the C++11 feature Variadic Templates.") +if (UNIX AND NOT APPLE) + find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin) endif() enable_testing() @@ -283,6 +279,9 @@ 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) list(SORT UNIT_TESTS) +file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/*.chai) +list(SORT PERFORMANCE_TESTS) + if (RUN_FUZZY_TESTS) @@ -347,8 +346,8 @@ if(BUILD_TESTING) string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents}) foreach(hit ${found_tests}) string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit}) - add_test(${test_name} "${executable}" ${test_name}) - set_tests_properties(${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}") + add_test(compiled.${test_name} "${executable}" ${test_name}) + set_tests_properties(compiled.${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}") endforeach() endif() endif() @@ -382,12 +381,21 @@ if(BUILD_TESTING) ) + set(TESTS "") + foreach(filename ${UNIT_TESTS}) - message(STATUS "Adding test ${filename}") - add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename}) + message(STATUS "Adding unit test ${filename}") + add_test(unit.${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename}) + list(APPEND TESTS unit.${filename}) endforeach() - set_property(TEST ${UNIT_TESTS} + foreach(filename ${PERFORMANCE_TESTS}) + message(STATUS "Adding performance test ${filename}") + add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename}) + list(APPEND TESTS performance.${filename}) + endforeach() + + set_property(TEST ${TESTS} PROPERTY ENVIRONMENT "CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/" "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" diff --git a/cmake/CheckCXX11Features.cmake b/cmake/CheckCXX11Features.cmake deleted file mode 100644 index 27b823d..0000000 --- a/cmake/CheckCXX11Features.cmake +++ /dev/null @@ -1,103 +0,0 @@ -# Checks for C++11 features -# CXX11_FEATURE_LIST - a list containing all supported features -# HAS_CXX11_AUTO - auto keyword -# HAS_CXX11_NULLPTR - nullptr -# HAS_CXX11_LAMBDA - lambdas -# HAS_CXX11_STATIC_ASSERT - static_assert() -# HAS_CXX11_RVALUE_REFERENCES - rvalue references -# HAS_CXX11_DECLTYPE - decltype keyword -# HAS_CXX11_CSTDINT_H - cstdint header -# HAS_CXX11_LONG_LONG - long long signed & unsigned types -# HAS_CXX11_VARIADIC_TEMPLATES - variadic templates -# HAS_CXX11_CONSTEXPR - constexpr keyword -# HAS_CXX11_SIZEOF_MEMBER - sizeof() non-static members -# HAS_CXX11_FUNC - __func__ preprocessor constant -# -# Original script by Rolf Eike Beer -# Modifications by Andreas Weis -# -CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3) - -SET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) -IF(CMAKE_COMPILER_IS_GNUCXX) - SET(CMAKE_CXX_FLAGS "-std=c++0x") -endif() - -MACRO(CXX11_CHECK_FEATURE FEATURE_NAME FEATURE_NUMBER RESULT_VAR) - IF (NOT DEFINED ${RESULT_VAR}) - SET(_bindir "${CMAKE_CURRENT_BINARY_DIR}/cxx11/cxx11_${FEATURE_NAME}") - - IF (${FEATURE_NUMBER}) - SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME}-N${FEATURE_NUMBER}) - SET(_LOG_NAME "\"${FEATURE_NAME}\" (N${FEATURE_NUMBER})") - ELSE (${FEATURE_NUMBER}) - SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME}) - SET(_LOG_NAME "\"${FEATURE_NAME}\"") - ENDIF (${FEATURE_NUMBER}) - MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME}") - - SET(_SRCFILE "${_SRCFILE_BASE}.cpp") - SET(_SRCFILE_FAIL "${_SRCFILE_BASE}_fail.cpp") - SET(_SRCFILE_FAIL_COMPILE "${_SRCFILE_BASE}_fail_compile.cpp") - - IF (CROSS_COMPILING) - try_compile(${RESULT_VAR} "${_bindir}" "${_SRCFILE}") - IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL}) - try_compile(${RESULT_VAR} "${_bindir}_fail" "${_SRCFILE_FAIL}") - ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL}) - ELSE (CROSS_COMPILING) - try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR - "${_bindir}" "${_SRCFILE}") - IF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR) - SET(${RESULT_VAR} TRUE) - ELSE (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR) - SET(${RESULT_VAR} FALSE) - ENDIF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR) - IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL}) - try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR - "${_bindir}_fail" "${_SRCFILE_FAIL}") - IF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR) - SET(${RESULT_VAR} TRUE) - ELSE (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR) - SET(${RESULT_VAR} FALSE) - ENDIF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR) - ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL}) - ENDIF (CROSS_COMPILING) - IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE}) - try_compile(_TMP_RESULT "${_bindir}_fail_compile" "${_SRCFILE_FAIL_COMPILE}") - IF (_TMP_RESULT) - SET(${RESULT_VAR} FALSE) - ELSE (_TMP_RESULT) - SET(${RESULT_VAR} TRUE) - ENDIF (_TMP_RESULT) - ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE}) - - IF (${RESULT_VAR}) - MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- works") - LIST(APPEND CXX11_FEATURE_LIST ${RESULT_VAR}) - ELSE (${RESULT_VAR}) - MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- not supported") - ENDIF (${RESULT_VAR}) - SET(${RESULT_VAR} ${${RESULT_VAR}} CACHE INTERNAL "C++11 support for ${_LOG_NAME}") - ENDIF (NOT DEFINED ${RESULT_VAR}) -ENDMACRO(CXX11_CHECK_FEATURE) - -CXX11_CHECK_FEATURE("auto" 2546 HAS_CXX11_AUTO) -CXX11_CHECK_FEATURE("nullptr" 2431 HAS_CXX11_NULLPTR) -CXX11_CHECK_FEATURE("lambda" 2927 HAS_CXX11_LAMBDA) -CXX11_CHECK_FEATURE("static_assert" 1720 HAS_CXX11_STATIC_ASSERT) -CXX11_CHECK_FEATURE("rvalue_references" 2118 HAS_CXX11_RVALUE_REFERENCES) -CXX11_CHECK_FEATURE("decltype" 2343 HAS_CXX11_DECLTYPE) -CXX11_CHECK_FEATURE("cstdint" "" HAS_CXX11_CSTDINT_H) -CXX11_CHECK_FEATURE("long_long" 1811 HAS_CXX11_LONG_LONG) -CXX11_CHECK_FEATURE("variadic_templates" 2555 HAS_CXX11_VARIADIC_TEMPLATES) -CXX11_CHECK_FEATURE("constexpr" 2235 HAS_CXX11_CONSTEXPR) -CXX11_CHECK_FEATURE("sizeof_member" 2253 HAS_CXX11_SIZEOF_MEMBER) -CXX11_CHECK_FEATURE("__func__" 2340 HAS_CXX11_FUNC) - -SET(CXX11_FEATURE_LIST ${CXX11_FEATURE_LIST} CACHE STRING "C++11 feature support list") -MARK_AS_ADVANCED(FORCE CXX11_FEATURE_LIST) - -SET(CMAKE_CXX_FLAGS ${CHECK_CXX11_OLD_CMAKE_CXX_FLAGS}) -UNSET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS) - diff --git a/cmake/c++11-test-__func__-N2340.cpp b/cmake/c++11-test-__func__-N2340.cpp deleted file mode 100644 index d961df8..0000000 --- a/cmake/c++11-test-__func__-N2340.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -int main() -{ - if (!__func__) { return 1; } - if(std::strlen(__func__) <= 0) { return 1; } - return 0; -} diff --git a/cmake/c++11-test-auto-N2546.cpp b/cmake/c++11-test-auto-N2546.cpp deleted file mode 100644 index 948648e..0000000 --- a/cmake/c++11-test-auto-N2546.cpp +++ /dev/null @@ -1,12 +0,0 @@ - -int main() -{ - auto i = 5; - auto f = 3.14159f; - auto d = 3.14159; - bool ret = ( - (sizeof(f) < sizeof(d)) && - (sizeof(i) == sizeof(int)) - ); - return ret ? 0 : 1; -} diff --git a/cmake/c++11-test-constexpr-N2235.cpp b/cmake/c++11-test-constexpr-N2235.cpp deleted file mode 100644 index ed62451..0000000 --- a/cmake/c++11-test-constexpr-N2235.cpp +++ /dev/null @@ -1,19 +0,0 @@ -constexpr int square(int x) -{ - return x*x; -} - -constexpr int the_answer() -{ - return 42; -} - -int main() -{ - int test_arr[square(3)]; - bool ret = ( - (square(the_answer()) == 1764) && - (sizeof(test_arr)/sizeof(test_arr[0]) == 9) - ); - return ret ? 0 : 1; -} diff --git a/cmake/c++11-test-cstdint.cpp b/cmake/c++11-test-cstdint.cpp deleted file mode 100644 index be2878f..0000000 --- a/cmake/c++11-test-cstdint.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include -int main() -{ - bool test = - (sizeof(int8_t) == 1) && - (sizeof(int16_t) == 2) && - (sizeof(int32_t) == 4) && - (sizeof(int64_t) == 8); - return test ? 0 : 1; -} diff --git a/cmake/c++11-test-decltype-N2343.cpp b/cmake/c++11-test-decltype-N2343.cpp deleted file mode 100644 index 843f83a..0000000 --- a/cmake/c++11-test-decltype-N2343.cpp +++ /dev/null @@ -1,11 +0,0 @@ - -bool check_size(int i) -{ - return sizeof(int) == sizeof(decltype(i)); -} - -int main() -{ - bool ret = check_size(42); - return ret ? 0 : 1; -} diff --git a/cmake/c++11-test-lambda-N2927.cpp b/cmake/c++11-test-lambda-N2927.cpp deleted file mode 100644 index 4c33ed5..0000000 --- a/cmake/c++11-test-lambda-N2927.cpp +++ /dev/null @@ -1,5 +0,0 @@ -int main() -{ - int ret = 0; - return ([&ret]() -> int { return ret; })(); -} diff --git a/cmake/c++11-test-long_long-N1811.cpp b/cmake/c++11-test-long_long-N1811.cpp deleted file mode 100644 index 0911127..0000000 --- a/cmake/c++11-test-long_long-N1811.cpp +++ /dev/null @@ -1,7 +0,0 @@ -int main(void) -{ - long long l; - unsigned long long ul; - - return ((sizeof(l) >= 8) && (sizeof(ul) >= 8)) ? 0 : 1; -} diff --git a/cmake/c++11-test-nullptr-N2431.cpp b/cmake/c++11-test-nullptr-N2431.cpp deleted file mode 100644 index c78fac4..0000000 --- a/cmake/c++11-test-nullptr-N2431.cpp +++ /dev/null @@ -1,5 +0,0 @@ -int main() -{ - int* test = nullptr; - return test ? 1 : 0; -} diff --git a/cmake/c++11-test-nullptr-N2431_fail_compile.cpp b/cmake/c++11-test-nullptr-N2431_fail_compile.cpp deleted file mode 100644 index 7ab77a2..0000000 --- a/cmake/c++11-test-nullptr-N2431_fail_compile.cpp +++ /dev/null @@ -1,5 +0,0 @@ -int main() -{ - int i = nullptr; - return 1; -} diff --git a/cmake/c++11-test-rvalue_references-N2118.cpp b/cmake/c++11-test-rvalue_references-N2118.cpp deleted file mode 100644 index 75fb555..0000000 --- a/cmake/c++11-test-rvalue_references-N2118.cpp +++ /dev/null @@ -1,15 +0,0 @@ -int foo(int& lvalue) -{ - return 123; -} - -int foo(int&& rvalue) -{ - return 321; -} - -int main() -{ - int i = 42; - return ((foo(i) == 123) && (foo(42) == 321)) ? 0 : 1; -} diff --git a/cmake/c++11-test-sizeof_member-N2253.cpp b/cmake/c++11-test-sizeof_member-N2253.cpp deleted file mode 100644 index a55fc09..0000000 --- a/cmake/c++11-test-sizeof_member-N2253.cpp +++ /dev/null @@ -1,14 +0,0 @@ -struct foo { - char bar; - int baz; -}; - -int main(void) -{ - bool ret = ( - (sizeof(foo::bar) == 1) && - (sizeof(foo::baz) >= sizeof(foo::bar)) && - (sizeof(foo) >= sizeof(foo::bar)+sizeof(foo::baz)) - ); - return ret ? 0 : 1; -} diff --git a/cmake/c++11-test-static_assert-N1720.cpp b/cmake/c++11-test-static_assert-N1720.cpp deleted file mode 100644 index c3d74ca..0000000 --- a/cmake/c++11-test-static_assert-N1720.cpp +++ /dev/null @@ -1,5 +0,0 @@ -int main() -{ - static_assert(0 < 1, "your ordering of integers is screwed"); - return 0; -} diff --git a/cmake/c++11-test-static_assert-N1720_fail_compile.cpp b/cmake/c++11-test-static_assert-N1720_fail_compile.cpp deleted file mode 100644 index 4cb1183..0000000 --- a/cmake/c++11-test-static_assert-N1720_fail_compile.cpp +++ /dev/null @@ -1,5 +0,0 @@ -int main() -{ - static_assert(1 < 0, "this should fail"); - return 0; -} diff --git a/cmake/c++11-test-variadic_templates-N2555.cpp b/cmake/c++11-test-variadic_templates-N2555.cpp deleted file mode 100644 index 4518e88..0000000 --- a/cmake/c++11-test-variadic_templates-N2555.cpp +++ /dev/null @@ -1,23 +0,0 @@ -int Accumulate() -{ - return 0; -} - -template -int Accumulate(T v, Ts... vs) -{ - return v + Accumulate(vs...); -} - -template -int CountElements() -{ - return sizeof...(Is); -} - -int main() -{ - int acc = Accumulate(1, 2, 3, 4, -5); - int count = CountElements<1,2,3,4,5>(); - return ((acc == 5) && (count == 5)) ? 0 : 1; -} diff --git a/contrib/codeanalysis/heterogenous_array_loop.chai b/performance_tests/heterogenous_array_loop.chai similarity index 100% rename from contrib/codeanalysis/heterogenous_array_loop.chai rename to performance_tests/heterogenous_array_loop.chai diff --git a/contrib/codeanalysis/is_prime.chai b/performance_tests/is_prime.chai similarity index 100% rename from contrib/codeanalysis/is_prime.chai rename to performance_tests/is_prime.chai diff --git a/contrib/codeanalysis/profile.chai b/performance_tests/profile.chai similarity index 100% rename from contrib/codeanalysis/profile.chai rename to performance_tests/profile.chai diff --git a/contrib/codeanalysis/profile_cpp_calls.chai b/performance_tests/profile_cpp_calls.chai similarity index 100% rename from contrib/codeanalysis/profile_cpp_calls.chai rename to performance_tests/profile_cpp_calls.chai diff --git a/contrib/codeanalysis/profile_math.chai b/performance_tests/profile_math.chai similarity index 100% rename from contrib/codeanalysis/profile_math.chai rename to performance_tests/profile_math.chai diff --git a/contrib/codeanalysis/type_conversions.chai b/performance_tests/type_conversions.chai similarity index 100% rename from contrib/codeanalysis/type_conversions.chai rename to performance_tests/type_conversions.chai From 8bd7ccfa9f9899035438d97de07caac825a76ed4 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 23 Oct 2015 16:38:04 -0600 Subject: [PATCH 075/131] Only run performance tests on linux --- .decent_ci-Linux.yaml | 4 ++-- CMakeLists.txt | 14 +++++++++----- include/chaiscript/dispatchkit/type_info.hpp | 12 ++++++------ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.decent_ci-Linux.yaml b/.decent_ci-Linux.yaml index 246241a..0188db0 100644 --- a/.decent_ci-Linux.yaml +++ b/.decent_ci-Linux.yaml @@ -2,7 +2,7 @@ compilers: - name: "clang" version: "3.5" skip_packaging: true - cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON + cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON - name: "clang" build_tag: "LibC++" version: "3.5" @@ -20,7 +20,7 @@ compilers: cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON - name: "gcc" version: "4.8" - cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON + cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON - name: "gcc" version: "4.6" skip_packaging: true diff --git a/CMakeLists.txt b/CMakeLists.txt index 8025748..471784c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ option(BUILD_MODULES "Build Extra Modules (stl)" TRUE) option(BUILD_SAMPLES "Build Samples Folder" FALSE) option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE) option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE) +option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE) mark_as_advanced(USE_STD_MAKE_SHARED) @@ -389,11 +390,14 @@ if(BUILD_TESTING) list(APPEND TESTS unit.${filename}) endforeach() - foreach(filename ${PERFORMANCE_TESTS}) - message(STATUS "Adding performance test ${filename}") - add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename}) - list(APPEND TESTS performance.${filename}) - endforeach() + if (RUN_PERFORMANCE_TESTS) + foreach(filename ${PERFORMANCE_TESTS}) + message(STATUS "Adding performance test ${filename}") + + add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename}) + list(APPEND TESTS performance.${filename}) + endforeach() + endif() set_property(TEST ${TESTS} PROPERTY ENVIRONMENT diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 5be3a2e..9cb338c 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -83,12 +83,12 @@ namespace chaiscript && (*m_bare_type_info) == ti; } - CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_const_flag); } - CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_reference_flag); } - CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_void_flag); } - CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_arithmetic_flag); } - CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_undef_flag); } - CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_pointer_flag); } + CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_const_flag)); } + CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_reference_flag)); } + CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_void_flag)); } + CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_arithmetic_flag)); } + CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_undef_flag)); } + CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_pointer_flag)); } std::string name() const { From da1511a0925398e2e328d1426fcdef6bc8135af7 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 23 Oct 2015 20:38:51 -0600 Subject: [PATCH 076/131] Enable collection of performance results where possible --- .decent_ci-Linux.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.decent_ci-Linux.yaml b/.decent_ci-Linux.yaml index 0188db0..495b699 100644 --- a/.decent_ci-Linux.yaml +++ b/.decent_ci-Linux.yaml @@ -3,6 +3,7 @@ compilers: version: "3.5" skip_packaging: true cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON + collect_performance_results: true - name: "clang" build_tag: "LibC++" version: "3.5" @@ -21,10 +22,12 @@ compilers: - name: "gcc" version: "4.8" cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON + collect_performance_results: true - name: "gcc" version: "4.6" skip_packaging: true - cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON + cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON + collect_performance_results: true - name: cppcheck compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*" --suppress="*:unittests/catch.hpp" --force From d9f86a96f035676018b9f3c4bc396015d0c7382c Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 3 Nov 2015 15:59:43 -0700 Subject: [PATCH 077/131] Add initial failing test --- unittests/compiled_tests.cpp | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 9d1df58..ce3bcf9 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -785,3 +785,54 @@ TEST_CASE("Variable Scope When Calling From C++ 2") } + +struct Returned_Converted_Config +{ + int num_iterations; + int something_else; + std::string a_string; + std::function a_function; +}; + + +TEST_CASE("Return of converted type from script") +{ + chaiscript::ChaiScript chai; + + chai.add(chaiscript::constructor(), "Returned_Converted_Config"); + chai.add(chaiscript::fun(&Returned_Converted_Config::num_iterations), "num_iterations"); + chai.add(chaiscript::fun(&Returned_Converted_Config::something_else), "something_else"); + chai.add(chaiscript::fun(&Returned_Converted_Config::a_string), "a_string"); + chai.add(chaiscript::fun(&Returned_Converted_Config::a_function), "a_function"); + chai.add(chaiscript::vector_conversion>()); + + auto c = chai.eval>(R"( + var c = Returned_Converted_Config(); + + c.num_iterations = 5; + c.something_else = c.num_iterations * 2; + c.a_string = "string"; + c.a_function = fun(s) { s.size(); } + + print("making vector"); + var v = []; + print("adding config item"); + v.push_back_ref(c); + print("returning vector"); + v; + + )"); + + + std::cout << typeid(decltype(c)).name() << std::endl; + + std::cout << "Info: " << c.size() << " " << &c[0] << std::endl; + + std::cout << "num_iterations " << c[0].num_iterations << '\n' + << "something_else " << c[0].something_else << '\n' + << "a_string " << c[0].a_string << '\n' + << "a_function " << c[0].a_function("bob") << '\n'; + + chai.add(chaiscript::user_type(), "Returned_Converted_Config"); +} + From 6fe7f5ce98261a4eb8778dacd1adf87bcfd13dcb Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 3 Nov 2015 16:02:25 -0700 Subject: [PATCH 078/131] Don't return reference to copied values --- .../dispatchkit/boxed_cast_helper.hpp | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index d8df9be..bb6835d 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -33,14 +33,14 @@ namespace chaiscript template struct Cast_Helper_Inner { - typedef std::reference_wrapper::type > Result_Type; + typedef typename std::add_const::type Result_Type; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { if (ob.get_type_info().bare_equal_type_info(typeid(Result))) { auto p = throw_if_null(ob.get_const_ptr()); - return std::cref(*static_cast(p)); + return *static_cast(p); } else { throw chaiscript::detail::exception::bad_any_cast(); } @@ -52,12 +52,6 @@ namespace chaiscript { }; - /// Cast_Helper_Inner for casting to a const & type - template - struct Cast_Helper_Inner : Cast_Helper_Inner - { - }; - /// Cast_Helper_Inner for casting to a const * type template @@ -91,6 +85,24 @@ namespace chaiscript } }; + /// Cast_Helper_Inner for casting to a & type + template + struct Cast_Helper_Inner + { + typedef const Result& Result_Type; + + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + { + if (ob.get_type_info().bare_equal_type_info(typeid(Result))) + { + auto p = throw_if_null(ob.get_const_ptr()); + return *static_cast(p); + } else { + throw chaiscript::detail::exception::bad_any_cast(); + } + } + }; + /// Cast_Helper_Inner for casting to a & type From 34c6b1721569ac23024ec648253b1352cda41aac Mon Sep 17 00:00:00 2001 From: Christian Kaeser Date: Sun, 8 Nov 2015 11:39:48 +0100 Subject: [PATCH 079/131] Fix broken escape sequence parsing after octal/hex escape The parser code just added the first character after an octal/hex sequence as raw text, resulting in erroneous data whenever another escape sequence follows directly after. --- .../chaiscript/language/chaiscript_parser.hpp | 52 ++++++++++--------- unittests/hex_escapes.chai | 1 + unittests/octal_escapes.chai | 1 + 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 37b717f..e50046d 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -961,6 +961,32 @@ namespace chaiscript } void parse(const char_type t_char, const int line, const int col, const std::string &filename) { + const bool is_octal_char = t_char >= '0' && t_char <= '7'; + + if (is_octal) { + if (is_octal_char) { + octal_matches.push_back(t_char); + + if (octal_matches.size() == 3) { + process_octal(); + } + return; + } else { + process_octal(); + } + } else if (is_hex) { + const bool is_hex_char = (t_char >= '0' && t_char <= '9') + || (t_char >= 'a' && t_char <= 'f') + || (t_char >= 'A' && t_char <= 'F'); + + if (is_hex_char) { + hex_matches.push_back(t_char); + return; + } else { + process_hex(); + } + } + if (t_char == '\\') { if (is_escaped) { match.push_back('\\'); @@ -970,31 +996,7 @@ namespace chaiscript } } else { if (is_escaped) { - const bool is_octal_char = t_char >= '0' && t_char <= '7'; - - if (is_octal) { - if (is_octal_char) { - octal_matches.push_back(t_char); - - if (octal_matches.size() == 3) { - process_octal(); - } - } else { - process_octal(); - match.push_back(t_char); - } - } else if (is_hex) { - const bool is_hex_char = (t_char >= '0' && t_char <= '9') - || (t_char >= 'a' && t_char <= 'f') - || (t_char >= 'A' && t_char <= 'F'); - - if (is_hex_char) { - hex_matches.push_back(t_char); - } else { - process_hex(); - match.push_back(t_char); - } - } else if (is_octal_char) { + if (is_octal_char) { is_octal = true; octal_matches.push_back(t_char); } else if (t_char == 'x') { diff --git a/unittests/hex_escapes.chai b/unittests/hex_escapes.chai index 283ef87..14ec62e 100644 --- a/unittests/hex_escapes.chai +++ b/unittests/hex_escapes.chai @@ -3,4 +3,5 @@ assert_equal("\x39", "9") assert_equal("\x039", "9") assert_equal("\x39g", "9g") assert_equal("b\x39g", "b9g") +assert_equal("\x39\x38g", "98g") diff --git a/unittests/octal_escapes.chai b/unittests/octal_escapes.chai index 83b5392..a220d57 100644 --- a/unittests/octal_escapes.chai +++ b/unittests/octal_escapes.chai @@ -3,4 +3,5 @@ assert_equal("\71", "9") assert_equal("\071", "9") assert_equal("\71a", "9a") assert_equal("b\71a", "b9a") +assert_equal("\71\70a", "98a") From 202204a82ac2160780e12a51ffa6b1357b3dea35 Mon Sep 17 00:00:00 2001 From: Christian Kaeser Date: Sun, 8 Nov 2015 18:36:16 +0100 Subject: [PATCH 080/131] Limit hexadecimal escape sequence length Helps with cases like "\xFFecho" by limiting the number of hex digits that will be parsed to maximum suitable for the char type. This rule differs from the C/C++ standard, but ChaiScript does not offer the same workaround options. Furthermore, without it having hexadecimal sequences longer than can fit into the char type is undefined behavior anyway. --- include/chaiscript/language/chaiscript_parser.hpp | 8 ++++++++ unittests/hex_escapes.chai | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index e50046d..6548521 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -981,6 +981,14 @@ namespace chaiscript if (is_hex_char) { hex_matches.push_back(t_char); + + if (hex_matches.size() == 2*sizeof(char_type)) { + // This rule differs from the C/C++ standard, but ChaiScript + // does not offer the same workaround options, and having + // hexadecimal sequences longer than can fit into the char + // type is undefined behavior anyway. + process_hex(); + } return; } else { process_hex(); diff --git a/unittests/hex_escapes.chai b/unittests/hex_escapes.chai index 14ec62e..fdd0a8a 100644 --- a/unittests/hex_escapes.chai +++ b/unittests/hex_escapes.chai @@ -1,6 +1,6 @@ assert_equal("\x39", "9") -assert_equal("\x039", "9") +assert_equal("\x39ec", "9ec") assert_equal("\x39g", "9g") assert_equal("b\x39g", "b9g") assert_equal("\x39\x38g", "98g") From 4826bddb5ba911c1744ab40e206cd3bd56c793d8 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 20 Nov 2015 07:46:52 -0600 Subject: [PATCH 081/131] Add overloads for cosnt *& casts --- .../dispatchkit/boxed_cast_helper.hpp | 17 ++++++++++++++--- unittests/boxed_cast_test.cpp | 4 ++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index bb6835d..c72edb7 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -62,7 +62,7 @@ namespace chaiscript { if (ob.get_type_info().bare_equal_type_info(typeid(Result))) { - return static_cast(throw_if_null(ob.get_const_ptr())); + return static_cast(ob.get_const_ptr()); } else { throw chaiscript::detail::exception::bad_any_cast(); } @@ -76,15 +76,26 @@ namespace chaiscript typedef Result * Result_Type; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { - if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result)) + if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result))) { - return static_cast(throw_if_null(ob.get_ptr())); + return static_cast(ob.get_ptr()); } else { throw chaiscript::detail::exception::bad_any_cast(); } } }; + template + struct Cast_Helper_Inner : public Cast_Helper_Inner + { + }; + + template + struct Cast_Helper_Inner : public Cast_Helper_Inner + { + }; + + /// Cast_Helper_Inner for casting to a & type template struct Cast_Helper_Inner diff --git a/unittests/boxed_cast_test.cpp b/unittests/boxed_cast_test.cpp index e575649..1e92874 100644 --- a/unittests/boxed_cast_test.cpp +++ b/unittests/boxed_cast_test.cpp @@ -13,9 +13,9 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass) try { To ret = chaiscript::boxed_cast(bv); use(ret); - } catch (const chaiscript::exception::bad_boxed_cast &/*e*/) { + } catch (const chaiscript::exception::bad_boxed_cast &e) { if (expectedpass) { -// std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n'; + std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n'; return false; } else { return true; From 49c89a3b884e7f75bbda6e31db90d987c5340658 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 25 Nov 2015 09:49:26 -0500 Subject: [PATCH 082/131] un-break ** cast operation --- include/chaiscript/dispatchkit/boxed_cast_helper.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index c72edb7..2e08777 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -76,7 +76,7 @@ namespace chaiscript typedef Result * Result_Type; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { - if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result))) + if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result)) { return static_cast(ob.get_ptr()); } else { From c249bef27df531a7d8791d91fbfdebf39d31c4ab Mon Sep 17 00:00:00 2001 From: Joshua Boyce Date: Sat, 26 Dec 2015 03:03:24 -0800 Subject: [PATCH 083/131] Fix multiply defined symbols. --- include/chaiscript/utility/json.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index 893f7bf..80b0530 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -421,22 +421,22 @@ class JSON Class Type; }; -JSON Array() { +inline JSON Array() { return JSON::Make( JSON::Class::Array ); } template -JSON Array( T... args ) { +inline JSON Array( T... args ) { JSON arr = JSON::Make( JSON::Class::Array ); arr.append( args... ); return arr; } -JSON Object() { +inline JSON Object() { return JSON::Make( JSON::Class::Object ); } -std::ostream& operator<<( std::ostream &os, const JSON &json ) { +inline std::ostream& operator<<( std::ostream &os, const JSON &json ) { os << json.dump(); return os; } From e60eabbeb289455e00aa3d553c429ee73f17c8a2 Mon Sep 17 00:00:00 2001 From: Joshua Boyce Date: Sat, 26 Dec 2015 03:04:05 -0800 Subject: [PATCH 084/131] Fix another multiply defined symbol. --- include/chaiscript/utility/json.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index 80b0530..c023c2b 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -636,7 +636,7 @@ namespace { } } -JSON JSON::Load( const string &str ) { +inline JSON JSON::Load( const string &str ) { size_t offset = 0; return parse_next( str, offset ); } From f0796b51c8541319378bfa53e180b9ab73be14be Mon Sep 17 00:00:00 2001 From: Viktor Rennert Date: Sat, 2 Jan 2016 14:17:36 +0100 Subject: [PATCH 085/131] Added template specialization in chaiscript::utility::add_class to register bulk constants. --- include/chaiscript/utility/utility.hpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index ecd5a3f..2704929 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -8,6 +8,7 @@ #define CHAISCRIPT_UTILITY_UTILITY_HPP_ #include +#include #include #include @@ -62,6 +63,21 @@ namespace chaiscript t_module.add(fun.first, fun.second); } } + + template + typename std::enable_if::value, void>::type + add_class(ModuleType &t_module, + const std::string &t_class_name, + const std::vector &t_constructors, + const std::vector> &t_constants) + { + t_module.add(chaiscript::user_type(), t_class_name); + + for (const auto &constant : t_constants) + { + t_module.add_global_const(constant.first, constant.second); + } + } } } From 316ba45e3c9fa72ff781011a770748fc53f20ec6 Mon Sep 17 00:00:00 2001 From: Viktor Rennert Date: Sat, 2 Jan 2016 20:54:55 +0100 Subject: [PATCH 086/131] Added unittest to cover utility::add_class registration. --- unittests/compiled_tests.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index da7eb7c..90095ac 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -517,6 +517,41 @@ TEST_CASE("Utility_Test utility class wrapper") } +enum Utility_Test_Numbers +{ + ONE, + TWO, + THREE +}; + +TEST_CASE("Utility_Test utility class wrapper") +{ + + chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module()); + + using namespace chaiscript; + + chaiscript::utility::add_class(*m, + "Utility_Test_Numbers", + { + }, + { { const_var(ONE), "ONE" }, + { const_var(TWO), "TWO" }, + { const_var(THREE), "THREE" } + + } + ); + + + chaiscript::ChaiScript chai; + chai.add(m); + + CHECK(chai.eval("ONE ") == 0); + CHECK(chai.eval("TWO ") == 1); + CHECK(chai.eval("THREE ") == 2); + +} + ////// Object copy count test From d7489358f3b14d580f27bb9fc0bc674dd53318f1 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 2 Jan 2016 19:24:14 -0700 Subject: [PATCH 087/131] Add failing test for vector of enum values --- unittests/compiled_tests.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 90095ac..ca5e9ec 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -2,6 +2,7 @@ // caught in other cpp files if chaiscript causes them #include +#include #ifdef CHAISCRIPT_MSVC #pragma warning(push) @@ -517,14 +518,19 @@ TEST_CASE("Utility_Test utility class wrapper") } + enum Utility_Test_Numbers { - ONE, + ONE, TWO, THREE }; -TEST_CASE("Utility_Test utility class wrapper") +void do_something_with_enum_vector(const std::vector &) +{ +} + +TEST_CASE("Utility_Test utility class wrapper for enum") { chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module()); @@ -538,7 +544,7 @@ TEST_CASE("Utility_Test utility class wrapper") { { const_var(ONE), "ONE" }, { const_var(TWO), "TWO" }, { const_var(THREE), "THREE" } - + } ); @@ -550,6 +556,12 @@ TEST_CASE("Utility_Test utility class wrapper") CHECK(chai.eval("TWO ") == 1); CHECK(chai.eval("THREE ") == 2); + chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector"); + chai.add(chaiscript::vector_conversion>()); + CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]")); + CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE])")); + CHECK_NOTHROW(chai.eval("[ONE]")); + } From e1c40f3e8f586abc5e88cf55e90fa28fb2428b50 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 2 Jan 2016 19:26:53 -0700 Subject: [PATCH 088/131] Automatically add copy constuctor for enums added with utility --- include/chaiscript/utility/utility.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index 2704929..4dfd079 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -72,7 +72,10 @@ namespace chaiscript 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); + for (const auto &constant : t_constants) { t_module.add_global_const(constant.first, constant.second); From e32714c456236327269d6e46dfb10c67fa4280f3 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 2 Jan 2016 19:45:10 -0700 Subject: [PATCH 089/131] Add some operators for Enums made with helper class --- include/chaiscript/utility/utility.hpp | 9 ++++++++- unittests/compiled_tests.cpp | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index 4dfd079..05c49c5 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -15,6 +15,7 @@ #include "../chaiscript.hpp" #include "../dispatchkit/proxy_functions.hpp" #include "../dispatchkit/type_info.hpp" +#include "../dispatchkit/operators.hpp" namespace chaiscript @@ -63,7 +64,7 @@ namespace chaiscript t_module.add(fun.first, fun.second); } } - + template typename std::enable_if::value, void>::type add_class(ModuleType &t_module, @@ -76,6 +77,12 @@ namespace chaiscript t_module.add(chaiscript::constructor(), t_class_name); t_module.add(chaiscript::constructor(), t_class_name); + t_module.add([](){ + // add some comparison and assignment operators + using namespace chaiscript::bootstrap::operators; + return assign(not_equal(equal())); + }()); + for (const auto &constant : t_constants) { t_module.add_global_const(constant.first, constant.second); diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index ca5e9ec..a028526 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -562,6 +562,11 @@ TEST_CASE("Utility_Test utility class wrapper for enum") CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE])")); CHECK_NOTHROW(chai.eval("[ONE]")); + CHECK(chai.eval("ONE == ONE")); + CHECK(chai.eval("ONE != TWO")); + CHECK_NOTHROW(chai.eval("var o = ONE; o = TWO")); + + } From 888d897a3eda962e6b765085bb40d115b05a3491 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 2 Jan 2016 19:59:54 -0700 Subject: [PATCH 090/131] Simplify use of enum helper --- include/chaiscript/utility/utility.hpp | 8 +++++--- unittests/compiled_tests.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index 05c49c5..381afda 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -69,8 +69,7 @@ namespace chaiscript typename std::enable_if::value, void>::type add_class(ModuleType &t_module, const std::string &t_class_name, - const std::vector &t_constructors, - const std::vector> &t_constants) + const std::vector::type, std::string>> &t_constants) { t_module.add(chaiscript::user_type(), t_class_name); @@ -83,9 +82,12 @@ namespace chaiscript return assign(not_equal(equal())); }()); + t_module.add(chaiscript::fun([](const Enum &e, const typename std::underlying_type::type &i) { return e == i; }), "=="); + t_module.add(chaiscript::fun([](const typename std::underlying_type::type &i, const Enum &e) { return i == e; }), "=="); + for (const auto &constant : t_constants) { - t_module.add_global_const(constant.first, constant.second); + t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second); } } } diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index a028526..6724973 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -539,11 +539,9 @@ TEST_CASE("Utility_Test utility class wrapper for enum") chaiscript::utility::add_class(*m, "Utility_Test_Numbers", - { - }, - { { const_var(ONE), "ONE" }, - { const_var(TWO), "TWO" }, - { const_var(THREE), "THREE" } + { { ONE, "ONE" }, + { TWO, "TWO" }, + { THREE, "THREE" } } ); @@ -556,6 +554,8 @@ TEST_CASE("Utility_Test utility class wrapper for enum") CHECK(chai.eval("TWO ") == 1); CHECK(chai.eval("THREE ") == 2); + CHECK(chai.eval("ONE == 0")); + chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector"); chai.add(chaiscript::vector_conversion>()); CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]")); From b55eff95cf54f5b61319330ce04e4aa30d9e445a Mon Sep 17 00:00:00 2001 From: Bobhostern Date: Sun, 3 Jan 2016 13:34:27 -0600 Subject: [PATCH 091/131] Fix formatting error in cheatsheet.md --- cheatsheet.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cheatsheet.md b/cheatsheet.md index 841cb92..5e78553 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -365,6 +365,7 @@ class My_Class { this.x = 2; // this would fail with explicit set to true } }; +``` ## method_missing From 208107fd7ecb5c898e301e5d3a985b681bd7db20 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 3 Jan 2016 17:58:05 -0700 Subject: [PATCH 092/131] Add additional tests for vector conversion --- unittests/compiled_tests.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 6724973..2782904 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -526,8 +526,12 @@ enum Utility_Test_Numbers THREE }; -void do_something_with_enum_vector(const std::vector &) +void do_something_with_enum_vector(const std::vector &v) { + CHECK(v.size() == 3); + CHECK(v[0] == ONE); + CHECK(v[1] == THREE); + CHECK(v[2] == TWO); } TEST_CASE("Utility_Test utility class wrapper for enum") @@ -559,9 +563,13 @@ TEST_CASE("Utility_Test utility class wrapper for enum") chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector"); chai.add(chaiscript::vector_conversion>()); CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]")); - CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE])")); + CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE, THREE, TWO])")); CHECK_NOTHROW(chai.eval("[ONE]")); + const auto v = chai.eval>("a"); + CHECK(v.size() == 3); + CHECK(v.at(1) == TWO); + CHECK(chai.eval("ONE == ONE")); CHECK(chai.eval("ONE != TWO")); CHECK_NOTHROW(chai.eval("var o = ONE; o = TWO")); From a97cb1530df257e0bf9bd4b0380f388302cc95f4 Mon Sep 17 00:00:00 2001 From: Michael Lamb Date: Fri, 8 Jan 2016 14:23:09 +1100 Subject: [PATCH 093/131] Fix user_type example in cheatsheet.md Fixed example code as chaiscript::user_type is a function. --- cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cheatsheet.md b/cheatsheet.md index 5e78553..eca67f0 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -77,7 +77,7 @@ chai.add(chaiscript::constructor(), "MyType"); It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc. ``` -chai.add(chaiscript::user_type, "MyClass"); +chai.add(chaiscript::user_type(), "MyClass"); ``` ## Adding Type Conversions From 561b47e4630c25552a2be42869dfb54c9f34df61 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 16 Jan 2016 09:27:16 -0700 Subject: [PATCH 094/131] More explicit int/bool conversions --- include/chaiscript/dispatchkit/type_info.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 5be3a2e..eadce9a 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -83,12 +83,12 @@ namespace chaiscript && (*m_bare_type_info) == ti; } - CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_const_flag); } - CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_reference_flag); } - CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_void_flag); } - CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_arithmetic_flag); } - CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_undef_flag); } - CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_pointer_flag); } + CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return static_cast(m_flags & (1 << is_const_flag)); } + CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return static_cast(m_flags & (1 << is_reference_flag)); } + CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return static_cast(m_flags & (1 << is_void_flag)); } + CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return static_cast(m_flags & (1 << is_arithmetic_flag)); } + CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return static_cast(m_flags & (1 << is_undef_flag)); } + CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return static_cast(m_flags & (1 << is_pointer_flag)); } std::string name() const { From 43def57852ece0a09a1f88721a63e0e6c2a8d6c9 Mon Sep 17 00:00:00 2001 From: ktm Date: Sun, 17 Jan 2016 00:01:51 -0500 Subject: [PATCH 095/131] add set_global, update unit test --- .../chaiscript/dispatchkit/dispatchkit.hpp | 37 +++++++++++++------ .../chaiscript/language/chaiscript_engine.hpp | 14 +++++-- unittests/global_in_script.chai | 14 +++++++ 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index aa09486..b962df9 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -535,9 +535,9 @@ namespace chaiscript chaiscript::detail::threading::unique_lock l(m_mutex); - const auto itr = m_state.m_global_objects.find(name); - if (itr == m_state.m_global_objects.end()) - { + const auto itr = m_state.m_global_objects.find(name); + if (itr == m_state.m_global_objects.end()) + { m_state.m_global_objects.insert(std::make_pair(name, obj)); return obj; } else { @@ -549,18 +549,33 @@ namespace chaiscript /// Adds a new global (non-const) shared object, between all the threads void add_global(const Boxed_Value &obj, const std::string &name) { - validate_object_name(name); + validate_object_name(name); - chaiscript::detail::threading::unique_lock l(m_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); - if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) - { - throw chaiscript::exception::name_conflict_error(name); - } else { - m_state.m_global_objects.insert(std::make_pair(name, obj)); - } + if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) + { + throw chaiscript::exception::name_conflict_error(name); + } else { + m_state.m_global_objects.insert(std::make_pair(name, obj)); + } } + /// Adds a new global (non-const) shared object, between all the threads + void set_global(const Boxed_Value &obj, const std::string &name) + { + validate_object_name(name); + + chaiscript::detail::threading::unique_lock l(m_mutex); + + const auto itr = m_state.m_global_objects.find(name); + if (itr != m_state.m_global_objects.end()) + { + itr->second.assign(obj); + } else { + m_state.m_global_objects.insert(std::make_pair(name, obj)); + } + } /// Adds a new scope to the stack void new_scope() diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 4764c67..09039fc 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -401,7 +401,7 @@ namespace chaiscript m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global"); - + m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global"); } @@ -622,11 +622,17 @@ namespace chaiscript /// ChaiScript is thread-safe but provides no threading locking mechanism to the script ChaiScript &add_global(const Boxed_Value &t_bv, const std::string &t_name) { - m_engine.add_global(t_bv, t_name); - return *this; + m_engine.add_global(t_bv, t_name); + return *this; } - /// \brief Represents the current state of the ChaiScript system. State and be saved and restored + ChaiScript &set_global(const Boxed_Value &t_bv, const std::string &t_name) + { + m_engine.set_global(t_bv, t_name); + return *this; + } + + /// \brief Represents the current state of the ChaiScript system. State and be saved and restored /// \warning State object does not contain the user defined type conversions of the engine. They /// are left out due to performance considerations involved in tracking the state /// \sa ChaiScript::get_state diff --git a/unittests/global_in_script.chai b/unittests/global_in_script.chai index 951a910..ad0f7e6 100644 --- a/unittests/global_in_script.chai +++ b/unittests/global_in_script.chai @@ -8,3 +8,17 @@ def myFun() } myFun(); + + +def myFun2() +{ + assert_equal(j, 7) +} + +set_global(7, "j") + +myFun2(); + +set_global(5, "j") + +myFun(); \ No newline at end of file From acc4345b65cbe1a92772dc59957a8f66a2e7c262 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 18 Jan 2016 10:36:21 -0700 Subject: [PATCH 096/131] Add a custom check-for-tabs test to CI --- .decent_ci-Linux.yaml | 4 ++++ contrib/check_for_tabs.rb | 11 +++++++++++ 2 files changed, 15 insertions(+) create mode 100755 contrib/check_for_tabs.rb diff --git a/.decent_ci-Linux.yaml b/.decent_ci-Linux.yaml index 246241a..0b4b9d8 100644 --- a/.decent_ci-Linux.yaml +++ b/.decent_ci-Linux.yaml @@ -27,4 +27,8 @@ compilers: cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON - name: cppcheck compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*" --suppress="*:unittests/catch.hpp" --force + - name: custom_check + commands: + - ./contrib/check_for_tabs.rb + diff --git a/contrib/check_for_tabs.rb b/contrib/check_for_tabs.rb new file mode 100755 index 0000000..bee7d0d --- /dev/null +++ b/contrib/check_for_tabs.rb @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby + +require 'json' + +`grep -rPIHn '\t' src/* include/* samples/*`.lines { |line| + if /(?.+(hpp|cpp|chai)):(?[0-9]+):(?.+)/ =~ line + puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "tab_checker", :message => "Source Code Line Contains Tabs", :messagetype => "warning"})) + end +} + + From 3587c3e16511f4bc72ea607acc861d946dd56735 Mon Sep 17 00:00:00 2001 From: ktm Date: Mon, 18 Jan 2016 13:24:59 -0500 Subject: [PATCH 097/131] fixed comment on set_global --- include/chaiscript/dispatchkit/dispatchkit.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index b962df9..3a1000c 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -561,7 +561,7 @@ namespace chaiscript } } - /// Adds a new global (non-const) shared object, between all the threads + /// Updates an existing global shared object or adds a new global shared object if not found void set_global(const Boxed_Value &obj, const std::string &name) { validate_object_name(name); From 4aa370fbfd07e605be98f6a8404d18e7a483403a Mon Sep 17 00:00:00 2001 From: ktm Date: Mon, 18 Jan 2016 13:33:38 -0500 Subject: [PATCH 098/131] restore newline to bottom of file --- unittests/global_in_script.chai | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/global_in_script.chai b/unittests/global_in_script.chai index ad0f7e6..3d94c7a 100644 --- a/unittests/global_in_script.chai +++ b/unittests/global_in_script.chai @@ -21,4 +21,4 @@ myFun2(); set_global(5, "j") -myFun(); \ No newline at end of file +myFun(); From 12cbbd20976745fbdf276515ccf17159d7d779fd Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 19 Jan 2016 10:00:26 -0700 Subject: [PATCH 099/131] Add test for assignment of map() return vector --- unittests/map.chai | 50 ++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/unittests/map.chai b/unittests/map.chai index b2901ce..eb7a133 100644 --- a/unittests/map.chai +++ b/unittests/map.chai @@ -1,29 +1,41 @@ -assert_equal([true, false, true], map([1,2,3], odd)) +// Map function + +{ + assert_equal([true, false, true], map([1,2,3], odd)) + + var v = [1, 2, 3]; + var y = map(v, fun(s) { s*2; }); + y[0] = 1; + assert_equal(1, y[0]); +} +// Map objects -var m = ["a":1, "b":2]; +{ + var m = ["a":1, "b":2]; -assert_equal(1, m.count("a")) -assert_equal(0, m.count("c")) -assert_equal(1, m.erase("a")) -assert_equal(1, m.size()) -assert_equal(0, m.erase("a")) + assert_equal(1, m.count("a")) + assert_equal(0, m.count("c")) + assert_equal(1, m.erase("a")) + assert_equal(1, m.size()) + assert_equal(0, m.erase("a")) -assert_equal(1, m.size()); + assert_equal(1, m.size()); -var m2 = ["c":3, "b":4] -m.insert(m2); + var m2 = ["c":3, "b":4] + m.insert(m2); -assert_equal(3, m["c"]) -// The inserted values do not overwrite the existing ones -assert_equal(2, m["b"]) -assert_equal(2, m.size()) + assert_equal(3, m["c"]) + // The inserted values do not overwrite the existing ones + assert_equal(2, m["b"]) + assert_equal(2, m.size()) -var v = "bob"; + var v = "bob"; -m.insert_ref(Map_Pair("d", v)) + m.insert_ref(Map_Pair("d", v)) -assert_equal("bob", m["d"]) -v = "bob2" -assert_equal("bob2", m["d"]) + assert_equal("bob", m["d"]) + v = "bob2" + assert_equal("bob2", m["d"]) +} From fcca453223c6d22f7543253d01ba3b20be8ef662 Mon Sep 17 00:00:00 2001 From: Viktor Rennert Date: Tue, 26 Jan 2016 00:06:57 +0100 Subject: [PATCH 100/131] Added initializer_list conversion as possible function call argument or return type. --- .../dispatchkit/type_conversions.hpp | 61 ++++++++++++++++++- .../chaiscript/language/chaiscript_eval.hpp | 1 + unittests/compiled_tests.cpp | 42 +++++++++++++ 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 602d4d9..fe181d0 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -310,7 +310,48 @@ namespace chaiscript private: Callable m_func; }; - +#ifndef CHAISCRIPT_MSVC_12 + //http://stackoverflow.com/questions/18895583/convert-a-vectort-to-initializer-listt + constexpr size_t DEFAULT_MAX_LENGTH = 128; + + template struct backingValue { static V value; }; + template V backingValue::value; + + template struct backingList { static std::initializer_list list; }; + template + std::initializer_list backingList::list = { (Vcount)backingValue::value... }; + + template + static typename std::enable_if< sizeof...(Vcount) >= maxLength, + std::initializer_list >::type generate_n(It begin, It end, It current) + { + throw std::length_error("More than maxLength elements in range."); + } + + template + static typename std::enable_if< sizeof...(Vcount) < maxLength, + std::initializer_list >::type generate_n(It begin, It end, It current) + { + if (current != end) + { + return generate_n(begin, end, ++current); + } + + current = begin; + for (auto it = backingList::list.begin(); + it != backingList::list.end(); + ++current, ++it) + *const_cast(&*it) = *current; + + return backingList::list; + } + + template + std::initializer_list range_to_initializer_list(It begin, It end) + { + return detail::generate_n(begin, end, begin); + } +#endif } class Type_Conversions @@ -593,6 +634,24 @@ namespace chaiscript return chaiscript::make_shared>(user_type>(), user_type(), func); } +#ifndef CHAISCRIPT_MSVC_12 + template + Type_Conversion initializer_list_conversion() { + auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { + const std::vector &from_vec = detail::Cast_Helper &>::cast(t_bv, nullptr); + + std::vector vec; + vec.reserve(from_vec.size()); + for (const auto &bv : from_vec) { + vec.push_back(detail::Cast_Helper::cast(bv, nullptr)); + } + + return Boxed_Value(detail::range_to_initializer_list(vec.begin(), vec.end())); + }; + auto ret = chaiscript::make_shared>(user_type>(), user_type(), func); + return ret; + } +#endif } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index aa01de9..c3391b5 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -1005,6 +1005,7 @@ namespace chaiscript try { std::vector vec; if (!children.empty()) { + vec.reserve(children[0]->children.size()); for (const auto &child : children[0]->children) { auto obj = child->eval(t_ss); if (!obj.is_return_value()) { diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 9a9a4a5..2da054a 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -913,3 +913,45 @@ TEST_CASE("Return of converted type from script") chai.add(chaiscript::user_type(), "Returned_Converted_Config"); } +#ifndef CHAISCRIPT_MSVC_12 +TEST_CASE("Return initializer_list") +{ + chaiscript::ChaiScript chai; + + chai.add(chaiscript::initializer_list_conversion>()); + + auto initlist = chai.eval>(R"( + return [11, 22, 33, 44]; + )"); + + CHECK(initlist.size() == 4); + CHECK(typeid(decltype(initlist)) == typeid(std::initializer_list)); +} + +bool initializer_list_of_enums_interface(std::initializer_list initlist) { + return initlist.size() == 3 && *initlist.begin() == THREE; +} + +TEST_CASE("Call from script with initializer_list argument") +{ + chaiscript::ChaiScript chai; + + chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module()); + chaiscript::utility::add_class(*m, + "Utility_Test_Numbers", + { { ONE, "ONE" }, + { TWO, "TWO" }, + { THREE, "THREE" } + } + ); + chai.add(m); + + chai.add(chaiscript::initializer_list_conversion>()); + chai.add(chaiscript::fun(&initializer_list_of_enums_interface), "initializer_list_of_enums_interface"); + + auto interface_result = chai.eval("return initializer_list_of_enums_interface([THREE, TWO, ONE]);"); + + CHECK(interface_result == true); +} +#endif + From f82f6c2068b2ce9be2ae00a3e1474a869016c457 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 25 Jan 2016 16:41:11 -0700 Subject: [PATCH 101/131] Some fixes found by resharper c++ --- include/chaiscript/dispatchkit/dispatchkit.hpp | 14 +++++++------- .../dispatchkit/exception_specification.hpp | 2 +- include/chaiscript/language/chaiscript_engine.hpp | 4 ++-- include/chaiscript/language/chaiscript_parser.hpp | 2 +- src/main.cpp | 7 +++---- unittests/compiled_tests.cpp | 2 +- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index aa09486..9274b65 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -596,13 +596,13 @@ namespace chaiscript /// Pushes a new stack on to the list of stacks - void new_stack(Stack_Holder &t_holder) + static void new_stack(Stack_Holder &t_holder) { // add a new Stack with 1 element t_holder.stacks.emplace_back(1); } - void pop_stack(Stack_Holder &t_holder) + static void pop_stack(Stack_Holder &t_holder) { t_holder.stacks.pop_back(); } @@ -1082,7 +1082,7 @@ namespace chaiscript /// Returns true if a call can be made that consists of the first parameter /// (the function) with the remaining parameters as its arguments. - Boxed_Value call_exists(const std::vector ¶ms) + Boxed_Value call_exists(const std::vector ¶ms) const { if (params.empty()) { @@ -1160,12 +1160,12 @@ namespace chaiscript m_state = t_state; } - void save_function_params(Stack_Holder &t_s, std::initializer_list t_params) + 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)); } - void save_function_params(Stack_Holder &t_s, std::vector &&t_params) + static void save_function_params(Stack_Holder &t_s, std::vector &&t_params) { for (auto &¶m : t_params) { @@ -1173,7 +1173,7 @@ namespace chaiscript } } - void save_function_params(Stack_Holder &t_s, const std::vector &t_params) + static void save_function_params(Stack_Holder &t_s, const std::vector &t_params) { t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end()); } @@ -1240,7 +1240,7 @@ namespace chaiscript return m_stack_holder->stacks.back(); } - StackData &get_stack_data(Stack_Holder &t_holder) + static StackData &get_stack_data(Stack_Holder &t_holder) { return t_holder.stacks.back(); } diff --git a/include/chaiscript/dispatchkit/exception_specification.hpp b/include/chaiscript/dispatchkit/exception_specification.hpp index 54f19c4..2a9f0b6 100644 --- a/include/chaiscript/dispatchkit/exception_specification.hpp +++ b/include/chaiscript/dispatchkit/exception_specification.hpp @@ -32,7 +32,7 @@ namespace chaiscript protected: template - void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) + static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) { try { T t = t_engine.boxed_cast(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {} } diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 4764c67..776569b 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -177,11 +177,11 @@ namespace chaiscript FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, + nullptr, t_err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&lpMsgBuf), - 0, NULL ) != 0 && lpMsgBuf) + 0, nullptr ) != 0 && lpMsgBuf) { retval = lpMsgBuf; LocalFree(lpMsgBuf); diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 6548521..dfbbde2 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -278,7 +278,7 @@ namespace chaiscript bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast(c)]; } /// Prints the parsed ast_nodes as a tree - void debug_print(AST_NodePtr t, std::string prepend = "") { + void debug_print(AST_NodePtr t, std::string prepend = "") const { std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start().line << ", " << t->start().column << '\n'; for (unsigned int j = 0; j < t->children.size(); ++j) { debug_print(t->children[j], prepend + " "); diff --git a/src/main.cpp b/src/main.cpp index 372adf7..6fe1bc2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -66,7 +66,7 @@ std::vector default_search_paths() #ifdef CHAISCRIPT_WINDOWS // force no unicode CHAR path[4096]; - int size = GetModuleFileNameA(0, path, sizeof(path)-1); + int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1); std::string exepath(path, size); @@ -344,17 +344,16 @@ int main(int argc, char *argv[]) mode = eFile; } - chaiscript::Boxed_Value val ; try { switch ( mode ) { case eInteractive: interactive(chai); break; case eCommand: - val = chai.eval(arg); + chai.eval(arg); break; case eFile: - val = chai.eval_file(arg); + chai.eval_file(arg); } } catch (const chaiscript::exception::eval_error &ee) { diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 9a9a4a5..d4d429e 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -397,7 +397,7 @@ class Short_Comparison_Test { public: Short_Comparison_Test() : value_(5) {} - short get_value() { return value_; } + short get_value() const { return value_; } short value_; }; From af1eba1b0e9b4e672199f68f5c33f695f3c1905f Mon Sep 17 00:00:00 2001 From: Viktor Rennert Date: Tue, 26 Jan 2016 18:36:45 +0100 Subject: [PATCH 102/131] Added type fix for gcc/clang and tiny formating fixes. --- include/chaiscript/dispatchkit/type_conversions.hpp | 10 ++++++---- unittests/compiled_tests.cpp | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index fe181d0..962d7f3 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -623,7 +623,7 @@ namespace chaiscript const std::vector &from_vec = detail::Cast_Helper &>::cast(t_bv, nullptr); To vec; - + vec.reserve(from_vec.size()); for (const Boxed_Value &bv : from_vec) { vec.push_back(detail::Cast_Helper::cast(bv, nullptr)); } @@ -636,13 +636,15 @@ namespace chaiscript #ifndef CHAISCRIPT_MSVC_12 template - Type_Conversion initializer_list_conversion() { + Type_Conversion initializer_list_conversion() + { auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { const std::vector &from_vec = detail::Cast_Helper &>::cast(t_bv, nullptr); - std::vector vec; + std::vector vec; vec.reserve(from_vec.size()); - for (const auto &bv : from_vec) { + for (const auto &bv : from_vec) + { vec.push_back(detail::Cast_Helper::cast(bv, nullptr)); } diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 2da054a..7c4d769 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -928,7 +928,8 @@ TEST_CASE("Return initializer_list") CHECK(typeid(decltype(initlist)) == typeid(std::initializer_list)); } -bool initializer_list_of_enums_interface(std::initializer_list initlist) { +bool initializer_list_of_enums_interface(std::initializer_list initlist) +{ return initlist.size() == 3 && *initlist.begin() == THREE; } From 651eed8d7a9698338292e6add74ad7d3cfc1e0e1 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 29 Jan 2016 13:57:14 -0700 Subject: [PATCH 103/131] Add no-threads build for testing Closes #60 --- .decent_ci-Linux.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.decent_ci-Linux.yaml b/.decent_ci-Linux.yaml index e8ecf73..1c15246 100644 --- a/.decent_ci-Linux.yaml +++ b/.decent_ci-Linux.yaml @@ -19,6 +19,11 @@ compilers: version: "3.6" skip_packaging: true cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON + - name: "gcc" + version: "4.8" + build_tag: "NoThreads" + cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON -DMULTITHREAD_SUPPORT_ENABLED:BOOL=OFF + collect_performance_results: true - name: "gcc" version: "4.8" cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON From dfd04c82919dff816a3005f48f97bb8e174042ff Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 29 Jan 2016 15:16:35 -0700 Subject: [PATCH 104/131] Clean up formatting from last merge Closes #238 --- .../chaiscript/dispatchkit/dispatchkit.hpp | 40 +++++++++---------- .../chaiscript/language/chaiscript_engine.hpp | 10 ++--- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 8edb38c..0aa7db0 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -535,9 +535,9 @@ namespace chaiscript chaiscript::detail::threading::unique_lock l(m_mutex); - const auto itr = m_state.m_global_objects.find(name); - if (itr == m_state.m_global_objects.end()) - { + const auto itr = m_state.m_global_objects.find(name); + if (itr == m_state.m_global_objects.end()) + { m_state.m_global_objects.insert(std::make_pair(name, obj)); return obj; } else { @@ -549,32 +549,32 @@ namespace chaiscript /// Adds a new global (non-const) shared object, between all the threads void add_global(const Boxed_Value &obj, const std::string &name) { - validate_object_name(name); + validate_object_name(name); - chaiscript::detail::threading::unique_lock l(m_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); - if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) - { - throw chaiscript::exception::name_conflict_error(name); - } else { - m_state.m_global_objects.insert(std::make_pair(name, obj)); - } + if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) + { + throw chaiscript::exception::name_conflict_error(name); + } else { + m_state.m_global_objects.insert(std::make_pair(name, obj)); + } } /// Updates an existing global shared object or adds a new global shared object if not found void set_global(const Boxed_Value &obj, const std::string &name) { - validate_object_name(name); + validate_object_name(name); - chaiscript::detail::threading::unique_lock l(m_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); - const auto itr = m_state.m_global_objects.find(name); - if (itr != m_state.m_global_objects.end()) - { - itr->second.assign(obj); - } else { - m_state.m_global_objects.insert(std::make_pair(name, obj)); - } + const auto itr = m_state.m_global_objects.find(name); + if (itr != m_state.m_global_objects.end()) + { + itr->second.assign(obj); + } else { + m_state.m_global_objects.insert(std::make_pair(name, obj)); + } } /// Adds a new scope to the stack diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 16199c3..3e58116 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -622,17 +622,17 @@ namespace chaiscript /// ChaiScript is thread-safe but provides no threading locking mechanism to the script ChaiScript &add_global(const Boxed_Value &t_bv, const std::string &t_name) { - m_engine.add_global(t_bv, t_name); - return *this; + m_engine.add_global(t_bv, t_name); + return *this; } ChaiScript &set_global(const Boxed_Value &t_bv, const std::string &t_name) { - m_engine.set_global(t_bv, t_name); - return *this; + m_engine.set_global(t_bv, t_name); + return *this; } - /// \brief Represents the current state of the ChaiScript system. State and be saved and restored + /// \brief Represents the current state of the ChaiScript system. State and be saved and restored /// \warning State object does not contain the user defined type conversions of the engine. They /// are left out due to performance considerations involved in tracking the state /// \sa ChaiScript::get_state From 140a90f72adf8968033f9b7026cbd9bc12320269 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 29 Jan 2016 15:35:40 -0700 Subject: [PATCH 105/131] Fix g++4.6 build issues --- .../chaiscript/dispatchkit/type_conversions.hpp | 2 +- include/chaiscript/utility/utility.hpp | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 962d7f3..1fcabe9 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -319,7 +319,7 @@ namespace chaiscript template struct backingList { static std::initializer_list list; }; template - std::initializer_list backingList::list = { (Vcount)backingValue::value... }; + std::initializer_list backingList::list = { static_cast(backingValue::value)... }; template static typename std::enable_if< sizeof...(Vcount) >= maxLength, diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index 381afda..fbd8c66 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -69,21 +69,31 @@ namespace chaiscript typename std::enable_if::value, void>::type add_class(ModuleType &t_module, const std::string &t_class_name, - const std::vector::type, std::string>> &t_constants) +#ifdef CHAISCRIPT_GCC_4_6 + const std::vector> &t_constants +#else + const std::vector::type, std::string>> &t_constants +#endif + ) { 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; t_module.add([](){ // add some comparison and assignment operators - using namespace chaiscript::bootstrap::operators; return assign(not_equal(equal())); }()); +#ifdef CHAISCRIPT_GCC_4_6 + t_module.add(chaiscript::fun([](const Enum &e, const int &i) { return e == i; }), "=="); + t_module.add(chaiscript::fun([](const int &i, const Enum &e) { return i == e; }), "=="); +#else t_module.add(chaiscript::fun([](const Enum &e, const typename std::underlying_type::type &i) { return e == i; }), "=="); t_module.add(chaiscript::fun([](const typename std::underlying_type::type &i, const Enum &e) { return i == e; }), "=="); +#endif for (const auto &constant : t_constants) { From b33f0a08bce03dd8e8025475b0d3fa92d7b10348 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 29 Jan 2016 16:04:06 -0700 Subject: [PATCH 106/131] Remove initializer_list conversion due to the issues mentioned here: http://stackoverflow.com/questions/18895583/convert-a-vectort-to-initializer-listt --- .../dispatchkit/type_conversions.hpp | 42 ------------------- unittests/compiled_tests.cpp | 42 ------------------- 2 files changed, 84 deletions(-) diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 1fcabe9..aaa089e 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -310,48 +310,6 @@ namespace chaiscript private: Callable m_func; }; -#ifndef CHAISCRIPT_MSVC_12 - //http://stackoverflow.com/questions/18895583/convert-a-vectort-to-initializer-listt - constexpr size_t DEFAULT_MAX_LENGTH = 128; - - template struct backingValue { static V value; }; - template V backingValue::value; - - template struct backingList { static std::initializer_list list; }; - template - std::initializer_list backingList::list = { static_cast(backingValue::value)... }; - - template - static typename std::enable_if< sizeof...(Vcount) >= maxLength, - std::initializer_list >::type generate_n(It begin, It end, It current) - { - throw std::length_error("More than maxLength elements in range."); - } - - template - static typename std::enable_if< sizeof...(Vcount) < maxLength, - std::initializer_list >::type generate_n(It begin, It end, It current) - { - if (current != end) - { - return generate_n(begin, end, ++current); - } - - current = begin; - for (auto it = backingList::list.begin(); - it != backingList::list.end(); - ++current, ++it) - *const_cast(&*it) = *current; - - return backingList::list; - } - - template - std::initializer_list range_to_initializer_list(It begin, It end) - { - return detail::generate_n(begin, end, begin); - } -#endif } class Type_Conversions diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 4d65bee..28e7d4c 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -913,46 +913,4 @@ TEST_CASE("Return of converted type from script") chai.add(chaiscript::user_type(), "Returned_Converted_Config"); } -#ifndef CHAISCRIPT_MSVC_12 -TEST_CASE("Return initializer_list") -{ - chaiscript::ChaiScript chai; - - chai.add(chaiscript::initializer_list_conversion>()); - - auto initlist = chai.eval>(R"( - return [11, 22, 33, 44]; - )"); - - CHECK(initlist.size() == 4); - CHECK(typeid(decltype(initlist)) == typeid(std::initializer_list)); -} - -bool initializer_list_of_enums_interface(std::initializer_list initlist) -{ - return initlist.size() == 3 && *initlist.begin() == THREE; -} - -TEST_CASE("Call from script with initializer_list argument") -{ - chaiscript::ChaiScript chai; - - chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module()); - chaiscript::utility::add_class(*m, - "Utility_Test_Numbers", - { { ONE, "ONE" }, - { TWO, "TWO" }, - { THREE, "THREE" } - } - ); - chai.add(m); - - chai.add(chaiscript::initializer_list_conversion>()); - chai.add(chaiscript::fun(&initializer_list_of_enums_interface), "initializer_list_of_enums_interface"); - - auto interface_result = chai.eval("return initializer_list_of_enums_interface([THREE, TWO, ONE]);"); - - CHECK(interface_result == true); -} -#endif From 7222390c9664c7db752938e187835319042b6e29 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 29 Jan 2016 16:12:10 -0700 Subject: [PATCH 107/131] Fix build --- .../dispatchkit/type_conversions.hpp | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index aaa089e..b5bce8d 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -592,26 +592,6 @@ namespace chaiscript return chaiscript::make_shared>(user_type>(), user_type(), func); } -#ifndef CHAISCRIPT_MSVC_12 - template - Type_Conversion initializer_list_conversion() - { - auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { - const std::vector &from_vec = detail::Cast_Helper &>::cast(t_bv, nullptr); - - std::vector vec; - vec.reserve(from_vec.size()); - for (const auto &bv : from_vec) - { - vec.push_back(detail::Cast_Helper::cast(bv, nullptr)); - } - - return Boxed_Value(detail::range_to_initializer_list(vec.begin(), vec.end())); - }; - auto ret = chaiscript::make_shared>(user_type>(), user_type(), func); - return ret; - } -#endif } From 5b1b1dbcb42e1be7ec529bd02a8d5672cf3c3b8d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 29 Jan 2016 17:20:19 -0700 Subject: [PATCH 108/131] Added appveyor.yml --- appveyor.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..c402efe --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,16 @@ +version: 5.7.2.{build} +os: Visual Studio 2015 +environment: + matrix: + - {} +build_script: +- cmd: >- + mkdir build + + cd build + + cmake c:\Projects\chaiscript -G "Visual Studio 14" + + cmake --build . --config Debug +test_script: +- cmd: ctest -C Debug From b2ae317877b419a23fc9eb1c429bbcf6392e2bca Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 29 Jan 2016 19:13:10 -0700 Subject: [PATCH 109/131] Seperate out async moves into a separate test --- unittests/move_async.chai | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 unittests/move_async.chai diff --git a/unittests/move_async.chai b/unittests/move_async.chai new file mode 100644 index 0000000..7975a7c --- /dev/null +++ b/unittests/move_async.chai @@ -0,0 +1,17 @@ +load_module("stl_extra") + +auto x = List() +// push_back newly constructed return value that's non-copyable +x.push_front(async(fun(){})) + +// push_front newly constructed return value that's non-copyable +x.push_front(async(fun(){})) + + + +// push_back newly constructed return value that's non-copyable + +var v = [] +v.push_back(async(fun(){})) + + From 485482b2beae992ad94dd910b29050f9ce08b646 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 29 Jan 2016 19:42:50 -0700 Subject: [PATCH 110/131] Fix tabs in source code --- include/chaiscript/language/chaiscript_parser.hpp | 2 +- samples/fun_call_performance.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index dfbbde2..84a9cef 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -929,7 +929,7 @@ namespace chaiscript { } - Char_Parser &operator=(const Char_Parser &) = delete; + Char_Parser &operator=(const Char_Parser &) = delete; ~Char_Parser(){ if (is_octal) { diff --git a/samples/fun_call_performance.cpp b/samples/fun_call_performance.cpp index a416cc2..7e340f3 100644 --- a/samples/fun_call_performance.cpp +++ b/samples/fun_call_performance.cpp @@ -316,7 +316,7 @@ int main(int argc, char *argv[]) ////for (int i = 0; i < 1000; i++) ////{ - //// chai.eval("puts(helloWorld(\"Bob12345\"));"); + //// chai.eval("puts(helloWorld(\"Bob12345\"));"); ////} //chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai"); From 7f4ef8d8fd43fd786ff7a43401b263debedb6bec Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 29 Jan 2016 20:00:20 -0700 Subject: [PATCH 111/131] Fix cppcheck warnings --- .decent_ci-Linux.yaml | 2 +- samples/test_num_exceptions.cpp | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.decent_ci-Linux.yaml b/.decent_ci-Linux.yaml index 1c15246..dfb5056 100644 --- a/.decent_ci-Linux.yaml +++ b/.decent_ci-Linux.yaml @@ -34,7 +34,7 @@ compilers: cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON collect_performance_results: true - name: cppcheck - compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*" --suppress="*:unittests/catch.hpp" --force + compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:unittests/catch.hpp" --force --suppress="unusedFunction:*" - name: custom_check commands: - ./contrib/check_for_tabs.rb diff --git a/samples/test_num_exceptions.cpp b/samples/test_num_exceptions.cpp index 36bbb75..3a35fb7 100644 --- a/samples/test_num_exceptions.cpp +++ b/samples/test_num_exceptions.cpp @@ -7,20 +7,22 @@ int main( int /*argc*/ , char * /*argv*/[] ) { chaiscript::ChaiScript ch( chaiscript::Std_Lib::library( ) ); - static const char script[ ] = - R""( + + try + { + static const char script[ ] = + R""( class Rectangle { def Rectangle() { } } - var rect = Rectangle( ); + var rect = Rectangle( ); )""; - try - { + ch.eval( script ); } catch ( const std::exception &e ) From bde2a453849d4cc89b537d8314b2effcfee59f4f Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 29 Jan 2016 20:41:12 -0700 Subject: [PATCH 112/131] Add map conversions closes #57 --- cheatsheet.md | 7 ++++++ .../dispatchkit/type_conversions.hpp | 18 +++++++++++++ unittests/compiled_tests.cpp | 25 +++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/cheatsheet.md b/cheatsheet.md index eca67f0..25b8469 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -90,6 +90,13 @@ A helper function exists for strongly typed and ChaiScript `Vector` function con chai.add(chaiscript::vector_conversion>()); ``` +A helper function also exists for strongly typed and ChaiScript `Map` function conversion definition: + +``` +chai.add(chaiscript::map_conversion>()); +``` + + This allows you to pass a ChaiScript function to a function requiring `std::vector` ## Adding Objects diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index b5bce8d..2a9a398 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -592,6 +592,24 @@ namespace chaiscript return chaiscript::make_shared>(user_type>(), user_type(), func); } + template + Type_Conversion map_conversion() + { + auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { + const std::map &from_map = detail::Cast_Helper &>::cast(t_bv, nullptr); + + To map; + for (const std::pair &p : from_map) { + map.insert(std::make_pair(p.first, detail::Cast_Helper::cast(p.second, nullptr))); + } + + return Boxed_Value(std::move(map)); + }; + + return chaiscript::make_shared>(user_type>(), user_type(), func); + } + + } diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 28e7d4c..b27db07 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -872,6 +872,7 @@ struct Returned_Converted_Config }; + TEST_CASE("Return of converted type from script") { chaiscript::ChaiScript chai; @@ -914,3 +915,27 @@ TEST_CASE("Return of converted type from script") } +int get_value_a(const std::map &t_m) +{ + return t_m.at("a"); +} + + +TEST_CASE("Map conversions") +{ + chaiscript::ChaiScript chai; + chai.add(chaiscript::map_conversion>()); + chai.add(chaiscript::fun(&get_value_a), "get_value_a"); + + const auto c = chai.eval(R"( + var m = ["a": 42]; + get_value_a(m); + )"); + + CHECK(c == 42); + +} + + + + From 7688c14d43456af5a12f618e7cd1f3531c015413 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 29 Jan 2016 21:34:04 -0700 Subject: [PATCH 113/131] Parse strings in ${} closes #131 --- include/chaiscript/language/chaiscript_parser.hpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 84a9cef..cdc23f6 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -881,9 +881,19 @@ namespace chaiscript char prev_char = *m_position; ++m_position; - while (m_position.has_more() && ((*m_position != '\"') || ((*m_position == '\"') && (prev_char == '\\')))) { + int in_interpolation = 0; + bool in_quote = false; + + while (m_position.has_more() && ((*m_position != '\"') || ((*m_position == '\"') && (in_interpolation > 0)) || ((*m_position == '\"') && (prev_char == '\\')))) { + if (!Eol_()) { - if (prev_char == '\\') { + if (prev_char == '$' && *m_position == '{') { + ++in_interpolation; + } else if (*m_position == '"') { + in_quote = !in_quote; + } else if (*m_position == '}' && !in_quote) { + --in_interpolation; + } else if (prev_char == '\\') { prev_char = 0; } else { prev_char = *m_position; From 872f16e45abafb4e763eec4ece2e2e5f6ad47041 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 30 Jan 2016 06:56:01 -0700 Subject: [PATCH 114/131] Add some tests that were laying around --- unittests/array_access.chai | 3 +++ unittests/instring_eval_with_string.chai | 1 + unittests/return_value_assignment.chai | 16 ++++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 unittests/array_access.chai create mode 100644 unittests/instring_eval_with_string.chai create mode 100644 unittests/return_value_assignment.chai diff --git a/unittests/array_access.chai b/unittests/array_access.chai new file mode 100644 index 0000000..7600492 --- /dev/null +++ b/unittests/array_access.chai @@ -0,0 +1,3 @@ +var v = [[[15]]] + +assert_true(v[0][0][0] == 15) diff --git a/unittests/instring_eval_with_string.chai b/unittests/instring_eval_with_string.chai new file mode 100644 index 0000000..9cb1091 --- /dev/null +++ b/unittests/instring_eval_with_string.chai @@ -0,0 +1 @@ +assert_equal("a string", "${"a string"}") diff --git a/unittests/return_value_assignment.chai b/unittests/return_value_assignment.chai new file mode 100644 index 0000000..e6906e6 --- /dev/null +++ b/unittests/return_value_assignment.chai @@ -0,0 +1,16 @@ + +try { + eval("to_string(5) = \"some string\"") + assert_true(false) +} catch (e) { + print("Caught Error: " + e.what()); +} + + + +try { + eval("var v = [1,2,3]; v.size() = 3") + assert_true(false) +} catch (e) { + print("Caught Error: " + e.what()); +} From 7923c3e0c7a53d77a3becebcf43bf6f3d4053932 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 31 Jan 2016 14:05:44 -0700 Subject: [PATCH 115/131] Add docs on `set_global` --- cheatsheet.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cheatsheet.md b/cheatsheet.md index 25b8469..9b51f2a 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -107,8 +107,9 @@ chai.add(chaiscript::var(std::ref(somevar), "somevar"); // by reference, shared auto shareddouble = std::make_shared(4.3); chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const -chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const -chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const +chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const, throws if object exists +chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throws if object exists +chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object ``` # Using STL ChaiScript recognize many types from STL, but you have to add specific instantiation yourself. From c438a388d71fa8c186e38fe37389b8af59309d71 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 31 Jan 2016 19:05:37 -0700 Subject: [PATCH 116/131] Add workaround for msvc 2015 update 1 with 1 CPU. --- include/chaiscript/chaiscript_stdlib.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/chaiscript/chaiscript_stdlib.hpp b/include/chaiscript/chaiscript_stdlib.hpp index 4b38f2c..84797b7 100644 --- a/include/chaiscript/chaiscript_stdlib.hpp +++ b/include/chaiscript/chaiscript_stdlib.hpp @@ -49,7 +49,13 @@ namespace chaiscript #ifndef CHAISCRIPT_NO_THREADS lib->add(standard_library::future_type>("future")); +#ifdef CHAISCRIPT_MSVC + /// this is to work around an issue that seems to only come up on single CPU hosts on MSVC 2015 Update 1 + /// \todo reevaluate this later + lib->add(chaiscript::fun([](const std::function &t_func){ return std::async(std::thread::hardware_concurrency() <= 1 ? std::launch::deferred : std::launch::async, t_func);}), "async"); +#else lib->add(chaiscript::fun([](const std::function &t_func){ return std::async(std::launch::async, t_func);}), "async"); +#endif #endif lib->add(json_wrap::library()); From 1a06e53c58c18ec853ea3f7bf799582ec4d661ec Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 31 Jan 2016 19:06:44 -0700 Subject: [PATCH 117/131] Add some compiler identification info to build --- include/chaiscript/chaiscript_defines.hpp | 32 +++++++++++++++++ .../chaiscript/language/chaiscript_engine.hpp | 35 +++++++++++++++++-- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index c2ba4ae..87f3eeb 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -8,11 +8,14 @@ #define CHAISCRIPT_DEFINES_HPP_ #ifdef _MSC_VER +#define CHAISCRIPT_COMPILER_VERSION #_MSC_FULL_VER #define CHAISCRIPT_MSVC _MSC_VER #define CHAISCRIPT_HAS_DECLSPEC #if _MSC_VER <= 1800 #define CHAISCRIPT_MSVC_12 #endif +#else +#define CHAISCRIPT_COMPILER_VERSION __VERSION__ #endif #ifndef CHAISCRIPT_MSVC_12 @@ -29,6 +32,25 @@ #define CHAISCRIPT_WINDOWS #endif +#if defined(_WIN32) +#if defined(__llvm__) +#define CHAISCRIPT_COMPILER_NAME "clang(windows)" +#elif defined(__GNUC__) +#define CHAISCRIPT_COMPILER_NAME "gcc(mingw)" +#else +#define CHAISCRIPT_COMPILER_NAME "msvc" +#endif +#else +#if defined(__llvm__) +#define CHAISCRIPT_COMPILER_NAME "clang" +#elif defined(__GNUC__) +#define CHAISCRIPT_COMPILER_NAME "gcc" +#else +#define CHAISCRIPT_COMPILER_NAME "unknown" +#endif +#endif + + #if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP)) /// Currently only g++>=4.8 supports this natively /// \todo Make this support other compilers when possible @@ -64,6 +86,12 @@ #define CHAISCRIPT_CONSTEXPR constexpr #endif +#ifdef _DEBUG +#define CHAISCRIPT_DEBUG true +#else +#define CHAISCRIPT_DEBUG false +#endif + #include namespace chaiscript { @@ -71,6 +99,10 @@ namespace chaiscript { static const int version_minor = 7; static const int version_patch = 2; + static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION; + static const char *compiler_name = CHAISCRIPT_COMPILER_NAME; + static const bool debug_build = CHAISCRIPT_DEBUG; + template inline std::shared_ptr make_shared(Arg && ... arg) { diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 3e58116..fba4f8f 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -398,6 +398,10 @@ namespace chaiscript m_engine.add(fun(&ChaiScript::version_minor), "version_minor"); m_engine.add(fun(&ChaiScript::version_patch), "version_patch"); m_engine.add(fun(&ChaiScript::version), "version"); + m_engine.add(fun(&ChaiScript::compiler_version), "compiler_version"); + m_engine.add(fun(&ChaiScript::compiler_name), "compiler_name"); + m_engine.add(fun(&ChaiScript::compiler_id), "compiler_id"); + m_engine.add(fun(&ChaiScript::debug_build), "debug_build"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global"); @@ -552,11 +556,36 @@ namespace chaiscript static std::string version() { - std::stringstream ss; - ss << version_major() << "." << version_minor() << "." << version_patch(); - return ss.str(); + return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch()); } + static std::string compiler_id() + { + return compiler_name() + '-' + compiler_version(); + } + + static std::string build_id() + { + return compiler_id() + (debug_build()?"-Debug":"-Release"); + } + + static std::string compiler_version() + { + return chaiscript::compiler_version; + } + + static std::string compiler_name() + { + return chaiscript::compiler_name; + } + + static bool debug_build() + { + return chaiscript::debug_build; + } + + + std::string get_type_name(const Type_Info &ti) const { return m_engine.get_type_name(ti); From b104b26f1125f5bbb0041a64960d681139ebe120 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 31 Jan 2016 19:15:32 -0700 Subject: [PATCH 118/131] Also allow lcase global keyword Closes #221 --- cheatsheet.md | 10 ++++++---- .../chaiscript/language/chaiscript_engine.hpp | 1 + .../chaiscript/language/chaiscript_parser.hpp | 2 +- unittests/global_lcase.chai | 18 ++++++++++++++++++ 4 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 unittests/global_lcase.chai diff --git a/cheatsheet.md b/cheatsheet.md index 9b51f2a..ce8e04a 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -229,11 +229,13 @@ var k = 5; // initialized to 5 (integer) var l := k; // reference to k auto &m = k; // reference to k -GLOBAL g = 5; // creates a global variable. If global already exists, it is not re-added -GLOBAL g = 2; // global 'g' now equals 2 +global g = 5; // creates a global variable. If global already exists, it is not re-added +global g = 2; // global 'g' now equals 2 -GLOBAL g2; -if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if GLOBAL decl hit more than once +global g2; +if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if global decl hit more than once + +GLOBAL g3; // all upper case version also accepted ``` ## Built in Types diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index fba4f8f..9824bd2 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -342,6 +342,7 @@ namespace chaiscript m_engine.add_reserved_word("class"); m_engine.add_reserved_word("attr"); m_engine.add_reserved_word("var"); + m_engine.add_reserved_word("global"); m_engine.add_reserved_word("GLOBAL"); m_engine.add_reserved_word("_"); diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index cdc23f6..82d81f6 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -2065,7 +2065,7 @@ namespace chaiscript } build_match(prev_stack_top); - } else if (Keyword("GLOBAL")) { + } else if (Keyword("GLOBAL") || Keyword("global")) { retval = true; if (!(Reference() || Id())) { diff --git a/unittests/global_lcase.chai b/unittests/global_lcase.chai new file mode 100644 index 0000000..7f8959a --- /dev/null +++ b/unittests/global_lcase.chai @@ -0,0 +1,18 @@ +// Test global + +global g = 3; +assert_true(g == 3); + +var v := g; +assert_true(v == 3); + +global g = 2; +assert_true(g == 2); +assert_true(v == 2); + +def f() { + assert_true(g == 2); +} + +f(); + From bff30278e196a5c6cec185dc0271d3ae4a067592 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 31 Jan 2016 19:35:40 -0700 Subject: [PATCH 119/131] Fix string parsing --- include/chaiscript/language/chaiscript_parser.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 82d81f6..2f0d596 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -889,11 +889,13 @@ namespace chaiscript if (!Eol_()) { if (prev_char == '$' && *m_position == '{') { ++in_interpolation; - } else if (*m_position == '"') { + } else if (prev_char != '\\' && *m_position == '"') { in_quote = !in_quote; } else if (*m_position == '}' && !in_quote) { --in_interpolation; - } else if (prev_char == '\\') { + } + + if (prev_char == '\\') { prev_char = 0; } else { prev_char = *m_position; From c562d0d78b55421b5d29fe2af6ca395855825a90 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 31 Jan 2016 21:18:23 -0700 Subject: [PATCH 120/131] Fix MSVC build --- include/chaiscript/chaiscript_defines.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 87f3eeb..1b340cb 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -8,7 +8,8 @@ #define CHAISCRIPT_DEFINES_HPP_ #ifdef _MSC_VER -#define CHAISCRIPT_COMPILER_VERSION #_MSC_FULL_VER +#define CHAISCRIPT_STRINGIZE(x) "" #x +#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE(_MSC_FULL_VER) #define CHAISCRIPT_MSVC _MSC_VER #define CHAISCRIPT_HAS_DECLSPEC #if _MSC_VER <= 1800 From d0630d5eddd475db8b648a2605e4d631cf0ebe33 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 1 Feb 2016 15:24:08 -0700 Subject: [PATCH 121/131] Attempt to fix warning from MSVC --- CMakeLists.txt | 2 +- include/chaiscript/utility/json.hpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 471784c..841615f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,7 +210,7 @@ endif() include_directories(include) -set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp) +set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp include/chaiscript/utility/json.hpp include/chaiscript/utility/json_wrap.hpp) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index c023c2b..56f28e7 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -19,6 +19,7 @@ #include #include #include +#include "../chaiscript_defines.hpp" namespace json { @@ -48,6 +49,21 @@ namespace { } return output; } + + bool isspace(const char c) + { +#ifdef CHAISCRIPT_MSVC + // MSVC warns on these line in some circumstances +#pragma warning(push) +#pragma warning(disable : 6330) +#endif + return ::isspace(c) != 0; +#ifdef CHAISCRIPT_MSVC +#pragma warning(pop) +#endif + + + } } class JSON From 357df5c8ec36a7e74c430a4a775852e349c754b7 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 1 Feb 2016 15:38:32 -0700 Subject: [PATCH 122/131] Remove async test from list_push_back --- unittests/list_push_back.chai | 2 -- 1 file changed, 2 deletions(-) diff --git a/unittests/list_push_back.chai b/unittests/list_push_back.chai index 5a058fc..35b8fa6 100644 --- a/unittests/list_push_back.chai +++ b/unittests/list_push_back.chai @@ -8,7 +8,5 @@ assert_equal(3, x.front()); assert_equal("A", x.back()); -// push_back newly constructed return value that's non-copyable -x.push_back(async(fun(){})) From caf0a8b5d178b307d0fd47be96a5b2f0962fa26b Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 2 Feb 2016 07:25:41 -0700 Subject: [PATCH 123/131] Remove extra version of push_back async vector --- unittests/vector_push_back.chai | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/unittests/vector_push_back.chai b/unittests/vector_push_back.chai index 176e1ce..148e7ff 100644 --- a/unittests/vector_push_back.chai +++ b/unittests/vector_push_back.chai @@ -12,9 +12,6 @@ uint16v.push_back(1u); assert_equal(1, uint16v.front()); -// push_back newly constructed return value that's non-copyable - -var v = [] -v.push_back(async(fun(){})) + From 08ba6462003c086cfb76a5a8fc87c215d66efa16 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 2 Feb 2016 09:18:08 -0700 Subject: [PATCH 124/131] Enable thread local in MSVC 2015 --- include/chaiscript/chaiscript_defines.hpp | 3 +-- include/chaiscript/chaiscript_stdlib.hpp | 6 ------ include/chaiscript/chaiscript_threading.hpp | 5 +++-- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 1b340cb..553ff54 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -51,8 +51,7 @@ #endif #endif - -#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP)) +#if (defined(CHAISCRIPT_MSVC) && !defined(CHAISCRIPT_MSVC_12)) || (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP)) /// Currently only g++>=4.8 supports this natively /// \todo Make this support other compilers when possible #define CHAISCRIPT_HAS_THREAD_LOCAL diff --git a/include/chaiscript/chaiscript_stdlib.hpp b/include/chaiscript/chaiscript_stdlib.hpp index 84797b7..4b38f2c 100644 --- a/include/chaiscript/chaiscript_stdlib.hpp +++ b/include/chaiscript/chaiscript_stdlib.hpp @@ -49,13 +49,7 @@ namespace chaiscript #ifndef CHAISCRIPT_NO_THREADS lib->add(standard_library::future_type>("future")); -#ifdef CHAISCRIPT_MSVC - /// this is to work around an issue that seems to only come up on single CPU hosts on MSVC 2015 Update 1 - /// \todo reevaluate this later - lib->add(chaiscript::fun([](const std::function &t_func){ return std::async(std::thread::hardware_concurrency() <= 1 ? std::launch::deferred : std::launch::async, t_func);}), "async"); -#else lib->add(chaiscript::fun([](const std::function &t_func){ return std::async(std::launch::async, t_func);}), "async"); -#endif #endif lib->add(json_wrap::library()); diff --git a/include/chaiscript/chaiscript_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index 09fc617..0bb3cfd 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -160,13 +160,14 @@ namespace chaiscript { unique_lock lock(m_mutex); - auto itr = m_instances.find(std::this_thread::get_id()); + const auto id = std::this_thread::get_id(); + auto itr = m_instances.find(id); if (itr != m_instances.end()) { return itr->second; } std::shared_ptr new_instance(std::make_shared()); - m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance)); + m_instances.insert(std::make_pair(id, new_instance)); return new_instance; } From e0827634bbe8abbae14a9720257ca98e75da8b39 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 5 Feb 2016 16:18:54 -0700 Subject: [PATCH 125/131] Add some cpp<->chai performance tests --- CMakeLists.txt | 8 ++++++++ performance_tests/profile_cpp_calls_2.cpp | 20 ++++++++++++++++++++ performance_tests/profile_fun_wrappers.cpp | 20 ++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 performance_tests/profile_cpp_calls_2.cpp create mode 100644 performance_tests/profile_fun_wrappers.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 841615f..07af575 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -397,6 +397,14 @@ if(BUILD_TESTING) add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename}) list(APPEND TESTS performance.${filename}) endforeach() + + add_executable(profile_cpp_calls_2 performance_tests/profile_cpp_calls_2.cpp) + target_link_libraries(profile_cpp_calls_2 ${LIBS}) + add_test(NAME performance.profile_cpp_calls_2 COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_cpp_calls_2 $) + + add_executable(profile_fun_wrappers performance_tests/profile_fun_wrappers.cpp) + target_link_libraries(profile_fun_wrappers ${LIBS}) + add_test(NAME performance.profile_fun_wrappers COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_fun_wrappers $) endif() set_property(TEST ${TESTS} diff --git a/performance_tests/profile_cpp_calls_2.cpp b/performance_tests/profile_cpp_calls_2.cpp new file mode 100644 index 0000000..0424654 --- /dev/null +++ b/performance_tests/profile_cpp_calls_2.cpp @@ -0,0 +1,20 @@ +#include +#include + +double f(const std::string &, double, bool) noexcept { + return .0; +} + +int main() +{ + chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); + + chai.add(chaiscript::fun(&f), "f"); + + chai.eval(R"( + for (var i = 0; i < 100000; ++i) { + f("str", 1.2, false); + } + )"); + +} diff --git a/performance_tests/profile_fun_wrappers.cpp b/performance_tests/profile_fun_wrappers.cpp new file mode 100644 index 0000000..fb96f48 --- /dev/null +++ b/performance_tests/profile_fun_wrappers.cpp @@ -0,0 +1,20 @@ +#include +#include + +double f(const std::string &, double, bool) noexcept { + return .0; +} + +int main() +{ + chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); + + chai.add(chaiscript::fun(&f), "f"); + + const auto f = chai.eval>(R"(fun(){ f("str", 1.2, false); })"); + + for (int i = 0; i < 100000; ++i) { + f(); + } + +} From bc0eaa5d15bec3a0bcad86c021b2e7b2a65f2eec Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 14 Feb 2016 20:01:49 -0700 Subject: [PATCH 126/131] Fix some issues found by cppcheck --- CMakeLists.txt | 2 +- include/chaiscript/chaiscript_threading.hpp | 18 +++++++++--------- include/chaiscript/dispatchkit/any.hpp | 2 +- .../chaiscript/dispatchkit/bad_boxed_cast.hpp | 2 +- .../chaiscript/language/chaiscript_eval.hpp | 2 ++ 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07af575..e064455 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,7 +178,7 @@ else() add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG}) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors) + add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command) else() add_definitions(-Wnoexcept) endif() diff --git a/include/chaiscript/chaiscript_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index 0bb3cfd..f273be6 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -45,14 +45,14 @@ namespace chaiscript class unique_lock : public std::unique_lock { public: - unique_lock(T &t) : std::unique_lock(t) {} + explicit unique_lock(T &t) : std::unique_lock(t) {} }; template class shared_lock : public std::unique_lock { public: - shared_lock(T &t) : std::unique_lock(t) {} + explicit shared_lock(T &t) : std::unique_lock(t) {} void unlock() {} }; @@ -60,7 +60,7 @@ namespace chaiscript class lock_guard : public std::lock_guard { public: - lock_guard(T &t) : std::lock_guard(t) {} + explicit lock_guard(T &t) : std::lock_guard(t) {} }; class shared_mutex : public std::mutex { }; @@ -77,7 +77,7 @@ namespace chaiscript { public: - Thread_Storage(void *t_key) + explicit Thread_Storage(void *t_key) : m_key(t_key) { } @@ -129,7 +129,7 @@ namespace chaiscript { public: - Thread_Storage(void *) + explicit Thread_Storage(void *) { } @@ -183,7 +183,7 @@ namespace chaiscript class unique_lock { public: - unique_lock(T &) {} + explicit unique_lock(T &) {} void lock() {} void unlock() {} }; @@ -192,7 +192,7 @@ namespace chaiscript class shared_lock { public: - shared_lock(T &) {} + explicit shared_lock(T &) {} void lock() {} void unlock() {} }; @@ -201,7 +201,7 @@ namespace chaiscript class lock_guard { public: - lock_guard(T &) {} + explicit lock_guard(T &) {} }; class shared_mutex { }; @@ -213,7 +213,7 @@ namespace chaiscript class Thread_Storage { public: - Thread_Storage(void *) + explicit Thread_Storage(void *) { } diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index 8a624b1..e86ba0e 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -46,7 +46,7 @@ namespace chaiscript { private: struct Data { - Data(const std::type_info &t_type) + explicit Data(const std::type_info &t_type) : m_type(t_type) { } diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index c2be40f..4a18e06 100644 --- a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -40,7 +40,7 @@ namespace chaiscript { } - bad_boxed_cast(std::string t_what) CHAISCRIPT_NOEXCEPT + explicit bad_boxed_cast(std::string t_what) CHAISCRIPT_NOEXCEPT : to(nullptr), m_what(std::move(t_what)) { } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index c3391b5..114d5e4 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -172,8 +172,10 @@ namespace chaiscript virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { if (!m_value.is_undef()) { + std::cout << "1\n"; return m_value; } else { + std::cout << "0\n"; try { return t_ss->get_object(this->text, m_loc); } From ed65ad72d003fc15741b4b8b09ce889f6249044e Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 14 Feb 2016 20:04:17 -0700 Subject: [PATCH 127/131] Update copyrights --- LICENSE | 2 +- include/chaiscript/chaiscript.hpp | 2 +- include/chaiscript/chaiscript_defines.hpp | 2 +- include/chaiscript/chaiscript_threading.hpp | 2 +- include/chaiscript/dispatchkit/bad_boxed_cast.hpp | 2 +- include/chaiscript/dispatchkit/bind_first.hpp | 2 +- include/chaiscript/dispatchkit/bootstrap.hpp | 2 +- include/chaiscript/dispatchkit/bootstrap_stl.hpp | 2 +- include/chaiscript/dispatchkit/boxed_cast.hpp | 2 +- include/chaiscript/dispatchkit/boxed_cast_helper.hpp | 2 +- include/chaiscript/dispatchkit/boxed_number.hpp | 2 +- include/chaiscript/dispatchkit/boxed_value.hpp | 2 +- include/chaiscript/dispatchkit/callable_traits.hpp | 2 +- include/chaiscript/dispatchkit/dispatchkit.hpp | 2 +- include/chaiscript/dispatchkit/dynamic_object.hpp | 2 +- include/chaiscript/dispatchkit/dynamic_object_detail.hpp | 2 +- include/chaiscript/dispatchkit/exception_specification.hpp | 2 +- include/chaiscript/dispatchkit/function_call.hpp | 2 +- include/chaiscript/dispatchkit/function_call_detail.hpp | 2 +- include/chaiscript/dispatchkit/handle_return.hpp | 2 +- include/chaiscript/dispatchkit/operators.hpp | 2 +- include/chaiscript/dispatchkit/proxy_constructors.hpp | 2 +- include/chaiscript/dispatchkit/proxy_functions.hpp | 2 +- include/chaiscript/dispatchkit/proxy_functions_detail.hpp | 2 +- include/chaiscript/dispatchkit/register_function.hpp | 2 +- include/chaiscript/dispatchkit/type_conversions.hpp | 2 +- include/chaiscript/dispatchkit/type_info.hpp | 2 +- include/chaiscript/language/chaiscript_algebraic.hpp | 2 +- include/chaiscript/language/chaiscript_common.hpp | 2 +- include/chaiscript/language/chaiscript_engine.hpp | 2 +- include/chaiscript/language/chaiscript_eval.hpp | 2 +- include/chaiscript/language/chaiscript_parser.hpp | 2 +- include/chaiscript/utility/utility.hpp | 2 +- license.txt | 2 +- readme.md | 2 +- samples/fun_call_performance.cpp | 2 +- src/main.cpp | 2 +- src/stl_extra.cpp | 2 +- 38 files changed, 38 insertions(+), 38 deletions(-) diff --git a/LICENSE b/LICENSE index 48f5292..105662d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2009-2015 Jason Turner +Copyright 2009-2016 Jason Turner Copyright 2009-2012 Jonathan Turner. All Rights Reserved. diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index 1b37e9b..79ef8cf 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_HPP_ diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 553ff54..941ba87 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_DEFINES_HPP_ diff --git a/include/chaiscript/chaiscript_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index f273be6..2a0e63c 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_THREADING_HPP_ diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index 4a18e06..0716749 100644 --- a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_ diff --git a/include/chaiscript/dispatchkit/bind_first.hpp b/include/chaiscript/dispatchkit/bind_first.hpp index 5cd61da..fcba534 100644 --- a/include/chaiscript/dispatchkit/bind_first.hpp +++ b/include/chaiscript/dispatchkit/bind_first.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BIND_FIRST_HPP_ diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 7e3a301..ef9f032 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BOOTSTRAP_HPP_ diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 8b55981..8c225c3 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com /// \file diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 1ddaacc..3880430 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BOXED_CAST_HPP_ diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index 2e08777..bbcab16 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_ diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index dd5bf8c..23e60c7 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_ diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 1c2ebe7..5a49119 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BOXED_VALUE_HPP_ diff --git a/include/chaiscript/dispatchkit/callable_traits.hpp b/include/chaiscript/dispatchkit/callable_traits.hpp index cc1b2e7..765e6d6 100644 --- a/include/chaiscript/dispatchkit/callable_traits.hpp +++ b/include/chaiscript/dispatchkit/callable_traits.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_ diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 0aa7db0..1f2e9d8 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_DISPATCHKIT_HPP_ diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 1e79eea..05fc069 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_ diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index f1e20a1..91fcc7d 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_ diff --git a/include/chaiscript/dispatchkit/exception_specification.hpp b/include/chaiscript/dispatchkit/exception_specification.hpp index 2a9f0b6..55398f7 100644 --- a/include/chaiscript/dispatchkit/exception_specification.hpp +++ b/include/chaiscript/dispatchkit/exception_specification.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ diff --git a/include/chaiscript/dispatchkit/function_call.hpp b/include/chaiscript/dispatchkit/function_call.hpp index c5b950a..e28bf61 100644 --- a/include/chaiscript/dispatchkit/function_call.hpp +++ b/include/chaiscript/dispatchkit/function_call.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_FUNCTION_CALL_HPP_ diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index 4054b59..2fc3f96 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index e3a8254..2650e3b 100644 --- a/include/chaiscript/dispatchkit/handle_return.hpp +++ b/include/chaiscript/dispatchkit/handle_return.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_HANDLE_RETURN_HPP_ diff --git a/include/chaiscript/dispatchkit/operators.hpp b/include/chaiscript/dispatchkit/operators.hpp index a04cba4..2d4401e 100644 --- a/include/chaiscript/dispatchkit/operators.hpp +++ b/include/chaiscript/dispatchkit/operators.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_OPERATORS_HPP_ diff --git a/include/chaiscript/dispatchkit/proxy_constructors.hpp b/include/chaiscript/dispatchkit/proxy_constructors.hpp index 063c557..a5ad41e 100644 --- a/include/chaiscript/dispatchkit/proxy_constructors.hpp +++ b/include/chaiscript/dispatchkit/proxy_constructors.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 6214b4d..e115d96 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index 130d3c1..5c2fe91 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ diff --git a/include/chaiscript/dispatchkit/register_function.hpp b/include/chaiscript/dispatchkit/register_function.hpp index 598dd8b..8334b7b 100644 --- a/include/chaiscript/dispatchkit/register_function.hpp +++ b/include/chaiscript/dispatchkit/register_function.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_ diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 2a9a398..6987389 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 9614597..1426085 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_TYPE_INFO_HPP_ diff --git a/include/chaiscript/language/chaiscript_algebraic.hpp b/include/chaiscript/language/chaiscript_algebraic.hpp index 151a94b..52441e8 100644 --- a/include/chaiscript/language/chaiscript_algebraic.hpp +++ b/include/chaiscript/language/chaiscript_algebraic.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_ALGEBRAIC_HPP_ diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 259946f..76881d5 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_COMMON_HPP_ diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 9824bd2..bf2338b 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_ENGINE_HPP_ diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 114d5e4..451bd21 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_EVAL_HPP_ diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 2f0d596..0bfabe5 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_PARSER_HPP_ diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index fbd8c66..22ab8e9 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_ diff --git a/license.txt b/license.txt index 48f5292..105662d 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright 2009-2015 Jason Turner +Copyright 2009-2016 Jason Turner Copyright 2009-2012 Jonathan Turner. All Rights Reserved. diff --git a/readme.md b/readme.md index 75e470a..160662a 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,7 @@ ChaiScript http://www.chaiscript.com (c) 2009-2012 Jonathan Turner -(c) 2009-2015 Jason Turner +(c) 2009-2016 Jason Turner Release under the BSD license, see "license.txt" for details. diff --git a/samples/fun_call_performance.cpp b/samples/fun_call_performance.cpp index 7e340f3..0ccc08d 100644 --- a/samples/fun_call_performance.cpp +++ b/samples/fun_call_performance.cpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #include diff --git a/src/main.cpp b/src/main.cpp index 6fe1bc2..7f203cd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #include diff --git a/src/stl_extra.cpp b/src/stl_extra.cpp index e391b18..ec38db7 100644 --- a/src/stl_extra.cpp +++ b/src/stl_extra.cpp @@ -1,7 +1,7 @@ // This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #include From e024b99b36496e309ce70abff0f1473e959c5de8 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 16 Feb 2016 08:29:01 -0700 Subject: [PATCH 128/131] Fixes for type_conversion handling --- include/chaiscript/dispatchkit/boxed_cast.hpp | 10 +-- .../dispatchkit/boxed_cast_helper.hpp | 22 +++--- .../chaiscript/dispatchkit/boxed_number.hpp | 2 +- .../chaiscript/dispatchkit/dispatchkit.hpp | 62 +++++++++------- .../dispatchkit/dynamic_object_detail.hpp | 14 ++-- .../chaiscript/dispatchkit/function_call.hpp | 14 ++-- .../dispatchkit/function_call_detail.hpp | 51 ++++++++++---- .../dispatchkit/proxy_functions.hpp | 52 +++++++------- .../dispatchkit/proxy_functions_detail.hpp | 26 +++---- .../dispatchkit/type_conversions.hpp | 70 +++++++++++++------ .../chaiscript/language/chaiscript_common.hpp | 4 +- .../chaiscript/language/chaiscript_engine.hpp | 6 +- .../chaiscript/language/chaiscript_eval.hpp | 28 ++++---- 13 files changed, 216 insertions(+), 145 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 3880430..44450a0 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -69,9 +69,9 @@ namespace chaiscript /// assert(i == 5); /// \endcode template - typename detail::Cast_Helper::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr) + typename detail::Cast_Helper::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr) { - if (!t_conversions || bv.get_type_info().bare_equal(user_type()) || (t_conversions && !t_conversions->convertable_type())) { + if (!t_conversions || bv.get_type_info().bare_equal(user_type()) || (t_conversions && !(*t_conversions)->convertable_type())) { try { return detail::Cast_Helper::cast(bv, t_conversions); } catch (const chaiscript::detail::exception::bad_any_cast &) { @@ -79,18 +79,18 @@ namespace chaiscript } - if (t_conversions && t_conversions->convertable_type()) + if (t_conversions && (*t_conversions)->convertable_type()) { try { // std::cout << "trying an up conversion " << typeid(Type).name() << '\n'; // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // either way, we are not responsible if it doesn't work - return detail::Cast_Helper::cast(t_conversions->boxed_type_conversion(bv), t_conversions); + return detail::Cast_Helper::cast((*t_conversions)->boxed_type_conversion(t_conversions->saves(), bv), t_conversions); } catch (...) { try { // std::cout << "trying a down conversion " << typeid(Type).name() << '\n'; // try going the other way - down the inheritance graph - return detail::Cast_Helper::cast(t_conversions->boxed_type_down_conversion(bv), t_conversions); + return detail::Cast_Helper::cast((*t_conversions)->boxed_type_down_conversion(t_conversions->saves(), bv), t_conversions); } catch (const chaiscript::detail::exception::bad_any_cast &) { throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); } diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index bbcab16..505b1e1 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -16,7 +16,7 @@ namespace chaiscript { - class Type_Conversions; + class Type_Conversions_State; namespace detail { @@ -35,7 +35,7 @@ namespace chaiscript { typedef typename std::add_const::type Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) { if (ob.get_type_info().bare_equal_type_info(typeid(Result))) { @@ -58,7 +58,7 @@ namespace chaiscript struct Cast_Helper_Inner { typedef const Result * Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) { if (ob.get_type_info().bare_equal_type_info(typeid(Result))) { @@ -74,7 +74,7 @@ namespace chaiscript struct Cast_Helper_Inner { typedef Result * Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) { if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result)) { @@ -102,7 +102,7 @@ namespace chaiscript { typedef const Result& Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) { if (ob.get_type_info().bare_equal_type_info(typeid(Result))) { @@ -122,7 +122,7 @@ namespace chaiscript { typedef Result& Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) { if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result))) { @@ -139,7 +139,7 @@ namespace chaiscript { typedef std::shared_ptr Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob.get().cast >(); } @@ -151,7 +151,7 @@ namespace chaiscript { typedef std::shared_ptr Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) { if (!ob.get_type_info().is_const()) { @@ -191,7 +191,7 @@ namespace chaiscript { typedef Boxed_Value Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob; } @@ -203,7 +203,7 @@ namespace chaiscript { typedef std::reference_wrapper Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) { return std::ref(const_cast(ob)); } @@ -259,7 +259,7 @@ namespace chaiscript { typedef typename Cast_Helper_Inner::Result_Type Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { return Cast_Helper_Inner::cast(ob, t_conversions); } diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index 23e60c7..604d0d0 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -1011,7 +1011,7 @@ namespace chaiscript { typedef Boxed_Number Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) { return Boxed_Number(ob); } diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 1f2e9d8..9670d0f 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -314,7 +314,7 @@ namespace chaiscript return arity; } - virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { return std::any_of(m_funcs.cbegin(), m_funcs.cend(), [&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); }); @@ -326,7 +326,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { return dispatch::dispatch(m_funcs, params, t_conversions); } @@ -442,7 +442,8 @@ namespace chaiscript template typename detail::Cast_Helper::Result_Type boxed_cast(const Boxed_Value &bv) const { - return chaiscript::boxed_cast(bv, &m_conversions); + Type_Conversions_State state(m_conversions, m_conversions.conversion_saves()); + return chaiscript::boxed_cast(bv, &state); } /// Add a new conversion for upcasting to a base class @@ -911,7 +912,7 @@ namespace chaiscript } bool is_attribute_call(const std::vector &t_funs, const std::vector &t_params, - bool t_has_params) const + bool t_has_params, const Type_Conversions_State &t_conversions) const { if (!t_has_params || t_params.empty()) { return false; @@ -919,7 +920,7 @@ namespace chaiscript for (const auto &fun : t_funs) { if (fun->is_attribute_function()) { - if (fun->compare_first_type(t_params[0], m_conversions)) { + if (fun->compare_first_type(t_params[0], t_conversions)) { return true; } } @@ -934,14 +935,15 @@ namespace chaiscript #pragma warning(push) #pragma warning(disable : 4715) #endif - Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms, bool t_has_params) + Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms, bool t_has_params, + const Type_Conversions_State &t_conversions) { uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); const auto funs = get_function(t_name, loc); if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed); const auto do_attribute_call = - [this](int l_num_params, const std::vector &l_params, const std::vector &l_funs, const Type_Conversions &l_conversions)->Boxed_Value + [this](int l_num_params, const std::vector &l_params, const std::vector &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value { std::vector attr_params{l_params.begin(), l_params.begin() + l_num_params}; Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions); @@ -974,14 +976,14 @@ namespace chaiscript } }; - if (is_attribute_call(*funs.second, params, t_has_params)) { - return do_attribute_call(1, params, *funs.second, m_conversions); + if (is_attribute_call(*funs.second, params, t_has_params, t_conversions)) { + return do_attribute_call(1, params, *funs.second, t_conversions); } else { std::exception_ptr except; if (!funs.second->empty()) { try { - return dispatch::dispatch(*funs.second, params, m_conversions); + return dispatch::dispatch(*funs.second, params, t_conversions); } catch(chaiscript::exception::dispatch_error&) { except = std::current_exception(); } @@ -997,7 +999,7 @@ namespace chaiscript for (const auto &f : *method_missing_funs) { - if(f->compare_first_type(params[0], m_conversions)) { + if(f->compare_first_type(params[0], t_conversions)) { fs.push_back(f); } } @@ -1021,9 +1023,9 @@ namespace chaiscript if (is_no_param) { std::vector tmp_params(params); tmp_params.insert(tmp_params.begin() + 1, var(t_name)); - return do_attribute_call(2, tmp_params, functions, m_conversions); + return do_attribute_call(2, tmp_params, functions, t_conversions); } else { - return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector(params.begin()+1, params.end()))}, m_conversions); + return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector(params.begin()+1, params.end()))}, t_conversions); } } catch (const dispatch::option_explicit_set &e) { throw chaiscript::exception::dispatch_error(params, std::vector(funs.second->begin(), funs.second->end()), @@ -1046,12 +1048,13 @@ namespace chaiscript - Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms) const + Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms, + const Type_Conversions_State &t_conversions) const { uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); const auto funs = get_function(t_name, loc); if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed); - return dispatch::dispatch(*funs.second, params, m_conversions); + return dispatch::dispatch(*funs.second, params, t_conversions); } @@ -1105,8 +1108,9 @@ namespace chaiscript } const Const_Proxy_Function &f = this->boxed_cast(params[0]); + const Type_Conversions_State conversions(m_conversions, m_conversions.conversion_saves()); - return Boxed_Value(f->call_match(std::vector(params.begin() + 1, params.end()), m_conversions)); + return Boxed_Value(f->call_match(std::vector(params.begin() + 1, params.end()), conversions)); } /// Dump all system info to stdout @@ -1208,19 +1212,19 @@ namespace chaiscript save_function_params(*m_stack_holder, t_params); } - void new_function_call(Stack_Holder &t_s) + void new_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves) { if (t_s.call_depth == 0) { - m_conversions.enable_conversion_saves(true); + m_conversions.enable_conversion_saves(t_saves, true); } ++t_s.call_depth; - save_function_params(m_conversions.take_saves()); + save_function_params(m_conversions.take_saves(t_saves)); } - void pop_function_call(Stack_Holder &t_s) + void pop_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves) { --t_s.call_depth; @@ -1229,18 +1233,18 @@ namespace chaiscript if (t_s.call_depth == 0) { t_s.call_params.back().clear(); - m_conversions.enable_conversion_saves(false); + m_conversions.enable_conversion_saves(t_saves, false); } } void new_function_call() { - new_function_call(*m_stack_holder); + new_function_call(*m_stack_holder, m_conversions.conversion_saves()); } void pop_function_call() { - pop_function_call(*m_stack_holder); + pop_function_call(*m_stack_holder, m_conversions.conversion_saves()); } Stack_Holder &get_stack_holder() @@ -1510,7 +1514,8 @@ namespace chaiscript public: Dispatch_State(Dispatch_Engine &t_engine) : m_engine(t_engine), - m_stack_holder(t_engine.get_stack_holder()) + m_stack_holder(t_engine.get_stack_holder()), + m_conversions(t_engine.conversions(), t_engine.conversions().conversion_saves()) { } @@ -1526,6 +1531,14 @@ namespace chaiscript return m_stack_holder.get(); } + const Type_Conversions_State &conversions() const { + return m_conversions; + } + + Type_Conversions::Conversion_Saves &conversion_saves() const { + return m_conversions.saves(); + } + void add_object(const std::string &t_name, Boxed_Value obj) const { m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get()); } @@ -1533,6 +1546,7 @@ namespace chaiscript private: std::reference_wrapper m_engine; std::reference_wrapper m_stack_holder; + Type_Conversions_State m_conversions; }; } } diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index 91fcc7d..8c9b8f6 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -84,7 +84,7 @@ namespace chaiscript virtual bool is_attribute_function() const CHAISCRIPT_OVERRIDE { return m_is_attribute; } - virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) { @@ -106,7 +106,7 @@ namespace chaiscript protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) { @@ -116,7 +116,7 @@ namespace chaiscript } } - virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); } @@ -134,7 +134,7 @@ namespace chaiscript } bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, - const std::unique_ptr &ti, const Type_Conversions &t_conversions) const + const std::unique_ptr &ti, const Type_Conversions_State &t_conversions) const { if (bv.get_type_info().bare_equal(m_doti)) { @@ -156,7 +156,7 @@ namespace chaiscript } bool dynamic_object_typename_match(const std::vector &bvs, const std::string &name, - const std::unique_ptr &ti, const Type_Conversions &t_conversions) const + const std::unique_ptr &ti, const Type_Conversions_State &t_conversions) const { if (bvs.size() > 0) { @@ -216,7 +216,7 @@ namespace chaiscript return dc && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); } - virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { std::vector new_vals{Boxed_Value(Dynamic_Object(m_type_name))}; new_vals.insert(new_vals.end(), vals.begin(), vals.end()); @@ -230,7 +230,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { auto bv = Boxed_Value(Dynamic_Object(m_type_name), true); std::vector new_params{bv}; diff --git a/include/chaiscript/dispatchkit/function_call.hpp b/include/chaiscript/dispatchkit/function_call.hpp index e28bf61..ea0a61e 100644 --- a/include/chaiscript/dispatchkit/function_call.hpp +++ b/include/chaiscript/dispatchkit/function_call.hpp @@ -18,7 +18,7 @@ namespace chaiscript { class Boxed_Value; -class Type_Conversions; +class Type_Conversions_State; namespace detail { template struct Cast_Helper; } // namespace detail @@ -36,7 +36,7 @@ namespace chaiscript /// \param[in] funcs the set of functions to dispatch on. template std::function - functor(const std::vector &funcs, const Type_Conversions *t_conversions) + functor(const std::vector &funcs, const Type_Conversions_State *t_conversions) { const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(), [](const Const_Proxy_Function &f) { @@ -64,7 +64,7 @@ namespace chaiscript /// \param[in] func A function to execute. template std::function - functor(Const_Proxy_Function func, const Type_Conversions *t_conversions) + functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) { return functor(std::vector({std::move(func)}), t_conversions); } @@ -73,7 +73,7 @@ namespace chaiscript /// and creating a typesafe C++ function caller from it. template std::function - functor(const Boxed_Value &bv, const Type_Conversions *t_conversions) + functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) { return functor(boxed_cast(bv, t_conversions), t_conversions); } @@ -86,7 +86,7 @@ namespace chaiscript { typedef std::function Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { @@ -103,7 +103,7 @@ namespace chaiscript { typedef std::function Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { @@ -120,7 +120,7 @@ namespace chaiscript { typedef std::function Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index 2fc3f96..8ed6115 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -31,9 +31,15 @@ namespace chaiscript struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions *t_conversions) + const std::vector ¶ms, const Type_Conversions_State *t_conversions) { - return boxed_cast(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()), t_conversions); + if (t_conversions) { + return boxed_cast(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions); + } else { + Type_Conversions conv; + Type_Conversions_State state(conv, conv.conversion_saves()); + return boxed_cast(dispatch::dispatch(t_funcs, params, state), t_conversions); + } } }; @@ -44,9 +50,15 @@ namespace chaiscript struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions *t_conversions) + const std::vector ¶ms, const Type_Conversions_State *t_conversions) { - return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions())).get_as(); + if (t_conversions) { + return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as(); + } else { + Type_Conversions conv; + Type_Conversions_State state(conv, conv.conversion_saves()); + return Boxed_Number(dispatch::dispatch(t_funcs, params, state)).get_as(); + } } }; @@ -58,9 +70,15 @@ namespace chaiscript struct Function_Caller_Ret { static void call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions *t_conversions) + const std::vector ¶ms, const Type_Conversions_State *t_conversions) { - dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()); + if (t_conversions) { + dispatch::dispatch(t_funcs, params, *t_conversions); + } else { + Type_Conversions conv; + Type_Conversions_State state(conv, conv.conversion_saves()); + dispatch::dispatch(t_funcs, params, state); + } } }; @@ -79,11 +97,18 @@ namespace chaiscript template Ret operator()(P&& ... param) { - return Function_Caller_Ret::value && !std::is_same::value>::call(m_funcs, { - box

(std::forward

(param))... - }, m_conversions - - ); + if (m_conversions) { + Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves()); + return Function_Caller_Ret::value && !std::is_same::value>::call(m_funcs, { + box

(std::forward

(param))... + }, &state + ); + } else { + return Function_Caller_Ret::value && !std::is_same::value>::call(m_funcs, { + box

(std::forward

(param))... + }, nullptr + ); + } } @@ -114,7 +139,7 @@ namespace chaiscript /// \todo what happens if t_conversions is deleted out from under us?! template - std::function build_function_caller_helper(Ret (Params...), const std::vector &funcs, const Type_Conversions *t_conversions) + std::function build_function_caller_helper(Ret (Params...), const std::vector &funcs, const Type_Conversions_State *t_conversions) { /* if (funcs.size() == 1) @@ -132,7 +157,7 @@ namespace chaiscript } */ - return std::function(Build_Function_Caller_Helper(funcs, t_conversions)); + return std::function(Build_Function_Caller_Helper(funcs, t_conversions?t_conversions->get():nullptr)); } } } diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index e115d96..6128b33 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -43,7 +43,7 @@ namespace chaiscript namespace dispatch { template - std::function functor(std::shared_ptr func, const Type_Conversions *t_conversions); + std::function functor(std::shared_ptr func, const Type_Conversions_State *t_conversions); class Param_Types { @@ -72,7 +72,7 @@ namespace chaiscript return m_types == t_rhs.m_types; } - bool match(const std::vector &vals, const Type_Conversions &t_conversions) const + 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; @@ -147,7 +147,7 @@ namespace chaiscript public: virtual ~Proxy_Function_Base() {} - Boxed_Value operator()(const std::vector ¶ms, const chaiscript::Type_Conversions &t_conversions) const + Boxed_Value operator()(const std::vector ¶ms, const chaiscript::Type_Conversions_State &t_conversions) const { if (m_arity < 0 || size_t(m_arity) == params.size()) { return do_call(params, t_conversions); @@ -163,7 +163,7 @@ namespace chaiscript const std::vector &get_param_types() const { return m_types; } virtual bool operator==(const Proxy_Function_Base &) const = 0; - virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const = 0; + virtual bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const = 0; virtual bool is_attribute_function() const { return false; } @@ -179,7 +179,7 @@ namespace chaiscript //! Return true if the function is a possible match //! to the passed in values - bool filter(const std::vector &vals, const Type_Conversions &t_conversions) const + bool filter(const std::vector &vals, const Type_Conversions_State &t_conversions) const { if (m_arity < 0) { @@ -206,7 +206,7 @@ namespace chaiscript virtual std::string annotation() const = 0; - static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions &t_conversions) + static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions) { if (ti.is_undef() || ti.bare_equal(user_type()) @@ -214,7 +214,7 @@ namespace chaiscript && ( (ti.bare_equal(user_type()) && bv.get_type_info().is_arithmetic()) || ti.bare_equal(bv.get_type_info()) || bv.get_type_info().bare_equal(user_type >()) - || t_conversions.converts(ti, bv.get_type_info()) + || t_conversions->converts(ti, bv.get_type_info()) ) ) ) @@ -225,13 +225,13 @@ namespace chaiscript } } - virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const + virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const { return compare_type_to_param(m_types[1], bv, t_conversions); } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const = 0; + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const = 0; Proxy_Function_Base(std::vector t_types, int t_arity) : m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false) @@ -248,7 +248,7 @@ namespace chaiscript } - static bool compare_types(const std::vector &tis, const std::vector &bvs, const Type_Conversions &t_conversions) + static bool compare_types(const std::vector &tis, const std::vector &bvs, const Type_Conversions_State &t_conversions) { if (tis.size() - 1 != bvs.size()) { @@ -327,7 +327,7 @@ namespace chaiscript && this->m_param_types == prhs->m_param_types); } - virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions))) && test_guard(vals, t_conversions); @@ -351,7 +351,7 @@ namespace chaiscript protected: - bool test_guard(const std::vector ¶ms, const Type_Conversions &t_conversions) const + bool test_guard(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const { if (m_guard) { @@ -419,7 +419,7 @@ namespace chaiscript protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { if (call_match(params, t_conversions) && test_guard(params, t_conversions)) { @@ -469,7 +469,7 @@ namespace chaiscript virtual ~Bound_Function() {} - virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { return m_f->call_match(build_param_list(vals), t_conversions); } @@ -548,7 +548,7 @@ namespace chaiscript return retval; } - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { return (*m_f)(build_param_list(params), t_conversions); } @@ -573,12 +573,12 @@ namespace chaiscript return ""; } - virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { return static_cast(vals.size()) == get_arity() && (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions)); } - virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions &t_conversions) const = 0; + virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const = 0; }; @@ -596,7 +596,7 @@ namespace chaiscript virtual ~Proxy_Function_Callable_Impl() {} - virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); } @@ -608,7 +608,7 @@ namespace chaiscript protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { typedef typename detail::Function_Signature::Return_Type Return_Type; return detail::Do_Call::template go(m_f, params, t_conversions); @@ -648,7 +648,7 @@ namespace chaiscript virtual ~Assignable_Proxy_Function_Impl() {} - virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); } @@ -668,7 +668,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { return detail::Do_Call::result_type>::template go(m_f.get(), params, t_conversions); } @@ -705,7 +705,7 @@ namespace chaiscript } } - virtual bool call_match(const std::vector &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions_State &) const CHAISCRIPT_OVERRIDE { if (vals.size() != 1) { @@ -721,7 +721,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE { const Boxed_Value &bv = params[0]; if (bv.is_const()) @@ -782,7 +782,7 @@ namespace chaiscript { template bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector &plist, - const Type_Conversions &t_conversions) + const Type_Conversions_State &t_conversions) { const std::vector &types = t_func->get_param_types(); @@ -801,7 +801,7 @@ namespace chaiscript template Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector &plist, - const Type_Conversions &t_conversions, const Funcs &t_funcs) + const Type_Conversions_State &t_conversions, const Funcs &t_funcs) { InItr matching_func(end); @@ -878,7 +878,7 @@ namespace chaiscript */ template Boxed_Value dispatch(const Funcs &funcs, - const std::vector &plist, const Type_Conversions &t_conversions) + const std::vector &plist, const Type_Conversions_State &t_conversions) { std::vector> ordered_funcs; ordered_funcs.reserve(funcs.size()); diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index 5c2fe91..452a999 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -19,7 +19,7 @@ #include "callable_traits.hpp" namespace chaiscript { -class Type_Conversions; +class Type_Conversions_State; namespace exception { class bad_boxed_cast; } // namespace exception @@ -77,7 +77,7 @@ namespace chaiscript template struct Try_Cast { - static void do_try(const std::vector ¶ms, size_t generation, const Type_Conversions &t_conversions) + static void do_try(const std::vector ¶ms, size_t generation, const Type_Conversions_State &t_conversions) { boxed_cast(params[generation], &t_conversions); Try_Cast::do_try(params, generation+1, t_conversions); @@ -88,7 +88,7 @@ namespace chaiscript template<> struct Try_Cast<> { - static void do_try(const std::vector &, size_t, const Type_Conversions &) + static void do_try(const std::vector &, size_t, const Type_Conversions_State &) { } }; @@ -101,7 +101,7 @@ namespace chaiscript */ template bool compare_types_cast(Ret (*)(Params...), - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions_State &t_conversions) { try { Try_Cast::do_try(params, 0, t_conversions); @@ -118,7 +118,7 @@ namespace chaiscript template static Ret do_call(const Callable &f, - const std::vector ¶ms, const Type_Conversions &t_conversions, InnerParams &&... innerparams) + const std::vector ¶ms, const Type_Conversions_State &t_conversions, InnerParams &&... innerparams) { return Call_Func::do_call(f, params, t_conversions, std::forward(innerparams)..., params[sizeof...(Params) - count]); } @@ -133,7 +133,7 @@ namespace chaiscript #endif template static Ret do_call(const Callable &f, - const std::vector &, const Type_Conversions &t_conversions, InnerParams &&... innerparams) + const std::vector &, const Type_Conversions_State &t_conversions, InnerParams &&... innerparams) { return f(boxed_cast(std::forward(innerparams), &t_conversions)...); } @@ -150,7 +150,7 @@ namespace chaiscript */ template Ret call_func(const chaiscript::dispatch::detail::Function_Signature &, const Callable &f, - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions_State &t_conversions) { if (params.size() == sizeof...(Params)) { @@ -190,7 +190,7 @@ namespace chaiscript */ template bool compare_types_cast(Indexes, Ret (*)(Params...), - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions_State &t_conversions) { try { (void)params; (void)t_conversions; @@ -204,7 +204,7 @@ namespace chaiscript template bool compare_types_cast(Ret (*f)(Params...), - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions_State &t_conversions) { typedef typename Make_Indexes::indexes indexes; return compare_types_cast(indexes(), f, params, t_conversions); @@ -213,7 +213,7 @@ namespace chaiscript template Ret call_func(const chaiscript::dispatch::detail::Function_Signature &, Indexes, const Callable &f, - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions_State &t_conversions) { (void)params; (void)t_conversions; return f(boxed_cast(params[I], &t_conversions)...); @@ -228,7 +228,7 @@ namespace chaiscript */ template Ret call_func(const chaiscript::dispatch::detail::Function_Signature &sig, const Callable &f, - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions_State &t_conversions) { typedef typename Make_Indexes::indexes indexes; return call_func(sig, indexes(), f, params, t_conversions); @@ -252,7 +252,7 @@ namespace chaiscript struct Do_Call { template - static Boxed_Value go(const Callable &fun, const std::vector ¶ms, const Type_Conversions &t_conversions) + static Boxed_Value go(const Callable &fun, const std::vector ¶ms, const Type_Conversions_State &t_conversions) { return Handle_Return::handle(call_func(Function_Signature(), fun, params, t_conversions)); } @@ -262,7 +262,7 @@ namespace chaiscript struct Do_Call { template - static Boxed_Value go(const Callable &fun, const std::vector ¶ms, const Type_Conversions &t_conversions) + static Boxed_Value go(const Callable &fun, const std::vector ¶ms, const Type_Conversions_State &t_conversions) { call_func(Function_Signature(), fun, params, t_conversions); return Handle_Return::handle(); diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 6987389..3a4d239 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -315,6 +315,16 @@ namespace chaiscript class Type_Conversions { public: + struct Conversion_Saves + { + Conversion_Saves() + : enabled(false) + {} + + bool enabled; + std::vector saves; + }; + struct Less_Than { bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const @@ -386,15 +396,14 @@ namespace chaiscript } else { return false; } - } template - Boxed_Value boxed_type_conversion(const Boxed_Value &from) const + Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const { try { Boxed_Value ret = get_conversion(user_type(), from.get_type_info())->convert(from); - if (m_conversion_saves->enabled) m_conversion_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"); @@ -404,11 +413,11 @@ namespace chaiscript } template - Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const + Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const { try { Boxed_Value ret = get_conversion(to.get_type_info(), user_type())->convert_down(to); - if (m_conversion_saves->enabled) m_conversion_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"); @@ -417,15 +426,15 @@ namespace chaiscript } } - void enable_conversion_saves(bool t_val) + static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val) { - m_conversion_saves->enabled = t_val; + t_saves.enabled = t_val; } - std::vector take_saves() + std::vector take_saves(Conversion_Saves &t_saves) { std::vector ret; - std::swap(ret, m_conversion_saves->saves); + std::swap(ret, t_saves.saves); return ret; } @@ -449,6 +458,10 @@ namespace chaiscript } } + Conversion_Saves &conversion_saves() const { + return *m_conversion_saves; + } + private: std::set >::const_iterator find_bidir( const Type_Info &to, const Type_Info &from) const @@ -458,7 +471,6 @@ namespace chaiscript { return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from)) || (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from)); -; } ); } @@ -482,15 +494,6 @@ namespace chaiscript } - struct Conversion_Saves - { - Conversion_Saves() - : enabled(false) - {} - - bool enabled; - std::vector saves; - }; mutable chaiscript::detail::threading::shared_mutex m_mutex; std::set> m_conversions; @@ -500,6 +503,33 @@ namespace chaiscript mutable chaiscript::detail::threading::Thread_Storage m_conversion_saves; }; + class Type_Conversions_State + { + public: + Type_Conversions_State(const Type_Conversions &t_conversions, + Type_Conversions::Conversion_Saves &t_saves) + : m_conversions(t_conversions), + m_saves(t_saves) + { + } + + const Type_Conversions *operator->() const { + return &m_conversions.get(); + } + + const Type_Conversions *get() const { + return &m_conversions.get(); + } + + Type_Conversions::Conversion_Saves &saves() const { + return m_saves; + } + + private: + std::reference_wrapper m_conversions; + std::reference_wrapper m_saves; + }; + typedef std::shared_ptr Type_Conversion; /// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you @@ -608,8 +638,6 @@ namespace chaiscript return chaiscript::make_shared>(user_type>(), user_type(), func); } - - } diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 76881d5..b44a5a3 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -582,12 +582,12 @@ namespace chaiscript Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) : m_ds(t_ds) { - m_ds.get()->new_function_call(m_ds.get().stack_holder()); + m_ds.get()->new_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves()); } ~Function_Push_Pop() { - m_ds.get()->pop_function_call(m_ds.get().stack_holder()); + m_ds.get()->pop_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves()); } void save_params(const std::vector &t_params) diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index bf2338b..f0c42be 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -368,11 +368,15 @@ namespace chaiscript // m_engine.add(fun &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call"); // +// + m_engine.add(fun( [=](const dispatch::Proxy_Function_Base &t_fun, const std::vector &t_params) { - return t_fun(t_params, this->m_engine.conversions()); + Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves()); + return t_fun(t_params, s); }), "call"); + m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name"); m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type"); diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 451bd21..9cdc482 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -118,7 +118,7 @@ namespace chaiscript } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); fpp.save_params({t_lhs, t_rhs}); - return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs}); + return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs}, t_ss.conversions()); } } catch(const exception::dispatch_error &e){ @@ -255,7 +255,7 @@ namespace chaiscript Boxed_Value fn(this->children[0]->eval(t_ss)); try { - return (*t_ss->boxed_cast(fn))(params, t_ss->conversions()); + 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); @@ -436,14 +436,14 @@ namespace chaiscript } else { if (!rhs.is_return_value()) { - rhs = t_ss->call_function("clone", m_clone_loc, {rhs}); + rhs = t_ss->call_function("clone", m_clone_loc, {rhs}, t_ss.conversions()); } rhs.reset_return_value(); } } try { - return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}); + return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions()); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss); @@ -463,7 +463,7 @@ namespace chaiscript } else { try { - return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}); + return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions()); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss); } @@ -546,7 +546,7 @@ namespace chaiscript try { fpp.save_params(params); - return t_ss->call_function("[]", m_loc, params); + return t_ss->call_function("[]", m_loc, params, t_ss.conversions()); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss ); @@ -599,7 +599,7 @@ namespace chaiscript fpp.save_params(params); try { - retval = t_ss->call_member(m_fun_name, m_loc, std::move(params), has_function_params); + retval = t_ss->call_member(m_fun_name, m_loc, std::move(params), has_function_params, t_ss.conversions()); } catch(const exception::dispatch_error &e){ if (e.functions.empty()) @@ -615,7 +615,7 @@ namespace chaiscript if (this->children[2]->identifier == AST_Node_Type::Array_Call) { try { - retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[2]->children[1]->eval(t_ss)}); + retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[2]->children[1]->eval(t_ss)}, t_ss.conversions()); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss); @@ -941,7 +941,7 @@ namespace chaiscript if (this->children[currentCase]->identifier == AST_Node_Type::Case) { //This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here. try { - if (hasMatched || boxed_cast(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}))) { + if (hasMatched || boxed_cast(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}, t_ss.conversions()))) { this->children[currentCase]->eval(t_ss); hasMatched = true; } @@ -1011,7 +1011,7 @@ namespace chaiscript for (const auto &child : children[0]->children) { auto obj = child->eval(t_ss); if (!obj.is_return_value()) { - vec.push_back(t_ss->call_function("clone", m_loc, {obj})); + vec.push_back(t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions())); } else { vec.push_back(std::move(obj)); } @@ -1044,7 +1044,7 @@ namespace chaiscript for (const auto &child : children[0]->children) { auto obj = child->children[1]->eval(t_ss); if (!obj.is_return_value()) { - obj = t_ss->call_function("clone", m_loc, {obj}); + obj = t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions()); } retval[t_ss->boxed_cast(child->children[0]->eval(t_ss))] = std::move(obj); @@ -1140,7 +1140,7 @@ namespace chaiscript } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); fpp.save_params({bv}); - return t_ss->call_function(children[0]->text, m_loc, {std::move(bv)}); + return t_ss->call_function(children[0]->text, m_loc, {std::move(bv)}, t_ss.conversions()); } } catch (const exception::dispatch_error &e) { throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, *t_ss); @@ -1212,7 +1212,7 @@ namespace chaiscript try { auto oper1 = children[0]->children[0]->children[0]->eval(t_ss); auto oper2 = children[0]->children[0]->children[1]->eval(t_ss); - return t_ss->call_function("generate_range", m_loc, {oper1, oper2}); + return t_ss->call_function("generate_range", m_loc, {oper1, oper2}, t_ss.conversions()); } catch (const exception::dispatch_error &e) { throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss); @@ -1257,7 +1257,7 @@ namespace chaiscript if (dispatch::Param_Types( std::vector>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)} - ).match(std::vector{t_except}, t_ss->conversions())) + ).match(std::vector{t_except}, t_ss.conversions())) { t_ss.add_object(name, t_except); From 07fa8010e4ce913728c3d6f77ce49a342fb6fe4a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 16 Feb 2016 11:06:20 -0700 Subject: [PATCH 129/131] Ack! Rollback debug statement print out --- include/chaiscript/language/chaiscript_eval.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 9cdc482..60474b4 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -172,10 +172,8 @@ namespace chaiscript virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { if (!m_value.is_undef()) { - std::cout << "1\n"; return m_value; } else { - std::cout << "0\n"; try { return t_ss->get_object(this->text, m_loc); } From 7f8a6f24f907f4aeac02f7803e1a5c38f99a52f0 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 16 Feb 2016 11:13:14 -0700 Subject: [PATCH 130/131] Fix a few warnings from old gcc --- include/chaiscript/dispatchkit/dispatchkit.hpp | 4 ++-- include/chaiscript/language/chaiscript_engine.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 9670d0f..23dc7ee 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -1108,9 +1108,9 @@ namespace chaiscript } const Const_Proxy_Function &f = this->boxed_cast(params[0]); - const Type_Conversions_State conversions(m_conversions, m_conversions.conversion_saves()); + const Type_Conversions_State convs(m_conversions, m_conversions.conversion_saves()); - return Boxed_Value(f->call_match(std::vector(params.begin() + 1, params.end()), conversions)); + return Boxed_Value(f->call_match(std::vector(params.begin() + 1, params.end()), convs)); } /// Dump all system info to stdout diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index f0c42be..f3aa069 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -371,7 +371,7 @@ namespace chaiscript // m_engine.add(fun( - [=](const dispatch::Proxy_Function_Base &t_fun, const std::vector &t_params) { + [=](const dispatch::Proxy_Function_Base &t_fun, const std::vector &t_params) -> Boxed_Value { Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves()); return t_fun(t_params, s); }), "call"); From 6c483bd6f632c08442bbc80f4d409c05edc23bfa Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 16 Feb 2016 15:00:13 -0700 Subject: [PATCH 131/131] Update release notes and prepare for 5.8.0 --- CMakeLists.txt | 4 ++-- include/chaiscript/chaiscript_defines.hpp | 4 ++-- releasenotes.md | 25 ++++++++++++++++++++++- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e064455..50b5e3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,8 +102,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 7) -set(CPACK_PACKAGE_VERSION_PATCH 2) +set(CPACK_PACKAGE_VERSION_MINOR 8) +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 941ba87..8d250eb 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -96,8 +96,8 @@ namespace chaiscript { static const int version_major = 5; - static const int version_minor = 7; - static const int version_patch = 2; + static const int version_minor = 8; + static const int version_patch = 0; static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION; static const char *compiler_name = CHAISCRIPT_COMPILER_NAME; diff --git a/releasenotes.md b/releasenotes.md index c78376d..993f93d 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,6 +1,29 @@ Notes: ======= -Current Version: 5.7.1 +Current Version: 5.8.0 + +### Changes since 5.7.1 +* Make all parser iterator operations range checked +* Parse in-string eval statements once, not once for each execution +* Fix parsing of operators (ie 1<-1 now parses) +* Fix variable scoping for functors +* Exception reduction +* Various object lifetime fixes +* Add JSON support for load / save #207 +* Numeric overload resolution fixes #209 +* Fix long long #208 +* Add octal escapes in strings #211 +* Fixed sizing of binary literals #213 +* Added support for != with bool values #217 +* Various value assignment vector fixes +* Fixed broken hex escape sequences from @ChristianKaeser +* Multiply defined symbols fixes #232 @RaptorFactor +* Add add_class helper #233 @vrennert +* Cheatsheet fixes #235 @mlamby +* Fix parsing of strings inside of in-string eval statements +* Allow lower-case global keyword +* Enable thread-local on MSVC (should be significant performance boost) + ### Changes since 5.7.0 * Build time reduction