Index: generic/gentclAPI.decls =================================================================== diff -u -r2ce14fba0764a9fcbbe7cc2f582472526a58ddf0 -re12f842804807d9b0e849858697d94a57c6b3fe6 --- generic/gentclAPI.decls (.../gentclAPI.decls) (revision 2ce14fba0764a9fcbbe7cc2f582472526a58ddf0) +++ generic/gentclAPI.decls (.../gentclAPI.decls) (revision e12f842804807d9b0e849858697d94a57c6b3fe6) @@ -38,8 +38,8 @@ } xotclCmd dispatch XOTclDispatchCmd { {-argName "object" -required 1 -type object} - {-argName "methodName" -required 1} {-argName "-objscope"} + {-argName "command" -required 1 -type tclobj} {-argName "args" -type args} } xotclCmd finalize XOTclFinalizeObjCmd { Index: generic/tclAPI.h =================================================================== diff -u -r2ce14fba0764a9fcbbe7cc2f582472526a58ddf0 -re12f842804807d9b0e849858697d94a57c6b3fe6 --- generic/tclAPI.h (.../tclAPI.h) (revision 2ce14fba0764a9fcbbe7cc2f582472526a58ddf0) +++ generic/tclAPI.h (.../tclAPI.h) (revision e12f842804807d9b0e849858697d94a57c6b3fe6) @@ -234,7 +234,7 @@ static int XOTclConfigureCmd(Tcl_Interp *interp, int configureoption, Tcl_Obj *value); static int XOTclCreateObjectSystemCmd(Tcl_Interp *interp, char *rootClass, char *rootMetaClass); static int XOTclDeprecatedCmd(Tcl_Interp *interp, char *oldCmd, char *newCmd); -static int XOTclDispatchCmd(Tcl_Interp *interp, XOTclObject *object, char *methodName, int withObjscope, int nobjc, Tcl_Obj *CONST nobjv[]); +static int XOTclDispatchCmd(Tcl_Interp *interp, XOTclObject *object, int withObjscope, Tcl_Obj *command, int nobjc, Tcl_Obj *CONST nobjv[]); static int XOTclFinalizeObjCmd(Tcl_Interp *interp); static int XOTclInstvarCmd(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int XOTclMethodPropertyCmd(Tcl_Interp *interp, XOTclObject *object, char *methodName, int withPer_object, int methodproperty, Tcl_Obj *value); @@ -2184,11 +2184,11 @@ return TCL_ERROR; } else { XOTclObject *object = (XOTclObject *)pc.clientData[0]; - char *methodName = (char *)pc.clientData[1]; - int withObjscope = (int )pc.clientData[2]; + int withObjscope = (int )pc.clientData[1]; + Tcl_Obj *command = (Tcl_Obj *)pc.clientData[2]; parseContextRelease(&pc); - return XOTclDispatchCmd(interp, object, methodName, withObjscope, objc-pc.lastobjc, objv+pc.lastobjc); + return XOTclDispatchCmd(interp, object, withObjscope, command, objc-pc.lastobjc, objv+pc.lastobjc); } } @@ -2685,8 +2685,8 @@ }, {"::xotcl::dispatch", XOTclDispatchCmdStub, 4, { {"object", 1, 0, convertToObject}, - {"methodName", 1, 0, convertToString}, {"-objscope", 0, 0, convertToString}, + {"command", 1, 0, convertToTclobj}, {"args", 0, 0, convertToNothing}} }, {"::xotcl::finalize", XOTclFinalizeObjCmdStub, 0, { Index: generic/xotcl.c =================================================================== diff -u -r590b606a40220ba451e16d87387255b096ce5b71 -re12f842804807d9b0e849858697d94a57c6b3fe6 --- generic/xotcl.c (.../xotcl.c) (revision 590b606a40220ba451e16d87387255b096ce5b71) +++ generic/xotcl.c (.../xotcl.c) (revision e12f842804807d9b0e849858697d94a57c6b3fe6) @@ -8646,20 +8646,21 @@ } static int -XOTclDispatchCmd(Tcl_Interp *interp, XOTclObject *object, char *methodName, - int withObjscope, int nobjc, Tcl_Obj *CONST nobjv[]) { +XOTclDispatchCmd(Tcl_Interp *interp, XOTclObject *object, int withObjscope, + Tcl_Obj *command, int nobjc, Tcl_Obj *CONST nobjv[]) { int result; + char *methodName = ObjStr(command); register char *n = methodName + strlen(methodName); - /* TODO: test, handle withObjScope */ + /* fprintf(stderr, "Dispatch obj=%s, o=%p cmd m='%s'\n",objectName(object),object,methodName);*/ - /*fprintf(stderr, "Dispatch obj=%s, o=%p cmd m='%s'\n",ObjStr(objv[2]),obj,method);*/ + /* + * If the specified method is a fully qualified cmd name like + * e.g. ::xotcl::cmd::Class::alloc, this method is called on the + * specified , no matter whether it was registered on + * it. + */ - /* if the specified method is a fully qualified cmd name like e.g. - ::xotcl::cmd::Class::alloc, this method is called on the - specified , no matter whether it was registered on - it */ - /*search for last '::'*/ while ((*n != ':' || *(n-1) != ':') && n-1 > methodName) {n--; } if (*n == ':' && n > methodName && *(n-1) == ':') {n--;} @@ -8671,6 +8672,14 @@ char *parentName, *tail = n+2; DSTRING_INIT(dsp); + /* + * We have an absolute name. We assume, the name is the name of a + * tcl command, that will be dispatched. If "withObjscope is + * specified, a callstack frame is pushed to make instvars + * accessible for the command. + */ + + /*fprintf(stderr, "colon name %s\n",tail);*/ if (n-methodName != 0) { Tcl_DStringAppend(dsp, methodName, (n-methodName)); parentName = Tcl_DStringValue(dsp); @@ -8683,40 +8692,54 @@ return XOTclVarErrMsg(interp, "cannot lookup parent namespace '", methodName, "'", (char *) NULL); } - fprintf(stderr, " .... findmethod '%s' in %s\n",tail, nsPtr->fullName); cmd = FindMethod(nsPtr, tail); if (cmd && (importedCmd = TclGetOriginalCommand(cmd))) { cmd = importedCmd; } + /*fprintf(stderr, " .... findmethod '%s' in %s returns %p\n",tail, nsPtr->fullName, cmd);*/ if (cmd == NULL) { return XOTclVarErrMsg(interp, "cannot lookup command '", tail, "'", (char *) NULL); } + {XOTcl_FrameDecls; - result = InvokeMethod((ClientData)object, interp, - nobjc, nobjv, cmd, object, - NULL /*XOTclClass *cl*/, tail, - XOTCL_CSC_TYPE_PLAIN); + if (withObjscope) { + XOTcl_PushFrame(interp, object); + } + /* + * Since we know, that we are always called with a full argument + * vector, we can include the cmd name in the objv by using + * nobjv-1; this way, we avoid a memcpy() + */ + result = InvokeMethod((ClientData)object, interp, + nobjc+1, nobjv-1, cmd, object, + NULL /*XOTclClass *cl*/, tail, + XOTCL_CSC_TYPE_PLAIN); + if (withObjscope) { + XOTcl_PopFrame(interp, object); + } + } } else { - /* no colons, use method from dispatch order, with filters etc. - - strictly speaking unneccessary, but can be used to invoke protected methods */ - - /* TODO: adjust objv, objc, wont't be correct after switch to parameter interface */ - int objc; + /* + * No colons in command name, use method from the precedence + * order, with filters etc. -- strictly speaking unneccessary, + * since we could dispatch the method also without + * XOTclDispatchCmd(), but it can be used to invoke protected + * methods. 'withObjscope' is here a no-op. + */ Tcl_Obj *arg; Tcl_Obj *CONST *objv; - if (nobjc >= 3) { - arg = nobjv[3]; - objv = nobjv + 2; + if (nobjc >= 1) { + arg = nobjv[0]; + objv = nobjv+1; } else { arg = NULL; objv = NULL; } - objc = nobjc-3; - result = XOTclCallMethodWithArgs((ClientData)object, interp, nobjv[1], arg, - objc, objv, XOTCL_CM_NO_UNKNOWN); + result = XOTclCallMethodWithArgs((ClientData)object, interp, command, arg, + nobjc, objv, XOTCL_CM_NO_UNKNOWN); } return result; } Index: tests/object-system.xotcl =================================================================== diff -u -r8d4f0d69f9586bdafbffa45b0368b84b86169bca -re12f842804807d9b0e849858697d94a57c6b3fe6 --- tests/object-system.xotcl (.../object-system.xotcl) (revision 8d4f0d69f9586bdafbffa45b0368b84b86169bca) +++ tests/object-system.xotcl (.../object-system.xotcl) (revision e12f842804807d9b0e849858697d94a57c6b3fe6) @@ -7,14 +7,14 @@ # since even class Test might not work at that time. # proc ? {cmd expected {msg ""}} { - puts "??? $cmd" + #puts "??? $cmd" set r [uplevel $cmd] if {$msg eq ""} {set msg $cmd} if {$r ne $expected} { - puts stderr "$msg returned '$r' ne '$expected'" + puts stderr "ERROR $msg returned '$r' ne '$expected'" exit } else { - puts -nonewline stderr "." + puts stderr "OK $msg" } } @@ -91,6 +91,29 @@ ? {X::slot info vars} __parameter ? {X info parameter} {{x 1} {y 2}} -puts stderr "DONE" -#puts stderr ===EXIT +# +# tests for the dispatch command + +Object o +o proc foo {} {return goo} +o proc bar {x} {return goo-$x} + +# dispatch without colon names +::xotcl::dispatch o set x 1 +? {o info vars} x "simple dispatch has set variable x" +? {o set x} 1 "simple dispatch has set variable x to 1" +? {::xotcl::dispatch o foo} "goo" "simple dispatch with one arg works" +? {::xotcl::dispatch o bar 1} "goo-1" "simple dispatch with two args works" +o destroy + +# dispatch without colon names +Object o -set x 1 +::xotcl::dispatch ::o ::incr x +? {o set x} 1 "cmd dispatch without -objscope did not modify the instance variable" +::xotcl::dispatch ::o -objscope ::incr x +? {o set x} 2 "cmd dispatch -objscope modifies the instance variable" +? {catch {::xotcl::dispatch ::o -objscope ::xxx x}} 1 "cmd dispatch with unknown command" +o destroy + +puts stderr ===EXIT