Merge branch 'develop' into typed_function_ordering

This commit is contained in:
Jason Turner
2016-01-20 18:28:28 -07:00
13 changed files with 271 additions and 69 deletions

View File

@@ -30,4 +30,8 @@ compilers:
collect_performance_results: true collect_performance_results: true
- name: cppcheck - name: cppcheck
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*" --suppress="*:unittests/catch.hpp" --force compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*" --suppress="*:unittests/catch.hpp" --force
- name: custom_check
commands:
- ./contrib/check_for_tabs.rb

View File

@@ -77,7 +77,7 @@ chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc. It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
``` ```
chai.add(chaiscript::user_type<MyClass>, "MyClass"); chai.add(chaiscript::user_type<MyClass>(), "MyClass");
``` ```
## Adding Type Conversions ## Adding Type Conversions
@@ -365,6 +365,7 @@ class My_Class {
this.x = 2; // this would fail with explicit set to true this.x = 2; // this would fail with explicit set to true
} }
}; };
```
## method_missing ## method_missing

11
contrib/check_for_tabs.rb Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/env ruby
require 'json'
`grep -rPIHn '\t' src/* include/* samples/*`.lines { |line|
if /(?<filename>.+(hpp|cpp|chai)):(?<linenumber>[0-9]+):(?<restofline>.+)/ =~ line
puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "tab_checker", :message => "Source Code Line Contains Tabs", :messagetype => "warning"}))
end
}

View File

@@ -33,14 +33,14 @@ namespace chaiscript
template<typename Result> template<typename Result>
struct Cast_Helper_Inner struct Cast_Helper_Inner
{ {
typedef std::reference_wrapper<typename std::add_const<Result>::type > Result_Type; typedef typename std::add_const<Result>::type Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
if (ob.get_type_info().bare_equal_type_info(typeid(Result))) if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{ {
auto p = throw_if_null(ob.get_const_ptr()); auto p = throw_if_null(ob.get_const_ptr());
return std::cref(*static_cast<const Result *>(p)); return *static_cast<const Result *>(p);
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
@@ -52,12 +52,6 @@ namespace chaiscript
{ {
}; };
/// Cast_Helper_Inner for casting to a const & type
template<typename Result>
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
{
};
/// Cast_Helper_Inner for casting to a const * type /// Cast_Helper_Inner for casting to a const * type
template<typename Result> template<typename Result>
@@ -68,7 +62,7 @@ namespace chaiscript
{ {
if (ob.get_type_info().bare_equal_type_info(typeid(Result))) if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{ {
return static_cast<const Result *>(throw_if_null(ob.get_const_ptr())); return static_cast<const Result *>(ob.get_const_ptr());
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
@@ -84,7 +78,36 @@ namespace chaiscript
{ {
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result)) if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
{ {
return static_cast<Result *>(throw_if_null(ob.get_ptr())); return static_cast<Result *>(ob.get_ptr());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
};
template<typename Result>
struct Cast_Helper_Inner<Result * const &> : public Cast_Helper_Inner<Result *>
{
};
template<typename Result>
struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const Result *>
{
};
/// Cast_Helper_Inner for casting to a & type
template<typename Result>
struct Cast_Helper_Inner<const Result &>
{
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<const Result *>(p);
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }

View File

@@ -83,12 +83,12 @@ namespace chaiscript
&& (*m_bare_type_info) == ti; && (*m_bare_type_info) == ti;
} }
CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_const_flag)); } CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_const_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_reference_flag)); } CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_reference_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_void_flag)); } CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_void_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_arithmetic_flag)); } CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_arithmetic_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_undef_flag)); } CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_undef_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_pointer_flag)); } CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_pointer_flag)) != 0; }
std::string name() const std::string name() const
{ {

View File

@@ -961,15 +961,6 @@ namespace chaiscript
} }
void parse(const char_type 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('\\');
is_escaped = false;
} else {
is_escaped = true;
}
} else {
if (is_escaped) {
const 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) {
@@ -979,9 +970,9 @@ namespace chaiscript
if (octal_matches.size() == 3) { if (octal_matches.size() == 3) {
process_octal(); process_octal();
} }
return;
} else { } else {
process_octal(); process_octal();
match.push_back(t_char);
} }
} else if (is_hex) { } else if (is_hex) {
const bool is_hex_char = (t_char >= '0' && t_char <= '9') const bool is_hex_char = (t_char >= '0' && t_char <= '9')
@@ -990,11 +981,30 @@ namespace chaiscript
if (is_hex_char) { if (is_hex_char) {
hex_matches.push_back(t_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 { } else {
process_hex(); process_hex();
match.push_back(t_char);
} }
} else if (is_octal_char) { }
if (t_char == '\\') {
if (is_escaped) {
match.push_back('\\');
is_escaped = false;
} else {
is_escaped = true;
}
} else {
if (is_escaped) {
if (is_octal_char) {
is_octal = true; is_octal = true;
octal_matches.push_back(t_char); octal_matches.push_back(t_char);
} else if (t_char == 'x') { } else if (t_char == 'x') {

View File

@@ -421,22 +421,22 @@ class JSON
Class Type; Class Type;
}; };
JSON Array() { inline JSON Array() {
return JSON::Make( JSON::Class::Array ); return JSON::Make( JSON::Class::Array );
} }
template <typename... T> template <typename... T>
JSON Array( T... args ) { inline JSON Array( T... args ) {
JSON arr = JSON::Make( JSON::Class::Array ); JSON arr = JSON::Make( JSON::Class::Array );
arr.append( args... ); arr.append( args... );
return arr; return arr;
} }
JSON Object() { inline JSON Object() {
return JSON::Make( JSON::Class::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(); os << json.dump();
return os; return os;
} }
@@ -636,7 +636,7 @@ namespace {
} }
} }
JSON JSON::Load( const string &str ) { inline JSON JSON::Load( const string &str ) {
size_t offset = 0; size_t offset = 0;
return parse_next( str, offset ); return parse_next( str, offset );
} }

View File

@@ -8,12 +8,14 @@
#define CHAISCRIPT_UTILITY_UTILITY_HPP_ #define CHAISCRIPT_UTILITY_UTILITY_HPP_
#include <string> #include <string>
#include <type_traits>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "../chaiscript.hpp" #include "../chaiscript.hpp"
#include "../dispatchkit/proxy_functions.hpp" #include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp" #include "../dispatchkit/type_info.hpp"
#include "../dispatchkit/operators.hpp"
namespace chaiscript namespace chaiscript
@@ -62,6 +64,32 @@ namespace chaiscript
t_module.add(fun.first, fun.second); t_module.add(fun.first, fun.second);
} }
} }
template<typename Enum, typename ModuleType>
typename std::enable_if<std::is_enum<Enum>::value, void>::type
add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants)
{
t_module.add(chaiscript::user_type<Enum>(), t_class_name);
t_module.add(chaiscript::constructor<Enum ()>(), t_class_name);
t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name);
t_module.add([](){
// add some comparison and assignment operators
using namespace chaiscript::bootstrap::operators;
return assign<Enum>(not_equal<Enum>(equal<Enum>()));
}());
t_module.add(chaiscript::fun([](const Enum &e, const typename std::underlying_type<Enum>::type &i) { return e == i; }), "==");
t_module.add(chaiscript::fun([](const typename std::underlying_type<Enum>::type &i, const Enum &e) { return i == e; }), "==");
for (const auto &constant : t_constants)
{
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
}
}
} }
} }

View File

@@ -13,9 +13,9 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass)
try { try {
To ret = chaiscript::boxed_cast<To>(bv); To ret = chaiscript::boxed_cast<To>(bv);
use(ret); use(ret);
} catch (const chaiscript::exception::bad_boxed_cast &/*e*/) { } catch (const chaiscript::exception::bad_boxed_cast &e) {
if (expectedpass) { 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; return false;
} else { } else {
return true; return true;

View File

@@ -2,6 +2,7 @@
// caught in other cpp files if chaiscript causes them // caught in other cpp files if chaiscript causes them
#include <chaiscript/utility/utility.hpp> #include <chaiscript/utility/utility.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
@@ -520,6 +521,65 @@ TEST_CASE("Utility_Test utility class wrapper")
} }
enum Utility_Test_Numbers
{
ONE,
TWO,
THREE
};
void do_something_with_enum_vector(const std::vector<Utility_Test_Numbers> &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")
{
chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
using namespace chaiscript;
chaiscript::utility::add_class<Utility_Test_Numbers>(*m,
"Utility_Test_Numbers",
{ { ONE, "ONE" },
{ TWO, "TWO" },
{ THREE, "THREE" }
}
);
chaiscript::ChaiScript chai;
chai.add(m);
CHECK(chai.eval<Utility_Test_Numbers>("ONE ") == 0);
CHECK(chai.eval<Utility_Test_Numbers>("TWO ") == 1);
CHECK(chai.eval<Utility_Test_Numbers>("THREE ") == 2);
CHECK(chai.eval<bool>("ONE == 0"));
chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector");
chai.add(chaiscript::vector_conversion<std::vector<Utility_Test_Numbers>>());
CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]"));
CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE, THREE, TWO])"));
CHECK_NOTHROW(chai.eval("[ONE]"));
const auto v = chai.eval<std::vector<Utility_Test_Numbers>>("a");
CHECK(v.size() == 3);
CHECK(v.at(1) == TWO);
CHECK(chai.eval<bool>("ONE == ONE"));
CHECK(chai.eval<bool>("ONE != TWO"));
CHECK_NOTHROW(chai.eval("var o = ONE; o = TWO"));
}
////// Object copy count test ////// Object copy count test
class Object_Copy_Count_Test class Object_Copy_Count_Test
@@ -804,3 +864,54 @@ TEST_CASE("Test long long dispatch")
chai.eval("ulonglong(15)"); chai.eval("ulonglong(15)");
} }
struct Returned_Converted_Config
{
int num_iterations;
int something_else;
std::string a_string;
std::function<int (const std::string &)> a_function;
};
TEST_CASE("Return of converted type from script")
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::constructor<Returned_Converted_Config ()>(), "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<std::vector<Returned_Converted_Config>>());
auto c = chai.eval<std::vector<Returned_Converted_Config>>(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>(), "Returned_Converted_Config");
}

View File

@@ -1,6 +1,7 @@
assert_equal("\x39", "9") assert_equal("\x39", "9")
assert_equal("\x039", "9") assert_equal("\x39ec", "9ec")
assert_equal("\x39g", "9g") assert_equal("\x39g", "9g")
assert_equal("b\x39g", "b9g") assert_equal("b\x39g", "b9g")
assert_equal("\x39\x38g", "98g")

View File

@@ -1,29 +1,41 @@
assert_equal([true, false, true], map([1,2,3], odd)) // Map function
{
assert_equal([true, false, true], map([1,2,3], odd))
var v = [1, 2, 3];
var y = map(v, fun(s) { s*2; });
y[0] = 1;
assert_equal(1, y[0]);
}
// Map objects
var m = ["a":1, "b":2]; {
var m = ["a":1, "b":2];
assert_equal(1, m.count("a")) assert_equal(1, m.count("a"))
assert_equal(0, m.count("c")) assert_equal(0, m.count("c"))
assert_equal(1, m.erase("a")) assert_equal(1, m.erase("a"))
assert_equal(1, m.size()) assert_equal(1, m.size())
assert_equal(0, m.erase("a")) assert_equal(0, m.erase("a"))
assert_equal(1, m.size()); assert_equal(1, m.size());
var m2 = ["c":3, "b":4] var m2 = ["c":3, "b":4]
m.insert(m2); m.insert(m2);
assert_equal(3, m["c"]) assert_equal(3, m["c"])
// The inserted values do not overwrite the existing ones // The inserted values do not overwrite the existing ones
assert_equal(2, m["b"]) assert_equal(2, m["b"])
assert_equal(2, m.size()) assert_equal(2, m.size())
var v = "bob"; var v = "bob";
m.insert_ref(Map_Pair("d", v)) m.insert_ref(Map_Pair("d", v))
assert_equal("bob", m["d"]) assert_equal("bob", m["d"])
v = "bob2" v = "bob2"
assert_equal("bob2", m["d"]) assert_equal("bob2", m["d"])
}

View File

@@ -3,4 +3,5 @@ assert_equal("\71", "9")
assert_equal("\071", "9") assert_equal("\071", "9")
assert_equal("\71a", "9a") assert_equal("\71a", "9a")
assert_equal("b\71a", "b9a") assert_equal("b\71a", "b9a")
assert_equal("\71\70a", "98a")