Index: TODO =================================================================== diff -u -r0595a14ffaf82764ce8bcc642741cd8ded14dc38 -r29ed0c8902296dbea451c12d031cc06b6126dd5b --- TODO (.../TODO) (revision 0595a14ffaf82764ce8bcc642741cd8ded14dc38) +++ TODO (.../TODO) (revision 29ed0c8902296dbea451c12d031cc06b6126dd5b) @@ -3337,6 +3337,12 @@ dispatches are forbidden, ignored in mixins and next; * extended regression test + * fixed name path in unknown called from ensemble + methods (erroneous colon could show up) + * added -system flag to: + - ordinary dispatch (e.g. "o1 -system info vars") + - nsf::object::dispatch with plain methodName + - nsf::my (mutual exclusive with -local) TODO: - private: Index: generic/nsf.c =================================================================== diff -u -r05101e4e8362d0901d36787f88309d945e28fe41 -r29ed0c8902296dbea451c12d031cc06b6126dd5b --- generic/nsf.c (.../nsf.c) (revision 05101e4e8362d0901d36787f88309d945e28fe41) +++ generic/nsf.c (.../nsf.c) (revision 29ed0c8902296dbea451c12d031cc06b6126dd5b) @@ -8885,7 +8885,10 @@ if (self->nsPtr) { cmd = FindMethod(self->nsPtr, methodName); - /*fprintf(stderr, "... method %p %s csc %p\n", cmd, methodName, cscPtr); */ + + /*fprintf(stderr, "... objv[0] %s method %p %s csc %p\n", + ObjStr(objv[0]), cmd, methodName, cscPtr); */ + if (cmd) { /* * In order to allow [next] to be called in an ensemble method, @@ -8901,8 +8904,10 @@ */ /*fprintf(stderr, ".... ensemble dispatch on %s.%s cscPtr %p base flags %.6x cl %s\n", - ObjectName(object), methodName, cscPtr, - (0xFF & cscPtr->flags), cscPtr->cl?ObjStr(cscPtr->cl->object.cmdName):NULL);*/ + ObjectName(object), methodName, cscPtr, + (0xFF & cscPtr->flags), + cscPtr->cl ? ObjStr(cscPtr->cl->object.cmdName) : NULL);*/ + result = MethodDispatch(object, interp, objc-1, objv+1, cmd, object, cscPtr->cl, methodName, cscPtr->frameType|NSF_CSC_TYPE_ENSEMBLE, @@ -8958,12 +8963,13 @@ Tcl_Obj *methodPathObj = CallStackMethodPath(interp, (Tcl_CallFrame *)framePtr); INCR_REF_COUNT(methodPathObj); - /*fprintf(stderr, "next calls DispatchUnknownMethod\n");*/ Tcl_ListObjAppendList(interp, callInfoObj, methodPathObj); - DECR_REF_COUNT(methodPathObj); - Tcl_ListObjAppendElement(interp, callInfoObj, objv[0]); + + Tcl_ListObjAppendElement(interp, callInfoObj, Tcl_NewStringObj(MethodName(objv[0]), -1)); Tcl_ListObjAppendElement(interp, callInfoObj, objv[1]); + DECR_REF_COUNT(methodPathObj); + result = DispatchUnknownMethod(interp, self, objc-1, objv+1, callInfoObj, objv[1], NSF_CM_NO_OBJECT_METHOD|NSF_CSC_IMMEDIATE); } @@ -9037,8 +9043,8 @@ assert (object->teardown); assert (cmd); - /*fprintf(stderr, "MethodDispatch method '%s.%s' objc %d flags %.6x call %d\n", - ObjectName(object), methodName, objc, flags, call); */ + /*fprintf(stderr, "MethodDispatch method '%s.%s' objc %d flags %.6x\n", + ObjectName(object), methodName, objc, flags); */ cscPtr = CscAlloc(interp, &csc, cmd); @@ -9242,8 +9248,11 @@ } } - /*fprintf(stderr, "ObjectDispatch obj = %s objc = %d 0=%s methodName=%s\n", - object ? ObjectName(object) : NULL, objc, cmdObj ? ObjStr(cmdObj) : NULL, methodName);*/ + /*fprintf(stderr, "ObjectDispatch obj = %s objc = %d 0=%s methodName=%s shift %d\n", + object ? ObjectName(object) : NULL, + objc, cmdObj ? ObjStr(cmdObj) : NULL, + methodName, shift);*/ + objflags = object->flags; /* avoid stalling */ /* @@ -12585,8 +12594,6 @@ isLeafNext = (cscPtr != topCscPtr) && (topCscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) && (topCscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) == 0; - /*fprintf(stderr, "--- no cmd, csc %p frameType %.6x callType %.6x endOfFilterChain %d NSF_CSC_CALL_IS_ENSEMBLE %d NSF_CSC_TYPE_ENSEMBLE % d NSF_CSC_CALL_IS_NEXT %d rst->unknown %d isLeafNext %d\n", cscPtr, cscPtr->frameType, cscPtr->flags, endOfFilterChain, (cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) != 0, (cscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) != 0, (cscPtr->flags & NSF_CSC_CALL_IS_NEXT) != 0, rst->unknown, isLeafNext);*/ - rst->unknown = /* case 1 */ endOfFilterChain || /* case 3 */ (!isLeafNext && (cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE)); @@ -17829,13 +17836,15 @@ cmd "object::dispatch" NsfObjectDispatchCmd { {-argName "object" -required 1 -type object} {-argName "-frame" -required 0 -nrargs 1 -type "method|object|default" -default "default"} + {-argName "-system" -required 0 -nrargs 0} {-argName "command" -required 1 -type tclobj} {-argName "args" -type args} } */ static int -NsfObjectDispatchCmd(Tcl_Interp *interp, NsfObject *object, int withFrame, - Tcl_Obj *command, int nobjc, Tcl_Obj *CONST nobjv[]) { +NsfObjectDispatchCmd(Tcl_Interp *interp, NsfObject *object, + int withFrame, int withSystem, + Tcl_Obj *command, int nobjc, Tcl_Obj *CONST nobjv[]) { int result; CONST char *methodName = ObjStr(command); @@ -17913,13 +17922,18 @@ Tcl_Obj *arg; Tcl_Obj *CONST *objv; + int flags = NSF_CM_NO_UNKNOWN|NSF_CSC_IMMEDIATE; if (withFrame && withFrame != FrameDefaultIdx) { return NsfPrintError(interp, "cannot use -frame object|method in dispatch for plain method name '%s'", methodName); } + if (withSystem) { + flags |= NSF_CM_SYSTEM_METHOD; + } + if (nobjc >= 1) { arg = nobjv[0]; objv = nobjv+1; @@ -17928,7 +17942,7 @@ objv = NULL; } result = NsfCallMethodWithArgs(interp, (Nsf_Object *)object, command, arg, - nobjc, objv, NSF_CM_NO_UNKNOWN|NSF_CSC_IMMEDIATE); + nobjc, objv, flags); } return result; @@ -18112,13 +18126,16 @@ /* cmd my NsfMyCmd { - {-argName "-local"} + {-argName "-local" -nrargs 0} + {-argName "-system" -nrargs 0} {-argName "method" -required 1 -type tclobj} {-argName "args" -type args} } */ static int -NsfMyCmd(Tcl_Interp *interp, int withLocal, Tcl_Obj *methodObj, int nobjc, Tcl_Obj *CONST nobjv[]) { +NsfMyCmd(Tcl_Interp *interp, + int withLocal, int withSystem, Tcl_Obj *methodObj, + int nobjc, Tcl_Obj *CONST nobjv[]) { NsfObject *self = GetSelfObj(interp); int result; @@ -18131,6 +18148,11 @@ NsfCallStackContent *cscPtr = CallStackGetTopFrame0(interp); NsfClass *cl = cscPtr ? cscPtr->cl : NULL; Tcl_Command cmd = cl ? FindMethod(cl->nsPtr, methodName) : FindMethod(self->nsPtr, methodName); + + if (withSystem) { + return NsfPrintError(interp, "flags '-local' and '-systemÄ are mutual exclusive"); + } + if (cmd == NULL) { return NsfPrintError(interp, "%s: unable to dispatch local method '%s' in %s %s", ObjectName(self), methodName, @@ -18140,9 +18162,9 @@ result = MethodDispatch(self, interp, nobjc+1, nobjv-1, cmd, self, cl, methodName, 0, NSF_CSC_IMMEDIATE); } else { + int flags; #if 0 /* TODO attempt to make "my" NRE-enabled, failed so far (crash in mixinInheritanceTest) */ - int flags; NsfCallStackContent *cscPtr = CallStackGetTopFrame0(interp); if (!cscPtr || self != cscPtr->self) { flags = NSF_CSC_IMMEDIATE; @@ -18151,8 +18173,11 @@ fprintf(stderr, "XXX MY %s.%s frame has flags %.6x -> next-flags %.6x\n", ObjectName(self), ObjStr(methodObj), cscPtr->flags, flags); } + if (withSystem) {flags |= NSF_CM_SYSTEM_METHOD;} result = CallMethod(self, interp, methodObj, nobjc+2, nobjv, flags); #else + flags = NSF_CSC_IMMEDIATE; + if (withSystem) {flags |= NSF_CM_SYSTEM_METHOD;} result = CallMethod(self, interp, methodObj, nobjc+2, nobjv, NSF_CSC_IMMEDIATE); #endif } Index: generic/nsfAPI.decls =================================================================== diff -u -r0595a14ffaf82764ce8bcc642741cd8ded14dc38 -r29ed0c8902296dbea451c12d031cc06b6126dd5b --- generic/nsfAPI.decls (.../nsfAPI.decls) (revision 0595a14ffaf82764ce8bcc642741cd8ded14dc38) +++ generic/nsfAPI.decls (.../nsfAPI.decls) (revision 29ed0c8902296dbea451c12d031cc06b6126dd5b) @@ -109,10 +109,11 @@ # object cmds # cmd "object::dispatch" NsfObjectDispatchCmd { - {-argName "object" -required 1 -type object} - {-argName "-frame" -required 0 -type "method|object|default" -default "default"} + {-argName "object" -required 1 -type object} + {-argName "-frame" -required 0 -type "method|object|default" -default "default"} + {-argName "-system" -required 0 -nrargs 0} {-argName "command" -required 1 -type tclobj} - {-argName "args" -type args} + {-argName "args" -type args} } cmd "object::exists" NsfObjectExistsCmd { {-argName "value" -required 1 -type tclobj} @@ -136,6 +137,7 @@ cmd my NsfMyCmd { {-argName "-local" -nrargs 0} + {-argName "-system" -nrargs 0} {-argName "methodName" -required 1 -type tclobj} {-argName "args" -type args} } Index: generic/nsfAPI.h =================================================================== diff -u -r0595a14ffaf82764ce8bcc642741cd8ded14dc38 -r29ed0c8902296dbea451c12d031cc06b6126dd5b --- generic/nsfAPI.h (.../nsfAPI.h) (revision 0595a14ffaf82764ce8bcc642741cd8ded14dc38) +++ generic/nsfAPI.h (.../nsfAPI.h) (revision 29ed0c8902296dbea451c12d031cc06b6126dd5b) @@ -345,11 +345,11 @@ static int NsfMethodPropertyCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *methodName, int methodproperty, Tcl_Obj *value); static int NsfMethodRegisteredCmd(Tcl_Interp *interp, Tcl_Obj *handle); static int NsfMethodSetterCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *parameter); -static int NsfMyCmd(Tcl_Interp *interp, int withLocal, Tcl_Obj *methodName, int nobjc, Tcl_Obj *CONST nobjv[]); +static int NsfMyCmd(Tcl_Interp *interp, int withLocal, int withSystem, Tcl_Obj *methodName, int nobjc, Tcl_Obj *CONST nobjv[]); static int NsfNSCopyCmdsCmd(Tcl_Interp *interp, Tcl_Obj *fromNs, Tcl_Obj *toNs); static int NsfNSCopyVarsCmd(Tcl_Interp *interp, Tcl_Obj *fromNs, Tcl_Obj *toNs); static int NsfNextCmd(Tcl_Interp *interp, Tcl_Obj *arguments); -static int NsfObjectDispatchCmd(Tcl_Interp *interp, NsfObject *object, int withFrame, Tcl_Obj *command, int nobjc, Tcl_Obj *CONST nobjv[]); +static int NsfObjectDispatchCmd(Tcl_Interp *interp, NsfObject *object, int withFrame, int withSystem, Tcl_Obj *command, int nobjc, Tcl_Obj *CONST nobjv[]); static int NsfObjectExistsCmd(Tcl_Interp *interp, Tcl_Obj *value); static int NsfObjectPropertyCmd(Tcl_Interp *interp, NsfObject *objectName, int objectproperty); static int NsfObjectQualifyCmd(Tcl_Interp *interp, Tcl_Obj *objectName); @@ -1334,10 +1334,11 @@ return TCL_ERROR; } else { int withLocal = (int )PTR2INT(pc.clientData[0]); - Tcl_Obj *methodName = (Tcl_Obj *)pc.clientData[1]; + int withSystem = (int )PTR2INT(pc.clientData[1]); + Tcl_Obj *methodName = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); - return NsfMyCmd(interp, withLocal, methodName, objc-pc.lastObjc, objv+pc.lastObjc); + return NsfMyCmd(interp, withLocal, withSystem, methodName, objc-pc.lastObjc, objv+pc.lastObjc); } } @@ -1411,10 +1412,11 @@ } else { NsfObject *object = (NsfObject *)pc.clientData[0]; int withFrame = (int )PTR2INT(pc.clientData[1]); - Tcl_Obj *command = (Tcl_Obj *)pc.clientData[2]; + int withSystem = (int )PTR2INT(pc.clientData[2]); + Tcl_Obj *command = (Tcl_Obj *)pc.clientData[3]; assert(pc.status == 0); - return NsfObjectDispatchCmd(interp, object, withFrame, command, objc-pc.lastObjc, objv+pc.lastObjc); + return NsfObjectDispatchCmd(interp, object, withFrame, withSystem, command, objc-pc.lastObjc, objv+pc.lastObjc); } } @@ -2522,8 +2524,9 @@ {"-per-object", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"parameter", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, -{"::nsf::my", NsfMyCmdStub, 3, { +{"::nsf::my", NsfMyCmdStub, 4, { {"-local", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"-system", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"methodName", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, @@ -2538,9 +2541,10 @@ {"::nsf::next", NsfNextCmdStub, 1, { {"arguments", 0, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, -{"::nsf::object::dispatch", NsfObjectDispatchCmdStub, 4, { +{"::nsf::object::dispatch", NsfObjectDispatchCmdStub, 5, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertToObject, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-frame", 0|NSF_ARG_IS_ENUMERATION, 1, ConvertToFrame, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"-system", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"command", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, Index: library/nx/nx.tcl =================================================================== diff -u -r0595a14ffaf82764ce8bcc642741cd8ded14dc38 -r29ed0c8902296dbea451c12d031cc06b6126dd5b --- library/nx/nx.tcl (.../nx.tcl) (revision 0595a14ffaf82764ce8bcc642741cd8ded14dc38) +++ library/nx/nx.tcl (.../nx.tcl) (revision 29ed0c8902296dbea451c12d031cc06b6126dd5b) @@ -479,12 +479,13 @@ set path [lrange $callInfo 1 end-1]; # set path [current methodpath] set m [lindex $callInfo end] set obj [lindex $callInfo 0] - # puts stderr "+++ UNKNOWN ARGS=[current args] obj $obj '$m' callInfo=$callInfo args=$args // path '[current methodpath]'" + #puts stderr "### [list $obj ::nsf::methods::object::info::lookupmethods -path \"$path *\"]" if {[catch {set valid [$obj ::nsf::methods::object::info::lookupmethods -path "$path *"]} errorMsg]} { set valid "" puts stderr "+++ UNKNOWN raises error $errorMsg" } set ref "\"$m\" of $obj $path" +puts stderr "***VALID <[lsort $valid]>" error "Unable to dispatch sub-method $ref; valid are: [join [lsort $valid] {, }]" } Index: tests/info-method.test =================================================================== diff -u -r1d1a1be1636a5b6f9ad6e3b5df2a6aa7170b62f0 -r29ed0c8902296dbea451c12d031cc06b6126dd5b --- tests/info-method.test (.../info-method.test) (revision 1d1a1be1636a5b6f9ad6e3b5df2a6aa7170b62f0) +++ tests/info-method.test (.../info-method.test) (revision 29ed0c8902296dbea451c12d031cc06b6126dd5b) @@ -124,8 +124,8 @@ ? {::nx::Object info lookup methods -source application} "" ? {::nx::Class info lookup methods -source application} "" - set object_methods "alias configure contains copy delete destroy eval filter forward info method mixin move property protected public require variable volatile" - set class_methods "alias class configure contains copy create delete destroy eval filter forward info method mixin move new property protected public require variable volatile" + set object_methods "alias configure contains copy delete destroy eval filter forward info method mixin move private property protected public require variable volatile" + set class_methods "alias class configure contains copy create delete destroy eval filter forward info method mixin move new private property protected public require variable volatile" ? {lsort [::nx::Object info lookup methods -source baseclasses]} $class_methods ? {lsort [::nx::Class info lookup methods -source baseclasses]} $class_methods Index: tests/protected.test =================================================================== diff -u -r0595a14ffaf82764ce8bcc642741cd8ded14dc38 -r29ed0c8902296dbea451c12d031cc06b6126dd5b --- tests/protected.test (.../protected.test) (revision 0595a14ffaf82764ce8bcc642741cd8ded14dc38) +++ tests/protected.test (.../protected.test) (revision 29ed0c8902296dbea451c12d031cc06b6126dd5b) @@ -211,3 +211,50 @@ ? {s1 foo 3 4} 7 ? {s1 bar 3 4} 12 } + +# +# Test -system flag on dispatch with explicit receiver +# +nx::Test case system-flag { + + # + # create an object, which overloads some system behavior + # + nx::Object create o1 { + :public method info {} {return "overloads system info"} + :public method destroy {} {return "overloads system destroy"} + :variable v 1 + } + + ? {o1 info} "overloads system info" + ? {o1 ::nx::Object::slot::__info::vars} "v" + ? {o1 [nx::Object info method origin "info vars"]} "v" + ? {o1 -system info vars} "v" + ? {nsf::object::dispatch o1 -system info vars} "v" + + ? {o1 destroy} "overloads system destroy" + ? {nsf::object::exists o1} 1 + ? {o1 -system destroy} "" + ? {nsf::object::exists o1} 0 + + # + # create a class, which overloads some system behavior + # + nx::Class create C { + :public method info {} {return "overloads system info"} + :public method destroy {} {return "overloads system destroy"} + :variable v 1 + :create c1 + } + + ? {c1 info} "overloads system info" + ? {c1 ::nx::Object::slot::__info::vars} "v" + ? {c1 [nx::Object info method origin "info vars"]} "v" + ? {c1 -system info vars} "v" + ? {nsf::object::dispatch c1 -system info vars} "v" + + ? {c1 destroy} "overloads system destroy" + ? {nsf::object::exists c1} 1 + ? {c1 -system destroy} "" + ? {nsf::object::exists c1} 0 +} \ No newline at end of file