diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index b5ed774..28e4a93 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -21,7 +21,7 @@ #include "dispatchkit/bootstrap.hpp" #include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/function_call.hpp" - +#include "dispatchkit/dynamic_object.hpp" #ifdef BOOST_HAS_DECLSPEC #define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport) diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp new file mode 100644 index 0000000..f0a9a72 --- /dev/null +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -0,0 +1,213 @@ +#ifndef __DYNAMIC_OBJECT_HPP__ +#define __DYNAMIC_OBJECT_HPP__ + +namespace chaiscript +{ + class Dynamic_Object + { + public: + Dynamic_Object(const std::string &t_type_name) + : m_type_name(t_type_name) + { + } + + std::string get_type_name() const + { + return m_type_name; + } + + Boxed_Value get_attr(const std::string &t_attr_name) + { + return m_attrs[t_attr_name]; + } + + private: + std::string m_type_name; + + std::map m_attrs; + }; + + Boxed_Value dynamic_object_attribute(const std::string &t_type_name, const std::string &t_attr_name, + Dynamic_Object &t_do) + { + if (t_do.get_type_name() != t_type_name) + { + throw bad_boxed_cast("Dynamic object type mismatch"); + } + + return t_do.get_attr(t_attr_name); + } + + bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name) + { + try { + const Dynamic_Object &d = boxed_cast(bv); + return d.get_type_name() == name; + } catch (const std::bad_cast &) { + return false; + } + } + + bool dynamic_object_typename_match(const std::vector &bvs, const std::string &name) + { + if (bvs.size() > 0) + { + return dynamic_object_typename_match(bvs.front(), name); + } else { + return false; + } + } + + /** + * A Proxy_Function implementation designed for calling a function + * that is automatically guarded based on the first param based on the + * param's type name + */ + class Dynamic_Object_Function : public Proxy_Function_Base + { + public: + Dynamic_Object_Function( + const std::string &t_type_name, + const Proxy_Function &t_func) + : Proxy_Function_Base(t_func->get_param_types()), + m_type_name(t_type_name), m_func(t_func) + { + assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) + && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); + } + + virtual ~Dynamic_Object_Function() {} + + virtual bool operator==(const Proxy_Function_Base &f) const + { + try + { + const Dynamic_Object_Function &df = dynamic_cast(f); + return df.m_type_name == m_type_name && (*df.m_func) == (*m_func); + } catch (const std::bad_cast &) { + return false; + } + } + + virtual bool call_match(const std::vector &vals) const + { + if (dynamic_object_typename_match(vals, m_type_name)) + { + return m_func->call_match(vals); + } else { + return false; + } + } + + virtual Boxed_Value operator()(const std::vector ¶ms) + { + if (dynamic_object_typename_match(params, m_type_name)) + { + return (*m_func)(params); + } else { + throw guard_error(); + } + } + + virtual int get_arity() const + { + return m_func->get_arity(); + } + + virtual std::string annotation() const + { + return m_func->annotation(); + } + + private: + std::string m_type_name; + Proxy_Function m_func; + + }; + + + /** + * A Proxy_Function implementation designed for creating a new + * Dynamic_Object + * that is automatically guarded based on the first param based on the + * param's type name + */ + class Dynamic_Object_Constructor : public Proxy_Function_Base + { + public: + Dynamic_Object_Constructor( + const std::string &t_type_name, + const Proxy_Function &t_func) + : Proxy_Function_Base(build_type_list(t_func->get_param_types())), + m_type_name(t_type_name), m_func(t_func) + { + assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) + && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); + } + + static std::vector build_type_list(const std::vector &tl) + { + std::vector::const_iterator begin = tl.begin(); + std::vector::const_iterator end = tl.end(); + + if (begin != end) + { + ++begin; + } + + return std::vector(begin, end); + } + + virtual ~Dynamic_Object_Constructor() {} + + virtual bool operator==(const Proxy_Function_Base &f) const + { + try + { + const Dynamic_Object_Constructor &dc = dynamic_cast(f); + return dc.m_type_name == m_type_name && (*dc.m_func) == (*m_func); + } catch (const std::bad_cast &) { + return false; + } + } + + virtual bool call_match(const std::vector &vals) const + { + std::vector new_vals; + new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name))); + new_vals.insert(new_vals.end(), vals.begin(), vals.end()); + + return m_func->call_match(new_vals); + } + + virtual Boxed_Value operator()(const std::vector ¶ms) + { + std::vector new_params; + chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name)); + new_params.push_back(bv); + new_params.insert(new_params.end(), params.begin(), params.end()); + + (*m_func)(new_params); + + return bv; + } + + virtual int get_arity() const + { + // "this" is not considered part of the arity + return m_func->get_arity() - 1; + } + + virtual std::string annotation() const + { + return m_func->annotation(); + } + + private: + std::string m_type_name; + Proxy_Function m_func; + + }; +} +#endif + diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 74a3ae5..38d789a 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -251,7 +251,6 @@ namespace chaiscript int m_arity; std::string m_description; Proxy_Function m_guard; - std::vector m_types; }; /** diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index be838ff..f59ce68 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -464,6 +464,13 @@ namespace chaiscript engine.add(Proxy_Function( new Dynamic_Proxy_Function(boost::bind(&ChaiScript_System::internal_eval, boost::ref(*this), _1), 1)), "eval"); + + engine.add(user_type(), "Dynamic_Object"); + engine.add(chaiscript::bootstrap::copy_constructor("Dynamic_Object")); + + + + do_eval(chaiscript_prelude, "standard prelude"); } diff --git a/src/example.cpp b/src/example.cpp index 9b3f7aa..8b87630 100644 --- a/src/example.cpp +++ b/src/example.cpp @@ -22,6 +22,18 @@ void log(const std::string &module, const std::string &msg) std::cout << "[" << boost::posix_time::microsec_clock::local_time() << "] <" << module << "> " << msg << std::endl; } + +void hello_world(const chaiscript::Boxed_Value &o) +{ + std::cout << "Hello World" << std::endl; +} + +void hello_constructor(const chaiscript::Boxed_Value &o) +{ + std::cout << "Hello Constructor" << std::endl; +} + + struct System { std::map > m_callbacks; @@ -130,7 +142,18 @@ int main(int argc, char *argv[]) { chai.add(bootstrap::vector_type >("IntVector")); -// chai("dump_system()"); + // Test ability to register a function that excepts a shared_ptr version of a type chai("take_shared_ptr(\"Hello World as a shared_ptr\");"); + + + //Dynamic objects test + chai.add(chaiscript::Proxy_Function(new Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world"); + chai.add(chaiscript::Proxy_Function(new Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType"); + chai.add(fun(boost::function(boost::bind(&dynamic_object_attribute, "TestType", "attr", _1))), "attr"); + + chai.eval("var x = TestType()"); + chai.eval("x.attr = \"hi\""); + chai.eval("print(x.attr)"); + chai.eval("x.hello_world()"); }