Itcl - the [incr Tcl] extension

Check-in [3e21a7bc42]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Revert last commit and take the better approach. Stop ItclObjectCmd from going poking into Tcl's areas of the CallFrame. Use Itcl's own mechanisms for fetching proper context information.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3e21a7bc42753ccf705e10c6bae59cf5a4e0d424
User & Date: dgp 2017-07-20 20:54:22
Context
2017-07-28
16:42
Add routines to manage ItclObject context. Add routines to directly access instance variables. Revise instance variable access to agree with class resolution rules. check-in: 0354a67b77 user: dgp tags: trunk, itcl-4-1-0
2017-07-25
20:33
Getting utilities exposed needed by Itk 4.1 check-in: cbc674f840 user: dgp tags: experiment
2017-07-20
20:54
Revert last commit and take the better approach. Stop ItclObjectCmd from going poking into Tcl's areas of the CallFrame. Use Itcl's own mechanisms for fetching proper context information. check-in: 3e21a7bc42 user: dgp tags: trunk
2017-07-07
18:48
Reproduce TclOO's practice of sticking context info in the clientdata of the current frame. This is needed because ItclObjectCommand goes poking in there expecting to find it. One internals intrusion leads to more. Ugly! But for now it fixes [Itk Bug 38744a21a0]. check-in: 23b1e4cd73 user: dgp tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/itclInt.h.

694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
MODULE_SCOPE Tcl_Var Itcl_VarAliasProc(Tcl_Interp *interp,
        Tcl_Namespace *nsPtr, const char *VarName, ClientData clientData);
MODULE_SCOPE int ItclIsClass(Tcl_Interp *interp, Tcl_Command cmd);
MODULE_SCOPE int ItclCheckCallMethod(ClientData clientData, Tcl_Interp *interp,
        Tcl_ObjectContext contextPtr, Tcl_CallFrame *framePtr, int *isFinished);
MODULE_SCOPE int ItclAfterCallMethod(ClientData clientData, Tcl_Interp *interp,
        Tcl_ObjectContext contextPtr, Tcl_Namespace *nsPtr, int result);
MODULE_SCOPE int ItclSetCallFrameClientData(Tcl_Interp *interp,
	ClientData clientData);
MODULE_SCOPE void ItclReportObjectUsage(Tcl_Interp *interp,
        ItclObject *contextIoPtr, Tcl_Namespace *callerNsPtr,
	Tcl_Namespace *contextNsPtr);
MODULE_SCOPE int ItclMapMethodNameProc(Tcl_Interp *interp, Tcl_Object oPtr,
        Tcl_Class *startClsPtr, Tcl_Obj *methodObj);
MODULE_SCOPE int ItclCreateArgList(Tcl_Interp *interp, const char *str,
        int *argcPtr, int *maxArgcPtr, Tcl_Obj **usagePtr,







<
<







694
695
696
697
698
699
700


701
702
703
704
705
706
707
MODULE_SCOPE Tcl_Var Itcl_VarAliasProc(Tcl_Interp *interp,
        Tcl_Namespace *nsPtr, const char *VarName, ClientData clientData);
MODULE_SCOPE int ItclIsClass(Tcl_Interp *interp, Tcl_Command cmd);
MODULE_SCOPE int ItclCheckCallMethod(ClientData clientData, Tcl_Interp *interp,
        Tcl_ObjectContext contextPtr, Tcl_CallFrame *framePtr, int *isFinished);
MODULE_SCOPE int ItclAfterCallMethod(ClientData clientData, Tcl_Interp *interp,
        Tcl_ObjectContext contextPtr, Tcl_Namespace *nsPtr, int result);


MODULE_SCOPE void ItclReportObjectUsage(Tcl_Interp *interp,
        ItclObject *contextIoPtr, Tcl_Namespace *callerNsPtr,
	Tcl_Namespace *contextNsPtr);
MODULE_SCOPE int ItclMapMethodNameProc(Tcl_Interp *interp, Tcl_Object oPtr,
        Tcl_Class *startClsPtr, Tcl_Obj *methodObj);
MODULE_SCOPE int ItclCreateArgList(Tcl_Interp *interp, const char *str,
        int *argcPtr, int *maxArgcPtr, Tcl_Obj **usagePtr,

Changes to generic/itclMigrate2TclCore.c.

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
    CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
    if (framePtr == NULL) {
        return NULL;
    }
    return framePtr->clientData;
}

int
ItclSetCallFrameClientData(
    Tcl_Interp *interp,
    ClientData clientData)
{
    CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
    if (framePtr == NULL) {
        return TCL_ERROR;
    }
    framePtr->clientData = clientData;
    return TCL_OK;
}

int
Itcl_SetCallFrameNamespace(
    Tcl_Interp *interp,
    Tcl_Namespace *nsPtr)
{
    CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
    if (framePtr == NULL) {







<
<
<
<
<
<
<
<
<
<
<
<
<







148
149
150
151
152
153
154













155
156
157
158
159
160
161
    CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
    if (framePtr == NULL) {
        return NULL;
    }
    return framePtr->clientData;
}














int
Itcl_SetCallFrameNamespace(
    Tcl_Interp *interp,
    Tcl_Namespace *nsPtr)
{
    CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
    if (framePtr == NULL) {

Changes to generic/itclObject.c.

2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
    int objc,
    Tcl_Obj *const *objv)
{
    Tcl_Obj *methodNamePtr;
    Tcl_Obj **newObjv;
    Tcl_DString buffer;
    Tcl_Obj *myPtr;
    ItclObjectInfo *infoPtr;
    ItclMemberFunc *imPtr;
    ItclClass *iclsPtr;
    Itcl_ListElem *elem;
    ItclClass *basePtr;
    void *callbackPtr;
    const char *className;
    const char *tail;







<







2805
2806
2807
2808
2809
2810
2811

2812
2813
2814
2815
2816
2817
2818
    int objc,
    Tcl_Obj *const *objv)
{
    Tcl_Obj *methodNamePtr;
    Tcl_Obj **newObjv;
    Tcl_DString buffer;
    Tcl_Obj *myPtr;

    ItclMemberFunc *imPtr;
    ItclClass *iclsPtr;
    Itcl_ListElem *elem;
    ItclClass *basePtr;
    void *callbackPtr;
    const char *className;
    const char *tail;
2827
2828
2829
2830
2831
2832
2833


2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861

2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878

    incr = 0;
    found = 0;
    isDirectCall = 0;
    myPtr = NULL;
    imPtr = (ItclMemberFunc *)clientData;
    iclsPtr = imPtr->iclsPtr;


    infoPtr = imPtr->iclsPtr->infoPtr;
    if ((oPtr == NULL) && (clsPtr == NULL)) {
         isDirectCall = 1;
    }
    if (oPtr == NULL) {
	ClientData clientData2;
	if ((imPtr->flags & ITCL_COMMON)
	        && (imPtr->codePtr != NULL)
	        && !(imPtr->codePtr->flags & ITCL_BUILTIN)) {
	    result = Itcl_InvokeProcedureMethod(imPtr->tmPtr, interp,
	            objc, objv);
            return result;
	}
	oPtr = NULL;
	clientData2 = Itcl_GetCallFrameClientData(interp);
	if ((clientData2 == NULL) && (oPtr == NULL)) {
	    if (((imPtr->codePtr != NULL)
	            && (imPtr->codePtr->flags & ITCL_BUILTIN))) {
	        result = Itcl_InvokeProcedureMethod(imPtr->tmPtr, interp,
	                objc, objv);
                return result;
	    }
	    if (infoPtr->currIoPtr != NULL) {
	        /* if we want to call methods in the constructor for example
	         * config* methods, clientData
	         * is still NULL, but we can use infoPtr->currIoPtr
	         * for getting the TclOO object ptr
	         */

	        oPtr = infoPtr->currIoPtr->oPtr;
	    } else {
	        Tcl_AppendResult(interp,
	                "ItclObjectCmd cannot get context object (NULL)", NULL);
	        return TCL_ERROR;
	    }
	}
	if (oPtr == NULL) {
            oPtr = Tcl_ObjectContextObject((Tcl_ObjectContext)clientData2);
        }
    }
    methodNamePtr = NULL;
    if (objv[0] != NULL) {
        Itcl_ParseNamespPath(Tcl_GetString(objv[0]), &buffer,
	        &className, &tail);
        if (className != NULL) {
            methodNamePtr = Tcl_NewStringObj(tail, -1);







>
>
|
|
|
|
<
<







<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
>
|
|
|
<
<
|
<
<
<
<







2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838


2839
2840
2841
2842
2843
2844
2845








2846






2847
2848
2849
2850


2851




2852
2853
2854
2855
2856
2857
2858

    incr = 0;
    found = 0;
    isDirectCall = 0;
    myPtr = NULL;
    imPtr = (ItclMemberFunc *)clientData;
    iclsPtr = imPtr->iclsPtr;
    if (oPtr == NULL) {
	ItclClass *icPtr = NULL;
	ItclObject *ioPtr = NULL;

	isDirectCall = (clsPtr == NULL);



	if ((imPtr->flags & ITCL_COMMON)
	        && (imPtr->codePtr != NULL)
	        && !(imPtr->codePtr->flags & ITCL_BUILTIN)) {
	    result = Itcl_InvokeProcedureMethod(imPtr->tmPtr, interp,
	            objc, objv);
            return result;
	}















	if (TCL_OK == Itcl_GetContext(interp, &icPtr, &ioPtr)) {
	    oPtr = ioPtr ? ioPtr->oPtr : icPtr->oPtr;
	} else {
	    Tcl_Panic("No Context");


	}




    }
    methodNamePtr = NULL;
    if (objv[0] != NULL) {
        Itcl_ParseNamespPath(Tcl_GetString(objv[0]), &buffer,
	        &className, &tail);
        if (className != NULL) {
            methodNamePtr = Tcl_NewStringObj(tail, -1);

Changes to generic/itclParse.c.

670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
CallAfterCallMethod(
    ClientData data[],
    Tcl_Interp *interp,
    int result)
{
    ClientData clientData = data[0];
    Tcl_ObjectContext context = data[1];
    ClientData save = data[2];

    ItclSetCallFrameClientData(interp, save);
    return ItclAfterCallMethod(clientData, interp, context, NULL, result);
}

static int
ObjCallProc(
    ClientData clientData,
    Tcl_Interp *interp,
    Tcl_ObjectContext context,
    int objc,
    Tcl_Obj *const *objv)
{
    ItclMemberFunc *imPtr = (ItclMemberFunc *)clientData;
    Tcl_ObjectContext save = Itcl_GetCallFrameClientData(interp);

    if (TCL_ERROR == ItclCheckCallMethod(clientData, interp, context,
	    NULL, NULL)) {
	return TCL_ERROR;
    }

    /*
     * This is an ugly workaround.  Someday Itcl 4 should be generally
     * better designed to replace such nastiness.
     *
     * This exists to fix [Itk Bug 38744a21a0] in Itk 4.1.  Starting
     * with Itcl 4.1, we have the itclObjMethodType to attach Itcl
     * methods coded as C routines to the TclOO foundation.  Trouble
     * happens when one of those C routines calls Tcl*Eval*() and
     * expects an Itcl object context to be in control.
     *
     * The Itcl routine ItclObjectCommand goes looking directly at
     * the clientData of the interp's current frame to get the
     * controlling Tcl_ObjectContext.  This is a horrifying internals
     * intrusion that's been inherited.  Since that routine is expecting
     * to find what's been left there by Tcl's procedure method machinery,
     * we have to duplicate it here in our own method invocation machinery.
     *
     * Note that a lot of Itcl itself could be implemented via direct
     * dispatch to C routines, but even more ugly somersaults are turned
     * to fake passing through procedure methods instead.  This might
     * be a first step to untangling some of those awful knots too.
     */

    if (TCL_OK != ItclSetCallFrameClientData(interp, (ClientData) context)) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"ObjCallProc: FAILED to set callframe context"));
	return TCL_ERROR;
    }

    Tcl_NRAddCallback(interp, CallAfterCallMethod, clientData, context,
	    save, NULL);

    if ((imPtr->flags & ITCL_COMMON) == 0) {
	return Itcl_ExecMethod(clientData, interp, objc-1, objv+1);
    } else {
	return Itcl_ExecProc(clientData, interp, objc-1, objv+1);
    }
}







<

<












<






<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

|







670
671
672
673
674
675
676

677

678
679
680
681
682
683
684
685
686
687
688
689

690
691
692
693
694
695





























696
697
698
699
700
701
702
703
704
CallAfterCallMethod(
    ClientData data[],
    Tcl_Interp *interp,
    int result)
{
    ClientData clientData = data[0];
    Tcl_ObjectContext context = data[1];



    return ItclAfterCallMethod(clientData, interp, context, NULL, result);
}

static int
ObjCallProc(
    ClientData clientData,
    Tcl_Interp *interp,
    Tcl_ObjectContext context,
    int objc,
    Tcl_Obj *const *objv)
{
    ItclMemberFunc *imPtr = (ItclMemberFunc *)clientData;


    if (TCL_ERROR == ItclCheckCallMethod(clientData, interp, context,
	    NULL, NULL)) {
	return TCL_ERROR;
    }






























    Tcl_NRAddCallback(interp, CallAfterCallMethod, clientData, context,
	    NULL, NULL);

    if ((imPtr->flags & ITCL_COMMON) == 0) {
	return Itcl_ExecMethod(clientData, interp, objc-1, objv+1);
    } else {
	return Itcl_ExecProc(clientData, interp, objc-1, objv+1);
    }
}