From 9a0a12d230fb6a8d9a4e2f037c43ba581a531836 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 20 Jul 2015 19:49:45 -0600 Subject: [PATCH 01/89] 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 59c33a36..58841b75 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 5b3bea5b..c28e9a56 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 02/89] 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 c14a156a..0478452a 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 ddc484fb..4ba2f541 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 03/89] 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 04/89] 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 4ba2f541..089ed7f5 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 05/89] 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 3a46c96c..259946f1 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 0478452a..b3cc017e 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 06/89] 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 00000000..c07ce798 --- /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 07/89] 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 b3cc017e..05973859 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 08/89] 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 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 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 09/89] 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 089ed7f5..a2fd4b11 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 10/89] 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 9954eeab..cc1b2e70 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 3c8e3c53..5692e34e 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 11/89] 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 00000000..59d23149 --- /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 12/89] 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 a2fd4b11..6aef0502 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 13/89] 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 c856e9aa..9e344ccd 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 14/89] 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 00000000..371d7f1b --- /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 15/89] Add exceptions test to cmakelist --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58841b75..2380e06d 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 16/89] 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 1624e023..0f575288 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 1eee0602..156831f7 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 0fe2a5a6..acb8407f 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 17/89] 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 8f478bf4..0e8870d3 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 371d7f1b..ba97f7a7 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 18/89] 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 0e8870d3..d8df9be8 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 19/89] 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 0f575288..25f9f432 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 a6a604ab..70802772 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 00000000..05c2014e --- /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 20/89] 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 a6a604ab..9fbdd4c2 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 21/89] 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 05973859..12b0ea97 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 22/89] 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 9d501aed..f1e20a1d 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 23/89] 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 9e344ccd..9d1df58d 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 24/89] 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 12b0ea97..5581fc16 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 25/89] 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 43cb7b12..45578703 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 5581fc16..53d8e416 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 26/89] 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 19d17e13..5a058fc8 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 fe318216..b07c2734 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 eea34b78..176e1cec 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 27/89] 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 25f9f432..d81edd5e 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 1a03888f..2504f007 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 28/89] 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 00000000..8b7d484d --- /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 29/89] 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 8b7d484d..011f9a19 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 53d8e416..6f28008d 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 30/89] 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 45578703..3ded2df6 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 31/89] 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 3ded2df6..14571cf4 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 32/89] 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 14571cf4..b1cef9a6 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 6f28008d..f6fde402 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 33/89] 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 b1cef9a6..47988764 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 34/89] 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 d81edd5e..0cd7bab2 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 a6d9c5b1..ae213822 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 35/89] 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 c28e9a56..5c54051e 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 47988764..de2caa04 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 36/89] 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 c07e64c6..4b38f2cd 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 5a9ccaa7..9ea827c9 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 00000000..dbdf8863 --- /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 00000000..55c32fe5 --- /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 37/89] 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 dbdf8863..9b1c6592 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 38/89] 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 c953886e..07a1103d 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 9b1c6592..ef3fd343 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 55c32fe5..cf843f06 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 39/89] 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 cf843f06..b7e3ca1e 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 40/89] 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 5692e34e..c5b950a1 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 ef3fd343..82a1dac8 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 b7e3ca1e..1b0631d3 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 41/89] 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 9d1df58d..da7eb7c4 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 42/89] 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 c953886e..8c5440ec 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 43/89] 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 2504f007..186ccbac 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 44/89] 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 82a1dac8..e8cae197 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 00000000..63277b3b --- /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 00000000..f19c7cfb --- /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 00000000..f11db384 --- /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 00000000..a93211d3 --- /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 00000000..3f9fa009 --- /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 00000000..0f779bdd --- /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 00000000..d3f222e4 --- /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 00000000..22d388c7 --- /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 00000000..9ad2ca21 --- /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 00000000..8c33bff3 --- /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 00000000..b2c6efa8 --- /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 00000000..104c8bc4 --- /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 00000000..15127387 --- /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 45/89] 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 00000000..90b81cdb --- /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 00000000..832d984d --- /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 46/89] 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 de2caa04..806abae1 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 156831f7..d9da2e61 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 47/89] 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 00000000..94682e5f --- /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 48/89] 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 6aef0502..9e075eeb 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 49/89] 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 2380e06d..07ae809a 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 9e075eeb..ebb8bfcd 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 e8cae197..e5ba4f7b 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 50/89] 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 ebb8bfcd..bd902f12 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 00000000..283ef87e --- /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 00000000..83b53928 --- /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 51/89] 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 bd902f12..ddc21115 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 e5ba4f7b..893f7bf3 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 1b0631d3..d15528ff 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 52/89] 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 0cd7bab2..ef5a94b3 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 ddc21115..a05129ae 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 ecaff8a1..9a02c201 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 99ac03fc..b8fd1f58 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 53/89] 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 a05129ae..c995f7d3 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 54/89] 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 c995f7d3..f582ab1b 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 9a02c201..58e954a9 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 55/89] 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 f582ab1b..57387d30 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 56/89] 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 57387d30..11a2d04c 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 57/89] 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 07ae809a..417f74a6 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 00000000..ac8eb476 --- /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 58/89] 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 f6fde402..aa01de96 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 11a2d04c..d012e268 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 00000000..5082ab61 --- /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 59/89] 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 00000000..f3abc040 --- /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 60/89] 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 ef5a94b3..7e0fd6b8 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 ae213822..1c2ebe72 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 806abae1..305de996 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 acb8407f..55514bba 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 f3abc040..8646105b 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 61/89] 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 00000000..61d4b580 --- /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 62/89] 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 7e0fd6b8..c063ca82 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 186ccbac..8b559811 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 63/89] 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 00000000..6fdea7a1 --- /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 64/89] 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 c063ca82..ac8c5dc1 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 65/89] 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 07ae809a..0b67b72f 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 66/89] 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 00000000..b26b6100 --- /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 67/89] 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 ac8c5dc1..7e3a3015 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 9ea827c9..7df1abf4 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 b26b6100..b37dc0fb 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 68/89] 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 9ff4ad4b..841cb924 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 305de996..aa094867 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 7df1abf4..eaabf9bd 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 d9da2e61..6214b4dd 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 69/89] 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 24990bd8..246241a7 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 eaabf9bd..1e79eeab 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 d012e268..a9b93115 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 70/89] 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 ba97f7a7..36bbb756 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 71/89] 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 0d5c5f38..105440b1 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 72/89] 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 5c54051e..c2ba4ae6 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 a9b93115..37b717f8 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 73/89] 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 105440b1..5be3a2ef 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 d9f86a96f035676018b9f3c4bc396015d0c7382c Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 3 Nov 2015 15:59:43 -0700 Subject: [PATCH 74/89] 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 9d1df58d..ce3bcf96 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 75/89] 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 d8df9be8..bb6835d9 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 76/89] 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 37b717f8..e50046d2 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 283ef87e..14ec62ed 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 83b53928..a220d578 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 77/89] 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 e50046d2..6548521d 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 14ec62ed..fdd0a8a6 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 78/89] 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 bb6835d9..c72edb79 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 e5756492..1e928749 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 79/89] 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 c72edb79..2e087776 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 80/89] 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 893f7bf3..80b05301 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 81/89] 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 80b05301..c023c2bf 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 82/89] 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 ecd5a3f0..27049297 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 83/89] 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 da7eb7c4..90095acc 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 84/89] 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 90095acc..ca5e9ec5 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 85/89] 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 27049297..4dfd079d 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 86/89] 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 4dfd079d..05c49c59 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 ca5e9ec5..a028526e 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 87/89] 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 05c49c59..381afda2 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 a028526e..6724973f 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 88/89] Fix formatting error in cheatsheet.md --- cheatsheet.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cheatsheet.md b/cheatsheet.md index 841cb924..5e785535 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 89/89] 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 6724973f..27829049 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"));