Merge branch 'develop' into typed_function_ordering
This commit is contained in:
@@ -30,4 +30,8 @@ compilers:
|
||||
collect_performance_results: true
|
||||
- name: cppcheck
|
||||
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*" --suppress="*:unittests/catch.hpp" --force
|
||||
- name: custom_check
|
||||
commands:
|
||||
- ./contrib/check_for_tabs.rb
|
||||
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
```
|
||||
chai.add(chaiscript::user_type<MyClass>, "MyClass");
|
||||
chai.add(chaiscript::user_type<MyClass>(), "MyClass");
|
||||
```
|
||||
|
||||
## Adding Type Conversions
|
||||
@@ -365,6 +365,7 @@ class My_Class {
|
||||
this.x = 2; // this would fail with explicit set to true
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## method_missing
|
||||
|
||||
|
11
contrib/check_for_tabs.rb
Executable file
11
contrib/check_for_tabs.rb
Executable 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
|
||||
}
|
||||
|
||||
|
@@ -33,14 +33,14 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
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 *)
|
||||
{
|
||||
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<const Result *>(p));
|
||||
return *static_cast<const Result *>(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<typename Result>
|
||||
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a const * type
|
||||
template<typename Result>
|
||||
@@ -68,7 +62,7 @@ namespace chaiscript
|
||||
{
|
||||
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 {
|
||||
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))
|
||||
{
|
||||
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 {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
@@ -83,12 +83,12 @@ namespace chaiscript
|
||||
&& (*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_reference() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_reference_flag)); }
|
||||
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_void_flag)); }
|
||||
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_arithmetic_flag)); }
|
||||
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_undef_flag)); }
|
||||
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return bool(m_flags & (1 << is_pointer_flag)); }
|
||||
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 (m_flags & (1 << is_reference_flag)) != 0; }
|
||||
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 (m_flags & (1 << is_arithmetic_flag)) != 0; }
|
||||
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 (m_flags & (1 << is_pointer_flag)) != 0; }
|
||||
|
||||
std::string name() const
|
||||
{
|
||||
|
@@ -961,6 +961,40 @@ 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);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
if (t_char == '\\') {
|
||||
if (is_escaped) {
|
||||
match.push_back('\\');
|
||||
@@ -970,31 +1004,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') {
|
||||
|
@@ -421,22 +421,22 @@ class JSON
|
||||
Class Type;
|
||||
};
|
||||
|
||||
JSON Array() {
|
||||
inline JSON Array() {
|
||||
return JSON::Make( JSON::Class::Array );
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
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;
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
|
@@ -8,12 +8,14 @@
|
||||
#define CHAISCRIPT_UTILITY_UTILITY_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../chaiscript.hpp"
|
||||
#include "../dispatchkit/proxy_functions.hpp"
|
||||
#include "../dispatchkit/type_info.hpp"
|
||||
#include "../dispatchkit/operators.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
@@ -62,6 +64,32 @@ namespace chaiscript
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -13,9 +13,9 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass)
|
||||
try {
|
||||
To ret = chaiscript::boxed_cast<To>(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;
|
||||
|
@@ -2,6 +2,7 @@
|
||||
// caught in other cpp files if chaiscript causes them
|
||||
|
||||
#include <chaiscript/utility/utility.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#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
|
||||
|
||||
class Object_Copy_Count_Test
|
||||
@@ -804,3 +864,54 @@ TEST_CASE("Test long long dispatch")
|
||||
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");
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
|
||||
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")
|
||||
|
||||
|
@@ -1,29 +1,41 @@
|
||||
assert_equal([true, false, true], map([1,2,3], odd))
|
||||
// Map function
|
||||
|
||||
{
|
||||
assert_equal([true, false, true], map([1,2,3], odd))
|
||||
|
||||
var v = [1, 2, 3];
|
||||
var y = map(v, fun(s) { s*2; });
|
||||
y[0] = 1;
|
||||
assert_equal(1, y[0]);
|
||||
}
|
||||
|
||||
|
||||
// Map objects
|
||||
|
||||
var m = ["a":1, "b":2];
|
||||
{
|
||||
var m = ["a":1, "b":2];
|
||||
|
||||
assert_equal(1, m.count("a"))
|
||||
assert_equal(0, m.count("c"))
|
||||
assert_equal(1, m.erase("a"))
|
||||
assert_equal(1, m.size())
|
||||
assert_equal(0, m.erase("a"))
|
||||
assert_equal(1, m.count("a"))
|
||||
assert_equal(0, m.count("c"))
|
||||
assert_equal(1, m.erase("a"))
|
||||
assert_equal(1, m.size())
|
||||
assert_equal(0, m.erase("a"))
|
||||
|
||||
assert_equal(1, m.size());
|
||||
assert_equal(1, m.size());
|
||||
|
||||
var m2 = ["c":3, "b":4]
|
||||
m.insert(m2);
|
||||
var m2 = ["c":3, "b":4]
|
||||
m.insert(m2);
|
||||
|
||||
assert_equal(3, m["c"])
|
||||
// The inserted values do not overwrite the existing ones
|
||||
assert_equal(2, m["b"])
|
||||
assert_equal(2, m.size())
|
||||
assert_equal(3, m["c"])
|
||||
// The inserted values do not overwrite the existing ones
|
||||
assert_equal(2, m["b"])
|
||||
assert_equal(2, m.size())
|
||||
|
||||
var v = "bob";
|
||||
var v = "bob";
|
||||
|
||||
m.insert_ref(Map_Pair("d", v))
|
||||
m.insert_ref(Map_Pair("d", v))
|
||||
|
||||
assert_equal("bob", m["d"])
|
||||
v = "bob2"
|
||||
assert_equal("bob2", m["d"])
|
||||
assert_equal("bob", m["d"])
|
||||
v = "bob2"
|
||||
assert_equal("bob2", m["d"])
|
||||
}
|
||||
|
@@ -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")
|
||||
|
||||
|
Reference in New Issue
Block a user