Index: generic/predefined.h =================================================================== diff -u -r5524b83ed5dda30e55f7a02e4c22d26783688954 -red15b5be7e88cbbcdf6121f3869722dbc354d76f --- generic/predefined.h (.../predefined.h) (revision 5524b83ed5dda30e55f7a02e4c22d26783688954) +++ generic/predefined.h (.../predefined.h) (revision ed15b5be7e88cbbcdf6121f3869722dbc354d76f) @@ -159,8 +159,12 @@ "lappend objopts required\n" "lappend methodopts required}\n" "if {[$slot exists type]} {\n" -"lappend objopts [$slot type]\n" -"lappend methodopts [$slot type]}\n" +"set type [$slot type]\n" +"if {[string match ::* $type]} {\n" +"lappend objopts type=$type\n" +"lappend methodopts type=$type} else {\n" +"lappend objopts $type\n" +"lappend methodopts $type}}\n" "if {[$slot exists multivalued] && [$slot multivalued]} {\n" "if {!([$slot exists type] && [$slot type] eq \"relation\")} {\n" "lappend objopts multivalued} else {}}\n" Index: generic/predefined.xotcl =================================================================== diff -u -r5524b83ed5dda30e55f7a02e4c22d26783688954 -red15b5be7e88cbbcdf6121f3869722dbc354d76f --- generic/predefined.xotcl (.../predefined.xotcl) (revision 5524b83ed5dda30e55f7a02e4c22d26783688954) +++ generic/predefined.xotcl (.../predefined.xotcl) (revision ed15b5be7e88cbbcdf6121f3869722dbc354d76f) @@ -327,8 +327,14 @@ lappend methodopts required } if {[$slot exists type]} { - lappend objopts [$slot type] - lappend methodopts [$slot type] + set type [$slot type] + if {[string match ::* $type]} { + lappend objopts type=$type + lappend methodopts type=$type + } else { + lappend objopts $type + lappend methodopts $type + } } # TODO: remove multivalued check on relations by handling multivalued # not in relation, but in the converters Index: generic/xotcl.c =================================================================== diff -u -r9e28ec16bdd81fae21e29e17f6ebf654b437635f -red15b5be7e88cbbcdf6121f3869722dbc354d76f --- generic/xotcl.c (.../xotcl.c) (revision 9e28ec16bdd81fae21e29e17f6ebf654b437635f) +++ generic/xotcl.c (.../xotcl.c) (revision ed15b5be7e88cbbcdf6121f3869722dbc354d76f) @@ -5262,8 +5262,9 @@ if (paramPtr->name) ckfree(paramPtr->name); if (paramPtr->nameObj) {DECR_REF_COUNT(paramPtr->nameObj);} if (paramPtr->defaultValue) {DECR_REF_COUNT(paramPtr->defaultValue);} - if (paramPtr->arg) {DECR_REF_COUNT(paramPtr->arg);} + if (paramPtr->converterName) {DECR_REF_COUNT(paramPtr->converterName);} if (paramPtr->converterArg) {DECR_REF_COUNT(paramPtr->converterArg);} + if (paramPtr->paramObj) {DECR_REF_COUNT(paramPtr->paramObj);} } FREE(XOTclParam*, paramsPtr); } @@ -5329,47 +5330,58 @@ static Tcl_Obj * ParamDefsFormat(Tcl_Interp *interp, XOTclParamDefs *paramDefs) { int first, colonWritten; - Tcl_Obj *list = Tcl_NewListObj(0, NULL), *innerlist, *nameStringObj; + Tcl_Obj *list = Tcl_NewListObj(0, NULL), *innerList, *nameStringObj; XOTclParam CONST *pPtr; for (pPtr = paramDefs->paramsPtr; pPtr->name; pPtr++) { - int isNonpos = *pPtr->name == '-'; - int outputRequired = (isNonpos && (pPtr->flags & XOTCL_ARG_REQUIRED)); - int outputOptional = (!isNonpos && !(pPtr->flags & XOTCL_ARG_REQUIRED) - && !pPtr->defaultValue && - pPtr->converter != convertToNothing); - first = 1; - colonWritten = 0; + if (pPtr -> paramObj) { + innerList = pPtr->paramObj; + } else { + /* We need this part only for C-defined parameter definitions, + defined via genTclAPI. - nameStringObj = Tcl_NewStringObj(pPtr->name, -1); - if (pPtr->type) { - ParamDefsFormatOption(interp, nameStringObj, pPtr->type, &colonWritten, &first); + TODO: we could streamline this by defining as well C-Api via + the same syntax as for accepted for tcl obj types + "xotclParam" + */ + int isNonpos = *pPtr->name == '-'; + int outputRequired = (isNonpos && (pPtr->flags & XOTCL_ARG_REQUIRED)); + int outputOptional = (!isNonpos && !(pPtr->flags & XOTCL_ARG_REQUIRED) + && !pPtr->defaultValue && + pPtr->converter != convertToNothing); + first = 1; + colonWritten = 0; + + nameStringObj = Tcl_NewStringObj(pPtr->name, -1); + if (pPtr->type) { + ParamDefsFormatOption(interp, nameStringObj, pPtr->type, &colonWritten, &first); + } + if (outputRequired) { + ParamDefsFormatOption(interp, nameStringObj, "required", &colonWritten, &first); + } else if (outputOptional) { + ParamDefsFormatOption(interp, nameStringObj, "optional", &colonWritten, &first); + } + if ((pPtr->flags & XOTCL_ARG_SUBST_DEFAULT)) { + ParamDefsFormatOption(interp, nameStringObj, "substdefault", &colonWritten, &first); + } + if ((pPtr->flags & XOTCL_ARG_INITCMD)) { + ParamDefsFormatOption(interp, nameStringObj, "initcmd", &colonWritten, &first); + } else if ((pPtr->flags & XOTCL_ARG_METHOD)) { + ParamDefsFormatOption(interp, nameStringObj, "method", &colonWritten, &first); + } else if ((pPtr->flags & XOTCL_ARG_NOARG)) { + ParamDefsFormatOption(interp, nameStringObj, "noarg", &colonWritten, &first); + } else if ((pPtr->flags & XOTCL_ARG_MULTIVALUED)) { + ParamDefsFormatOption(interp, nameStringObj, "multivalued", &colonWritten, &first); + } + + innerList = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, innerList, nameStringObj); + if (pPtr->defaultValue) { + Tcl_ListObjAppendElement(interp, innerList, pPtr->defaultValue); + } } - if (outputRequired) { - ParamDefsFormatOption(interp, nameStringObj, "required", &colonWritten, &first); - } else if (outputOptional) { - ParamDefsFormatOption(interp, nameStringObj, "optional", &colonWritten, &first); - } - if ((pPtr->flags & XOTCL_ARG_SUBST_DEFAULT)) { - ParamDefsFormatOption(interp, nameStringObj, "substdefault", &colonWritten, &first); - } - if ((pPtr->flags & XOTCL_ARG_INITCMD)) { - ParamDefsFormatOption(interp, nameStringObj, "initcmd", &colonWritten, &first); - } else if ((pPtr->flags & XOTCL_ARG_METHOD)) { - ParamDefsFormatOption(interp, nameStringObj, "method", &colonWritten, &first); - } else if ((pPtr->flags & XOTCL_ARG_NOARG)) { - ParamDefsFormatOption(interp, nameStringObj, "noarg", &colonWritten, &first); - } else if ((pPtr->flags & XOTCL_ARG_MULTIVALUED)) { - ParamDefsFormatOption(interp, nameStringObj, "multivalued", &colonWritten, &first); - } - - innerlist = Tcl_NewListObj(0, NULL); - Tcl_ListObjAppendElement(interp, innerlist, nameStringObj); - if (pPtr->defaultValue) { - Tcl_ListObjAppendElement(interp, innerlist, pPtr->defaultValue); - } - - Tcl_ListObjAppendElement(interp, list, innerlist); + + Tcl_ListObjAppendElement(interp, list, innerList); } return list; @@ -6219,7 +6231,31 @@ } return XOTclObjErrType(interp, objPtr, "class"); } +static int convertToObjectOfType(Tcl_Interp *interp, Tcl_Obj *objPtr, XOTclParam CONST *pPtr, ClientData *clientData) { + XOTclObject *object; + XOTclClass *cl; + Tcl_Obj *valueObj = pPtr->converterArg; + Tcl_DString ds, *dsPtr = &ds; + if (valueObj == NULL) + return XOTclVarErrMsg(interp, "No object type specified", (char *) NULL); + + if ((GetObjectFromObj(interp, objPtr, &object) == TCL_OK) + && (GetClassFromObj(interp, valueObj, &cl, 0) == TCL_OK) + && isSubType(object->cl, cl)) { + *clientData = object; + return TCL_OK; + } + + DSTRING_INIT(dsPtr); + Tcl_DStringAppend(dsPtr, "object of type ", -1); + Tcl_DStringAppend(dsPtr, ObjStr(valueObj), -1); + XOTclObjErrType(interp, objPtr, Tcl_DStringValue(dsPtr)); + DSTRING_FREE(dsPtr); + + return TCL_ERROR; +} + static int convertToRelation(Tcl_Interp *interp, Tcl_Obj *objPtr, XOTclParam CONST *pPtr, ClientData *clientData) { /* XOTclRelationCmd is the real setter, which checks the values according to the relation type (Class, List of Class, list of @@ -6233,7 +6269,7 @@ int result, oc; ov[0] = XOTclGlobalObjects[XOTE_PARAMETER_TYPE_OBJ]; - ov[1] = pPtr->arg; + ov[1] = pPtr->converterName; ov[2] = pPtr->nameObj; ov[3] = objPtr; @@ -6342,6 +6378,12 @@ result = ParamOptionSetConverter(interp, paramPtr, "relation", convertToRelation); paramPtr->flags |= XOTCL_ARG_RELATION; /*paramPtr->type = "tclobj";*/ + } else if (length >= 6 && strncmp(option, "type=", 5) == 0) { + if (paramPtr->converterArg) + return XOTclVarErrMsg(interp, "Converter arg specified twice", (char *) NULL); + result = ParamOptionSetConverter(interp, paramPtr, option, convertToObjectOfType); + paramPtr->converterArg = Tcl_NewStringObj(option+5, length-5); + INCR_REF_COUNT(paramPtr->converterArg); } else { XOTclObject *paramObj; Tcl_Obj *checker; @@ -6362,7 +6404,7 @@ /* TODO: for the time being, we do not return an error here */ } result = ParamOptionSetConverter(interp, paramPtr, "usertype", convertViaCmd); - paramPtr->arg = checker; + paramPtr->converterName = checker; } if ((paramPtr->flags & disallowedOptions)) { @@ -6379,6 +6421,9 @@ char *argString, *argName; Tcl_Obj **npav; + paramPtr->paramObj = arg; + INCR_REF_COUNT(paramPtr->paramObj); + result = Tcl_ListObjGetElements(interp, arg, &npac, &npav); if (result != TCL_OK || npac < 1 || npac > 2) { return XOTclVarErrMsg(interp, "wrong # of elements in parameter definition for method", Index: generic/xotclInt.h =================================================================== diff -u -r5524b83ed5dda30e55f7a02e4c22d26783688954 -red15b5be7e88cbbcdf6121f3869722dbc354d76f --- generic/xotclInt.h (.../xotclInt.h) (revision 5524b83ed5dda30e55f7a02e4c22d26783688954) +++ generic/xotclInt.h (.../xotclInt.h) (revision ed15b5be7e88cbbcdf6121f3869722dbc354d76f) @@ -409,7 +409,8 @@ Tcl_Obj *defaultValue; char *type; Tcl_Obj *nameObj; - Tcl_Obj *arg; + Tcl_Obj *converterName; + Tcl_Obj *paramObj; } XOTclParam; typedef struct XOTclParamDefs { Index: tests/info-method.xotcl =================================================================== diff -u -r210eab6d9149846d5d6a6a8e0fa74e232ca5b6de -red15b5be7e88cbbcdf6121f3869722dbc354d76f --- tests/info-method.xotcl (.../info-method.xotcl) (revision 210eab6d9149846d5d6a6a8e0fa74e232ca5b6de) +++ tests/info-method.xotcl (.../info-method.xotcl) (revision ed15b5be7e88cbbcdf6121f3869722dbc354d76f) @@ -50,7 +50,7 @@ ? {Class info method parameter method} \ {name arguments body -precondition -postcondition} ? {Object info method parameter alias} \ - {{-objscope:switch 0} methodName cmd} + {-objscope:switch methodName cmd} # raises currently an error ? {catch {C info method parameter a}} 1 Index: tests/parameters.xotcl =================================================================== diff -u -r5524b83ed5dda30e55f7a02e4c22d26783688954 -red15b5be7e88cbbcdf6121f3869722dbc354d76f --- tests/parameters.xotcl (.../parameters.xotcl) (revision 5524b83ed5dda30e55f7a02e4c22d26783688954) +++ tests/parameters.xotcl (.../parameters.xotcl) (revision ed15b5be7e88cbbcdf6121f3869722dbc354d76f) @@ -13,7 +13,11 @@ Test case valuecheck Test parameter count 10000 #Test parameter count 10 + Object create o1 +Class create C -parameter {a {b:boolean} {c 1}} +C create c1 + ? {::xotcl::valuecheck object o1} 1 ? {::xotcl::is o1 object} 1 ? {::xotcl::valuecheck class o1} 0 @@ -23,6 +27,10 @@ ? {::xotcl::valuecheck integer,multivalued [list 1 2 3]} 1 ? {::xotcl::valuecheck integer,multivalued [list 1 2 3 a]} 0 ? {::xotcl::valuecheck in1 aaa} {invalid value constraints "in1"} +? {::xotcl::valuecheck type=::C c1} 1 +? {::xotcl::valuecheck type=::C o} 0 "object, but different type" +? {::xotcl::valuecheck type=::C c} 0 "no object" +? {::xotcl::valuecheck type=::xotcl2::Object c1} 1 "general type" # # parameter options @@ -51,6 +59,7 @@ # boolean YES YES NO NO YES YES YES # object YES YES NO NO YES YES YES # class YES YES NO NO YES YES YES +# objectOfType YES YES NO NO YES YES YES # userdefined YES YES NO YES YES YES YES ####################################################### @@ -303,7 +312,7 @@ ? {D info method args bar} {s literal c d switch optflag x y z} "all args" ? {D info method parameter bar} \ - {{-s:substdefault {[self]}} {-literal {[self]}} {-c:substdefault {[my c]}} {-d:integer,substdefault {$d}} {-switch:switch 0} -optflag x y:integer {z 1}} \ + {{-s:substdefault "[self]"} {-literal "[self]"} {-c:substdefault "[my c]"} {-d:integer,substdefault "$d"} -switch:switch -optflag x y:integer {z 1}} \ "query method parameter" D method foo {a b {-c 1} {-d} x {-end 100}} { @@ -477,11 +486,6 @@ # are already predefined, define the rest. # TODO: should go finally to predefined. -::xotcl::parameterType method type=type {name value arg} { - if {![::xotcl::is $value type $arg]} { - error "Value '$value' of $name of not of type $arg" - } -} ::xotcl::parameterType method type=mixin {name value arg} { if {![::xotcl::is $value mixin $arg]} { error "Value '$value' of $name has not mixin $arg" @@ -503,8 +507,12 @@ D method foo-object {x:object} {return $x} D method foo-meta {x:metaclass} {return $x} D method foo-mixin {x:mixin,arg=::M} {return $x} -D method foo-type {x:type,arg=::C} {return $x} +D method foo-type {x:type=::C} {return $x} +? {D info method parameter foo-base} "x:baseclass" +? {D info method parameter foo-mixin} "x:mixin,arg=::M" +? {D info method parameter foo-type} "x:type=::C" + ? {d1 foo-base ::xotcl2::Object} "::xotcl2::Object" ? {d1 foo-base C} \ "Value 'C' of x is not a baseclass" \ @@ -536,7 +544,7 @@ ? {d1 foo-type d1} "d1" ? {d1 foo-type c1} "c1" ? {d1 foo-type o} \ - "Value 'o' of x of not of type ::C" \ + {expected object of type ::C but got "o"} \ "o not of type ::C" @@ -552,11 +560,27 @@ Class create ParamTest -parameter { o:object c:class - d:type,arg=D + d:type=::C + d1:type=C m:metaclass mix:mixin,arg=M b:baseclass + {x:object,multivalued {o}} } + +# TODO: we have no good interface for querying the slot notation for parameters +proc parameterFromSlot {class objectparameter} { + set slot ${class}::slot::$objectparameter + array set "" [::xotcl::parameterFromSlot $slot $objectparameter] + return $(oparam) +} + +? {parameterFromSlot ParamTest o} "o:object" +? {parameterFromSlot ParamTest d} "d:type=::C" +? {parameterFromSlot ParamTest d1} "d1:type=C" +? {parameterFromSlot ParamTest mix} "mix:mixin,arg=M" +? {parameterFromSlot ParamTest x} "x:object,multivalued o" + ? {ParamTest create p -o o} ::p ? {ParamTest create p -o xxx} \ {expected object but got "xxx"} \ @@ -567,6 +591,13 @@ "Value 'o' of mix has not mixin M" \ "does not have mixin M" +? {ParamTest create p -d d1} ::p +? {ParamTest create p -d1 d1} ::p +? {ParamTest create p -d c1} ::p +? {ParamTest create p -d o} \ + {expected object of type ::C but got "o"} \ + "o not of type ::C" + # TODO: naming "type" and "mixin" not perfect. # maybe "type" => "hastype" # maybe "mixin" => "hasmixin" Index: tests/slottest.xotcl =================================================================== diff -u -r5524b83ed5dda30e55f7a02e4c22d26783688954 -red15b5be7e88cbbcdf6121f3869722dbc354d76f --- tests/slottest.xotcl (.../slottest.xotcl) (revision 5524b83ed5dda30e55f7a02e4c22d26783688954) +++ tests/slottest.xotcl (.../slottest.xotcl) (revision ed15b5be7e88cbbcdf6121f3869722dbc354d76f) @@ -384,21 +384,14 @@ $obj set __oldvalue($var) $value } -#todo: (1) temporary solution, (2) name "type" is not optimal -::xotcl::parameterType method type=type {name value arg} { - if {![::xotcl::is $value type $arg]} { - error "Value '$value' of $name of not of type $arg" - } -} - Person slots { - Attribute create projects -default "" -multivalued true -type type -arg ::Project + Attribute create projects -default "" -multivalued true -type ::Project Attribute create salary -type integer } Person p2 -name "Gustaf" p2 projects add ::project1 -? {p2 projects add ::o1} {Value '::o1' of value of not of type ::Project} +? {p2 projects add ::o1} {expected object of type ::Project but got "::o1"} p2 salary 100 ? {catch {p2 salary 100.9}} 1 ? {p2 salary} 100