Index: generic/aol-xotcl.tcl =================================================================== diff -u -r11d5a8a7fab7ba69a94b161bb9c0aae5a2636e7b -r335be502582c8dbf25ed808978d56a8fde39c991 --- generic/aol-xotcl.tcl (.../aol-xotcl.tcl) (revision 11d5a8a7fab7ba69a94b161bb9c0aae5a2636e7b) +++ generic/aol-xotcl.tcl (.../aol-xotcl.tcl) (revision 335be502582c8dbf25ed808978d56a8fde39c991) @@ -23,7 +23,7 @@ _ns_getnamespaces namespaces foreach n $namespaces { if {[string match "::xotcl*" $n] == 0 - && ([catch {::xotcl::Object isobject $n} ret] || $ret == 0)} { + && ([catch {::xotcl::objectproperty $n object} ret] || $ret == 0)} { lappend nslist $n } } Index: generic/xotcl.c =================================================================== diff -u -r1d26e6269b5380e52588f077cd65e32c8a5c0cb6 -r335be502582c8dbf25ed808978d56a8fde39c991 --- generic/xotcl.c (.../xotcl.c) (revision 1d26e6269b5380e52588f077cd65e32c8a5c0cb6) +++ generic/xotcl.c (.../xotcl.c) (revision 335be502582c8dbf25ed808978d56a8fde39c991) @@ -376,7 +376,7 @@ result = ObjectDispatch(clientData, interp, objc, tov, flags); - FREE_ON_STACK(tov); + FREE_ON_STACK(Tcl_Obj*, tov); return result; } @@ -401,7 +401,7 @@ ObjStr(tov[0]), ObjStr(tov[1]), objc);*/ result = ObjectDispatch(clientData, interp, objc, tov, flags); - FREE_ON_STACK(tov); + FREE_ON_STACK(Tcl_Obj*, tov); return result; } @@ -1548,10 +1548,7 @@ assert(object); varTablePtr = object->nsPtr ? Tcl_Namespace_varTable(object->nsPtr) : object->varTable; - if (varTablePtr == NULL && object->varTable == NULL) { - fprintf(stderr, "+++ create varTable in InterpColonVarResolver\n"); - varTablePtr = object->varTable = VarHashTableCreate(); - } + assert(varTablePtr); /* * Does the variable exist in the object's namespace? @@ -1586,25 +1583,54 @@ * Begin of compiled var resolver * *********************************************************/ +#define FOR_COLON_RESOLVER(ptr) (*(ptr) == ':' && *(ptr+1) != ':') + typedef struct xotclResolvedVarInfo { Tcl_ResolvedVarInfo vInfo; /* This must be the first element. */ - XOTclObject *lastObj; + XOTclObject *lastObject; Tcl_Var var; Tcl_Obj *nameObj; - char buffer[64]; /* for now */ } xotclResolvedVarInfo; +/* + *---------------------------------------------------------------------- + * HashVarFree -- + * + * Free hashed variables based on refcount. + * + * Results: + * None. + * + * Side effects: + * Changed refCount or freed variable. + * + *---------------------------------------------------------------------- + */ static void HashVarFree(Tcl_Var var) { - /*fprintf(stderr,"#### refcount %d\n", VarHashRefCount(var));*/ - if (VarHashRefCount(var) == 1) { + if (VarHashRefCount(var) < 2) { /*fprintf(stderr,"#### free %p\n", var);*/ ckfree((char *) var); } else { VarHashRefCount(var)--; } } +/* + *---------------------------------------------------------------------- + * CompiledColonVarFetch -- + * + * Fetch value of a a compiled XOTcl instance variable at runtime. + * + * Results: + * Tcl_Var containing value or NULL. + * + * Side effects: + * Updates of Variable structure cache in necessary. + * + *---------------------------------------------------------------------- + */ + static Tcl_Var CompiledColonVarFetch(Tcl_Interp *interp, Tcl_ResolvedVarInfo *vinfoPtr) { xotclResolvedVarInfo *resVarInfo = (xotclResolvedVarInfo *)vinfoPtr; @@ -1620,12 +1646,15 @@ #endif /* - * We cache lookups based on obj; we have to care about cases, where - * variables are deleted in recreates or on single deletes. In these - * cases, the var flags are reset. + * We cache lookups based on xotcl objects; we have to care about + * cases, where the instance variables are in some delete states. + * */ - if (object == resVarInfo->lastObj && ((flags & VAR_DEAD_HASH)) == 0) { + if (object == resVarInfo->lastObject && ((flags & VAR_DEAD_HASH)) == 0) { + /* + * The variable is valid. + */ #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, ".... cached var '%s' var %p flags = %.4x\n", ObjStr(resVarInfo->nameObj), var, flags); @@ -1635,25 +1664,15 @@ if (var) { /* - * We have already a variable, which is not valid anymore. Clean - * it up. + * The variable is not valid anymore. Clean it up. */ HashVarFree(var); } varTablePtr = object->nsPtr ? Tcl_Namespace_varTable(object->nsPtr) : object->varTable; - if (varTablePtr == NULL && object->varTable == NULL) { - /* - * The variable table does not exist. This seems to be is the - * first access to a variable on this object. We create the and - * initialize the variable hash table and update the object - */ - varTablePtr = object->varTable = VarHashTableCreate(); - fprintf(stderr, "+++ create varTable in %s CompiledColonVarFetch for '%s'\n", - objectName(object), ObjStr(resVarInfo->nameObj)); - } + assert(varTablePtr); - resVarInfo->lastObj = object; + resVarInfo->lastObject = object; resVarInfo->var = var = (Tcl_Var) VarHashCreateVar(varTablePtr, resVarInfo->nameObj, &new); /* * Increment the reference counter to avoid ckfree() of the variable @@ -1665,28 +1684,60 @@ #if defined(VAR_RESOLVER_TRACE) { Var *v = (Var*)(resVarInfo->var); - fprintf(stderr, ".... looked up var %s (%s) var %p flags = %.6x\n", - resVarInfo->buffer, ObjStr(resVarInfo->nameObj), + fprintf(stderr, ".... looked up var %s var %p flags = %.6x\n", + ObjStr(resVarInfo->nameObj), v, v->flags); } #endif return var; } +/* + *---------------------------------------------------------------------- + * CompiledColonVarFree -- + * + * DeleteProc of the compiled variable handler. + * + * Results: + * None. + * + * Side effects: + * Free compiled variable structure and variable. + * + *---------------------------------------------------------------------- + */ void CompiledColonVarFree(Tcl_ResolvedVarInfo *vinfoPtr) { xotclResolvedVarInfo *resVarInfo = (xotclResolvedVarInfo *)vinfoPtr; DECR_REF_COUNT(resVarInfo->nameObj); if (resVarInfo->var) {HashVarFree(resVarInfo->var);} ckfree((char *) vinfoPtr); } -#define FOR_COLON_RESOLVER(ptr) (*(ptr) == ':' && *(ptr+1) != ':') - +/* + *---------------------------------------------------------------------- + * InterpCompiledColonVarResolver -- + * + * Register for prefixed variables our own compiled var handler. + * + * Results: + * TCL_OK or TCL_CONTINUE (based on Tcl's var resolver protocol) + * + * Side effects: + * Registered var handler or none. + * + *---------------------------------------------------------------------- + */ int InterpCompiledColonVarResolver(Tcl_Interp *interp, CONST84 char *name, int length, Tcl_Namespace *context, Tcl_ResolvedVarInfo **rPtr) { - /* getting the self object is a weak protection against handling of wrong vars */ + /* + * The variable handler is registered, when we have an active XOTcl + * object and the variable starts with the appropriate prefix. Note + * that getting the "self" object is a weak protection against + * handling of wrong vars + */ XOTclObject *object = GetSelfObj(interp); + #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "compiled var resolver for %s, obj %p\n", name, object); #endif @@ -1696,66 +1747,36 @@ vInfoPtr->vInfo.fetchProc = CompiledColonVarFetch; vInfoPtr->vInfo.deleteProc = CompiledColonVarFree; /* if NULL, tcl does a ckfree on proc clean up */ - vInfoPtr->lastObj = NULL; + vInfoPtr->lastObject = NULL; vInfoPtr->var = NULL; - fprintf(stderr, "copying %d bytes\n", length); - memcpy(vInfoPtr->buffer, name+1, length-1); vInfoPtr->nameObj = Tcl_NewStringObj(name+1, length-1); INCR_REF_COUNT(vInfoPtr->nameObj); - vInfoPtr->buffer[length-1] = 0; *rPtr = (Tcl_ResolvedVarInfo *)vInfoPtr; return TCL_OK; } return TCL_CONTINUE; } +/* + *---------------------------------------------------------------------- + * InterpColonVarResolver -- + * + * Resolve varnames as instance variables. These might be compiled + * locals or variables to be created (e.g. during an eval) in the + * objects vartables. If the command starts with the XOTcl + * specific prefix and we are on an XOTcl stack frame, treat + * command as instance varname. + * + * Results: + * TCL_OK or TCL_CONTINUE (based on Tcl's var resolver protocol) + * + * Side effects: + * If successful, return varPtr, pointing to instance variable. + * + *---------------------------------------------------------------------- + */ static int -InterpColonCmdResolver(Tcl_Interp *interp, CONST char *cmdName, Tcl_Namespace *nsPtr, int flags, Tcl_Command *cmdPtr) { - CallFrame *varFramePtr; - int frameFlags; - - if (!FOR_COLON_RESOLVER(cmdName) || flags & TCL_GLOBAL_ONLY) { - /* ordinary names and global lookups are not for us */ - return TCL_CONTINUE; - } - - varFramePtr = Tcl_Interp_varFramePtr(interp); - frameFlags = Tcl_CallFrame_isProcCallFrame(varFramePtr); - - /* skip over a nonproc frame, in case Tcl stacks it */ - if (frameFlags == 0 && Tcl_CallFrame_callerPtr(varFramePtr)) { - varFramePtr = (CallFrame *)Tcl_CallFrame_callerPtr(varFramePtr); - frameFlags = Tcl_CallFrame_isProcCallFrame(varFramePtr); -#if defined(CMD_RESOLVER_TRACE) - fprintf(stderr, "InterpColonCmdResolver uses parent frame\n"); -#endif - } -#if defined(CMD_RESOLVER_TRACE) - fprintf(stderr, "InterpColonCmdResolver cmdName %s flags %.6x, frame flags %.6x\n",cmdName, - flags, Tcl_CallFrame_isProcCallFrame(varFramePtr)); -#endif - - if (frameFlags & (FRAME_IS_XOTCL_METHOD|FRAME_IS_XOTCL_OBJECT|FRAME_IS_XOTCL_CMETHOD )) { -#if defined(CMD_RESOLVER_TRACE) - fprintf(stderr, " ... call colonCmd for %s\n", cmdName); -#endif - /* - * We have a cmd starting with ':', we are in an xotcl frame, so - * forward to the colonCmd. - */ - *cmdPtr = RUNTIME_STATE(interp)->colonCmd; - return TCL_OK; - } - -#if defined(CMD_RESOLVER_TRACE) - fprintf(stderr, " ... not found %s\n", cmdName); - tcl85showStack(interp); -#endif - return TCL_CONTINUE; -} - -static int InterpColonVarResolver(Tcl_Interp *interp, CONST char *varName, Tcl_Namespace *nsPtr, int flags, Tcl_Var *varPtr) { int new, frameFlags; CallFrame *varFramePtr; @@ -1764,30 +1785,24 @@ Tcl_Obj *keyObj; Tcl_Var var; - varFramePtr = Tcl_Interp_varFramePtr(interp); - frameFlags = Tcl_CallFrame_isProcCallFrame(varFramePtr); - - /*fprintf(stderr, "InterpColonVarResolver '%s' flags %.6x frameFlags %.6x\n", varName, flags, frameFlags);*/ - - if ( - !FOR_COLON_RESOLVER(varName) - /*|| (frameFlags & (FRAME_IS_XOTCL_CMETHOD|FRAME_IS_XOTCL_OBJECT)) == 0 */ - || (flags & TCL_GLOBAL_ONLY) - ) { + if (!FOR_COLON_RESOLVER(varName) || (flags & TCL_GLOBAL_ONLY)) { /* ordinary names and global lookups are not for us */ +#if defined(VAR_RESOLVER_TRACE) + fprintf(stderr, "InterpColonVarResolver '%s' flags %.6x not for us nsPtr %p\n", + varName, flags, nsPtr); +#endif return TCL_CONTINUE; } + varFramePtr = Tcl_Interp_varFramePtr(interp); + frameFlags = Tcl_CallFrame_isProcCallFrame(varFramePtr); + #if defined(VAR_RESOLVER_TRACE) - fprintf(stderr, "InterpColonVarResolver called var '%s' flags %.4x\n", varName, flags); + fprintf(stderr, "InterpColonVarResolver called var '%s' flags %.4x frame flags %.6x\n", + varName, flags, frameFlags); #endif varName ++; - -#if defined(VAR_RESOLVER_TRACE) - fprintf(stderr, " frame flags %.6x\n", frameFlags); -#endif - if (frameFlags & FRAME_IS_XOTCL_METHOD) { if ((*varPtr = CompiledLocalsLookup(varFramePtr, varName))) { #if defined(VAR_RESOLVER_TRACE) @@ -1815,10 +1830,7 @@ assert(object); varTablePtr = object->nsPtr ? Tcl_Namespace_varTable(object->nsPtr) : object->varTable; - if (varTablePtr == NULL && object->varTable == NULL) { - fprintf(stderr, "+++ create varTable in InterpColonVarResolver\n"); - varTablePtr = object->varTable = VarHashTableCreate(); - } + assert(varTablePtr); /*fprintf(stderr, "Object Var Resolver, name=%s, obj %p, nsPtr %p, varTable %p\n", varName, object, object->nsPtr, varTablePtr);*/ @@ -1847,10 +1859,81 @@ } /********************************************************* * - * End of compiled var resolver + * End of var resolvers * *********************************************************/ +/********************************************************* + * + * Begin of cmd resolver + * + *********************************************************/ +/* + *---------------------------------------------------------------------- + * InterpColonCmdResolver -- + * + * Resolve command names. If the command starts with the XOTcl + * specific prefix and we are on an XOTcl stack frame, treat + * command as OO method. + * + * Results: + * TCL_OK or TCL_CONTINUE (based on Tcl's command resolver protocol) + * + * Side effects: + * If successful, return cmdPtr, pointing to method. + * + *---------------------------------------------------------------------- + */ +static int +InterpColonCmdResolver(Tcl_Interp *interp, CONST char *cmdName, Tcl_Namespace *nsPtr, int flags, Tcl_Command *cmdPtr) { + CallFrame *varFramePtr; + int frameFlags; + + if (!FOR_COLON_RESOLVER(cmdName) || flags & TCL_GLOBAL_ONLY) { + /* ordinary names and global lookups are not for us */ + return TCL_CONTINUE; + } + + varFramePtr = Tcl_Interp_varFramePtr(interp); + frameFlags = Tcl_CallFrame_isProcCallFrame(varFramePtr); + + /* skip over a nonproc frame, in case Tcl stacks it */ + if (frameFlags == 0 && Tcl_CallFrame_callerPtr(varFramePtr)) { + varFramePtr = (CallFrame *)Tcl_CallFrame_callerPtr(varFramePtr); + frameFlags = Tcl_CallFrame_isProcCallFrame(varFramePtr); +#if defined(CMD_RESOLVER_TRACE) + fprintf(stderr, "InterpColonCmdResolver uses parent frame\n"); +#endif + } +#if defined(CMD_RESOLVER_TRACE) + fprintf(stderr, "InterpColonCmdResolver cmdName %s flags %.6x, frame flags %.6x\n",cmdName, + flags, Tcl_CallFrame_isProcCallFrame(varFramePtr)); +#endif + + if (frameFlags & (FRAME_IS_XOTCL_METHOD|FRAME_IS_XOTCL_OBJECT|FRAME_IS_XOTCL_CMETHOD )) { +#if defined(CMD_RESOLVER_TRACE) + fprintf(stderr, " ... call colonCmd for %s\n", cmdName); +#endif + /* + * We have a cmd starting with ':', we are in an xotcl frame, so + * forward to the colonCmd. + */ + *cmdPtr = RUNTIME_STATE(interp)->colonCmd; + return TCL_OK; + } + +#if defined(CMD_RESOLVER_TRACE) + fprintf(stderr, " ... not found %s\n", cmdName); + tcl85showStack(interp); +#endif + return TCL_CONTINUE; +} +/********************************************************* + * + * End of cmd resolver + * + *********************************************************/ + static Tcl_Namespace * requireObjNamespace(Tcl_Interp *interp, XOTclObject *object) { @@ -2416,15 +2499,15 @@ if (XOTclCallCommand(interp, XOTE_FORMAT, 3, ov) != TCL_OK) { XOTcl_PopFrameObj(interp, framePtr); DECR_REF_COUNT(savedResult); - FREE_ON_STACK(ov); + FREE_ON_STACK(Tcl_Obj*, ov); return 0; } DECR_REF_COUNT(result); result = Tcl_DuplicateObj(Tcl_GetObjResult(interp)); INCR_REF_COUNT(result); Tcl_SetObjResult(interp, savedResult); DECR_REF_COUNT(savedResult); - FREE_ON_STACK(ov); + FREE_ON_STACK(Tcl_Obj*, ov); } else { valueString = Tcl_GetStringFromObj(valueObj, &valueLength); Tcl_AppendToObj(result, valueString, valueLength); @@ -5953,7 +6036,7 @@ */ flags &= ~XOTCL_CM_NO_SHIFT; result = ObjectDispatch(clientData, interp, objc+2-shift, tov, flags | XOTCL_CM_NO_UNKNOWN); - FREE_ON_STACK(tov); + FREE_ON_STACK(Tcl_Obj*, tov); } else { /* unknown failed */ result = XOTclVarErrMsg(interp, objectName(object), @@ -8166,7 +8249,7 @@ /* the provided name of the method is just for error reporting */ tov[0] = methodObj ? methodObj : XOTclGlobalObjs[XOTE_CONFIGURE]; result = XOTclOConfigureMethod(interp, object, objc-1, tov); - FREE_ON_STACK(tov); + FREE_ON_STACK(Tcl_Obj*, tov); } else { result = callMethod((ClientData) object, interp, methodObj, objc, objv+2, 0); } @@ -8333,7 +8416,7 @@ } result = XOTclCCreateMethod(interp, cl, ObjStr(nameObj), objc+2, ov); - FREE_ON_STACK(ov); + FREE_ON_STACK(Tcl_Obj*, ov); DECR_REF_COUNT(nameObj); return result; @@ -8369,7 +8452,6 @@ Var *varPtr = NULL, *otherPtr = NULL, *arrayPtr; int new = 0, flgs = TCL_LEAVE_ERR_MSG; Tcl_CallFrame *varFramePtr; - TclVarHashTable *tablePtr; Tcl_CallFrame frame, *framePtr = &frame; XOTcl_PushFrameObj(interp, object, framePtr); @@ -8421,13 +8503,20 @@ if (varFramePtr && (Tcl_CallFrame_isProcCallFrame(varFramePtr) & FRAME_IS_PROC)) { varPtr = (Var *)CompiledLocalsLookup((CallFrame *)varFramePtr, ObjStr(newName)); - if (varPtr == NULL) { /* look in frame's local var hashtable */ - tablePtr = Tcl_CallFrame_varTablePtr(varFramePtr); - if (tablePtr == NULL) { + if (varPtr == NULL) { + /* look in frame's local var hashtable */ + TclVarHashTable *varTablePtr = Tcl_CallFrame_varTablePtr(varFramePtr); + + if (varTablePtr == NULL) { + /* + * The variable table does not exist. This seems to be is the + * first access to a variable on this frame. We create the and + * initialize the variable hash table and update the object + */ /*fprintf(stderr, "+++ create varTable in GetInstVarIntoCurrentScope\n");*/ - Tcl_CallFrame_varTablePtr(varFramePtr) = tablePtr = VarHashTableCreate(); + Tcl_CallFrame_varTablePtr(varFramePtr) = varTablePtr = VarHashTableCreate(); } - varPtr = VarHashCreateVar(tablePtr, newName, &new); + varPtr = VarHashCreateVar(varTablePtr, newName, &new); } /* @@ -8865,7 +8954,7 @@ memcpy(ov, objv, sizeof(Tcl_Obj *)*objc); ov[0] = tcd->cmdName; result = callForwarder(tcd, interp, objc, ov); - FREE_ON_STACK(ov); + FREE_ON_STACK(Tcl_Obj *, ov); return result; } else { Tcl_Obj **ov, *freeList=NULL; @@ -8996,8 +9085,8 @@ if (tcd->prefix) {DECR_REF_COUNT(ov[1]);} exitforwardmethod: if (freeList) {DECR_REF_COUNT(freeList);} - FREE_ON_STACK(objvmap); - FREE_ON_STACK(OV); + FREE_ON_STACK(int,objvmap); + FREE_ON_STACK(Tcl_Obj*,OV); } return result; } @@ -13111,7 +13200,7 @@ /*fprintf(stderr, "create -- end ... %s => %d\n", ObjStr(nameObj), result);*/ if (tmpObj) {DECR_REF_COUNT(tmpObj);} - FREE_ON_STACK(tov); + FREE_ON_STACK(Tcl_Obj *, tov); return result; } @@ -13205,7 +13294,7 @@ result = ObjectDispatch((ClientData)cl, interp, objc+3, ov, 0); } - FREE_ON_STACK(ov); + FREE_ON_STACK(Tcl_Obj *, ov); } DECR_REF_COUNT(fullnameObj); Index: generic/xotcl.h =================================================================== diff -u -rd7b2898d74c2ff2158ae2cc4ca3f7a6d87533d45 -r335be502582c8dbf25ed808978d56a8fde39c991 --- generic/xotcl.h (.../xotcl.h) (revision d7b2898d74c2ff2158ae2cc4ca3f7a6d87533d45) +++ generic/xotcl.h (.../xotcl.h) (revision 335be502582c8dbf25ed808978d56a8fde39c991) @@ -77,8 +77,8 @@ /* activate/deacticate assert #define NDEBUG 1 */ -#define NDEBUG 1 + /* activate/deacticate memory tracing #define XOTCL_MEM_TRACE 1 #define XOTCL_MEM_COUNT 1 Index: generic/xotclInt.h =================================================================== diff -u -rd7b2898d74c2ff2158ae2cc4ca3f7a6d87533d45 -r335be502582c8dbf25ed808978d56a8fde39c991 --- generic/xotclInt.h (.../xotclInt.h) (revision d7b2898d74c2ff2158ae2cc4ca3f7a6d87533d45) +++ generic/xotclInt.h (.../xotclInt.h) (revision 335be502582c8dbf25ed808978d56a8fde39c991) @@ -165,18 +165,18 @@ # define ALLOC_ON_STACK(type,n,var) \ int __##var##_count = (n); type __##var[n+2]; \ type *var = __##var + 1; var[-1] = var[__##var##_count] = (type)0xdeadbeaf -# define FREE_ON_STACK(var) \ - assert(var[-1] == var[__##var##_count] && (void *)var[-1] == (void*)0xdeadbeaf) +# define FREE_ON_STACK(type,var) \ + assert(var[-1] == var[__##var##_count] && var[-1] == (type)0xdeadbeaf) # else # define ALLOC_ON_STACK(type,n,var) type var[(n)] -# define FREE_ON_STACK(var) +# define FREE_ON_STACK(type,var) # endif #elif defined(USE_ALLOCA) # define ALLOC_ON_STACK(type,n,var) type *var = (type *)alloca((n)*sizeof(type)) -# define FREE_ON_STACK(var) +# define FREE_ON_STACK(type,var) #else # define ALLOC_ON_STACK(type,n,var) type *var = (type *)ckalloc((n)*sizeof(type)) -# define FREE_ON_STACK(var) ckfree((char*)var) +# define FREE_ON_STACK(type,var) ckfree((char*)var) #endif #ifdef USE_ALLOCA Index: generic/xotclShadow.c =================================================================== diff -u -r15b6823910520e77bfa8c2cf4ea78289af91c28c -r335be502582c8dbf25ed808978d56a8fde39c991 --- generic/xotclShadow.c (.../xotclShadow.c) (revision 15b6823910520e77bfa8c2cf4ea78289af91c28c) +++ generic/xotclShadow.c (.../xotclShadow.c) (revision 335be502582c8dbf25ed808978d56a8fde39c991) @@ -226,6 +226,6 @@ if (objc > 1) memcpy(ov+1, objv+1, sizeof(Tcl_Obj *)*(objc-1)); result = Tcl_NRCallObjProc(interp, ti->proc, ti->clientData, objc, objv); - FREE_ON_STACK(ov); + FREE_ON_STACK(Tcl_Obj *, ov); return result; }