Itcl - the [incr Tcl] extension

Check-in [23b1e4cd73]
Login

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

Overview
Comment: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].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 23b1e4cd73c0fe71b1c200d32dae88969b712f86
User & Date: dgp 2017-07-07 18:48:31
Context
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
2017-06-29
11:51
merge bug fixes from 4.0.6 check-in: fa9bab3e83 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
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,







>
>







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,

Changes to generic/itclMigrate2TclCore.c.

147
148
149
150
151
152
153













154
155
156
157
158
159
160
     */
    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;







>
>
>
>
>
>
>
>
>
>
>
>
>







147
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
     */
    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;

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
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);
    }
}







>

>












>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|







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);
    }
}