// This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009, Jonathan Turner (jturner@minnow-lang.org) // and Jason Turner (lefticus@gmail.com) // http://www.chaiscript.com #ifndef __bootstrap_hpp #define __bootstrap_hpp__ #include "dispatchkit.hpp" #include "register_function.hpp" namespace chaiscript { namespace bootstrap { namespace detail { /** * Set of helper functions for common operators */ template Ret add(P1 p1, P2 p2) { return p1 + p2; } template Ret subtract(P1 p1, P2 p2) { return p1 - p2; } template Ret divide(P1 p1, P2 p2) { return p1 / p2; } template Ret multiply(P1 p1, P2 p2) { return p1 * p2; } template Ret modulus(P1 p1, P2 p2) { return p1 % p2; } template P1 &assign(P1 &p1, const P2 &p2) { return (p1 = p2); } template bool equals(P1 p1, P2 p2) { return p1 == p2; } template bool not_equals(P1 p1, P2 p2) { return p1 != p2; } template bool less_than(P1 p1, P2 p2) { return p1 < p2; } template bool greater_than(P1 p1, P2 p2) { return p1 > p2; } template bool less_than_equals(P1 p1, P2 p2) { return p1 <= p2; } template bool greater_than_equals(P1 p1, P2 p2) { return p1 >= p2; } template P1 ×equal(P1 &p1, const P2 &p2) { return (p1 *= p2); } template P1 ÷sequal(P1 &p1, const P2 &p2) { return (p1 /= p2); } template P1 &addsequal(P1 &p1, const P2 &p2) { return (p1 += p2); } template P1 &subtractsequal(P1 &p1, const P2 &p2) { return (p1 -= p2); } template P1 &prefixincrement(P1 &p1) { return (++p1); } template P1 &prefixdecrement(P1 &p1) { return (--p1); } template P1 &prefixnegate(P1 &p1) { return (p1); } template P1 &prefixnot(P1 &p1) { return (p1); } /* 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 ×equal_pod(P1 &p1, Boxed_POD_Value r) { if (r.m_isfloat) { return p1 *= P1(r.d); } else { return p1 *= P1(r.i); } } template P1 ÷sequal_pod(P1 &p1, Boxed_POD_Value r) { if (r.m_isfloat) { return p1 /= P1(r.d); } else { return p1 /= P1(r.i); } } template P1 &addsequal_pod(P1 &p1, Boxed_POD_Value r) { if (r.m_isfloat) { return p1 += P1(r.d); } else { return p1 += P1(r.i); } } template P1 &subtractsequal_pod(P1 &p1, Boxed_POD_Value r) { if (r.m_isfloat) { return p1 -= P1(r.d); } else { return p1 -= P1(r.i); } } } /** * Add canonical form of "=" for type T */ template ModulePtr oper_equals(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::equals), "="); return m; } /** * Add canonical form of "+" for type T */ template ModulePtr oper_add(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::add), "+"); return m; } /** * Add canonical form of "+=" for type T */ template ModulePtr oper_add_equals(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::addsequal), "+="); return m; } /** * Add canonical form of "-" for type T */ template ModulePtr oper_subtract(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::subtract), "-"); return m; } /** * Add canonical form of "/" for type T */ template ModulePtr oper_divide(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::divide), "/"); return m; } /** * Add canonical form of "*" for type T */ template ModulePtr oper_multiply(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::multiply), "*"); return m; } /** * Add canonical form of "!=" for type T */ template ModulePtr oper_not_equals(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::not_equals), "!="); return m; } /** * Add user defined assignment operator for T = U */ template ModulePtr oper_assign_overload(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::assign), "="); return m; } /** * Add canonical form of "=" for type T */ template ModulePtr oper_assign(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::assign), "="); return m; } /** * 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 canonical form of "<" for type T */ template ModulePtr oper_less_than(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::less_than), "<"); return m; } /** * Add canonical form of ">" for type T */ template ModulePtr oper_greater_than(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::greater_than), ">"); return m; } /** * Add canonical form of "<=" for type T */ template ModulePtr oper_less_than_equals(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::less_than_equals), "<="); return m; } /** * Add canonical form of ">=" for type T */ template ModulePtr oper_greater_than_equals(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::greater_than_equals), ">="); return m; } /** * Add user defined comparison operators for T and R. * Examples: T < R, T == R, etc. */ template ModulePtr opers_comparison_overload(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::equals), "=="); m->add(fun(&detail::not_equals), "!="); m->add(fun(&detail::less_than), "<"); m->add(fun(&detail::greater_than), ">"); m->add(fun(&detail::less_than_equals), "<="); m->add(fun(&detail::greater_than_equals), ">="); return m; } /** * Add canonical forms of all comparison operators for type T */ template ModulePtr opers_comparison(ModulePtr m = ModulePtr(new Module())) { opers_comparison_overload(m); return m; } /** * Add all arithmetic operators that return a type of Ret, taking * a lhs of T and a rhs of R, when possible. * examples: Ret = T + R; * ++T * T *= R; */ template ModulePtr opers_arithmetic_overload(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::add), "+"); m->add(fun(&detail::subtract), "-"); m->add(fun(&detail::divide), "/"); m->add(fun(&detail::multiply), "*"); m->add(fun(&detail::timesequal), "*="); m->add(fun(&detail::dividesequal), "/="); m->add(fun(&detail::subtractsequal), "-="); m->add(fun(&detail::addsequal), "+="); m->add(fun(&detail::prefixincrement), "++"); m->add(fun(&detail::prefixdecrement), "--"); m->add(fun(&detail::prefixnegate), "-"); m->add(fun(&detail::prefixnot), "!"); return m; } /** * Add arithmetic assign operators for POD types: * example: POD *= T, POD /= T */ template ModulePtr opers_arithmetic_modify_pod(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::timesequal_pod), "*="); m->add(fun(&detail::dividesequal_pod), "/="); m->add(fun(&detail::subtractsequal_pod), "-="); m->add(fun(&detail::addsequal_pod), "+="); 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; } /** * Add canonical forms of all arithmetic operators for type T */ template ModulePtr opers_arithmetic(ModulePtr m = ModulePtr(new Module())) { opers_arithmetic_overload(m); return m; } /** * to_string function for internal use. Uses ostream operator<< */ template std::string to_string(Input i) { return boost::lexical_cast(i); } /** * Boolean specialization of internal to_string function */ template<> std::string to_string(bool b) { if (b) { return "true"; } else { return "false"; } } /** * 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 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); oper_assign(m); oper_assign_pod(m); construct_pod(name, m); opers_arithmetic(m); opers_arithmetic_modify_pod(m); m->add(fun(&to_string), "to_string"); m->add(fun(&parse_string), "to_" + name); 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(boost::shared_ptr f) { return f; } /** * 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, boost::shared_ptr rhs) { lhs.assign(Boxed_Value(rhs)); return lhs; } /** * 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_unknown()) { return (lhs.assign(rhs)); } else { throw 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 comparison operators for POD types */ static void opers_comparison_pod(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::equals), "=="); m->add(fun(&detail::not_equals), "!="); m->add(fun(&detail::less_than), "<"); m->add(fun(&detail::greater_than), ">"); m->add(fun(&detail::less_than_equals), "<="); m->add(fun(&detail::greater_than_equals), ">="); } /** * Add all arithmetic operators for PODs */ static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&detail::add), "+"); m->add(fun(&detail::subtract), "-"); m->add(fun(&detail::divide), "/"); m->add(fun(&detail::multiply), "*"); } /** * 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 arity_error(params.size(), 2); } Proxy_Function f = boxed_cast(params[0]); return Boxed_Value(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 arity_error(params.size(), 1); } Proxy_Function f = boxed_cast(params[0]); return Boxed_Value(f->call_match(std::vector(params.begin() + 1, params.end()))); } 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(); } 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"); basic_constructors("bool", m); oper_assign(m); oper_assign(m); m->add(fun(&to_string), "internal_to_string"); m->add(fun(&to_string), "internal_to_string"); m->add(fun(&unknown_assign), "="); m->add(fun(&throw_exception), "throw"); m->add(fun(&what), "what"); bootstrap_pod_type("double", m); bootstrap_pod_type("int", m); bootstrap_pod_type("size_t", m); bootstrap_pod_type("char", m); bootstrap_pod_type("int64_t", m); opers_comparison_pod(m); opers_arithmetic_pod(m); m->add(fun(&detail::modulus), "%"); 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_clone), "clone"); m->add(fun(&ptr_assign), "="); 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