Compare commits
72 Commits
v5.7.1
...
Test_Relea
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7ba7b81a5c | ||
![]() |
882cbf2dfb | ||
![]() |
38b98c55cc | ||
![]() |
3a675bf379 | ||
![]() |
985b62705f | ||
![]() |
5aecb7f17b | ||
![]() |
ad69bf7d38 | ||
![]() |
84554ed0a5 | ||
![]() |
36765df3c0 | ||
![]() |
b11ebf9e8f | ||
![]() |
84e2d449b9 | ||
![]() |
64dd349e32 | ||
![]() |
1add4c4b0f | ||
![]() |
14b3870efb | ||
![]() |
d2cf12f948 | ||
![]() |
e221ceaa4c | ||
![]() |
beedf13d01 | ||
![]() |
9d18360333 | ||
![]() |
18e5ee0ba2 | ||
![]() |
41e9027d9a | ||
![]() |
8d9dc2b0a3 | ||
![]() |
6a4647af43 | ||
![]() |
5a651e2b8a | ||
![]() |
d9fa5605ac | ||
![]() |
3a8cb581cc | ||
![]() |
b434d26a5d | ||
![]() |
ba30d4f483 | ||
![]() |
b4ffcd594d | ||
![]() |
ca35128503 | ||
![]() |
681f18ee62 | ||
![]() |
e62a38b39f | ||
![]() |
85ac1052dd | ||
![]() |
8024edeadf | ||
![]() |
f9f1d5807a | ||
![]() |
14227475b2 | ||
![]() |
e1a80fb5ce | ||
![]() |
aabe53c934 | ||
![]() |
f3dbb7ed87 | ||
![]() |
52e11bf001 | ||
![]() |
f06e5cdcd6 | ||
![]() |
15eb78bd8f | ||
![]() |
9f362608b7 | ||
![]() |
e21c8f87b4 | ||
![]() |
0a143d1cd3 | ||
![]() |
08935beaf3 | ||
![]() |
c9625b09b0 | ||
![]() |
800c7fb37b | ||
![]() |
179eaefafe | ||
![]() |
28f5a74e98 | ||
![]() |
781d62d3a5 | ||
![]() |
8ed2158709 | ||
![]() |
8f98e16e5e | ||
![]() |
3a595ef912 | ||
![]() |
5aa0bfcea4 | ||
![]() |
04e2256c92 | ||
![]() |
38ba00e55c | ||
![]() |
8931346230 | ||
![]() |
8bdd2deb19 | ||
![]() |
535055eff8 | ||
![]() |
913d2fd20f | ||
![]() |
0c4951d742 | ||
![]() |
9d17b18f26 | ||
![]() |
31b3195c17 | ||
![]() |
0d4e4090a0 | ||
![]() |
b946af42cc | ||
![]() |
22339d10db | ||
![]() |
b3d2350f33 | ||
![]() |
3cae2aed1d | ||
![]() |
c6f262c675 | ||
![]() |
8239206ec5 | ||
![]() |
a2ff672b34 | ||
![]() |
9a0a12d230 |
@@ -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)
|
||||
@@ -95,7 +102,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")
|
||||
@@ -174,7 +181,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()
|
||||
@@ -253,6 +260,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)
|
||||
|
@@ -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
|
||||
|
26
contrib/codeanalysis/profile_cpp_calls.chai
Normal file
26
contrib/codeanalysis/profile_cpp_calls.chai
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
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);
|
||||
|
||||
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";
|
||||
}
|
@@ -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
|
||||
@@ -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<typename B, typename D, typename ...Arg>
|
||||
inline std::shared_ptr<B> make_shared(Arg && ... arg)
|
||||
|
@@ -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 <future>
|
||||
@@ -51,6 +52,8 @@ namespace chaiscript
|
||||
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &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;
|
||||
|
@@ -440,6 +440,8 @@ namespace chaiscript
|
||||
m->add(constructor<dispatch::Dynamic_Object ()>(), "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<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
||||
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
||||
@@ -450,7 +452,13 @@ namespace chaiscript
|
||||
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
||||
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&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");
|
||||
@@ -460,9 +468,12 @@ 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::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");
|
||||
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>(), "Type_Info");
|
||||
@@ -485,6 +496,7 @@ namespace chaiscript
|
||||
basic_constructors<bool>("bool", m);
|
||||
operators::assign<bool>(m);
|
||||
operators::equal<bool>(m);
|
||||
operators::not_equal<bool>(m);
|
||||
|
||||
m->add(fun([](const std::string &s) -> std::string { return s; }), "to_string");
|
||||
m->add(fun(&Bootstrap::bool_to_string), "to_string");
|
||||
@@ -502,6 +514,8 @@ namespace chaiscript
|
||||
bootstrap_pod_type<long>("long", m);
|
||||
bootstrap_pod_type<unsigned int>("unsigned_int", m);
|
||||
bootstrap_pod_type<unsigned long>("unsigned_long", m);
|
||||
bootstrap_pod_type<long long>("long_long", m);
|
||||
bootstrap_pod_type<unsigned long long>("unsigned_long_long", m);
|
||||
bootstrap_pod_type<size_t>("size_t", m);
|
||||
bootstrap_pod_type<char>("char", m);
|
||||
bootstrap_pod_type<wchar_t>("wchar_t", m);
|
||||
@@ -556,13 +570,14 @@ namespace chaiscript
|
||||
"eval_error",
|
||||
{ },
|
||||
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
|
||||
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
|
||||
std::vector<Boxed_Value> retval;
|
||||
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
|
||||
std::back_inserter(retval),
|
||||
&chaiscript::var<std::shared_ptr<const chaiscript::AST_Node>>);
|
||||
return retval;
|
||||
})), "call_stack"} }
|
||||
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
|
||||
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
|
||||
std::vector<Boxed_Value> retval;
|
||||
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
|
||||
std::back_inserter(retval),
|
||||
&chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>);
|
||||
return retval;
|
||||
})), "call_stack"} }
|
||||
);
|
||||
|
||||
|
||||
@@ -588,7 +603,7 @@ namespace chaiscript
|
||||
std::vector<Boxed_Value> retval;
|
||||
std::transform(t_node.children.begin(), t_node.children.end(),
|
||||
std::back_inserter(retval),
|
||||
&chaiscript::var<std::shared_ptr<chaiscript::AST_Node>>);
|
||||
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
|
||||
return retval;
|
||||
})), "children"},
|
||||
{fun(&AST_Node::replace_child), "replace_child"}
|
||||
|
@@ -334,7 +334,12 @@ 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"
|
||||
" x.reset_var_return_value() \n"
|
||||
" container.push_back_ref(x) \n"
|
||||
" } else { \n"
|
||||
" container.push_back_ref(clone(x)); \n"
|
||||
" }\n"
|
||||
"} \n"
|
||||
);
|
||||
|
||||
@@ -370,7 +375,12 @@ 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"
|
||||
" x.reset_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";
|
||||
@@ -460,6 +470,30 @@ namespace chaiscript
|
||||
m->add(fun(static_cast<elem_access>(&MapType::at)), "at");
|
||||
m->add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
|
||||
|
||||
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>))
|
||||
{
|
||||
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<MapType>(type, m);
|
||||
default_constructible_type<MapType>(type, m);
|
||||
assignable_type<MapType>(type, m);
|
||||
@@ -515,7 +549,7 @@ namespace chaiscript
|
||||
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
|
||||
{
|
||||
m->eval(R"(
|
||||
def Vector::`==`(rhs) : type_match(rhs, this) {
|
||||
def Vector::`==`(Vector rhs) {
|
||||
if ( rhs.size() != this.size() ) {
|
||||
return false;
|
||||
} else {
|
||||
|
@@ -166,7 +166,7 @@ namespace chaiscript
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value>
|
||||
{
|
||||
typedef const Boxed_Value & Result_Type;
|
||||
typedef Boxed_Value Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||
{
|
||||
@@ -178,11 +178,11 @@ namespace chaiscript
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value &>
|
||||
{
|
||||
typedef Boxed_Value& Result_Type;
|
||||
typedef std::reference_wrapper<Boxed_Value> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||
{
|
||||
return const_cast<Boxed_Value &>(ob);
|
||||
return std::ref(const_cast<Boxed_Value &>(ob));
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -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();
|
||||
@@ -120,8 +121,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)) {
|
||||
@@ -513,6 +518,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))) {
|
||||
@@ -537,8 +557,12 @@ namespace chaiscript
|
||||
return Boxed_Number(get_as<unsigned int>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(long))) {
|
||||
return Boxed_Number(get_as<long>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(long long))) {
|
||||
return Boxed_Number(get_as<long long>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(unsigned long))) {
|
||||
return Boxed_Number(get_as<unsigned long>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(unsigned long long))) {
|
||||
return Boxed_Number(get_as<unsigned long long>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(int8_t))) {
|
||||
return Boxed_Number(get_as<int8_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(int16_t))) {
|
||||
|
@@ -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
|
||||
@@ -330,9 +337,9 @@ namespace chaiscript
|
||||
///
|
||||
/// @sa @ref adding_objects
|
||||
template<typename T>
|
||||
Boxed_Value var(T t)
|
||||
Boxed_Value var(T &&t)
|
||||
{
|
||||
return Boxed_Value(t);
|
||||
return Boxed_Value(std::forward<T>(t));
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
@@ -61,6 +61,17 @@ namespace chaiscript {
|
||||
Ret (Class::*m_func)(Param...);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Arity
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Arity<Ret (Params...)>
|
||||
{
|
||||
static const size_t arity = sizeof...(Params);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Function_Signature
|
||||
|
@@ -417,9 +417,9 @@ namespace chaiscript
|
||||
|
||||
struct State
|
||||
{
|
||||
std::map<std::string, std::vector<Proxy_Function> > m_functions;
|
||||
std::map<std::string, Proxy_Function> m_function_objects;
|
||||
std::map<std::string, Boxed_Value> m_boxed_functions;
|
||||
std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> m_functions;
|
||||
std::vector<std::pair<std::string, Proxy_Function>> m_function_objects;
|
||||
std::vector<std::pair<std::string, Boxed_Value>> m_boxed_functions;
|
||||
std::map<std::string, Boxed_Value> m_global_objects;
|
||||
Type_Name_Map m_types;
|
||||
std::set<std::string> m_reserved_words;
|
||||
@@ -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<std::string, Boxed_Value> &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<std::string, Boxed_Value> &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
|
||||
@@ -511,7 +518,7 @@ namespace chaiscript
|
||||
throw chaiscript::exception::global_non_const();
|
||||
}
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
|
||||
{
|
||||
@@ -526,7 +533,7 @@ namespace chaiscript
|
||||
{
|
||||
validate_object_name(name);
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto itr = m_state.m_global_objects.find(name);
|
||||
if (itr == m_state.m_global_objects.end())
|
||||
@@ -544,7 +551,7 @@ namespace chaiscript
|
||||
{
|
||||
validate_object_name(name);
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
|
||||
{
|
||||
@@ -641,19 +648,21 @@ namespace chaiscript
|
||||
return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second;
|
||||
}
|
||||
|
||||
// Is the value we are looking for a global?
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
// Is the value we are looking for a global or function?
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> 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?
|
||||
auto obj = get_function_object_int(name, loc);
|
||||
if (obj.first != loc) t_loc.store(uint_fast32_t(obj.first), std::memory_order_relaxed);
|
||||
return obj.second;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// Registers a new named type
|
||||
@@ -711,20 +720,29 @@ namespace chaiscript
|
||||
return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end());
|
||||
}
|
||||
|
||||
std::shared_ptr<std::vector<Proxy_Function>> 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(uint_fast32_t(method_missing_funs.first), std::memory_order_relaxed);
|
||||
return std::move(method_missing_funs.second);
|
||||
}
|
||||
|
||||
|
||||
/// Return a function by name
|
||||
std::vector< Proxy_Function > get_function(const std::string &t_name) const
|
||||
std::pair<size_t, std::shared_ptr<std::vector< Proxy_Function>>> get_function(const std::string &t_name, const size_t t_hint) const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto &funs = get_functions_int();
|
||||
|
||||
auto itr = funs.find(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::vector<Proxy_Function>();
|
||||
return std::make_pair(size_t(0), std::make_shared<std::vector<Proxy_Function>>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,28 +750,36 @@ 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<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
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
|
||||
std::pair<size_t, Boxed_Value> get_function_object_int(const std::string &t_name, const size_t t_hint) const
|
||||
{
|
||||
const auto &funs = get_boxed_functions_int();
|
||||
|
||||
auto itr = funs.find(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Return true if a function exists
|
||||
bool function_exists(const std::string &name) const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> 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,
|
||||
@@ -810,11 +836,8 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
// add the global values
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
|
||||
retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end());
|
||||
}
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end());
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -851,7 +874,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);
|
||||
}
|
||||
@@ -896,38 +919,54 @@ namespace chaiscript
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4715)
|
||||
#endif
|
||||
Boxed_Value call_member(const std::string &t_name, const std::vector<Boxed_Value> ¶ms, bool t_has_params) const
|
||||
Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> ¶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(uint_fast32_t(funs.first), std::memory_order_relaxed);
|
||||
|
||||
const auto do_attribute_call =
|
||||
[this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions &l_conversions)->Boxed_Value
|
||||
{
|
||||
std::vector<Boxed_Value> attr_params{l_params.begin(), l_params.begin() + l_num_params};
|
||||
std::vector<Boxed_Value> 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<dispatch::Proxy_Function_Base>())) {
|
||||
if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) {
|
||||
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<Dispatch_Engine> m_e;
|
||||
};
|
||||
|
||||
This_Foist fi(*this, l_params.front());
|
||||
|
||||
auto func = boxed_cast<std::shared_ptr<const dispatch::Proxy_Function_Base>>(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<Const_Proxy_Function>{func});
|
||||
throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, std::vector<Const_Proxy_Function>{func});
|
||||
} else {
|
||||
return bv;
|
||||
}
|
||||
};
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -939,7 +978,9 @@ namespace chaiscript
|
||||
const auto functions = [&]()->std::vector<Proxy_Function> {
|
||||
std::vector<Proxy_Function> fs;
|
||||
|
||||
for (const auto &f : 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)) {
|
||||
fs.push_back(f);
|
||||
@@ -961,12 +1002,17 @@ namespace chaiscript
|
||||
}();
|
||||
|
||||
if (!functions.empty()) {
|
||||
if (is_no_param) {
|
||||
std::vector<Boxed_Value> 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<Boxed_Value>(params.begin()+1, params.end()))}, m_conversions);
|
||||
try {
|
||||
if (is_no_param) {
|
||||
std::vector<Boxed_Value> 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<Boxed_Value>(params.begin()+1, params.end()))}, m_conversions);
|
||||
}
|
||||
} catch (const dispatch::option_explicit_set &e) {
|
||||
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.second->begin(), funs.second->end()),
|
||||
e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -975,7 +1021,7 @@ namespace chaiscript
|
||||
if (except) {
|
||||
std::rethrow_exception(except);
|
||||
} else {
|
||||
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.begin(), funs.end()));
|
||||
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.second->begin(), funs.second->end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -985,30 +1031,14 @@ namespace chaiscript
|
||||
|
||||
|
||||
|
||||
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> ¶ms) const
|
||||
Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
Boxed_Value bv = dispatch::dispatch(get_function(t_name), 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();
|
||||
}
|
||||
return bv;
|
||||
uint_fast32_t loc = t_loc.load(std::memory_order_relaxed);
|
||||
const auto funs = get_function(t_name, loc);
|
||||
if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed);
|
||||
return dispatch::dispatch(*funs.second, params, m_conversions);
|
||||
}
|
||||
|
||||
Boxed_Value call_function(const std::string &t_name) const
|
||||
{
|
||||
return call_function(t_name, std::vector<Boxed_Value>());
|
||||
}
|
||||
|
||||
Boxed_Value call_function(const std::string &t_name, Boxed_Value p1) const
|
||||
{
|
||||
return call_function(t_name, std::vector<Boxed_Value>({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<Boxed_Value>({std::move(p1), std::move(p2)}));
|
||||
}
|
||||
|
||||
/// Dump object info to stdout
|
||||
void dump_object(const Boxed_Value &o) const
|
||||
@@ -1119,7 +1149,6 @@ namespace chaiscript
|
||||
State get_state() const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_global_object_mutex);
|
||||
|
||||
return m_state;
|
||||
}
|
||||
@@ -1127,7 +1156,6 @@ namespace chaiscript
|
||||
void set_state(const State &t_state)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_global_object_mutex);
|
||||
|
||||
m_state = t_state;
|
||||
}
|
||||
@@ -1205,7 +1233,6 @@ namespace chaiscript
|
||||
return *m_stack_holder;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Returns the current stack
|
||||
/// make const/non const versions
|
||||
const StackData &get_stack_data() const
|
||||
@@ -1223,32 +1250,34 @@ namespace chaiscript
|
||||
return m_stack_holder->stacks.back();
|
||||
}
|
||||
|
||||
const std::map<std::string, Boxed_Value> &get_boxed_functions_int() const
|
||||
private:
|
||||
|
||||
const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const
|
||||
{
|
||||
return m_state.m_boxed_functions;
|
||||
}
|
||||
|
||||
std::map<std::string, Boxed_Value> &get_boxed_functions_int()
|
||||
std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int()
|
||||
{
|
||||
return m_state.m_boxed_functions;
|
||||
}
|
||||
|
||||
const std::map<std::string, Proxy_Function> &get_function_objects_int() const
|
||||
const std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int() const
|
||||
{
|
||||
return m_state.m_function_objects;
|
||||
}
|
||||
|
||||
std::map<std::string, Proxy_Function> &get_function_objects_int()
|
||||
std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int()
|
||||
{
|
||||
return m_state.m_function_objects;
|
||||
}
|
||||
|
||||
const std::map<std::string, std::vector<Proxy_Function> > &get_functions_int() const
|
||||
const std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &get_functions_int() const
|
||||
{
|
||||
return m_state.m_functions;
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<Proxy_Function> > &get_functions_int()
|
||||
std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &get_functions_int()
|
||||
{
|
||||
return m_state.m_functions;
|
||||
}
|
||||
@@ -1362,6 +1391,49 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Container, typename Key, typename Value>
|
||||
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.reserve(t_c.size() + 1); // tightly control growth of memory usage here
|
||||
t_c.emplace_back(t_key, std::forward<Value>(t_value));
|
||||
} else {
|
||||
typedef typename Container::value_type value_type;
|
||||
*itr = value_type(t_key, std::forward<Value>(t_value));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Container, typename Key>
|
||||
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<typename Container, typename Key>
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Container, typename Key>
|
||||
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
|
||||
void add_function(const Proxy_Function &t_f, const std::string &t_name)
|
||||
@@ -1370,16 +1442,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))
|
||||
@@ -1388,33 +1457,35 @@ 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);
|
||||
return std::make_shared<Dispatch_Function>(vec);
|
||||
itr->second = std::make_shared<std::vector<Proxy_Function>>(vec);
|
||||
return std::make_shared<Dispatch_Function>(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<Proxy_Function> vec({t_f});
|
||||
funcs.insert(std::make_pair(t_name, vec));
|
||||
funcs.emplace_back(t_name, std::make_shared<std::vector<Proxy_Function>>(vec));
|
||||
return std::make_shared<Dispatch_Function>(std::move(vec));
|
||||
} else {
|
||||
funcs.insert(std::make_pair(t_name, std::vector<Proxy_Function>{t_f}));
|
||||
funcs.emplace_back(t_name, std::make_shared<std::vector<Proxy_Function>>(std::initializer_list<Proxy_Function>({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;
|
||||
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;
|
||||
|
||||
mutable std::atomic_uint_fast32_t m_method_missing_loc;
|
||||
|
||||
State m_state;
|
||||
};
|
||||
@@ -1440,6 +1511,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<Dispatch_Engine> m_engine;
|
||||
std::reference_wrapper<Stack_Holder> m_stack_holder;
|
||||
|
@@ -24,23 +24,53 @@ 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:
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -59,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);
|
||||
}
|
||||
|
||||
@@ -75,6 +113,7 @@ namespace chaiscript
|
||||
|
||||
private:
|
||||
std::string m_type_name;
|
||||
bool m_option_explicit;
|
||||
|
||||
std::map<std::string, Boxed_Value> m_attrs;
|
||||
};
|
||||
|
@@ -232,7 +232,7 @@ namespace chaiscript
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶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<Boxed_Value> new_params{bv};
|
||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||
|
||||
|
@@ -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<FunctionType>
|
||||
functor(const std::vector<Const_Proxy_Function> &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 || size_t(f->get_arity()) == chaiscript::dispatch::detail::Arity<FunctionType>::arity;
|
||||
});
|
||||
|
||||
if (!has_arity_match) {
|
||||
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>));
|
||||
}
|
||||
|
||||
FunctionType *p=nullptr;
|
||||
return detail::build_function_caller_helper(p, funcs, t_conversions);
|
||||
}
|
||||
|
@@ -211,7 +211,7 @@ namespace chaiscript
|
||||
if (ti.is_undef()
|
||||
|| ti.bare_equal(user_type<Boxed_Value>())
|
||||
|| (!bv.get_type_info().is_undef()
|
||||
&& (ti.bare_equal(user_type<Boxed_Number>())
|
||||
&& ( (ti.bare_equal(user_type<Boxed_Number>()) && bv.get_type_info().is_arithmetic())
|
||||
|| ti.bare_equal(bv.get_type_info())
|
||||
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|
||||
|| t_conversions.converts(ti, bv.get_type_info())
|
||||
@@ -248,7 +248,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs)
|
||||
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &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<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return static_cast<int>(vals.size()) == get_arity() && (compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions));
|
||||
return static_cast<int>(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<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
|
||||
@@ -763,6 +760,14 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
dispatch_error(std::vector<Boxed_Value> t_parameters,
|
||||
std::vector<Const_Proxy_Function> 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 {}
|
||||
|
||||
|
@@ -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",
|
||||
|
@@ -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 <windows.h>
|
||||
#endif
|
||||
#endif
|
||||
@@ -284,14 +286,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 +391,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 +513,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;
|
||||
|
@@ -44,16 +44,33 @@ 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<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> &t_locals=std::map<std::string, Boxed_Value>()) {
|
||||
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> *t_locals=nullptr) {
|
||||
chaiscript::detail::Dispatch_State state(t_ss);
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(state);
|
||||
|
||||
for (const auto &local : t_locals) {
|
||||
t_ss.add_object(local.first, local.second);
|
||||
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 (thisobj) state.add_object("this", *thisobj);
|
||||
|
||||
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]);
|
||||
if (t_param_names[i] != "this") {
|
||||
state.add_object(t_param_names[i], t_vals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -73,9 +90,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
|
||||
@@ -101,8 +118,7 @@ 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);
|
||||
return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs});
|
||||
}
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
@@ -112,13 +128,14 @@ namespace chaiscript
|
||||
|
||||
private:
|
||||
Operators::Opers m_oper;
|
||||
mutable std::atomic_uint_fast32_t m_loc;
|
||||
};
|
||||
|
||||
struct Int_AST_Node : public AST_Node {
|
||||
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;
|
||||
@@ -236,7 +253,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<const Const_Proxy_Function &>(fn))(params, t_ss->conversions());
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
@@ -286,73 +302,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<AST_NodePtr> 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<Boxed_Value> 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<const Const_Proxy_Function &>(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<AST_NodePtr> t_children) :
|
||||
@@ -448,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 {
|
||||
@@ -483,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);
|
||||
@@ -503,13 +454,14 @@ 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");
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -560,7 +512,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 &) {
|
||||
@@ -591,9 +543,8 @@ namespace chaiscript
|
||||
std::vector<Boxed_Value> 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);
|
||||
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 );
|
||||
@@ -615,6 +566,8 @@ namespace chaiscript
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
mutable std::atomic_uint_fast32_t m_loc;
|
||||
};
|
||||
|
||||
struct Dot_Access_AST_Node : public AST_Node {
|
||||
@@ -629,6 +582,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<Boxed_Value> params{retval};
|
||||
|
||||
@@ -643,9 +597,7 @@ namespace chaiscript
|
||||
fpp.save_params(params);
|
||||
|
||||
try {
|
||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
||||
t_ss->add_object("this", retval);
|
||||
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())
|
||||
@@ -661,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);
|
||||
@@ -672,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;
|
||||
};
|
||||
|
||||
@@ -745,7 +699,7 @@ namespace chaiscript
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[engine, lambda_node, param_names, captures](const std::vector<Boxed_Value> &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<int>(numparams), lambda_node, param_types
|
||||
)
|
||||
@@ -876,7 +830,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);
|
||||
|
||||
@@ -985,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<bool>(t_ss->call_function("==", match_value, this->children[currentCase]->children[0]->eval(t_ss)))) {
|
||||
if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}))) {
|
||||
this->children[currentCase]->eval(t_ss);
|
||||
hasMatched = true;
|
||||
}
|
||||
@@ -996,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 &) {
|
||||
@@ -1006,6 +960,8 @@ namespace chaiscript
|
||||
}
|
||||
return Boxed_Value();
|
||||
}
|
||||
|
||||
mutable std::atomic_uint_fast32_t m_loc;
|
||||
};
|
||||
|
||||
struct Case_AST_Node : public AST_Node {
|
||||
@@ -1052,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));
|
||||
}
|
||||
@@ -1069,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 {
|
||||
@@ -1083,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<std::string>(child->children[0]->eval(t_ss))] = std::move(obj);
|
||||
@@ -1096,6 +1054,7 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
mutable std::atomic_uint_fast32_t m_loc;
|
||||
};
|
||||
|
||||
struct Return_AST_Node : public AST_Node {
|
||||
@@ -1148,7 +1107,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 &) {
|
||||
@@ -1177,9 +1136,8 @@ 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));
|
||||
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);
|
||||
@@ -1188,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 {
|
||||
@@ -1248,15 +1207,16 @@ namespace chaiscript
|
||||
virtual ~Inline_Range_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
try {
|
||||
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));
|
||||
auto oper1 = children[0]->children[0]->children[0]->eval(t_ss);
|
||||
auto oper2 = children[0]->children[0]->children[1]->eval(t_ss);
|
||||
return t_ss->call_function("generate_range", m_loc, {oper1, oper2});
|
||||
}
|
||||
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 {
|
||||
@@ -1296,7 +1256,7 @@ namespace chaiscript
|
||||
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)}
|
||||
).match(std::vector<Boxed_Value>{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
|
||||
@@ -1433,7 +1393,7 @@ namespace chaiscript
|
||||
if (guardnode) {
|
||||
guard = dispatch::make_dynamic_proxy_function(
|
||||
[engine, t_param_names, guardnode](const std::vector<Boxed_Value> &t_params) {
|
||||
return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params, std::map<std::string, Boxed_Value>());
|
||||
return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), guardnode);
|
||||
}
|
||||
@@ -1450,7 +1410,7 @@ namespace chaiscript
|
||||
std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
|
||||
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map<std::string, Boxed_Value>());
|
||||
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), node, param_types, l_annotation, guard
|
||||
)
|
||||
@@ -1466,7 +1426,7 @@ namespace chaiscript
|
||||
t_ss->add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
|
||||
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map<std::string, Boxed_Value>());
|
||||
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), node, param_types, l_annotation, guard), type),
|
||||
function_name);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
647
include/chaiscript/utility/json.hpp
Normal file
647
include/chaiscript/utility/json.hpp
Normal file
@@ -0,0 +1,647 @@
|
||||
// From github.com/nbsdx/SimpleJSON.
|
||||
// Released under the DWTFYW PL
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef SIMPLEJSON_HPP
|
||||
#define SIMPLEJSON_HPP
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <initializer_list>
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
|
||||
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<JSON> *List;
|
||||
map<string,JSON> *Map;
|
||||
string *String;
|
||||
double Float;
|
||||
long Int;
|
||||
bool Bool;
|
||||
} Internal;
|
||||
|
||||
public:
|
||||
enum class Class {
|
||||
Null,
|
||||
Object,
|
||||
Array,
|
||||
String,
|
||||
Floating,
|
||||
Integral,
|
||||
Boolean
|
||||
};
|
||||
|
||||
template <typename Container>
|
||||
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 <typename Container>
|
||||
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)
|
||||
: Internal(), Type(Class::Null)
|
||||
{
|
||||
SetType( type );
|
||||
}
|
||||
|
||||
JSON( initializer_list<JSON> list )
|
||||
: Internal(), Type(Class::Null)
|
||||
{
|
||||
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<string,JSON>( other.Internal.Map->begin(),
|
||||
other.Internal.Map->end() );
|
||||
break;
|
||||
case Class::Array:
|
||||
Internal.List =
|
||||
new deque<JSON>( 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<string,JSON>( other.Internal.Map->begin(),
|
||||
other.Internal.Map->end() );
|
||||
break;
|
||||
case Class::Array:
|
||||
Internal.List =
|
||||
new deque<JSON>( 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 <typename T>
|
||||
JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = 0 ) : Internal( b ), Type( Class::Boolean ){}
|
||||
|
||||
template <typename T>
|
||||
JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = 0 ) : Internal( long(i) ), Type( Class::Integral ){}
|
||||
|
||||
template <typename T>
|
||||
JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = 0 ) : Internal( double(f) ), Type( Class::Floating ){}
|
||||
|
||||
template <typename T>
|
||||
JSON( T s, typename enable_if<is_convertible<T,string>::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 <typename T>
|
||||
void append( T arg ) {
|
||||
SetType( Class::Array ); Internal.List->emplace_back( arg );
|
||||
}
|
||||
|
||||
template <typename T, typename... U>
|
||||
void append( T arg, U... args ) {
|
||||
append( arg ); append( args... );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_same<T,bool>::value, JSON&>::type operator=( T b ) {
|
||||
SetType( Class::Boolean ); Internal.Bool = b; return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_integral<T>::value && !is_same<T,bool>::value, JSON&>::type operator=( T i ) {
|
||||
SetType( Class::Integral ); Internal.Int = i; return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_floating_point<T>::value, JSON&>::type operator=( T f ) {
|
||||
SetType( Class::Floating ); Internal.Float = f; return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_convertible<T,string>::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[]( const size_t 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<int>(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<int>(Internal.Map->size());
|
||||
else if( Type == Class::Array )
|
||||
return static_cast<int>(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 ? *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<map<string,JSON>> ObjectRange() {
|
||||
if( Type == Class::Object )
|
||||
return JSONWrapper<map<string,JSON>>( Internal.Map );
|
||||
return JSONWrapper<map<string,JSON>>( nullptr );
|
||||
}
|
||||
|
||||
JSONWrapper<deque<JSON>> ArrayRange() {
|
||||
if( Type == Class::Array )
|
||||
return JSONWrapper<deque<JSON>>( Internal.List );
|
||||
return JSONWrapper<deque<JSON>>( nullptr );
|
||||
}
|
||||
|
||||
JSONConstWrapper<map<string,JSON>> ObjectRange() const {
|
||||
if( Type == Class::Object )
|
||||
return JSONConstWrapper<map<string,JSON>>( Internal.Map );
|
||||
return JSONConstWrapper<map<string,JSON>>( nullptr );
|
||||
}
|
||||
|
||||
|
||||
JSONConstWrapper<deque<JSON>> ArrayRange() const {
|
||||
if( Type == Class::Array )
|
||||
return JSONConstWrapper<deque<JSON>>( Internal.List );
|
||||
return JSONConstWrapper<deque<JSON>>( 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";
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unhandled JSON type");
|
||||
}
|
||||
|
||||
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<string,JSON>(); break;
|
||||
case Class::Array: Internal.List = new deque<JSON>(); 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;
|
||||
};
|
||||
|
||||
JSON Array() {
|
||||
return JSON::Make( JSON::Class::Array );
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
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 (;offset<str.size();) {
|
||||
JSON Key = parse_next( str, offset );
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] != ':' ) {
|
||||
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 );
|
||||
Object[Key.ToString()] = Value;
|
||||
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] == ',' ) {
|
||||
++offset; continue;
|
||||
}
|
||||
else if( str[offset] == '}' ) {
|
||||
++offset; break;
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str[offset] + "'\n");
|
||||
}
|
||||
}
|
||||
|
||||
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 (;offset < str.size();) {
|
||||
Array[index++] = parse_next( str, offset );
|
||||
consume_ws( str, offset );
|
||||
|
||||
if( str[offset] == ',' ) {
|
||||
++offset; continue;
|
||||
}
|
||||
else if( str[offset] == ']' ) {
|
||||
++offset; break;
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str[offset] + "'\n");
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
|
||||
}
|
||||
}
|
||||
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 = '\0';
|
||||
bool isDouble = false;
|
||||
long exp = 0;
|
||||
for (; offset < str.size() ;) {
|
||||
c = str[offset++];
|
||||
if( (c == '-') || (c >= '0' && c <= '9') )
|
||||
val += c;
|
||||
else if( c == '.' ) {
|
||||
val += c;
|
||||
isDouble = true;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if( offset < str.size() && (c == 'E' || c == 'e' )) {
|
||||
c = str[ offset++ ];
|
||||
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 != '}' ) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'");
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
exp = std::stol( exp_str );
|
||||
}
|
||||
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
|
||||
}
|
||||
--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" ) {
|
||||
offset += 4;
|
||||
Bool = true;
|
||||
} else if( str.substr( offset, 5 ) == "false" ) {
|
||||
offset += 5;
|
||||
Bool = false;
|
||||
} else {
|
||||
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" ) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'");
|
||||
}
|
||||
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 );
|
||||
}
|
||||
throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
|
||||
}
|
||||
}
|
||||
|
||||
JSON JSON::Load( const string &str ) {
|
||||
size_t offset = 0;
|
||||
return parse_next( str, offset );
|
||||
}
|
||||
|
||||
} // End Namespace json
|
||||
|
||||
|
||||
#endif
|
158
include/chaiscript/utility/json_wrap.hpp
Normal file
158
include/chaiscript/utility/json_wrap.hpp
Normal file
@@ -0,0 +1,158 @@
|
||||
#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<Module>())
|
||||
{
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
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<std::string, Boxed_Value> m;
|
||||
|
||||
for (const auto &p : t_json.ObjectRange())
|
||||
{
|
||||
m.insert(std::make_pair(p.first, from_json(p.second)));
|
||||
}
|
||||
|
||||
return Boxed_Value(m);
|
||||
}
|
||||
case json::JSON::Class::Array:
|
||||
{
|
||||
std::vector<Boxed_Value> 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) );
|
||||
}
|
||||
|
||||
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 {
|
||||
const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(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<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(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<double>();
|
||||
} else {
|
||||
obj = bn.get_as<long>();
|
||||
}
|
||||
return obj;
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
// not a number
|
||||
}
|
||||
|
||||
try {
|
||||
bool b = boxed_cast<bool>(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<std::string>(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<const dispatch::Dynamic_Object &>(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");
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
32
samples/test_num_exceptions.cpp
Normal file
32
samples/test_num_exceptions.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
#include <chaiscript/dispatchkit/function_call.hpp>
|
||||
|
||||
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;
|
||||
}
|
12
unittests/bool_comparisons.chai
Normal file
12
unittests/bool_comparisons.chai
Normal file
@@ -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)
|
||||
|
@@ -743,3 +743,62 @@ TEST_CASE("Test Derived->Base with non-polymorphic classes")
|
||||
chai.add(chaiscript::fun(&myfunction), "myfunction");
|
||||
CHECK(chai.eval<int>("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<TestCppVariableScope>(), "Test");
|
||||
chai.add(chaiscript::constructor<TestCppVariableScope()>(), "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<std::function<void()>>("func");
|
||||
CHECK_THROWS(func());
|
||||
}
|
||||
|
||||
TEST_CASE("Variable Scope When Calling From C++ 2")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.eval("var obj = 2;");
|
||||
auto func = chai.eval<std::function<void()>>("fun(){ return obj; }");
|
||||
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)");
|
||||
}
|
||||
|
||||
|
14
unittests/dynamic_object_dynamic_attrs_explicit.chai
Normal file
14
unittests/dynamic_object_dynamic_attrs_explicit.chai
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
class MyClass {
|
||||
def MyClass()
|
||||
{
|
||||
this.set_explicit(true);
|
||||
}
|
||||
};
|
||||
|
||||
var o = MyClass();
|
||||
|
||||
assert_true(o.is_explicit());
|
||||
|
||||
assert_throws("error", fun[o](){o.x = 2})
|
||||
|
Binary file not shown.
6
unittests/hex_escapes.chai
Normal file
6
unittests/hex_escapes.chai
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
assert_equal("\x39", "9")
|
||||
assert_equal("\x039", "9")
|
||||
assert_equal("\x39g", "9g")
|
||||
assert_equal("b\x39g", "b9g")
|
||||
|
@@ -5,9 +5,10 @@
|
||||
template<typename T>
|
||||
bool test_literal(T val, const std::string &str)
|
||||
{
|
||||
std::cout << "Comparing : " << val;
|
||||
chaiscript::ChaiScript chai;
|
||||
T val2 = chai.eval<T>(str);
|
||||
std::cout << "Comparing : " << val << " " << val2 << '\n';
|
||||
std::cout << " " << val2 << '\n';
|
||||
return val == val2;
|
||||
}
|
||||
|
||||
@@ -74,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;
|
||||
|
3
unittests/json_1.chai
Normal file
3
unittests/json_1.chai
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
assert_true(from_json("null").is_var_null())
|
1
unittests/json_10.chai
Normal file
1
unittests/json_10.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(from_json("\"This is a\\n\\nMultiline string\""), "This is a\n\nMultiline string")
|
14
unittests/json_11.chai
Normal file
14
unittests/json_11.chai
Normal file
@@ -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" ]);
|
||||
|
||||
|
||||
|
1
unittests/json_12.chai
Normal file
1
unittests/json_12.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(from_json("\"\""), "")
|
1
unittests/json_13.chai
Normal file
1
unittests/json_13.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(from_json("1.20E+2"), 1.20e2)
|
3
unittests/json_2.chai
Normal file
3
unittests/json_2.chai
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
assert_true(from_json("true"))
|
||||
|
1
unittests/json_3.chai
Normal file
1
unittests/json_3.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(from_json("100"), 100)
|
1
unittests/json_4.chai
Normal file
1
unittests/json_4.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(from_json("1.234"), 1.234)
|
1
unittests/json_5.chai
Normal file
1
unittests/json_5.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(from_json("\"StringTest\""), "StringTest")
|
1
unittests/json_6.chai
Normal file
1
unittests/json_6.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(from_json("{}"), Map())
|
4
unittests/json_7.chai
Normal file
4
unittests/json_7.chai
Normal file
@@ -0,0 +1,4 @@
|
||||
assert_equal(from_json("\n" +
|
||||
"{\n" +
|
||||
" \"Key\" : \"Value\"\n" +
|
||||
"}\n"), ["Key":"Value"])
|
1
unittests/json_8.chai
Normal file
1
unittests/json_8.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(from_json("[]"), [])
|
2
unittests/json_9.chai
Normal file
2
unittests/json_9.chai
Normal file
@@ -0,0 +1,2 @@
|
||||
assert_equal(from_json("[1,2,3]"), [1,2,3])
|
||||
|
6
unittests/json_roundtrip.chai
Normal file
6
unittests/json_roundtrip.chai
Normal file
@@ -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)
|
||||
|
||||
|
@@ -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(){}))
|
||||
|
||||
|
||||
|
@@ -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(){}))
|
||||
|
||||
|
||||
|
@@ -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()))
|
||||
|
6
unittests/octal_escapes.chai
Normal file
6
unittests/octal_escapes.chai
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
assert_equal("\71", "9")
|
||||
assert_equal("\071", "9")
|
||||
assert_equal("\71a", "9a")
|
||||
assert_equal("b\71a", "b9a")
|
||||
|
7
unittests/operator_overload3.chai
Normal file
7
unittests/operator_overload3.chai
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
|
||||
def string::`/=`(double d) { this = "${this}/=${d}"; return this; }
|
||||
|
||||
var s = "Hello World"
|
||||
s /= 2
|
||||
|
6
unittests/operator_overload4.chai
Normal file
6
unittests/operator_overload4.chai
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
def string::`*`(double d) { return "${this} * ${d}"; }
|
||||
|
||||
"Hello World" * 2
|
||||
|
4
unittests/operator_parsing.chai
Normal file
4
unittests/operator_parsing.chai
Normal file
@@ -0,0 +1,4 @@
|
||||
assert_true(2>-1);
|
||||
assert_false(3<-2);
|
||||
assert_true(-1==-1);
|
||||
|
7
unittests/order_of_operations.chai
Normal file
7
unittests/order_of_operations.chai
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
|
||||
var s = ""
|
||||
|
||||
s += to_string(fun[s](){ s += "3"; 3}() % fun[s](){ s += "2"; 2}());
|
||||
|
||||
assert_equal(s, "321");
|
10
unittests/parser_test.chai
Normal file
10
unittests/parser_test.chai
Normal file
@@ -0,0 +1,10 @@
|
||||
auto p = parse("5 + 4");
|
||||
|
||||
try {
|
||||
assert_equal(eval(p), 9)
|
||||
} catch (e) {
|
||||
print(e.pretty_print());
|
||||
assert_true(false);
|
||||
}
|
||||
|
||||
|
18
unittests/switch_default_2.chai
Normal file
18
unittests/switch_default_2.chai
Normal file
@@ -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)
|
18
unittests/vector_assignment.chai
Normal file
18
unittests/vector_assignment.chai
Normal file
@@ -0,0 +1,18 @@
|
||||
var v = []
|
||||
v.push_back(3.4);
|
||||
v.push_back(1);
|
||||
v.push_back("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")
|
||||
|
||||
|
5
unittests/vector_assignment_3.chai
Normal file
5
unittests/vector_assignment_3.chai
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
var v = []
|
||||
v.push_back(int(1));
|
||||
v[0] = 3;
|
||||
|
@@ -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(){}))
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user