1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/*
* tclProc.c --
*
* This file contains routines that implement Tcl procedures,
* including the "proc" and "uplevel" commands.
*
* Copyright (c) 1987-1993 The Regents of the University of California.
* Copyright (c) 1994-1998 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tclProc.c,v 1.66 2004/11/25 16:37:15 dkf Exp $
*/
#include "tclInt.h"
#include "tclCompile.h"
/*
* Prototypes for static functions in this file
|
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/*
* tclProc.c --
*
* This file contains routines that implement Tcl procedures,
* including the "proc" and "uplevel" commands.
*
* Copyright (c) 1987-1993 The Regents of the University of California.
* Copyright (c) 1994-1998 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tclProc.c,v 1.67 2004/12/10 13:09:15 msofer Exp $
*/
#include "tclInt.h"
#include "tclCompile.h"
/*
* Prototypes for static functions in this file
|
| ︙ | | | ︙ | |
337
338
339
340
341
342
343
344
345
346
347
348
349
350
|
goto procError;
}
localPtr = procPtr->firstLocalPtr;
} else {
procPtr->numArgs = numArgs;
procPtr->numCompiledLocals = numArgs;
}
for (i = 0; i < numArgs; i++) {
int fieldCount, nameLength, valueLength;
CONST char **fieldValues;
/*
* Now divide the specifier up into name and default.
*/
|
>
|
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
|
goto procError;
}
localPtr = procPtr->firstLocalPtr;
} else {
procPtr->numArgs = numArgs;
procPtr->numCompiledLocals = numArgs;
}
for (i = 0; i < numArgs; i++) {
int fieldCount, nameLength, valueLength;
CONST char **fieldValues;
/*
* Now divide the specifier up into name and default.
*/
|
| ︙ | | | ︙ | |
441
442
443
444
445
446
447
448
449
450
451
452
453
454
|
Tcl_AppendResult(interp, "procedure \"", procName,
"\": formal parameter \"", fieldValues[0],
"\" has default value inconsistent with precompiled body",
(char *) NULL);
ckfree((char *) fieldValues);
goto procError;
}
}
localPtr = localPtr->nextPtr;
} else {
/*
* Allocate an entry in the runtime procedure frame's array of
* local variables for the argument.
|
>
>
>
>
>
>
|
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
|
Tcl_AppendResult(interp, "procedure \"", procName,
"\": formal parameter \"", fieldValues[0],
"\" has default value inconsistent with precompiled body",
(char *) NULL);
ckfree((char *) fieldValues);
goto procError;
}
if ((i == numArgs - 1)
&& (localPtr->nameLength == 4)
&& (localPtr->name[0] == 'a')
&& (strcmp(localPtr->name, "args") == 0)) {
localPtr->flags |= VAR_IS_ARGS;
}
}
localPtr = localPtr->nextPtr;
} else {
/*
* Allocate an entry in the runtime procedure frame's array of
* local variables for the argument.
|
| ︙ | | | ︙ | |
473
474
475
476
477
478
479
480
481
482
483
484
485
486
|
localPtr->defValuePtr =
Tcl_NewStringObj(fieldValues[1], valueLength);
Tcl_IncrRefCount(localPtr->defValuePtr);
} else {
localPtr->defValuePtr = NULL;
}
strcpy(localPtr->name, fieldValues[0]);
}
ckfree((char *) fieldValues);
}
*procPtrPtr = procPtr;
ckfree((char *) argArray);
|
>
>
>
>
>
>
|
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
|
localPtr->defValuePtr =
Tcl_NewStringObj(fieldValues[1], valueLength);
Tcl_IncrRefCount(localPtr->defValuePtr);
} else {
localPtr->defValuePtr = NULL;
}
strcpy(localPtr->name, fieldValues[0]);
if ((i == numArgs - 1)
&& (localPtr->nameLength == 4)
&& (localPtr->name[0] == 'a')
&& (strcmp(localPtr->name, "args") == 0)) {
localPtr->flags |= VAR_IS_ARGS;
}
}
ckfree((char *) fieldValues);
}
*procPtrPtr = procPtr;
ckfree((char *) argArray);
|
| ︙ | | | ︙ | |
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
|
register Proc *procPtr = (Proc *) clientData;
Namespace *nsPtr = procPtr->cmdPtr->nsPtr;
CallFrame frame;
register CallFrame *framePtr = &frame;
register Var *varPtr;
register CompiledLocal *localPtr;
char *procName;
int nameLen, localCt, numArgs, argCt, i, result;
/*
* This procedure generates an array "compiledLocals" that holds the
* storage for local variables. It starts out with stack-allocated space
* but uses dynamically-allocated storage if needed.
*/
|
|
|
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
|
register Proc *procPtr = (Proc *) clientData;
Namespace *nsPtr = procPtr->cmdPtr->nsPtr;
CallFrame frame;
register CallFrame *framePtr = &frame;
register Var *varPtr;
register CompiledLocal *localPtr;
char *procName;
int nameLen, localCt, numArgs, argCt, i, imax, result;
/*
* This procedure generates an array "compiledLocals" that holds the
* storage for local variables. It starts out with stack-allocated space
* but uses dynamically-allocated storage if needed.
*/
|
| ︙ | | | ︙ | |
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
|
* numArgs entries in both the Proc structure's local variable list and
* the call frame's local variable array.
*/
numArgs = procPtr->numArgs;
varPtr = framePtr->compiledLocals;
localPtr = procPtr->firstLocalPtr;
argCt = objc;
for (i = 1, argCt -= 1; i <= numArgs; i++, argCt--) {
if (!TclIsVarArgument(localPtr)) {
Tcl_Panic("TclObjInterpProc: local variable %s is not argument but should be",
localPtr->name);
return TCL_ERROR;
}
if (TclIsVarTemporary(localPtr)) {
Tcl_Panic("TclObjInterpProc: local variable %d is temporary but should be an argument", i);
return TCL_ERROR;
}
/*
* Handle the special case of the last formal being "args". When
* it occurs, assign it a list consisting of all the remaining
* actual arguments.
*/
if ((i == numArgs) && ((localPtr->name[0] == 'a')
&& (strcmp(localPtr->name, "args") == 0))) {
Tcl_Obj *listPtr = Tcl_NewListObj(argCt, &(objv[i]));
varPtr->value.objPtr = listPtr;
Tcl_IncrRefCount(listPtr); /* local var is a reference */
TclClearVarUndefined(varPtr);
argCt = 0;
break; /* done processing args */
} else if (argCt > 0) {
Tcl_Obj *objPtr = objv[i];
varPtr->value.objPtr = objPtr;
TclClearVarUndefined(varPtr);
Tcl_IncrRefCount(objPtr); /* since the local variable now has
* another reference to object. */
} else if (localPtr->defValuePtr != NULL) {
Tcl_Obj *objPtr = localPtr->defValuePtr;
varPtr->value.objPtr = objPtr;
TclClearVarUndefined(varPtr);
Tcl_IncrRefCount(objPtr); /* since the local variable now has
* another reference to object. */
} else {
goto incorrectArgs;
}
varPtr++;
localPtr = localPtr->nextPtr;
}
if (argCt > 0) {
Tcl_Obj **desiredObjs, *argObj;
incorrectArgs:
/*
* Build up desired argument list for Tcl_WrongNumArgs
*/
desiredObjs = (Tcl_Obj **)
ckalloc(sizeof(Tcl_Obj *) * (unsigned)(numArgs+1));
|
|
|
|
|
|
|
<
<
<
|
|
>
|
<
|
|
<
<
<
<
<
<
<
<
<
<
|
|
<
|
<
>
>
>
>
>
>
>
>
|
<
|
<
>
>
>
|
>
>
|
>
>
|
>
>
>
>
|
>
>
>
>
>
>
>
>
|
<
|
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
|
* numArgs entries in both the Proc structure's local variable list and
* the call frame's local variable array.
*/
numArgs = procPtr->numArgs;
varPtr = framePtr->compiledLocals;
localPtr = procPtr->firstLocalPtr;
argCt = objc-1; /* set it to the number of args to the proc */
if (numArgs == 0) {
if (argCt) {
goto incorrectArgs;
} else {
goto runProc;
}
}
imax = ((argCt < numArgs - 1)? argCt : (numArgs - 1));
for (i = 1; i <= imax; i++) {
/*
* "Normal" arguments; last formal is special, depends on
* it being 'args'.
*/
Tcl_Obj *objPtr = objv[i];
varPtr->value.objPtr = objPtr;
Tcl_IncrRefCount(objPtr); /* local var is a reference */
varPtr++;
localPtr = localPtr->nextPtr;
}
for (; i < numArgs; i++) {
/*
* This loop is entered if argCt < (numArgs-1).
* Set default values; last formal is special.
*/
if (localPtr->defValuePtr != NULL) {
Tcl_Obj *objPtr = localPtr->defValuePtr;
varPtr->value.objPtr = objPtr;
Tcl_IncrRefCount(objPtr); /* local var is a reference */
varPtr++;
localPtr = localPtr->nextPtr;
} else {
goto incorrectArgs;
}
}
/*
* When we get here, the last formal argument remains
* to be defined: localPtr and varPtr point to the last
* argument to be initialized.
*/
if (localPtr->flags & VAR_IS_ARGS) {
Tcl_Obj *listPtr = Tcl_NewListObj(objc-numArgs, &(objv[numArgs]));
varPtr->value.objPtr = listPtr;
Tcl_IncrRefCount(listPtr); /* local var is a reference */
} else if (argCt == numArgs) {
Tcl_Obj *objPtr = objv[numArgs];
varPtr->value.objPtr = objPtr;
Tcl_IncrRefCount(objPtr); /* local var is a reference */
} else if ((argCt < numArgs) && (localPtr->defValuePtr != NULL)) {
Tcl_Obj *objPtr = localPtr->defValuePtr;
varPtr->value.objPtr = objPtr;
Tcl_IncrRefCount(objPtr); /* local var is a reference */
} else {
Tcl_Obj **desiredObjs, *argObj;
incorrectArgs:
/*
* Build up desired argument list for Tcl_WrongNumArgs
*/
desiredObjs = (Tcl_Obj **)
ckalloc(sizeof(Tcl_Obj *) * (unsigned)(numArgs+1));
|
| ︙ | | | ︙ | |
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
|
goto procDone;
}
/*
* Invoke the commands in the procedure's body.
*/
#ifdef TCL_COMPILE_DEBUG
if (tclTraceExec >= 1) {
fprintf(stdout, "Calling proc ");
for (i = 0; i < objc; i++) {
TclPrintObject(stdout, objv[i], 15);
fprintf(stdout, " ");
}
|
>
|
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
|
goto procDone;
}
/*
* Invoke the commands in the procedure's body.
*/
runProc:
#ifdef TCL_COMPILE_DEBUG
if (tclTraceExec >= 1) {
fprintf(stdout, "Calling proc ");
for (i = 0; i < objc; i++) {
TclPrintObject(stdout, objv[i], 15);
fprintf(stdout, " ");
}
|
| ︙ | | | ︙ | |
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
|
Tcl_AppendToObj(message, ")", -1);
TclAppendObjToErrorInfo(interp, message);
Tcl_DecrRefCount(message);
}
return result;
}
} else if (codePtr->nsEpoch != nsPtr->resolverEpoch) {
register CompiledLocal *localPtr;
/*
* The resolver epoch has changed, but we only need to invalidate
* the resolver cache.
*/
for (localPtr = procPtr->firstLocalPtr; localPtr != NULL;
localPtr = localPtr->nextPtr) {
localPtr->flags &= ~(VAR_RESOLVED);
if (localPtr->resolveInfo) {
if (localPtr->resolveInfo->deleteProc) {
localPtr->resolveInfo->deleteProc(localPtr->resolveInfo);
} else {
ckfree((char*)localPtr->resolveInfo);
}
localPtr->resolveInfo = NULL;
}
}
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
<
<
<
<
|
<
<
<
<
<
<
<
<
<
|
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
|
Tcl_AppendToObj(message, ")", -1);
TclAppendObjToErrorInfo(interp, message);
Tcl_DecrRefCount(message);
}
return result;
}
} else if (codePtr->nsEpoch != nsPtr->resolverEpoch) {
/*
* The resolver epoch has changed, but we only need to invalidate
* the resolver cache.
*/
codePtr->flags |= TCL_BYTECODE_RESOLVE_VARS;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | | | ︙ | |