Index: TODO =================================================================== diff -u -r2b56284a45054d5136ddfb67343a70655aba5666 -rba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd --- TODO (.../TODO) (revision 2b56284a45054d5136ddfb67343a70655aba5666) +++ TODO (.../TODO) (revision ba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd) @@ -4072,17 +4072,33 @@ - extended nsf::method::delete to handle ensemble names nx.tcl: -- added tk/incr-tcl style cget methods on class/object levels. +- added tk/incr-tcl style cget methods on class/object levels as + ensemble methods. - improve copy handling with other child-types of the slot container working - make sure to ignore non-slot-type objects in slot introspection - worked on regression test until "methods.test". others are missing, but maybe reconsideration + +nsf.c: +- implememted cget as a configure-like method, dropped ensemble method variant + +nx.tcl: +- simplified "/obj|cls/ delete method" due to resolving capabilities in + nsf::delete::method + +xotcl2.tcl: +- made destructor of Connection more robust such it does not depend on + accessor methods. + +- fixed regression test to run all test again correctly ======================================================================== TODO: -- maybe revise class/object level cgets by implementing a global method +- handling of "-cget" without methods +- register cget per default in nx +- use cget per default instead of accessor methods +- default menchanism for accessor methods -- check for potential simplications in scripts for nsf::method::delete - handling of method names in error messages from nsfAPI.h. The following ? {o __alloc x} {method __alloc not dispatched on valid class} should be Index: generic/nsf.c =================================================================== diff -u -r2b56284a45054d5136ddfb67343a70655aba5666 -rba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd --- generic/nsf.c (.../nsf.c) (revision 2b56284a45054d5136ddfb67343a70655aba5666) +++ generic/nsf.c (.../nsf.c) (revision ba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd) @@ -22013,6 +22013,121 @@ } /* +objectMethod cget NsfOCgetMethod { + {-argName "name" -type tclobj} +} +*/ +static int +NsfOCgetMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *nameObj) { + int result, i, found = 0; + NsfParsedParam parsedParam; + Nsf_Param *paramPtr; + NsfParamDefs *paramDefs; + CallFrame frame, *framePtr = &frame, *uplevelVarFramePtr; + char *nameString = ObjStr(nameObj); + + /* + * Get the object parameter definition + */ + result = GetObjectParameterDefinition(interp, NsfGlobalObjs[NSF_EMPTY], + object->cl, &parsedParam); + if (unlikely(result != TCL_OK)) { + return result; + } + + /* + * The uplevel handling is exactly the same as in NsfOConfigureMethod() and + * is needed, when methods are called, which perform an upvar. + */ + uplevelVarFramePtr = + (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp) != Tcl_Interp_framePtr(interp) + ? Tcl_Interp_varFramePtr(interp) + : NULL; + + /* + * Push frame to allow invocations of [self] and make instance variables of + * obj accessible as locals. + */ + Nsf_PushFrameObj(interp, object, framePtr); + + paramDefs = parsedParam.paramDefs; + ParamDefsRefCountIncr(paramDefs); + + /* + * Iterate over the parameter definitions to lookup the desired parameter + */ + for (i = 1, paramPtr = paramDefs->paramsPtr; paramPtr->name; paramPtr++, i++) { + if (*paramPtr->name != '-') continue; + if (strcmp(nameString, paramPtr->name) == 0) { + found = 1; + break; + } + } + + /* + * The parameter is linked to a method via + * "initcmd", "alias" and "forward". + */ + if (paramPtr->flags & NSF_ARG_METHOD_INVOCATION) { + // TODO: just for the time being + fprintf(stderr, "method arg %s found, flags %.8x slot %p\n", nameString, paramPtr->flags, paramPtr->slotObj); + found = 0; + } + + if (!found) { + result = NsfPrintError(interp, "cannot lookup parameter value for %s", nameString); + } else { + + //fprintf(stderr, "arg %s found, flags %.8x\n", nameString, paramPtr->flags); + + if (paramPtr->slotObj) { + NsfObject *slotObject = GetSlotObject(interp, paramPtr->slotObj); + /* + * Actually get instance variable or slot value + * In case, explicit slot invocation is needed, we call it. + */ + + if (likely(slotObject != NULL)) { + Tcl_Obj *ov[1]; + + if (uplevelVarFramePtr) { + Tcl_Interp_varFramePtr(interp) = uplevelVarFramePtr; + } + + ov[0] = paramPtr->nameObj; + result = NsfCallMethodWithArgs(interp, (Nsf_Object *)slotObject, NsfGlobalObjs[NSF_GET], + object->cmdName, 2, ov, NSF_CSC_IMMEDIATE); + } else { + fprintf(stderr, "strange, no slotobj\n"); + } + if (result != TCL_OK) { + /* + * The error message was set either by GetSlotObject or by ...CallMethod... + */ + Nsf_PopFrameObj(interp, framePtr); + goto cget_exit; + } + } else { + int flags = (object->nsPtr) ? TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY : TCL_LEAVE_ERR_MSG; + Tcl_Obj *resutObj = Tcl_ObjGetVar2(interp, paramPtr->nameObj, NULL, flags); + if (resutObj) { + /* + * The value exists + */ + Tcl_SetObjResult(interp, resutObj); + } + } + } + + Nsf_PopFrameObj(interp, framePtr); + + cget_exit: + + ParamDefsRefCountDecr(paramDefs); + return result; +} + +/* objectMethod destroy NsfODestroyMethod { } */ Index: generic/nsfAPI.decls =================================================================== diff -u -r7495af656ca04a32826ecb0b6e207f886eaaa7f8 -rba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd --- generic/nsfAPI.decls (.../nsfAPI.decls) (revision 7495af656ca04a32826ecb0b6e207f886eaaa7f8) +++ generic/nsfAPI.decls (.../nsfAPI.decls) (revision ba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd) @@ -245,6 +245,10 @@ objectMethod cleanup NsfOCleanupMethod { } +objectMethod cget NsfOCgetMethod { + {-argName "name" -type tclobj} +} + objectMethod configure NsfOConfigureMethod { {-argName "args" -type allargs} } Index: generic/nsfAPI.h =================================================================== diff -u -r9dadb4297ee2e6b648f14674b79f8ef678fbb8fb -rba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd --- generic/nsfAPI.h (.../nsfAPI.h) (revision 9dadb4297ee2e6b648f14674b79f8ef678fbb8fb) +++ generic/nsfAPI.h (.../nsfAPI.h) (revision ba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd) @@ -222,7 +222,7 @@ /* just to define the symbol */ -static Nsf_methodDefinition method_definitions[101]; +static Nsf_methodDefinition method_definitions[102]; static CONST char *method_command_namespace_names[] = { "::nsf::methods::object::info", @@ -294,6 +294,7 @@ static int NsfVarSetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfVarUnsetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfOAutonameMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfOCgetMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfOClassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfOCleanupMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfOConfigureMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); @@ -395,6 +396,7 @@ static int NsfVarSetCmd(Tcl_Interp *interp, int withArray, NsfObject *object, Tcl_Obj *varName, Tcl_Obj *value); static int NsfVarUnsetCmd(Tcl_Interp *interp, int withNocomplain, NsfObject *object, Tcl_Obj *varName); static int NsfOAutonameMethod(Tcl_Interp *interp, NsfObject *obj, int withInstance, int withReset, Tcl_Obj *name); +static int NsfOCgetMethod(Tcl_Interp *interp, NsfObject *obj, Tcl_Obj *name); static int NsfOClassMethod(Tcl_Interp *interp, NsfObject *obj, Tcl_Obj *class); static int NsfOCleanupMethod(Tcl_Interp *interp, NsfObject *obj); static int NsfOConfigureMethod(Tcl_Interp *interp, NsfObject *obj, int objc, Tcl_Obj *CONST objv[]); @@ -497,6 +499,7 @@ NsfVarSetCmdIdx, NsfVarUnsetCmdIdx, NsfOAutonameMethodIdx, + NsfOCgetMethodIdx, NsfOClassMethodIdx, NsfOCleanupMethodIdx, NsfOConfigureMethodIdx, @@ -1848,6 +1851,22 @@ } static int +NsfOCgetMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + NsfObject *obj = (NsfObject *)clientData; + if (unlikely(obj == NULL)) return NsfDispatchClientDataError(interp, clientData, "object", "cget"); + + + if (objc < 1 || objc > 2) { + return NsfArgumentError(interp, "wrong # of arguments:", + method_definitions[NsfOCgetMethodIdx].paramDefs, + NULL, objv[0]); + } + + return NsfOCgetMethod(interp, obj, objc == 2 ? objv[1] : NULL); + +} + +static int NsfOClassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { NsfObject *obj = (NsfObject *)clientData; if (unlikely(obj == NULL)) return NsfDispatchClientDataError(interp, clientData, "object", "class"); @@ -2489,7 +2508,7 @@ } } -static Nsf_methodDefinition method_definitions[101] = { +static Nsf_methodDefinition method_definitions[102] = { {"::nsf::methods::class::alloc", NsfCAllocMethodStub, 1, { {"objectName", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, @@ -2784,6 +2803,9 @@ {"-reset", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"name", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, +{"::nsf::methods::object::cget", NsfOCgetMethodStub, 1, { + {"name", 0, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, {"::nsf::methods::object::class", NsfOClassMethodStub, 1, { {"class", 0, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, Index: generic/nsfAPI.nxdocindex =================================================================== diff -u -r7a3ce03f8d70724a621e75469908f0d3aa57ba3e -rba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd --- generic/nsfAPI.nxdocindex (.../nsfAPI.nxdocindex) (revision 7a3ce03f8d70724a621e75469908f0d3aa57ba3e) +++ generic/nsfAPI.nxdocindex (.../nsfAPI.nxdocindex) (revision ba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd) @@ -42,6 +42,7 @@ set ::nxdoc::include(::nsf::methods::object::autoname) 0 set ::nxdoc::include(::nsf::methods::object::class) 0 set ::nxdoc::include(::nsf::methods::object::cleanup) 0 +set ::nxdoc::include(::nsf::methods::object::cget) 0 set ::nxdoc::include(::nsf::methods::object::configure) 0 set ::nxdoc::include(::nsf::methods::object::destroy) 0 set ::nxdoc::include(::nsf::methods::object::exists) 0 Index: library/nx/nx.tcl =================================================================== diff -u -r2b56284a45054d5136ddfb67343a70655aba5666 -rba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd --- library/nx/nx.tcl (.../nx.tcl) (revision 2b56284a45054d5136ddfb67343a70655aba5666) +++ library/nx/nx.tcl (.../nx.tcl) (revision ba42e7d2b911f631d2bd104eb2e22a9da6f7e1bd) @@ -557,8 +557,7 @@ } } Object public method "delete method" {name} { - array set "" [:__resolve_method_path -per-object $name] - ::nsf::method::delete $(object) -per-object $(methodName) + ::nsf::method::delete [self] -per-object $name } Class public method "delete property" {name} { @@ -568,8 +567,7 @@ } Class public alias "delete variable" ::nx::Class::slot::__delete::property Class public method "delete method" {name} { - array set "" [:__resolve_method_path $name] - ::nsf::method::delete $(object) $(methodName) + ::nsf::method::delete [self] $name } # @@ -1178,26 +1176,12 @@ # # delete the accessors # - set cgetName "cget -${:name}" if {${:per-object}} { if {[${:domain} ::nsf::methods::object::info::method exists ${:name}]} { ::nsf::method::delete ${:domain} -per-object ${:name} } - if {[${:domain} ::nsf::methods::object::info::method exists ${cgetName}]} { - nsf::method::delete ${:domain} -per-object ${cgetName} - # TODO cleanup - #puts stderr "nsf::method::delete ${:domain} -per-object ${cgetName}" - #puts stderr o-still=[${:domain} ::nsf::methods::object::info::method exists ${cgetName}] - } - } else { - #array set "" [${:domain} eval [list :__resolve_method_path $cgetName]] - if {[${:domain} ::nsf::methods::class::info::method exists ${:name}]} { - ::nsf::method::delete ${:domain} ${:name} - } - if {[${:domain} ::nsf::methods::class::info::method exists ${cgetName}]} { - nsf::method::delete ${:domain} ${cgetName} - #puts stderr c-still=[${:domain} ::nsf::methods::class::info::method exists ${cgetName}] - } + } elseif {[${:domain} ::nsf::methods::class::info::method exists ${:name}]} { + ::nsf::method::delete ${:domain} ${:name} } } ::nsf::next @@ -1621,8 +1605,11 @@ } } } elseif {[:info lookup method assign] ne "::nsf::classes::nx::VariableSlot::assign"} { - # In case the "assign method" was provided, ask nsf to call it directly + # In case the "assign" method was provided on the slot, ask nsf to call it directly lappend options slot=[::nsf::self] slotassign + } elseif {[:info lookup method get] ne "::nsf::classes::nx::VariableSlot::get"} { + # In case the "get" method was provided on the slot, ask nsf to call it directly + lappend options slot=[::nsf::self] } if {[:info lookup method initialize] ne "" && $forObjectParameter} { if {"slot=[::nsf::self]" ni $options} {lappend options slot=[::nsf::self]} @@ -1671,23 +1658,12 @@ } ::nx::VariableSlot public method makeAccessor {} { - set needsForwarder [:needsForwarder] - if {$needsForwarder} { - set body "{[self]} get \[self\] ${:name}" - } else { - set body "return \${:${:name}}" - } - ${:domain} public \ - [expr {${:per-object} ? "::nsf::classes::nx::Object::method" : "::nsf::classes::nx::Class::method"}] \ - "cget -${:name}" \ - {} $body - if {!${:accessor}} { #puts stderr "Do not register forwarder ${:domain} ${:name}" return 0 } - if {$needsForwarder} { + if {[:needsForwarder]} { set handle [:makeForwarder] :makeIncrementalOperations } else { @@ -1727,15 +1703,20 @@ ::nx::VariableSlot protected method makeIncrementalOperations {} { set options_single [:getParameterOptions] - if {[llength $options_single] == 0} { + #if {[llength $options_single] == 0} {} + if {![info exists :type]} { # No need to make per-slot methods; the general rules on # nx::VariableSlot are sufficient return } + #puts "makeIncrementalOperations -- $options_single // [:info vars]" + #if {[info exists :type]} {puts ".... type ${:type}"} set options [:getParameterOptions -withMultiplicity true] lappend options slot=[::nsf::self] set body {::nsf::var::set $obj $var $value} + # We need the following rule e.g. for private properties, where + # the setting of the property is handled via slot. if {[:info lookup method assign] eq "::nsf::classes::nx::VariableSlot::assign"} { #puts stderr ":public method assign [list obj var [:namedParameterSpec {} value $options]] $body" :public method assign [list obj var [:namedParameterSpec {} value $options]] $body