4 * This file contains implementations of the "simple" commands and
5 * methods from the object-system core.
7 * Copyright (c) 2005-2013 by Donal K. Fellows
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
19 static inline Tcl_Object *AddConstructionFinalizer(Tcl_Interp *interp);
20 static Tcl_NRPostProc AfterNRDestructor;
21 static Tcl_NRPostProc DecrRefsPostClassConstructor;
22 static Tcl_NRPostProc FinalizeConstruction;
23 static Tcl_NRPostProc FinalizeEval;
24 static Tcl_NRPostProc NextRestoreFrame;
27 * ----------------------------------------------------------------------
29 * AddCreateCallback, FinalizeConstruction --
31 * Special version of TclNRAddCallback that allows the caller to splice
32 * the object created later on. Always calls FinalizeConstruction, which
33 * converts the object into its name and stores that in the interpreter
34 * result. This is shared by all the construction methods (create,
35 * createWithNamespace, new).
37 * Note that this is the only code in this file (or, indeed, the whole of
38 * TclOO) that uses NRE internals; it is the only code that does
39 * non-standard poking in the NRE guts.
41 * ----------------------------------------------------------------------
44 static inline Tcl_Object *
45 AddConstructionFinalizer(
48 TclNRAddCallback(interp, FinalizeConstruction, NULL, NULL, NULL, NULL);
49 return (Tcl_Object *) &(TOP_CB(interp)->data[0]);
58 Object *oPtr = data[0];
60 if (result != TCL_OK) {
63 Tcl_SetObjResult(interp, TclOOObjectName(interp, oPtr));
68 * ----------------------------------------------------------------------
70 * TclOO_Class_Constructor --
72 * Implementation for oo::class constructor.
74 * ----------------------------------------------------------------------
78 TclOO_Class_Constructor(
79 ClientData clientData,
81 Tcl_ObjectContext context,
85 Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
88 if (objc-1 > Tcl_ObjectContextSkippedArgs(context)) {
89 Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
90 "?definitionScript?");
92 } else if (objc == Tcl_ObjectContextSkippedArgs(context)) {
97 * Delegate to [oo::define] to do the work.
100 invoke = ckalloc(3 * sizeof(Tcl_Obj *));
101 invoke[0] = oPtr->fPtr->defineName;
102 invoke[1] = TclOOObjectName(interp, oPtr);
103 invoke[2] = objv[objc-1];
106 * Must add references or errors in configuration script will cause
110 Tcl_IncrRefCount(invoke[0]);
111 Tcl_IncrRefCount(invoke[1]);
112 Tcl_IncrRefCount(invoke[2]);
113 TclNRAddCallback(interp, DecrRefsPostClassConstructor,
114 invoke, NULL, NULL, NULL);
117 * Tricky point: do not want the extra reported level in the Tcl stack
118 * trace, so use TCL_EVAL_NOERR.
121 return TclNREvalObjv(interp, 3, invoke, TCL_EVAL_NOERR, NULL);
125 DecrRefsPostClassConstructor(
130 Tcl_Obj **invoke = data[0];
132 TclDecrRefCount(invoke[0]);
133 TclDecrRefCount(invoke[1]);
134 TclDecrRefCount(invoke[2]);
140 * ----------------------------------------------------------------------
142 * TclOO_Class_Create --
144 * Implementation for oo::class->create method.
146 * ----------------------------------------------------------------------
151 ClientData clientData, /* Ignored. */
152 Tcl_Interp *interp, /* Interpreter in which to create the object;
153 * also used for error reporting. */
154 Tcl_ObjectContext context, /* The object/call context. */
155 int objc, /* Number of arguments. */
156 Tcl_Obj *const *objv) /* The actual arguments. */
158 Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
163 * Sanity check; should not be possible to invoke this method on a
167 if (oPtr->classPtr == NULL) {
168 Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);
170 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
171 "object \"%s\" is not a class", TclGetString(cmdnameObj)));
172 Tcl_SetErrorCode(interp, "TCL", "OO", "INSTANTIATE_NONCLASS", NULL);
177 * Check we have the right number of (sensible) arguments.
180 if (objc - Tcl_ObjectContextSkippedArgs(context) < 1) {
181 Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
182 "objectName ?arg ...?");
185 objName = Tcl_GetStringFromObj(
186 objv[Tcl_ObjectContextSkippedArgs(context)], &len);
188 Tcl_SetObjResult(interp, Tcl_NewStringObj(
189 "object name must not be empty", -1));
190 Tcl_SetErrorCode(interp, "TCL", "OO", "EMPTY_NAME", NULL);
195 * Make the object and return its name.
198 return TclNRNewObjectInstance(interp, (Tcl_Class) oPtr->classPtr,
199 objName, NULL, objc, objv,
200 Tcl_ObjectContextSkippedArgs(context)+1,
201 AddConstructionFinalizer(interp));
205 * ----------------------------------------------------------------------
207 * TclOO_Class_CreateNs --
209 * Implementation for oo::class->createWithNamespace method.
211 * ----------------------------------------------------------------------
215 TclOO_Class_CreateNs(
216 ClientData clientData, /* Ignored. */
217 Tcl_Interp *interp, /* Interpreter in which to create the object;
218 * also used for error reporting. */
219 Tcl_ObjectContext context, /* The object/call context. */
220 int objc, /* Number of arguments. */
221 Tcl_Obj *const *objv) /* The actual arguments. */
223 Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
224 const char *objName, *nsName;
228 * Sanity check; should not be possible to invoke this method on a
232 if (oPtr->classPtr == NULL) {
233 Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);
235 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
236 "object \"%s\" is not a class", TclGetString(cmdnameObj)));
237 Tcl_SetErrorCode(interp, "TCL", "OO", "INSTANTIATE_NONCLASS", NULL);
242 * Check we have the right number of (sensible) arguments.
245 if (objc - Tcl_ObjectContextSkippedArgs(context) < 2) {
246 Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
247 "objectName namespaceName ?arg ...?");
250 objName = Tcl_GetStringFromObj(
251 objv[Tcl_ObjectContextSkippedArgs(context)], &len);
253 Tcl_SetObjResult(interp, Tcl_NewStringObj(
254 "object name must not be empty", -1));
255 Tcl_SetErrorCode(interp, "TCL", "OO", "EMPTY_NAME", NULL);
258 nsName = Tcl_GetStringFromObj(
259 objv[Tcl_ObjectContextSkippedArgs(context)+1], &len);
261 Tcl_SetObjResult(interp, Tcl_NewStringObj(
262 "namespace name must not be empty", -1));
263 Tcl_SetErrorCode(interp, "TCL", "OO", "EMPTY_NAME", NULL);
268 * Make the object and return its name.
271 return TclNRNewObjectInstance(interp, (Tcl_Class) oPtr->classPtr,
272 objName, nsName, objc, objv,
273 Tcl_ObjectContextSkippedArgs(context)+2,
274 AddConstructionFinalizer(interp));
278 * ----------------------------------------------------------------------
282 * Implementation for oo::class->new method.
284 * ----------------------------------------------------------------------
289 ClientData clientData, /* Ignored. */
290 Tcl_Interp *interp, /* Interpreter in which to create the object;
291 * also used for error reporting. */
292 Tcl_ObjectContext context, /* The object/call context. */
293 int objc, /* Number of arguments. */
294 Tcl_Obj *const *objv) /* The actual arguments. */
296 Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
299 * Sanity check; should not be possible to invoke this method on a
303 if (oPtr->classPtr == NULL) {
304 Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);
306 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
307 "object \"%s\" is not a class", TclGetString(cmdnameObj)));
308 Tcl_SetErrorCode(interp, "TCL", "OO", "INSTANTIATE_NONCLASS", NULL);
313 * Make the object and return its name.
316 return TclNRNewObjectInstance(interp, (Tcl_Class) oPtr->classPtr,
317 NULL, NULL, objc, objv, Tcl_ObjectContextSkippedArgs(context),
318 AddConstructionFinalizer(interp));
322 * ----------------------------------------------------------------------
324 * TclOO_Object_Destroy --
326 * Implementation for oo::object->destroy method.
328 * ----------------------------------------------------------------------
332 TclOO_Object_Destroy(
333 ClientData clientData, /* Ignored. */
334 Tcl_Interp *interp, /* Interpreter in which to create the object;
335 * also used for error reporting. */
336 Tcl_ObjectContext context, /* The object/call context. */
337 int objc, /* Number of arguments. */
338 Tcl_Obj *const *objv) /* The actual arguments. */
340 Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
341 CallContext *contextPtr;
343 if (objc != Tcl_ObjectContextSkippedArgs(context)) {
344 Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
348 if (!(oPtr->flags & DESTRUCTOR_CALLED)) {
349 oPtr->flags |= DESTRUCTOR_CALLED;
350 contextPtr = TclOOGetCallContext(oPtr, NULL, DESTRUCTOR, NULL);
351 if (contextPtr != NULL) {
352 contextPtr->callPtr->flags |= DESTRUCTOR;
353 contextPtr->skip = 0;
354 TclNRAddCallback(interp, AfterNRDestructor, contextPtr,
356 TclPushTailcallPoint(interp);
357 return TclOOInvokeContext(contextPtr, interp, 0, NULL);
361 Tcl_DeleteCommandFromToken(interp, oPtr->command);
372 CallContext *contextPtr = data[0];
374 if (contextPtr->oPtr->command) {
375 Tcl_DeleteCommandFromToken(interp, contextPtr->oPtr->command);
377 TclOODeleteContext(contextPtr);
382 * ----------------------------------------------------------------------
384 * TclOO_Object_Eval --
386 * Implementation for oo::object->eval method.
388 * ----------------------------------------------------------------------
393 ClientData clientData, /* Ignored. */
394 Tcl_Interp *interp, /* Interpreter in which to create the object;
395 * also used for error reporting. */
396 Tcl_ObjectContext context, /* The object/call context. */
397 int objc, /* Number of arguments. */
398 Tcl_Obj *const *objv) /* The actual arguments. */
400 CallContext *contextPtr = (CallContext *) context;
401 Tcl_Object object = Tcl_ObjectContextObject(context);
402 const int skip = Tcl_ObjectContextSkippedArgs(context);
403 CallFrame *framePtr, **framePtrPtr = &framePtr;
408 Tcl_WrongNumArgs(interp, skip, objv, "arg ?arg ...?");
413 * Make the object's namespace the current namespace and evaluate the
417 (void) TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
418 Tcl_GetObjectNamespace(object), 0);
419 framePtr->objc = objc;
420 framePtr->objv = objv; /* Reference counts do not need to be
421 * incremented here. */
423 if (!(contextPtr->callPtr->flags & PUBLIC_METHOD)) {
424 object = NULL; /* Now just for error mesage printing. */
428 * Work out what script we are actually going to evaluate.
430 * When there's more than one argument, we concatenate them together with
431 * spaces between, then evaluate the result. Tcl_EvalObjEx will delete the
432 * object when it decrements its refcount after eval'ing it.
435 if (objc != skip+1) {
436 scriptPtr = Tcl_ConcatObj(objc-skip, objv+skip);
439 scriptPtr = objv[skip];
440 invoker = ((Interp *) interp)->cmdFramePtr;
444 * Evaluate the script now, with FinalizeEval to do the processing after
445 * the script completes.
448 TclNRAddCallback(interp, FinalizeEval, object, NULL, NULL, NULL);
449 return TclNREvalObjEx(interp, scriptPtr, 0, invoker, skip);
458 if (result == TCL_ERROR) {
459 Object *oPtr = data[0];
463 namePtr = TclGetString(TclOOObjectName(interp, oPtr));
468 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
469 "\n (in \"%s eval\" script line %d)",
470 namePtr, Tcl_GetErrorLine(interp)));
474 * Restore the previous "current" namespace.
477 TclPopStackFrame(interp);
482 * ----------------------------------------------------------------------
484 * TclOO_Object_Unknown --
486 * Default unknown method handler method (defined in oo::object). This
487 * just creates a suitable error message.
489 * ----------------------------------------------------------------------
493 TclOO_Object_Unknown(
494 ClientData clientData, /* Ignored. */
495 Tcl_Interp *interp, /* Interpreter in which to create the object;
496 * also used for error reporting. */
497 Tcl_ObjectContext context, /* The object/call context. */
498 int objc, /* Number of arguments. */
499 Tcl_Obj *const *objv) /* The actual arguments. */
501 CallContext *contextPtr = (CallContext *) context;
502 Object *oPtr = contextPtr->oPtr;
503 const char **methodNames;
504 int numMethodNames, i, skip = Tcl_ObjectContextSkippedArgs(context);
508 * If no method name, generate an error asking for a method name. (Only by
509 * overriding *this* method can an object handle the absence of a method
510 * name without an error).
514 Tcl_WrongNumArgs(interp, skip, objv, "method ?arg ...?");
519 * Get the list of methods that we want to know about.
522 numMethodNames = TclOOGetSortedMethodList(oPtr,
523 contextPtr->callPtr->flags & PUBLIC_METHOD, &methodNames);
526 * Special message when there are no visible methods at all.
529 if (numMethodNames == 0) {
530 Tcl_Obj *tmpBuf = TclOOObjectName(interp, oPtr);
533 if (contextPtr->callPtr->flags & PUBLIC_METHOD) {
534 piece = "visible methods";
538 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
539 "object \"%s\" has no %s", TclGetString(tmpBuf), piece));
540 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
541 TclGetString(objv[skip]), NULL);
545 errorMsg = Tcl_ObjPrintf("unknown method \"%s\": must be ",
546 TclGetString(objv[skip]));
547 for (i=0 ; i<numMethodNames-1 ; i++) {
549 Tcl_AppendToObj(errorMsg, ", ", -1);
551 Tcl_AppendToObj(errorMsg, methodNames[i], -1);
554 Tcl_AppendToObj(errorMsg, " or ", -1);
556 Tcl_AppendToObj(errorMsg, methodNames[i], -1);
558 Tcl_SetObjResult(interp, errorMsg);
559 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
560 TclGetString(objv[skip]), NULL);
565 * ----------------------------------------------------------------------
567 * TclOO_Object_LinkVar --
569 * Implementation of oo::object->variable method.
571 * ----------------------------------------------------------------------
575 TclOO_Object_LinkVar(
576 ClientData clientData, /* Ignored. */
577 Tcl_Interp *interp, /* Interpreter in which to create the object;
578 * also used for error reporting. */
579 Tcl_ObjectContext context, /* The object/call context. */
580 int objc, /* Number of arguments. */
581 Tcl_Obj *const *objv) /* The actual arguments. */
583 Interp *iPtr = (Interp *) interp;
584 Tcl_Object object = Tcl_ObjectContextObject(context);
585 Namespace *savedNsPtr;
588 if (objc-Tcl_ObjectContextSkippedArgs(context) < 0) {
589 Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
595 * A sanity check. Shouldn't ever happen. (This is all that remains of a
596 * more complex check inherited from [global] after we have applied the
597 * fix for [Bug 2903811]; note that the fix involved *removing* code.)
600 if (iPtr->varFramePtr == NULL) {
604 for (i=Tcl_ObjectContextSkippedArgs(context) ; i<objc ; i++) {
605 Var *varPtr, *aryPtr;
606 const char *varName = TclGetString(objv[i]);
609 * The variable name must not contain a '::' since that's illegal in
613 if (strstr(varName, "::") != NULL) {
614 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
615 "variable name \"%s\" illegal: must not contain namespace"
616 " separator", varName));
617 Tcl_SetErrorCode(interp, "TCL", "UPVAR", "INVERTED", NULL);
622 * Switch to the object's namespace for the duration of this call.
623 * Like this, the variable is looked up in the namespace of the
624 * object, and not in the namespace of the caller. Otherwise this
625 * would only work if the caller was a method of the object itself,
626 * which might not be true if the method was exported. This is a bit
627 * of a hack, but the simplest way to do this (pushing a stack frame
628 * would be horribly expensive by comparison).
631 savedNsPtr = iPtr->varFramePtr->nsPtr;
632 iPtr->varFramePtr->nsPtr = (Namespace *)
633 Tcl_GetObjectNamespace(object);
634 varPtr = TclObjLookupVar(interp, objv[i], NULL, TCL_NAMESPACE_ONLY,
635 "define", 1, 0, &aryPtr);
636 iPtr->varFramePtr->nsPtr = savedNsPtr;
638 if (varPtr == NULL || aryPtr != NULL) {
640 * Variable cannot be an element in an array. If aryPtr is not
641 * NULL, it is an element, so throw up an error and return.
644 TclVarErrMsg(interp, varName, NULL, "define",
645 "name refers to an element in an array");
646 Tcl_SetErrorCode(interp, "TCL", "UPVAR", "LOCAL_ELEMENT", NULL);
651 * Arrange for the lifetime of the variable to be correctly managed.
652 * This is copied out of Tcl_VariableObjCmd...
655 if (!TclIsVarNamespaceVar(varPtr)) {
656 TclSetVarNamespaceVar(varPtr);
659 if (TclPtrMakeUpvar(interp, varPtr, varName, 0, -1) != TCL_OK) {
667 * ----------------------------------------------------------------------
669 * TclOO_Object_VarName --
671 * Implementation of the oo::object->varname method.
673 * ----------------------------------------------------------------------
677 TclOO_Object_VarName(
678 ClientData clientData, /* Ignored. */
679 Tcl_Interp *interp, /* Interpreter in which to create the object;
680 * also used for error reporting. */
681 Tcl_ObjectContext context, /* The object/call context. */
682 int objc, /* Number of arguments. */
683 Tcl_Obj *const *objv) /* The actual arguments. */
685 Var *varPtr, *aryVar;
686 Tcl_Obj *varNamePtr, *argPtr;
689 if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
690 Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
694 argPtr = objv[objc-1];
695 arg = Tcl_GetString(argPtr);
698 * Convert the variable name to fully-qualified form if it wasn't already.
699 * This has to be done prior to lookup because we can run into problems
700 * with resolvers otherwise. [Bug 3603695]
702 * We still need to do the lookup; the variable could be linked to another
703 * variable and we want the target's name.
706 if (arg[0] == ':' && arg[1] == ':') {
709 Tcl_Namespace *namespacePtr =
710 Tcl_GetObjectNamespace(Tcl_ObjectContextObject(context));
712 varNamePtr = Tcl_NewStringObj(namespacePtr->fullName, -1);
713 Tcl_AppendToObj(varNamePtr, "::", 2);
714 Tcl_AppendObjToObj(varNamePtr, argPtr);
716 Tcl_IncrRefCount(varNamePtr);
717 varPtr = TclObjLookupVar(interp, varNamePtr, NULL,
718 TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG, "refer to", 1, 1, &aryVar);
719 Tcl_DecrRefCount(varNamePtr);
720 if (varPtr == NULL) {
721 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARIABLE", arg, NULL);
726 * Now that we've pinned down what variable we're really talking about
727 * (including traversing variable links), convert back to a name.
730 varNamePtr = Tcl_NewObj();
731 if (aryVar != NULL) {
733 Tcl_HashSearch search;
735 Tcl_GetVariableFullName(interp, (Tcl_Var) aryVar, varNamePtr);
738 * WARNING! This code pokes inside the implementation of hash tables!
741 hPtr = Tcl_FirstHashEntry((Tcl_HashTable *) aryVar->value.tablePtr,
743 while (hPtr != NULL) {
744 if (varPtr == Tcl_GetHashValue(hPtr)) {
745 Tcl_AppendToObj(varNamePtr, "(", -1);
746 Tcl_AppendObjToObj(varNamePtr, hPtr->key.objPtr);
747 Tcl_AppendToObj(varNamePtr, ")", -1);
750 hPtr = Tcl_NextHashEntry(&search);
753 Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, varNamePtr);
755 Tcl_SetObjResult(interp, varNamePtr);
760 * ----------------------------------------------------------------------
762 * TclOONextObjCmd, TclOONextToObjCmd --
764 * Implementation of the [next] and [nextto] commands. Note that these
765 * commands are only ever to be used inside the body of a procedure-like
768 * ----------------------------------------------------------------------
773 ClientData clientData,
776 Tcl_Obj *const *objv)
778 Interp *iPtr = (Interp *) interp;
779 CallFrame *framePtr = iPtr->varFramePtr;
780 Tcl_ObjectContext context;
783 * Start with sanity checks on the calling context to make sure that we
784 * are invoked from a suitable method context. If so, we can safely
785 * retrieve the handle to the object call context.
788 if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
789 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
790 "%s may only be called from inside a method",
791 TclGetString(objv[0])));
792 Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL);
795 context = framePtr->clientData;
798 * Invoke the (advanced) method call context in the caller context. Note
799 * that this is like [uplevel 1] and not [eval].
802 TclNRAddCallback(interp, NextRestoreFrame, framePtr, NULL,NULL,NULL);
803 iPtr->varFramePtr = framePtr->callerVarPtr;
804 return TclNRObjectContextInvokeNext(interp, context, objc, objv, 1);
809 ClientData clientData,
812 Tcl_Obj *const *objv)
814 Interp *iPtr = (Interp *) interp;
815 CallFrame *framePtr = iPtr->varFramePtr;
817 CallContext *contextPtr;
820 const char *methodType;
823 * Start with sanity checks on the calling context to make sure that we
824 * are invoked from a suitable method context. If so, we can safely
825 * retrieve the handle to the object call context.
828 if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
829 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
830 "%s may only be called from inside a method",
831 TclGetString(objv[0])));
832 Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL);
835 contextPtr = framePtr->clientData;
838 * Sanity check the arguments; we need the first one to refer to a class.
842 Tcl_WrongNumArgs(interp, 1, objv, "class ?arg...?");
845 object = Tcl_GetObjectFromObj(interp, objv[1]);
846 if (object == NULL) {
849 classPtr = ((Object *)object)->classPtr;
850 if (classPtr == NULL) {
851 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
852 "\"%s\" is not a class", TclGetString(objv[1])));
853 Tcl_SetErrorCode(interp, "TCL", "OO", "CLASS_REQUIRED", NULL);
858 * Search for an implementation of a method associated with the current
859 * call on the call chain past the point where we currently are. Do not
860 * allow jumping backwards!
863 for (i=contextPtr->index+1 ; i<contextPtr->callPtr->numChain ; i++) {
864 struct MInvoke *miPtr = contextPtr->callPtr->chain + i;
866 if (!miPtr->isFilter && miPtr->mPtr->declaringClassPtr == classPtr) {
868 * Invoke the (advanced) method call context in the caller
869 * context. Note that this is like [uplevel 1] and not [eval].
872 TclNRAddCallback(interp, NextRestoreFrame, framePtr,
873 contextPtr, INT2PTR(contextPtr->index), NULL);
874 contextPtr->index = i-1;
875 iPtr->varFramePtr = framePtr->callerVarPtr;
876 return TclNRObjectContextInvokeNext(interp,
877 (Tcl_ObjectContext) contextPtr, objc, objv, 2);
882 * Generate an appropriate error message, depending on whether the value
883 * is on the chain but unreachable, or not on the chain at all.
886 if (contextPtr->callPtr->flags & CONSTRUCTOR) {
887 methodType = "constructor";
888 } else if (contextPtr->callPtr->flags & DESTRUCTOR) {
889 methodType = "destructor";
891 methodType = "method";
894 for (i=contextPtr->index ; i>=0 ; i--) {
895 struct MInvoke *miPtr = contextPtr->callPtr->chain + i;
897 if (!miPtr->isFilter && miPtr->mPtr->declaringClassPtr == classPtr) {
898 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
899 "%s implementation by \"%s\" not reachable from here",
900 methodType, TclGetString(objv[1])));
901 Tcl_SetErrorCode(interp, "TCL", "OO", "CLASS_NOT_REACHABLE",
906 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
907 "%s has no non-filter implementation by \"%s\"",
908 methodType, TclGetString(objv[1])));
909 Tcl_SetErrorCode(interp, "TCL", "OO", "CLASS_NOT_THERE", NULL);
919 Interp *iPtr = (Interp *) interp;
920 CallContext *contextPtr = data[1];
922 iPtr->varFramePtr = data[0];
923 if (contextPtr != NULL) {
924 contextPtr->index = PTR2INT(data[2]);
930 * ----------------------------------------------------------------------
934 * Implementation of the [self] command, which provides introspection of
937 * ----------------------------------------------------------------------
942 ClientData clientData,
945 Tcl_Obj *const *objv)
947 static const char *const subcmds[] = {
948 "call", "caller", "class", "filter", "method", "namespace", "next",
949 "object", "target", NULL
952 SELF_CALL, SELF_CALLER, SELF_CLASS, SELF_FILTER, SELF_METHOD, SELF_NS,
953 SELF_NEXT, SELF_OBJECT, SELF_TARGET
955 Interp *iPtr = (Interp *) interp;
956 CallFrame *framePtr = iPtr->varFramePtr;
957 CallContext *contextPtr;
961 #define CurrentlyInvoked(contextPtr) \
962 ((contextPtr)->callPtr->chain[(contextPtr)->index])
965 * Start with sanity checks on the calling context and the method context.
968 if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
969 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
970 "%s may only be called from inside a method",
971 TclGetString(objv[0])));
972 Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL);
976 contextPtr = framePtr->clientData;
979 * Now we do "conventional" argument parsing for a while. Note that no
980 * subcommand takes arguments.
984 Tcl_WrongNumArgs(interp, 1, objv, "subcommand");
986 } else if (objc == 1) {
988 } else if (Tcl_GetIndexFromObj(interp, objv[1], subcmds, "subcommand", 0,
993 switch ((enum SelfCmds) index) {
995 Tcl_SetObjResult(interp, TclOOObjectName(interp, contextPtr->oPtr));
998 Tcl_SetObjResult(interp, Tcl_NewStringObj(
999 contextPtr->oPtr->namespacePtr->fullName,-1));
1002 Class *clsPtr = CurrentlyInvoked(contextPtr).mPtr->declaringClassPtr;
1004 if (clsPtr == NULL) {
1005 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1006 "method not defined by a class", -1));
1007 Tcl_SetErrorCode(interp, "TCL", "OO", "UNMATCHED_CONTEXT", NULL);
1011 Tcl_SetObjResult(interp, TclOOObjectName(interp, clsPtr->thisPtr));
1015 if (contextPtr->callPtr->flags & CONSTRUCTOR) {
1016 Tcl_SetObjResult(interp, contextPtr->oPtr->fPtr->constructorName);
1017 } else if (contextPtr->callPtr->flags & DESTRUCTOR) {
1018 Tcl_SetObjResult(interp, contextPtr->oPtr->fPtr->destructorName);
1020 Tcl_SetObjResult(interp,
1021 CurrentlyInvoked(contextPtr).mPtr->namePtr);
1025 if (!CurrentlyInvoked(contextPtr).isFilter) {
1026 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1027 "not inside a filtering context", -1));
1028 Tcl_SetErrorCode(interp, "TCL", "OO", "UNMATCHED_CONTEXT", NULL);
1031 struct MInvoke *miPtr = &CurrentlyInvoked(contextPtr);
1035 if (miPtr->filterDeclarer != NULL) {
1036 oPtr = miPtr->filterDeclarer->thisPtr;
1039 oPtr = contextPtr->oPtr;
1043 result[0] = TclOOObjectName(interp, oPtr);
1044 result[1] = Tcl_NewStringObj(type, -1);
1045 result[2] = miPtr->mPtr->namePtr;
1046 Tcl_SetObjResult(interp, Tcl_NewListObj(3, result));
1050 if ((framePtr->callerVarPtr == NULL) ||
1051 !(framePtr->callerVarPtr->isProcCallFrame & FRAME_IS_METHOD)){
1052 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1053 "caller is not an object", -1));
1054 Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL);
1057 CallContext *callerPtr = framePtr->callerVarPtr->clientData;
1058 Method *mPtr = callerPtr->callPtr->chain[callerPtr->index].mPtr;
1059 Object *declarerPtr;
1061 if (mPtr->declaringClassPtr != NULL) {
1062 declarerPtr = mPtr->declaringClassPtr->thisPtr;
1063 } else if (mPtr->declaringObjectPtr != NULL) {
1064 declarerPtr = mPtr->declaringObjectPtr;
1067 * This should be unreachable code.
1070 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1071 "method without declarer!", -1));
1075 result[0] = TclOOObjectName(interp, declarerPtr);
1076 result[1] = TclOOObjectName(interp, callerPtr->oPtr);
1077 if (callerPtr->callPtr->flags & CONSTRUCTOR) {
1078 result[2] = declarerPtr->fPtr->constructorName;
1079 } else if (callerPtr->callPtr->flags & DESTRUCTOR) {
1080 result[2] = declarerPtr->fPtr->destructorName;
1082 result[2] = mPtr->namePtr;
1084 Tcl_SetObjResult(interp, Tcl_NewListObj(3, result));
1088 if (contextPtr->index < contextPtr->callPtr->numChain-1) {
1090 contextPtr->callPtr->chain[contextPtr->index+1].mPtr;
1091 Object *declarerPtr;
1093 if (mPtr->declaringClassPtr != NULL) {
1094 declarerPtr = mPtr->declaringClassPtr->thisPtr;
1095 } else if (mPtr->declaringObjectPtr != NULL) {
1096 declarerPtr = mPtr->declaringObjectPtr;
1099 * This should be unreachable code.
1102 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1103 "method without declarer!", -1));
1107 result[0] = TclOOObjectName(interp, declarerPtr);
1108 if (contextPtr->callPtr->flags & CONSTRUCTOR) {
1109 result[1] = declarerPtr->fPtr->constructorName;
1110 } else if (contextPtr->callPtr->flags & DESTRUCTOR) {
1111 result[1] = declarerPtr->fPtr->destructorName;
1113 result[1] = mPtr->namePtr;
1115 Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
1119 if (!CurrentlyInvoked(contextPtr).isFilter) {
1120 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1121 "not inside a filtering context", -1));
1122 Tcl_SetErrorCode(interp, "TCL", "OO", "UNMATCHED_CONTEXT", NULL);
1126 Object *declarerPtr;
1129 for (i=contextPtr->index ; i<contextPtr->callPtr->numChain ; i++){
1130 if (!contextPtr->callPtr->chain[i].isFilter) {
1134 if (i == contextPtr->callPtr->numChain) {
1135 Tcl_Panic("filtering call chain without terminal non-filter");
1137 mPtr = contextPtr->callPtr->chain[i].mPtr;
1138 if (mPtr->declaringClassPtr != NULL) {
1139 declarerPtr = mPtr->declaringClassPtr->thisPtr;
1140 } else if (mPtr->declaringObjectPtr != NULL) {
1141 declarerPtr = mPtr->declaringObjectPtr;
1144 * This should be unreachable code.
1147 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1148 "method without declarer!", -1));
1151 result[0] = TclOOObjectName(interp, declarerPtr);
1152 result[1] = mPtr->namePtr;
1153 Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
1157 result[0] = TclOORenderCallChain(interp, contextPtr->callPtr);
1158 TclNewIntObj(result[1], contextPtr->index);
1159 Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
1166 * ----------------------------------------------------------------------
1170 * Implementation of the [oo::copy] command, which clones an object (but
1171 * not its namespace). Note that no constructors are called during this
1174 * ----------------------------------------------------------------------
1179 ClientData clientData,
1182 Tcl_Obj *const *objv)
1184 Tcl_Object oPtr, o2Ptr;
1186 if (objc < 2 || objc > 4) {
1187 Tcl_WrongNumArgs(interp, 1, objv,
1188 "sourceName ?targetName? ?targetNamespace?");
1192 oPtr = Tcl_GetObjectFromObj(interp, objv[1]);
1198 * Create a cloned object of the correct class. Note that constructors are
1199 * not called. Also note that we must resolve the object name ourselves
1200 * because we do not want to create the object in the current namespace,
1201 * but rather in the context of the namespace of the caller of the overall
1202 * [oo::define] command.
1206 o2Ptr = Tcl_CopyObjectInstance(interp, oPtr, NULL, NULL);
1208 const char *name, *namespaceName;
1210 name = TclGetString(objv[2]);
1211 if (name[0] == '\0') {
1216 * Choose a unique namespace name if the user didn't supply one.
1219 namespaceName = NULL;
1221 namespaceName = TclGetString(objv[3]);
1223 if (namespaceName[0] == '\0') {
1224 namespaceName = NULL;
1225 } else if (Tcl_FindNamespace(interp, namespaceName, NULL,
1227 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1228 "%s refers to an existing namespace", namespaceName));
1233 o2Ptr = Tcl_CopyObjectInstance(interp, oPtr, name, namespaceName);
1236 if (o2Ptr == NULL) {
1241 * Return the name of the cloned object.
1244 Tcl_SetObjResult(interp, TclOOObjectName(interp, (Object *) o2Ptr));