diff --git a/CMakeLists.txt b/CMakeLists.txt index d2741e5..3479058 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ include(cmake/version.cmake) load_git_properties(cpptcl ${CMAKE_BINARY_DIR}/generated) set(CPPTCL_VERSION 2.2.5) +set(CMAKE_CXX_STANDARD 17) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to Release as none was specified.") @@ -68,19 +69,10 @@ list(APPEND SRCS ${CMAKE_BINARY_DIR}/generated/cpptcl_version.cpp) list(APPEND HDRS ${cpptcl_SOURCE_DIR}/cpptcl/cpptcl.h) list(APPEND HDRS ${cpptcl_SOURCE_DIR}/cpptcl/cpptcl_object.h) list(APPEND HDRS ${cpptcl_SOURCE_DIR}/cpptcl/version.h) -list(APPEND HDRS_DETAILS ${cpptcl_SOURCE_DIR}/cpptcl/details/callbacks.h) -list(APPEND HDRS_DETAILS ${cpptcl_SOURCE_DIR}/cpptcl/details/callbacks_v.h) -list(APPEND HDRS_DETAILS ${cpptcl_SOURCE_DIR}/cpptcl/details/constructors.h) -list(APPEND HDRS_DETAILS ${cpptcl_SOURCE_DIR}/cpptcl/details/conversions.h) -list(APPEND HDRS_DETAILS ${cpptcl_SOURCE_DIR}/cpptcl/details/dispatchers.h) -list(APPEND HDRS_DETAILS ${cpptcl_SOURCE_DIR}/cpptcl/details/metahelpers.h) -list(APPEND HDRS_DETAILS ${cpptcl_SOURCE_DIR}/cpptcl/details/methods.h) -list(APPEND HDRS_DETAILS ${cpptcl_SOURCE_DIR}/cpptcl/details/methods_v.h) -list(APPEND HDRS_DETAILS ${cpptcl_SOURCE_DIR}/cpptcl/details/bind.h) add_library(cpptcl SHARED ${SRCS} ${HDRS} ${HDRS_DETAILS}) add_library(cpptcl::cpptcl ALIAS cpptcl) -target_compile_features(cpptcl PUBLIC cxx_std_11) +target_compile_features(cpptcl PUBLIC cxx_std_17) set_target_properties(cpptcl PROPERTIES CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON) @@ -94,7 +86,7 @@ target_link_libraries(cpptcl PUBLIC ${TCL_STUB_LIBRARY}) add_library(cpptcl_static STATIC ${SRCS} ${HDRS} ${HDRS_DETAILS}) add_library(cpptcl::cpptcl_static ALIAS cpptcl_static) -target_compile_features(cpptcl_static PUBLIC cxx_std_11) +target_compile_features(cpptcl_static PUBLIC cxx_std_17) set_target_properties(cpptcl_static PROPERTIES POSITION_INDEPENDENT_CODE ON CXX_EXTENSIONS OFF @@ -108,7 +100,7 @@ target_include_directories(cpptcl_static PUBLIC ${TCL_INCLUDE_PATH}) add_library(cpptcl_runtime STATIC ${cpptcl_SOURCE_DIR}/cpptcl_runtime.c) add_library(cpptcl::cpptcl_runtime ALIAS cpptcl_runtime) -target_compile_features(cpptcl_runtime PUBLIC cxx_std_11) +target_compile_features(cpptcl_runtime PUBLIC cxx_std_17) set_target_properties(cpptcl_runtime PROPERTIES POSITION_INDEPENDENT_CODE ON CXX_EXTENSIONS OFF diff --git a/cpptcl.cc b/cpptcl.cc index 9cef8ab..d399850 100644 --- a/cpptcl.cc +++ b/cpptcl.cc @@ -13,93 +13,92 @@ #include #include +#include + +#include + #include "cpptcl/cpptcl.h" using namespace Tcl; using namespace Tcl::details; using namespace std; -result::result(Tcl_Interp *interp) : interp_(interp) {} - -result::operator bool() const { - Tcl_Obj *obj = Tcl_GetObjResult(interp_); - - int val, cc; - cc = Tcl_GetBooleanFromObj(interp_, obj, &val); - if (cc != TCL_OK) { - throw tcl_error(interp_); - } - - return static_cast(val); -} - -result::operator double() const { - Tcl_Obj *obj = Tcl_GetObjResult(interp_); - - double val; - int cc = Tcl_GetDoubleFromObj(interp_, obj, &val); - if (cc != TCL_OK) { - throw tcl_error(interp_); - } - - return val; -} - -result::operator int() const { - Tcl_Obj *obj = Tcl_GetObjResult(interp_); - - int val, cc; - cc = Tcl_GetIntFromObj(interp_, obj, &val); - if (cc != TCL_OK) { - throw tcl_error(interp_); - } +typedef std::pair, policies> callback_handler_client_data_t; +struct constructor_handler_client_data_t { + callback_base * cb; + class_handler_base * chb; + interpreter * interp; +}; + +struct method_handler_client_data { + void * obj; + class_handler_base * chb; + bool unroll; + Tcl_Interp * interp; + interpreter * tcli; +}; + +struct managed_method_handler_client_data { + void * obj; + callback_base * cb; + interpreter * interp; +}; - return val; -} - -result::operator long() const { - Tcl_Obj *obj = Tcl_GetObjResult(interp_); - - long val; - int cc; - cc = Tcl_GetLongFromObj(interp_, obj, &val); - if (cc != TCL_OK) { - throw tcl_error(interp_); - } - - return val; -} +result::result(Tcl_Interp *interp) : interp_(interp) {} +result::operator bool() const { return tcl_cast::from(interp_, Tcl_GetObjResult(interp_)); } +result::operator double() const { return tcl_cast::from(interp_, Tcl_GetObjResult(interp_)); } +result::operator int() const { return tcl_cast::from(interp_, Tcl_GetObjResult(interp_)); } +result::operator long() const { return tcl_cast::from(interp_, Tcl_GetObjResult(interp_)); } result::operator string() const { Tcl_Obj *obj = Tcl_GetObjResult(interp_); return Tcl_GetString(obj); } +result::operator object() const { object ret(Tcl_GetObjResult(interp_)); return ret; } //ret.set_interp(interp_); return ret; } -result::operator object() const { return object(Tcl_GetObjResult(interp_)); } - -void details::set_result(Tcl_Interp *interp, bool b) { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(b)); } - -void details::set_result(Tcl_Interp *interp, int i) { Tcl_SetObjResult(interp, Tcl_NewIntObj(i)); } - -void details::set_result(Tcl_Interp *interp, long i) { Tcl_SetObjResult(interp, Tcl_NewLongObj(i)); } - -void details::set_result(Tcl_Interp *interp, double d) { Tcl_SetObjResult(interp, Tcl_NewDoubleObj(d)); } +void result::reset() { + Tcl_ResetResult(interp_); +} +void details::set_result(Tcl_Interp *interp, bool b ) { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(b)); } +void details::set_result(Tcl_Interp *interp, int i ) { Tcl_SetObjResult(interp, Tcl_NewIntObj(i)); } +void details::set_result(Tcl_Interp *interp, long i ) { Tcl_SetObjResult(interp, Tcl_NewLongObj(i)); } +void details::set_result(Tcl_Interp *interp, double d ) { Tcl_SetObjResult(interp, Tcl_NewDoubleObj(d)); } void details::set_result(Tcl_Interp *interp, string const &s) { Tcl_SetObjResult(interp, Tcl_NewStringObj(s.data(), static_cast(s.size()))); } - void details::set_result(Tcl_Interp *interp, void *p) { ostringstream ss; - ss << 'p' << p; + ss << interpreter::object_namespace_name << "::" << p; string s(ss.str()); - - Tcl_SetObjResult(interp, Tcl_NewStringObj(s.data(), static_cast(s.size()))); + Tcl_Obj * to = Tcl_NewStringObj(s.data(), static_cast(s.size())); + to->internalRep.otherValuePtr = nullptr; + Tcl_SetObjResult(interp, to); +} +void details::set_result(Tcl_Interp *interp, named_pointer_result p) { + Tcl_Obj * to; + if (p.name.empty()) { + ostringstream ss; + ss << interpreter::object_namespace_name << "::" << p.p; + string s(ss.str()); + to = Tcl_NewStringObj(s.data(), static_cast(s.size())); + } else { + to = Tcl_NewStringObj(p.name.data(), p.name.size()); + } + to->internalRep.otherValuePtr = p.p; + Tcl_SetObjResult(interp, to); } void details::set_result(Tcl_Interp *interp, object const &o) { Tcl_SetObjResult(interp, o.get_object()); } -void details::check_params_no(int objc, int required, const std::string &message) { +void details::check_params_no(int objc, int required, int maximum, const std::string &message) { if (objc < required) { - throw tcl_error(message); + std::ostringstream oss; + oss << "too few arguments: " << objc << " given, " << required << " required"; + throw tcl_error(oss.str()); + } + if (maximum != -1 && objc > maximum) { + std::ostringstream oss; + oss << "too many arguments: " << objc << " given, " << maximum << " allowed"; + throw tcl_error(oss.str()); } } @@ -107,141 +106,34 @@ object details::get_var_params(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv object o; if (pol.variadic_) { - check_params_no(objc, from, pol.usage_); + check_params_no(objc, from, -1, pol.usage_); o.assign(objv + from, objv + objc); } else { - check_params_no(objc, from + 1, pol.usage_); + check_params_no(objc, from + 1, from + 1, pol.usage_); o.assign(objv[from]); } - o.set_interp(interp); + //o.set_interp(interp); return o; } namespace // anonymous { -// map of polymorphic callbacks -typedef map> callback_interp_map; -typedef map callback_map; - -callback_map callbacks; -callback_map constructors; - -// map of call policies -typedef map policies_interp_map; -typedef map policies_map; - -policies_map call_policies; - -// map of object handlers -typedef map> class_interp_map; -typedef map class_handlers_map; - -class_handlers_map class_handlers; - -// helper for finding call policies - returns true when found -bool find_policies(Tcl_Interp *interp, string const &cmdName, policies_interp_map::iterator &piti) { - policies_map::iterator pit = call_policies.find(interp); - - if (pit == call_policies.end()) { - return false; - } - - piti = pit->second.find(cmdName); - return piti != pit->second.end(); -} - extern "C" int object_handler(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); -// helper function for post-processing call policies -// for both free functions (isMethod == false) -// and class methods (isMethod == true) -void post_process_policies(Tcl_Interp *interp, policies &pol, Tcl_Obj *CONST objv[], bool isMethod) { - // check if it is a factory - if (!pol.factory_.empty()) { - class_handlers_map::iterator it = class_handlers.find(interp); - - if (it == class_handlers.end()) { - throw tcl_error("Factory was registered for unknown class."); - } - - class_interp_map::iterator oit = it->second.find(pol.factory_); - if (oit == it->second.end()) { - throw tcl_error("Factory was registered for unknown class."); - } - - class_handler_base *chb = oit->second.get(); - - // register a new command for the object returned - // by this factory function - // if everything went OK, the result is the address of the - // new object in the 'pXXX' form - // - the new command will be created with this name - - Tcl_CreateObjCommand(interp, Tcl_GetString(Tcl_GetObjResult(interp)), object_handler, static_cast(chb), 0); - } - - // process all declared sinks - // - unregister all object commands that envelopes the pointers - for (vector::iterator s = pol.sinks_.begin(); s != pol.sinks_.end(); ++s) { - if (isMethod == false) { - // example: if there is a declared sink at parameter 3, - // and the Tcl command was: - // % fun par1 par2 PAR3 par4 - // then the index 3 correctly points into the objv array - - int index = *s; - Tcl_DeleteCommand(interp, Tcl_GetString(objv[index])); - } else { - // example: if there is a declared sink at parameter 3, - // and the Tcl command was: - // % $p method par1 par2 PAR3 par4 - // then the index 3 needs to be incremented - // in order correctly point into the 4th index of objv array - - int index = *s + 1; - Tcl_DeleteCommand(interp, Tcl_GetString(objv[index])); - } - } -} - // actual functions handling various callbacks // generic callback handler -extern "C" int callback_handler(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { - callback_map::iterator it = callbacks.find(interp); - - if (it == callbacks.end()) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("Trying to invoke non-existent callback (wrong interpreter?)", -1)); - return TCL_ERROR; - } - - string cmdName(Tcl_GetString(objv[0])); - callback_interp_map::iterator iti = it->second.find(cmdName); - if (iti == it->second.end()) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("Trying to invoke non-existent callback (wrong cmd name?)", -1)); - return TCL_ERROR; - } - - policies_map::iterator pit = call_policies.find(interp); - if (pit == call_policies.end()) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("Trying to invoke callback with no known policies", -1)); - return TCL_ERROR; - } - - policies_interp_map::iterator piti; - if (find_policies(interp, cmdName, piti) == false) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("Trying to invoke callback with no known policies", -1)); - return TCL_ERROR; - } - - policies &pol = piti->second; +#if 0 +extern "C" int callback_handler(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + // callback_handler_client_data_t * cdp = (callback_handler_client_data_t *) cd; + callback_base * cb = (callback_base *) cd; + try { - iti->second->invoke(interp, objc, objv, pol); - - post_process_policies(interp, pol, objv, false); + cb->invoke(nullptr, interp, objc, objv, false); + //post_process_policies(interp, cdp->second, objv, false); } catch (exception const &e) { Tcl_SetObjResult(interp, Tcl_NewStringObj(const_cast(e.what()), -1)); return TCL_ERROR; @@ -252,31 +144,37 @@ extern "C" int callback_handler(ClientData, Tcl_Interp *interp, int objc, Tcl_Ob return TCL_OK; } - +#endif + // generic "object" command handler extern "C" int object_handler(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { // here, client data points to the singleton object // which is responsible for managing commands for // objects of a given type - class_handler_base *chb = reinterpret_cast(cd); + auto cdd = reinterpret_cast(cd); + + //class_handler_base *chb = reinterpret_cast(cd); // the command name has the form 'pXXX' where XXX is the address // of the "this" object +#if 0 string const str(Tcl_GetString(objv[0])); istringstream ss(str); char dummy; void *p; ss >> dummy >> p; - +#endif + try { - string methodName(Tcl_GetString(objv[1])); - policies &pol = chb->get_policies(methodName); - - chb->invoke(p, interp, objc, objv, pol); + //string methodName(Tcl_GetString(objv[1])); + //policies &pol = chb->get_policies(methodName); + + cdd->chb->invoke(cdd->tcli, cdd->obj, interp, objc, objv, false); + //chb->invoke(p, interp, objc, objv); - post_process_policies(interp, pol, objv, true); + //post_process_policies(interp, pol, objv, true); } catch (exception const &e) { Tcl_SetObjResult(interp, Tcl_NewStringObj(const_cast(e.what()), -1)); return TCL_ERROR; @@ -288,43 +186,159 @@ extern "C" int object_handler(ClientData cd, Tcl_Interp *interp, int objc, Tcl_O return TCL_OK; } +extern "C" int managed_method_handler(ClientData cd, Tcl_Interp * interp, int objc, Tcl_Obj *CONST objv[]) { + auto cdd = reinterpret_cast(cd); + + try { + cdd->cb->invoke(cdd->interp, cdd->obj, interp, objc, objv, true); + } catch (std::exception & e) { + Tcl_SetObjResult(interp, Tcl_NewStringObj(const_cast(e.what()), -1)); + return TCL_ERROR; + } catch (...) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("Unknown error.", -1)); + return TCL_ERROR; + } + + return TCL_OK; +} + +static void method_handler_client_data_delete(ClientData cd) { + auto * p = reinterpret_cast(cd); + if (p->unroll) { + std::ostringstream oss; + oss << 'p' << p->obj; + p->chb->uninstall_methods(p->tcli, p->interp, oss.str().c_str()); + } + delete p; +} + // generic "constructor" command extern "C" int constructor_handler(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { // here, client data points to the singleton object // which is responsible for managing commands for // objects of a given type - class_handler_base *chb = reinterpret_cast(cd); + constructor_handler_client_data_t * up = (constructor_handler_client_data_t *) cd; - callback_map::iterator it = constructors.find(interp); - if (it == constructors.end()) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("Trying to invoke non-existent callback (wrong interpreter?)", -1)); - return TCL_ERROR; - } + try { + up->cb->invoke(up->interp, nullptr, interp, objc, objv, false); - string className(Tcl_GetString(objv[0])); - callback_interp_map::iterator iti = it->second.find(className); - if (iti == it->second.end()) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("Trying to invoke non-existent callback (wrong class name?)", -1)); - return TCL_ERROR; - } + // if everything went OK, the result is the address of the + // new object in the 'pXXX' form + // - we can create a new command with this name - policies_interp_map::iterator piti; - if (find_policies(interp, className, piti) == false) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("Trying to invoke callback with no known policies", -1)); + // convert it back to a pointer for faster method calls + // object creation could be sped up by getting the raw pointer across + string const str(Tcl_GetString(Tcl_GetObjResult(interp)) + interpreter::object_namespace_prefix_len); + istringstream ss(str); + void *p; + ss >> p; + + method_handler_client_data * cd = new method_handler_client_data; + cd->obj = p; + cd->chb = up->chb; + cd->unroll = false; + cd->interp = nullptr; + cd->tcli = up->interp; + + //Tcl_CreateObjCommand(interp, Tcl_GetString(Tcl_GetObjResult(interp)), object_handler, static_cast(up->chb), 0); + Tcl_CreateObjCommand(interp, Tcl_GetString(Tcl_GetObjResult(interp)), object_handler, static_cast(cd), method_handler_client_data_delete); + } catch (exception const &e) { + Tcl_SetResult(interp, const_cast(e.what()), TCL_VOLATILE); + return TCL_ERROR; + } catch (...) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("Unknown error.", -1)); return TCL_ERROR; } - policies &pol = piti->second; + return TCL_OK; +} + +extern "C" int managed_constructor_handler(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + // here, client data points to the singleton object + // which is responsible for managing commands for + // objects of a given type + + constructor_handler_client_data_t * up = (constructor_handler_client_data_t *) cd; try { - iti->second->invoke(interp, objc, objv, pol); + bool unroll = false; + bool nocommand = false; + + Tcl_Obj ** objv2 = nullptr; + if (objc > 1) { + const char * arg1 = Tcl_GetString(objv[1]); + + if (strcmp(arg1, "-methods") == 0) { + unroll = true; + } else if (strcmp(arg1, "-nocommand") == 0) { + nocommand = true; + } + + if ((nocommand || unroll)) { + if (objc > 2) { + objv2 = new Tcl_Obj *[objc - 1]; + objv2[0] = objv[0]; + for (int j = 2; j < objc; ++j) { + objv2[j - 1] = objv[j]; + } + } + --objc; + } + } + + if (objv2) { + up->cb->invoke(up->interp, nullptr, interp, objc, objv2, false); + delete[] objv2; + } else { + up->cb->invoke(up->interp, nullptr, interp, objc, objv, false); + } + //std::cerr << " managed construct " << Tcl_GetObjResult(interp)->refCount << "\n"; + // if everything went OK, the result is the address of the // new object in the 'pXXX' form // - we can create a new command with this name - Tcl_CreateObjCommand(interp, Tcl_GetString(Tcl_GetObjResult(interp)), object_handler, static_cast(chb), 0); + //string const str(Tcl_GetString(Tcl_GetObjResult(interp)) + interpreter::object_namespace_prefix_len); + + //istringstream ss(str); + //void *p; + //ss >> p; + + Tcl_Obj * ores = Tcl_GetObjResult(interp); + + method_handler_client_data * cd = new method_handler_client_data; + void * p = cd->obj = ores->internalRep.twoPtrValue.ptr1; + cd->chb = up->chb; + cd->unroll = unroll; + cd->interp = interp; + cd->tcli = up->interp; + + //Tcl_CreateObjCommand(interp, cmd.c_str(), object_handler, static_cast(up->chb), 0); + + if (unroll) { + //std::cerr << "install methods\n"; + up->chb->install_methods(up->interp, interp, Tcl_GetString(Tcl_GetObjResult(interp)), p); + } + + if (! nocommand) { + std::string cmd = Tcl_GetString(Tcl_GetObjResult(interp)); + cmd += "."; + //std::cerr << "ohandler " << (void *) object_handler << " " << (void *) cd << "\n"; + //std::cerr << "create command " << cmd << "\n"; + if (! Tcl_CreateObjCommand(interp, cmd.c_str(), object_handler, static_cast(cd), method_handler_client_data_delete)) { + std::cerr << "cannot create command " << cmd << "\n"; + } + + //Tcl_CmdInfo cmdinfo; + + //Tcl_GetCommandInfo(interp, cmd.c_str(), &cmdinfo); + + //std::cerr << "cmdinfo proc=" << (void *) cmdinfo.objProc << " cd=" << cmdinfo.objClientData << " ns=" << cmdinfo.namespacePtr << "\n"; + + //std::cerr << " managed construct2 " << Tcl_GetObjResult(interp)->refCount << "\n"; + } } catch (exception const &e) { Tcl_SetResult(interp, const_cast(e.what()), TCL_VOLATILE); return TCL_ERROR; @@ -350,10 +364,17 @@ policies &policies::sink(int index) { return *this; } +policies & policies::options(string const & options) { + options_ = options; + return *this; +} + +#if 0 policies &policies::variadic() { variadic_ = true; return *this; } +#endif policies &policies::usage(string const &message) { usage_ = std::string("Usage: ") + message; @@ -364,40 +385,90 @@ policies Tcl::factory(string const &name) { return policies().factory(name); } policies Tcl::sink(int index) { return policies().sink(index); } -policies Tcl::variadic() { return policies().variadic(); } +//policies Tcl::variadic() { return policies().variadic(); } + +policies Tcl::options(std::string const & opt) { return policies().options(opt); } policies Tcl::usage(string const &message) { return policies().usage(message); } class_handler_base::class_handler_base() { // default policies for the -delete command - policies_["-delete"] = policies(); + //policies_["-delete"] = policies(); } -void class_handler_base::register_method(string const &name, shared_ptr ocb, policies const &p) { - methods_[name] = ocb; - policies_[name] = p; +static void managed_method_client_data_delete(ClientData cd) { + auto * p = reinterpret_cast(cd); + delete[] p; +} + +void class_handler_base::uninstall_methods(interpreter * tcli, Tcl_Interp * interp, const char * prefix) { + char buf[1024]; + strcpy(buf, prefix); + char * p = buf + strlen(buf); + *p = '.'; ++p; + + for (auto it = methods_.begin(); it != methods_.end(); ++it) { + strcpy(p, it->first); + Tcl_DeleteCommand(interp, buf); + //throw tcl_error(std::string("cannot register method ") + buf + " on object creation of managed class"); + //} + } } -policies &class_handler_base::get_policies(string const &name) { - policies_map_type::iterator it = policies_.find(name); - if (it == policies_.end()) { - throw tcl_error("Trying to use non-existent policy: " + name); +void class_handler_base::install_methods(interpreter * tcli, Tcl_Interp * interp, const char * prefix, void * obj) { + char buf[1024]; + strcpy(buf, prefix); + char * p = buf + strlen(buf); + *p = '.'; ++p; + + managed_method_handler_client_data * cds = new managed_method_handler_client_data[methods_.size()]; + int ix = 0; + for (auto it = methods_.begin(); it != methods_.end(); ++it, ++ix) { + strcpy(p, it->first); + cds[ix].obj = obj; + cds[ix].cb = it->second; + cds[ix].interp = tcli; + //std::cerr << "install method " << buf << "\n"; + Tcl_CreateObjCommand(interp, buf, managed_method_handler, static_cast(cds + ix), ix == 0 ? managed_method_client_data_delete : nullptr); + //throw tcl_error(std::string("cannot register method ") + buf + " on object creation of managed class"); + //} } +} - return it->second; +void class_handler_base::register_method(string const & name, callback_base * ocb, Tcl_Interp * interp, bool managed) { + char * str = new char[name.size() + 1]; + strcpy(str, name.c_str()); + methods_[str] = ocb; + //policies_[name] = p; } -object::object() : interp_(0) { - obj_ = Tcl_NewObj(); +thread_local Tcl_Obj * object::default_object_ = nullptr; + +object::object() : interp_(nullptr) { + if (! default_object_) { static_initialize(); } + obj_ = default_object_; + Tcl_IncrRefCount(obj_); +} +object::object(interpreter * interp) : interp_(interp) { + if (! default_object_) { static_initialize(); } + obj_ = default_object_; Tcl_IncrRefCount(obj_); } -object::object(bool b) : interp_(0) { +object::object(bool b) : interp_(nullptr) { + obj_ = Tcl_NewBooleanObj(b); + Tcl_IncrRefCount(obj_); +} +object::object(interpreter * interp, bool b) : interp_(interp) { obj_ = Tcl_NewBooleanObj(b); Tcl_IncrRefCount(obj_); } -object::object(char const *buf, size_t size) : interp_(0) { +object::object(char const * buf, size_t size) : interp_(0) { + obj_ = Tcl_NewByteArrayObj(reinterpret_cast(buf), static_cast(size)); + Tcl_IncrRefCount(obj_); +} +object::object(interpreter * interp, char const * buf, size_t size) : interp_(interp) { obj_ = Tcl_NewByteArrayObj(reinterpret_cast(buf), static_cast(size)); Tcl_IncrRefCount(obj_); } @@ -406,33 +477,54 @@ object::object(double d) : interp_(0) { obj_ = Tcl_NewDoubleObj(d); Tcl_IncrRefCount(obj_); } +object::object(interpreter * interp, double d) : interp_(interp) { + obj_ = Tcl_NewDoubleObj(d); + Tcl_IncrRefCount(obj_); +} object::object(int i) : interp_(0) { obj_ = Tcl_NewIntObj(i); Tcl_IncrRefCount(obj_); } +object::object(interpreter * interp, int i) : interp_(interp) { + obj_ = Tcl_NewIntObj(i); + Tcl_IncrRefCount(obj_); +} object::object(long l) : interp_(0) { obj_ = Tcl_NewLongObj(l); Tcl_IncrRefCount(obj_); } +object::object(interpreter * interp, long l) : interp_(interp) { + obj_ = Tcl_NewLongObj(l); + Tcl_IncrRefCount(obj_); +} -object::object(char const *s) : interp_(0) { +object::object(char const * s) : interp_(0) { + obj_ = Tcl_NewStringObj(s, -1); + Tcl_IncrRefCount(obj_); +} +object::object(interpreter * interp, char const * s) : interp_(interp) { obj_ = Tcl_NewStringObj(s, -1); Tcl_IncrRefCount(obj_); } -object::object(string const &s) : interp_(0) { +object::object(string const & s) : interp_(0) { + obj_ = Tcl_NewStringObj(s.data(), static_cast(s.size())); + Tcl_IncrRefCount(obj_); +} +object::object(interpreter * interp, string const & s) : interp_(interp) { obj_ = Tcl_NewStringObj(s.data(), static_cast(s.size())); Tcl_IncrRefCount(obj_); } -object::object(Tcl_Obj *o, bool shared) : interp_(0) { init(o, shared); } +object::object(Tcl_Obj * o, bool shared) : interp_(0) { init(o, shared); } +object::object(interpreter * interp, Tcl_Obj * o, bool shared) : interp_(interp) { init(o, shared); } -object::object(object const &other, bool shared) : interp_(other.get_interp()) { init(other.obj_, shared); } +object::object(object const & other, bool shared) : interp_(other.interp_) { init(other.obj_, shared); } -void object::init(Tcl_Obj *o, bool shared) { - if (shared) { +void object::init(Tcl_Obj * o, bool shared) { + if (true || shared) { obj_ = o; } else { obj_ = Tcl_DuplicateObj(o); @@ -443,42 +535,85 @@ void object::init(Tcl_Obj *o, bool shared) { object::~object() { Tcl_DecrRefCount(obj_); } object &object::assign(bool b) { - Tcl_SetBooleanObj(obj_, b); + if (Tcl_IsShared(obj_)) { + Tcl_DecrRefCount(obj_); + obj_ = Tcl_NewBooleanObj(b ? 1 : 0); + Tcl_IncrRefCount(obj_); + } else { + Tcl_SetBooleanObj(obj_, b ? 1 : 0); + } return *this; } object &object::resize(size_t size) { + dupshared(); Tcl_SetByteArrayLength(obj_, static_cast(size)); return *this; } object &object::assign(char const *buf, size_t size) { - Tcl_SetByteArrayObj(obj_, reinterpret_cast(buf), static_cast(size)); + if (Tcl_IsShared(obj_)) { + Tcl_DecrRefCount(obj_); + obj_ = Tcl_NewByteArrayObj(reinterpret_cast(buf), static_cast(size)); + Tcl_IncrRefCount(obj_); + } else { + Tcl_SetByteArrayObj(obj_, reinterpret_cast(buf), static_cast(size)); + } return *this; } object &object::assign(double d) { - Tcl_SetDoubleObj(obj_, d); + if (Tcl_IsShared(obj_)) { + Tcl_DecrRefCount(obj_); + obj_ = Tcl_NewDoubleObj(d); + Tcl_IncrRefCount(obj_); + } else { + Tcl_SetDoubleObj(obj_, d); + } return *this; } object &object::assign(int i) { - Tcl_SetIntObj(obj_, i); + if (Tcl_IsShared(obj_)) { + Tcl_DecrRefCount(obj_); + obj_ = Tcl_NewIntObj(i); + Tcl_IncrRefCount(obj_); + } else { + Tcl_SetIntObj(obj_, i); + } return *this; } object &object::assign(long l) { - Tcl_SetLongObj(obj_, l); + if (Tcl_IsShared(obj_)) { + Tcl_DecrRefCount(obj_); + obj_ = Tcl_NewLongObj(l); + Tcl_IncrRefCount(obj_); + } else { + Tcl_SetLongObj(obj_, l); + } return *this; } object &object::assign(char const *s) { - Tcl_SetStringObj(obj_, s, -1); + if (Tcl_IsShared(obj_)) { + Tcl_DecrRefCount(obj_); + obj_ = Tcl_NewStringObj(s, -1); + Tcl_IncrRefCount(obj_); + } else { + Tcl_SetStringObj(obj_, s, -1); + } return *this; } object &object::assign(string const &s) { - Tcl_SetStringObj(obj_, s.data(), static_cast(s.size())); + if (Tcl_IsShared(obj_)) { + Tcl_DecrRefCount(obj_); + obj_ = Tcl_NewStringObj(s.data(), static_cast(s.size())); + Tcl_IncrRefCount(obj_); + } else { + Tcl_SetStringObj(obj_, s.data(), static_cast(s.size())); + } return *this; } @@ -492,71 +627,34 @@ object &object::assign(Tcl_Obj *o) { return *this; } +object object::duplicate() const { + Tcl_Obj * to = Tcl_DuplicateObj(obj_); + return object(interp_, to); +} + object &object::swap(object &other) { std::swap(obj_, other.obj_); std::swap(interp_, other.interp_); return *this; } -template <> bool object::get(interpreter &i) const { - int retVal; - int res = Tcl_GetBooleanFromObj(i.get(), obj_, &retVal); - if (res != TCL_OK) { - throw tcl_error(i.get()); - } - - return static_cast(retVal); -} - -template <> vector object::get>(interpreter &) const { - size_t size; - char const *buf = get(size); - return vector(buf, buf + size); +template T object::get() const { //interpreter &i) const { + return tcl_cast::from(interp_ ? interp_->get() : nullptr, obj_, false); } -template <> double object::get(interpreter &i) const { - double retVal; - int res = Tcl_GetDoubleFromObj(i.get(), obj_, &retVal); - if (res != TCL_OK) { - throw tcl_error(i.get()); - } - - return retVal; -} - -template <> int object::get(interpreter &i) const { - int retVal; - - int res = Tcl_GetIntFromObj(i.get(), obj_, &retVal); - if (res != TCL_OK) { - throw tcl_error(i.get()); - } - - return retVal; -} - -template <> long object::get(interpreter &i) const { - long retVal; - int res = Tcl_GetLongFromObj(i.get(), obj_, &retVal); - if (res != TCL_OK) { - throw tcl_error(i.get()); - } - - return retVal; -} - -template <> char const *object::get(interpreter &) const { return get(); } - -template <> string object::get(interpreter &) const { - int len; - char const *buf = Tcl_GetStringFromObj(obj_, &len); - return string(buf, buf + len); -} +template bool object::get() const; +template double object::get() const; +template float object::get() const; +template int object::get() const; +template long object::get() const; +template char const * object::get() const; +template std::string object::get() const; +template std::vector object::get>() const; string object::asString() const { return get(); } -int object::asInt() const { return get(); } -bool object::asBool() const { return get(); } -long object::asLong() const { return get(); } +int object::asInt() const { return get(); } +bool object::asBool() const { return get(); } +long object::asLong() const { return get(); } double object::asDouble() const { return get(); } char const *object::get() const { return Tcl_GetString(obj_); } @@ -568,114 +666,207 @@ char const *object::get(size_t &size) const { return const_cast(reinterpret_cast(buf)); } -size_t object::size(interpreter &i) const { - int len; - int res = Tcl_ListObjLength(i.get(), obj_, &len); +bool object::is_list() const { + return obj_->typePtr && strcmp(obj_->typePtr->name, "list") == 0; +} - if (res != TCL_OK) { - throw tcl_error(i.get()); +size_t object::size() const { + int len; + if (Tcl_ListObjLength(interp_ ? interp_->get_interp() : nullptr, obj_, &len) != TCL_OK) { + throw tcl_error(interp_->get_interp()); } - return static_cast(len); } -object object::at(size_t index, interpreter &i) const { +object object::at_ref(size_t index) const { Tcl_Obj *o; - int res = Tcl_ListObjIndex(i.get(), obj_, static_cast(index), &o); - if (res != TCL_OK) { - throw tcl_error(i.get()); + if (Tcl_ListObjIndex(interp_ ? interp_->get_interp() : nullptr, obj_, static_cast(index), &o) != TCL_OK) { + throw tcl_error(interp_->get_interp()); } if (o == NULL) { throw tcl_error("Index out of range."); } + return object(o, true); +} +object object::at(size_t index) const { + Tcl_Obj *o; + if (Tcl_ListObjIndex(interp_ ? interp_->get_interp() : nullptr, obj_, static_cast(index), &o) != TCL_OK) { + throw tcl_error(interp_->get_interp()); + } + if (o == NULL) { + throw tcl_error("Index out of range."); + } return object(o); } -object &object::append(object const &o, interpreter &i) { - int res = Tcl_ListObjAppendElement(i.get(), obj_, o.obj_); - if (res != TCL_OK) { - throw tcl_error(i.get()); - } +object &object::append(object const &o) { + dupshared(); + if (Tcl_ListObjAppendElement(interp_ ? interp_->get_interp() : nullptr, obj_, o.obj_) != TCL_OK) { + throw tcl_error(interp_->get_interp()); + } return *this; } -object &object::append_list(object const &o, interpreter &i) { - int res = Tcl_ListObjAppendList(i.get(), obj_, o.obj_); - if (res != TCL_OK) { - throw tcl_error(i.get()); - } +object &object::append_list(object const &o) { + dupshared(); + if (Tcl_ListObjAppendList(interp_ ? interp_->get_interp() : nullptr, obj_, o.obj_) != TCL_OK) { + throw tcl_error(interp_->get_interp()); + } return *this; } -object &object::replace(size_t index, size_t count, object const &o, interpreter &i) { - int res = Tcl_ListObjReplace(i.get(), obj_, static_cast(index), static_cast(count), 1, &(o.obj_)); +object &object::replace(size_t index, size_t count, object const &o) { + dupshared(); + int res = Tcl_ListObjReplace(interp_ ? interp_->get_interp() : nullptr, obj_, static_cast(index), static_cast(count), 1, &(o.obj_)); if (res != TCL_OK) { - throw tcl_error(i.get()); + throw tcl_error(interp_->get_interp()); } - return *this; } -object &object::replace_list(size_t index, size_t count, object const &o, interpreter &i) { +object &object::replace_list(size_t index, size_t count, object const &o) { int objc; Tcl_Obj **objv; - int res = Tcl_ListObjGetElements(i.get(), o.obj_, &objc, &objv); + int res = Tcl_ListObjGetElements(interp_ ? interp_->get_interp() : nullptr, o.obj_, &objc, &objv); if (res != TCL_OK) { - throw tcl_error(i.get()); + throw tcl_error(interp_->get_interp()); } - - res = Tcl_ListObjReplace(i.get(), obj_, static_cast(index), static_cast(count), objc, objv); + dupshared(); + res = Tcl_ListObjReplace(interp_ ? interp_->get_interp() : nullptr, obj_, static_cast(index), static_cast(count), objc, objv); if (res != TCL_OK) { - throw tcl_error(i.get()); + throw tcl_error(interp_->get_interp()); } - return *this; } -void object::set_interp(Tcl_Interp *interp) { interp_ = interp; } +//void object::set_interp(Tcl_Interp *interp) { interp_ = interp; } -Tcl_Interp *object::get_interp() const { return interp_; } +//Tcl_Interp *object::get_interp() const { return interp_; } Tcl::interpreter *interpreter::defaultInterpreter = nullptr; -interpreter::interpreter() { +void interpreter::unsetVar(std::string const & name) { + Tcl_UnsetVar(get_interp(), name.c_str(), 0); +} + +details::result interpreter::upVar(std::string const & frame, std::string const & srcname, std::string const & destname) { + if (Tcl_UpVar(interp_, frame.c_str(), srcname.c_str(), destname.c_str(), 0) == TCL_OK) { + return getVar(destname); + } + return result(interp_); +} + + +int interpreter::dot_call_handler(ClientData cd, Tcl_Interp * interp, int objc, Tcl_Obj * CONST * objv) { + interpreter * this_p = (interpreter *) cd; + if (objc > 1) { + Tcl_Obj * o = objv[1]; + if (Tcl_ObjType const * ot = o->typePtr) { + if (ot[1].name) { + auto it = this_p->all_classes_by_objtype_.find(ot); + if (it != this_p->all_classes_by_objtype_.end()) { + it->second.class_handler->invoke(this_p, o->internalRep.twoPtrValue.ptr1, interp, objc - 1, objv + 1, false); + } else { + std::cerr << "primary argument is not a registered cpptcl object\n"; + return TCL_ERROR; + } + } else { + assert(ot[-1].name); + auto it = this_p->all_classes_by_objtype_.find(ot - 1); + if (it != this_p->all_classes_by_objtype_.end()) { + if (it->second.is_inline) { + it->second.class_handler->invoke(this_p, (void *) &o->internalRep, interp, objc - 1, objv + 1, false); + } else { + it->second.class_handler->invoke(this_p, o->internalRep.twoPtrValue.ptr1, interp, objc - 1, objv + 1, false); + } + } else { + std::cerr << "primary argument is not a registered cpptcl object\n"; + return TCL_ERROR; + } + } + } else { + std::cerr << "primary argument in object call is not a tcl object\n"; + return TCL_ERROR; + } + } else { + std::cerr << "object call requires at least 2 parameters\n"; + return TCL_ERROR; + } + return TCL_OK; +} + +interpreter::interpreter() : tin_(nullptr), tout_(nullptr), terr_(nullptr) { + static_initialize(); + interp_ = Tcl_CreateInterp(); owner_ = true; if (defaultInterpreter) { throw tcl_error("expecting a single interpreter"); } + find_standard_types(); + Tcl_CreateObjCommand(interp_, ".", dot_call_handler, (ClientData) this, nullptr); } -interpreter::interpreter(Tcl_Interp *interp, bool owner) { +interpreter::interpreter(Tcl_Interp *interp, bool owner) : tin_(nullptr), tout_(nullptr), terr_(nullptr) { + static_initialize(); + interp_ = interp; + + if (! interp_) { interp_ = Tcl_CreateInterp(); } owner_ = owner; if (!defaultInterpreter) { - if (Tcl_InitStubs(interp, "8.6", 0) == NULL) { + if (Tcl_InitStubs(interp_, "8.6", 0) == NULL) { throw tcl_error("Failed to initialize stubs"); } // Make a copy + } + find_standard_types(); + if (!defaultInterpreter) { defaultInterpreter = new interpreter(*this); } + Tcl_CreateObjCommand(interp_, ".", dot_call_handler, (ClientData) this, nullptr); +} + +interpreter::interpreter(const interpreter &i) : interp_(i.interp_), owner_(i.owner_), tin_(nullptr), tout_(nullptr), terr_(nullptr), + list_type_(i.list_type_), cmdname_type_(i.cmdname_type_), object_namespace_(i.object_namespace_) { + static_initialize(); +} + +void interpreter::custom_construct(const char * c_name, const char * o_name, void * p) { + auto it2 = all_classes_.find(c_name); + if (it2 != all_classes_.end()) { + auto * cd = new method_handler_client_data; + cd->obj = p; + cd->chb = it2->second.get(); + cd->unroll = false; + cd->interp = nullptr; + Tcl_CreateObjCommand(interp_, o_name, object_handler, static_cast(cd), method_handler_client_data_delete); + return; + } + throw tcl_error("custom construct failed"); } -interpreter::interpreter(const interpreter &i) : interp_(i.interp_), owner_(i.owner_) {} +void interpreter::find_standard_types() { + list_type_ = Tcl_GetObjType("list"); + cmdname_type_ = Tcl_GetObjType("cmdName"); + object_namespace_ = Tcl_FindNamespace(interp_, object_namespace_name, Tcl_GetGlobalNamespace(interp_), 0); + //object_command_namespace_ = Tcl_FindNamespace(interp_, object_command_namespace_name, nullptr, 0); +} interpreter::~interpreter() { + clear_definitions(); if (owner_) { // clear all callback info belonging to this interpreter - clear_definitions(interp_); - Tcl_DeleteInterp(interp_); } } void interpreter::make_safe() { - int cc = Tcl_MakeSafe(interp_); - if (cc != TCL_OK) { + if (Tcl_MakeSafe(interp_) != TCL_OK) { throw tcl_error(interp_); } } @@ -683,9 +874,13 @@ void interpreter::make_safe() { result interpreter::eval(string const &script) { int cc = Tcl_Eval(interp_, script.c_str()); if (cc != TCL_OK) { - throw tcl_error(interp_); + if (want_abort_) { + want_abort_ = false; + throw tcl_aborted(); + } else { + throw tcl_error(interp_); + } } - return result(interp_); } @@ -697,9 +892,13 @@ result interpreter::eval(istream &s) { result interpreter::eval(object const &o) { int cc = Tcl_EvalObjEx(interp_, o.get_object(), 0); if (cc != TCL_OK) { - throw tcl_error(interp_); + if (want_abort_) { + want_abort_ = false; + throw tcl_aborted(); + } else { + throw tcl_error(interp_); + } } - return result(interp_); } @@ -708,11 +907,11 @@ result interpreter::getVar(string const &variableName, string const &indexName) object i = object(indexName.c_str()); Tcl_Obj * obj = Tcl_ObjGetVar2(interp_, n.get_object(), i.get_object(), 0); if (obj == NULL) { - throw tcl_error(interp_); + std::cerr << "throw!\n"; + throw tcl_error("no such variable: " + variableName + "(" + indexName + ")"); } else { Tcl_SetObjResult(interp_, obj); } - return result(interp_); } @@ -720,11 +919,10 @@ result interpreter::getVar(string const &variableName) { object n = object(variableName.c_str()); Tcl_Obj * obj = Tcl_ObjGetVar2(interp_, n.get_object(), nullptr, 0); if (obj == NULL) { - throw tcl_error(interp_); + throw tcl_error("no such variable: " + variableName); } else { Tcl_SetObjResult(interp_, obj); } - return result(interp_); } @@ -754,7 +952,6 @@ void interpreter::create_namespace(string const &name) { } } - void interpreter::create_alias(string const &cmd, interpreter &targetInterp, string const &targetCmd) { int cc = Tcl_CreateAlias(interp_, cmd.c_str(), targetInterp.interp_, targetCmd.c_str(), 0, 0); if (cc != TCL_OK) { @@ -762,116 +959,207 @@ void interpreter::create_alias(string const &cmd, interpreter &targetInterp, str } } -void interpreter::clear_definitions(Tcl_Interp *interp) { - // delete all callbacks that were registered for given interpreter - - { - callback_map::iterator it = callbacks.find(interp); - - if (it == callbacks.end()) { - // no callbacks defined for this interpreter - return; - } - - callback_interp_map &imap = it->second; - for (callback_interp_map::iterator it2 = imap.begin(); it2 != imap.end(); ++it2) { - Tcl_DeleteCommand(interp, it2->first.c_str()); - } - - callbacks.erase(interp); +void interpreter::clear_definitions() { + for (auto & c : all_callbacks_) { + Tcl_DeleteCommand(get_interp(), c.first.c_str()); } +} - // delete all constructors - - { - callback_map::iterator it = constructors.find(interp); - if (it == constructors.end()) { - // no callbacks defined for this interpreter - return; - } - - callback_interp_map &imap = it->second; - for (callback_interp_map::iterator it2 = imap.begin(); it2 != imap.end(); ++it2) { - Tcl_DeleteCommand(interp, it2->first.c_str()); - } +void interpreter::add_function(string const &name, std::shared_ptr cb) { + cb->install(this); + all_callbacks_.insert(std::pair(name, cb)); +} - callbacks.erase(interp); +void interpreter::add_class(string const &name, std::shared_ptr chb, bool is_inline) { + all_classes_.insert(std::pair(name, chb)); + Tcl_ObjType * ot = get_objtype(name.c_str()); + if (ot) { + all_classes_by_objtype_.insert(std::pair(ot, all_classes_by_objtype_value{ chb, is_inline })); } - - // delete all call policies - - call_policies.erase(interp); - - // delete all object handlers - // (we have to assume that all living objects were destroyed, - // otherwise Bad Things will happen) - - class_handlers.erase(interp); } - -void interpreter::add_function(string const &name, shared_ptr cb, policies const &p) { - Tcl_CreateObjCommand(interp_, name.c_str(), callback_handler, 0, 0); - - callbacks[interp_][name] = cb; - call_policies[interp_][name] = p; +details::class_handler_base * interpreter::get_class_handler(std::string const & name) { + auto it2 = all_classes_.find(name); + if (it2 == all_classes_.end()) return nullptr; + return it2->second.get(); } -void interpreter::add_class(string const &name, shared_ptr chb) { class_handlers[interp_][name] = chb; } - -void interpreter::add_constructor(string const &name, shared_ptr chb, shared_ptr cb, policies const &p) { - Tcl_CreateObjCommand(interp_, name.c_str(), constructor_handler, static_cast(chb.get()), 0); +void interpreter::add_constructor(string const &name, class_handler_base * chb, std::shared_ptr cb) { + constructor_handler_client_data_t * up = new constructor_handler_client_data_t; + up->cb = cb.get(); + up->chb = chb; + up->interp = this; + + Tcl_CreateObjCommand(interp_, name.c_str(), constructor_handler, up, 0); + all_callbacks_.insert(std::pair(name, cb)); +} - constructors[interp_][name] = cb; - call_policies[interp_][name] = p; +void interpreter::add_managed_constructor(string const &name, class_handler_base * chb, std::shared_ptr cb) { + constructor_handler_client_data_t * up = new constructor_handler_client_data_t; + up->cb = cb.get(); + up->chb = chb; + up->interp = this; + + Tcl_CreateObjCommand(interp_, name.c_str(), managed_constructor_handler, up, 0); + all_callbacks_.insert(std::pair(name, cb)); } int tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj, bool) { int res; - int cc = Tcl_GetIntFromObj(interp, obj, &res); - if (cc != TCL_OK) { + if (Tcl_GetIntFromObj(interp, obj, &res) != TCL_OK) { + throw tcl_error(interp); + } + return res; +} +unsigned int tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj, bool) { + int res; + if (Tcl_GetIntFromObj(interp, obj, &res) != TCL_OK) { throw tcl_error(interp); } - return res; } long tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj, bool) { long res; - int cc = Tcl_GetLongFromObj(interp, obj, &res); - if (cc != TCL_OK) { + if (Tcl_GetLongFromObj(interp, obj, &res) != TCL_OK) { throw tcl_error(interp); } - return res; } bool tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj, bool) { int res; - int cc = Tcl_GetBooleanFromObj(interp, obj, &res); - if (cc != TCL_OK) { + if (Tcl_GetBooleanFromObj(interp, obj, &res) != TCL_OK) { throw tcl_error(interp); } - return res != 0; } double tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj, bool) { double res; - int cc = Tcl_GetDoubleFromObj(interp, obj, &res); - if (cc != TCL_OK) { + if (Tcl_GetDoubleFromObj(interp, obj, &res) != TCL_OK) { throw tcl_error(interp); } - return res; } -string tcl_cast::from(Tcl_Interp *, Tcl_Obj *obj, bool) { return Tcl_GetString(obj); } +float tcl_cast::from(Tcl_Interp * interp, Tcl_Obj * obj, bool b) { + return tcl_cast::from(interp, obj, b); +} +string tcl_cast::from(Tcl_Interp *, Tcl_Obj *obj, bool) { return Tcl_GetString(obj); } char const *tcl_cast::from(Tcl_Interp *, Tcl_Obj *obj, bool) { return Tcl_GetString(obj); } -object tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj, bool) { +object tcl_cast::from(Tcl_Interp * interp, Tcl_Obj * obj, bool) { object o(obj); - o.set_interp(interp); - + //o.set_interp(interp); return o; } + +std::vector tcl_cast >::from(Tcl_Interp * interp, Tcl_Obj * obj, bool asref) { + std::string s = tcl_cast::from(interp, obj, asref); + return std::vector(s.begin(), s.end()); +} + +namespace Tcl { +// helper function for post-processing call policies +// for both free functions (isMethod == false) +// and class methods (isMethod == true) +void interpreter::post_process_policies(Tcl_Interp *interp, policies &pol, Tcl_Obj *CONST objv[], bool isMethod) { + // check if it is a factory + if (!pol.factory_.empty()) { + auto oit = all_classes_.find(pol.factory_); + if (oit == all_classes_.end()) { + throw tcl_error("Factory was registered for unknown class."); + } + + class_handler_base *chb = oit->second.get(); + + // register a new command for the object returned + // by this factory function + // if everything went OK, the result is the address of the + // new object in the 'pXXX' form + // - the new command will be created with this name + + Tcl_Obj * to = Tcl_GetObjResult(interp); + void * p = nullptr; + if (to->internalRep.otherValuePtr) { + p = to->internalRep.otherValuePtr; + } else { + string const str(Tcl_GetString(to) + interpreter::object_namespace_prefix_len); + istringstream ss(str); + ss >> p; + } + + + auto * cd = new method_handler_client_data; + cd->obj = p; + cd->chb = chb; + cd->unroll = false; + cd->interp = nullptr; + cd->tcli = this; + + Tcl_CreateObjCommand(interp, Tcl_GetString(Tcl_GetObjResult(interp)), object_handler, static_cast(cd), 0); + } + + // process all declared sinks + // - unregister all object commands that envelopes the pointers + for (vector::iterator s = pol.sinks_.begin(); s != pol.sinks_.end(); ++s) { + if (isMethod == false) { + // example: if there is a declared sink at parameter 3, + // and the Tcl command was: + // % fun par1 par2 PAR3 par4 + // then the index 3 correctly points into the objv array + + int index = *s; + Tcl_DeleteCommand(interp, Tcl_GetString(objv[index])); + } else { + // example: if there is a declared sink at parameter 3, + // and the Tcl command was: + // % $p method par1 par2 PAR3 par4 + // then the index 3 needs to be incremented + // in order correctly point into the 4th index of objv array + + int index = *s + 1; + Tcl_DeleteCommand(interp, Tcl_GetString(objv[index])); + } + } +} + +tcl_error::tcl_error(std::string const & msg) : msg_(msg), std::runtime_error(msg) { + //backtrace_size_ = backtrace(backtrace_, sizeof(backtrace_) / sizeof(backtrace_[0])); +} +tcl_error::tcl_error(Tcl_Interp * interp) : std::runtime_error(Tcl_GetString(Tcl_GetObjResult(interp))), msg_(Tcl_GetString(Tcl_GetObjResult(interp))) {} +const char * tcl_error::what() const throw() { + std::ostringstream oss; + oss << msg_ << "\n"; +#if 0 + char ** b = backtrace_symbols(backtrace_, backtrace_size_); + for (int i = 0; i < backtrace_size_; ++i) { + bool done = false; + const char * pos = index(b[i], '('); + if (pos) { + ++pos; + const char * epos = index(pos, '+'); + if (epos) { + oss << std::string(b[i], pos - b[i]); + std::string str(pos, epos - pos); + oss << boost::core::demangle(str.c_str()); + oss << epos << "\n"; + done = true; + } + } + if (! done) { + oss << boost::core::demangle(b[i]) << "\n"; + } + } + free(b); +#endif + return strdup(oss.str().c_str()); +} + + decltype(interpreter::obj_type_by_tclname_) interpreter::obj_type_by_tclname_; + decltype(interpreter::obj_type_by_cppname_) interpreter::obj_type_by_cppname_; + decltype(interpreter::capture_callback) interpreter::capture_callback; + bool interpreter::static_initialized_ = false; +} + diff --git a/cpptcl/cpptcl.h b/cpptcl/cpptcl.h index 7a748d6..4b8962c 100644 --- a/cpptcl/cpptcl.h +++ b/cpptcl/cpptcl.h @@ -1,3 +1,4 @@ +//-*- mode: c++; eval: (c-set-offset 'innamespace 0); -*- // // Copyright (C) 2004-2006, Maciej Sobczak // Copyright (C) 2017-2019, FlightAware LLC @@ -19,13 +20,23 @@ #endif #endif +#include #include +#include #include #include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include // // Using TCL stubs is the default behavior @@ -48,16 +59,26 @@ namespace Tcl { // exception class used for reporting all Tcl errors class tcl_error : public std::runtime_error { - public: - explicit tcl_error(std::string const &msg) : std::runtime_error(msg) {} - explicit tcl_error(Tcl_Interp *interp) : std::runtime_error(Tcl_GetString(Tcl_GetObjResult(interp))) {} + std::string msg_; + void * backtrace_[16]; + size_t backtrace_size_; +public: + explicit tcl_error(std::string const &msg); //: std::runtime_error(msg) {} + explicit tcl_error(Tcl_Interp *interp); + const char * what() const throw(); +}; + +class tcl_aborted : public std::exception { +}; + +class tcl_usage_message_printed { }; // call policies struct policies { policies() : variadic_(false), usage_("Too few arguments.") {} - + policies &factory(std::string const &name); // note: this is additive @@ -67,41 +88,80 @@ struct policies { policies &usage(std::string const &message); + policies &options(std::string const & opts); + std::string factory_; std::vector sinks_; bool variadic_; std::string usage_; + std::string options_; + bool has_postprocess() { + return !factory_.empty() || ! sinks_.empty(); + } }; // syntax short-cuts policies factory(std::string const &name); policies sink(int index); -policies variadic(); policies usage(std::string const &message); +policies options(std::string const & options); class interpreter; class object; +struct named_pointer_result { + std::string name; + void * p; + template + named_pointer_result(std::string const & n, U * u) : name(n), p((void *) u) { } +}; + namespace details { +template struct tcl_cast; + +// the following partial specialization is to strip reference +// (it returns a temporary object of the underlying type, which +// can be bound to the const-ref parameter of the actual function) + +template struct tcl_cast { + static T from(Tcl_Interp *interp, Tcl_Obj *obj, bool byReference) { return tcl_cast::from(interp, obj, byReference); } +}; + +template class tcl_cast_by_reference { + public: + static bool const value = false; +}; + +// the following specializations are implemented +template <> struct tcl_cast { static int from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; +template <> struct tcl_cast { static unsigned int from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; +template <> struct tcl_cast { static long from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; +template <> struct tcl_cast { static bool from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; +template <> struct tcl_cast { static double from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; +template <> struct tcl_cast { static float from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; +template <> struct tcl_cast { static std::string from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; +template <> struct tcl_cast { static char const *from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; +template <> struct tcl_cast { static object from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; +template <> struct tcl_cast > { static std::vector from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; // wrapper for the evaluation result class result { public: result(Tcl_Interp *interp); - + //result(interpreter * interp); + operator bool() const; operator double() const; operator int() const; operator long() const; operator std::string() const; operator object() const; - + void reset(); private: Tcl_Interp *interp_; + //interpreter * interp_; }; -// helper functions used to set the result value - void set_result(Tcl_Interp *interp, bool b); void set_result(Tcl_Interp *interp, int i); void set_result(Tcl_Interp *interp, long i); @@ -109,16 +169,19 @@ void set_result(Tcl_Interp *interp, double d); void set_result(Tcl_Interp *interp, std::string const &s); void set_result(Tcl_Interp *interp, void *p); void set_result(Tcl_Interp *interp, object const &o); +void set_result(Tcl_Interp *interp, named_pointer_result); -// helper functor for converting Tcl objects to the given type -#include "cpptcl/details/conversions.h" +template ::value_type, void>::value, bool>::type = true> +void set_result(Tcl_Interp * interp, std::pair it); -// dispatchers able to capture (or ignore) the result -#include "cpptcl/details/dispatchers.h" +template +void set_result(Tcl_Interp * interp, std::vector const & v) { + set_result(interp, std::pair(v.begin(), v.end())); +} // helper for checking for required number of parameters // (throws tcl_error when not met) -void check_params_no(int objc, int required, const std::string &message); +void check_params_no(int objc, int required, int maximum, const std::string &message); // helper for gathering optional params in variadic functions object get_var_params(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int from, policies const &pol); @@ -128,17 +191,18 @@ class callback_base { public: virtual ~callback_base() {} - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) = 0; + virtual void invoke(interpreter *, void * p, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], bool object_dot_method) = 0; + virtual void install(interpreter *) = 0; + virtual void uninstall(interpreter *) = 0; }; // base class for object command handlers // and for class handlers -class object_cmd_base { +class object_cmd_base : public callback_base { public: // destructor not needed, but exists to shut up the compiler warnings - virtual ~object_cmd_base() {} - - virtual void invoke(void *p, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) = 0; + //virtual ~object_cmd_base() {} + //virtual void invoke(void *p, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], bool object_dot_method) = 0; }; // base class for all class handlers, still abstract @@ -148,327 +212,3000 @@ class class_handler_base : public object_cmd_base { class_handler_base(); - void register_method(std::string const &name, std::shared_ptr ocb, policies const &p); + void register_method(std::string const &name, callback_base * ocb, Tcl_Interp * interp, bool managed); - policies &get_policies(std::string const &name); + //policies &get_policies(std::string const &name); + + void install_methods(interpreter * tcli, Tcl_Interp * interp, const char * prefix, void * obj); + void uninstall_methods(interpreter * tcli, Tcl_Interp * interp, const char * prefix); + ~class_handler_base() { + for (auto & r : methods_) { + delete r.second; + delete[] r.first; + } + } +protected: + struct str_less { + bool operator()(const char * a, const char * b) const { + return strcmp(a, b) < 0; + } + }; - protected: - typedef std::map > method_map_type; + typedef std::map method_map_type; // a map of methods for the given class method_map_type methods_; - policies_map_type policies_; + //policies_map_type policies_; }; // class handler - responsible for executing class methods -template class class_handler : public class_handler_base { +template +class class_handler : public class_handler_base { public: - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - C *p = static_cast(pv); - - if (objc < 2) { - throw tcl_error(pol.usage_); - } + virtual void invoke(interpreter * tcli, void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], bool object_dot_method) { + C * p = static_cast(pv); - std::string methodName(Tcl_GetString(objv[1])); - - if (methodName == "-delete") { + char * methodName = Tcl_GetString(objv[1]); + if (objc == 2 && strcmp(methodName, "-delete") == 0) { Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); delete p; return; } - // dispatch on the method name - method_map_type::iterator it = methods_.find(methodName); if (it == methods_.end()) { - throw tcl_error("Method " + methodName + " not found."); + throw tcl_error("Method " + std::string(methodName) + " not found."); } - it->second->invoke(pv, interp, objc, objv, pol); + it->second->invoke(tcli, pv, interp, objc, objv, false); } + void install(interpreter *) { } + void uninstall(interpreter *) { } }; +} // details -// factory functions for creating class objects -#include "cpptcl/details/constructors.h" +class interpreter; -// actual callback envelopes -#include "cpptcl/details/callbacks.h" +template +struct objref { + T * val_; + Tcl_Obj * obj_; + T * operator->() { + return &val_; + } + T const * operator->() const { + return &val_; + } + T & operator*() { + return val_; + } + T const & operator*() const { + return val_; + } +}; -// actual method envelopes -#include "cpptcl/details/methods.h" +template +struct optional { + T val; + bool valid; + bool is_reference_; + + bool is_reference() const { return is_reference_; } + operator bool() const { return valid; } + T const & operator*() const { + if (!valid) { + throw tcl_error("retrieving value of unspecified optional attempted"); + } + return val; + } + T const * operator->() const { + if (!valid) { + throw tcl_error("retrieving value of unspecified optional attempted"); + } + return &val; + } + optional() : valid(false) { } + optional(T) : valid(false) { } + optional(T t, bool v, bool ref) : val(t), valid(v), is_reference_(ref) { } + operator std::optional() { return valid ? std::optional(val) : std::optional(); } +}; -// helper meta function for figuring appropriate constructor callback -#include "cpptcl/details/metahelpers.h" +template +struct getopt : public optional { + using optional::optional; + using optional::operator std::optional; +}; -// this class is used to provide the "def" interface for defining -// class member functions +template +struct getopt_d : public optional { + using optional::optional; +}; -template class class_definer { - public: - class_definer(std::shared_ptr> ch) : ch_(ch) {} +template +using opt = optional; - template class_definer &def(std::string const &name, R (C::*f)(), policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method0(f)), p); - return *this; - } +template +struct any; - template class_definer &def(std::string const &name, R (C::*f)() const, policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method0(f)), p); - return *this; - } +namespace details { +template +struct is_any { + static const bool value = false; +}; +template +struct is_any > { + static const bool value = true; +}; - template class_definer &def(std::string const &name, R (C::*f)(T1), policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method1(f)), p); - return *this; - } +template +struct is_basic_type_impl { + static const bool value = false; +}; +template +struct is_basic_type_impl { + static const bool value = std::is_same::value || is_basic_type_impl::value; +}; - template class_definer &def(std::string const &name, R (C::*f)(T1) const, policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method1(f)), p); - return *this; - } +template +struct is_basic_type { + static const bool value = is_basic_type_impl >::value; +}; +} // details - template class_definer &def(std::string const &name, R (C::*f)(T1, T2), policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method2(f)), p); - return *this; - } +template +struct overloaded { + std::tuple ts; +}; - template class_definer &def(std::string const &name, R (C::*f)(T1, T2) const, policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method2(f)), p); - return *this; - } +template +overloaded overload(Ts... ts) { + return overloaded{ { ts... } }; +}; - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3), policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method3(f)), p); - return *this; +template +struct list { + interpreter * interp_; + Tcl_Obj * lo_; + Tcl_ObjType ** ot_; + bool list_owner_ = false; + + static const bool isany = details::is_any::value; + + list() : interp_(nullptr) { } + list(interpreter * interp, Tcl_Obj * lo, Tcl_ObjType ** ot, bool list_owner = false) : interp_(interp), lo_(lo), ot_(ot), list_owner_(list_owner) { + if (list_owner) { + Tcl_IncrRefCount(lo); + } } - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3) const, policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method3(f)), p); - return *this; + list(list const & o) : interp_(o.interp_), lo_(o.lo_), ot_(o.ot_), list_owner_(o.list_owner_) { + if (list_owner_) { + Tcl_IncrRefCount(lo_); + } } - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4), policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method4(f)), p); - return *this; + ~list() { + if (list_owner_) { + Tcl_DecrRefCount(lo_); + } } + + //list(list const & other) : ot_(other.ot_), interp_(other.interp_), lo_(other.lo_) { std::cerr << '#'; } + + typedef typename std::conditional::value || std::is_same::value, T, T *>::type return_t; - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4) const, policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method4(f)), p); - return *this; + operator bool() const { + return interp_; } - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4, T5), policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method5(f)), p); - return *this; + struct iterator { + const list * l; + std::size_t ix; + return_t operator*() const { + return l->at(ix); + } + void operator++(int) { ++ix; } + void operator++() { ++ix; } + bool operator!=(const iterator & other) { return ix != other.ix; } + }; + iterator begin() const { + return iterator{this, 0}; } - - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4, T5) const, policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method5(f)), p); - return *this; + iterator end() const { + return iterator{this, size()}; } - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4, T5, T6), policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method6(f)), p); - return *this; + std::size_t size() const ; + return_t at(std::size_t ix) const { + return with_obj_at(ix).first; } - - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4, T5, T6) const, policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method6(f)), p); - return *this; + return_t operator[](std::size_t ix) const { return at(ix); } + bool is_reference(std::size_t ix) const { + Tcl_Obj * o = obj_at(ix); + if (o->typePtr == ot_[0]) { return true; } + else if (o->typePtr == ot_[1]) { return false; } } + std::pair with_obj_at(std::size_t ix) const; + Tcl_Obj * obj_at(std::size_t ix) const; +}; - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4, T5, T6, T7), policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method7(f)), p); - return *this; - } +template +struct variadic { + Tcl_Obj * const * objv; + int objc; + interpreter * interp_; + + variadic() : objc(0) { } + variadic(interpreter * i, int c, Tcl_Obj * const * v) : interp_(i), objv(v), objc(c) { } + int size() const { return objc; } + T at(int ix) const; + T operator[](int ix) const { return at(ix); } + struct iterator { + variadic const * v; + int ix; + bool operator!=(const iterator & other) { return ix != other.ix; } + void operator++() { ++ix; } + T operator *() { return v->at(ix); } + }; + iterator begin() const { return iterator{ this, 0 }; } + iterator end() const { return iterator{ this, size() }; } + operator bool() const { return objc; } +}; - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4, T5, T6, T7) const, policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method7(f)), p); - return *this; +// allow variadic() to be used to indicate traditional variadic policies +struct variadic_compat_tag; +variadic() -> variadic; +template <> +struct variadic : public policies { + variadic() { + variadic_ = true; } +}; - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4, T5, T6, T7, T8), policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method8(f)), p); - return *this; - } +namespace details { - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4, T5, T6, T7, T8) const, policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method8(f)), p); - return *this; - } +template +struct is_variadic { + static const bool value = false; +}; +template +struct is_variadic > { + static const bool value = true; +}; - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4, T5, T6, T7, T8, T9), policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method9(f)), p); - return *this; - } +template +struct has_variadic { + static const bool value = false; +}; +template +struct has_variadic : public has_variadic { }; +template +struct has_variadic, Ts...> { + static const bool value = true; +}; +template +struct has_variadic const &, Ts...> { + static const bool value = true; +}; - template class_definer &def(std::string const &name, R (C::*f)(T1, T2, T3, T4, T5, T6, T7, T8, T9) const, policies const &p = policies()) { - ch_->register_method(name, std::shared_ptr(new details::method9(f)), p); - return *this; - } +template +struct remove_rc { + typedef T type; +}; +template +struct remove_rc { + typedef T type; +}; - private: - std::shared_ptr> ch_; +template +struct is_list { + static const bool value = false; +}; +template +struct is_list > { + static const bool value = true; }; -} // namespace details +template +struct all_lists_impl { + static const bool value = true; +}; +template +struct all_lists_impl, Ts...> { + static const bool value = all_lists_impl::value; +}; +template +struct all_lists_impl { + static const bool value = false; +}; -// init type for defining class constructors -template class init {}; +template +struct all_lists { + static const bool value = false; +}; +template +struct all_lists > : public all_lists_impl { +}; -// no_init type and object - to define classes without constructors -namespace details { -struct no_init_type {}; -} // namespace details -extern details::no_init_type no_init; +#if 0 +template +struct any_impl { + Tcl_Obj * o_; +}; +template +struct any_impl : public any_impl { +}; +#endif -// interpreter wrapper -class interpreter { - public: - static interpreter *defaultInterpreter; +template +struct type_at { + static const int value = -1; +}; +template +struct type_at { + static const int value = std::is_same::value ? sizeof...(Ts) : type_at::value; +}; +} - static interpreter *getDefault() { - if (defaultInterpreter == NULL) { - throw tcl_error("No default interpreter available"); +template +struct any { //: public details::any_impl { + //typedef details::any_impl super_t; + //any() { super_t::which_ = -1; } + interpreter * interp_; + Tcl_ObjType ** ot_; + bool list_owner_ = false; + Tcl_Obj * o_; + + any(interpreter * i, Tcl_Obj * o, Tcl_ObjType ** ot, bool list_owner = false) : interp_(i), ot_(ot), list_owner_(list_owner), o_(o) { + if (list_owner) { + Tcl_IncrRefCount(this->o_); + } + } + any(any const & o) : interp_(o.interp_), ot_(o.ot_), list_owner_(o.list_owner_), o_(o.o_) { + if (list_owner_) { + Tcl_IncrRefCount(this->o_); + } + } + any() : o_(nullptr) { } + ~any() { + if (list_owner_) { + Tcl_DecrRefCount(this->o_); } - return defaultInterpreter; } - private: - interpreter(const interpreter &i); - interpreter(); - - public: - interpreter(Tcl_Interp *, bool owner = false); - ~interpreter(); - - void make_safe(); - - Tcl_Interp *get() const { return interp_; } + object as_object(); + + bool is_reference() const { + for (int i = 0; i < sizeof...(Ts); ++i) { + if (ot_[i] == this->o_->typePtr) { + return true; + } else if (ot_[i] + 1 == this->o_->typePtr) { + return false; + } + } + throw("is_reference called on invalid any<> object"); + } + operator bool() const { + if (! o_) return false; + for (int i = 0; i < sizeof...(Ts); ++i) { + if (ot_[i] == this->o_->typePtr || ot_[i] + 1 == this->o_->typePtr) return true; + } + return false; + } - // free function definitions + template + bool visit(Fs... f) const; + + template + typename std::conditional::value, TT, TT *>::type as() const; +}; - template void def(std::string const &name, R (*f)(), policies const &p = policies()) { add_function(name, std::shared_ptr(new details::callback0(f)), p); } +namespace details { struct init_default_tag { }; } - template void def(std::string const &name, R (*f)(T1), policies const &p = policies()) { add_function(name, std::shared_ptr(new details::callback1(f)), p); } +template struct init { + bool default_; + init() : default_(false) { } + init(details::init_default_tag) : default_(true) { } +}; - template void def(std::string const &name, R (*f)(T1, T2), policies const &p = policies()) { add_function(name, std::shared_ptr(new details::callback2(f)), p); } +namespace details { - template void def(std::string const &name, R (*f)(T1, T2, T3), policies const &p = policies()) { add_function(name, std::shared_ptr(new details::callback3(f)), p); } +template +struct is_optional { + static const bool value = false; +}; +template +struct is_optional > { + static const bool value = true; +}; +template +struct is_optional const &> { + static const bool value = true; +}; - template void def(std::string const &name, R (*f)(T1, T2, T3, T4), policies const &p = policies()) { add_function(name, std::shared_ptr(new details::callback4(f)), p); } +template +struct is_getopt { + static const bool value = false; +}; +template +struct is_getopt > { + static const bool value = true; +}; +template +struct is_getopt const &> { + static const bool value = true; +}; - template void def(std::string const &name, R (*f)(T1, T2, T3, T4, T5), policies const &p = policies()) { add_function(name, std::shared_ptr(new details::callback5(f)), p); } +template +struct is_getopt_d { + static const bool value = false; +}; +template +struct is_getopt_d > { + static const bool value = true; +}; +template +struct is_getopt_d const &> { + static const bool value = true; +}; - template void def(std::string const &name, R (*f)(T1, T2, T3, T4, T5, T6), policies const &p = policies()) { add_function(name, std::shared_ptr(new details::callback6(f)), p); } - template void def(std::string const &name, R (*f)(T1, T2, T3, T4, T5, T6, T7), policies const &p = policies()) { add_function(name, std::shared_ptr(new details::callback7(f)), p); } +template +struct optional_unpack { + typedef T type; +}; +template +struct optional_unpack > { + typedef T type; +}; +template +struct optional_unpack > { + typedef T type; +}; +template +struct optional_unpack > { + typedef T type; +}; - template void def(std::string const &name, R (*f)(T1, T2, T3, T4, T5, T6, T7, T8), policies const &p = policies()) { add_function(name, std::shared_ptr(new details::callback8(f)), p); } +template +struct list_unpack { + typedef T type; +}; +template +struct list_unpack > { + typedef T type; +}; - template void def(std::string const &name, R (*f)(T1, T2, T3, T4, T5, T6, T7, T8, T9), policies const &p = policies()) { add_function(name, std::shared_ptr(new details::callback9(f)), p); } +template +struct ppack { +}; - // class definitions +template +struct num_optional { + static const int value = 0; +}; +template +struct num_optional { + static const int value = num_optional::value + (is_optional::value ? 1 : 0); +}; - template details::class_definer class_(std::string const &name) { - std::shared_ptr> ch(new details::class_handler()); +template +struct num_getopt { + static const int value = 0; +}; +template +struct num_getopt { + static const int value = num_getopt::value + (is_getopt::value ? 1 : 0); +}; +template +struct num_getopt_d { + static const int value = 0; +}; +template +struct num_getopt_d { + static const int value = num_getopt_d::value + (is_getopt_d::value ? 1 : 0); +}; - add_class(name, ch); - add_constructor(name, ch, std::shared_ptr(new details::callback0(&details::construct::doit))); +template +struct getopt_index { + static const int value = -1; +}; +template +struct getopt_index, Ts...> { + static const int value = Ix == Itarget ? Ipos : getopt_index::value; +}; +template +struct getopt_index const &, Ts...> { + static const int value = Ix == Itarget ? Ipos : getopt_index::value; +}; +template +struct getopt_index { + static const int value = getopt_index::value; +}; - return details::class_definer(ch); +template +struct visit_impl { + template + static bool invoke(any const &) { + return false; } +}; - template details::class_definer class_(std::string const &name, init const &, policies const &p = policies()) { - typedef typename details::get_callback_type_for_construct::type callback_type; - - std::shared_ptr> ch(new details::class_handler()); - - add_class(name, ch); - - add_constructor(name, ch, std::shared_ptr(new callback_type(&details::construct::doit)), p); +class no_argument_match { }; +template +struct argument_type { + typedef no_argument_match type; +}; +template +struct argument_type { + typedef typename std::conditional::type, T>::type arg1_t; + + typedef typename std::conditional< + std::is_invocable::value || std::is_invocable::value, + T, + typename argument_type::type + >::type type; +}; - return details::class_definer(ch); +template +struct visit_impl { + template + static bool invoke(any const & a, F f, Fs... fs) { + typedef typename argument_type::type arg_t; + typedef typename argument_type::type arg_list_t; + + if constexpr (! std::is_same::value || ! std::is_same::value) { + if constexpr (!std::is_same::value) { + if (arg_list_t li = a.template as()) { + if constexpr (std::is_invocable::value) { + for (auto && i : li) { + if constexpr (std::is_same::type, bool>::value) { + if (! f(i)) break; + } else { + f(i); + } + } + } else if constexpr (std::is_invocable::value) { + for (std::size_t i = 0; i < li.size(); ++i) { + auto both = li.with_obj_at(i); + if constexpr (std::is_same::type, bool>::value) { + if (! f(both.first, both.second)) break; + } else { + f(both.first, both.second); + } + } + } + return true; + } + } else { + if (arg_t * p = a.template as()) { + if constexpr (std::is_invocable::value) { + f(p); + } else if constexpr (std::is_invocable::value) { + f(p, nullptr); + } + return true; + } + } + } + return visit_impl::invoke(a, fs...); } +}; - template details::class_definer class_(std::string const &name, details::no_init_type const &) { - std::shared_ptr> ch(new details::class_handler()); +inline std::string tcl_typename(Tcl_ObjType const * ot) { + std::ostringstream oss; + oss << ot; + return std::string(ot ? ot->name : "()") + "@" + oss.str(); +} +inline std::string tcl_typename(Tcl_Obj const * o) { + return tcl_typename(o->typePtr); +} +} - add_class(name, ch); +template +template +bool any::visit(Fs... f) const { + return details::visit_impl::invoke(*this, f...); +} - return details::class_definer(ch); +namespace details { +template +struct generate_hasarg { + static void invoke(bool * arr, std::string *, std::string *, const char *, bool) { } +}; +template +struct generate_hasarg { + static void invoke(bool * arr, std::string * opts, std::string * defaults, const char * p, bool may_have_defaults) { + if constexpr (is_getopt_d::value) { + while (*p && isspace(*p)) ++p; + if (p) { + const char * pend = p; + while (*pend && !isspace(*pend) && *pend != '=') ++pend; + } + generate_hasarg::invoke(arr, opts, defaults, p, may_have_defaults); + } else if constexpr (!is_getopt::value) { + generate_hasarg::invoke(arr, opts, defaults, p, may_have_defaults); + } else { + arr[I] = !std::is_same::type, getopt >::value; + while (*p && isspace(*p)) ++p; + if (p) { + const char * pend = p; + while (*pend && !isspace(*pend) && *pend != '=') ++pend; + opts[I] = std::string(p, pend - p); + if (*pend == '=') { + if (!may_have_defaults) { + throw tcl_error("function is not allowed to have defaults"); + } + ++pend; p = pend; + while (*pend && !isspace(*pend)) ++pend; + defaults[I] = std::string(p, pend - p); + } + generate_hasarg::invoke(arr, opts, defaults, pend, may_have_defaults); + } else { + std::cerr << "option error\n"; + } + } } +}; - // free script evaluation - details::result eval(std::string const &script); - details::result eval(std::istream &s); +template +struct no_type { }; - details::result eval(object const &o); +template +struct signature { }; - // the InputIterator should give object& or Tcl_Obj* when dereferenced - template details::result eval(InputIterator first, InputIterator last); +template +struct subtype_notype_tag { + static const int value = 0; +}; +template +struct subtype_notype_tag > { + static const int value = I; +}; - // Get a variable from TCL interpreter with Tcl_GetVar - details::result getVar(std::string const &scalarTclVariable); - details::result getVar(std::string const &arrayTclVariable, std::string const &arrayIndex); +template +struct subtype { + typedef no_type type; +}; +template +struct subtype<0, T, false> { + typedef T type; +}; - // check if variables exist - bool exists(std::string const &scalarTclVariable); - bool exists(std::string const &arrayTclVariable, std::string const &arrayIndex); +template +struct subtype, true> { + typedef typename subtype::type type; +}; +template +struct subtype<0, list, false> { + typedef typename subtype<0, T>::type type; +}; - // create alias from the *this interpreter to the target interpreter - void create_alias(std::string const &cmd, interpreter &targetInterp, std::string const &targetCmd); +template +struct subtype, true> { + typedef typename subtype::type t1; - // register a package info (useful when defining packages) - void pkg_provide(std::string const &name, std::string const &version); + typedef typename std::conditional< + sizeof...(Ts) && bool(subtype_notype_tag::value), + typename subtype::value - 1, any >::type, + typename subtype::type + >::type type; +}; +template +struct subtype<0, any, false> { + typedef typename subtype<0, T>::type t1; + + typedef typename std::conditional< + sizeof...(Ts) && bool(subtype_notype_tag::value), + typename subtype::value, any >::type, + typename subtype<0, T>::type + >::type type; +}; - // create a namespace - void create_namespace(std::string const &name); +template +struct subtype, true> { + typedef typename subtype::type t1; - // helper for cleaning up callbacks in non-managed interpreters - static void clear_definitions(Tcl_Interp *); + typedef typename std::conditional< + bool(subtype_notype_tag::value), + typename subtype::value, signature >::type, + typename subtype::type + >::type type; +}; - private: - void operator=(const interpreter &); +template +struct subtype, true> { + typedef typename subtype::type type; +}; +template +struct subtype, true > { + typedef typename subtype::type type; +}; +template +struct subtype, true> { + typedef typename subtype::type type; +}; - void add_function(std::string const &name, std::shared_ptr cb, policies const &p = policies()); +template +struct subtype<0, getopt, false> { + typedef typename subtype<0, T>::type type; +}; +template +struct subtype<0, opt, false> { + typedef typename subtype<0, T>::type type; +}; +template +struct subtype<0, variadic, false> { + typedef typename subtype<0, T>::type type; +}; - void add_class(std::string const &name, std::shared_ptr chb); +template +struct num_subtypes { + static const int value = 1 + 100000 - subtype_notype_tag::type>::value; +}; - void add_constructor(std::string const &name, std::shared_ptr chb, std::shared_ptr cb, policies const &p = policies()); +template +struct generate_argtypes { + static void invoke(interpreter *, Tcl_ObjType **) { } + static const int length = 0; +}; - Tcl_Interp *interp_; - bool owner_; +template +struct fix_variadic_return { + //typedef typename std::decay::type type; + typedef T type; +}; +template +struct fix_variadic_return const &, Last> { + typedef opt type; +}; +template +struct fix_variadic_return const &, Last> { + typedef getopt type; +}; +template +struct fix_variadic_return const &, Last> { + typedef getopt_d type; }; -#include "cpptcl/cpptcl_object.h" +template +struct fix_variadic_return const &, Last> { + typedef list type; +}; +template +struct fix_variadic_return const &, Last> { + typedef any type; +}; +template +struct fix_variadic_return const &, Last> { + typedef variadic type; +}; +template +struct fix_variadic_return { + typedef std::string type; +}; -// the InputIterator should give object& or Tcl_Obj* when dereferenced -template details::result interpreter::eval(InputIterator first, InputIterator last) { - std::vector v; - object::fill_vector(v, first, last); - int cc = Tcl_EvalObjv(interp_, static_cast(v.size()), v.empty() ? NULL : &v[0], 0); - if (cc != TCL_OK) { - throw tcl_error(interp_); +template <> +struct fix_variadic_return { + typedef object type; +}; +template +struct return_dummy_value { + static typename std::decay::type doit(object const &) { + return typename std::decay::type(); + } + template + static typename std::decay::type doit(OptionalT, bool) { + return typename std::decay::type(); + } + static typename std::decay::type doit(Tcl_Interp *, Tcl_Obj *, Tcl_ObjType *) { + return typename std::decay::type(); + } +}; +template struct return_dummy_value { + static TT doit(object const & o) { + return o; + } + template + static TT doit(OptionalT o, bool v) { + return TT(o, v); } + static TT doit(interpreter * i, Tcl_Obj * o, Tcl_ObjType *ot) { + return TT(i, o, ot); + } +}; +template +TT do_cast(ppack, bool variadic, Tcl_Interp * interp, int objc, Tcl_Obj * CONST objv[], int getoptc, Tcl_Obj * CONST getoptv[], policies const & pol); - return details::result(interp_); -} +struct no_init_type {}; +struct no_class { }; +struct no_class_lambda { }; -namespace details { +template +struct class_lambda { }; -// additional callback envelopes for variadic functions -#include "cpptcl/details/callbacks_v.h" +template +struct conversions { +}; + +template +struct conversion_ix { }; +template +struct conversion_t { }; + +template +struct make_conversions { +}; + +struct default_conversion { +}; + +struct conversions_end { +}; + +struct conversion_error { +}; + +template +struct make_conversions, conversion_t > { + typedef conversions_end type; + typedef conversions_end recurse; +}; + +template +struct make_conversions, conversion_t > { + typedef typename std::conditional::type type; + typedef typename std::conditional + , conversion_t >, + make_conversions, conversion_t > >::type recurse; +}; + +template +struct conversion_at { + typedef typename std::conditional + ::type>::type type; +}; + +template +struct conversion_at { + typedef conversion_error type; +}; + +struct callback_empty_base { }; +template +struct callback_no_baseclass { }; // policy tag + +template +struct callback_base_type { + typedef object_cmd_base type; +}; +template <> +struct callback_base_type { + typedef callback_base type; +}; +template +struct callback_free_method { }; // policy tag + +template +struct callback_postproc { }; // policy tag + +template +struct callback_attributes { }; + +template +struct callback_base_type > { + typedef callback_empty_base type; +}; + +template +struct callback_pass_interpreter { }; // policy tag + +template +struct attributes { + static const bool cold = cold_; +}; +template +struct is_attribute { + static const bool value = false; +}; + +template +struct is_attribute > { + static const bool value = true; +}; + +template +struct callback_policy_unpack { + typedef T type; + static const bool no_base = false; + static const bool free_method = false; + static const bool class_lambda = false; + static const bool postproc = true; + static const bool pass_interp = false; + typedef attributes<> attr; +}; + +template +struct callback_policy_unpack > : public callback_policy_unpack { + static const bool no_base = P; +}; +template +struct callback_policy_unpack > : public callback_policy_unpack { + static const bool postproc = P; +}; + +template +struct callback_policy_unpack > : public callback_policy_unpack { + typedef A attr; + //typedef typename attributes_merge::type attr; +}; + +template +struct callback_policy_unpack > : public callback_policy_unpack { + static const bool free_method = true; +}; +template +struct callback_policy_unpack > : public callback_policy_unpack { + static const bool class_lambda = true; +}; + +template +struct callback_policy_unpack > : public callback_policy_unpack { + static const bool pass_interp = true; +}; + +template +class callback_v : public callback_base_type::type { + typedef callback_v this_t; + + struct client_data { + this_t * this_p; + interpreter * interp; + }; + static void cleanup_client_data(ClientData cd) { + client_data * p = (client_data *) cd; + delete p; + } + + typedef callback_policy_unpack pol_t; + typedef typename pol_t::type C; + + static const bool may_have_defaults = false; + + typedef Fn functor_type; + policies policies_; + functor_type f_; + + static const int num_opt = num_getopt::value + num_getopt_d::value; + std::string opts_[num_opt], defaults_[num_opt]; + + bool has_arg_[num_opt + 1] = { false }; + + static const int arg_offset = -num_opt; + + Tcl_ObjType * argument_types_all_[generate_argtypes<0, Ts...>::length + 1]; + + //interpreter * interpreter_; + Conv conv_; + + std::string name_; + + static const bool cold = pol_t::attr::cold; +public : + static const int num_arguments = (std::is_same::value || pol_t::free_method ? 0 : 1) + sizeof...(Ts); + +#ifdef COLD +#error fixme +#else +#define COLD __attribute__((optimize("s"))) __attribute__((cold)) +#endif + + callback_v(interpreter * i, functor_type f, std::string const & name, policies const & pol = policies(), Conv conv = Conv()) COLD : policies_(pol), f_(f), conv_(conv), name_(name) { + if (num_opt) { + if (pol.options_.empty()) { + throw tcl_error(std::string("no getopt string supplied for function \"") + name + "\" taking getopt<> arguments"); + } + generate_hasarg<0, Ts...>::invoke(has_arg_, opts_, defaults_, pol.options_.c_str(), may_have_defaults); + } + generate_argtypes<0, Ts...>::invoke(i, argument_types_all_); + } + void install(interpreter *) __attribute__((optimize("s"))); + void uninstall(interpreter *) __attribute__((optimize("s"))); + void invoke(interpreter * tcli, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv [], bool object_dot_method) { + checked_invoke_impl(tcli, pv, interp, argc, argv, object_dot_method); + } + void invoke_impl(interpreter *, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv [], bool object_dot_method) COLD; + + ~callback_v() COLD { } +private : + template struct void_return { }; + + template + std::pair args() { + return generate_argtypes<0, Ts...>::template get(argument_types_all_); + } + + template + void do_invoke(std::index_sequence const &, interpreter *, CC * p, Tcl_Interp * interp, int argc, Tcl_Obj * const argv[], int getoptc, Tcl_Obj * const getoptv[], policies const & pol, void_return) __attribute__((optimize(cold ? "s" : "3"))); + template + void do_invoke(std::index_sequence const &, interpreter *, CC * p, Tcl_Interp * interp, int argc, Tcl_Obj * const argv[], int getoptc, Tcl_Obj ** getoptv, policies const & pol, void_return) __attribute__((optimize(cold ? "s" : "3"))); + + int checked_invoke_impl(interpreter *, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv [], bool object_dot_method) __attribute__((optimize(cold ? "s" : "3"))); + + static int callback_handler(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) __attribute__((optimize(cold ? "s" : "3"))); + +}; + +template +template +void callback_v::do_invoke(std::index_sequence const &, interpreter * tcli, CC * p, Tcl_Interp * interp, int argc, Tcl_Obj * const argv[], int getoptc, Tcl_Obj * const getoptv[], policies const & pol, void_return) { + if (argc && argv) { } + + if constexpr (pol_t::pass_interp) { + if constexpr (pol_t::class_lambda) { + details::set_result(interp, f_(tcli, p, do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...)); + } else if constexpr (std::is_same::value || pol_t::free_method) { + details::set_result(interp, f_(tcli, do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...)); + } else { + details::set_result(interp, (p->*f_)(tcli, do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...)); + } + } else { + if constexpr (pol_t::class_lambda) { + details::set_result(interp, f_(p, do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...)); + } else if constexpr (std::is_same::value || pol_t::free_method) { + details::set_result(interp, f_(do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...)); + } else { + details::set_result(interp, (p->*f_)(do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...)); + } + } +} + +template +template +void callback_v::do_invoke(std::index_sequence const &, interpreter * tcli, CC * p, Tcl_Interp * interp, int argc, Tcl_Obj * const argv[], int getoptc, Tcl_Obj ** getoptv, policies const & pol, void_return) { + if (argc && argv && interp) { } + + if constexpr (pol_t::pass_interp) { + if constexpr (pol_t::class_lambda) { + f_(tcli, p, do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...); + } else if constexpr (std::is_same::value || pol_t::free_method) { + f_(tcli, do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...); + } else { + (p->*f_)(tcli, do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...); + } + } else { + if constexpr (pol_t::class_lambda) { + f_(p, do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...); + } else if constexpr (std::is_same::value || pol_t::free_method) { + f_(do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...); + } else { + (p->*f_)(do_cast(tcli, args(), ppack(), pol.variadic_, interp, argc, argv, getoptc, getoptv, pol, conv_, p)...); + } + } +} + + +template , typename E = void> +struct callback_expand_f { +}; + +template +struct callback_expand_f::value>::type> { + typedef callback_v, no_base>, postproc> >, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f::value>::type> { + typedef callback_v, Attr>, no_base>, postproc> >, Conv, Fn, R, Ts...> type; +}; + +template +struct callback_expand_f::value>::type> { + typedef callback_v, no_base>, postproc>, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f::value>::type> { + typedef callback_v, Attr>, no_base>, postproc>, Conv, Fn, R, Ts...> type; +}; + +template +struct callback_expand_f, postproc, no_base, Attr> { + typedef callback_v, no_base>, postproc>, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f, postproc, no_base, Attr> { + typedef callback_v, Attr>, no_base>, postproc>, Conv, Fn, R, Ts...> type; +}; + +template +struct senti { }; + +template +struct callback_expand_f2 { + typedef typename senti::type type; +}; + +// 6 definitions without pass_interpreter +template +struct callback_expand_f2 { + typedef callback_v, no_base>, postproc> >, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f2 { + typedef callback_v, no_base>, postproc> >, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f2 { + typedef callback_v, no_base>, postproc> >, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f2 { + typedef callback_v, no_base>, postproc> >, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f2 { + typedef callback_v, no_base>, postproc>, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f2 { + typedef callback_v, no_base>, postproc>, Conv, Fn, R, Ts...> type; +}; + +// same 6 definitions with pass_interpreter +template +struct callback_expand_f2 { + typedef callback_v, Attr>, no_base>, postproc> >, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f2 { + typedef callback_v, Attr>, no_base>, postproc> >, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f2 { + typedef callback_v, Attr>, no_base>, postproc> >, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f2 { + typedef callback_v, Attr>, no_base>, postproc> >, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f2 { + typedef callback_v, Attr>, no_base>, postproc>, Conv, Fn, R, Ts...> type; +}; +template +struct callback_expand_f2 { + typedef callback_v, Attr>, no_base>, postproc>, Conv, Fn, R, Ts...> type; +}; + + + + + + + + +template +struct is_std_function { + static const bool value = false; +}; +template +struct is_std_function > { + static const bool value = true; +}; + +template +struct callback_expand_f::value && !is_std_function::value>::type> { + typedef typename callback_expand_f2::type type; +}; + +template +struct num_arguments { + static const int value = -1; +}; + +template +struct num_arguments { + static const int value = sizeof...(Ts); +}; + +template +static void overload_enumerate(Fn fn, Tup const & tup) { + fn(&std::get(tup)); + if constexpr (Ix < std::tuple_size::value - 1) { + overload_enumerate(fn, tup); + } +} + +template +struct overloaded_callback : public callback_base_type::type { + typedef overloaded_callback this_t; + typedef callback_policy_unpack pol_t; + typedef typename pol_t::type Cparm_out; + + static const bool cold = pol_t::attr::cold; + + struct client_data { + this_t * this_p; + interpreter * interp; + }; + static void cleanup_client_data(ClientData cd) { + client_data * p = (client_data *) cd; + delete p; + } + + //interpreter * interpreter_; + std::string name_; -// additional method envelopes for variadic methods -#include "cpptcl/details/methods_v.h" + std::tuple>::type...> callbacks_; + + overloaded_callback(interpreter * i, overloaded f, std::string const & name, policies const & pol, Conv conv) + : overloaded_callback(std::make_index_sequence(), i, f, name, pol, conv) { + } + + template + overloaded_callback(std::index_sequence const &, interpreter * i, overloaded f, std::string const & name, policies const & pol, Conv conv) + : name_(name), callbacks_(typename callback_expand_f>::type(i, std::get(f.ts), name, pol, conv)...) { } + + template + void do_invoke(interpreter * tcli, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv[], bool object_dot_method) __attribute__((optimize(cold ? "s" : "3"))); + + static int callback_handler(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) __attribute__((optimize(cold ? "s" : "3"))); + int checked_invoke_impl(interpreter * tcli, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv[], bool object_dot_method) __attribute__((optimize(cold ? "s" : "3"))); + void invoke_impl(interpreter * tcli, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv[], bool object_dot_method) __attribute__((optimize(cold ? "s" : "3"))); + void invoke(interpreter * tcli, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv[], bool object_dot_method) { + checked_invoke_impl(tcli, pv, interp, argc, argv, object_dot_method); + } + void install(interpreter * tcli) COLD; + void uninstall(interpreter * tcli) COLD; +}; + +template +template +void overloaded_callback::do_invoke(interpreter * tcli, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv[], bool object_dot_method) { + if (std::tuple_element::type::num_arguments + 1 == argc) { + std::get(callbacks_).invoke_impl(tcli, pv, interp, argc, argv, object_dot_method); + return; + } + if constexpr (ti + 1 < std::tuple_size::value) { + do_invoke(tcli, pv, interp, argc, argv, object_dot_method); + } else { + std::cerr << "wrong number of arguments, overload accepts any of:"; + overload_enumerate<0>([&] (auto * o) { + std::cerr << " " << std::remove_pointer::type::num_arguments; + }, callbacks_); + std::cerr << " arguments\n"; + + } +} + +template +struct std_function { + typedef void type; +}; +template +struct std_function { + typedef std::function type; +}; +} + +template +struct lambda_wrapper { Fn fn; lambda_wrapper(Fn f) : fn(f) { } }; + +namespace details { +template +struct is_lambda_wrapper { + static const bool value = false; +}; +template +struct is_lambda_wrapper > { + static const bool value = true; +}; + +inline policies default_policies; + +template +inline policies const & extra_args_policies(E const & e, Extra... extra) { + if constexpr (std::is_same::type, policies>::value) { + return e; + } + return default_policies; +} + +inline policies const & extra_args_policies() { + return default_policies; +} + +inline auto extra_args_conversions() { + return std::tuple<>(); +} + +template +struct has_policies { + static const bool value = false; +}; + +template +struct has_policies { + static const bool value = std::is_same::value ? true : has_policies::value; +}; + +template +inline auto extra_args_conversions(E e, Extra... extra) { + if constexpr (std::is_same::type, policies>::value) { + return extra_args_conversions(extra...); + } else if constexpr (is_lambda_wrapper::value) { + return extra_args_conversions(extra...); + } else if constexpr (is_attribute::value) { + return extra_args_conversions(extra...); + } else { + return std::tuple(e, extra...); + } +} + +template +inline auto apply_extra_args_wrappers(Fn fn) { + return fn; +} + +template +inline auto apply_extra_args_wrappers(Fn fn, E e, Extra... extra) { + if constexpr (std::is_same::type, policies>::value) { + return apply_extra_args_wrappers(fn, extra...); + } else if constexpr (is_lambda_wrapper::value) { + return e.fn(fn); + } else { + return fn; + } +} +template +struct attributes_merge { + typedef attributes<> type; +}; + +template +struct attributes_merge { + typedef typename std::conditional::value, E, typename attributes_merge::type>::type type; +}; } // namespace details -#include "cpptcl/details/bind.h" +extern details::no_init_type no_init; + +// interpreter wrapper +class interpreter { + public: + static interpreter *defaultInterpreter; + + static interpreter *getDefault() { + if (defaultInterpreter == NULL) { + throw tcl_error("No default interpreter available"); + } + return defaultInterpreter; + } + void post_process_policies(Tcl_Interp *interp, policies &pol, Tcl_Obj *CONST objv[], bool isMethod); + bool want_abort_ = false; + void want_abort() { + want_abort_ = true; + } + + static std::function capture_callback; +private: + interpreter(const interpreter &i); + interpreter(); + + static bool static_initialized_; + + static int capture_interpreter_init(Tcl_Interp * interp) { + if (capture_callback) { + interpreter * tcli = new interpreter(interp, false); + capture_callback(tcli); + } + return TCL_OK; + } + + static void static_initialize() { + if (! static_initialized_) { + Tcl_StaticPackage(nullptr, "Capture_interpreter", capture_interpreter_init, capture_interpreter_init); + static_initialized_ = true; + } + } + + + + class TclChannelStreambuf : public std::streambuf { + private: + Tcl_Channel channel_; + Tcl_DString iBuffer_; + int iOffset_; + public: + TclChannelStreambuf (Tcl_Channel channel) + : channel_ (channel) + { + Tcl_DStringInit (&iBuffer_); + iOffset_ = 0; + base_ = (char *) malloc(1024); + buf_size_ = 1024; + my_base_ = true; + } + ~TclChannelStreambuf () + { + Tcl_DStringFree (&iBuffer_); + } + + char * base() { + return base_; + } + char * ebuf() { + return base_ + buf_size_; + } + char * base_; + bool my_base_; + std::streamsize buf_size_; + + std::streambuf * setbuf(char * s, std::streamsize n) { + if (my_base_) { + free(base_); + my_base_ = false; + } + base_ = s; + buf_size_ = n; + return this; + } + + std::streamsize xsputn(const char_type * s, std::streamsize n) { + if (base() == 0) { + int r = Tcl_Write(channel_, s, n); + return r; + } + if (pptr() < ebuf()) { + std::streamsize nn = std::min(n, ebuf() - pptr()); + memcpy(pptr(), s, nn); + setp(pptr() + nn, ebuf()); + return nn; + } + return 0; + } + int overflow (int c) { + int status; + + //std::cerr << "overflow " << (char) c << "\n"; + + // Allocate reserve area if necessary + + if (base() == 0) { + char b[1]; + b[0] = c; + status = Tcl_Write (channel_, b, 1); + if (status != 1) return EOF; + return 1; + } + + // If there's no output buffer, allocate one. Place it after the + // end of the input buffer if there's input. + + if (!pbase ()) { + if (egptr () > gptr ()) { + setp (egptr (), ebuf ()); + } else { + setp (base (), ebuf ()); + } + } + + // If there's stuff in the output buffer, write it to the channel. + + if (pptr () > pbase ()) { + status = Tcl_Write (channel_, pbase (), pptr () - pbase ()); + if (status < (pptr () - pbase ())) { + return EOF; + } + setp (pbase (), ebuf ()); + } + + // Save the next character in the output buffer. If there is none, + // flush the channel + + if (c != EOF) { + *(pptr()) = c; + pbump (1); + return c; + } else { + setp (0, 0); + status = Tcl_Flush (channel_); + if (status != TCL_OK) return EOF; + return 0; + } + } + + int underflow () + { + if (egptr() > gptr()) { + return *gptr (); + } + + if (pptr () > pbase ()) { + if (overflow (EOF) == EOF) { + return EOF; + } + } + + // Get a fresh line of input if needed + + if (iOffset_ >= Tcl_DStringLength (&iBuffer_)) { + if (Tcl_Gets (channel_, &iBuffer_)) { + return EOF; + } + Tcl_DStringAppend (&iBuffer_, "\n", 1); + } + + // Determine how much input to transfer. Don't fill the reserve + // area more than half full + + size_t xferlen = Tcl_DStringLength (&iBuffer_); + if ((long) xferlen > (ebuf () - base ()) / 2) { + xferlen = (ebuf () - base ()) / 2; + } + + // Copy string into the buffer, and advance pointers + + memcpy ((void *) base (), (void *) Tcl_DStringValue (&iBuffer_), xferlen); + iOffset_ += xferlen; + setg (base (), base (), base () + xferlen); + + // Free the input string if we're finished with it + + if (iOffset_ >= Tcl_DStringLength (&iBuffer_)) { + Tcl_DStringFree (&iBuffer_); + iOffset_ = 0; + } + + // Return the first character read. + + return *gptr (); + } + + int sync () { + // Flush output + + if (overflow (EOF) == EOF) { + return EOF; + } + + // Discard input + setg (0, 0, 0); + + return 0; + } + }; +public: + std::iostream & tin() { + if (! tin_.rdbuf()) { + tin_.rdbuf(new TclChannelStreambuf (Tcl_GetStdChannel (TCL_STDIN))); + } + return tin_; + } + std::iostream & tout() { + if (! tout_.rdbuf()) { + tout_.rdbuf(new TclChannelStreambuf (Tcl_GetStdChannel (TCL_STDOUT))); + } + return tout_; + } + std::iostream & terr() { + if (! terr_.rdbuf()) { + terr_.rdbuf(new TclChannelStreambuf (Tcl_GetStdChannel (TCL_STDERR))); + terr_.rdbuf()->pubsetbuf(NULL, 0); + } + return terr_; + } + + typedef std::map > all_callbacks_t; + all_callbacks_t all_callbacks_; + typedef std::map > all_classes_t; + all_classes_t all_classes_; + + struct all_classes_by_objtype_value { + std::shared_ptr class_handler; + bool is_inline; + }; + + typedef std::map all_classes_by_objtype_t; + all_classes_by_objtype_t all_classes_by_objtype_; + + static int dot_call_handler(ClientData cd, Tcl_Interp * interp, int objc, Tcl_Obj * CONST * objv); + + std::shared_ptr find_callback(std::string const & name) { + auto it = all_callbacks_.find(name); + if (it != all_callbacks_.end()) { + return std::shared_ptr(it->second); + } + return std::shared_ptr(nullptr); + } + std::shared_ptr find_class(std::string const & name) { + auto it = all_classes_.find(name); + if (it != all_classes_.end()) { + return std::shared_ptr(it->second); + } + return std::shared_ptr(nullptr); + } + + void trace(bool v) { + trace_ = v; + } + bool trace() const { + return trace_; + } + bool trace_ = false; + + int trace_count() const { + return trace_count_; + } + void trace_count(int v) { + trace_count_ = v; + } + + int trace_count_ = 0; + + template , typename R=void, typename ...Ts> + using callback_t = typename details::callback_expand_f::type; + + template + static inline std::integral_constant arg; + + struct { + } res; + + static constexpr details::attributes cold = { }; + + template + static auto eac(Extra... e) { + return details::extra_args_conversions(e...); + } + template + static auto eap(Extra... e) { + return details::extra_args_policies(e...); + } + template + static auto eaw(Fn fn, Extra ... e) { + return details::apply_extra_args_wrappers(fn, e...); + } + + template + class class_definer { + std::tuple with_extra; + public: + class_definer(details::class_handler * ch, interpreter * inter, bool managed, WExtra... extra) : ch_(ch), interp_(inter), managed_(managed), with_extra(extra...) {} + + template + class_definer & def(std::string const & name, Fn fn, Extra... extra) { + //return def2(name, fn, std::make_index_sequence(), extra...); + return def2(name, fn, std::make_index_sequence(), extra...); + } + + template + class_definer & def2(std::string const & name, Fn f, std::index_sequence, Extra... extra) COLD; + + template + class_definer & def2(std::string const & name, overloaded const & over, std::index_sequence seq, Extra... extra) COLD; + + template + class_definer & defvar(std::string const & name, T CC::*varp) COLD; + private: + interpreter * interp_; + details::class_handler * ch_; + bool managed_; + }; + + template + struct function_definer { + std::tuple with_extra; + + function_definer(C * this_p, interpreter * interp, WExtra... extra) : this_p_(this_p), interp_(interp), with_extra(extra...) { } + + template + function_definer & def(std::string const & name, Fn fn, Extra... extra) { + return def2(name, fn, std::make_index_sequence(), extra...); + } + + template + function_definer & def2(std::string const & name, Fn fn, std::index_sequence, Extra... extra) COLD; + + template + function_definer & defvar(std::string const & name, T C::*t) COLD; + //template + //function_definer & defvar(std::string const & name, T C::&t) { + // return defvar(name, &t); + //} + + C * this_p_; + interpreter * interp_; + }; + + const Tcl_ObjType * list_type_ = nullptr; + const Tcl_ObjType * cmdname_type_ = nullptr; + const Tcl_Namespace * object_namespace_ = nullptr; + //const Tcl_Namespace * object_commandnamespace_ = nullptr; + + bool is_list(Tcl_Obj * o) { return o->typePtr == list_type_; } + + static constexpr const char * object_namespace_name = "o"; + static constexpr const char * object_namespace_prefix = "o::"; + static const int object_namespace_prefix_len = 3; + +#if 0 + static constexpr const char * object_command_namespace_name = "O"; + static constexpr const char * object_command_namespace_prefix = "O::"; + static const int object_command_namespace_prefix_len = 3; +#endif + +#if 0 + object make_object(long i) { return object(this, i); } + object make_object(char const *s) { return object(this, s); } + object make_object(std::string const &s) { return object(this, s); } + object make_object(Tcl_Obj *o) { return object(this, o); } + object make_object(bool b) { return object(this, b); } + object make_object(char const *buf, size_t size) { return object(this, buf, size); } + object make_object(double b) { return object(this, b); } + object make_object(int i) { return object(this, i); } + object make_object() { return object(this); } +#endif + + void find_standard_types(); + interpreter(Tcl_Interp *, bool owner = false); + ~interpreter(); + + interpreter * master_ = nullptr; + void set_master(interpreter * master) { + master_ = master; + } + + void make_safe(); + + void custom_construct(const char * classname, const char * objname, void * p); + + Tcl_Interp * get() const { return interp_; } + Tcl_Interp * get_interp() { return interp_; } + + // free function definitions + + template + void def(std::string const & name, Fn fn, Extra... extra) { + auto pol = eap(extra...); + + def2::value>(name, fn, extra...); + } + template + void def2(std::string const & name, Fn fn, Extra... extra) { + if (master_) { + add_function(name, master_->find_callback(name)); + } else { + typedef decltype(details::extra_args_conversions(extra...)) conv_t; + add_function(name, std::shared_ptr(new callback_t(this, fn, name, eap(extra...), eac(extra...)))); + } + } + + template + void def(std::string const & name, R (C::*f)(Ts...), C * this_p, Extra... extra) { + def(name, [this_p, f](Ts... args) { return (this_p->*f)(args...); }, extra...); + } + + + template + void def(std::string const & name, overloaded over, Extra... extra) { + if (master_) { + add_function(name, master_->find_callback(name)); + } else { + typedef decltype(details::extra_args_conversions(extra...)) conv_t; + add_function(name, std::shared_ptr(new details::overloaded_callback(this, over, name, eap(extra...), eac(extra...)))); + } + } + + template + void defvar(std::string const & name, T & v); + + template + function_definer with(C * this_p, Extra... extra) { + return function_definer(this_p, this, extra...); + } + template + function_definer with(Extra... extra) { + return function_definer(nullptr, this, extra...); + } + + template struct call_constructor { + static C * doit(Ts... ts) { + return new C(ts...); + } + }; + + template + class_definer class_(std::string const &name, init const & init_arg = init(details::init_default_tag()), Extra... extra) COLD; + template + class_definer class_(std::string const &name, details::no_init_type const &, Extra... extra) COLD; + + template struct call_managed_constructor { + interpreter * interp_; + call_managed_constructor(interpreter * i) : interp_(i) { } + + object operator()(Ts... ts); + }; + + template + class_definer managed_class_(std::string const &name, init const & = init(), Extra... extra) { + if (master_) { + std::shared_ptr chp = master_->find_class(name); + assert(chp); + add_class(name, chp, sizeof(C) <= sizeof(((Tcl_Obj *) 0)->internalRep)); + add_managed_constructor(name, chp.get(), master_->find_callback(name)); + details::class_handler * ch = static_cast *>(chp.get()); + return class_definer(ch, this, true, extra...); + } else { + typedef details::callback_v, call_managed_constructor, object, Ts...> callback_type; + + if (get_class_handler(name)) { + throw tcl_error("overloaded constructors not implemented"); + } + + details::class_handler * ch = new details::class_handler(); + + this->type, ValueType >(name, (C *) 0); + + add_class(name, std::shared_ptr(ch), sizeof(C) <= sizeof(((Tcl_Obj *) 0)->internalRep)); + + add_managed_constructor(name, ch, std::shared_ptr(new callback_type(this, call_managed_constructor(this), name))); + + return class_definer(ch, this, true, extra...); + } + } + + template + class_definer managed_class_(std::string const &name, details::no_init_type const &, Extra... extra) { + if (master_) { + std::shared_ptr chp = master_->find_class(name); + if (all_classes_.count(name) == 0) { + add_class(name, chp, sizeof(C) <= sizeof(((Tcl_Obj *) 0)->internalRep)); + } + details::class_handler * ch = static_cast *>(chp.get()); + return class_definer(ch, this, true, extra...); + } else { + details::class_handler * ch = static_cast *>(get_class_handler(name)); + if (!ch) { + ch = new details::class_handler(); + this->type, ValueType >(name, (C *) 0); + add_class(name, std::shared_ptr(ch), sizeof(C) <= sizeof(((Tcl_Obj *) 0)->internalRep)); + } + return class_definer(ch, this, true, extra...); + } + } + + static std::map obj_type_by_tclname_; + static std::map obj_type_by_cppname_; + + template + struct deleter { + virtual bool free(Tcl_Obj * o) { + delete (T *) o->internalRep.twoPtrValue.ptr1; + return false; + } + virtual deleter * dup_deleter() { return this; } + virtual void * dup(void * obj) { + return obj; + } + virtual ~deleter() { } + }; + + template + struct dyn_deleter : public deleter { + bool free(Tcl_Obj * o) override { + delete (T *) o->internalRep.twoPtrValue.ptr1; + return true; + } + deleter * dup_deleter() override { return new dyn_deleter(); } + }; + + template + struct shared_ptr_deleter : public deleter { + std::shared_ptr p_; + + shared_ptr_deleter(T * p) : p_(p) { } + + template + shared_ptr_deleter(T * p, DEL del) : p_(p, del) { + } + shared_ptr_deleter(std::shared_ptr & p) : p_(p) { + } + bool free(Tcl_Obj * o) override { + return true; + } + virtual void * dup(void * obj) override { return obj; } + deleter * dup_deleter() override { + return new shared_ptr_deleter(p_); + } + ~shared_ptr_deleter() { + } + }; + + template + struct type_ops { + static void dup(Tcl_Obj * src, Tcl_Obj * dst) { + if (src->internalRep.twoPtrValue.ptr2) { + deleter * d = (deleter *) src->internalRep.twoPtrValue.ptr2; + dst->internalRep.twoPtrValue.ptr1 = d->dup(src->internalRep.twoPtrValue.ptr1); + dst->internalRep.twoPtrValue.ptr2 = (( deleter *)src->internalRep.twoPtrValue.ptr2)->dup_deleter(); + } else { + dst->internalRep.twoPtrValue.ptr1 = src->internalRep.twoPtrValue.ptr1; + dst->internalRep.twoPtrValue.ptr2 = nullptr; + } + dst->typePtr = src->typePtr; + } + static void dup_v(Tcl_Obj * src, Tcl_Obj * dst) { + if constexpr (sizeof(T) <= sizeof(dst->internalRep)) { + memcpy(&dst->internalRep, &src->internalRep, sizeof(T)); + } else { + if constexpr (std::is_copy_constructible::value) { + dst->internalRep.twoPtrValue.ptr1 = new T(* ((T *) src->internalRep.twoPtrValue.ptr1)); + } else { + throw tcl_error("attempting to make value for class with no copy constructor"); + } + } + } + static void free(Tcl_Obj * o) { + if (o->internalRep.twoPtrValue.ptr2) { + deleter * d = (deleter *) o->internalRep.twoPtrValue.ptr2; + if (d->free(o)) { + delete d; + } + } + } + static void free_v(Tcl_Obj * o) { + if constexpr (sizeof(T) <= sizeof(o->internalRep)) { + ((T *) &o->internalRep)->~T(); + } else { + delete ((T *) o->internalRep.twoPtrValue.ptr1); + } + } + static void str(Tcl_Obj * o) { + std::ostringstream oss; + oss << (Managed ? object_namespace_name : object_namespace_name) << "::" << o->internalRep.twoPtrValue.ptr1; + str_impl(o, oss.str()); + } + static void str_v(Tcl_Obj * o) { + if constexpr (sizeof(T) <= sizeof(o->internalRep)) { + std::ostringstream oss; + oss << &o->internalRep; + str_impl(o, oss.str()); + } else { + std::ostringstream oss; + oss << o->internalRep.twoPtrValue.ptr1; + str_impl(o, oss.str()); + } + } + static void str_impl(Tcl_Obj * o, std::string const & name) { + o->bytes = Tcl_Alloc(name.size() + 1); + strncpy(o->bytes, name.c_str(), name.size()); + o->bytes[name.size()] = 0; + o->length = name.size(); + } + static int set(Tcl_Interp * interp, Tcl_Obj * o) { + //std::cerr << "setfromany " << interp << " " << o << "\n"; + return TCL_OK; + } + static int set_v(Tcl_Interp *, Tcl_Obj *) { + return TCL_OK; + } + }; + + template + Tcl_ObjType * get_objtype() { + auto it = obj_type_by_cppname_.find(std::type_index(typeid(TY))); + if (it != obj_type_by_cppname_.end()) { + return it->second; + } + return nullptr; + } + Tcl_ObjType * get_objtype(const char * name) { + auto & o = obj_type_by_tclname_; + auto it = o.find(name); + return it == o.end() ? nullptr : it->second; + } + template + bool is_type(Tcl_Obj * o) { + return o->typePtr && get_objtype() == o->typePtr; + } + template + T * try_type(Tcl_Obj * o) { + if (is_type(o)) { + return (T *) o->internalRep.twoPtrValue.ptr1; + } + return nullptr; + } + + struct extra_typeinfo { + bool value_type; + }; + + template + static void type(std::string const & name, TY * p) { + auto it = obj_type_by_cppname_.find(std::type_index(typeid(TY))); + if (it != obj_type_by_cppname_.end()) { + //std::cerr << "attempt to register type " << name << " twice\n"; + return; + } + auto it2 = obj_type_by_tclname_.find(name); + if (it2 != obj_type_by_tclname_.end()) { + //std::cerr << "attempt to register type " << name << " twice\n"; + return; + } + Tcl_ObjType * ot = new Tcl_ObjType[4]; + + if constexpr (ValueType) { + char * cp_vt = new char[name.size() + 3]; + strcpy(cp_vt, name.c_str()); + cp_vt[name.size()] = '_'; + cp_vt[name.size() + 1] = 'v'; + cp_vt[name.size() + 2] = 0; + ot[2].name = cp_vt; + ot[2].freeIntRepProc = &OPS::free_v; + ot[2].dupIntRepProc = &OPS::dup_v; + ot[2].updateStringProc = &OPS::str_v; + ot[2].setFromAnyProc = &OPS::set_v; + Tcl_RegisterObjType(ot + 2); + } else { + memset(ot + 2, 0, sizeof(*ot)); + ot[2].name = "unused"; + } + //std::type_index * tip = (std::type_index *) (cp + 256); + //*tip = std::type_index(typeid(TY)); + memset(ot, 0, sizeof(*ot)); + memset(ot + 3, 0, sizeof(*ot)); + + char * cp = new char[name.size() + 1]; + strcpy(cp, name.c_str()); + cp[name.size()] = 0; + ot[1].name = cp; + ot[1].freeIntRepProc = &OPS::free; + ot[1].dupIntRepProc = &OPS::dup; + ot[1].updateStringProc = &OPS::str; + ot[1].setFromAnyProc = &OPS::set; + + Tcl_RegisterObjType(ot + 1); + obj_type_by_tclname_.insert(std::pair(name, ot + 1)); + obj_type_by_cppname_.insert(std::pair(std::type_index(typeid(TY)), ot + 1)); + } + + template ::type>::value, bool>::type = true> + T tcl_cast(Tcl_Interp *, Tcl_Obj *, bool) { + throw; + } + template ::type>::value, bool>::type = true> + T tcl_cast(Tcl_Interp *, Tcl_Obj *, bool, Tcl_ObjType *) { + throw; + } + + template + T tcl_cast(Tcl_Obj * o) { + return this->template tcl_cast(this->get_interp(), o, false); + } + template + T tcl_cast(Tcl_Obj * o, Tcl_ObjType * ot) { + return this->template tcl_cast(this->get_interp(), o, false, ot); + } + + template ::value && std::is_same::type>::type, char>::value, bool>::type = true> + T tcl_cast(Tcl_Interp * i, Tcl_Obj * o, bool byref) { + return Tcl_GetStringFromObj(o, nullptr); + } + + template ::value>::type = true> + T tcl_cast(Tcl_Interp * i, Tcl_Obj * o, bool byref) { + return o; + } + + template ::value && !std::is_same::type>::type, char>::value, bool>::type = true> + T tcl_cast(Tcl_Interp * i, Tcl_Obj * o, bool byref) { + auto it = obj_type_by_cppname_.find(std::type_index(typeid(typename std::remove_pointer::type))); + if (it != obj_type_by_cppname_.end()) { + return this->template tcl_cast(i, o, byref, it->second); + } + throw tcl_error("function argument type is not registered"); + } + + template ::value, bool>::type = true> + T tcl_cast(Tcl_Interp * interp, Tcl_Obj * o, bool byref) { + return *tcl_cast::type *>(interp, o, byref); + } + + template ::value, bool>::type = true> + T tcl_cast(Tcl_Interp * i, Tcl_Obj * o, bool byref, Tcl_ObjType * ot) { + if (std::is_pointer::value && o->typePtr) { + Tcl_ObjType * otp = ot; + if (otp == o->typePtr) { + return (T) o->internalRep.twoPtrValue.ptr1;//otherValuePtr; + } else if (otp + 1 == o->typePtr) { + if (sizeof(typename std::remove_pointer::type) <= sizeof(o->internalRep)) { + return (T) &o->internalRep; + } else { + return (T) o->internalRep.twoPtrValue.ptr1; + } + } else if (is_list(o)) { + int len; + if (Tcl_ListObjLength(i, o, &len) == TCL_OK) { + if (len == 1) { + Tcl_Obj *o2; + if (Tcl_ListObjIndex(i, o, 0, &o2) == TCL_OK) { + if (otp == o2->typePtr) { + return (T) o2->internalRep.twoPtrValue.ptr1; + } else { + throw tcl_error("function argument has wrong type. expect " + details::tcl_typename(otp) + ", got " + details::tcl_typename(o2->typePtr)); + } + } else { + throw tcl_error("internal error. cannot access valid list index"); + } + } else { + throw tcl_error("Expected single object, got list"); + } + } else { + throw tcl_error("Unknown tcl error"); + } + } else { + throw tcl_error("function argument has wrong type. expect " + details::tcl_typename(otp) + ", got " + details::tcl_typename(o->typePtr)); + } + } else { + throw tcl_error("function argument is not a tcl object type"); + } + return nullptr; + } + template ::value && !std::is_reference::value && std::is_same::type>::value && !details::is_any::value, bool>::type = true> + T tcl_cast(Tcl_Interp * i, Tcl_Obj * o, bool byref) { + return details::tcl_cast::from(i, o, byref); + } + template ::value && std::is_same::type>::value && !details::is_any::value, bool>::type = true> + T tcl_cast(Tcl_Interp * i, Tcl_Obj * o, bool byref, Tcl_ObjType *) { + return details::tcl_cast::from(i, o, byref); + } + + // free script evaluation + details::result eval(std::string const &script); + details::result eval(std::istream &s); + + details::result eval(object const &o); + + void result_reset() { + Tcl_ResetResult(get_interp()); + } + + static std::string objinfo(object const & o); + + // the InputIterator should give object& or Tcl_Obj* when dereferenced + template details::result eval(InputIterator first, InputIterator last); + + template + object makeobj(OT * n, bool owning = false, DEL delfn = []{}); + template + object makeobj(OT * n, bool owning = false); + template + void makeobj_inplace(OT * p, object & obj, bool owning = false, DEL delfn = []{}); + + template + void makevalue_inplace(OT * o, object & obj); + template + object makevalue(OT * o); + + + template + void setVar(std::string const & name, T const & value); + void setVar(std::string const & name, object const & value); + + template + void setVar(std::string const & name, object & ptr); + + void unsetVar(std::string const & name); + + // Get a variable from TCL interpreter with Tcl_GetVar + details::result getVar(std::string const &scalarTclVariable); + details::result getVar(std::string const &arrayTclVariable, std::string const &arrayIndex); + + details::result upVar(std::string const & frame, std::string const & srcname, std::string const & destname); + + // check if variables exist + bool exists(std::string const &scalarTclVariable); + bool exists(std::string const &arrayTclVariable, std::string const &arrayIndex); + + // create alias from the *this interpreter to the target interpreter + void create_alias(std::string const &cmd, interpreter &targetInterp, std::string const &targetCmd); + + // register a package info (useful when defining packages) + void pkg_provide(std::string const &name, std::string const &version); + + // create a namespace + void create_namespace(std::string const &name); + + // helper for cleaning up callbacks in non-managed interpreters + void clear_definitions(); + + private: + void operator=(const interpreter &); + + void add_function(std::string const &name, std::shared_ptr cb); + + void add_class(std::string const &name, std::shared_ptr chb, bool is_inline); + details::class_handler_base * get_class_handler(std::string const & name); + + void add_constructor(std::string const &name, details::class_handler_base * chb, std::shared_ptr cb); + void add_managed_constructor(std::string const &name, details::class_handler_base * chb, std::shared_ptr cb); + + Tcl_Interp *interp_; + bool owner_; + std::iostream tin_, tout_, terr_; +}; + +template +std::size_t list::size() const { + if (! interp_) return 0; + int len; + if (Tcl_ListObjLength(interp_->get(), lo_, &len) == TCL_OK) { + return len; + } + return 0; +} + +template +T variadic::at(int ix) const { return interp_->template tcl_cast(objv[ix]); } + +template +Tcl_Obj * list::obj_at(std::size_t ix) const { + Tcl_Obj *o; + if (Tcl_ListObjIndex(interp_->get(), lo_, ix, &o) == TCL_OK) { + return o; + } +} + +template +std::pair::return_t, Tcl_Obj *> list::with_obj_at(std::size_t ix) const { + typedef std::pair ret_t; + Tcl_Obj *o; + if (Tcl_ListObjIndex(interp_->get(), lo_, ix, &o) == TCL_OK) { + if constexpr (isany) { + return ret_t(return_t(interp_, o, ot_), o); + } else if constexpr (details::is_basic_type::value) { + return ret_t(interp_->template tcl_cast(o), o); + } else if constexpr (std::is_same::value) { + return ret_t(object(o), o); + } else { + if (o->typePtr == ot_[0]) { + return ret_t((return_t) o->internalRep.twoPtrValue.ptr1, o); + } else { + throw tcl_error("Unexpected type in list. Got " + details::tcl_typename(o) + " need " + details::tcl_typename(ot_[0])); + } + } + } + return ret_t(return_t(), nullptr); +} + +template +template +typename std::conditional::value, TT, TT *>::type any::as() const { + const int toff = sizeof...(Ts) - 1 - details::type_at::value; + + if constexpr (details::is_list::value) { + if (this->o_ && interp_->is_list(this->o_)) { + Tcl_Obj * oo; + if (Tcl_ListObjIndex(interp_->get_interp(), this->o_, 0, &oo) == TCL_OK) { + if (oo->typePtr == this->ot_[toff]) { + return TT(interp_, this->o_, this->ot_ + toff); + } + } + return TT(); + } else { + return TT(); + } + } else { + if (this->o_ && this->ot_[toff] == this->o_->typePtr) { + return (TT *) this->o_->internalRep.twoPtrValue.ptr1; + } else { + return nullptr; + } + } +} + +namespace details { +template struct tcl_cast { + static T *from(Tcl_Interp *, Tcl_Obj *obj, bool byReference) { + std::string s(Tcl_GetString(obj) + interpreter::object_namespace_prefix_len); + if (s.size() == 0) { + throw tcl_error("Expected pointer value, got empty string."); + } + + if (s.compare(0, interpreter::object_namespace_prefix_len, interpreter::object_namespace_prefix) != 0) { + throw tcl_error("Expected pointer value."); + } + + std::istringstream ss(s); + void *p; + ss >> p; + + return static_cast(p); + } +}; + +template +struct generate_argtypes { + template + struct wrap { }; + + typedef typename remove_rc::type T; + + template + static Tcl_ObjType * lookup_type(interpreter * interp, int pos, wrap * np) { + auto * ot = interp->get_objtype::type>(); + return ot; + } + template + static void invoke_helper(std::index_sequence const &, interpreter * interp, Tcl_ObjType ** all) { + ((all[Is] = lookup_type(interp, Is, (wrap::type> *) 0)), ...); + generate_argtypes::invoke(interp, all + sizeof...(Is)); + } + static void invoke(interpreter * interp, Tcl_ObjType ** all) { + invoke_helper(std::make_index_sequence::value>(), interp, all); + } + + template + static std::pair get(Tcl_ObjType ** p) { + if constexpr (ArgI == I) { + return { p, p + num_subtypes::value }; + } else { + return generate_argtypes::template get(p + num_subtypes::value); + } + } + + static const int length = num_subtypes::value + generate_argtypes::length; +}; + +template +struct back { + typedef void type; +}; + +template +struct back { + using type = typename std::conditional::type>::type; +}; + +template +void callback_v::install(interpreter * tcli) { + client_data * cdata = new client_data { this, tcli }; + + Tcl_CreateObjCommand(tcli->get_interp(), name_.c_str(), callback_handler, (ClientData) cdata, cleanup_client_data); +} +template +void callback_v::uninstall(interpreter * tcli) { + Tcl_DeleteCommand(tcli->get_interp(), name_.c_str()); +} + +template +void callback_v::invoke_impl(interpreter * tcli, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv [], bool object_dot_method) { + static const int num_gopt = num_getopt::value; + static const int num_gopt_d = num_getopt_d::value; + static const int num_opt = num_optional::value; + Tcl_Obj * getopt_argv[num_gopt + 1] = { nullptr }; + bool getopt_allocated[num_gopt + 1] = { false }; + Tcl_Obj boolean_dummy_object; + std::size_t ai = std::is_same::value || pol_t::free_method || object_dot_method ? 1 : 2; + static const bool has_variadic_ = has_variadic::value; + bool any_getopt_allocated = false; + + if (tcli->trace()) { + for (int i = 0; i < argc; ++i) { + std::cerr << " "; + if (tcli->is_list(argv[i])) { + std::cerr << '{' << Tcl_GetString(argv[i]) << '}'; + } else { + std::cerr << Tcl_GetString(argv[i]); + } + } + std::cerr << "\n"; + } + ++tcli->trace_count_; + + if (num_gopt && argc == ai + 1 && strcmp(Tcl_GetString(argv[ai]), "-help") == 0 && std::find(opts_, opts_ + num_gopt, "help") == opts_ + num_gopt) { + if (num_gopt) { + std::cerr << Tcl_GetString(argv[0]); + for (int oi = 0; oi < num_gopt; ++oi) { + tcli->terr() << " -" << opts_[oi] << (has_arg_[oi] ? " " : ""); + } + + if (policies_.variadic_) { + tcli->terr() << " objects..."; + } + tcli->terr() << "\n"; + } + return; + } + + if constexpr (num_gopt) { + for (; ai < argc; ++ai) { + char * s = Tcl_GetString(argv[ai]); + if (s[0] == '-') { + if (s[1] == '-' && s[2] == 0) { + ++ai; + break; + } + bool found = false; + for (int oi = 0; oi < num_gopt; ++oi) { + if (opts_[oi].compare(s + 1) == 0) { + found = true; + if (has_arg_[oi]) { + ++ai; + if (ai >= argc) { + throw tcl_error(std::string("option requires an argument: ") + s); + } + getopt_argv[oi] = argv[ai]; + } else { + getopt_argv[oi] = &boolean_dummy_object; + } + } + } + if (!found) { + throw tcl_error(std::string("unknown option: ") + s + " at index " + std::to_string(ai)); + } + } else { + break; + } + } + if (may_have_defaults) { + for (int oi = 0; oi < num_gopt; ++oi) { + if (! getopt_argv[oi]) { + if (!defaults_[oi].empty()) { + Tcl_IncrRefCount(getopt_argv[oi] = Tcl_NewStringObj(defaults_[oi].c_str(), defaults_[oi].size())); + getopt_allocated[oi] = true; + any_getopt_allocated |= true; + } + } + } + } + } + check_params_no(argc - ai, sizeof...(Ts) - (has_variadic_ || policies_.variadic_ ? 1 : 0) - num_gopt - num_opt - num_gopt_d, has_variadic_ || policies_.variadic_ ? -1 : sizeof...(Ts) - num_gopt - num_gopt_d, policies_.usage_); + + auto dealloc = [&](void *) { + if (may_have_defaults && any_getopt_allocated) { + for (int oi = 0; oi < num_gopt; ++oi) { + if (getopt_allocated[oi]) { + Tcl_DecrRefCount(getopt_argv[oi]); + } + } + } + }; + std::unique_ptr dealloc_raii(0, dealloc); + + do_invoke(std::make_index_sequence(), tcli, (C *) pv, interp, argc - ai, argv + ai, num_gopt + num_gopt_d, getopt_argv, policies_, void_return::value>()); + if (pol_t::postproc) { + tcli->post_process_policies(interp, policies_, argv + ai, false); + } +} +template +int callback_v::callback_handler(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + client_data * cdata = (client_data *) cd; + //this_t * this_p = (this_t *) cd; + + return cdata->this_p->checked_invoke_impl(cdata->interp, nullptr, interp, objc, objv, false); +} + +template +void overloaded_callback::invoke_impl(interpreter * tcli, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv[], bool object_dot_method) { + do_invoke<0>(tcli, pv, interp, argc, argv, object_dot_method); +} + +template +int overloaded_callback::checked_invoke_impl(interpreter * tcli, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv[], bool object_dot_method) { + try { + invoke_impl(tcli, pv, interp, argc, argv, object_dot_method); + } catch (tcl_usage_message_printed & e) { + } catch (std::exception & e) { + for (int i = 0; i < argc; ++i) { + if (i) { std::cerr << " "; } + if (tcli->is_list(argv[i])) { + std::cerr << '{' << Tcl_GetString(argv[i]) << '}'; + } else { + std::cerr << Tcl_GetString(argv[i]); + } + } + std::cerr << ": " << e.what() << "\n"; + return TCL_ERROR; + } catch (...) { + std::cerr << "Unknown error.\n"; + return TCL_ERROR; + } + return TCL_OK; +} +template +int overloaded_callback::callback_handler(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + //this_t * this_p = (this_t *) cd; + client_data * cdata = (client_data *) cd; + + return cdata->this_p->checked_invoke_impl(cdata->interp, nullptr, interp, objc, objv, false); +} + +template +void overloaded_callback::install(interpreter * tcli) { + client_data * cdata = new client_data {this, tcli}; + + Tcl_CreateObjCommand(tcli->get_interp(), name_.c_str(), callback_handler, (ClientData) cdata, cleanup_client_data); +} +template +void overloaded_callback::uninstall(interpreter * tcli) { + Tcl_DeleteCommand(tcli->get_interp(), name_.c_str()); +} +} +#undef COLD + +#include "cpptcl/cpptcl_object.h" + +template ::value_type, void>::value, bool>::type = true> +void set_result(Tcl_Interp * interp, std::pair it) { + object o; + for (; it.first != it.second; ++it.first) { + o.append(object(*it.first)); + } + Tcl_SetObjResult(interp, o.get_object_refcounted()); +} + +template +object interpreter::call_managed_constructor::operator()(Ts... ts) { + object ret = interp_->makeobj(new C(ts...), true, [this](C * p) { + std::ostringstream oss; + oss << object_namespace_name << "::" << p << "."; + Tcl_DeleteCommand(interp_->get_interp(), oss.str().c_str()); + delete p; + }); + return ret; +} + +inline std::string interpreter::objinfo(object const & o) { + Tcl_Obj * oo = o.get_object(); + std::ostringstream oss; + oss << "obj=" << oo << " refcount=" << oo->refCount << " typePtr=" << oo->typePtr << " typename=" << (oo->typePtr ? oo->typePtr->name : "(notype)") << " ptr1=" << oo->internalRep.twoPtrValue.ptr1 << " ptr2=" << oo->internalRep.twoPtrValue.ptr2 << "\n"; + return oss.str(); +} + +template +inline object any::as_object() { + return object(this->o_); +} + +namespace details { +template +int callback_v::checked_invoke_impl(interpreter * tcli, void * pv, Tcl_Interp * interp, int argc, Tcl_Obj * const argv [], bool object_dot_method) { + try { + this->invoke_impl(tcli, pv, interp, argc, argv, object_dot_method); + } catch (tcl_usage_message_printed & e) { + } catch (std::exception & e) { + for (int i = 0; i < argc; ++i) { + if (i) { std::cerr << " "; } + if (tcli->is_list(argv[i])) { + std::cerr << '{' << Tcl_GetString(argv[i]) << '}'; + } else { + std::cerr << Tcl_GetString(argv[i]); + } + } + std::cerr << ": " << e.what() << "\n"; + //Tcl_SetObjResult(interp, Tcl_NewStringObj(const_cast(e.what()), -1)); + return TCL_ERROR; + } catch (...) { + std::cerr << "Unknown error.\n"; + return TCL_ERROR; + } + if (tcli->want_abort_) { + Tcl_SetObjResult(interp, object().get_object()); + return TCL_ERROR; + } + return TCL_OK; +} + +template +struct conversion_offset { + static const int value = + (std::is_same::type, std::integral_constant >::value || + std::is_same::type, std::integral_constant >::value) + ? i + 1 : conversion_offset::value; +}; + +template +struct conversion_offset { + static const int value = -1; +}; +template +struct conversion_offset<0, 0, arg, nargs, Conv> { + static const int value = -1; +}; + +template +typename details::fix_variadic_return::type do_cast(interpreter * tcli, std::pair objecttypes, ppack pack, bool variadic, Tcl_Interp * interp, int objc, Tcl_Obj * CONST objv[], int getoptc, Tcl_Obj * CONST getoptv[], policies const & pol, Conv const & conv, C * this_p) { + //typedef typename remove_rc::type TT; + typedef typename details::fix_variadic_return::type TT; + + static const bool is_variadic_arg = is_variadic::value; + static const bool is_optional_arg = is_optional::value; + static const bool is_getopt_arg = is_getopt::value; + + static const bool is_old_variadic_arg = Ii + 1 == In && std::is_same::type, object const &>::value; + + typedef typename list_unpack::type list_unpack_t; + static const bool is_list_arg = !std::is_same::value; + static const bool cpptcl_byref = false; + + static const bool is_any_arg = is_any::value; + static const bool is_any_list_arg = is_any_arg && all_lists::value; + + typedef typename optional_unpack::type opt_unpack_t; + + static const int conversion = conversion_offset<0, std::tuple_size::value, Ii + ConvOffset, In + ConvOffset, Conv>::value; + + if constexpr (is_getopt_d::value) { + return TT(opt_unpack_t(), false, false); + } + + if constexpr (conversion >= 0) { + using conv_t = typename std::tuple_element::type; + if constexpr (std::is_invocable::value) { + return std::get(conv)(objv[Ii]); + } else if constexpr (std::is_invocable::value) { + return std::get(conv)(this_p, objc, objv, ArgOffset + Ii); + } else if constexpr (std::is_invocable::value) { + return std::get(conv)(objc, objv, ArgOffset + Ii); + } else if constexpr (std::is_invocable::value) { + //return std::get(conv)(do_cast<0, ConvOffset, opt_unpack_t, In, Ii>(tcli, objecttypes, pack, variadic, interp, getoptc, getoptv, getoptc, getoptv, pol, std::tuple<>(), this_p)); + } else { + static_assert(Conv::no_such_member); + std::cerr << "_Z" << typeid(this_p).name() << "\n"; + throw tcl_error("conversion function has incompatible signature. this ought to be a compile time error"); + } + } + + if constexpr (is_old_variadic_arg) { + if (pol.variadic_) { + return details::get_var_params(tcli->get(), objc, objv, Ii + ArgOffset, pol); + } + } + + if constexpr (is_optional_arg || is_getopt_arg) { + if constexpr (is_getopt_arg) { + static const int getopti = getopt_index<0, Ii, 0, Ts...>::value; + + if (getoptv[getopti]) { + if constexpr (std::is_same >::value) { + return TT(true, true, false); + } else { + return TT(do_cast<0, ConvOffset, opt_unpack_t, In, Ii>(tcli, objecttypes, pack, variadic, interp, getoptc, getoptv, getoptc, getoptv, pol, conv, this_p), true, false); + } + } else { + return TT(opt_unpack_t(), false, false); + } + } else { + if (objc > Ii + ArgOffset) { + return TT(do_cast(tcli, objecttypes, pack, variadic, interp, objc, objv, getoptc, getoptv, pol, conv, this_p), true, false); + } else { + return { typename std::decay::type(), false, false }; + } + } + } else if constexpr (is_list_arg) { + if constexpr (is_basic_type::value || std::is_same::value) { + if (tcli->is_list(objv[Ii + ArgOffset])) { + return TT(tcli, objv[Ii + ArgOffset], nullptr); + } else { + Tcl_Obj * lo = Tcl_NewListObj(1, objv + Ii + ArgOffset); + return TT(tcli, lo, nullptr, true); + } + } else { + if (objv[Ii + ArgOffset]->typePtr) { + Tcl_ObjType * ot = tcli->get_objtype(); + if (tcli->is_list(objv[Ii + ArgOffset])) { + return TT(tcli, objv[Ii + ArgOffset], objecttypes.first); + } else { + Tcl_Obj * lo = Tcl_NewListObj(1, objv + Ii + ArgOffset); + return TT(tcli, lo, objecttypes.first, true); + } + } else { + return TT(nullptr, nullptr, nullptr); + } + } + } else if constexpr (is_any_arg) { + if (objv[Ii + ArgOffset]->typePtr) { + if (tcli->is_list(objv[Ii + ArgOffset])) {//->typePtr == list_type_) { + if constexpr (is_any_list_arg) { + int len; + if (Tcl_ListObjLength(interp, objv[Ii + ArgOffset], &len) == TCL_OK) { + if (len == 0) { + return TT(nullptr, nullptr, nullptr); + } else { + return TT(tcli, objv[Ii + ArgOffset], objecttypes.first); + } + } else { + throw tcl_error("cannot query list length"); + } + } else { + int len; + if (Tcl_ListObjLength(interp, objv[Ii + ArgOffset], &len) == TCL_OK) { + if (len == 1) { + Tcl_Obj * oo; + if (Tcl_ListObjIndex(interp, objv[Ii + ArgOffset], 0, &oo) == TCL_OK) { + return TT(tcli, oo, objecttypes.first); + } else throw tcl_error("cannot get list element"); + } else throw tcl_error("expecting object or list of size one, got list of size " + std::to_string(len)); + } else throw tcl_error("cannot get list size"); + throw tcl_error("cannot convert list"); + } + } else { + if (is_any_list_arg) { + Tcl_Obj * lo = Tcl_NewListObj(1, objv + Ii + ArgOffset); + return TT(tcli, lo, objecttypes.first, true); + } else { + return TT(tcli, objv[Ii + ArgOffset], objecttypes.first); + } + } + } else { + if constexpr (is_any_list_arg) { + return TT(nullptr, nullptr, nullptr); + } else { + throw tcl_error("any<> argument does not map to an object"); + } + } + } else { + if constexpr (is_variadic_arg) { + return TT(tcli, objc, objv); + } else { + if constexpr (std::is_pointer::value && std::is_class::type>::value) { + return tcli->template tcl_cast::type>::type>(interp, objv[Ii + ArgOffset], false, *objecttypes.first); + } else { + //return tcli->template tcl_cast::type>::type>(interp, objv[Ii + ArgOffset], false); + return tcli->template tcl_cast(interp, objv[Ii + ArgOffset], false); + } + } + } +} +} + +template +void interpreter::defvar(std::string const & name, T & v) { + def(name, [&v] (opt const & arg) -> T { + if (arg) { + v = *arg; + } + return v; + }); +} + +template +template +interpreter::function_definer & interpreter::function_definer::defvar(std::string const & name, T C::*t) { + return this->def(name, [t, this] (opt const & arg) -> T { + if (arg) { + this_p_->*t = arg; + } + return this_p_->*t; + }); +} + +template +template +interpreter::class_definer & interpreter::class_definer::defvar(std::string const & name, T CC::*varp) { + return this->def(name, [varp] (CC * this_p, opt const & val) -> T { + if (val) this_p->*varp = *val; + return this_p->*varp; + }); +} + +template +template +interpreter::function_definer & interpreter::function_definer::def2(std::string const & name, Fn fn, std::index_sequence, Extra... extra) { + if constexpr (std::is_same::value) { + interp_->def(name, fn, std::get(with_extra)..., extra...); + } else { + interp_->def(name, fn, this_p_, std::get(with_extra)..., extra...); + } + return *this; +} + +template +template +interpreter::class_definer & interpreter::class_definer::def2(std::string const & name, Fn f, std::index_sequence, Extra... extra) { + if (interp_->master_) { + return *this; + } + const bool epol = std::tuple_size::value != sizeof...(extra); + auto pol = epol ? eap(extra...) : eap(std::get(with_extra)...); + + auto convtu = std::tuple_cat(eac(extra...), eac(std::get(with_extra)...)); + auto wrapped = eaw(f, std::get(with_extra)...); + + typedef typename details::attributes_merge::type attrs; + + ch_->register_method(name, new callback_t::value || details::has_policies::value, attrs> + (interp_, wrapped, name, pol, convtu), + interp_->get_interp(), managed_); + return *this; +} + +template +template +interpreter::class_definer & interpreter::class_definer::def2(std::string const & name, overloaded const & over, std::index_sequence seq, Extra... extra) { + if (interp_->master_) { + return *this; + } + + const bool epol = std::tuple_size::value != sizeof...(extra); + auto convtu = std::tuple_cat(eac(extra...), eac(std::get(with_extra)...)); + + typedef typename details::attributes_merge::type attrs; + + ch_->register_method(name, new details::overloaded_callback, decltype(convtu), Over...> + (interp_, over, name, epol ? eap(extra...) : eap(std::get(with_extra)...), convtu), + interp_->get_interp(), managed_); + return *this; +} + +template +interpreter::class_definer interpreter::class_(std::string const &name, init const & init_arg, Extra... extra) { + auto * ch = static_cast *>(get_class_handler(name)); + if (master_) { + assert(ch); + if (all_callbacks_.count(name) == 0) { + add_constructor(name, ch, master_->find_callback(name)); + } + } else { + typedef callback_t, C * (*)(Ts...), true> callback_type; + + if (ch && ! init_arg.default_) { + throw tcl_error("overloaded constructors not implemented"); + } + if (!ch) { + ch = new details::class_handler(); + add_class(name, std::shared_ptr(ch), sizeof(C) <= sizeof(((Tcl_Obj *) 0)->internalRep)); + add_constructor(name, ch, std::shared_ptr(new callback_type(this, &call_constructor::doit, name, extra...))); + } + } + return class_definer(ch, this, false, extra...); +} + +template +interpreter::class_definer interpreter::class_(std::string const &name, details::no_init_type const &, Extra... extra) { + details::class_handler * ch = static_cast *>(get_class_handler(name)); + if (master_) { + } else { + if (! ch) { + ch = new details::class_handler(); + add_class(name, ch, sizeof(C) <= sizeof(((Tcl_Obj *) 0)->internalRep)); + } + } + return class_definer(ch, this, false, extra...); +} + +inline void interpreter::setVar(std::string const & name, object const & value) { + object name_obj(name); + + Tcl_ObjSetVar2(interp_, name_obj.get_object(), nullptr, value.get_object(), 0); +} + +template +void interpreter::setVar(std::string const & name, T const & value) { + object val_obj(value); + object name_obj(name); + + Tcl_ObjSetVar2(interp_, name_obj.get_object(), nullptr, val_obj.get_object(), 0); +} + +template +void interpreter::makevalue_inplace(OT * p, object & obj) { + Tcl_Obj * o = obj.get_object(); + + if (Tcl_IsShared(o)) { + throw tcl_error("cannot modify shared object in-place"); + } + + if (sizeof(OT) <= sizeof(o->internalRep)) { + void * dp = (void *) &o->internalRep; + new (dp) OT(*p); + } else { + o->internalRep.twoPtrValue.ptr1 = new OT(*p); + } + + auto it = this->obj_type_by_cppname_.find(std::type_index(typeid(OT))); + bool ok = it != this->obj_type_by_cppname_.end(); + if (ok) { + o->typePtr = it->second + 1; + } else { + throw tcl_error("type lookup failed"); + } + Tcl_InvalidateStringRep(o); +} + +template +void interpreter::makeobj_inplace(OT * n, object & obj, bool owning, DEL delfn) { + Tcl_Obj * o = obj.get_object(); + + if (Tcl_IsShared(o)) { + throw tcl_error("cannot modify shared object in-place"); + } + + o->internalRep.twoPtrValue.ptr1 = (void *) n; + if (owning) { + if constexpr (std::is_same::value) { + if (delfn) { } + o->internalRep.twoPtrValue.ptr2 = new interpreter::shared_ptr_deleter(n); //new interpreter::dyn_deleter(); //nullptr; + } else { + o->internalRep.twoPtrValue.ptr2 = new interpreter::shared_ptr_deleter(n, delfn); //new interpreter::dyn_deleter(); //nullptr; + } + } else { + o->internalRep.twoPtrValue.ptr2 = nullptr; + } + + auto it = this->obj_type_by_cppname_.find(std::type_index(typeid(OT))); + bool ok = it != this->obj_type_by_cppname_.end(); + if (ok) { + o->typePtr = it->second; + } else { + throw tcl_error("type lookup failed"); + } + Tcl_InvalidateStringRep(o); +} + +template +object interpreter::makeobj(OT * p, bool owning, DELFN delfn) { + object obj = object().duplicate(); + makeobj_inplace(p, obj, owning, delfn); + return obj; +} + +template +object interpreter::makeobj(OT * n, bool owning) { + return makeobj(n, owning, (void *) 0 ); +} + +template +object interpreter::makevalue(OT * v) { + object obj = object().duplicate(); + makevalue_inplace(v, obj); + return obj; +} + +template +void interpreter::setVar(std::string const & name, object & obj) { + object name_obj(name); + Tcl_ObjSetVar2(interp_, name_obj.get_object(), nullptr, obj.get_object(), 0); +} + +template +struct Bind { + object cmd_; + + template + void dummy(TTs...) { + } + + Bind(std::string const & cmd) : cmd_(object(cmd)) { } + R operator()(Ts... args) { + object e(cmd_); + + dummy(e.append(object(args))...); + return (R) (interpreter::getDefault()->eval(e)); + } +}; + +// the InputIterator should give object& or Tcl_Obj* when dereferenced +template details::result interpreter::eval(InputIterator first, InputIterator last) { + std::vector v; + object::fill_vector(v, first, last); + int cc = Tcl_EvalObjv(interp_, static_cast(v.size()), v.empty() ? NULL : &v[0], 0); + if (cc != TCL_OK) { + if (want_abort_) { + want_abort_ = false; + throw tcl_aborted(); + } else { + throw tcl_error(interp_); + } + } + + return details::result(interp_); +} inline std::ostream & operator<<(std::ostream &os, const object& obj) { diff --git a/cpptcl/cpptcl_object.h b/cpptcl/cpptcl_object.h index 2d8cb18..e40dcf0 100644 --- a/cpptcl/cpptcl_object.h +++ b/cpptcl/cpptcl_object.h @@ -79,12 +79,27 @@ class object { // constructors object(); - explicit object(bool b); object(char const *buf, size_t size); // byte array explicit object(double b); explicit object(int i); + explicit object(long i); + explicit object(char const *s); // string construction + explicit object(std::string const &s); // string construction + explicit object(Tcl_Obj *o, bool shared = false); + + object(interpreter *); + explicit object(interpreter *, bool b); + object(interpreter *, char const *buf, size_t size); // byte array + explicit object(interpreter *, double b); + explicit object(interpreter *, int i); + explicit object(interpreter *, long i); + explicit object(interpreter *, char const *s); // string construction + explicit object(interpreter *, std::string const &s); // string construction + explicit object(interpreter *, Tcl_Obj *o, bool shared = false); + + // list creation // the InputIterator should give object& or Tcl_Obj* when dereferenced template object(InputIterator first, InputIterator last) : interp_(0) { @@ -93,12 +108,12 @@ class object { obj_ = Tcl_NewListObj(static_cast(v.size()), v.empty() ? NULL : &v[0]); Tcl_IncrRefCount(obj_); } - - explicit object(long i); - explicit object(char const *s); // string construction - explicit object(std::string const &s); // string construction - - explicit object(Tcl_Obj *o, bool shared = false); + template object(interpreter * interp, InputIterator first, InputIterator last) : interp_(interp) { + std::vector v; + fill_vector(v, first, last); + obj_ = Tcl_NewListObj(static_cast(v.size()), v.empty() ? NULL : &v[0]); + Tcl_IncrRefCount(obj_); + } object(object const &other, bool shared = false); ~object(); @@ -138,40 +153,48 @@ class object { // (logically) non-modifying members - template T get(interpreter &i = *interpreter::defaultInterpreter) const; + //template T get(interpreter &i = *interpreter::defaultInterpreter) const; + template T get() const; //interpreter &i = *interpreter::defaultInterpreter) const; char const *get() const; // string get char const *get(size_t &size) const; // byte array get - size_t size(interpreter &i = *interpreter::defaultInterpreter) const; // returns list length - object at(size_t index, interpreter &i = *interpreter::defaultInterpreter) const; + size_t size() const; //interpreter &i = *interpreter::defaultInterpreter) const; // returns list length + object at(size_t index) const; //, interpreter &i = *interpreter::defaultInterpreter) const; + object at_ref(size_t index) const; //, interpreter &i = *interpreter::defaultInterpreter) const; + bool is_list() const; + Tcl_Obj *get_object() const { return obj_; } - + Tcl_Obj * get_object_refcounted() { + Tcl_IncrRefCount(obj_); + return obj_; + } + // modifying members - object &append(object const &o, interpreter &i = *interpreter::defaultInterpreter); - object &append_list(object const &o, interpreter &i = *interpreter::defaultInterpreter); + object &append(object const &o); //, interpreter &i = *interpreter::defaultInterpreter); + object &append_list(object const &o); //, interpreter &i = *interpreter::defaultInterpreter); // list replace // the InputIterator should give Tcl_Obj* or object& when dereferenced - template object &replace(size_t index, size_t count, InputIterator first, InputIterator last, interpreter &i = *interpreter::defaultInterpreter) { + template object &replace(size_t index, size_t count, InputIterator first, InputIterator last) { //, interpreter &i = *interpreter::defaultInterpreter) { std::vector v; fill_vector(v, first, last); - int res = Tcl_ListObjReplace(i.get(), obj_, static_cast(index), static_cast(count), static_cast(v.size()), v.empty() ? NULL : &v[0]); + int res = Tcl_ListObjReplace(interp_->get_interp(), obj_, static_cast(index), static_cast(count), static_cast(v.size()), v.empty() ? NULL : &v[0]); if (res != TCL_OK) { - throw tcl_error(i.get()); + throw tcl_error(interp_->get_interp()); } return *this; } - object &replace(size_t index, size_t count, object const &o, interpreter &i = *interpreter::defaultInterpreter); - object &replace_list(size_t index, size_t count, object const &o, interpreter &i = *interpreter::defaultInterpreter); + object &replace(size_t index, size_t count, object const &o); //, interpreter &i = *interpreter::defaultInterpreter); + object &replace_list(size_t index, size_t count, object const &o); //, interpreter &i = *interpreter::defaultInterpreter); // helper functions for piggy-backing interpreter info - void set_interp(Tcl_Interp *interp); - Tcl_Interp *get_interp() const; + //void set_interp(Tcl_Interp *interp); + //Tcl_Interp *get_interp() const; // helper function, also used from interpreter::eval template static void fill_vector(std::vector &v, InputIterator first, InputIterator last) { @@ -184,13 +207,13 @@ class object { const maybe_object operator()(std::string const & idx) const { Tcl_Obj *array = obj_; const char *name = Tcl_GetString(array); - Tcl_Obj *o = Tcl_GetVar2Ex(interp_, name, idx.c_str(), TCL_LEAVE_ERR_MSG); - return maybe_object(o, interp_, std::string(name), idx); + Tcl_Obj *o = Tcl_GetVar2Ex(interp_->get_interp(), name, idx.c_str(), TCL_LEAVE_ERR_MSG); + return maybe_object(o, *interp_, std::string(name), idx); } - const bool exists(std::string idx) const { + bool exists(std::string idx) const { Tcl_Obj *array = obj_; - Tcl_Obj *o = Tcl_GetVar2Ex(interp_, Tcl_GetString(array), idx.c_str(), 0); + Tcl_Obj *o = Tcl_GetVar2Ex(interp_->get_interp(), Tcl_GetString(array), idx.c_str(), 0); return (o != 0); } @@ -200,10 +223,10 @@ class object { void bind(std::string const& variableName) { object n(variableName); Tcl_IncrRefCount(obj_); - if (interp_ == nullptr) { - interp_ = interpreter::getDefault()->get(); - } - Tcl_ObjSetVar2(interp_, n.get_object(), nullptr, obj_, 0); + //if (interp_ == nullptr) { + // interp_ = interpreter::getDefault()->get(); + //} + Tcl_ObjSetVar2(interp_->get_interp(), n.get_object(), nullptr, obj_, 0); } // Bind array value in TCL interpreter @@ -213,10 +236,10 @@ class object { object n(variableName); object i(indexName); Tcl_IncrRefCount(obj_); - if (interp_ == nullptr) { - interp_ = interpreter::getDefault()->get(); - } - Tcl_ObjSetVar2(interp_, n.get_object(), i.get_object(), obj_, 0); + //if (interp_ == nullptr) { + // interp_ = interpreter::getDefault()->get(); + //} + Tcl_ObjSetVar2(interp_->get_interp(), n.get_object(), i.get_object(), obj_, 0); } std::string asString() const; @@ -229,18 +252,39 @@ class object { // helper function used from copy constructors void init(Tcl_Obj *o, bool shared); - public: + static thread_local Tcl_Obj * default_object_; + static void static_initialize() { + default_object_ = Tcl_NewObj(); + Tcl_IncrRefCount(default_object_); + } + void dupshared() { + if (Tcl_IsShared(obj_)) { + Tcl_Obj * newo = Tcl_DuplicateObj(obj_); + Tcl_IncrRefCount(newo); + Tcl_DecrRefCount(obj_); + obj_ = newo; + } + } + public: + static object make() { + //if (! default_object_) { + // static_initialize(); + //} + return object().duplicate(); + } + void disown() { + Tcl_DecrRefCount(obj_); + } + void reown() { + Tcl_IncrRefCount(obj_); + } + object duplicate() const; + bool shared() const { + return Tcl_IsShared(obj_); + } Tcl_Obj *obj_; - Tcl_Interp *interp_; + interpreter * interp_; + //Tcl_Interp *interp_; }; -// available specializations for object::get -template <> bool object::get(interpreter &i) const; -template <> double object::get(interpreter &i) const; -template <> int object::get(interpreter &i) const; -template <> long object::get(interpreter &i) const; -template <> char const *object::get(interpreter &i) const; -template <> std::string object::get(interpreter &i) const; -template <> std::vector object::get>(interpreter &i) const; - #endif /* CPPTCL_OBJECT_H */ diff --git a/cpptcl/details/bind.h b/cpptcl/details/bind.h deleted file mode 100644 index f731c4e..0000000 --- a/cpptcl/details/bind.h +++ /dev/null @@ -1,175 +0,0 @@ -template struct Bind { - private: - object cmd_; - - public: - Bind(std::string cmd) : cmd_(object(cmd)){}; - - R operator()(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6, const T7 &t7, const T8 &t8, const T9 &t9) { - object obj(cmd_); - obj.append(t1); - obj.append(t2); - obj.append(t3); - obj.append(t4); - obj.append(t5); - obj.append(t6); - obj.append(t7); - obj.append(t8); - obj.append(t9); - return (R)(interpreter::getDefault()->eval(obj)); - } -}; - -template struct Bind { - private: - object cmd_; - - public: - Bind(std::string cmd) : cmd_(object(cmd)){}; - - R operator()(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6, const T7 &t7, const T8 &t8) { - object obj(cmd_); - obj.append(t1); - obj.append(t2); - obj.append(t3); - obj.append(t4); - obj.append(t5); - obj.append(t6); - obj.append(t7); - obj.append(t8); - return (R)(interpreter::getDefault()->eval(obj)); - } -}; - -template struct Bind { - private: - object cmd_; - - public: - Bind(std::string cmd) : cmd_(object(cmd)){}; - - R operator()(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6, const T7 &t7) { - object obj(cmd_); - obj.append(t1); - obj.append(t2); - obj.append(t3); - obj.append(t4); - obj.append(t5); - obj.append(t6); - obj.append(t7); - return (R)(interpreter::getDefault()->eval(obj)); - } -}; - -template struct Bind { - private: - object cmd_; - - public: - Bind(std::string cmd) : cmd_(object(cmd)){}; - - R operator()(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6) { - object obj(cmd_); - obj.append(t1); - obj.append(t2); - obj.append(t3); - obj.append(t4); - obj.append(t5); - obj.append(t6); - return (R)(interpreter::getDefault()->eval(obj)); - } -}; - -template struct Bind { - private: - object cmd_; - - public: - Bind(std::string cmd) : cmd_(object(cmd)){}; - - R operator()(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5) { - object obj(cmd_); - obj.append(t1); - obj.append(t2); - obj.append(t3); - obj.append(t4); - obj.append(t5); - return (R)(interpreter::getDefault()->eval(obj)); - } -}; - -template struct Bind { - private: - object cmd_; - - public: - Bind(std::string cmd) : cmd_(object(cmd)){}; - - R operator()(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) { - object obj(cmd_); - obj.append(t1); - obj.append(t2); - obj.append(t3); - obj.append(t4); - return (R)(interpreter::getDefault()->eval(obj)); - } -}; - -template struct Bind { - private: - object cmd_; - - public: - Bind(std::string cmd) : cmd_(object(cmd)){}; - - R operator()(const T1 &t1, const T2 &t2, const T3 &t3) { - object obj(cmd_); - obj.append(t1); - obj.append(t2); - obj.append(t3); - return (R)(interpreter::getDefault()->eval(obj)); - } -}; - -template struct Bind { - private: - object cmd_; - - public: - Bind(std::string cmd) : cmd_(object(cmd)){}; - - R operator()(const T1 &t1, const T2 &t2) { - object obj(cmd_); - obj.append(object(t1)); - obj.append(object(t2)); - return (R)(interpreter::getDefault()->eval(obj)); - } -}; - -template struct Bind { - private: - object cmd_; - - public: - Bind(std::string cmd) : cmd_(object(cmd)){}; - - R operator()(const T1 &t1) { - object obj(cmd_); - object e(t1); - obj.append(e); - return (R)(interpreter::getDefault()->eval(obj)); - } -}; - -template struct Bind { - private: - object cmd_; - - public: - Bind(std::string cmd) : cmd_(object(cmd)){}; - - R operator()() { - object obj(cmd_); - return (R)(interpreter::getDefault()->eval(obj)); - } -}; diff --git a/cpptcl/details/callbacks.h b/cpptcl/details/callbacks.h deleted file mode 100644 index ac60f01..0000000 --- a/cpptcl/details/callbacks.h +++ /dev/null @@ -1,215 +0,0 @@ -// -// Copyright (C) 2004-2006, Maciej Sobczak -// Copyright (C) 2017-2019, FlightAware LLC -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// - -// Note: this file is not supposed to be a stand-alone header - -#include -#include - -template class callback0 : public callback_base { - typedef R (*functor_type)(); - - public: - callback0(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int, Tcl_Obj *CONST[], policies const &pol) { dispatch::do_dispatch(interp, f_); } - - private: - functor_type f_; -}; - -template class callback1 : public callback_base { - typedef R (*functor_type)(T1); - - public: - callback1(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 2, pol.usage_); - tcl_cast_by_reference byRef1; - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value)); - } - - private: - functor_type f_; -}; - -template class callback2 : public callback_base { - typedef R (*functor_type)(T1, T2); - - public: - callback2(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 3, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value)); - } - - private: - functor_type f_; -}; - -template class callback3 : public callback_base { - typedef R (*functor_type)(T1, T2, T3); - - public: - callback3(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 4, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value)); - } - - private: - functor_type f_; -}; - -template class callback4 : public callback_base { - typedef R (*functor_type)(T1, T2, T3, T4); - - public: - callback4(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 5, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), tcl_cast::from(interp, objv[4], byRef4.value)); - } - - private: - functor_type f_; -}; - -template class callback5 : public callback_base { - typedef R (*functor_type)(T1, T2, T3, T4, T5); - - public: - callback5(functor_type f) : f_(f) {} - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 6, pol.usage_); - - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), tcl_cast::from(interp, objv[4], byRef4.value), tcl_cast::from(interp, objv[5], byRef5.value)); - } - - private: - functor_type f_; -}; - -template class callback6 : public callback_base { - typedef R (*functor_type)(T1, T2, T3, T4, T5, T6); - - public: - callback6(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 7, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - tcl_cast_by_reference byRef6; - - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), tcl_cast::from(interp, objv[4], byRef4.value), tcl_cast::from(interp, objv[5], byRef5.value), tcl_cast::from(interp, objv[6], byRef6.value)); - } - - private: - functor_type f_; -}; - -template class callback7 : public callback_base { - typedef R (*functor_type)(T1, T2, T3, T4, T5, T6, T7); - - public: - callback7(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 8, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - tcl_cast_by_reference byRef6; - tcl_cast_by_reference byRef7; - - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), tcl_cast::from(interp, objv[4], byRef4.value), tcl_cast::from(interp, objv[5], byRef5.value), tcl_cast::from(interp, objv[6], byRef6.value), tcl_cast::from(interp, objv[7], byRef7.value)); - } - - private: - functor_type f_; -}; - -template class callback8 : public callback_base { - typedef R (*functor_type)(T1, T2, T3, T4, T5, T6, T7, T8); - - public: - callback8(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 9, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - tcl_cast_by_reference byRef6; - tcl_cast_by_reference byRef7; - tcl_cast_by_reference byRef8; - - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), tcl_cast::from(interp, objv[4], byRef4.value), tcl_cast::from(interp, objv[5], byRef5.value), tcl_cast::from(interp, objv[6], byRef6.value), tcl_cast::from(interp, objv[7], byRef7.value), tcl_cast::from(interp, objv[8], byRef8.value)); - } - - private: - functor_type f_; -}; - -template class callback9 : public callback_base { - typedef R (*functor_type)(T1, T2, T3, T4, T5, T6, T7, T8, T9); - - public: - callback9(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 10, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - tcl_cast_by_reference byRef6; - tcl_cast_by_reference byRef7; - tcl_cast_by_reference byRef8; - tcl_cast_by_reference byRef9; - - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), tcl_cast::from(interp, objv[4], byRef4.value), tcl_cast::from(interp, objv[5], byRef5.value), tcl_cast::from(interp, objv[6], byRef6.value), tcl_cast::from(interp, objv[7], byRef7.value), tcl_cast::from(interp, objv[8], byRef8.value), - tcl_cast::from(interp, objv[9], byRef9.value)); - } - - private: - functor_type f_; -}; diff --git a/cpptcl/details/callbacks_v.h b/cpptcl/details/callbacks_v.h deleted file mode 100644 index 54d52f0..0000000 --- a/cpptcl/details/callbacks_v.h +++ /dev/null @@ -1,201 +0,0 @@ -// -// Copyright (C) 2004-2006, Maciej Sobczak -// Copyright (C) 2017-2019, FlightAware LLC -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// - -// Note: this file is not supposed to be a stand-alone header - -template class callback1 : public callback_base { - typedef object const &T1; - typedef R (*functor_type)(T1); - enum { var_start = 1 }; - - public: - callback1(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - object t1 = get_var_params(interp, objc, objv, var_start, pol); - dispatch::template do_dispatch(interp, f_, t1); - } - - private: - functor_type f_; -}; - -template class callback2 : public callback_base { - typedef object const &T2; - typedef R (*functor_type)(T1, T2); - enum { var_start = 2 }; - - public: - callback2(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - object t2 = get_var_params(interp, objc, objv, var_start, pol); - tcl_cast_by_reference byRef1; - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), t2); - } - - private: - functor_type f_; -}; - -template class callback3 : public callback_base { - typedef object const &T3; - typedef R (*functor_type)(T1, T2, T3); - enum { var_start = 3 }; - - public: - callback3(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - object t3 = get_var_params(interp, objc, objv, var_start, pol); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), t3); - } - - private: - functor_type f_; -}; - -template class callback4 : public callback_base { - typedef object const &T4; - typedef R (*functor_type)(T1, T2, T3, T4); - enum { var_start = 4 }; - - public: - callback4(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - object t4 = get_var_params(interp, objc, objv, var_start, pol); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), t4); - } - - private: - functor_type f_; -}; - -template class callback5 : public callback_base { - typedef object const &T5; - typedef R (*functor_type)(T1, T2, T3, T4, T5); - enum { var_start = 5 }; - - public: - callback5(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - object t5 = get_var_params(interp, objc, objv, var_start, pol); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), tcl_cast::from(interp, objv[4], byRef4.value), t5); - } - - private: - functor_type f_; -}; - -template class callback6 : public callback_base { - typedef object const &T6; - typedef R (*functor_type)(T1, T2, T3, T4, T5, T6); - enum { var_start = 6 }; - - public: - callback6(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - object t6 = get_var_params(interp, objc, objv, var_start, pol); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), tcl_cast::from(interp, objv[4], byRef4.value), tcl_cast::from(interp, objv[5], byRef5.value), t6); - } - - private: - functor_type f_; -}; - -template class callback7 : public callback_base { - typedef object const &T7; - typedef R (*functor_type)(T1, T2, T3, T4, T5, T6, T7); - enum { var_start = 7 }; - - public: - callback7(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - object t7 = get_var_params(interp, objc, objv, var_start, pol); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - tcl_cast_by_reference byRef6; - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), tcl_cast::from(interp, objv[4], byRef4.value), tcl_cast::from(interp, objv[5], byRef5.value), tcl_cast::from(interp, objv[6], byRef6.value), t7); - } - - private: - functor_type f_; -}; - -template class callback8 : public callback_base { - typedef object const &T8; - typedef R (*functor_type)(T1, T2, T3, T4, T5, T6, T7, T8); - enum { var_start = 8 }; - - public: - callback8(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - object t8 = get_var_params(interp, objc, objv, var_start, pol); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - tcl_cast_by_reference byRef6; - tcl_cast_by_reference byRef7; - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), tcl_cast::from(interp, objv[4], byRef4.value), tcl_cast::from(interp, objv[5], byRef5.value), tcl_cast::from(interp, objv[6], byRef6.value), tcl_cast::from(interp, objv[7], byRef7.value), t8); - } - - private: - functor_type f_; -}; - -template class callback9 : public callback_base { - typedef object const &T9; - typedef R (*functor_type)(T1, T2, T3, T4, T5, T6, T7, T8, T9); - enum { var_start = 9 }; - - public: - callback9(functor_type f) : f_(f) {} - - virtual void invoke(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - object t9 = get_var_params(interp, objc, objv, var_start, pol); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - tcl_cast_by_reference byRef6; - tcl_cast_by_reference byRef7; - tcl_cast_by_reference byRef8; - dispatch::template do_dispatch(interp, f_, tcl_cast::from(interp, objv[1], byRef1.value), tcl_cast::from(interp, objv[2], byRef2.value), tcl_cast::from(interp, objv[3], byRef3.value), tcl_cast::from(interp, objv[4], byRef4.value), tcl_cast::from(interp, objv[5], byRef5.value), tcl_cast::from(interp, objv[6], byRef6.value), tcl_cast::from(interp, objv[7], byRef7.value), tcl_cast::from(interp, objv[8], byRef8.value), - t9); - } - - private: - functor_type f_; -}; diff --git a/cpptcl/details/constructors.h b/cpptcl/details/constructors.h deleted file mode 100644 index 7ab5110..0000000 --- a/cpptcl/details/constructors.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (C) 2004-2006, Maciej Sobczak -// Copyright (C) 2017-2019, FlightAware LLC -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// - -// Note: this file is not supposed to be a stand-alone header - -template struct construct { - static C *doit(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) { return new C(t1, t2, t3, t4, t5, t6, t7, t8, t9); } -}; - -template struct construct { - static C *doit(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) { return new C(t1, t2, t3, t4, t5, t6, t7, t8); } -}; - -template struct construct { - static C *doit(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { return new C(t1, t2, t3, t4, t5, t6, t7); } -}; - -template struct construct { - static C *doit(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { return new C(t1, t2, t3, t4, t5, t6); } -}; - -template struct construct { - static C *doit(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { return new C(t1, t2, t3, t4, t5); } -}; - -template struct construct { - static C *doit(T1 t1, T2 t2, T3 t3, T4 t4) { return new C(t1, t2, t3, t4); } -}; - -template struct construct { - static C *doit(T1 t1, T2 t2, T3 t3) { return new C(t1, t2, t3); } -}; - -template struct construct { - static C *doit(T1 t1, T2 t2) { return new C(t1, t2); } -}; - -template struct construct { - static C *doit(T1 t1) { return new C(t1); } -}; - -template struct construct { - static C *doit() { return new C(); } -}; diff --git a/cpptcl/details/conversions.h b/cpptcl/details/conversions.h deleted file mode 100644 index ff12740..0000000 --- a/cpptcl/details/conversions.h +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright (C) 2004-2006, Maciej Sobczak -// Copyright (C) 2017-2019, FlightAware LLC -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// - -// Note: this file is not supposed to be a stand-alone header - -// helper functor for converting Tcl objects to the given type -// (it is a struct instead of function, -// because I need to partially specialize it) - -template struct tcl_cast; - -template struct tcl_cast { - static T *from(Tcl_Interp *, Tcl_Obj *obj, bool byReference) { - std::string s(Tcl_GetString(obj)); - if (s.size() == 0) { - throw tcl_error("Expected pointer value, got empty string."); - } - - if (s[0] != 'p') { - throw tcl_error("Expected pointer value."); - } - - std::istringstream ss(s); - char dummy; - void *p; - ss >> dummy >> p; - - return static_cast(p); - } -}; - -// the following partial specialization is to strip reference -// (it returns a temporary object of the underlying type, which -// can be bound to the const-ref parameter of the actual function) - -template struct tcl_cast { - static T from(Tcl_Interp *interp, Tcl_Obj *obj, bool byReference) { return tcl_cast::from(interp, obj, byReference); } -}; - -template class tcl_cast_by_reference { - public: - static bool const value = false; -}; - -// the following specializations are implemented - -template <> struct tcl_cast { static int from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; - -template <> struct tcl_cast { static long from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; - -template <> struct tcl_cast { static bool from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; - -template <> struct tcl_cast { static double from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; - -template <> struct tcl_cast { static std::string from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; - -template <> struct tcl_cast { static char const *from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; - -template <> struct tcl_cast { static object from(Tcl_Interp *, Tcl_Obj *, bool byReference = false); }; - diff --git a/cpptcl/details/dispatchers.h b/cpptcl/details/dispatchers.h deleted file mode 100644 index 9a1e93b..0000000 --- a/cpptcl/details/dispatchers.h +++ /dev/null @@ -1,89 +0,0 @@ -// -// Copyright (C) 2004-2006, Maciej Sobczak -// Copyright (C) 2017-2019, FlightAware LLC -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// - -// Note: this file is not supposed to be a stand-alone header - -// the dispatch class is used to execute the callback functor and to -// capture its return value -// further dispatch specialization ignores the res - -template struct dispatch { - template static void do_dispatch(Tcl_Interp *interp, Functor f) { - R res = f(); - set_result(interp, res); - } - - template static void do_dispatch(Tcl_Interp *interp, Functor f, T1 t1) { - R res = f(t1); - set_result(interp, res); - } - - template static void do_dispatch(Tcl_Interp *interp, Functor f, T1 t1, T2 t2) { - R res = f(t1, t2); - set_result(interp, res); - } - - template static void do_dispatch(Tcl_Interp *interp, Functor f, T1 t1, T2 t2, T3 t3) { - R res = f(t1, t2, t3); - set_result(interp, res); - } - - template static void do_dispatch(Tcl_Interp *interp, Functor f, T1 t1, T2 t2, T3 t3, T4 t4) { - R res = f(t1, t2, t3, t4); - set_result(interp, res); - } - - template static void do_dispatch(Tcl_Interp *interp, Functor f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { - R res = f(t1, t2, t3, t4, t5); - set_result(interp, res); - } - - template static void do_dispatch(Tcl_Interp *interp, Functor f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { - R res = f(t1, t2, t3, t4, t5, t6); - set_result(interp, res); - } - - template static void do_dispatch(Tcl_Interp *interp, Functor f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { - R res = f(t1, t2, t3, t4, t5, t6, t7); - set_result(interp, res); - } - - template static void do_dispatch(Tcl_Interp *interp, Functor f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) { - R res = f(t1, t2, t3, t4, t5, t6, t7, t8); - set_result(interp, res); - } - - template static void do_dispatch(Tcl_Interp *interp, Functor f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) { - R res = f(t1, t2, t3, t4, t5, t6, t7, t8, t9); - set_result(interp, res); - } -}; - -template <> struct dispatch { - template static void do_dispatch(Tcl_Interp *, Functor f) { f(); } - - template static void do_dispatch(Tcl_Interp *, Functor f, T1 t1) { f(t1); } - - template static void do_dispatch(Tcl_Interp *, Functor f, T1 t1, T2 t2) { f(t1, t2); } - - template static void do_dispatch(Tcl_Interp *, Functor f, T1 t1, T2 t2, T3 t3) { f(t1, t2, t3); } - - template static void do_dispatch(Tcl_Interp *, Functor f, T1 t1, T2 t2, T3 t3, T4 t4) { f(t1, t2, t3, t4); } - - template static void do_dispatch(Tcl_Interp *, Functor f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { f(t1, t2, t3, t4, t5); } - - template static void do_dispatch(Tcl_Interp *, Functor f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { f(t1, t2, t3, t4, t5, t6); } - - template static void do_dispatch(Tcl_Interp *, Functor f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { f(t1, t2, t3, t4, t5, t6, t7); } - - template static void do_dispatch(Tcl_Interp *, Functor f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) { f(t1, t2, t3, t4, t5, t6, t7, t8); } - - template static void do_dispatch(Tcl_Interp *, Functor f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) { f(t1, t2, t3, t4, t5, t6, t7, t8, t9); } -}; diff --git a/cpptcl/details/metahelpers.h b/cpptcl/details/metahelpers.h deleted file mode 100644 index d87cfa8..0000000 --- a/cpptcl/details/metahelpers.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (C) 2004-2006, Maciej Sobczak -// Copyright (C) 2017-2019, FlightAware LLC -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// - -// Note: this file is not supposed to be a stand-alone header - -template struct get_callback_type_for_construct { typedef callback9 type; }; - -template struct get_callback_type_for_construct { typedef callback8 type; }; - -template struct get_callback_type_for_construct { typedef callback7 type; }; - -template struct get_callback_type_for_construct { typedef callback6 type; }; - -template struct get_callback_type_for_construct { typedef callback5 type; }; - -template struct get_callback_type_for_construct { typedef callback4 type; }; - -template struct get_callback_type_for_construct { typedef callback3 type; }; - -template struct get_callback_type_for_construct { typedef callback2 type; }; - -template struct get_callback_type_for_construct { typedef callback1 type; }; - -template struct get_callback_type_for_construct { typedef callback0 type; }; diff --git a/cpptcl/details/methods.h b/cpptcl/details/methods.h deleted file mode 100644 index 34029ff..0000000 --- a/cpptcl/details/methods.h +++ /dev/null @@ -1,304 +0,0 @@ -// -// Copyright (C) 2004-2006, Maciej Sobczak -// Copyright (C) 2017-2019, FlightAware LLC -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// - -// Note: this file is not supposed to be a stand-alone header - -template class method0 : public object_cmd_base { - typedef R (C::*mem_type)(); - typedef R (C::*cmem_type)() const; - - public: - method0(mem_type f) : f_(f), cmem_(false) {} - method0(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int, Tcl_Obj *CONST[], policies const &) { - C *p = static_cast(pv); - if (cmem_) { - dispatch::do_dispatch(interp, std::bind(cf_, p)); - } else { - dispatch::do_dispatch(interp, std::bind(f_, p)); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method1 : public object_cmd_base { - typedef R (C::*mem_type)(T1); - typedef R (C::*cmem_type)(T1) const; - - public: - method1(mem_type f) : f_(f), cmem_(false) {} - method1(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 3, pol.usage_); - tcl_cast_by_reference byRef; - - C *p = static_cast(pv); - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1), tcl_cast::from(interp, objv[2], byRef.value)); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1), tcl_cast::from(interp, objv[2], byRef.value)); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method2 : public object_cmd_base { - typedef R (C::*mem_type)(T1, T2); - typedef R (C::*cmem_type)(T1, T2) const; - - public: - method2(mem_type f) : f_(f), cmem_(false) {} - method2(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 4, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - - C *p = static_cast(pv); - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value)); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value)); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method3 : public object_cmd_base { - typedef R (C::*mem_type)(T1, T2, T3); - typedef R (C::*cmem_type)(T1, T2, T3) const; - - public: - method3(mem_type f) : f_(f), cmem_(false) {} - method3(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 5, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - - C *p = static_cast(pv); - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value)); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value)); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method4 : public object_cmd_base { - typedef R (C::*mem_type)(T1, T2, T3, T4); - typedef R (C::*cmem_type)(T1, T2, T3, T4) const; - - public: - method4(mem_type f) : f_(f), cmem_(false) {} - method4(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 6, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - - C *p = static_cast(pv); - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value)); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value)); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method5 : public object_cmd_base { - typedef R (C::*mem_type)(T1, T2, T3, T4, T5); - typedef R (C::*cmem_type)(T1, T2, T3, T4, T5) const; - - public: - method5(mem_type f) : f_(f), cmem_(false) {} - method5(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 7, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - - C *p = static_cast(pv); - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value), tcl_cast::from(interp, objv[6], byRef5.value)); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value), tcl_cast::from(interp, objv[6], byRef5.value)); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method6 : public object_cmd_base { - typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6); - typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6) const; - - public: - method6(mem_type f) : f_(f), cmem_(false) {} - method6(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 8, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - tcl_cast_by_reference byRef6; - - C *p = static_cast(pv); - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value), tcl_cast::from(interp, objv[6], byRef5.value), tcl_cast::from(interp, objv[7], byRef6.value)); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value), tcl_cast::from(interp, objv[6], byRef5.value), tcl_cast::from(interp, objv[7], byRef6.value)); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method7 : public object_cmd_base { - typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7); - typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7) const; - - public: - method7(mem_type f) : f_(f), cmem_(false) {} - method7(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 9, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - tcl_cast_by_reference byRef6; - tcl_cast_by_reference byRef7; - - C *p = static_cast(pv); - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value), tcl_cast::from(interp, objv[6], byRef5.value), tcl_cast::from(interp, objv[7], byRef6.value), tcl_cast::from(interp, objv[8], byRef7.value)); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value), tcl_cast::from(interp, objv[6], byRef5.value), tcl_cast::from(interp, objv[7], byRef6.value), tcl_cast::from(interp, objv[8], byRef7.value)); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method8 : public object_cmd_base { - typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7, T8); - typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7, T8) const; - - public: - method8(mem_type f) : f_(f), cmem_(false) {} - method8(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 10, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - tcl_cast_by_reference byRef6; - tcl_cast_by_reference byRef7; - tcl_cast_by_reference byRef8; - - C *p = static_cast(pv); - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value), tcl_cast::from(interp, objv[6], byRef5.value), tcl_cast::from(interp, objv[7], byRef6.value), tcl_cast::from(interp, objv[8], byRef7.value), tcl_cast::from(interp, objv[9], byRef8.value)); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value), tcl_cast::from(interp, objv[6], byRef5.value), tcl_cast::from(interp, objv[7], byRef6.value), tcl_cast::from(interp, objv[8], byRef7.value), tcl_cast::from(interp, objv[9], byRef8.value)); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method9 : public object_cmd_base { - typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7, T8, T9); - typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7, T8, T9) const; - - public: - method9(mem_type f) : f_(f), cmem_(false) {} - method9(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - check_params_no(objc, 11, pol.usage_); - tcl_cast_by_reference byRef1; - tcl_cast_by_reference byRef2; - tcl_cast_by_reference byRef3; - tcl_cast_by_reference byRef4; - tcl_cast_by_reference byRef5; - tcl_cast_by_reference byRef6; - tcl_cast_by_reference byRef7; - tcl_cast_by_reference byRef8; - tcl_cast_by_reference byRef9; - - C *p = static_cast(pv); - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8, std::placeholders::_9), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value), tcl_cast::from(interp, objv[6], byRef5.value), tcl_cast::from(interp, objv[7], byRef6.value), tcl_cast::from(interp, objv[8], byRef7.value), tcl_cast::from(interp, objv[9], byRef8.value), tcl_cast::from(interp, objv[10], byRef9.value)); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8, std::placeholders::_9), tcl_cast::from(interp, objv[2], byRef1.value), tcl_cast::from(interp, objv[3], byRef2.value), tcl_cast::from(interp, objv[4], byRef3.value), tcl_cast::from(interp, objv[5], byRef4.value), tcl_cast::from(interp, objv[6], byRef5.value), tcl_cast::from(interp, objv[7], byRef6.value), tcl_cast::from(interp, objv[8], byRef7.value), tcl_cast::from(interp, objv[9], byRef8.value), tcl_cast::from(interp, objv[10], byRef9.value)); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; diff --git a/cpptcl/details/methods_v.h b/cpptcl/details/methods_v.h deleted file mode 100644 index 835dea8..0000000 --- a/cpptcl/details/methods_v.h +++ /dev/null @@ -1,263 +0,0 @@ -// -// Copyright (C) 2004-2006, Maciej Sobczak -// Copyright (C) 2017-2019, FlightAware LLC -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// - -// Note: this file is not supposed to be a stand-alone header - -template class method1 : public object_cmd_base { - typedef object const &T1; - typedef R (C::*mem_type)(T1); - typedef R (C::*cmem_type)(T1) const; - enum { var_start = 2 }; - - public: - method1(mem_type f) : f_(f), cmem_(false) {} - method1(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - C *p = static_cast(pv); - - object t1 = get_var_params(interp, objc, objv, var_start, pol); - - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1), t1); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1), t1); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method2 : public object_cmd_base { - typedef object const &T2; - typedef R (C::*mem_type)(T1, T2); - typedef R (C::*cmem_type)(T1, T2) const; - enum { var_start = 3 }; - - public: - method2(mem_type f) : f_(f), cmem_(false) {} - method2(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - C *p = static_cast(pv); - - object t2 = get_var_params(interp, objc, objv, var_start, pol); - - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2), tcl_cast::from(interp, objv[2]), t2); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2), tcl_cast::from(interp, objv[2]), t2); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method3 : public object_cmd_base { - typedef object const &T3; - typedef R (C::*mem_type)(T1, T2, T3); - typedef R (C::*cmem_type)(T1, T2, T3) const; - enum { var_start = 4 }; - - public: - method3(mem_type f) : f_(f), cmem_(false) {} - method3(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - C *p = static_cast(pv); - - object t3 = get_var_params(interp, objc, objv, var_start, pol); - - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), t3); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), t3); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method4 : public object_cmd_base { - typedef object const &T4; - typedef R (C::*mem_type)(T1, T2, T3, T4); - typedef R (C::*cmem_type)(T1, T2, T3, T4) const; - enum { var_start = 5 }; - - public: - method4(mem_type f) : f_(f), cmem_(false) {} - method4(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - C *p = static_cast(pv); - - object t4 = get_var_params(interp, objc, objv, var_start, pol); - - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), t4); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), t4); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method5 : public object_cmd_base { - typedef object const &T5; - typedef R (C::*mem_type)(T1, T2, T3, T4, T5); - typedef R (C::*cmem_type)(T1, T2, T3, T4, T5) const; - enum { var_start = 6 }; - - public: - method5(mem_type f) : f_(f), cmem_(false) {} - method5(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - C *p = static_cast(pv); - - object t5 = get_var_params(interp, objc, objv, var_start, pol); - - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), tcl_cast::from(interp, objv[5]), t5); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), tcl_cast::from(interp, objv[5]), t5); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method6 : public object_cmd_base { - typedef object const &T6; - typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6); - typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6) const; - enum { var_start = 7 }; - - public: - method6(mem_type f) : f_(f), cmem_(false) {} - method6(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - C *p = static_cast(pv); - - object t6 = get_var_params(interp, objc, objv, var_start, pol); - - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), tcl_cast::from(interp, objv[5]), tcl_cast::from(interp, objv[6]), t6); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), tcl_cast::from(interp, objv[5]), tcl_cast::from(interp, objv[6]), t6); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method7 : public object_cmd_base { - typedef object const &T7; - typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7); - typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7) const; - enum { var_start = 8 }; - - public: - method7(mem_type f) : f_(f), cmem_(false) {} - method7(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - C *p = static_cast(pv); - - object t7 = get_var_params(interp, objc, objv, var_start, pol); - - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), tcl_cast::from(interp, objv[5]), tcl_cast::from(interp, objv[6]), tcl_cast::from(interp, objv[7]), t7); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), tcl_cast::from(interp, objv[5]), tcl_cast::from(interp, objv[6]), tcl_cast::from(interp, objv[7]), t7); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method8 : public object_cmd_base { - typedef object const &T8; - typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7, T8); - typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7, T8) const; - enum { var_start = 9 }; - - public: - method8(mem_type f) : f_(f), cmem_(false) {} - method8(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - C *p = static_cast(pv); - - object t8 = get_var_params(interp, objc, objv, var_start, pol); - - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), tcl_cast::from(interp, objv[5]), tcl_cast::from(interp, objv[6]), tcl_cast::from(interp, objv[7]), tcl_cast::from(interp, objv[8]), t8); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), tcl_cast::from(interp, objv[5]), tcl_cast::from(interp, objv[6]), tcl_cast::from(interp, objv[7]), tcl_cast::from(interp, objv[8]), t8); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; - -template class method9 : public object_cmd_base { - typedef object const &T9; - typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7, T8, T9); - typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7, T8, T9) const; - enum { var_start = 10 }; - - public: - method9(mem_type f) : f_(f), cmem_(false) {} - method9(cmem_type f) : cf_(f), cmem_(true) {} - - virtual void invoke(void *pv, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], policies const &pol) { - C *p = static_cast(pv); - - object t9 = get_var_params(interp, objc, objv, var_start, pol); - - if (cmem_) { - dispatch::template do_dispatch(interp, std::bind(cf_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8, std::placeholders::_9), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), tcl_cast::from(interp, objv[5]), tcl_cast::from(interp, objv[6]), tcl_cast::from(interp, objv[7]), tcl_cast::from(interp, objv[8]), tcl_cast::from(interp, objv[9]), t9); - } else { - dispatch::template do_dispatch(interp, std::bind(f_, p, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8, std::placeholders::_9), tcl_cast::from(interp, objv[2]), tcl_cast::from(interp, objv[3]), tcl_cast::from(interp, objv[4]), tcl_cast::from(interp, objv[5]), tcl_cast::from(interp, objv[6]), tcl_cast::from(interp, objv[7]), tcl_cast::from(interp, objv[8]), tcl_cast::from(interp, objv[9]), t9); - } - } - - private: - mem_type f_; - cmem_type cf_; - bool cmem_; -}; diff --git a/doc/arguments.md b/doc/arguments.md new file mode 100644 index 0000000..2d62547 --- /dev/null +++ b/doc/arguments.md @@ -0,0 +1,159 @@ +[[prev](callpolicies.md)][[top](README.md)][[next](threads.md)] + +#### Advanced argument mapping + +Besides the usual role of providing mapping to existing functions, +cpptcl also allows C++ functions to be written that are specifically designed for interfacing TCL. + +The calling conventions are communicated to cpptcl as part of the function's signature. + +#### Tcl::opt + +``` +void print_hello(std::string & const message, Tcl::opt const & ntimes) { + for (int i = 0; i < (ntimes ? *ntimes : 1); ++i) { + std::cout << message << "\n"; + } +} +``` + +This function when registered with cpptcl can be called as + +``` +print_hello word_up + +print_hello word_up 10 +``` + +#### Tcl::variadic + +``` +void print_hello(Tcl::variadic const & messages) { + for (auto const & m : messages) { + std::cout << m << "\n"; + } +} +``` + +``` +print_hello word up +print_hello +print_hello Yoh pretty ladies around the world +``` + +The variadic argument can only appear once and it has to be the last argument. + +#### Tcl::list + +``` +void print_hello(Tcl::list const & messages) { + for (auto const & m : messages) { + std::cout << m << "\n"; + } +} +``` + +``` +print_hello { w o r d up } +print_hello [split "Wave your hands in the air" { }] +``` + +list is somewhat similar to variadic, but list can be specified multiple times and it +interprets a single argument as a list, whereas variadic maps to multiple arguments + +#### Object types + +tcl allows objects to be treated in much the same way as strings. When the tcl interpreter +is supplied with a function that generates a string representation of an object, the object +type can be attached to that scalar. + +For these examples, the *_ops structure can be imagined as providing functinality to generate +the string representation. For each registred type the tcl interpreter will allocate a typeobj +structure that has a unique memory address. + +``` +Tcl::interpreter interp(Tcl_CreateInterp(), true); + +interp.type("cell", (Component *)); +interp.type("pin", (Pin *)); +interp.type("net", (Net *)); + + + +Component * get_cell(std::string const & name) { + return all_my_cells[name]; +} +void number_of_pins(Component * c) { + std::cout << "cell " << c->name << " has " << c->num_pins << " pins\n"; +} + +number_of_pins [get_cell CPU] +``` + +#### Tcl::any + +To take a limited set of types as an argument. + +``` +void print_object(Tcl::any const & obj) { + if (Component * c = obj.as()) { + std::cout << c->name; + } else if (Net * n = obj.as()) { + std::cout << n->name; + } else if (Pin * p = obj.as()) { + std::cout << p->name; + } + + // or, alternatively + obj.visit([&](Component * c) { std::cout << c->name; }, + [&](Net * n) { std::cout << n->name; }, + [&](Pin * p) { std::cout << p->name; }); +} + +print_obj [get_cell PCH] +print_obj [get_net GND] +``` + +### Tcl::getopt + +This is the same as Tcl::opt, but when the procedure is called a getopt parser +is used to map tcl arguments to C++ arguments and the position of parameters +no longer maps trivially between function call and function implementation. + +``` +void fancy_print_hello(Tcl::getopt const & header, Tcl::getopt const & signature, std::string const & message) { + if (header) { + std::cout << "Now hear this:\n"; + } + std::cout << message << "\n"; + if (signature) { + std::cout << "\t" << *signature << "\n"; + } +} + +fancy_print_hello -signature Everybody -header "When you hear the call you got to get it underway" +``` + +#### Combinations + +Tcl::opt and Tcl::getopt can encapsulate Tcl::any and Tcl::list. + +``` +void optional_hello(Tcl::opt > const & obj) { + if (obj) { + obj->visit(...); + } else { + std::cout << "nothing to see here\n"; + } +} +``` + +Tcl::list can encapsulate Tcl::any. A list of objects belonging to a type in the set. +Tcl::any can encapsulate Tcl::list. A list of objects belonging to a type in the set and all elements +in the list are of the same type. + +Tcl::opt can encapsulate a Tcl::any. and so forth. + +Tcl::any and Tcl::list both cannot encapsulate a Tcl::opt or Tcl::getopt. Tcl::opt cannot encapsulate Tcl::getopt. +Neither can Tcl::getopt encapsulate Tcl::opt. The result of undefined (and frankly nonsensical) combinations are +undefined. TODO: turn them into compile time errors. \ No newline at end of file diff --git a/doc/callpolicies.md b/doc/callpolicies.md index 24dbbd1..7ed4c58 100644 --- a/doc/callpolicies.md +++ b/doc/callpolicies.md @@ -1,4 +1,4 @@ -[[prev](objects.md)][[top](README.md)][[next](threads.md)] +[[prev](objects.md)][[top](README.md)][[next](arguments.md)] #### Call Policies diff --git a/doc/freefun.md b/doc/freefun.md index b36e5a3..e95f640 100644 --- a/doc/freefun.md +++ b/doc/freefun.md @@ -54,8 +54,6 @@ If you create a Tcl command that's the same name as a command that already exist You probably noticed that the exposed functions can have parameters and can return values. -Functions with up to 9 parameters can be exposed. - At the moment, parameters and the return value of exposed functions can have the following types: * std::string, char const * @@ -63,6 +61,7 @@ At the moment, parameters and the return value of exposed functions can have the * int, * long, * bool, +* float, * double, * pointer to arbitrary type * [object](objects.md) diff --git a/examples/Makefile b/examples/Makefile index ddb5d36..f9db266 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,16 +1,518 @@ -OUTPUTS = build/example2 build/example6 +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.16 -all : ${OUTPUTS} +# Default target executed when no arguments are given to make. +default_target: all -build/Makefile: - mkdir -p build - (cd build; cmake ..) +.PHONY : default_target -build/example2 : build/Makefile example2.cc - (cd build; make example2) +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: -build/example6 : build/Makefile example6.cc - (cd build; make example6) -clean : - rm -rf build +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/sascha/git/cpptcl + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/sascha/git/cpptcl + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip/fast + +# Special rule for the target test +test: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running tests..." + /usr/bin/ctest --force-new-ctest-process $(ARGS) +.PHONY : test + +# Special rule for the target test +test/fast: test + +.PHONY : test/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache + +.PHONY : edit_cache/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache + +.PHONY : rebuild_cache/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components + +.PHONY : list_install_components/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local/fast + +# The main all target +all: cmake_check_build_system + cd /home/sascha/git/cpptcl && $(CMAKE_COMMAND) -E cmake_progress_start /home/sascha/git/cpptcl/CMakeFiles /home/sascha/git/cpptcl/examples/CMakeFiles/progress.marks + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 examples/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/sascha/git/cpptcl/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 examples/clean +.PHONY : clean + +# The main clean target +clean/fast: clean + +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 examples/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 examples/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /home/sascha/git/cpptcl && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +examples/CMakeFiles/cpptcl_example_functions.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 examples/CMakeFiles/cpptcl_example_functions.dir/rule +.PHONY : examples/CMakeFiles/cpptcl_example_functions.dir/rule + +# Convenience name for target. +cpptcl_example_functions: examples/CMakeFiles/cpptcl_example_functions.dir/rule + +.PHONY : cpptcl_example_functions + +# fast build rule for target. +cpptcl_example_functions/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_example_functions.dir/build.make examples/CMakeFiles/cpptcl_example_functions.dir/build +.PHONY : cpptcl_example_functions/fast + +# Convenience name for target. +examples/CMakeFiles/example2.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 examples/CMakeFiles/example2.dir/rule +.PHONY : examples/CMakeFiles/example2.dir/rule + +# Convenience name for target. +example2: examples/CMakeFiles/example2.dir/rule + +.PHONY : example2 + +# fast build rule for target. +example2/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/example2.dir/build.make examples/CMakeFiles/example2.dir/build +.PHONY : example2/fast + +# Convenience name for target. +examples/CMakeFiles/example6.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 examples/CMakeFiles/example6.dir/rule +.PHONY : examples/CMakeFiles/example6.dir/rule + +# Convenience name for target. +example6: examples/CMakeFiles/example6.dir/rule + +.PHONY : example6 + +# fast build rule for target. +example6/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/example6.dir/build.make examples/CMakeFiles/example6.dir/build +.PHONY : example6/fast + +# Convenience name for target. +examples/CMakeFiles/cpptcl_module_two.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 examples/CMakeFiles/cpptcl_module_two.dir/rule +.PHONY : examples/CMakeFiles/cpptcl_module_two.dir/rule + +# Convenience name for target. +cpptcl_module_two: examples/CMakeFiles/cpptcl_module_two.dir/rule + +.PHONY : cpptcl_module_two + +# fast build rule for target. +cpptcl_module_two/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_two.dir/build.make examples/CMakeFiles/cpptcl_module_two.dir/build +.PHONY : cpptcl_module_two/fast + +# Convenience name for target. +examples/CMakeFiles/cpptcl_module_three.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 examples/CMakeFiles/cpptcl_module_three.dir/rule +.PHONY : examples/CMakeFiles/cpptcl_module_three.dir/rule + +# Convenience name for target. +cpptcl_module_three: examples/CMakeFiles/cpptcl_module_three.dir/rule + +.PHONY : cpptcl_module_three + +# fast build rule for target. +cpptcl_module_three/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_three.dir/build.make examples/CMakeFiles/cpptcl_module_three.dir/build +.PHONY : cpptcl_module_three/fast + +# Convenience name for target. +examples/CMakeFiles/cpptcl_module_five.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 examples/CMakeFiles/cpptcl_module_five.dir/rule +.PHONY : examples/CMakeFiles/cpptcl_module_five.dir/rule + +# Convenience name for target. +cpptcl_module_five: examples/CMakeFiles/cpptcl_module_five.dir/rule + +.PHONY : cpptcl_module_five + +# fast build rule for target. +cpptcl_module_five/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_five.dir/build.make examples/CMakeFiles/cpptcl_module_five.dir/build +.PHONY : cpptcl_module_five/fast + +# Convenience name for target. +examples/CMakeFiles/cpptcl_module_six.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 examples/CMakeFiles/cpptcl_module_six.dir/rule +.PHONY : examples/CMakeFiles/cpptcl_module_six.dir/rule + +# Convenience name for target. +cpptcl_module_six: examples/CMakeFiles/cpptcl_module_six.dir/rule + +.PHONY : cpptcl_module_six + +# fast build rule for target. +cpptcl_module_six/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_six.dir/build.make examples/CMakeFiles/cpptcl_module_six.dir/build +.PHONY : cpptcl_module_six/fast + +cpptcl_example_functions.o: cpptcl_example_functions.cc.o + +.PHONY : cpptcl_example_functions.o + +# target to build an object file +cpptcl_example_functions.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_example_functions.dir/build.make examples/CMakeFiles/cpptcl_example_functions.dir/cpptcl_example_functions.cc.o +.PHONY : cpptcl_example_functions.cc.o + +cpptcl_example_functions.i: cpptcl_example_functions.cc.i + +.PHONY : cpptcl_example_functions.i + +# target to preprocess a source file +cpptcl_example_functions.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_example_functions.dir/build.make examples/CMakeFiles/cpptcl_example_functions.dir/cpptcl_example_functions.cc.i +.PHONY : cpptcl_example_functions.cc.i + +cpptcl_example_functions.s: cpptcl_example_functions.cc.s + +.PHONY : cpptcl_example_functions.s + +# target to generate assembly for a file +cpptcl_example_functions.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_example_functions.dir/build.make examples/CMakeFiles/cpptcl_example_functions.dir/cpptcl_example_functions.cc.s +.PHONY : cpptcl_example_functions.cc.s + +cpptcl_module_five.o: cpptcl_module_five.cc.o + +.PHONY : cpptcl_module_five.o + +# target to build an object file +cpptcl_module_five.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_five.dir/build.make examples/CMakeFiles/cpptcl_module_five.dir/cpptcl_module_five.cc.o +.PHONY : cpptcl_module_five.cc.o + +cpptcl_module_five.i: cpptcl_module_five.cc.i + +.PHONY : cpptcl_module_five.i + +# target to preprocess a source file +cpptcl_module_five.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_five.dir/build.make examples/CMakeFiles/cpptcl_module_five.dir/cpptcl_module_five.cc.i +.PHONY : cpptcl_module_five.cc.i + +cpptcl_module_five.s: cpptcl_module_five.cc.s + +.PHONY : cpptcl_module_five.s + +# target to generate assembly for a file +cpptcl_module_five.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_five.dir/build.make examples/CMakeFiles/cpptcl_module_five.dir/cpptcl_module_five.cc.s +.PHONY : cpptcl_module_five.cc.s + +cpptcl_module_six.o: cpptcl_module_six.cc.o + +.PHONY : cpptcl_module_six.o + +# target to build an object file +cpptcl_module_six.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_six.dir/build.make examples/CMakeFiles/cpptcl_module_six.dir/cpptcl_module_six.cc.o +.PHONY : cpptcl_module_six.cc.o + +cpptcl_module_six.i: cpptcl_module_six.cc.i + +.PHONY : cpptcl_module_six.i + +# target to preprocess a source file +cpptcl_module_six.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_six.dir/build.make examples/CMakeFiles/cpptcl_module_six.dir/cpptcl_module_six.cc.i +.PHONY : cpptcl_module_six.cc.i + +cpptcl_module_six.s: cpptcl_module_six.cc.s + +.PHONY : cpptcl_module_six.s + +# target to generate assembly for a file +cpptcl_module_six.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_six.dir/build.make examples/CMakeFiles/cpptcl_module_six.dir/cpptcl_module_six.cc.s +.PHONY : cpptcl_module_six.cc.s + +cpptcl_module_three.o: cpptcl_module_three.cc.o + +.PHONY : cpptcl_module_three.o + +# target to build an object file +cpptcl_module_three.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_three.dir/build.make examples/CMakeFiles/cpptcl_module_three.dir/cpptcl_module_three.cc.o +.PHONY : cpptcl_module_three.cc.o + +cpptcl_module_three.i: cpptcl_module_three.cc.i + +.PHONY : cpptcl_module_three.i + +# target to preprocess a source file +cpptcl_module_three.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_three.dir/build.make examples/CMakeFiles/cpptcl_module_three.dir/cpptcl_module_three.cc.i +.PHONY : cpptcl_module_three.cc.i + +cpptcl_module_three.s: cpptcl_module_three.cc.s + +.PHONY : cpptcl_module_three.s + +# target to generate assembly for a file +cpptcl_module_three.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_three.dir/build.make examples/CMakeFiles/cpptcl_module_three.dir/cpptcl_module_three.cc.s +.PHONY : cpptcl_module_three.cc.s + +cpptcl_module_two.o: cpptcl_module_two.cc.o + +.PHONY : cpptcl_module_two.o + +# target to build an object file +cpptcl_module_two.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_two.dir/build.make examples/CMakeFiles/cpptcl_module_two.dir/cpptcl_module_two.cc.o +.PHONY : cpptcl_module_two.cc.o + +cpptcl_module_two.i: cpptcl_module_two.cc.i + +.PHONY : cpptcl_module_two.i + +# target to preprocess a source file +cpptcl_module_two.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_two.dir/build.make examples/CMakeFiles/cpptcl_module_two.dir/cpptcl_module_two.cc.i +.PHONY : cpptcl_module_two.cc.i + +cpptcl_module_two.s: cpptcl_module_two.cc.s + +.PHONY : cpptcl_module_two.s + +# target to generate assembly for a file +cpptcl_module_two.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/cpptcl_module_two.dir/build.make examples/CMakeFiles/cpptcl_module_two.dir/cpptcl_module_two.cc.s +.PHONY : cpptcl_module_two.cc.s + +example2.o: example2.cc.o + +.PHONY : example2.o + +# target to build an object file +example2.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/example2.dir/build.make examples/CMakeFiles/example2.dir/example2.cc.o +.PHONY : example2.cc.o + +example2.i: example2.cc.i + +.PHONY : example2.i + +# target to preprocess a source file +example2.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/example2.dir/build.make examples/CMakeFiles/example2.dir/example2.cc.i +.PHONY : example2.cc.i + +example2.s: example2.cc.s + +.PHONY : example2.s + +# target to generate assembly for a file +example2.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/example2.dir/build.make examples/CMakeFiles/example2.dir/example2.cc.s +.PHONY : example2.cc.s + +example6.o: example6.cc.o + +.PHONY : example6.o + +# target to build an object file +example6.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/example6.dir/build.make examples/CMakeFiles/example6.dir/example6.cc.o +.PHONY : example6.cc.o + +example6.i: example6.cc.i + +.PHONY : example6.i + +# target to preprocess a source file +example6.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/example6.dir/build.make examples/CMakeFiles/example6.dir/example6.cc.i +.PHONY : example6.cc.i + +example6.s: example6.cc.s + +.PHONY : example6.s + +# target to generate assembly for a file +example6.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f examples/CMakeFiles/example6.dir/build.make examples/CMakeFiles/example6.dir/example6.cc.s +.PHONY : example6.cc.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... install/strip" + @echo "... cpptcl_example_functions" + @echo "... example2" + @echo "... example6" + @echo "... cpptcl_module_two" + @echo "... test" + @echo "... cpptcl_module_three" + @echo "... install" + @echo "... edit_cache" + @echo "... rebuild_cache" + @echo "... cpptcl_module_five" + @echo "... list_install_components" + @echo "... cpptcl_module_six" + @echo "... install/local" + @echo "... cpptcl_example_functions.o" + @echo "... cpptcl_example_functions.i" + @echo "... cpptcl_example_functions.s" + @echo "... cpptcl_module_five.o" + @echo "... cpptcl_module_five.i" + @echo "... cpptcl_module_five.s" + @echo "... cpptcl_module_six.o" + @echo "... cpptcl_module_six.i" + @echo "... cpptcl_module_six.s" + @echo "... cpptcl_module_three.o" + @echo "... cpptcl_module_three.i" + @echo "... cpptcl_module_three.s" + @echo "... cpptcl_module_two.o" + @echo "... cpptcl_module_two.i" + @echo "... cpptcl_module_two.s" + @echo "... example2.o" + @echo "... example2.i" + @echo "... example2.s" + @echo "... example6.o" + @echo "... example6.i" + @echo "... example6.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /home/sascha/git/cpptcl && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/libraries/gd.cpp b/libraries/gd.cpp new file mode 100644 index 0000000..815c973 --- /dev/null +++ b/libraries/gd.cpp @@ -0,0 +1,270 @@ +//#define USE_TCL_STUBS + +#ifndef USE_TCL_STUBS +#define CPPTCL_NO_TCL_STUBS +#endif + +#include "gd.hpp" + +namespace Tcl { namespace GD { + using namespace detail; + void init(interpreter * tcli) __attribute__((optimize("s"))) __attribute__((cold)); + + void init(interpreter * tcli) { + auto make_gdio_ctx_from_channel = [] (Tcl_Channel chan) -> gdIOCtx * { + gdIOCtx * x = new gdIOCtx; + gdio * io = new gdio(chan); + x->data = (void *) io; + gdio::gdio_install(x); + return x; + }; + auto make_gdio_ctx_from_name = [&](Tcl_Interp * i, const char * name, int wantmode) -> gdIOCtx * { + int mode; + Tcl_Channel chan = Tcl_GetChannel(i, name, &mode); + if (! chan) return nullptr; + if (! (mode & wantmode)) return nullptr; + return make_gdio_ctx_from_channel(chan); + }; + + auto conv_color = [&](Tcl_Obj * o) { + int ret; + if (Tcl_GetIntFromObj(tcli->get_interp(), o, &ret) == TCL_OK) { + return ret; + } + int slen; + const char * s = Tcl_GetStringFromObj(o, &slen); + auto cmp = [s](const char * b) { + return strcmp(s, b) == 0; + }; + if (cmp("antialiased")) return gdAntiAliased; + else if (cmp("brushed")) return gdBrushed; + else if (cmp("styled")) return gdStyled; + else if (cmp("styled_brushed")) return gdStyledBrushed; + else if (cmp("tiled")) return gdTiled; + else if (cmp("transparent")) return gdTransparent; + return 0; + }; + + using I = Tcl::interpreter; + + struct custom { + static void polygon3(GDImage * img, std::string const & filled_open, list points, int color) { + gdPoint * pp = new gdPoint[points.size() / 2]; + for (std::size_t i = 0; i < points.size() / 2; ++i) { + pp[i / 2].x = points.at(i * 2); + pp[i / 2].y = points.at(i * 2 + 1); + } + if (filled_open.empty()) { + gdImagePolygon(img->img, pp, points.size() / 2, color); + } else if (filled_open == "filled") { + gdImageFilledPolygon(img->img, pp, points.size() / 2, color); + } else if (filled_open == "open") { + gdImageOpenPolygon(img->img, pp, points.size() / 2, color); + } + } + static void polygon2(GDImage * img, list const & points, int color) { + polygon3(img, "", points, color); + } + }; + auto fromctx = [&] (auto f) { + return [&, f] (GDFactory *, const char * name) { + gdIOCtx * ctx = make_gdio_ctx_from_name(tcli->get_interp(), name, TCL_READABLE); + auto im = f(ctx); + ctx->gd_free(ctx); + return named_pointer_result(strcmp(name, "#auto") == 0 ? "" : name, new GDImage { im }); + }; + }; + auto fromdata = [](auto f) { + return [f] (GDFactory *, const char * name, object const & o) { + int size; + unsigned char * ptr = Tcl_GetByteArrayFromObj(o.get_object(), &size); + return named_pointer_result(strcmp(name, "#auto") == 0 ? "" : name, new GDImage { f(size, ptr) }); + }; + }; + auto fromnew = [](auto f) { + return [f] (GDFactory *, const char * name, int x, int y) { + return named_pointer_result(strcmp(name, "#auto") == 0 ? "" : name, new GDImage { f(x, y) }); + }; + }; + + tcli->class_("GDFactory", no_init, factory("GDImage"), lambda_wrapper(fromnew), I::cold) + .def("create", gdImageCreate) + .def("create_truecolor", gdImageCreateTrueColor); + + tcli->class_("GDFactory", no_init, factory("GDImage"), lambda_wrapper{fromctx}, I::cold) + .def("create_from_jpeg", gdImageCreateFromJpegCtx) + .def("create_from_png", gdImageCreateFromPngCtx) + .def("create_from_gif", gdImageCreateFromGifCtx) + .def("create_from_gd", gdImageCreateFromGdCtx) + .def("create_from_gd2", gdImageCreateFromGd2Ctx) + .def("create_from_wbmp", gdImageCreateFromWBMPCtx); + + tcli->class_("GDFactory", no_init, factory("GDImage"), lambda_wrapper(fromdata), I::cold) + .def("create_from_jpeg_data", gdImageCreateFromJpegPtr) + .def("create_from_png_data", gdImageCreateFromPngPtr) + .def("create_from_gif_data", gdImageCreateFromGifPtr) + .def("create_from_gd_data", gdImageCreateFromGdPtr) + .def("create_from_gd2_data", gdImageCreateFromGd2Ptr) + .def("create_from_wbmp_data", gdImageCreateFromWBMPPtr); + + tcli->class_("GDFactory", no_init, factory("GDImage"), I::cold) + .def("create_from_gd2_part", [&](GDFactory *, const char * name, const char * chan, int x, int y, int w, int h) { + gdIOCtx * ctx = make_gdio_ctx_from_name(tcli->get_interp(), chan, TCL_READABLE); + auto im = gdImageCreateFromGd2PartCtx(ctx, x, y, w, h); + ctx->gd_free(ctx); + return named_pointer_result(strcmp(name, "#auto") == 0 ? "" : name, new GDImage { im }); + }) + .def("create_from_gd2_part_data", [&](GDFactory *, const char * name, Tcl_Obj * data, int x, int y, int w, int h) { + int sz; + unsigned char * ptr = Tcl_GetByteArrayFromObj(data, &sz); + auto im = gdImageCreateFromGd2PartPtr(sz, ptr, x, y, w, h); + return named_pointer_result(strcmp(name, "#auto") == 0 ? "" : name, new GDImage { im }); + }) + .def("version", [](GDFactory *) { return object(GD_VERSION_STRING); }) + .def("create_from_xpm", [](GDFactory *, const char * name, const char * fname) { + auto im = gdImageCreateFromXpm(const_cast(fname)); + return named_pointer_result(strcmp(name, "#auto") == 0 ? "" : name, new GDImage { im }); + }) + .def("create_from_xbm", [&](GDFactory *, const char * name, const char * fh) { + FILE * file; + Tcl_GetOpenFile(tcli->get_interp(), fh, 1, 1, (ClientData *) &file); + auto im = gdImageCreateFromXbm(file); + return named_pointer_result(strcmp(name, "#auto") == 0 ? "" : name, new GDImage { im }); + }); + //.def("features",...) + + tcli->def("GDFactory_construct", [tcli](opt const & name) { + tcli->custom_construct("GDFactory", name ? *name : "GD", new GDFactory); + }); + + auto conv_imgobj = [](GDImage * this_p, int, Tcl_Obj * const *, int) { + return this_p->img; + }; + +#if 1 + tcli->class_("GDImage", no_init) + .def("pixel", overload(gdImageGetPixel, gdImageSetPixel), I::arg<3>, conv_color) + //.def("pixelrgb", overload(gdImageGetPixel, gdImageSetPixel)) + .def("polygon", overload(custom::polygon2, custom::polygon3)); +#endif + + // functions with a color argument + tcli->class_("GDImage", no_init, I::cold, I::arg<-1>, conv_color, I::arg<0>, conv_imgobj) + .def("line", gdImageLine) + .def("rectangle", gdImageRectangle) + .def("filled_rectangle", gdImageFilledRectangle) + .def("arc", gdImageArc) + //.def("filled_arc") + .def("filled_ellipse", gdImageFilledEllipse) + .def("fill_to_border", gdImageFillToBorder, I::arg<3>, conv_color) + .def("fill", gdImageFill) + .def("deallocate_color", gdImageColorDeallocate); + + // all else + tcli->class_("GDImage", no_init, I::cold, I::arg<0>, conv_imgobj) + .def("allocate_color", overload(gdImageColorAllocate, gdImageColorAllocateAlpha)) + .def("closest_color", overload(gdImageColorClosest, gdImageColorClosestAlpha)) + .def("closest_color_hwb", gdImageColorClosestHWB) + .def("exact_color", overload(gdImageColorExact, gdImageColorExactAlpha)) + .def("resolve_color", overload(gdImageColorResolve, gdImageColorResolveAlpha)) + .def("interlace", overload([](gdImagePtr img) { return gdImageGetInterlaced(img); }, gdImageInterlace)) + .def("transparent", overload([](gdImagePtr img) { return gdImageGetTransparent(img); }, gdImageColorTransparent)) + .def("set_anti_aliased", gdImageSetAntiAliased) + .def("set_anti_aliased_dont_blend", gdImageSetAntiAliasedDontBlend, I::arg<-2>, conv_color) + .def("set_thickness", gdImageSetThickness) + .def("alpha_blending", gdImageAlphaBlending) + .def("save_alpha", gdImageSaveAlpha) + .def("clip", gdImageSetClip) + .def("bounds_safe", gdImageBoundsSafe) + ; + + // functions defined as preprocessor macros + tcli->class_("GDImage", no_init, I::arg<0>, conv_imgobj) + .def("width", [](gdImagePtr img) { return gdImageSX(img); }) + .def("height", [](gdImagePtr img) { return gdImageSY(img); }) + .def("total_colors", [](gdImagePtr img) { return gdImageColorsTotal(img); }) + .def("get_alpha", [](gdImagePtr img, int c) { return gdImageAlpha(img, c); }) + .def("green_component", [](gdImagePtr img, int c) { return gdImageGreen(img, c); }) + .def("blue_component", [](gdImagePtr img, int c) { return gdImageBlue(img, c); }) + .def("red_component", [](gdImagePtr img, int c) { return gdImageRed(img, c); }) + .def("true_color", overload([](gdImagePtr, int r, int g, int b) { return gdTrueColor(r, g, b); }, + [](gdImagePtr, int r, int g, int b, int a) { return gdTrueColorAlpha(r, g, b, a); })) + ; + + auto todata0 = [](auto f) { + return [f](GDImage * this_p) { + int sz; + + unsigned char * p; + p = (unsigned char *) f(this_p->img, &sz); + return object(Tcl_NewByteArrayObj(p, sz)); + }; + }; + auto todata1 = [](auto f) { + return [f](GDImage * this_p, int i) { + int sz; + + unsigned char * p; + p = (unsigned char *) f(this_p->img, &sz, i); + return object(Tcl_NewByteArrayObj(p, sz)); + }; + }; + + tcli->class_("GDImage", no_init, I::cold) + .def("png_data", todata1(gdImagePngPtrEx)) + .def("jpeg_data", todata1(gdImageJpegPtr)) + .def("gif_data", todata0(gdImageGifPtr)) + .def("wbmp_data", todata1(gdImageWBMPPtr)) + .def("gd_data", todata0(gdImageGdPtr)); + + auto toctx_wbmp = [&](auto f) { + return [&, f](GDImage * img, const char * chan, int i) { + gdIOCtx * ctx = make_gdio_ctx_from_name(tcli->get_interp(), chan, TCL_WRITABLE); + f(img->img, i, ctx); + ctx->gd_free(ctx); + }; + }; + auto toctx_png_jpeg = [&](auto f) { + return [&, f](GDImage * img, const char * chan, int i) { + gdIOCtx * ctx = make_gdio_ctx_from_name(tcli->get_interp(), chan, TCL_WRITABLE); + f(img->img, ctx, i); + ctx->gd_free(ctx); + }; + }; + auto toctx0 = [&](auto f) { + return [&, f](GDImage * img, const char * chan) { + gdIOCtx * ctx = make_gdio_ctx_from_name(tcli->get_interp(), chan, TCL_WRITABLE); + f(img->img, ctx); + ctx->gd_free(ctx); + }; + }; + tcli->class_("GDImage", no_init, I::cold) + .def("write_png", toctx_png_jpeg(gdImagePngCtxEx)) + .def("write_jpeg", toctx_png_jpeg(gdImageJpegCtx)) + .def("write_gif", toctx0(gdImageGifCtx)) + .def("write_wbmp", toctx_wbmp(gdImageWBMPCtx)) + ; + + //.def("write_gd", toctx(gdImage + } +} } + +#if 1 +int main(int argc, char ** argv) { + using namespace Tcl; +#ifdef USE_TCL_STUBS + Tcl_Interp * tcl = Tcl_CreateInterpWithStubs("8.6", 0); +#else + Tcl_Interp * tcl = Tcl_CreateInterp(); +#endif + + interpreter tcli(tcl, true); + GD::init(&tcli); + try { + auto r = tcli.eval(argv[1]); + std::cerr << (std::string) r << "\n"; + } catch (std::exception & e) { + std::cerr << "error: " << e.what() << "\n"; + } +} +#endif diff --git a/libraries/gd.hpp b/libraries/gd.hpp new file mode 100644 index 0000000..b156378 --- /dev/null +++ b/libraries/gd.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include + +#include +#include + +namespace Tcl { + namespace GD { + namespace detail { + template + struct gdio : public Impl { + typedef Impl this_t; + using Impl::Impl; + + static int getC_(gdIOCtx * x) { + return ((this_t *) x->data)->getC(); + } + static int getBuf_(gdIOCtx * x, void * p, int n) { + return ((this_t *) x->data)->getBuf(p, n); + } + static void putC_(gdIOCtx * x, int c) { + ((this_t *) x->data)->putC(c); + } + static int putBuf_(gdIOCtx * x, const void * p, int n) { + return ((this_t *) x->data)->putBuf(p, n); + } + static int seek_(gdIOCtx * x, int o) { + return ((this_t *) x->data)->seek(o); + } + static long tell_(gdIOCtx * x) { + return ((this_t *) x->data)->tell(); + } + static void free_(gdIOCtx * x) { + delete (gdio *) x->data; + delete x; + } + static void gdio_install(gdIOCtx * x) { + x->getC = getC_; + x->getBuf = getBuf_; + x->putC = putC_; + x->putBuf = putBuf_; + x->tell = tell_; + x->seek = seek_; + x->gd_free = free_; + } + }; + struct Tcl_Channel_IO { + Tcl_Channel chan; + Tcl_Channel_IO(Tcl_Channel c) : chan(c) { } + int getC() { + char buf[2]; + Tcl_Read(chan, buf, 1); + return buf[0]; + } + void putC(int c) { + char buf[1]; + buf[0] = (char) c; + Tcl_Write(chan, buf, 1); + } + int getBuf(void * p, int n) { + return Tcl_Read(chan, (char *) p, n); + } + int putBuf(const void * p, int n) { + return Tcl_Write(chan, (const char *) p, n); + } + int seek(int o) { + return Tcl_Seek(chan, o, SEEK_SET); + } + long tell() { + return Tcl_Tell(chan); + } + }; + + struct GDFactory { + }; + struct GDImage : public interpreter::type_ops { + gdImagePtr img; + + GDImage(gdImagePtr i) : img(i) { } + }; + } + } +} diff --git a/test/Makefile b/test/Makefile index 295430a..66a0519 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,11 +1,615 @@ -all: build/Makefile - (cd build; make) +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.16 -build/Makefile: - cmake -Bbuild -H. +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/sascha/git/cpptcl + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/sascha/git/cpptcl + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local/fast + +# Special rule for the target test +test: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running tests..." + /usr/bin/ctest --force-new-ctest-process $(ARGS) +.PHONY : test + +# Special rule for the target test +test/fast: test + +.PHONY : test/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache + +.PHONY : edit_cache/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache + +.PHONY : rebuild_cache/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components + +.PHONY : list_install_components/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# The main all target +all: cmake_check_build_system + cd /home/sascha/git/cpptcl && $(CMAKE_COMMAND) -E cmake_progress_start /home/sascha/git/cpptcl/CMakeFiles /home/sascha/git/cpptcl/test/CMakeFiles/progress.marks + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/sascha/git/cpptcl/CMakeFiles 0 +.PHONY : all + +# The main clean target clean: - rm -rf build + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/clean +.PHONY : clean + +# The main clean target +clean/fast: clean + +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /home/sascha/git/cpptcl && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +test/CMakeFiles/test1.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/CMakeFiles/test1.dir/rule +.PHONY : test/CMakeFiles/test1.dir/rule + +# Convenience name for target. +test1: test/CMakeFiles/test1.dir/rule + +.PHONY : test1 + +# fast build rule for target. +test1/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test1.dir/build.make test/CMakeFiles/test1.dir/build +.PHONY : test1/fast + +# Convenience name for target. +test/CMakeFiles/test3.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/CMakeFiles/test3.dir/rule +.PHONY : test/CMakeFiles/test3.dir/rule + +# Convenience name for target. +test3: test/CMakeFiles/test3.dir/rule + +.PHONY : test3 + +# fast build rule for target. +test3/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test3.dir/build.make test/CMakeFiles/test3.dir/build +.PHONY : test3/fast + +# Convenience name for target. +test/CMakeFiles/test4.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/CMakeFiles/test4.dir/rule +.PHONY : test/CMakeFiles/test4.dir/rule + +# Convenience name for target. +test4: test/CMakeFiles/test4.dir/rule + +.PHONY : test4 + +# fast build rule for target. +test4/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test4.dir/build.make test/CMakeFiles/test4.dir/build +.PHONY : test4/fast + +# Convenience name for target. +test/CMakeFiles/test5.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/CMakeFiles/test5.dir/rule +.PHONY : test/CMakeFiles/test5.dir/rule + +# Convenience name for target. +test5: test/CMakeFiles/test5.dir/rule + +.PHONY : test5 + +# fast build rule for target. +test5/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test5.dir/build.make test/CMakeFiles/test5.dir/build +.PHONY : test5/fast + +# Convenience name for target. +test/CMakeFiles/test_main.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/CMakeFiles/test_main.dir/rule +.PHONY : test/CMakeFiles/test_main.dir/rule + +# Convenience name for target. +test_main: test/CMakeFiles/test_main.dir/rule + +.PHONY : test_main + +# fast build rule for target. +test_main/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test_main.dir/build.make test/CMakeFiles/test_main.dir/build +.PHONY : test_main/fast + +# Convenience name for target. +test/CMakeFiles/test6.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/CMakeFiles/test6.dir/rule +.PHONY : test/CMakeFiles/test6.dir/rule + +# Convenience name for target. +test6: test/CMakeFiles/test6.dir/rule + +.PHONY : test6 + +# fast build rule for target. +test6/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test6.dir/build.make test/CMakeFiles/test6.dir/build +.PHONY : test6/fast + +# Convenience name for target. +test/CMakeFiles/test2.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/CMakeFiles/test2.dir/rule +.PHONY : test/CMakeFiles/test2.dir/rule + +# Convenience name for target. +test2: test/CMakeFiles/test2.dir/rule + +.PHONY : test2 + +# fast build rule for target. +test2/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test2.dir/build.make test/CMakeFiles/test2.dir/build +.PHONY : test2/fast + +# Convenience name for target. +test/CMakeFiles/test7.dir/rule: + cd /home/sascha/git/cpptcl && $(MAKE) -f CMakeFiles/Makefile2 test/CMakeFiles/test7.dir/rule +.PHONY : test/CMakeFiles/test7.dir/rule + +# Convenience name for target. +test7: test/CMakeFiles/test7.dir/rule + +.PHONY : test7 + +# fast build rule for target. +test7/fast: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test7.dir/build.make test/CMakeFiles/test7.dir/build +.PHONY : test7/fast + +__/cpptcl.o: __/cpptcl.cc.o + +.PHONY : __/cpptcl.o + +# target to build an object file +__/cpptcl.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test1.dir/build.make test/CMakeFiles/test1.dir/__/cpptcl.cc.o + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test3.dir/build.make test/CMakeFiles/test3.dir/__/cpptcl.cc.o + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test4.dir/build.make test/CMakeFiles/test4.dir/__/cpptcl.cc.o + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test5.dir/build.make test/CMakeFiles/test5.dir/__/cpptcl.cc.o + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test_main.dir/build.make test/CMakeFiles/test_main.dir/__/cpptcl.cc.o + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test6.dir/build.make test/CMakeFiles/test6.dir/__/cpptcl.cc.o + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test2.dir/build.make test/CMakeFiles/test2.dir/__/cpptcl.cc.o + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test7.dir/build.make test/CMakeFiles/test7.dir/__/cpptcl.cc.o +.PHONY : __/cpptcl.cc.o + +__/cpptcl.i: __/cpptcl.cc.i + +.PHONY : __/cpptcl.i + +# target to preprocess a source file +__/cpptcl.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test1.dir/build.make test/CMakeFiles/test1.dir/__/cpptcl.cc.i + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test3.dir/build.make test/CMakeFiles/test3.dir/__/cpptcl.cc.i + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test4.dir/build.make test/CMakeFiles/test4.dir/__/cpptcl.cc.i + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test5.dir/build.make test/CMakeFiles/test5.dir/__/cpptcl.cc.i + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test_main.dir/build.make test/CMakeFiles/test_main.dir/__/cpptcl.cc.i + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test6.dir/build.make test/CMakeFiles/test6.dir/__/cpptcl.cc.i + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test2.dir/build.make test/CMakeFiles/test2.dir/__/cpptcl.cc.i + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test7.dir/build.make test/CMakeFiles/test7.dir/__/cpptcl.cc.i +.PHONY : __/cpptcl.cc.i + +__/cpptcl.s: __/cpptcl.cc.s + +.PHONY : __/cpptcl.s + +# target to generate assembly for a file +__/cpptcl.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test1.dir/build.make test/CMakeFiles/test1.dir/__/cpptcl.cc.s + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test3.dir/build.make test/CMakeFiles/test3.dir/__/cpptcl.cc.s + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test4.dir/build.make test/CMakeFiles/test4.dir/__/cpptcl.cc.s + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test5.dir/build.make test/CMakeFiles/test5.dir/__/cpptcl.cc.s + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test_main.dir/build.make test/CMakeFiles/test_main.dir/__/cpptcl.cc.s + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test6.dir/build.make test/CMakeFiles/test6.dir/__/cpptcl.cc.s + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test2.dir/build.make test/CMakeFiles/test2.dir/__/cpptcl.cc.s + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test7.dir/build.make test/CMakeFiles/test7.dir/__/cpptcl.cc.s +.PHONY : __/cpptcl.cc.s + +test1.o: test1.cc.o + +.PHONY : test1.o + +# target to build an object file +test1.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test1.dir/build.make test/CMakeFiles/test1.dir/test1.cc.o +.PHONY : test1.cc.o + +test1.i: test1.cc.i + +.PHONY : test1.i + +# target to preprocess a source file +test1.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test1.dir/build.make test/CMakeFiles/test1.dir/test1.cc.i +.PHONY : test1.cc.i + +test1.s: test1.cc.s + +.PHONY : test1.s + +# target to generate assembly for a file +test1.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test1.dir/build.make test/CMakeFiles/test1.dir/test1.cc.s +.PHONY : test1.cc.s + +test2.o: test2.cc.o + +.PHONY : test2.o + +# target to build an object file +test2.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test2.dir/build.make test/CMakeFiles/test2.dir/test2.cc.o +.PHONY : test2.cc.o + +test2.i: test2.cc.i + +.PHONY : test2.i + +# target to preprocess a source file +test2.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test2.dir/build.make test/CMakeFiles/test2.dir/test2.cc.i +.PHONY : test2.cc.i + +test2.s: test2.cc.s + +.PHONY : test2.s + +# target to generate assembly for a file +test2.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test2.dir/build.make test/CMakeFiles/test2.dir/test2.cc.s +.PHONY : test2.cc.s + +test3.o: test3.cc.o + +.PHONY : test3.o + +# target to build an object file +test3.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test3.dir/build.make test/CMakeFiles/test3.dir/test3.cc.o +.PHONY : test3.cc.o + +test3.i: test3.cc.i + +.PHONY : test3.i + +# target to preprocess a source file +test3.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test3.dir/build.make test/CMakeFiles/test3.dir/test3.cc.i +.PHONY : test3.cc.i + +test3.s: test3.cc.s + +.PHONY : test3.s + +# target to generate assembly for a file +test3.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test3.dir/build.make test/CMakeFiles/test3.dir/test3.cc.s +.PHONY : test3.cc.s + +test4.o: test4.cc.o + +.PHONY : test4.o + +# target to build an object file +test4.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test4.dir/build.make test/CMakeFiles/test4.dir/test4.cc.o +.PHONY : test4.cc.o + +test4.i: test4.cc.i + +.PHONY : test4.i + +# target to preprocess a source file +test4.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test4.dir/build.make test/CMakeFiles/test4.dir/test4.cc.i +.PHONY : test4.cc.i + +test4.s: test4.cc.s + +.PHONY : test4.s + +# target to generate assembly for a file +test4.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test4.dir/build.make test/CMakeFiles/test4.dir/test4.cc.s +.PHONY : test4.cc.s + +test5.o: test5.cc.o + +.PHONY : test5.o + +# target to build an object file +test5.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test5.dir/build.make test/CMakeFiles/test5.dir/test5.cc.o +.PHONY : test5.cc.o + +test5.i: test5.cc.i + +.PHONY : test5.i + +# target to preprocess a source file +test5.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test5.dir/build.make test/CMakeFiles/test5.dir/test5.cc.i +.PHONY : test5.cc.i + +test5.s: test5.cc.s + +.PHONY : test5.s + +# target to generate assembly for a file +test5.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test5.dir/build.make test/CMakeFiles/test5.dir/test5.cc.s +.PHONY : test5.cc.s + +test6.o: test6.cc.o + +.PHONY : test6.o + +# target to build an object file +test6.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test6.dir/build.make test/CMakeFiles/test6.dir/test6.cc.o +.PHONY : test6.cc.o + +test6.i: test6.cc.i + +.PHONY : test6.i + +# target to preprocess a source file +test6.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test6.dir/build.make test/CMakeFiles/test6.dir/test6.cc.i +.PHONY : test6.cc.i + +test6.s: test6.cc.s + +.PHONY : test6.s + +# target to generate assembly for a file +test6.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test6.dir/build.make test/CMakeFiles/test6.dir/test6.cc.s +.PHONY : test6.cc.s + +test7.o: test7.cc.o + +.PHONY : test7.o + +# target to build an object file +test7.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test7.dir/build.make test/CMakeFiles/test7.dir/test7.cc.o +.PHONY : test7.cc.o + +test7.i: test7.cc.i + +.PHONY : test7.i + +# target to preprocess a source file +test7.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test7.dir/build.make test/CMakeFiles/test7.dir/test7.cc.i +.PHONY : test7.cc.i + +test7.s: test7.cc.s + +.PHONY : test7.s + +# target to generate assembly for a file +test7.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test7.dir/build.make test/CMakeFiles/test7.dir/test7.cc.s +.PHONY : test7.cc.s + +test_main.o: test_main.cc.o + +.PHONY : test_main.o + +# target to build an object file +test_main.cc.o: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test_main.dir/build.make test/CMakeFiles/test_main.dir/test_main.cc.o +.PHONY : test_main.cc.o + +test_main.i: test_main.cc.i + +.PHONY : test_main.i + +# target to preprocess a source file +test_main.cc.i: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test_main.dir/build.make test/CMakeFiles/test_main.dir/test_main.cc.i +.PHONY : test_main.cc.i + +test_main.s: test_main.cc.s + +.PHONY : test_main.s + +# target to generate assembly for a file +test_main.cc.s: + cd /home/sascha/git/cpptcl && $(MAKE) -f test/CMakeFiles/test_main.dir/build.make test/CMakeFiles/test_main.dir/test_main.cc.s +.PHONY : test_main.cc.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... install/strip" + @echo "... install/local" + @echo "... test1" + @echo "... test3" + @echo "... test4" + @echo "... test5" + @echo "... test_main" + @echo "... test6" + @echo "... test2" + @echo "... test7" + @echo "... test" + @echo "... edit_cache" + @echo "... rebuild_cache" + @echo "... list_install_components" + @echo "... install" + @echo "... __/cpptcl.o" + @echo "... __/cpptcl.i" + @echo "... __/cpptcl.s" + @echo "... test1.o" + @echo "... test1.i" + @echo "... test1.s" + @echo "... test2.o" + @echo "... test2.i" + @echo "... test2.s" + @echo "... test3.o" + @echo "... test3.i" + @echo "... test3.s" + @echo "... test4.o" + @echo "... test4.i" + @echo "... test4.s" + @echo "... test5.o" + @echo "... test5.i" + @echo "... test5.s" + @echo "... test6.o" + @echo "... test6.i" + @echo "... test6.s" + @echo "... test7.o" + @echo "... test7.i" + @echo "... test7.s" + @echo "... test_main.o" + @echo "... test_main.i" + @echo "... test_main.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /home/sascha/git/cpptcl && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system -test: all - (cd build; ctest) diff --git a/test/test7.cc b/test/test7.cc index 7fe345f..ac902c5 100644 --- a/test/test7.cc +++ b/test/test7.cc @@ -52,7 +52,7 @@ void test1() { i.eval("fun1 1"); assert(false); } catch (tcl_error const &e) { - assert(e.what() == std::string("Usage: Needs a usage message.")); + assert(e.what() == std::string("too few arguments: 1 given, 2 required"));//std::string("Usage: Needs a usage message.")); } }