Index: TODO =================================================================== diff -u -r877c1e7d364b91e0a1d501738dfbb7b9dcb7d5ac -re52f2dd0f35e8a12230a20e90575f242da4e0e5c --- TODO (.../TODO) (revision 877c1e7d364b91e0a1d501738dfbb7b9dcb7d5ac) +++ TODO (.../TODO) (revision e52f2dd0f35e8a12230a20e90575f242da4e0e5c) @@ -3561,14 +3561,23 @@ - provide selective error messages for unknown nonpos args nsf.c: - - reform of method obj lookup. new code uses + - reform of method lookup. new code uses NsfInstanceMethodObjType and NsfObjectMethodObjType to reuse earlier lookup results. Improved speed for for methods with primitive bodies (over version before argument parse reform: 10%-43%. - additional compile-time option: METHOD_OBJECT_TRACE + - experimentation version of unknown handler for non-pos args + - extending regression test + + TODO: + - unknown arg handler must find a way to aviod method deletions or redefinitions + or to recover from these gracefully + - methodEpoch should go into interp state. + - cleanup yyyy + - warnings for "numeric" names for args and nonpos-args? - NsfUnexpectedNonposArgumentError() for valueInArgument, when structure settles - ouput of noleadingdash in introspection - ouput of noleadingdash in objectParameterSlots Index: generic/nsf.c =================================================================== diff -u -r877c1e7d364b91e0a1d501738dfbb7b9dcb7d5ac -re52f2dd0f35e8a12230a20e90575f242da4e0e5c --- generic/nsf.c (.../nsf.c) (revision 877c1e7d364b91e0a1d501738dfbb7b9dcb7d5ac) +++ generic/nsf.c (.../nsf.c) (revision e52f2dd0f35e8a12230a20e90575f242da4e0e5c) @@ -619,6 +619,7 @@ */ if (pcPtr->full_objv == &pcPtr->objv_static[0] && pcPtr->objc > 0) { for (i = pcPtr->objc - 1; i < PARSE_CONTEXT_PREALLOC; i++) { + //fprintf(stderr, "later flag %d: %.6x\n",i, pcPtr->flags[i]); assert(pcPtr->flags[i] == 0 || pcPtr->flags[i] == NSF_PC_IS_DEFAULT); } } @@ -1245,7 +1246,7 @@ /* *---------------------------------------------------------------------- - * NsfCallUnknownHandler -- + * NsfCallObjectUnknownHandler -- * * Call ::nsf::object::unknown; this function is typically called, when an unknown * object or class is passed as an argument. @@ -1260,13 +1261,13 @@ */ static int -NsfCallUnknownHandler(Tcl_Interp *interp, Tcl_Obj *nameObj) { +NsfCallObjectUnknownHandler(Tcl_Interp *interp, Tcl_Obj *nameObj) { int result = 0; Tcl_Obj *ov[3]; /*fprintf(stderr, "try ::nsf::object::unknown for '%s'\n", ObjStr(nameObj));*/ - ov[0] = NsfGlobalObjs[NSF_UNKNOWN_HANDLER]; + ov[0] = NsfGlobalObjs[NSF_OBJECT_UNKNOWN_HANDLER]; ov[1] = nameObj; INCR_REF_COUNT(ov[1]); @@ -1276,6 +1277,33 @@ return result; } +static int +NsfCallArgumentUnknownHandler(Tcl_Interp *interp, + Tcl_Obj *methodObj, + Tcl_Obj *argumentObj, + NsfObject *object) { + + Tcl_Obj *ov[4]; + int result, oc = 3; + + // yyyy + /*fprintf(stderr, "try ::nsf::argument::unknown for '%s'\n", ObjStr(nameObj));*/ + + ov[0] = NsfGlobalObjs[NSF_ARGUMENT_UNKNOWN_HANDLER]; + ov[1] = methodObj; + ov[2] = argumentObj; + if (object) { + ov[3] = object->cmdName; + oc ++; + } + + INCR_REF_COUNT(ov[1]); + result = Tcl_EvalObjv(interp, oc, ov, 0); + DECR_REF_COUNT(ov[1]); + + return result; +} + /* *---------------------------------------------------------------------- * GetClassFromObj -- @@ -1367,10 +1395,10 @@ } if (withUnknown) { - result = NsfCallUnknownHandler(interp, isAbsolutePath(objName) ? objPtr : - NameInNamespaceObj(interp, - objName, - CallingNameSpace(interp))); + result = NsfCallObjectUnknownHandler(interp, isAbsolutePath(objName) ? objPtr : + NameInNamespaceObj(interp, + objName, + CallingNameSpace(interp))); if (result == TCL_OK) { /* Retry, but now, the last argument (withUnknown) has to be 0 */ @@ -4228,7 +4256,7 @@ NSRequireParentObject(Tcl_Interp *interp, CONST char *parentName) { int result; - result = NsfCallUnknownHandler(interp, Tcl_NewStringObj(parentName, -1)); + result = NsfCallObjectUnknownHandler(interp, Tcl_NewStringObj(parentName, -1)); if (result == TCL_OK) { NsfObject *parentObj = (NsfObject *) GetObjectFromString(interp, parentName); @@ -15947,6 +15975,22 @@ nextParamPtr, nextParamPtr->name);*/ if (nextParamPtr > lastParamPtr || (nextParamPtr->flags & NSF_ARG_NOLEADINGDASH)) { + /// yyyy work in progress + int result, refcountBefore = procNameObj->refCount; + /*fprintf(stderr, "### refcount of %s before -> %d objc %d\n", + ObjStr(procNameObj), procNameObj->refCount, pcPtr->objc);*/ + result = NsfCallArgumentUnknownHandler(interp, + procNameObj, + argumentObj, + object); + /*fprintf(stderr, "### refcount of %s after -> %d\n", + ObjStr(procNameObj), procNameObj->refCount);*/ + if (procNameObj->refCount != refcountBefore) { + pcPtr->objc = nrParams ; + /*fprintf(stderr, "trigger error pcPtr->objc %d\n", pcPtr->objc);*/ + return NsfPrintError(interp, "Unknown handler for '%s' must not alter definition", + ObjStr(argumentObj)); + } return NsfUnexpectedNonposArgumentError(interp, argumentString, (Nsf_Object *)object, currentParamPtr, paramPtr, Index: generic/nsf.tcl =================================================================== diff -u -r8046b1da6bc0689f73d4dbdc3f8d1e03fd23acaf -re52f2dd0f35e8a12230a20e90575f242da4e0e5c --- generic/nsf.tcl (.../nsf.tcl) (revision 8046b1da6bc0689f73d4dbdc3f8d1e03fd23acaf) +++ generic/nsf.tcl (.../nsf.tcl) (revision e52f2dd0f35e8a12230a20e90575f242da4e0e5c) @@ -105,6 +105,11 @@ # Example unknown handler: # ::nsf::object::unknown::add xotcl {::xotcl::Class __unknown} + namespace eval ::nsf::argument {} + proc ::nsf::argument::unknown {args} { + #puts stderr "??? ::nsf::argument::unknown <$args> [info frame -1]" + return "" + } ###################################################################### # exit handlers Index: generic/nsfInt.h =================================================================== diff -u -r877c1e7d364b91e0a1d501738dfbb7b9dcb7d5ac -re52f2dd0f35e8a12230a20e90575f242da4e0e5c --- generic/nsfInt.h (.../nsfInt.h) (revision 877c1e7d364b91e0a1d501738dfbb7b9dcb7d5ac) +++ generic/nsfInt.h (.../nsfInt.h) (revision e52f2dd0f35e8a12230a20e90575f242da4e0e5c) @@ -604,7 +604,7 @@ NSF_ALIAS, NSF_ARGS, NSF_CMD, NSF_FILTER, NSF_FORWARD, NSF_METHOD, NSF_OBJECT, NSF_SETTER, NSF_VALUECHECK, NSF_GUARD_OPTION, NSF___UNKNOWN__, NSF_ARRAY, NSF_GET, NSF_SET, - NSF_UNKNOWN_HANDLER, + NSF_OBJECT_UNKNOWN_HANDLER, NSF_ARGUMENT_UNKNOWN_HANDLER, /* Partly redefined Tcl commands; leave them together at the end */ NSF_EXPR, NSF_FORMAT, NSF_INFO_BODY, NSF_INFO_FRAME, NSF_INTERP, NSF_IS, NSF_RENAME @@ -627,6 +627,7 @@ "-guard", "__unknown__", "::array", "get", "set", /* nsf tcl commands */ "::nsf::object::unknown", + "::nsf::argument::unknown", /* tcl commands */ "expr", "format", "::tcl::info::body", "::tcl::info::frame", "interp", "::tcl::string::is", "rename" Index: generic/predefined.h =================================================================== diff -u -r8046b1da6bc0689f73d4dbdc3f8d1e03fd23acaf -re52f2dd0f35e8a12230a20e90575f242da4e0e5c --- generic/predefined.h (.../predefined.h) (revision 8046b1da6bc0689f73d4dbdc3f8d1e03fd23acaf) +++ generic/predefined.h (.../predefined.h) (revision e52f2dd0f35e8a12230a20e90575f242da4e0e5c) @@ -40,6 +40,9 @@ "proc get {key} {return $::nsf::object::unknown($key)}\n" "proc delete {key} {array unset ::nsf::object::unknown($key)}\n" "proc keys {} {array names ::nsf::object::unknown}}\n" +"namespace eval ::nsf::argument {}\n" +"proc ::nsf::argument::unknown {args} {\n" +"return \"\"}\n" "proc ::nsf::exithandler {args} {\n" "lassign $args op value\n" "switch $op {\n" Index: library/lib/pkgIndex.tcl =================================================================== diff -u -rde25b8ac2f22701d21fead84ccc5793f8f809705 -re52f2dd0f35e8a12230a20e90575f242da4e0e5c --- library/lib/pkgIndex.tcl (.../pkgIndex.tcl) (revision de25b8ac2f22701d21fead84ccc5793f8f809705) +++ library/lib/pkgIndex.tcl (.../pkgIndex.tcl) (revision e52f2dd0f35e8a12230a20e90575f242da4e0e5c) @@ -13,4 +13,5 @@ package ifneeded nx::doc::xowiki 1.0 [list source [file join $dir nxdoc-xowiki.tcl]] package ifneeded nx::pp 1.0 [list source [file join $dir pp.tcl]] package ifneeded nx::test 1.0 [list source [file join $dir test.tcl]] +package ifneeded nx::trait 0.1 [list source [file join $dir nx-traits.tcl]] package ifneeded nx::zip 1.1 [list source [file join $dir nx-zip.tcl]] Index: tests/method-parameter.test =================================================================== diff -u -r24724ebae83af4e0104b349a2fb582bfc71a7475 -re52f2dd0f35e8a12230a20e90575f242da4e0e5c --- tests/method-parameter.test (.../method-parameter.test) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) +++ tests/method-parameter.test (.../method-parameter.test) (revision e52f2dd0f35e8a12230a20e90575f242da4e0e5c) @@ -24,8 +24,20 @@ should be "p1 ?-x value?"} ? {p1 -y --} {Invalid non-positional argument '-y', valid are : -x; should be "p1 ?-x value?"} + + # + # should we really allow numeric nonpos arg names? + # + ? {nsf::proc p2 {1 -2 -3} {return [list ${1} [info exists 2] [info exists 3]]}} "" + ? {p2 -4 -2 -3 -3 -2} "-4 1 1" ;# var 2 has value "-3", var 3 has value "-2" + ? {p2 -4 -3 + -2 -1} "-4 1 1" ;# var 2 has value "-2", var 3 has value "+" + + ? {nsf::proc p3 {1 -2 -3 4} {return [list ${1} [info exists 2] [info exists 3] ${4}]}} "" + ? {p3 -4 -3 -2 -1} "-4 0 1 -1" ;# var 1 has value "-4", var 4 has value "-1" } + + nx::Test case noleadingdash { nsf::proc p2a {-x args} {return [list [info exists x] $args]} @@ -47,30 +59,34 @@ ? {p3a 100 -x 1 -y 1 200} {100 1 1 200} ? {p3a 100 -xx 1 -y 1 200} {Invalid non-positional argument '-xx', valid are : -x, -y; should be "p3a a ?-x value? ?-y value? b ?-z value?"} +} +nx::Test case unknown-handler { - # - # For the "unknown args problem: It would be staightforward to - # provide an nsf-proc somewhat similar to NsfArgumentError () which - # gets the object passed if applicable (methodParameter) - # - # nsf::proc argumentError {cause arg -expected -msg -cmd -object -methodName} { - # - # } - # - # pros: - # - we could build the syntax from tcl... - # - an unknown handler for nonpos args could fit in, for method and object parameters - # - it should be possible to switch to a raw mode to make life easier when error - # messages change. - # - it should be feasible to output message to tk. - # - one could even think about nationalizing, etc... - # - maybe we could fit even the unknown object handling in (::nsf::object::unknown) - # - # contras: - # - not sure, we can hide the context on the error stack - # - not exactly the tcl-way - # - most errors are thrown in hopeless situations (not enough args), - # some errors could recover (e.g. unknown handler). we have to - # signal these situations from the C code. + Class create C { + :public method p1 {-x} {return [list [info exists x]]} + :create c1 + } + ? {c1 p1 -x 1 -y} {Invalid non-positional argument '-y', valid are : -x; + should be "::c1 p1 ?-x value?"} + + proc ::nsf::argument::unknown {method arg args} { + puts stderr "??? unknown nonpos-arg $arg in $method obj <$args>\n[info frame -1]\n" + return "" + } + + ? {c1 p1 -x 1 -y} {Invalid non-positional argument '-y', valid are : -x; + should be "::c1 p1 ?-x value?"} + + if {0} { + proc ::nsf::argument::unknown {method arg args} { + # nasty handler redefines method + puts stderr "??? REDEFINE ::nsf::argument::unknown <$args> [info frame -1]" + C public method p1 {-y} {return [list [info exists y]]} + return "" + } + + ? {c1 p1 -x 1 -y} {Invalid non-positional argument '-y', valid are : -x; + should be "::c1 p1 ?-x value?"} + } }