From 34c6b1721569ac23024ec648253b1352cda41aac Mon Sep 17 00:00:00 2001 From: Christian Kaeser Date: Sun, 8 Nov 2015 11:39:48 +0100 Subject: [PATCH 01/11] Fix broken escape sequence parsing after octal/hex escape The parser code just added the first character after an octal/hex sequence as raw text, resulting in erroneous data whenever another escape sequence follows directly after. --- .../chaiscript/language/chaiscript_parser.hpp | 52 ++++++++++--------- unittests/hex_escapes.chai | 1 + unittests/octal_escapes.chai | 1 + 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 37b717f..e50046d 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -961,6 +961,32 @@ namespace chaiscript } void parse(const char_type t_char, const int line, const int col, const std::string &filename) { + const bool is_octal_char = t_char >= '0' && t_char <= '7'; + + if (is_octal) { + if (is_octal_char) { + octal_matches.push_back(t_char); + + if (octal_matches.size() == 3) { + process_octal(); + } + return; + } else { + process_octal(); + } + } else if (is_hex) { + const bool is_hex_char = (t_char >= '0' && t_char <= '9') + || (t_char >= 'a' && t_char <= 'f') + || (t_char >= 'A' && t_char <= 'F'); + + if (is_hex_char) { + hex_matches.push_back(t_char); + return; + } else { + process_hex(); + } + } + if (t_char == '\\') { if (is_escaped) { match.push_back('\\'); @@ -970,31 +996,7 @@ namespace chaiscript } } else { if (is_escaped) { - const bool is_octal_char = t_char >= '0' && t_char <= '7'; - - if (is_octal) { - if (is_octal_char) { - octal_matches.push_back(t_char); - - if (octal_matches.size() == 3) { - process_octal(); - } - } else { - process_octal(); - match.push_back(t_char); - } - } else if (is_hex) { - const bool is_hex_char = (t_char >= '0' && t_char <= '9') - || (t_char >= 'a' && t_char <= 'f') - || (t_char >= 'A' && t_char <= 'F'); - - if (is_hex_char) { - hex_matches.push_back(t_char); - } else { - process_hex(); - match.push_back(t_char); - } - } else if (is_octal_char) { + if (is_octal_char) { is_octal = true; octal_matches.push_back(t_char); } else if (t_char == 'x') { diff --git a/unittests/hex_escapes.chai b/unittests/hex_escapes.chai index 283ef87..14ec62e 100644 --- a/unittests/hex_escapes.chai +++ b/unittests/hex_escapes.chai @@ -3,4 +3,5 @@ assert_equal("\x39", "9") assert_equal("\x039", "9") assert_equal("\x39g", "9g") assert_equal("b\x39g", "b9g") +assert_equal("\x39\x38g", "98g") diff --git a/unittests/octal_escapes.chai b/unittests/octal_escapes.chai index 83b5392..a220d57 100644 --- a/unittests/octal_escapes.chai +++ b/unittests/octal_escapes.chai @@ -3,4 +3,5 @@ assert_equal("\71", "9") assert_equal("\071", "9") assert_equal("\71a", "9a") assert_equal("b\71a", "b9a") +assert_equal("\71\70a", "98a") From 202204a82ac2160780e12a51ffa6b1357b3dea35 Mon Sep 17 00:00:00 2001 From: Christian Kaeser Date: Sun, 8 Nov 2015 18:36:16 +0100 Subject: [PATCH 02/11] Limit hexadecimal escape sequence length Helps with cases like "\xFFecho" by limiting the number of hex digits that will be parsed to maximum suitable for the char type. This rule differs from the C/C++ standard, but ChaiScript does not offer the same workaround options. Furthermore, without it having hexadecimal sequences longer than can fit into the char type is undefined behavior anyway. --- include/chaiscript/language/chaiscript_parser.hpp | 8 ++++++++ unittests/hex_escapes.chai | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index e50046d..6548521 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -981,6 +981,14 @@ namespace chaiscript if (is_hex_char) { hex_matches.push_back(t_char); + + if (hex_matches.size() == 2*sizeof(char_type)) { + // This rule differs from the C/C++ standard, but ChaiScript + // does not offer the same workaround options, and having + // hexadecimal sequences longer than can fit into the char + // type is undefined behavior anyway. + process_hex(); + } return; } else { process_hex(); diff --git a/unittests/hex_escapes.chai b/unittests/hex_escapes.chai index 14ec62e..fdd0a8a 100644 --- a/unittests/hex_escapes.chai +++ b/unittests/hex_escapes.chai @@ -1,6 +1,6 @@ assert_equal("\x39", "9") -assert_equal("\x039", "9") +assert_equal("\x39ec", "9ec") assert_equal("\x39g", "9g") assert_equal("b\x39g", "b9g") assert_equal("\x39\x38g", "98g") From c249bef27df531a7d8791d91fbfdebf39d31c4ab Mon Sep 17 00:00:00 2001 From: Joshua Boyce Date: Sat, 26 Dec 2015 03:03:24 -0800 Subject: [PATCH 03/11] Fix multiply defined symbols. --- include/chaiscript/utility/json.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index 893f7bf..80b0530 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -421,22 +421,22 @@ class JSON Class Type; }; -JSON Array() { +inline JSON Array() { return JSON::Make( JSON::Class::Array ); } template -JSON Array( T... args ) { +inline JSON Array( T... args ) { JSON arr = JSON::Make( JSON::Class::Array ); arr.append( args... ); return arr; } -JSON Object() { +inline JSON Object() { return JSON::Make( JSON::Class::Object ); } -std::ostream& operator<<( std::ostream &os, const JSON &json ) { +inline std::ostream& operator<<( std::ostream &os, const JSON &json ) { os << json.dump(); return os; } From e60eabbeb289455e00aa3d553c429ee73f17c8a2 Mon Sep 17 00:00:00 2001 From: Joshua Boyce Date: Sat, 26 Dec 2015 03:04:05 -0800 Subject: [PATCH 04/11] Fix another multiply defined symbol. --- include/chaiscript/utility/json.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index 80b0530..c023c2b 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -636,7 +636,7 @@ namespace { } } -JSON JSON::Load( const string &str ) { +inline JSON JSON::Load( const string &str ) { size_t offset = 0; return parse_next( str, offset ); } From f0796b51c8541319378bfa53e180b9ab73be14be Mon Sep 17 00:00:00 2001 From: Viktor Rennert Date: Sat, 2 Jan 2016 14:17:36 +0100 Subject: [PATCH 05/11] Added template specialization in chaiscript::utility::add_class to register bulk constants. --- include/chaiscript/utility/utility.hpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index ecd5a3f..2704929 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -8,6 +8,7 @@ #define CHAISCRIPT_UTILITY_UTILITY_HPP_ #include +#include #include #include @@ -62,6 +63,21 @@ namespace chaiscript t_module.add(fun.first, fun.second); } } + + template + typename std::enable_if::value, void>::type + add_class(ModuleType &t_module, + const std::string &t_class_name, + const std::vector &t_constructors, + const std::vector> &t_constants) + { + t_module.add(chaiscript::user_type(), t_class_name); + + for (const auto &constant : t_constants) + { + t_module.add_global_const(constant.first, constant.second); + } + } } } From 316ba45e3c9fa72ff781011a770748fc53f20ec6 Mon Sep 17 00:00:00 2001 From: Viktor Rennert Date: Sat, 2 Jan 2016 20:54:55 +0100 Subject: [PATCH 06/11] Added unittest to cover utility::add_class registration. --- unittests/compiled_tests.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index da7eb7c..90095ac 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -517,6 +517,41 @@ TEST_CASE("Utility_Test utility class wrapper") } +enum Utility_Test_Numbers +{ + ONE, + TWO, + THREE +}; + +TEST_CASE("Utility_Test utility class wrapper") +{ + + chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module()); + + using namespace chaiscript; + + chaiscript::utility::add_class(*m, + "Utility_Test_Numbers", + { + }, + { { const_var(ONE), "ONE" }, + { const_var(TWO), "TWO" }, + { const_var(THREE), "THREE" } + + } + ); + + + chaiscript::ChaiScript chai; + chai.add(m); + + CHECK(chai.eval("ONE ") == 0); + CHECK(chai.eval("TWO ") == 1); + CHECK(chai.eval("THREE ") == 2); + +} + ////// Object copy count test From d7489358f3b14d580f27bb9fc0bc674dd53318f1 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 2 Jan 2016 19:24:14 -0700 Subject: [PATCH 07/11] Add failing test for vector of enum values --- unittests/compiled_tests.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 90095ac..ca5e9ec 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -2,6 +2,7 @@ // caught in other cpp files if chaiscript causes them #include +#include #ifdef CHAISCRIPT_MSVC #pragma warning(push) @@ -517,14 +518,19 @@ TEST_CASE("Utility_Test utility class wrapper") } + enum Utility_Test_Numbers { - ONE, + ONE, TWO, THREE }; -TEST_CASE("Utility_Test utility class wrapper") +void do_something_with_enum_vector(const std::vector &) +{ +} + +TEST_CASE("Utility_Test utility class wrapper for enum") { chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module()); @@ -538,7 +544,7 @@ TEST_CASE("Utility_Test utility class wrapper") { { const_var(ONE), "ONE" }, { const_var(TWO), "TWO" }, { const_var(THREE), "THREE" } - + } ); @@ -550,6 +556,12 @@ TEST_CASE("Utility_Test utility class wrapper") CHECK(chai.eval("TWO ") == 1); CHECK(chai.eval("THREE ") == 2); + chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector"); + chai.add(chaiscript::vector_conversion>()); + CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]")); + CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE])")); + CHECK_NOTHROW(chai.eval("[ONE]")); + } From e1c40f3e8f586abc5e88cf55e90fa28fb2428b50 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 2 Jan 2016 19:26:53 -0700 Subject: [PATCH 08/11] Automatically add copy constuctor for enums added with utility --- include/chaiscript/utility/utility.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index 2704929..4dfd079 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -72,7 +72,10 @@ namespace chaiscript const std::vector> &t_constants) { t_module.add(chaiscript::user_type(), t_class_name); - + + t_module.add(chaiscript::constructor(), t_class_name); + t_module.add(chaiscript::constructor(), t_class_name); + for (const auto &constant : t_constants) { t_module.add_global_const(constant.first, constant.second); From e32714c456236327269d6e46dfb10c67fa4280f3 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 2 Jan 2016 19:45:10 -0700 Subject: [PATCH 09/11] Add some operators for Enums made with helper class --- include/chaiscript/utility/utility.hpp | 9 ++++++++- unittests/compiled_tests.cpp | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index 4dfd079..05c49c5 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -15,6 +15,7 @@ #include "../chaiscript.hpp" #include "../dispatchkit/proxy_functions.hpp" #include "../dispatchkit/type_info.hpp" +#include "../dispatchkit/operators.hpp" namespace chaiscript @@ -63,7 +64,7 @@ namespace chaiscript t_module.add(fun.first, fun.second); } } - + template typename std::enable_if::value, void>::type add_class(ModuleType &t_module, @@ -76,6 +77,12 @@ namespace chaiscript t_module.add(chaiscript::constructor(), t_class_name); t_module.add(chaiscript::constructor(), t_class_name); + t_module.add([](){ + // add some comparison and assignment operators + using namespace chaiscript::bootstrap::operators; + return assign(not_equal(equal())); + }()); + for (const auto &constant : t_constants) { t_module.add_global_const(constant.first, constant.second); diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index ca5e9ec..a028526 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -562,6 +562,11 @@ TEST_CASE("Utility_Test utility class wrapper for enum") CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE])")); CHECK_NOTHROW(chai.eval("[ONE]")); + CHECK(chai.eval("ONE == ONE")); + CHECK(chai.eval("ONE != TWO")); + CHECK_NOTHROW(chai.eval("var o = ONE; o = TWO")); + + } From 888d897a3eda962e6b765085bb40d115b05a3491 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 2 Jan 2016 19:59:54 -0700 Subject: [PATCH 10/11] Simplify use of enum helper --- include/chaiscript/utility/utility.hpp | 8 +++++--- unittests/compiled_tests.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index 05c49c5..381afda 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -69,8 +69,7 @@ namespace chaiscript typename std::enable_if::value, void>::type add_class(ModuleType &t_module, const std::string &t_class_name, - const std::vector &t_constructors, - const std::vector> &t_constants) + const std::vector::type, std::string>> &t_constants) { t_module.add(chaiscript::user_type(), t_class_name); @@ -83,9 +82,12 @@ namespace chaiscript return assign(not_equal(equal())); }()); + t_module.add(chaiscript::fun([](const Enum &e, const typename std::underlying_type::type &i) { return e == i; }), "=="); + t_module.add(chaiscript::fun([](const typename std::underlying_type::type &i, const Enum &e) { return i == e; }), "=="); + for (const auto &constant : t_constants) { - t_module.add_global_const(constant.first, constant.second); + t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second); } } } diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index a028526..6724973 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -539,11 +539,9 @@ TEST_CASE("Utility_Test utility class wrapper for enum") chaiscript::utility::add_class(*m, "Utility_Test_Numbers", - { - }, - { { const_var(ONE), "ONE" }, - { const_var(TWO), "TWO" }, - { const_var(THREE), "THREE" } + { { ONE, "ONE" }, + { TWO, "TWO" }, + { THREE, "THREE" } } ); @@ -556,6 +554,8 @@ TEST_CASE("Utility_Test utility class wrapper for enum") CHECK(chai.eval("TWO ") == 1); CHECK(chai.eval("THREE ") == 2); + CHECK(chai.eval("ONE == 0")); + chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector"); chai.add(chaiscript::vector_conversion>()); CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]")); From 208107fd7ecb5c898e301e5d3a985b681bd7db20 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 3 Jan 2016 17:58:05 -0700 Subject: [PATCH 11/11] Add additional tests for vector conversion --- unittests/compiled_tests.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 6724973..2782904 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -526,8 +526,12 @@ enum Utility_Test_Numbers THREE }; -void do_something_with_enum_vector(const std::vector &) +void do_something_with_enum_vector(const std::vector &v) { + CHECK(v.size() == 3); + CHECK(v[0] == ONE); + CHECK(v[1] == THREE); + CHECK(v[2] == TWO); } TEST_CASE("Utility_Test utility class wrapper for enum") @@ -559,9 +563,13 @@ TEST_CASE("Utility_Test utility class wrapper for enum") chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector"); chai.add(chaiscript::vector_conversion>()); CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]")); - CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE])")); + CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE, THREE, TWO])")); CHECK_NOTHROW(chai.eval("[ONE]")); + const auto v = chai.eval>("a"); + CHECK(v.size() == 3); + CHECK(v.at(1) == TWO); + CHECK(chai.eval("ONE == ONE")); CHECK(chai.eval("ONE != TWO")); CHECK_NOTHROW(chai.eval("var o = ONE; o = TWO"));