1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/*
* 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.
* 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.
*
* RCS: @(#) $Id: tclProc.c,v 1.121 2007/06/14 21:02:20 msofer 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
21
|
/*
* 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.
* 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.
*
* RCS: @(#) $Id: tclProc.c,v 1.122 2007/06/16 13:48:00 dkf Exp $
*/
#include "tclInt.h"
#include "tclCompile.h"
/*
* Prototypes for static functions in this file
|
| ︙ | | | ︙ | |
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
|
*/
if (iPtr->cmdFramePtr) {
CmdFrame context = *iPtr->cmdFramePtr;
if (context.type == TCL_LOCATION_BC) {
/*
* Retrieve source information from the bytecode, if possible.
* If the information is retrieved successfully, context.type
* will be TCL_LOCATION_SOURCE and the reference held by
* context.data.eval.path will be counted.
*/
TclGetSrcInfoForPc(&context);
} else if (context.type == TCL_LOCATION_SOURCE) {
/*
* The copy into 'context' up above has created another
* reference to 'context.data.eval.path'; account for it.
*/
Tcl_IncrRefCount(context.data.eval.path);
}
if (context.type == TCL_LOCATION_SOURCE) {
/*
* We can account for source location within a proc only
* if the proc body was not created by substitution.
*/
if (context.line
&& (context.nline >= 4) && (context.line[3] >= 0)) {
int isNew;
CmdFrame *cfPtr = (CmdFrame *) ckalloc(sizeof(CmdFrame));
cfPtr->level = -1;
cfPtr->type = context.type;
cfPtr->line = (int *) ckalloc(sizeof(int));
cfPtr->line[0] = context.line[3];
cfPtr->nline = 1;
cfPtr->framePtr = NULL;
cfPtr->nextPtr = NULL;
cfPtr->data.eval.path = context.data.eval.path;
Tcl_IncrRefCount(cfPtr->data.eval.path);
cfPtr->cmd.str.cmd = NULL;
cfPtr->cmd.str.len = 0;
Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->linePBodyPtr,
(char *) procPtr, &isNew),
cfPtr);
}
/*
* 'context' is going out of scope; account for the reference
* that it's holding to the path name.
*/
Tcl_DecrRefCount(context.data.eval.path);
context.data.eval.path = NULL;
}
}
|
|
|
|
>
|
|
<
|
|
|
|
|
|
|
<
|
|
|
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
|
*/
if (iPtr->cmdFramePtr) {
CmdFrame context = *iPtr->cmdFramePtr;
if (context.type == TCL_LOCATION_BC) {
/*
* Retrieve source information from the bytecode, if possible. If
* the information is retrieved successfully, context.type will be
* TCL_LOCATION_SOURCE and the reference held by
* context.data.eval.path will be counted.
*/
TclGetSrcInfoForPc(&context);
} else if (context.type == TCL_LOCATION_SOURCE) {
/*
* The copy into 'context' up above has created another reference
* to 'context.data.eval.path'; account for it.
*/
Tcl_IncrRefCount(context.data.eval.path);
}
if (context.type == TCL_LOCATION_SOURCE) {
/*
* We can account for source location within a proc only if the
* proc body was not created by substitution.
*/
if (context.line
&& (context.nline >= 4) && (context.line[3] >= 0)) {
int isNew;
CmdFrame *cfPtr = (CmdFrame *) ckalloc(sizeof(CmdFrame));
cfPtr->level = -1;
cfPtr->type = context.type;
cfPtr->line = (int *) ckalloc(sizeof(int));
cfPtr->line[0] = context.line[3];
cfPtr->nline = 1;
cfPtr->framePtr = NULL;
cfPtr->nextPtr = NULL;
cfPtr->data.eval.path = context.data.eval.path;
Tcl_IncrRefCount(cfPtr->data.eval.path);
cfPtr->cmd.str.cmd = NULL;
cfPtr->cmd.str.len = 0;
Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->linePBodyPtr,
(char *) procPtr, &isNew), cfPtr);
}
/*
* 'context' is going out of scope; account for the reference that
* it's holding to the path name.
*/
Tcl_DecrRefCount(context.data.eval.path);
context.data.eval.path = NULL;
}
}
|
| ︙ | | | ︙ | |
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
|
precompiled = 1;
} else {
/*
* If the procedure's body object is shared because its string value
* is identical to, e.g., the body of another procedure, we must
* create a private copy for this procedure to use. Such sharing of
* procedure bodies is rare but can cause problems. A procedure body
* is compiled in a context that includes the number of
* compiler-allocated "slots" for local variables. Each formal
* parameter is given a local variable slot (the
* "procPtr->numCompiledLocals = numArgs" assignment below). This
* means that the same code can not be shared by two procedures that
* have a different number of arguments, even if their bodies are
* identical. Note that we don't use Tcl_DuplicateObj since we would
* not want any bytecode internal representation.
*/
|
|
|
|
|
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
|
precompiled = 1;
} else {
/*
* If the procedure's body object is shared because its string value
* is identical to, e.g., the body of another procedure, we must
* create a private copy for this procedure to use. Such sharing of
* procedure bodies is rare but can cause problems. A procedure body
* is compiled in a context that includes the number of "slots"
* allocated by the compiler for local variables. There is a local
* variable slot for each formal parameter (the
* "procPtr->numCompiledLocals = numArgs" assignment below). This
* means that the same code can not be shared by two procedures that
* have a different number of arguments, even if their bodies are
* identical. Note that we don't use Tcl_DuplicateObj since we would
* not want any bytecode internal representation.
*/
|
| ︙ | | | ︙ | |
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
|
/*
*----------------------------------------------------------------------
*
* InitArgsAndLocals --
*
* This routine is invoked in order to initialize the arguments and other
* compiled locals table for a new call frame.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Allocates memory on the stack for the compiled local variables, the
* caller is responsible for freeing them. Initialises all variables.
* May invoke various name resolvers in order to determine which
* variables are being referenced at runtime.
*
*----------------------------------------------------------------------
*/
static int
InitArgsAndLocals(
register Tcl_Interp *interp,/* Interpreter in which procedure was
|
|
|
|
|
|
|
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
|
/*
*----------------------------------------------------------------------
*
* InitArgsAndLocals --
*
* This routine is invoked in order to initialize the arguments and other
* compiled locals table for a new call frame.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Allocates memory on the stack for the compiled local variables, the
* caller is responsible for freeing them. Initialises all variables. May
* invoke various name resolvers in order to determine which variables
* are being referenced at runtime.
*
*----------------------------------------------------------------------
*/
static int
InitArgsAndLocals(
register Tcl_Interp *interp,/* Interpreter in which procedure was
|
| ︙ | | | ︙ | |
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
|
register Var *varPtr;
register CompiledLocal *localPtr;
int localCt, numArgs, argCt, i, imax;
Var *compiledLocals;
Tcl_Obj *const *argObjs;
Tcl_Obj **desiredObjs;
const char *final;
/*
* Create the "compiledLocals" array. Make sure it is large enough to hold
* all the procedure's compiled local variables, including its formal
* parameters.
*/
localCt = procPtr->numCompiledLocals;
|
|
|
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
|
register Var *varPtr;
register CompiledLocal *localPtr;
int localCt, numArgs, argCt, i, imax;
Var *compiledLocals;
Tcl_Obj *const *argObjs;
Tcl_Obj **desiredObjs;
const char *final;
/*
* Create the "compiledLocals" array. Make sure it is large enough to hold
* all the procedure's compiled local variables, including its formal
* parameters.
*/
localCt = procPtr->numCompiledLocals;
|
| ︙ | | | ︙ | |
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
|
if (numArgs == 0) {
if (argCt) {
goto incorrectArgs;
} else {
goto correctArgs;
}
}
imax = ((argCt < numArgs - 1)? argCt : (numArgs - 1));
for (i = 0; i < imax; i++) {
/*
* "Normal" arguments; last formal is special, depends on it being
* 'args'.
*/
Tcl_Obj *objPtr = argObjs[i];
varPtr->value.objPtr = objPtr;
Tcl_IncrRefCount(objPtr); /* Local var is a reference. */
varPtr->name = localPtr->name;
varPtr->nsPtr = NULL;
varPtr->hPtr = NULL;
varPtr->refCount = 0;
varPtr->tracePtr = NULL;
varPtr->searchPtr = NULL;
varPtr->flags = localPtr->flags;
varPtr++;
localPtr = localPtr->nextPtr;
}
for (; i < (numArgs - 1); 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;
|
|
|
|
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
|
if (numArgs == 0) {
if (argCt) {
goto incorrectArgs;
} else {
goto correctArgs;
}
}
imax = ((argCt < numArgs-1) ? argCt : numArgs-1);
for (i = 0; i < imax; i++) {
/*
* "Normal" arguments; last formal is special, depends on it being
* 'args'.
*/
Tcl_Obj *objPtr = argObjs[i];
varPtr->value.objPtr = objPtr;
Tcl_IncrRefCount(objPtr); /* Local var is a reference. */
varPtr->name = localPtr->name;
varPtr->nsPtr = NULL;
varPtr->hPtr = NULL;
varPtr->refCount = 0;
varPtr->tracePtr = NULL;
varPtr->searchPtr = NULL;
varPtr->flags = localPtr->flags;
varPtr++;
localPtr = localPtr->nextPtr;
}
for (; i < numArgs-1; 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;
|
| ︙ | | | ︙ | |
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
|
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 {
goto incorrectArgs;
}
varPtr->name = localPtr->name;
varPtr->nsPtr = NULL;
varPtr->hPtr = NULL;
varPtr->refCount = 0;
|
<
|
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
|
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 {
goto incorrectArgs;
}
varPtr->name = localPtr->name;
varPtr->nsPtr = NULL;
varPtr->hPtr = NULL;
varPtr->refCount = 0;
|
| ︙ | | | ︙ | |
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
|
/*
* Do initialise all compiled locals, to avoid problems at
* DeleteLocalVars.
*/
final = NULL;
InitCompiledLocals(interp, codePtr, localPtr, varPtr, framePtr->nsPtr);
/*
* Build up desired argument list for Tcl_WrongNumArgs
*/
desiredObjs = (Tcl_Obj **) TclStackAlloc(interp,
(int) sizeof(Tcl_Obj *) * (numArgs+1));
#ifdef AVOID_HACKS_FOR_ITCL
desiredObjs[0] = framePtr->objv[skip-1];
#else
desiredObjs[0] = ((framePtr->isProcCallFrame & FRAME_IS_LAMBDA)
? framePtr->objv[skip-1]
: Tcl_NewListObj(skip, framePtr->objv));
#endif /* AVOID_HACKS_FOR_ITCL */
Tcl_IncrRefCount(desiredObjs[0]);
localPtr = procPtr->firstLocalPtr;
for (i=1 ; i<=numArgs ; i++) {
Tcl_Obj *argObj;
if (localPtr->defValuePtr != NULL) {
TclNewObj(argObj);
Tcl_AppendStringsToObj(argObj, "?", localPtr->name, "?", NULL);
} else if ((i==numArgs) && !strcmp(localPtr->name, "args")) {
numArgs--;
final = "...";
break;
} else {
argObj = Tcl_NewStringObj(localPtr->name, -1);
}
desiredObjs[i] = argObj;
localPtr = localPtr->nextPtr;
}
Tcl_ResetResult(interp);
Tcl_WrongNumArgs(interp, numArgs+1, desiredObjs, final);
for (i=0 ; i<=numArgs ; i++) {
Tcl_DecrRefCount(desiredObjs[i]);
}
TclStackFree(interp);
return TCL_ERROR;
}
|
|
|
|
|
|
|
|
|
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
|
/*
* Do initialise all compiled locals, to avoid problems at
* DeleteLocalVars.
*/
final = NULL;
InitCompiledLocals(interp, codePtr, localPtr, varPtr, framePtr->nsPtr);
/*
* Build up desired argument list for Tcl_WrongNumArgs
*/
desiredObjs = (Tcl_Obj **) TclStackAlloc(interp,
(int) sizeof(Tcl_Obj *) * (numArgs+1));
#ifdef AVOID_HACKS_FOR_ITCL
desiredObjs[0] = framePtr->objv[skip-1];
#else
desiredObjs[0] = ((framePtr->isProcCallFrame & FRAME_IS_LAMBDA)
? framePtr->objv[skip-1]
: Tcl_NewListObj(skip, framePtr->objv));
#endif /* AVOID_HACKS_FOR_ITCL */
Tcl_IncrRefCount(desiredObjs[0]);
localPtr = procPtr->firstLocalPtr;
for (i=1 ; i<=numArgs ; i++) {
Tcl_Obj *argObj;
if (localPtr->defValuePtr != NULL) {
TclNewObj(argObj);
Tcl_AppendStringsToObj(argObj, "?", localPtr->name, "?", NULL);
} else if ((i==numArgs) && !strcmp(localPtr->name, "args")) {
numArgs--;
final = "...";
break;
} else {
argObj = Tcl_NewStringObj(localPtr->name, -1);
}
desiredObjs[i] = argObj;
localPtr = localPtr->nextPtr;
}
Tcl_ResetResult(interp);
Tcl_WrongNumArgs(interp, numArgs+1, desiredObjs, final);
for (i=0 ; i<=numArgs ; i++) {
Tcl_DecrRefCount(desiredObjs[i]);
}
TclStackFree(interp);
return TCL_ERROR;
}
|
| ︙ | | | ︙ | |
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
|
register Tcl_Interp *interp,/* Interpreter in which procedure was
* invoked. */
int objc, /* Count of number of arguments to this
* procedure. */
Tcl_Obj *CONST objv[]) /* Argument value objects. */
{
int result;
result = PushProcCallFrame(clientData, interp, objc, objv, /*isLambda*/ 0);
if (result == TCL_OK) {
return TclObjInterpProcCore(interp, objv[0], 1, &MakeProcError);
} else {
return TCL_ERROR;
}
}
|
|
|
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
|
register Tcl_Interp *interp,/* Interpreter in which procedure was
* invoked. */
int objc, /* Count of number of arguments to this
* procedure. */
Tcl_Obj *CONST objv[]) /* Argument value objects. */
{
int result;
result = PushProcCallFrame(clientData, interp, objc, objv, /*isLambda*/ 0);
if (result == TCL_OK) {
return TclObjInterpProcCore(interp, objv[0], 1, &MakeProcError);
} else {
return TCL_ERROR;
}
}
|
| ︙ | | | ︙ | |
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
|
* invoked. */
Tcl_Obj *procNameObj, /* Procedure name for error reporting. */
int skip, /* Number of initial arguments to be skipped,
* i.e., words in the "command name". */
ProcErrorProc errorProc) /* How to convert results from the script into
* results of the overall procedure. */
{
CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
register Proc *procPtr = framePtr->procPtr;
ByteCode *codePtr = procPtr->bodyPtr->internalRep.otherValuePtr;
int result;
result = InitArgsAndLocals(interp, procNameObj, skip);
if (result != TCL_OK) {
goto procDone;
}
#if defined(TCL_COMPILE_DEBUG)
if (tclTraceExec >= 1) {
if (framePtr->isProcCallFrame & FRAME_IS_LAMBDA) {
fprintf(stdout, "Calling lambda ");
} else {
fprintf(stdout, "Calling proc ");
}
for (i = 0; i < framePtr->objc; i++) {
TclPrintObject(stdout, framePtr->objv[i], 15);
|
<
|
<
>
>
|
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
|
* invoked. */
Tcl_Obj *procNameObj, /* Procedure name for error reporting. */
int skip, /* Number of initial arguments to be skipped,
* i.e., words in the "command name". */
ProcErrorProc errorProc) /* How to convert results from the script into
* results of the overall procedure. */
{
register Proc *procPtr = ((Interp *)interp)->varFramePtr->procPtr;
int result;
result = InitArgsAndLocals(interp, procNameObj, skip);
if (result != TCL_OK) {
goto procDone;
}
#if defined(TCL_COMPILE_DEBUG)
if (tclTraceExec >= 1) {
register CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
if (framePtr->isProcCallFrame & FRAME_IS_LAMBDA) {
fprintf(stdout, "Calling lambda ");
} else {
fprintf(stdout, "Calling proc ");
}
for (i = 0; i < framePtr->objc; i++) {
TclPrintObject(stdout, framePtr->objv[i], 15);
|
| ︙ | | | ︙ | |
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
|
procPtr->refCount++;
((Interp *)interp)->numLevels++;
if (TclInterpReady(interp) == TCL_ERROR) {
result = TCL_ERROR;
} else {
codePtr->refCount++;
result = TclExecuteByteCode(interp, codePtr);
codePtr->refCount--;
if (codePtr->refCount <= 0) {
TclCleanupByteCode(codePtr);
}
}
((Interp *)interp)->numLevels--;
procPtr->refCount--;
if (procPtr->refCount <= 0) {
TclProcCleanupProc(procPtr);
}
/*
* If the procedure is completing normally, we can skip directly to the
* part where we clean up any associated memory.
*/
if (result == TCL_OK) {
goto procDone;
}
/*
* Non-standard results are processed by passing them through quickly.
* This means they all work as exceptions, unwinding the stack quickly and
* neatly. Who knows how well they are handled by third-party code
* though...
*/
if ((result > TCL_CONTINUE) || (result < TCL_OK)) {
goto procDone;
}
/*
* If it is a 'return', do the TIP#90 processing now.
*/
if (result == TCL_RETURN) {
result = TclUpdateReturnInfo((Interp *) interp);
goto procDone;
}
/*
* Must be an error, a 'break' or a 'continue'. It's an error to get to
* this point from a 'break' or 'continue' though, so transform to an
* error now.
*/
if (result != TCL_ERROR) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "invoked \"",
((result == TCL_BREAK) ? "break" : "continue"),
"\" outside of a loop", NULL);
result = TCL_ERROR;
}
/*
* Now it _must_ be an error, so we need to log it as such. This means
* filling out the error trace.
*/
(*errorProc)(interp, procNameObj);
procDone:
/*
* Free the stack-allocated compiled locals and CallFrame. It is important
* to pop the call frame without freeing it first: the compiledLocals
* cannot be freed before the frame is popped, as the local variables must
* be deleted. But the compiledLocals must be freed first, as they were
|
>
>
>
|
<
<
<
|
<
<
<
<
<
<
<
<
<
|
<
<
|
|
|
|
<
|
|
|
>
|
<
|
|
|
<
|
>
>
>
>
|
|
|
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
|
procPtr->refCount++;
((Interp *)interp)->numLevels++;
if (TclInterpReady(interp) == TCL_ERROR) {
result = TCL_ERROR;
} else {
register ByteCode *codePtr =
procPtr->bodyPtr->internalRep.otherValuePtr;
codePtr->refCount++;
result = TclExecuteByteCode(interp, codePtr);
codePtr->refCount--;
if (codePtr->refCount <= 0) {
TclCleanupByteCode(codePtr);
}
}
((Interp *)interp)->numLevels--;
procPtr->refCount--;
if (procPtr->refCount <= 0) {
TclProcCleanupProc(procPtr);
}
/*
* Process the result code.
*/
switch (result) {
case TCL_RETURN:
/*
* If it is a 'return', do the TIP#90 processing now.
*/
result = TclUpdateReturnInfo((Interp *) interp);
break;
case TCL_CONTINUE:
case TCL_BREAK:
/*
* It's an error to get to this point from a 'break' or 'continue', so
* transform to an error now.
*/
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "invoked \"",
((result == TCL_BREAK) ? "break" : "continue"),
"\" outside of a loop", NULL);
result = TCL_ERROR;
/*
* Fall through to the TCL_ERROR handling code.
*/
case TCL_ERROR:
/*
* Now it _must_ be an error, so we need to log it as such. This means
* filling out the error trace. Luckily, we just hand this off to the
* function handed to us as an argument.
*/
(*errorProc)(interp, procNameObj);
default:
/*
* Process other results (OK and non-standard) by doing nothing
* special, skipping directly to the code afterwards that cleans up
* associated memory.
*
* Non-standard results are processed by passing them through quickly.
* This means they all work as exceptions, unwinding the stack quickly
* and neatly. Who knows how well they are handled by third-party code
* though...
*/
(void) 0; /* do nothing */
}
procDone:
/*
* Free the stack-allocated compiled locals and CallFrame. It is important
* to pop the call frame without freeing it first: the compiledLocals
* cannot be freed before the frame is popped, as the local variables must
* be deleted. But the compiledLocals must be freed first, as they were
|
| ︙ | | | ︙ | |