Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f78fb77128 | ||
![]() |
bb08cc3699 | ||
![]() |
6692607507 | ||
![]() |
6bea42c1c0 | ||
![]() |
251790f144 | ||
![]() |
4ee9ba9c96 | ||
![]() |
a71903f185 | ||
![]() |
3fe80d70c6 | ||
![]() |
9c05779fac | ||
![]() |
a6e3fd5b42 | ||
![]() |
6a3f19d575 | ||
![]() |
9b7e4d2e78 | ||
![]() |
f546e46582 | ||
![]() |
fa1f4b795b | ||
![]() |
cb1c7730cf | ||
![]() |
3a775097dd | ||
![]() |
5692dfc58a | ||
![]() |
c5f6c549ec | ||
![]() |
14a280713f |
@@ -10,7 +10,7 @@ else()
|
||||
endif()
|
||||
|
||||
|
||||
option(BUILD_MODULES "Build Extra Modules (stl, reflection)" TRUE)
|
||||
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
|
||||
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
|
||||
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 5)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 3)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 1)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 4)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
||||
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
|
||||
@@ -210,9 +210,7 @@ if(BUILD_MODULES)
|
||||
add_library(stl_extra MODULE src/stl_extra.cpp)
|
||||
target_link_libraries(stl_extra ${LIBS})
|
||||
|
||||
add_library(reflection MODULE src/reflection.cpp)
|
||||
target_link_libraries(reflection ${LIBS})
|
||||
set(MODULES stl_extra reflection)
|
||||
set(MODULES stl_extra)
|
||||
endif()
|
||||
|
||||
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
|
||||
@@ -275,6 +273,10 @@ if(BUILD_TESTING)
|
||||
target_link_libraries(type_info_test ${LIBS})
|
||||
add_test(NAME Type_Info_Test COMMAND type_info_test)
|
||||
|
||||
add_executable(type_name_test unittests/type_name_test.cpp)
|
||||
target_link_libraries(type_name_test ${LIBS})
|
||||
add_test(NAME Type_Name_Test COMMAND type_name_test)
|
||||
|
||||
add_executable(eval_catch_exception_test unittests/eval_catch_exception_test.cpp)
|
||||
target_link_libraries(eval_catch_exception_test ${LIBS})
|
||||
add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test)
|
||||
|
@@ -1,9 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
pushd ..
|
||||
wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.64/cppcheck-1.65.tar.bz2
|
||||
tar -xvf cppcheck-1.65.tar.bz2
|
||||
cd cppcheck-1.65
|
||||
wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.66/cppcheck-1.66.tar.bz2
|
||||
tar -xvf cppcheck-1.66.tar.bz2
|
||||
cd cppcheck-1.66
|
||||
make -j2
|
||||
popd
|
||||
../cppcheck-1.65/cppcheck --enable=all -I include --inline-suppr --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output
|
||||
|
@@ -497,6 +497,21 @@
|
||||
/// print(rect.area())
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// Since ChaiScript 5.4.0 it has been possible to use the "class" keyword to simplify this code.
|
||||
///
|
||||
/// ~~~~~~~~~
|
||||
/// class Rectangle {
|
||||
/// attr height
|
||||
/// attr width
|
||||
/// def Rectangle() { this.height = 10; this.width = 20 }
|
||||
/// def area() { this.height * this.width }
|
||||
/// }
|
||||
///
|
||||
/// var rect = Rectangle()
|
||||
/// rect.height = 30
|
||||
/// print(rect.area())
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// @sa @ref keywordattr
|
||||
/// @sa @ref keyworddef
|
||||
|
||||
|
@@ -45,8 +45,8 @@
|
||||
|
||||
namespace chaiscript {
|
||||
static const int version_major = 5;
|
||||
static const int version_minor = 3;
|
||||
static const int version_patch = 1;
|
||||
static const int version_minor = 4;
|
||||
static const int version_patch = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -44,17 +44,29 @@ namespace chaiscript {
|
||||
private:
|
||||
struct Data
|
||||
{
|
||||
Data(const std::type_info &t_type)
|
||||
: m_type(t_type)
|
||||
{
|
||||
}
|
||||
|
||||
Data &operator=(const Data &) = delete;
|
||||
|
||||
virtual ~Data() {}
|
||||
virtual void *data() = 0;
|
||||
virtual const std::type_info &type() const = 0;
|
||||
virtual std::shared_ptr<Data> clone() const = 0;
|
||||
const std::type_info &type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<Data> clone() const = 0;
|
||||
const std::type_info &m_type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Data_Impl : Data
|
||||
{
|
||||
Data_Impl(T t_type)
|
||||
: m_type(typeid(T)),
|
||||
: Data(typeid(T)),
|
||||
m_data(std::move(t_type))
|
||||
{
|
||||
}
|
||||
@@ -66,23 +78,17 @@ namespace chaiscript {
|
||||
return &m_data;
|
||||
}
|
||||
|
||||
const std::type_info &type() const CHAISCRIPT_OVERRIDE
|
||||
std::unique_ptr<Data> clone() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
std::shared_ptr<Data> clone() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return std::shared_ptr<Data>(new Data_Impl<T>(m_data));
|
||||
return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
|
||||
}
|
||||
|
||||
Data_Impl &operator=(const Data_Impl&) = delete;
|
||||
|
||||
const std::type_info &m_type;
|
||||
|
||||
T m_data;
|
||||
};
|
||||
|
||||
std::shared_ptr<Data> m_data;
|
||||
std::unique_ptr<Data> m_data;
|
||||
|
||||
public:
|
||||
// construct/copy/destruct
|
||||
@@ -100,7 +106,7 @@ namespace chaiscript {
|
||||
|
||||
template<typename ValueType>
|
||||
Any(const ValueType &t_value)
|
||||
: m_data(std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value)))
|
||||
: m_data(std::unique_ptr<Data>(new Data_Impl<ValueType>(t_value)))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -114,7 +120,7 @@ namespace chaiscript {
|
||||
template<typename ValueType>
|
||||
Any & operator=(const ValueType &t_value)
|
||||
{
|
||||
m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
|
||||
m_data = std::unique_ptr<Data>(new Data_Impl<ValueType>(t_value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -127,7 +133,6 @@ namespace chaiscript {
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -138,9 +143,7 @@ namespace chaiscript {
|
||||
// modifiers
|
||||
Any & swap(Any &t_other)
|
||||
{
|
||||
std::shared_ptr<Data> data = t_other.m_data;
|
||||
t_other.m_data = m_data;
|
||||
m_data = data;
|
||||
std::swap(t_other.m_data, m_data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@@ -32,6 +32,8 @@
|
||||
#include "proxy_functions_detail.hpp"
|
||||
#include "register_function.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "../utility/utility.hpp"
|
||||
#include "../language/chaiscript_common.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
@@ -357,12 +359,48 @@ namespace chaiscript
|
||||
return vbv;
|
||||
}
|
||||
|
||||
|
||||
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
||||
{
|
||||
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
|
||||
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf)
|
||||
{
|
||||
if (pf->get_parse_tree())
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
||||
{
|
||||
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
|
||||
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf)
|
||||
{
|
||||
if (pf->get_parse_tree())
|
||||
{
|
||||
return pf->get_parse_tree();
|
||||
} else {
|
||||
throw std::runtime_error("Function does not have a parse tree");
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Function does not have a parse tree");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
|
||||
{
|
||||
return std::bind(&do_return_boxed_value_vector<Function>, f, std::placeholders::_1);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
/// \brief perform all common bootstrap functions for std::string, void and POD types
|
||||
/// \param[in,out] m Module to add bootstrapped functions to
|
||||
@@ -380,7 +418,7 @@ namespace chaiscript
|
||||
m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
|
||||
m->add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
|
||||
|
||||
|
||||
|
||||
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
|
||||
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
|
||||
|
||||
@@ -409,9 +447,12 @@ namespace chaiscript
|
||||
m->add(fun(&Boxed_Value::is_ref), "is_var_reference");
|
||||
m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
|
||||
m->add(fun(&Boxed_Value::is_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::get_type_info), "get_type_info");
|
||||
m->add(user_type<Type_Info>(), "Type_Info");
|
||||
m->add(constructor<Type_Info (const Type_Info &)>(), "Type_Info");
|
||||
|
||||
|
||||
operators::equal<Type_Info>(m);
|
||||
@@ -431,8 +472,8 @@ namespace chaiscript
|
||||
operators::assign<bool>(m);
|
||||
operators::equal<bool>(m);
|
||||
|
||||
m->add(fun(&to_string<const std::string &>), "internal_to_string");
|
||||
m->add(fun(&Bootstrap::bool_to_string), "internal_to_string");
|
||||
m->add(fun(&to_string<const std::string &>), "to_string");
|
||||
m->add(fun(&Bootstrap::bool_to_string), "to_string");
|
||||
m->add(fun(&unknown_assign), "=");
|
||||
m->add(fun(&throw_exception), "throw");
|
||||
m->add(fun(&what), "what");
|
||||
@@ -472,6 +513,68 @@ namespace chaiscript
|
||||
|
||||
m->add(fun(&Boxed_Value::type_match), "type_match");
|
||||
|
||||
|
||||
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
|
||||
m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
|
||||
|
||||
m->add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
|
||||
|
||||
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<chaiscript::exception::eval_error>(*m,
|
||||
"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> retval;
|
||||
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
|
||||
std::back_inserter(retval),
|
||||
&chaiscript::var<std::shared_ptr<chaiscript::AST_Node>>);
|
||||
return retval;
|
||||
})), "call_stack"} }
|
||||
);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<chaiscript::File_Position>(*m,
|
||||
"File_Position",
|
||||
{ constructor<File_Position()>(),
|
||||
constructor<File_Position(int, int)>() },
|
||||
{ {fun(&File_Position::line), "line"},
|
||||
{fun(&File_Position::column), "column"} }
|
||||
);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<AST_Node>(*m,
|
||||
"AST_Node",
|
||||
{ },
|
||||
{ {fun(&AST_Node::text), "text"},
|
||||
{fun(&AST_Node::identifier), "identifier"},
|
||||
{fun(&AST_Node::filename), "filename"},
|
||||
{fun(&AST_Node::start), "start"},
|
||||
{fun(&AST_Node::end), "end"},
|
||||
{fun(&AST_Node::to_string), "to_string"},
|
||||
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) {
|
||||
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>>);
|
||||
return retval;
|
||||
})), "children"},
|
||||
{fun(&AST_Node::replace_child), "replace_child"}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<parser::ChaiScript_Parser>(*m,
|
||||
"ChaiScript_Parser",
|
||||
{ constructor<parser::ChaiScript_Parser ()>() },
|
||||
{ {fun(&parser::ChaiScript_Parser::parse), "parse"},
|
||||
{fun(&parser::ChaiScript_Parser::ast), "ast"} }
|
||||
);
|
||||
|
||||
|
||||
|
||||
return m;
|
||||
}
|
||||
};
|
||||
|
@@ -185,7 +185,7 @@ namespace chaiscript
|
||||
|
||||
copy_constructor<Bidir_Type>(type + "_Range", m);
|
||||
|
||||
m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range");
|
||||
m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range_internal");
|
||||
|
||||
m->add(fun(&Bidir_Type::empty), "empty");
|
||||
m->add(fun(&Bidir_Type::pop_front), "pop_front");
|
||||
@@ -348,10 +348,12 @@ namespace chaiscript
|
||||
ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
typedef typename ContainerType::reference (ContainerType::*frontptr)();
|
||||
typedef typename ContainerType::const_reference (ContainerType::*constfrontptr)() const;
|
||||
typedef void (ContainerType::*pushptr)(typename ContainerType::const_reference);
|
||||
typedef void (ContainerType::*popptr)();
|
||||
|
||||
m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front");
|
||||
m->add(fun(static_cast<constfrontptr>(&ContainerType::front)), "front");
|
||||
|
||||
std::string push_front_name;
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
|
||||
@@ -475,7 +477,10 @@ namespace chaiscript
|
||||
m->add(user_type<VectorType>(), type);
|
||||
|
||||
typedef typename VectorType::reference (VectorType::*frontptr)();
|
||||
typedef typename VectorType::const_reference (VectorType::*constfrontptr)() const;
|
||||
|
||||
m->add(fun(static_cast<frontptr>(&VectorType::front)), "front");
|
||||
m->add(fun(static_cast<constfrontptr>(&VectorType::front)), "front");
|
||||
|
||||
|
||||
back_insertion_sequence_type<VectorType>(type, m);
|
||||
|
@@ -205,10 +205,25 @@ namespace chaiscript
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
|
||||
{
|
||||
return ob;
|
||||
return ob;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a Boxed_Value & type
|
||||
*/
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value &>
|
||||
{
|
||||
typedef Boxed_Value& Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
|
||||
{
|
||||
return const_cast<Boxed_Value &>(ob);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const Boxed_Value & type
|
||||
*/
|
||||
|
@@ -51,9 +51,16 @@ namespace chaiscript
|
||||
m_data_ptr = rhs.m_data_ptr;
|
||||
m_const_data_ptr = rhs.m_const_data_ptr;
|
||||
|
||||
if (rhs.m_attrs)
|
||||
{
|
||||
m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>(*rhs.m_attrs));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Data(const Data &) = delete;
|
||||
|
||||
~Data()
|
||||
{
|
||||
}
|
||||
@@ -63,6 +70,7 @@ namespace chaiscript
|
||||
void *m_data_ptr;
|
||||
const void *m_const_data_ptr;
|
||||
bool m_is_ref;
|
||||
std::unique_ptr<std::map<std::string, Boxed_Value>> m_attrs;
|
||||
};
|
||||
|
||||
struct Object_Data
|
||||
@@ -231,6 +239,26 @@ namespace chaiscript
|
||||
return m_data->m_const_data_ptr;
|
||||
}
|
||||
|
||||
Boxed_Value get_attr(const std::string &t_name)
|
||||
{
|
||||
if (!m_data->m_attrs)
|
||||
{
|
||||
m_data->m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>());
|
||||
}
|
||||
|
||||
return (*m_data->m_attrs)[t_name];
|
||||
}
|
||||
|
||||
Boxed_Value ©_attrs(const Boxed_Value &t_obj)
|
||||
{
|
||||
if (t_obj.m_data->m_attrs)
|
||||
{
|
||||
m_data->m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>(*t_obj.m_data->m_attrs));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// \returns true if the two Boxed_Values share the same internal type
|
||||
static bool type_match(Boxed_Value l, Boxed_Value r)
|
||||
{
|
||||
|
@@ -736,6 +736,19 @@ namespace chaiscript
|
||||
return functions.find(name) != functions.end();
|
||||
}
|
||||
|
||||
/// \returns All values in the local thread state in the parent scope, or if it doesn't exist,
|
||||
/// the current scope.
|
||||
std::map<std::string, Boxed_Value> get_parent_locals() const
|
||||
{
|
||||
StackData &stack = get_stack_data();
|
||||
if (stack.size() > 1)
|
||||
{
|
||||
return stack[1];
|
||||
} else {
|
||||
return stack[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// \returns All values in the local thread state, added through the add() function
|
||||
std::map<std::string, Boxed_Value> get_locals() const
|
||||
{
|
||||
|
@@ -440,34 +440,26 @@ namespace chaiscript
|
||||
int m_arity;
|
||||
};
|
||||
|
||||
/**
|
||||
* The standard typesafe function call implementation of Proxy_Function
|
||||
* It takes a std::function<> object and performs runtime
|
||||
* type checking of Boxed_Value parameters, in a type safe manner
|
||||
*/
|
||||
template<typename Func>
|
||||
class Proxy_Function_Impl : public Proxy_Function_Base
|
||||
class Proxy_Function_Impl_Base : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Proxy_Function_Impl(std::function<Func> f)
|
||||
: Proxy_Function_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))),
|
||||
m_f(std::move(f)), m_dummy_func(nullptr)
|
||||
Proxy_Function_Impl_Base(std::vector<Type_Info> t_types)
|
||||
: Proxy_Function_Base(std::move(t_types))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Proxy_Function_Impl() {}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
const Proxy_Function_Impl *pimpl = dynamic_cast<const Proxy_Function_Impl<Func> *>(&t_func);
|
||||
return pimpl != nullptr;
|
||||
}
|
||||
virtual ~Proxy_Function_Impl_Base() {}
|
||||
|
||||
virtual int get_arity() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return static_cast<int>(m_types.size()) - 1;
|
||||
}
|
||||
|
||||
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (int(vals.size()) != get_arity())
|
||||
@@ -475,12 +467,37 @@ namespace chaiscript
|
||||
return false;
|
||||
}
|
||||
|
||||
return compare_types(m_types, vals) || detail::compare_types_cast(m_dummy_func, vals, t_conversions);
|
||||
return compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions);
|
||||
}
|
||||
|
||||
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
|
||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* The standard typesafe function call implementation of Proxy_Function
|
||||
* It takes a std::function<> object and performs runtime
|
||||
* type checking of Boxed_Value parameters, in a type safe manner
|
||||
*/
|
||||
template<typename Func>
|
||||
class Proxy_Function_Impl : public Proxy_Function_Impl_Base
|
||||
{
|
||||
public:
|
||||
Proxy_Function_Impl(std::function<Func> f)
|
||||
: Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))),
|
||||
m_f(std::move(f)), m_dummy_func(nullptr)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual ~Proxy_Function_Impl() {}
|
||||
|
||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return detail::compare_types_cast(m_dummy_func, vals, t_conversions);
|
||||
}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return dynamic_cast<const Proxy_Function_Impl<Func> *>(&t_func) != nullptr;
|
||||
}
|
||||
|
||||
std::function<Func> internal_function() const
|
||||
@@ -489,7 +506,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Dynamic_Cast_Conversions &t_conversions) const
|
||||
{
|
||||
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions);
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ namespace chaiscript
|
||||
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,
|
||||
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop
|
||||
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class
|
||||
};
|
||||
};
|
||||
|
||||
@@ -430,17 +430,13 @@ namespace chaiscript
|
||||
|
||||
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
|
||||
<< this->text << " : " << this->start.line << ", " << this->start.column << std::endl;
|
||||
|
||||
|
||||
for (size_t j = 0; j < this->children.size(); ++j) {
|
||||
oss << this->children[j]->to_string(t_prepend + " ");
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string internal_to_string() {
|
||||
return to_string();
|
||||
}
|
||||
|
||||
Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e)
|
||||
{
|
||||
try {
|
||||
@@ -510,6 +506,9 @@ namespace chaiscript
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Scope_Push_Pop
|
||||
{
|
||||
Scope_Push_Pop(const Scope_Push_Pop &) = delete;
|
||||
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
|
||||
|
||||
Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
{
|
||||
@@ -523,9 +522,6 @@ namespace chaiscript
|
||||
|
||||
|
||||
private:
|
||||
// explicitly unimplemented copy and assignment
|
||||
Scope_Push_Pop(const Scope_Push_Pop &);
|
||||
Scope_Push_Pop& operator=(const Scope_Push_Pop &);
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
};
|
||||
@@ -533,6 +529,9 @@ namespace chaiscript
|
||||
/// Creates a new function call and pops it on destruction
|
||||
struct Function_Push_Pop
|
||||
{
|
||||
Function_Push_Pop(const Function_Push_Pop &) = delete;
|
||||
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
|
||||
|
||||
Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
{
|
||||
@@ -551,9 +550,6 @@ namespace chaiscript
|
||||
|
||||
|
||||
private:
|
||||
// explicitly unimplemented copy and assignment
|
||||
Function_Push_Pop(const Function_Push_Pop &);
|
||||
Function_Push_Pop& operator=(const Function_Push_Pop &);
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
};
|
||||
@@ -561,6 +557,9 @@ namespace chaiscript
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Stack_Push_Pop
|
||||
{
|
||||
Stack_Push_Pop(const Stack_Push_Pop &) = delete;
|
||||
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
|
||||
|
||||
Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
{
|
||||
@@ -574,9 +573,6 @@ namespace chaiscript
|
||||
|
||||
|
||||
private:
|
||||
// explicitly unimplemented copy and assignment
|
||||
Stack_Push_Pop(const Stack_Push_Pop &);
|
||||
Stack_Push_Pop& operator=(const Stack_Push_Pop &);
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
};
|
||||
|
@@ -330,6 +330,7 @@ namespace chaiscript
|
||||
m_engine.add_reserved_word("break");
|
||||
m_engine.add_reserved_word("true");
|
||||
m_engine.add_reserved_word("false");
|
||||
m_engine.add_reserved_word("class");
|
||||
m_engine.add_reserved_word("_");
|
||||
|
||||
if (t_lib)
|
||||
@@ -503,6 +504,18 @@ namespace chaiscript
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string get_type_name(const Type_Info &ti) const
|
||||
{
|
||||
return m_engine.get_type_name(ti);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string get_type_name() const
|
||||
{
|
||||
return get_type_name(user_type<T>());
|
||||
}
|
||||
|
||||
|
||||
/// \brief Loads and parses a file. If the file is already, it is not reloaded
|
||||
/// The use paths specified at ChaiScript construction time are searched for the
|
||||
/// requested file.
|
||||
|
@@ -584,9 +584,6 @@ namespace chaiscript
|
||||
params.clear();
|
||||
retval = t_ss.call_function("[]", retval, p1);
|
||||
}
|
||||
catch(std::out_of_range &) {
|
||||
throw exception::eval_error("Out of bounds exception");
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, t_ss );
|
||||
}
|
||||
@@ -662,9 +659,6 @@ namespace chaiscript
|
||||
try {
|
||||
retval = t_ss.call_function("[]", retval, this->children[i]->children[j]->eval(t_ss));
|
||||
}
|
||||
catch(std::out_of_range &) {
|
||||
throw exception::eval_error("Out of bounds exception");
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, t_ss);
|
||||
}
|
||||
@@ -856,7 +850,23 @@ namespace chaiscript
|
||||
|
||||
return Boxed_Value();
|
||||
}
|
||||
};
|
||||
|
||||
struct Class_AST_Node : public AST_Node {
|
||||
public:
|
||||
Class_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||
AST_Node(t_ast_node_text, AST_Node_Type::Class, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||
virtual ~Class_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE {
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
// 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(this->children[0]->text));
|
||||
|
||||
this->children[1]->eval(t_ss);
|
||||
|
||||
return Boxed_Value();
|
||||
}
|
||||
};
|
||||
|
||||
struct Ternary_Cond_AST_Node : public AST_Node {
|
||||
@@ -1400,23 +1410,29 @@ namespace chaiscript
|
||||
std::vector<std::string> t_param_names;
|
||||
AST_NodePtr guardnode;
|
||||
|
||||
auto d = t_ss.get_parent_locals();
|
||||
auto itr = d.find("_current_class_name");
|
||||
int class_offset = 0;
|
||||
if (itr != d.end()) class_offset = -1;
|
||||
const std::string & class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
|
||||
|
||||
//The first param of a method is always the implied this ptr.
|
||||
t_param_names.push_back("this");
|
||||
|
||||
if ((this->children.size() > 3) && (this->children[2]->identifier == AST_Node_Type::Arg_List)) {
|
||||
for (size_t i = 0; i < this->children[2]->children.size(); ++i) {
|
||||
t_param_names.push_back(this->children[2]->children[i]->text);
|
||||
if ((this->children.size() > (3 + class_offset)) && (this->children[(2 + class_offset)]->identifier == AST_Node_Type::Arg_List)) {
|
||||
for (size_t i = 0; i < this->children[(2 + class_offset)]->children.size(); ++i) {
|
||||
t_param_names.push_back(this->children[(2 + class_offset)]->children[i]->text);
|
||||
}
|
||||
|
||||
if (this->children.size() > 4) {
|
||||
guardnode = this->children[3];
|
||||
if (this->children.size() > (4 + class_offset)) {
|
||||
guardnode = this->children[(3 + class_offset)];
|
||||
}
|
||||
}
|
||||
else {
|
||||
//no parameters
|
||||
|
||||
if (this->children.size() > 3) {
|
||||
guardnode = this->children[2];
|
||||
if (this->children.size() > (3 + class_offset)) {
|
||||
guardnode = this->children[(2 + class_offset)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1432,8 +1448,9 @@ namespace chaiscript
|
||||
|
||||
try {
|
||||
const std::string & l_annotation = this->annotation?this->annotation->text:"";
|
||||
const std::string & class_name = this->children[0]->text;
|
||||
const std::string & function_name = this->children[1]->text;
|
||||
|
||||
const std::string & function_name = this->children[(1 + class_offset)]->text;
|
||||
|
||||
if (function_name == class_name) {
|
||||
t_ss.add(Proxy_Function
|
||||
(new dispatch::detail::Dynamic_Object_Constructor(class_name, Proxy_Function
|
||||
@@ -1478,22 +1495,28 @@ namespace chaiscript
|
||||
Attr_Decl_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||
AST_Node(t_ast_node_text, AST_Node_Type::Attr_Decl, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||
virtual ~Attr_Decl_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{
|
||||
try {
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
const auto &d = t_ss.get_parent_locals();
|
||||
const auto itr = d.find("_current_class_name");
|
||||
int class_offset = 0;
|
||||
if (itr != d.end()) class_offset = -1;
|
||||
std::string class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
|
||||
|
||||
try {
|
||||
t_ss.add(Proxy_Function
|
||||
(new dispatch::detail::Dynamic_Object_Function(
|
||||
this->children[0]->text,
|
||||
class_name,
|
||||
fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::Dynamic_Object::get_attr,
|
||||
std::placeholders::_1,
|
||||
this->children[1]->text
|
||||
this->children[(1 + class_offset)]->text
|
||||
)))
|
||||
)
|
||||
), this->children[1]->text);
|
||||
), this->children[(1 + class_offset)]->text);
|
||||
|
||||
}
|
||||
catch (const exception::reserved_word_error &) {
|
||||
throw exception::eval_error("Reserved word used as attribute '" + this->children[1]->text + "'");
|
||||
throw exception::eval_error("Reserved word used as attribute '" + this->children[(1 + class_offset)]->text + "'");
|
||||
} catch (const exception::name_conflict_error &e) {
|
||||
throw exception::eval_error("Attribute redefined '" + e.name() + "'");
|
||||
}
|
||||
|
@@ -1127,7 +1127,7 @@ namespace chaiscript
|
||||
}
|
||||
retval = true;
|
||||
m_input_pos = tmp;
|
||||
m_col += len;
|
||||
m_col += static_cast<int>(len);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -1175,7 +1175,7 @@ namespace chaiscript
|
||||
}
|
||||
retval = true;
|
||||
m_input_pos = tmp;
|
||||
m_col += len;
|
||||
m_col += static_cast<int>(len);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -1358,7 +1358,7 @@ namespace chaiscript
|
||||
/**
|
||||
* Reads a function definition from input
|
||||
*/
|
||||
bool Def() {
|
||||
bool Def(bool t_class_context = false) {
|
||||
bool retval = false;
|
||||
bool is_annotated = false;
|
||||
AST_NodePtr annotation;
|
||||
@@ -1410,7 +1410,7 @@ namespace chaiscript
|
||||
throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename);
|
||||
}
|
||||
|
||||
if (is_method) {
|
||||
if (is_method || t_class_context) {
|
||||
build_match(AST_NodePtr(new eval::Method_AST_Node()), prev_stack_top);
|
||||
}
|
||||
else {
|
||||
@@ -1555,6 +1555,35 @@ namespace chaiscript
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a class block from input
|
||||
*/
|
||||
bool Class() {
|
||||
bool retval = false;
|
||||
|
||||
size_t prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Keyword("class")) {
|
||||
retval = true;
|
||||
|
||||
if (!Id(true)) {
|
||||
throw exception::eval_error("Missing class name in definition", File_Position(m_line, m_col), *m_filename);
|
||||
}
|
||||
|
||||
|
||||
while (Eol()) {}
|
||||
|
||||
if (!Class_Block()) {
|
||||
throw exception::eval_error("Incomplete 'class' block", File_Position(m_line, m_col), *m_filename);
|
||||
}
|
||||
|
||||
build_match(AST_NodePtr(new eval::Class_AST_Node()), prev_stack_top);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a while block from input
|
||||
*/
|
||||
@@ -1737,6 +1766,28 @@ namespace chaiscript
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a curly-brace C-style class block from input
|
||||
*/
|
||||
bool Class_Block() {
|
||||
bool retval = false;
|
||||
|
||||
size_t prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Char('{')) {
|
||||
retval = true;
|
||||
|
||||
Class_Statements();
|
||||
if (!Char('}')) {
|
||||
throw exception::eval_error("Incomplete class block", File_Position(m_line, m_col), *m_filename);
|
||||
}
|
||||
|
||||
build_match(AST_NodePtr(new eval::Block_AST_Node()), prev_stack_top);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a curly-brace C-style block from input
|
||||
*/
|
||||
@@ -1875,12 +1926,20 @@ namespace chaiscript
|
||||
/**
|
||||
* Reads a variable declaration from input
|
||||
*/
|
||||
bool Var_Decl() {
|
||||
bool Var_Decl(bool t_class_context = false) {
|
||||
bool retval = false;
|
||||
|
||||
size_t prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Keyword("auto") || Keyword("var")) {
|
||||
if (t_class_context && (Keyword("attr") || Keyword("auto") || Keyword("var"))) {
|
||||
retval = true;
|
||||
|
||||
if (!Id(true)) {
|
||||
throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename);
|
||||
}
|
||||
|
||||
build_match(AST_NodePtr(new eval::Attr_Decl_AST_Node()), prev_stack_top);
|
||||
} else if (Keyword("auto") || Keyword("var")) {
|
||||
retval = true;
|
||||
|
||||
if (!(Reference() || Id(true))) {
|
||||
@@ -1888,8 +1947,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
build_match(AST_NodePtr(new eval::Var_Decl_AST_Node()), prev_stack_top);
|
||||
}
|
||||
else if (Keyword("attr")) {
|
||||
} else if (Keyword("attr")) {
|
||||
retval = true;
|
||||
|
||||
if (!Id(true)) {
|
||||
@@ -2262,6 +2320,44 @@ namespace chaiscript
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses statements allowed inside of a class block
|
||||
*/
|
||||
bool Class_Statements() {
|
||||
bool retval = false;
|
||||
|
||||
bool has_more = true;
|
||||
bool saw_eol = true;
|
||||
|
||||
while (has_more) {
|
||||
int prev_line = m_line;
|
||||
int prev_col = m_col;
|
||||
if (Def(true)) {
|
||||
if (!saw_eol) {
|
||||
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
|
||||
}
|
||||
has_more = true;
|
||||
retval = true;
|
||||
saw_eol = true;
|
||||
} else if (Var_Decl(true)) {
|
||||
if (!saw_eol) {
|
||||
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
|
||||
}
|
||||
has_more = true;
|
||||
retval = true;
|
||||
saw_eol = true;
|
||||
} else if (Eol()) {
|
||||
has_more = true;
|
||||
retval = true;
|
||||
saw_eol = true;
|
||||
} else {
|
||||
has_more = false;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Top level parser, starts parsing of all known parses
|
||||
*/
|
||||
@@ -2306,6 +2402,14 @@ namespace chaiscript
|
||||
retval = true;
|
||||
saw_eol = true;
|
||||
}
|
||||
else if (Class()) {
|
||||
if (!saw_eol) {
|
||||
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
|
||||
}
|
||||
has_more = true;
|
||||
retval = true;
|
||||
saw_eol = true;
|
||||
}
|
||||
else if (For()) {
|
||||
if (!saw_eol) {
|
||||
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
|
||||
|
@@ -40,9 +40,9 @@ def new(x) {
|
||||
eval(type_name(x))();
|
||||
}
|
||||
|
||||
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
|
||||
{
|
||||
eval(type_name(x))(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);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,11 +56,6 @@ def to_string(x) : call_exists(range, x) && !x.is_type("string"){
|
||||
"[" + x.join(", ") + "]";
|
||||
}
|
||||
|
||||
# Basic to_string function
|
||||
def to_string(x) {
|
||||
internal_to_string(x);
|
||||
}
|
||||
|
||||
# Prints to console with no carriage return
|
||||
def puts(x) {
|
||||
print_string(x.to_string());
|
||||
@@ -136,8 +131,8 @@ def insert_at(container, pos, x)
|
||||
|
||||
# Returns the reverse of the given container
|
||||
def reverse(container) {
|
||||
auto retval = new(container);
|
||||
auto r = range(container);
|
||||
auto retval := new(container);
|
||||
auto r := range(container);
|
||||
while (!r.empty()) {
|
||||
retval.push_back(r.back());
|
||||
r.pop_back();
|
||||
@@ -147,10 +142,16 @@ def reverse(container) {
|
||||
|
||||
# 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)
|
||||
{
|
||||
return clone(r);
|
||||
{
|
||||
clone(r);
|
||||
}
|
||||
|
||||
def range(r) : call_exists(range_internal, r)
|
||||
{
|
||||
var ri := range_internal(r);
|
||||
ri.get_var_attr("internal_obj") := r;
|
||||
ri;
|
||||
}
|
||||
|
||||
# The retro attribute that contains the underlying range
|
||||
attr retro::m_range;
|
||||
@@ -200,19 +201,19 @@ def retro::empty()
|
||||
|
||||
# Performs the second value function over the container first value
|
||||
def for_each(container, func) : call_exists(range, container) {
|
||||
var t_range = range(container);
|
||||
var t_range := range(container);
|
||||
while (!t_range.empty()) {
|
||||
func(t_range.front());
|
||||
t_range.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
def back_inserter(container) {
|
||||
bind(push_back, container, _);
|
||||
def back_inserter(container) {
|
||||
bind(push_back, container, _);
|
||||
}
|
||||
|
||||
def contains(container, item, compare_func) : call_exists(range, container) {
|
||||
auto t_range = range(container);
|
||||
auto t_range := range(container);
|
||||
while (!t_range.empty()) {
|
||||
if ( compare_func(t_range.front(), item) ) {
|
||||
return true;
|
||||
@@ -220,15 +221,15 @@ def contains(container, item, compare_func) : call_exists(range, container) {
|
||||
|
||||
t_range.pop_front();
|
||||
}
|
||||
return false;
|
||||
false;
|
||||
}
|
||||
|
||||
def contains(container, item) {
|
||||
return contains(container, item, eq)
|
||||
contains(container, item, eq)
|
||||
}
|
||||
|
||||
def map(container, func, inserter) : call_exists(range, container) {
|
||||
auto range = range(container);
|
||||
auto range := range(container);
|
||||
while (!range.empty()) {
|
||||
inserter(func(range.front()));
|
||||
range.pop_front();
|
||||
@@ -237,7 +238,7 @@ def map(container, func, inserter) : call_exists(range, container) {
|
||||
|
||||
# Performs the second value function over the container first value. Creates a new container with the results
|
||||
def map(container, func) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
map(container, func, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
@@ -245,7 +246,7 @@ def map(container, func) {
|
||||
# Performs the second value function over the container first value. Starts with initial and continues with each element.
|
||||
def foldl(container, func, initial) : call_exists(range, container){
|
||||
auto retval = initial;
|
||||
auto range = range(container);
|
||||
auto range := range(container);
|
||||
while (!range.empty()) {
|
||||
retval = (func(range.front(), retval));
|
||||
range.pop_front();
|
||||
@@ -266,8 +267,8 @@ def product(container) {
|
||||
# Returns a new container with the elements of the first value concatenated with the elements of the second value
|
||||
def concat(x, y) : call_exists(clone, x) {
|
||||
auto retval = x;
|
||||
auto inserter = back_inserter(retval);
|
||||
auto range = range(y);
|
||||
auto inserter := back_inserter(retval);
|
||||
auto range := range(y);
|
||||
while (!range.empty()) {
|
||||
inserter(range.front());
|
||||
range.pop_front();
|
||||
@@ -277,7 +278,7 @@ def concat(x, y) : call_exists(clone, x) {
|
||||
|
||||
|
||||
def take(container, num, inserter) : call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
auto i = num;
|
||||
while ((i > 0) && (!r.empty())) {
|
||||
inserter(r.front());
|
||||
@@ -289,14 +290,14 @@ def take(container, num, inserter) : call_exists(range, container) {
|
||||
|
||||
# Returns a new container with the given number of elements taken from the container
|
||||
def take(container, num) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
take(container, num, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
|
||||
|
||||
def take_while(container, f, inserter) : call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
while ((!r.empty()) && f(r.front())) {
|
||||
inserter(r.front());
|
||||
r.pop_front();
|
||||
@@ -306,14 +307,14 @@ def take_while(container, f, inserter) : call_exists(range, container) {
|
||||
|
||||
# Returns a new container with the given elements match the second value function
|
||||
def take_while(container, f) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
take_while(container, f, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
|
||||
|
||||
def drop(container, num, inserter) : call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
auto i = num;
|
||||
while ((i > 0) && (!r.empty())) {
|
||||
r.pop_front();
|
||||
@@ -328,14 +329,14 @@ def drop(container, num, inserter) : call_exists(range, container) {
|
||||
|
||||
# Returns a new container with the given number of elements dropped from the given container
|
||||
def drop(container, num) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
drop(container, num, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
|
||||
|
||||
def drop_while(container, f, inserter) : call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
while ((!r.empty())&& f(r.front())) {
|
||||
r.pop_front();
|
||||
}
|
||||
@@ -348,7 +349,7 @@ def drop_while(container, f, inserter) : call_exists(range, container) {
|
||||
|
||||
# Returns a new container with the given elements dropped that match the second value function
|
||||
def drop_while(container, f) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
drop_while(container, f, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
@@ -356,7 +357,7 @@ def drop_while(container, f) {
|
||||
|
||||
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.
|
||||
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
auto retval = r.front();
|
||||
r.pop_front();
|
||||
retval = func(retval, r.front());
|
||||
@@ -372,7 +373,7 @@ def reduce(container, func) : container.size() >= 2 && call_exists(range, contai
|
||||
# Returns a string of the elements in container delimited by the second value string
|
||||
def join(container, delim) {
|
||||
auto retval = "";
|
||||
auto range = range(container);
|
||||
auto range := range(container);
|
||||
if (!range.empty()) {
|
||||
retval += to_string(range.front());
|
||||
range.pop_front();
|
||||
@@ -387,7 +388,7 @@ def join(container, delim) {
|
||||
|
||||
|
||||
def filter(container, f, inserter) : call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
while (!r.empty()) {
|
||||
if (f(r.front())) {
|
||||
inserter(r.front());
|
||||
@@ -399,7 +400,7 @@ def filter(container, f, inserter) : call_exists(range, container) {
|
||||
|
||||
# Returns a new Vector which match the second value function
|
||||
def filter(container, f) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
filter(container, f, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
@@ -416,7 +417,7 @@ def generate_range(x, y, inserter) {
|
||||
|
||||
# Returns a new Vector which represents the range from the first value to the second value
|
||||
def generate_range(x, y) {
|
||||
auto retval = Vector();
|
||||
auto retval := Vector();
|
||||
generate_range(x,y,back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
@@ -429,8 +430,8 @@ def collate(x, y) {
|
||||
|
||||
|
||||
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) {
|
||||
auto r_x = range(x);
|
||||
auto r_y = range(y);
|
||||
auto r_x := range(x);
|
||||
auto r_y := range(y);
|
||||
while (!r_x.empty() && !r_y.empty()) {
|
||||
inserter(f(r_x.front(), r_y.front()));
|
||||
r_x.pop_front();
|
||||
@@ -441,7 +442,7 @@ def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y)
|
||||
|
||||
# Returns a new Vector which joins matching elements of the second and third value with the first value function
|
||||
def zip_with(f, x, y) {
|
||||
auto retval = Vector();
|
||||
auto retval := Vector();
|
||||
zip_with(f,x,y,back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
@@ -505,7 +506,7 @@ def string::trim() {
|
||||
|
||||
|
||||
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") {
|
||||
auto range = range(container);
|
||||
auto range := range(container);
|
||||
while (!range.empty()) {
|
||||
if (compare_func(range.front(), value)) {
|
||||
return range;
|
||||
@@ -513,12 +514,12 @@ def find(container, value, compare_func) : call_exists(range, container) && is_t
|
||||
range.pop_front();
|
||||
}
|
||||
}
|
||||
return range;
|
||||
range;
|
||||
}
|
||||
|
||||
|
||||
def find(container, value) {
|
||||
return find(container, value, eq)
|
||||
find(container, value, eq)
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,6 +1,16 @@
|
||||
Notes:
|
||||
=======
|
||||
Current Version: 5.3.1
|
||||
Current Version: 5.4.0
|
||||
|
||||
### Changes since 5.3.1
|
||||
* Decreased compile time and build size
|
||||
* Make "reflection" module built in (losing some of the time / build size gains)
|
||||
* Add new "class" syntax for ChaiScript defined methods and attributes see: [unittests/class.chai](unittests/class.chai) for examples
|
||||
* Minor performance enhancements
|
||||
* major to_string performance enhancements
|
||||
* Provide API for retrieving registered type name #124
|
||||
* Added strong reference to container to range object #132
|
||||
|
||||
|
||||
### Changes since 5.3.0
|
||||
* Add automatic conversion of arithmetic return types, following the same
|
||||
|
@@ -17,15 +17,15 @@
|
||||
#else
|
||||
|
||||
char *mystrdup (const char *s) {
|
||||
size_t len = strlen(s) + 1; // Space for length plus nul
|
||||
char *d = static_cast<char*>(malloc (len));
|
||||
size_t len = strlen(s); // Space for length plus nul
|
||||
char *d = static_cast<char*>(malloc (len+1));
|
||||
if (d == nullptr) return nullptr; // No memory
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
strcpy_s(d, len, s); // Copy the characters
|
||||
#else
|
||||
strncpy(d,s,len); // Copy the characters
|
||||
d[len] = '\0';
|
||||
#endif
|
||||
d[len] = '\0';
|
||||
return d; // Return the new string
|
||||
}
|
||||
|
||||
|
@@ -1,129 +0,0 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
#include <chaiscript/utility/utility.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
// MSVC doesn't like that we are using C++ return types from our C declared module
|
||||
// but this is the best way to do it for cross platform compatibility
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4190)
|
||||
#endif
|
||||
|
||||
|
||||
bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
||||
{
|
||||
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
|
||||
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf)
|
||||
{
|
||||
if (pf->get_parse_tree())
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
||||
{
|
||||
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
|
||||
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf)
|
||||
{
|
||||
if (pf->get_parse_tree())
|
||||
{
|
||||
return pf->get_parse_tree();
|
||||
} else {
|
||||
throw std::runtime_error("Function does not have a parse tree");
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Function does not have a parse tree");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef __llvm__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
|
||||
#endif
|
||||
|
||||
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflection()
|
||||
{
|
||||
chaiscript::ModulePtr m(new chaiscript::Module());
|
||||
|
||||
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
|
||||
m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
|
||||
|
||||
m->add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
|
||||
|
||||
chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
|
||||
|
||||
using namespace chaiscript;
|
||||
|
||||
chaiscript::utility::add_class<chaiscript::exception::eval_error>(*m,
|
||||
"eval_error",
|
||||
{ },
|
||||
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
|
||||
{fun(&chaiscript::exception::eval_error::call_stack), "call_stack"} }
|
||||
);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<chaiscript::File_Position>(*m,
|
||||
"File_Position",
|
||||
{ constructor<File_Position()>(),
|
||||
constructor<File_Position(int, int)>() },
|
||||
{ {fun(&File_Position::line), "line"},
|
||||
{fun(&File_Position::column), "column"} }
|
||||
);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<AST_Node>(*m,
|
||||
"AST_Node",
|
||||
{ },
|
||||
{ {fun(&AST_Node::text), "text"},
|
||||
{fun(&AST_Node::identifier), "identifier"},
|
||||
{fun(&AST_Node::filename), "filename"},
|
||||
{fun(&AST_Node::start), "start"},
|
||||
{fun(&AST_Node::end), "end"},
|
||||
{fun(&AST_Node::internal_to_string), "internal_to_string"},
|
||||
{fun(&AST_Node::children), "children"},
|
||||
{fun(&AST_Node::replace_child), "replace_child"}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<parser::ChaiScript_Parser>(*m,
|
||||
"ChaiScript_Parser",
|
||||
{ constructor<parser::ChaiScript_Parser ()>() },
|
||||
{ {fun(&parser::ChaiScript_Parser::parse), "parse"},
|
||||
{fun(&parser::ChaiScript_Parser::ast), "ast"} }
|
||||
);
|
||||
|
||||
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
#ifdef __llvm__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
@@ -1,4 +1,3 @@
|
||||
load_module("reflection")
|
||||
|
||||
def deep()
|
||||
{
|
||||
|
@@ -1,4 +1,3 @@
|
||||
load_module("reflection")
|
||||
var parser := ChaiScript_Parser()
|
||||
var parse_success = parser.parse("3 + 4", "INPUT")
|
||||
var a := parser.ast()
|
||||
|
27
unittests/class.chai
Normal file
27
unittests/class.chai
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
class Vector3
|
||||
{
|
||||
// you can use attr, auto or var in this context
|
||||
attr x
|
||||
auto y
|
||||
var z
|
||||
|
||||
def Vector3(x,y,z)
|
||||
{
|
||||
this.x = x
|
||||
this.y = y
|
||||
this.z = z
|
||||
}
|
||||
|
||||
def doSomething(mult)
|
||||
{
|
||||
return this.x * this.y * this.z * mult
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
auto v = Vector3(1,2,3)
|
||||
assert_equal(1, v.x)
|
||||
assert_equal(v.doSomething(2), 12)
|
||||
|
@@ -1,4 +1,3 @@
|
||||
load_module("reflection")
|
||||
|
||||
def deep()
|
||||
{
|
||||
|
@@ -1,4 +1,3 @@
|
||||
load_module("reflection")
|
||||
|
||||
try {
|
||||
eval("def `+`(x, y) \n { \n print(i); \n } \n \n var i = 10; \n \"1\" + 1;\n")
|
||||
|
@@ -2,3 +2,9 @@ auto x = [1, 2, 3, 4]
|
||||
auto r = range(x)
|
||||
r.pop_front()
|
||||
assert_equal(2, r.front());
|
||||
|
||||
// test with temporary vector for range
|
||||
auto q = range([1, 2, 3, 4])
|
||||
q.pop_front()
|
||||
assert_equal(2, q.front());
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
load_module("reflection")
|
||||
auto& parser = ChaiScript_Parser()
|
||||
auto parse_success = parser.parse("3 + 4", "INPUT")
|
||||
auto& a = parser.ast()
|
||||
|
22
unittests/type_name_test.cpp
Normal file
22
unittests/type_name_test.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Tests to make sure that the order in which function dispatches occur is correct
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <cstdlib>
|
||||
|
||||
class MyClass
|
||||
{
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
auto type = chaiscript::user_type<MyClass>();
|
||||
chai.add(type, "MyClass");
|
||||
|
||||
if (chai.get_type_name(type) == "MyClass" && chai.get_type_name<MyClass>() == "MyClass")
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user