Index: Makefile.in =================================================================== diff -u -r99fb4ec76728ea1c8a432d9b7d402f3cb865e92e -r24724ebae83af4e0104b349a2fb582bfc71a7475 --- Makefile.in (.../Makefile.in) (revision 99fb4ec76728ea1c8a432d9b7d402f3cb865e92e) +++ Makefile.in (.../Makefile.in) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -474,6 +474,7 @@ $(TCLSH) $(src_test_dir_native)/object-system.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/destroy.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/methods.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) + $(TCLSH) $(src_test_dir_native)/method-parameter.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/var-access.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/varresolution.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/info-method.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) Index: TODO =================================================================== diff -u -r2ba521e3dfbb1294908b51ed8e13dab5adc3ca03 -r24724ebae83af4e0104b349a2fb582bfc71a7475 --- TODO (.../TODO) (revision 2ba521e3dfbb1294908b51ed8e13dab5adc3ca03) +++ TODO (.../TODO) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -3555,10 +3555,22 @@ for methods with primitive bodies: 5%-25%. - added regression tests for argument parsing +- nsf.c + - added experimental parameter option noleadingdash + - additionalal regression test file method-parameter.test + - provide selective error messages for unknown nonpos args + TODO: + - NsfUnexpectedNonposArgumentError() for valueInArgument, when structure settles + - ouput of noleadingdash in introspection + - ouput of noleadingdash in objectParameterSlots + - handling of noleadingdash vor values of nonpos args + - special handling of values looking like nonpos-flags, + but wich are not ones (-1, "- a b c", ....) in detection + when to throw unknow. + - check flag reuses in ~/scripts/nonposargs-speed.xotcl - NSF_WITH_OS_RESOLVER - - ParseContextExtendObjv - private: * document private in tutorial - add "property" and "attribute" and "info property" and "info slot ..." to migration guide Index: generic/nsf.c =================================================================== diff -u -re639a46f30e0e0c10dc84c898e828b9abe9298d9 -r24724ebae83af4e0104b349a2fb582bfc71a7475 --- generic/nsf.c (.../nsf.c) (revision e639a46f30e0e0c10dc84c898e828b9abe9298d9) +++ generic/nsf.c (.../nsf.c) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -10870,6 +10870,9 @@ paramPtr->flags |= NSF_ARG_NOARG; paramPtr->nrArgs = 0; + } else if (strncmp(option, "noleadingdash", 8) == 0) { + paramPtr->flags |= NSF_ARG_NOLEADINGDASH; + } else if (strncmp(option, "noconfig", 8) == 0) { if (disallowedOptions != NSF_DISALLOWED_ARG_OBJECT_PARAMETER) { return NsfPrintError(interp, "Parameter option 'noconfig' only allowed for object parameters"); @@ -15682,6 +15685,12 @@ #define SkipNonposParamDefs(cPtr) \ for (; ++cPtr <= lastParamPtr && *cPtr->name == '-';) +Nsf_Param CONST * +NextParam(Nsf_Param CONST *paramPtr, Nsf_Param CONST *lastParamPtr) { + for (; ++paramPtr <= lastParamPtr && *paramPtr->name == '-'; ); + return paramPtr; +} + static int ArgumentParse(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], NsfObject *object, Tcl_Obj *procNameObj, @@ -15838,6 +15847,7 @@ int found = 0; for (; pPtr <= lastParamPtr && *pPtr->name == '-'; pPtr ++) { + /*fprintf(stderr, "comparing '%s' with '%s'\n", argumentString, pPtr->name);*/ if ((pPtr->flags & NSF_ARG_NOCONFIG) == 0 && ch1 == pPtr->name[1] && strcmp(argumentString, pPtr->name) == 0) { @@ -15848,8 +15858,20 @@ } } if (!found) { - SkipNonposParamDefs(currentParamPtr); - pPtr = currentParamPtr; + Nsf_Param CONST *nextParamPtr = NextParam(currentParamPtr, lastParamPtr); + /*fprintf(stderr, "non-pos-arg '%s' not found, current %p %s last %p %s next %p %s\n", + argumentString, + currentParamPtr, currentParamPtr->name, + lastParamPtr, lastParamPtr->name, + nextParamPtr, nextParamPtr->name);*/ + if (nextParamPtr > lastParamPtr + || (nextParamPtr->flags & NSF_ARG_NOLEADINGDASH)) { + return NsfUnexpectedNonposArgumentError(interp, argumentString, + (Nsf_Object *)object, + currentParamPtr, paramPtr, + procNameObj); + } + pPtr = currentParamPtr = nextParamPtr; } } } @@ -15885,7 +15907,7 @@ o++; if (unlikely(o >= objc)) { /* we expect an argument, but we are already at the end of the argument list */ - return NsfPrintError(interp, "Argument for parameter '%s' expected", pPtr->name); + return NsfPrintError(interp, "Value for parameter '%s' expected", pPtr->name); } assert(valueObj == NULL); valueObj = objv[o]; Index: generic/nsf.h =================================================================== diff -u -r2ba521e3dfbb1294908b51ed8e13dab5adc3ca03 -r24724ebae83af4e0104b349a2fb582bfc71a7475 --- generic/nsf.h (.../nsf.h) (revision 2ba521e3dfbb1294908b51ed8e13dab5adc3ca03) +++ generic/nsf.h (.../nsf.h) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -277,7 +277,15 @@ extern int NsfUnexpectedArgumentError(Tcl_Interp *interp, CONST char *argumentString, - Nsf_Object *object, Nsf_Param CONST *paramPtr, Tcl_Obj *procNameObj); + Nsf_Object *object, Nsf_Param CONST *paramPtr, + Tcl_Obj *procNameObj); +extern int +NsfUnexpectedNonposArgumentError(Tcl_Interp *interp, + CONST char *argumentString, + Nsf_Object *object, + Nsf_Param CONST *currentParamPtr, + Nsf_Param CONST *paramPtr, + Tcl_Obj *procNameObj); /* * logging Index: generic/nsfError.c =================================================================== diff -u -r2ba521e3dfbb1294908b51ed8e13dab5adc3ca03 -r24724ebae83af4e0104b349a2fb582bfc71a7475 --- generic/nsfError.c (.../nsfError.c) (revision 2ba521e3dfbb1294908b51ed8e13dab5adc3ca03) +++ generic/nsfError.c (.../nsfError.c) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -222,7 +222,8 @@ * * NsfUnexpectedArgumentError -- * - * Produce a unexpecte argument number (most likely, too many arguments) + * Produce an error message about an unexpected argument (most likely, + * too many arguments) * * Results: * TCL_ERROR @@ -250,6 +251,49 @@ /* *---------------------------------------------------------------------- * + * NsfUnexpectedNonposArgumentError -- + * + * Produce a unexpecte argument number (most likely, too many arguments) + * + * Results: + * TCL_ERROR + * + * Side effects: + * Sets the result message. + * + *---------------------------------------------------------------------- + */ +extern int +NsfUnexpectedNonposArgumentError(Tcl_Interp *interp, + CONST char *argumentString, + Nsf_Object *object, + Nsf_Param CONST *currentParamPtr, + Nsf_Param CONST *paramPtr, + Tcl_Obj *procNameObj) { + Tcl_DString ds, *dsPtr = &ds; + Nsf_Param CONST *pPtr; + + DSTRING_INIT(dsPtr); + Tcl_DStringAppend(dsPtr, "Invalid non-positional argument '", -1); + Tcl_DStringAppend(dsPtr, argumentString, -1); + Tcl_DStringAppend(dsPtr, "', valid are : ", -1); + for (pPtr = currentParamPtr; pPtr->name && *pPtr->name == '-'; pPtr ++) { + Tcl_DStringAppend(dsPtr, pPtr->name, -1); + Tcl_DStringAppend(dsPtr, ", ", -1); + } + Tcl_DStringTrunc(dsPtr, Tcl_DStringLength(dsPtr) - 2); + Tcl_DStringAppend(dsPtr, ";\n", 2); + + NsfArgumentError(interp, Tcl_DStringValue(dsPtr), paramPtr, + object ? object->cmdName : NULL, + procNameObj); + DSTRING_FREE(dsPtr); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * * NsfDispatchClientDataError -- * * Produce a error message when method was not dispatched on an object Index: generic/nsfInt.h =================================================================== diff -u -r2ba521e3dfbb1294908b51ed8e13dab5adc3ca03 -r24724ebae83af4e0104b349a2fb582bfc71a7475 --- generic/nsfInt.h (.../nsfInt.h) (revision 2ba521e3dfbb1294908b51ed8e13dab5adc3ca03) +++ generic/nsfInt.h (.../nsfInt.h) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -406,6 +406,7 @@ #define NSF_ARG_WARN 0x040000 #define NSF_ARG_UNNAMED 0x080000 #define NSF_ARG_IS_RETURNVALUE 0x100000 +#define NSF_ARG_NOLEADINGDASH 0x200000 /* method invocations */ #define NSF_ARG_METHOD_INVOCATION (NSF_ARG_ALIAS|NSF_ARG_FORWARD|NSF_ARG_INITCMD) Index: library/xotcl/tests/slottest.xotcl =================================================================== diff -u -ra24e1f836c3126d0a0e9467bde3a9fa8da901711 -r24724ebae83af4e0104b349a2fb582bfc71a7475 --- library/xotcl/tests/slottest.xotcl (.../slottest.xotcl) (revision a24e1f836c3126d0a0e9467bde3a9fa8da901711) +++ library/xotcl/tests/slottest.xotcl (.../slottest.xotcl) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -375,7 +375,7 @@ C instproc init args {set ::_ $args} set ::_ "" - ? {C create c2 -y 1 -x} {Argument for parameter '-x' expected} + ? {C create c2 -y 1 -x} {Value for parameter '-x' expected} ? {set ::_} "" ? {c2 x} {can't read "x": no such variable} ? {C create c3 -y 1 -x 0} "::c3" Index: library/xotcl/tests/testx.xotcl =================================================================== diff -u -rb37bf2deab94b6294509fa79bb7b922d6e8a5635 -r24724ebae83af4e0104b349a2fb582bfc71a7475 --- library/xotcl/tests/testx.xotcl (.../testx.xotcl) (revision b37bf2deab94b6294509fa79bb7b922d6e8a5635) +++ library/xotcl/tests/testx.xotcl (.../testx.xotcl) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -4113,7 +4113,7 @@ o foo o foo -foo 0 catch {o foo -foo} msg - errorCheck $msg "Argument for parameter '-foo' expected" "Empty non-pos arg" + errorCheck $msg "Value for parameter '-foo' expected" "Empty non-pos arg" Object oa oa proc foo {{-a A} b} { Index: tests/disposition.test =================================================================== diff -u -rce55b9f6e80b8444dd248b1e6e36217716331ee9 -r24724ebae83af4e0104b349a2fb582bfc71a7475 --- tests/disposition.test (.../disposition.test) (revision ce55b9f6e80b8444dd248b1e6e36217716331ee9) +++ tests/disposition.test (.../disposition.test) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -193,9 +193,10 @@ C setObjectParams {{-single-np:alias}} ? {[C new -single-np [list -x]] eval {set :single-np}} \ - "Argument for parameter '-x' expected" + "Value for parameter '-x' expected" ? {[C new -single-np [list -x X]] eval {set :single-np}} \ - "Invalid argument '-x X', maybe too many arguments; should be \"[C inst] single-np -x\"" + "Invalid non-positional argument '-x X', valid are : -x; + should be \"::__%&singleton single-np -x\"" # # INTERACTIONS with other parameter types Index: tests/method-parameter.test =================================================================== diff -u --- tests/method-parameter.test (revision 0) +++ tests/method-parameter.test (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -0,0 +1,76 @@ +# -*- Tcl -*- +package require nx +package require nx::test + +nx::Test case method-params-0 { + nsf::proc p0 {} {return 1} + nsf::proc p1 {-x} {return [list [info exists x]]} + + ? {p0} 1 + ;# the following error msg comes from Tcl + ? {p0 -x} {wrong # args: should be "p0"} + + ? {p1} 0 + ? {p1 -x} {Value for parameter '-x' expected} + ? {p1 -x 1} 1 + ? {p1 -x 1 2} {Invalid argument '2', maybe too many arguments; should be "p1 ?-x value?"} + ? {p1 -x 1 -y} {Invalid non-positional argument '-y', valid are : -x; + should be "p1 ?-x value?"} + ? {p1 a} {Invalid argument 'a', maybe too many arguments; should be "p1 ?-x value?"} + ? {p1 a -x} {Invalid argument 'a', maybe too many arguments; should be "p1 ?-x value?"} + + ? {p1 --} 0 + ? {p1 -y} {Invalid non-positional argument '-y', valid are : -x; + should be "p1 ?-x value?"} + ? {p1 -y --} {Invalid non-positional argument '-y', valid are : -x; + should be "p1 ?-x value?"} +} + +nx::Test case noleadingdash { + + nsf::proc p2a {-x args} {return [list [info exists x] $args]} + nsf::proc p2b {-x args:noleadingdash} {return [list [info exists x] $args]} + nsf::proc p2c {-x:noleadingdash args:noleadingdash} {return [list [info exists x] $args]} + + ? {p2a -x -y} {1 {}} ;# "-y" is the value of "x" + ? {p2b -x -y} {1 {}} ;# "-y" is the value of "x" + ? {p2c -x -y} {1 {}} ;# "-y" is the value of "x"; TODO: noleadindash currently only for posargs + + ? {p2a -x 1 -y} {1 -y} + ? {p2b -x 1 -y} {Invalid non-positional argument '-y', valid are : -x; + should be "p2b ?-x value? ?arg ...?"} + ? {p2c -x 1 -y} {Invalid non-positional argument '-y', valid are : -x; + should be "p2c ?-x value? ?arg ...?"} + + nsf::proc p3a {a -x -y b:noleadingdash -z} {return [list $a [info exists x] [info exists y] $b]} + + ? {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?"} + + + # + # 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. +} Index: tests/object-system.test =================================================================== diff -u -rc29a6f1e7448196346d3174a7f0a4cd18d65691a -r24724ebae83af4e0104b349a2fb582bfc71a7475 --- tests/object-system.test (.../object-system.test) (revision c29a6f1e7448196346d3174a7f0a4cd18d65691a) +++ tests/object-system.test (.../object-system.test) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -63,13 +63,15 @@ ? {p4 -- -x 1 2} {0 {-x 1 2}} ? {p4 --} {0 {}} ? {p4 -- --} {0 --} +? {p4 -y --} {0 {-y --}} ;# no -y parameter, so pushed into args ? {p5} {0 0 0 {}} ? {p5 -x 1} {1 0 0 {}} ? {p5 a} {0 0 1 {}} -? {p5 -y 1} {0 0 1 1} ;# "-y" is passed into arg, "1" into args +? {p5 -y 1} {0 0 1 1} ;# "-y" is passed into arg, "1" into args ? {p5 -y 1 2} {0 0 1 {1 2}} ;# "-y" is passed into arg, "1 2" into args -? {p5 -x 1 2} {1 0 1 {}} ;# "2" is passed into arg, "1 2" into args +? {p5 -x 1 2} {1 0 1 {}} ;# "2" is passed into arg, "1 2" into args +? {p5 -y --} {0 0 1 {}} ;# "--" is value of "y" # # Create objects and test its properties Index: tests/parameters.test =================================================================== diff -u -rb9638e7510abc38eed801d5e8f357f6f89664d90 -r24724ebae83af4e0104b349a2fb582bfc71a7475 --- tests/parameters.test (.../parameters.test) (revision b9638e7510abc38eed801d5e8f357f6f89664d90) +++ tests/parameters.test (.../parameters.test) (revision 24724ebae83af4e0104b349a2fb582bfc71a7475) @@ -1489,7 +1489,7 @@ } set ::_ "" - ? {C create c2 -y 1 -x} {Argument for parameter '-x' expected} + ? {C create c2 -y 1 -x} {Value for parameter '-x' expected} ? {set ::_} "" ? {c2 x} {can't read "x": no such variable} ? {C create c3 -y 1 -x 0} "::c3"