Attachment "apply3.patch" to
ticket [944803ffff]
added by
msofer
2006-01-12 05:33:00.
Index: generic/tclBasic.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBasic.c,v
retrieving revision 1.187
diff -u -r1.187 tclBasic.c
--- generic/tclBasic.c 11 Jan 2006 17:34:53 -0000 1.187
+++ generic/tclBasic.c 11 Jan 2006 22:27:02 -0000
@@ -105,6 +105,7 @@
*/
{"append", Tcl_AppendObjCmd, TclCompileAppendCmd, 1},
+ {"apply", Tcl_ApplyObjCmd, NULL, 1},
{"array", Tcl_ArrayObjCmd, NULL, 1},
{"binary", Tcl_BinaryObjCmd, NULL, 1},
{"break", Tcl_BreakObjCmd, TclCompileBreakCmd, 1},
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.264
diff -u -r1.264 tclInt.h
--- generic/tclInt.h 27 Dec 2005 20:14:09 -0000 1.264
+++ generic/tclInt.h 11 Jan 2006 22:27:04 -0000
@@ -2240,6 +2240,9 @@
MODULE_SCOPE int Tcl_AppendObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *CONST objv[]);
+MODULE_SCOPE int Tcl_ApplyObjCmd(ClientData clientData,
+ Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[]);
MODULE_SCOPE int Tcl_ArrayObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *CONST objv[]);
Index: generic/tclProc.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclProc.c,v
retrieving revision 1.83
diff -u -r1.83 tclProc.c
--- generic/tclProc.c 13 Dec 2005 22:43:18 -0000 1.83
+++ generic/tclProc.c 11 Jan 2006 22:27:05 -0000
@@ -6,6 +6,7 @@
*
* Copyright (c) 1987-1993 The Regents of the University of California.
* Copyright (c) 1994-1998 Sun Microsystems, Inc.
+ * Copyright (c) 2004-2006 Miguel Sofer
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -1866,6 +1867,206 @@
}
/*
+ * LAMBDA and APPLY implementation
+ *
+ */
+
+static void DupLambdaInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr,
+ Tcl_Obj *copyPtr));
+static void FreeLambdaInternalRep _ANSI_ARGS_((
+ Tcl_Obj *objPtr));
+static int SetLambdaFromAny _ANSI_ARGS_((Tcl_Interp *interp,
+ Tcl_Obj *objPtr));
+
+Tcl_ObjType tclLambdaType = {
+ "lambda", /* name */
+ FreeLambdaInternalRep, /* freeIntRepProc */
+ DupLambdaInternalRep, /* dupIntRepProc */
+ (Tcl_UpdateStringProc *) NULL, /* updateStringProc */
+ SetLambdaFromAny /* setFromAnyProc */
+};
+
+/*
+ * a Lambda Tcl_Obj has the form
+ *
+ * ptr1 is a *Proc: pointer to a proc structure
+ * ptr2 is a *Tcl_Obj: the lambda's namespace
+ */
+
+static void
+DupLambdaInternalRep(srcPtr, copyPtr)
+ Tcl_Obj *srcPtr; /* Object with internal rep to copy. */
+ register Tcl_Obj *copyPtr; /* Object with internal rep to set. */
+{
+ Proc *procPtr = (Proc *) srcPtr->internalRep.twoPtrValue.ptr1;
+ Tcl_Obj *nsObjPtr = (Tcl_Obj *) srcPtr->internalRep.twoPtrValue.ptr2;
+
+ copyPtr->internalRep.twoPtrValue.ptr1 = (VOID *) procPtr;
+ copyPtr->internalRep.twoPtrValue.ptr2 = (VOID *) nsObjPtr;
+
+ procPtr->refCount++;
+ Tcl_IncrRefCount(nsObjPtr);
+ copyPtr->typePtr = &tclLambdaType;
+}
+
+static void
+FreeLambdaInternalRep(objPtr)
+ register Tcl_Obj *objPtr; /* CmdName object with internal
+ * representation to free. */
+{
+ Proc *procPtr = (Proc *) objPtr->internalRep.twoPtrValue.ptr1;
+ Tcl_Obj *nsObjPtr = (Tcl_Obj *) objPtr->internalRep.twoPtrValue.ptr2;
+
+ procPtr->refCount--;
+ if (procPtr->refCount == 0) {
+ TclProcCleanupProc(procPtr);
+ }
+ TclDecrRefCount(nsObjPtr);
+}
+
+
+static int
+SetLambdaFromAny(interp, objPtr)
+ Tcl_Interp *interp; /* Used for error reporting if not NULL. */
+ register Tcl_Obj *objPtr; /* The object to convert. */
+{
+ char *name;
+ Tcl_Obj *argsPtr, *bodyPtr, *nsObjPtr, **objv, *errPtr;
+ int objc;
+ Proc *procPtr;
+ int result;
+
+ /*
+ * Convert objPtr to list type first; if it cannot be
+ * converted, or if its length is not 2, then it cannot
+ * be converted to tclLambdaType.
+ */
+
+ result = Tcl_ListObjGetElements(interp, objPtr, &objc, &objv);
+ if ((result != TCL_OK) || ((objc != 2) && (objc != 3))) {
+ errPtr = Tcl_NewStringObj("can't interpret \"",-1);
+ Tcl_IncrRefCount(errPtr);
+ Tcl_AppendObjToObj(errPtr, objPtr);
+ Tcl_AppendToObj(errPtr, "\" as a lambda expression", -1);
+ Tcl_SetObjResult(interp, errPtr);
+ Tcl_DecrRefCount(errPtr);
+ return TCL_ERROR;
+ }
+
+ argsPtr = objv[0];
+ bodyPtr = objv[1];
+
+ /*
+ * Create and initialize the Proc struct. The cmdPtr field is
+ * set to NULL to signal that this is an anonymous function.
+ */
+
+ name = TclGetString(objPtr);
+
+ if (TclCreateProc(interp, /*ignored nsPtr*/ NULL, name, argsPtr,
+ bodyPtr, &procPtr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ procPtr->refCount++;
+ procPtr->cmdPtr = (Command *) NULL;
+
+ /*
+ * Set the namespace for this lambda: given by objv[2] understood
+ * as a global reference, or else global per default.
+ */
+
+ nsObjPtr = Tcl_NewStringObj("::", 2);
+ Tcl_IncrRefCount(nsObjPtr);
+
+ if (objc == 3) {
+ Tcl_AppendObjToObj(nsObjPtr, objv[2]);
+ }
+
+
+ /*
+ * Free the list internalrep of objPtr - this will free argsPtr, but
+ * bodyPtr retains a reference from the Proc structure. Then finish
+ * the conversion to tclLambdaType.
+ */
+
+ objPtr->typePtr->freeIntRepProc(objPtr);
+
+ objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) procPtr;
+ objPtr->internalRep.twoPtrValue.ptr2 = (VOID *) nsObjPtr;
+ objPtr->typePtr = &tclLambdaType;
+ return TCL_OK;
+}
+
+int
+Tcl_ApplyObjCmd(dummy, interp, objc, objv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int objc; /* Number of arguments. */
+ Tcl_Obj *CONST objv[]; /* Argument objects. */
+{
+ Interp *iPtr = (Interp *) interp;
+ Proc *procPtr;
+ Tcl_Obj *lambdaPtr, *nsObjPtr, *errPtr;
+ int result;
+ Command cmd;
+ Tcl_Namespace *nsPtr;
+
+ if (objc < 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "lambdaExpr ?arg1 arg2 ...?");
+ return TCL_ERROR;
+ }
+
+ /*
+ * Set lambdaPtr, convert it to tclLambdaType in the current
+ * interp if necessary.
+ */
+
+ lambdaPtr = objv[1];
+ if (lambdaPtr->typePtr == &tclLambdaType) {
+ procPtr = (Proc *) lambdaPtr->internalRep.twoPtrValue.ptr1;
+ } else {
+ procPtr = (Proc *) NULL;
+ }
+
+ if ((procPtr == NULL) || (procPtr->iPtr != iPtr)) {
+ result = SetLambdaFromAny(interp, lambdaPtr);
+ if (result != TCL_OK) {
+ return result;
+ }
+ procPtr = (Proc *) lambdaPtr->internalRep.twoPtrValue.ptr1;
+ }
+ procPtr->cmdPtr = &cmd;
+
+ /*
+ * Find the namespace where this lambda should run, and
+ * push a call frame for that namespace. Note that
+ * TclObjInterpProc() will pop it.
+ */
+
+ nsObjPtr = (Tcl_Obj *) lambdaPtr->internalRep.twoPtrValue.ptr2;
+ result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr);
+ if (result != TCL_OK) {
+ return result;
+ }
+ if (nsPtr == (Tcl_Namespace *) NULL) {
+ errPtr = Tcl_NewStringObj("cannot find namespace \"",-1);
+ Tcl_IncrRefCount(errPtr);
+ Tcl_AppendObjToObj(errPtr, nsObjPtr);
+ Tcl_AppendToObj(errPtr, "\"", -1);
+ Tcl_SetObjResult(interp, errPtr);
+ Tcl_DecrRefCount(errPtr);
+ return TCL_ERROR;
+ }
+
+ /*
+ cmd = *((Command *) Tcl_GetCommandFromObj(interp, objv[0]));
+ */
+ cmd.nsPtr = (Namespace *) nsPtr;
+
+ return TclObjInterpProc((ClientData) procPtr, interp, objc-1, objv+1);
+}
+
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4