// This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef __bootstrap_hpp #define __bootstrap_hpp__ #include "dispatchkit.hpp" #include "dynamic_object.hpp" #include "register_function.hpp" #include "operators.hpp" #include "boxed_pod_value.hpp" #include namespace chaiscript { namespace bootstrap { namespace detail { /* Special helpers for generating generic "POD" type operators * The POD operators are needed for general support of C++ POD * types without iterating out all possible combinations of operators * (<, >, +, +=, *=, \=, -, <=, >=, ==) and types * (char, uint8_t, int8_t, uint16_t, int16_t...) */ template P1 &assign_pod(P1 &p1, Boxed_POD_Value v) { if (v.m_isfloat) { return (p1 = P1(v.d)); } else { return (p1 = P1(v.i)); } } template P1 construct_pod(Boxed_POD_Value v) { if (v.m_isfloat) { return P1(v.d); } else { return P1(v.i); } } template P1 &assign_bitwise_and_pod(P1 &p1, Boxed_POD_Value r) { if (!r.m_isfloat) { return p1 &= P1(r.i); } throw exception::bad_boxed_cast("&= only valid for integer types"); } template P1 &assign_xor_pod(P1 &p1, Boxed_POD_Value r) { if (!r.m_isfloat) { return p1 ^= P1(r.i); } throw exception::bad_boxed_cast("^= only valid for integer types"); } template P1 &assign_bitwise_or_pod(P1 &p1, Boxed_POD_Value r) { if (!r.m_isfloat) { return p1 |= P1(r.i); } throw exception::bad_boxed_cast("&= only valid for integer types"); } template P1 &assign_difference_pod(P1 &p1, Boxed_POD_Value r) { if (r.m_isfloat) { return p1 -= P1(r.d); } else { return p1 -= P1(r.i); } } template P1 &assign_left_shift_pod(P1 &p1, Boxed_POD_Value r) { if (!r.m_isfloat) { return p1 <<= P1(r.i); } throw exception::bad_boxed_cast("<<= only valid for integer types"); } template P1 &assign_product_pod(P1 &p1, Boxed_POD_Value r) { if (r.m_isfloat) { return p1 *= P1(r.d); } else { return p1 *= P1(r.i); } } template P1 &assign_quotient_pod(P1 &p1, Boxed_POD_Value r) { if (r.m_isfloat) { return p1 /= P1(r.d); } else { return p1 /= P1(r.i); } } template P1 &assign_remainder_pod(P1 &p1, Boxed_POD_Value r) { if (!r.m_isfloat) { return p1 %= P1(r.i); } throw exception::bad_boxed_cast("%= only valid for integer types"); } template P1 &assign_right_shift_pod(P1 &p1, Boxed_POD_Value r) { if (!r.m_isfloat) { return p1 >>= P1(r.i); } throw exception::bad_boxed_cast(">>= only valid for integer types"); } template P1 &assign_sum_pod(P1 &p1, Boxed_POD_Value r) { if (r.m_isfloat) { return p1 += P1(r.d); } else { return p1 += P1(r.i); } } } template ModulePtr opers_comparison(ModulePtr m = ModulePtr(new Module())) { operators::equal(m); operators::greater_than(m); operators::greater_than_equal(m); operators::less_than(m); operators::less_than_equal(m); operators::not_equal(m); return m; } template ModulePtr opers_integer_arithmetic(ModulePtr m = ModulePtr(new Module())) { operators::assign_bitwise_and(m); operators::assign_xor(m); operators::assign_bitwise_or(m); operators::assign_difference(m); operators::assign_left_shift(m); operators::assign_product(m); operators::assign_quotient(m); operators::assign_remainder(m); operators::assign_right_shift(m); operators::assign_sum(m); operators::prefix_decrement(m); operators::prefix_increment(m); operators::addition(m); operators::unary_plus(m); operators::subtraction(m); operators::unary_minus(m); operators::bitwise_and(m); operators::bitwise_compliment(m); operators::bitwise_xor(m); operators::bitwise_or(m); operators::division(m); operators::left_shift(m); operators::multiplication(m); operators::remainder(m); operators::right_shift(m); return m; } template ModulePtr opers_float_arithmetic(ModulePtr m = ModulePtr(new Module())) { operators::assign_difference(m); operators::assign_product(m); operators::assign_quotient(m); operators::assign_sum(m); operators::addition(m); operators::unary_plus(m); operators::subtraction(m); operators::unary_minus(m); operators::division(m); operators::multiplication(m); return m; } /** * Add a copy constructor for type T */ template ModulePtr copy_constructor(const std::string &type, ModulePtr m = ModulePtr(new Module())) { m->add(constructor(), type); return m; } /** * Add default and copy constructors for type T */ template ModulePtr basic_constructors(const std::string &type, ModulePtr m = ModulePtr(new Module())) { m->add(constructor(), type); copy_constructor(type, m); return m; } /** * Add POD type constructor for type T. ie: T = type(POD) */ template ModulePtr construct_pod(const std::string &type, ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::construct_pod), type); return m; } /** * add user defined single parameter constructor for type T. * T = type(const U &) */ template ModulePtr constructor_overload(const std::string &type, ModulePtr m = ModulePtr(new Module())) { m->add(constructor(), type); return m; } /** * to_string function for internal use. Uses ostream operator<< */ template std::string to_string(Input i) { return boost::lexical_cast(i); } /** * Internal function for converting from a string to a value * uses ostream operator >> to perform the conversion */ template Input parse_string(const std::string &i) { return boost::lexical_cast(i); } /** * Add assignment operator for T = POD. */ template ModulePtr oper_assign_pod(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::assign_pod), "="); return m; } /** * Add all common functions for a POD type. All operators, and * common conversions */ template ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module())) { m->add(user_type(), name); basic_constructors(name, m); operators::assign(m); oper_assign_pod(m); construct_pod(name, m); m->add(fun(&detail::assign_sum_pod), "+="); m->add(fun(&detail::assign_difference_pod), "-="); m->add(fun(&detail::assign_product_pod), "*="); m->add(fun(&detail::assign_quotient_pod), "/="); m->add(fun(&to_string), "to_string"); m->add(fun(&parse_string), "to_" + name); return m; } /** * Add all common functions for a POD type. All operators, and * common conversions */ template ModulePtr bootstrap_integer_type(const std::string &name, ModulePtr m = ModulePtr(new Module())) { bootstrap_pod_type(name, m); m->add(fun(&detail::assign_bitwise_and_pod), "&="); m->add(fun(&detail::assign_xor_pod), "^="); m->add(fun(&detail::assign_bitwise_or_pod), "|="); m->add(fun(&detail::assign_left_shift_pod), "<<="); m->add(fun(&detail::assign_remainder_pod), "%="); m->add(fun(&detail::assign_right_shift_pod), ">>="); opers_integer_arithmetic(m); return m; } /** * Add all common functions for a POD type. All operators, and * common conversions */ template ModulePtr bootstrap_float_type(const std::string &name, ModulePtr m = ModulePtr(new Module())) { bootstrap_pod_type(name, m); opers_float_arithmetic(m); return m; } /** * "clone" function for a shared_ptr type. This is used in the case * where you do not want to make a deep copy of an object during cloning * but want to instead maintain the shared_ptr. It is needed internally * for handling of Proxy_Function object (that is, * function variables. */ template boost::shared_ptr shared_ptr_clone(const boost::shared_ptr &p) { return p; } /** * Specific version of shared_ptr_clone just for Proxy_Functions */ template boost::shared_ptr::type> shared_ptr_unconst_clone(const boost::shared_ptr::type> &p) { return boost::const_pointer_cast::type>(p); } /** * Assignment function for shared_ptr objects, does not perform a copy of the * object pointed to, instead maintains the shared_ptr concept. * Similar to shared_ptr_clone. Used for Proxy_Function. */ template Boxed_Value ptr_assign(Boxed_Value lhs, const boost::shared_ptr &rhs) { if (lhs.is_undef() || (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info::get()))) { lhs.assign(Boxed_Value(rhs)); return lhs; } else { throw exception::bad_boxed_cast("type mismatch in pointer assignment"); } } /** * Class consisting of only static functions. All default bootstrapping occurs * from this class. */ class Bootstrap { private: /** * Function allowing for assignment of an unknown type to any other value */ static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) { if (lhs.is_undef()) { return (lhs.assign(rhs)); } else { throw exception::bad_boxed_cast("boxed_value has a set type already"); } } static void print(const std::string &s) { std::cout << s; } static void println(const std::string &s) { std::cout << s << std::endl; } /** * Add all arithmetic operators for PODs */ static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&operators::addition), "+"); m->add(fun(&operators::subtraction), "-"); m->add(fun(&operators::bitwise_and), "&"); m->add(fun(&operators::bitwise_xor), "^"); m->add(fun(&operators::bitwise_or), "|"); m->add(fun(&operators::division), "/"); m->add(fun(&operators::left_shift), "<<"); m->add(fun(&operators::multiplication), "*"); m->add(fun(&operators::remainder), "%"); m->add(fun(&operators::right_shift), ">>"); } /** * Create a bound function object. The first param is the function to bind * the remaining parameters are the args to bind into the * result */ static Boxed_Value bind_function(const std::vector ¶ms) { if (params.size() < 2) { throw exception::arity_error(static_cast(params.size()), 2); } Const_Proxy_Function f = boxed_cast(params[0]); return Boxed_Value(Const_Proxy_Function(new Bound_Function(f, std::vector(params.begin() + 1, params.end())))); } /** * Returns true if a call can be made that consists of the first parameter * (the function) with the remaining parameters as its arguments. */ static Boxed_Value call_exists(const std::vector ¶ms) { if (params.size() < 1) { throw exception::arity_error(static_cast(params.size()), 1); } Const_Proxy_Function f = boxed_cast(params[0]); return Boxed_Value(f->call_match(std::vector(params.begin() + 1, params.end()))); } static bool has_guard(const Const_Proxy_Function &t_pf) { boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); if (pf) { return pf->get_guard(); } else { return false; } } static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) { boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); if (pf) { if (pf->get_guard()) { return pf->get_guard(); } else { throw std::runtime_error("Function does not have a guard"); } } else { throw std::runtime_error("Function does not have a guard"); } } static void throw_exception(const Boxed_Value &bv) { throw bv; } static boost::shared_ptr bootstrap2(boost::shared_ptr e = boost::shared_ptr (new Dispatch_Engine())) { e->add(user_type(), "void"); return e; } static std::string what(const std::exception &e) { return e.what(); } /** * Boolean specialization of internal to_string function */ static std::string bool_to_string(bool b) { if (b) { return "true"; } else { return "false"; } } template static std::vector do_return_boxed_value_vector(FunctionType f, const Proxy_Function_Base *b) { typedef typename boost::function_types::result_type::type Vector; Vector v = (b->*f)(); std::vector vbv; for (typename Vector::const_iterator itr = v.begin(); itr != v.end(); ++itr) { vbv.push_back(const_var(*itr)); } return vbv; } template static boost::function (const Proxy_Function_Base*)> return_boxed_value_vector(const Function &f) { return boost::bind(&do_return_boxed_value_vector, f, _1); } public: /** * perform all common bootstrap functions for std::string, void and POD types */ static ModulePtr bootstrap(ModulePtr m = ModulePtr(new Module())) { m->add(user_type(), "void"); m->add(user_type(), "bool"); m->add(user_type(), "Object"); m->add(user_type(), "PODObject"); m->add(user_type(), "function"); m->add(user_type(), "exception"); m->add(fun(&Proxy_Function_Base::get_arity), "get_arity"); m->add(fun(&Proxy_Function_Base::annotation), "get_annotation"); m->add(fun(&Proxy_Function_Base::operator()), "call"); m->add(fun(&Proxy_Function_Base::operator==), "=="); m->add(fun(return_boxed_value_vector(&Proxy_Function_Base::get_param_types)), "get_param_types"); m->add(fun(return_boxed_value_vector(&Proxy_Function_Base::get_contained_functions)), "get_contained_functions"); m->add(user_type(), "runtime_error"); m->add(constructor(), "runtime_error"); m->add(fun(boost::function(&what)), "what"); m->add(user_type(), "Dynamic_Object"); m->add(constructor(), "Dynamic_Object"); m->add(fun(&Dynamic_Object::get_type_name), "get_type_name"); m->add(fun(&Dynamic_Object::get_attrs), "get_attrs"); m->add(fun(&Dynamic_Object::get_attr), "get_attr"); m->eval("def Dynamic_Object::clone() { var 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->add(fun(&has_guard), "has_guard"); m->add(fun(&get_guard), "get_guard"); m->add(fun(&Boxed_Value::is_undef), "is_var_undef"); m->add(fun(&Boxed_Value::is_null), "is_var_null"); 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_type), "is_type"); m->add(fun(&Boxed_Value::get_type_info), "get_type_info"); m->add(user_type(), "Type_Info"); operators::equal(m); m->add(fun(&Type_Info::is_const), "is_type_const"); m->add(fun(&Type_Info::is_reference), "is_type_reference"); m->add(fun(&Type_Info::is_void), "is_type_void"); m->add(fun(&Type_Info::is_undef), "is_type_undef"); m->add(fun(&Type_Info::is_pointer), "is_type_pointer"); m->add(fun(&Type_Info::name), "cpp_name"); m->add(fun(&Type_Info::bare_name), "cpp_bare_name"); m->add(fun(&Type_Info::bare_equal), "bare_equal"); typedef bool (Type_Info::*typeinfocompare)(const Type_Info &) const; m->add(fun(typeinfocompare(&Type_Info::operator==)), "=="); m->add(fun(&Type_Info::bare_equal), "bare_equal"); basic_constructors("bool", m); operators::assign(m); m->add(fun(&to_string), "internal_to_string"); m->add(fun(&Bootstrap::bool_to_string), "internal_to_string"); m->add(fun(&unknown_assign), "="); m->add(fun(&throw_exception), "throw"); m->add(fun(&what), "what"); bootstrap_float_type("double", m); bootstrap_integer_type("int", m); bootstrap_integer_type("size_t", m); bootstrap_integer_type("char", m); bootstrap_integer_type("int64_t", m); operators::logical_compliment(m); opers_comparison(m); opers_arithmetic_pod(m); m->add(fun(&print), "print_string"); m->add(fun(&println), "println_string"); m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&bind_function, _1))), "bind"); m->add(fun(&shared_ptr_unconst_clone), "clone"); m->add(fun(&ptr_assign::type>), "="); m->add(fun(&ptr_assign::type>), "="); m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&call_exists, _1))), "call_exists"); m->add(fun(&type_match), "type_match"); return m; } }; } } #endif