summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2012-11-05 14:55:14 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2012-11-05 14:55:14 (GMT)
commit17d34ed9ea3e7f173fad801e48240de9a99d77e8 (patch)
treee444cd464f93f10ffab5483b5917f5eb87b7cc2b
parent18dbdc3e40e19a7266c19924537e6914840adbe5 (diff)
parentcd1f27f0cf22ec6b5b83f2fd48c1ba93e5c27be2 (diff)
downloadtcl-17d34ed9ea3e7f173fad801e48240de9a99d77e8.zip
tcl-17d34ed9ea3e7f173fad801e48240de9a99d77e8.tar.gz
tcl-17d34ed9ea3e7f173fad801e48240de9a99d77e8.tar.bz2
Added bytecode compilation of many Tcl commands, merged from development branch.
-rw-r--r--ChangeLog24
-rw-r--r--generic/tclAssembly.c28
-rw-r--r--generic/tclBasic.c30
-rw-r--r--generic/tclCmdIL.c6
-rw-r--r--generic/tclCmdMZ.c8
-rw-r--r--generic/tclCompCmds.c1384
-rw-r--r--generic/tclCompCmdsSZ.c525
-rw-r--r--generic/tclCompile.c129
-rw-r--r--generic/tclCompile.h34
-rw-r--r--generic/tclDictObj.c6
-rw-r--r--generic/tclExecute.c537
-rw-r--r--generic/tclInt.h84
-rw-r--r--generic/tclNamesp.c275
-rw-r--r--generic/tclOO.c6
-rw-r--r--generic/tclOOInfo.c85
-rw-r--r--generic/tclVar.c6
-rw-r--r--tests/dict.test48
-rw-r--r--tests/info.test6
18 files changed, 2801 insertions, 420 deletions
diff --git a/ChangeLog b/ChangeLog
index e6a6f97..d9fa2a0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2012-11-05 Donal K. Fellows <dkf@users.sf.net>
+
+ Added bytecode compilation of many Tcl commands. Some of these are
+ total compilations and some are only partial (i.e., only compile in
+ some cases). The (sub-)commands affected are:
+ * array: exists, set, unset
+ * dict: create, exists, merge
+ * format: (simple cases only)
+ * info: commands, coroutine, level, object
+ * info object: class, isa object, namespace
+ * namespace: current, code, qualifiers, tail, which
+ * regsub: (only cases convertable to simple [string map])
+ * self: (only no-argument and [self object] cases)
+ * string: first, last, map, range
+ * tailcall:
+ * yield:
+
+ [This was work originally done on the 'dkf-compile-misc-info' branch.]
+
2012-11-05 Jan Nijtmans <nijtmans@users.sf.net>
IMPLEMENTATION OF TIP#413
@@ -12,6 +31,11 @@
* generic/regc_locale.c: Regexp engine must match [string is space]
* doc/string.n
* tests/string.test
+ ***POTENTIAL INCOMPATIBILITY***
+ Code that relied on characters not previously trimmed being not
+ removed will notice a difference; it is believed that this is rare,
+ but a workaround to get the behavior in Tcl 8.5 is to use " \t\n\r" as
+ an explicit trim set.
2012-10-31 Jan Nijtmans <nijtmans@users.sf.net>
diff --git a/generic/tclAssembly.c b/generic/tclAssembly.c
index 83f4fe9..7833105 100644
--- a/generic/tclAssembly.c
+++ b/generic/tclAssembly.c
@@ -362,6 +362,10 @@ static const TalInstDesc TalInstructionTable[] = {
| INST_APPEND_ARRAY4), 2, 1},
{"appendArrayStk", ASSEM_1BYTE, INST_APPEND_ARRAY_STK, 3, 1},
{"appendStk", ASSEM_1BYTE, INST_APPEND_STK, 2, 1},
+ {"arrayExistsImm", ASSEM_LVT4, INST_ARRAY_EXISTS_IMM, 0, 1},
+ {"arrayExistsStk", ASSEM_1BYTE, INST_ARRAY_EXISTS_STK, 1, 1},
+ {"arrayMakeImm", ASSEM_LVT4, INST_ARRAY_MAKE_IMM, 0, 0},
+ {"arrayMakeStk", ASSEM_1BYTE, INST_ARRAY_MAKE_STK, 1, 0},
{"beginCatch", ASSEM_BEGIN_CATCH,
INST_BEGIN_CATCH4, 0, 0},
{"bitand", ASSEM_1BYTE, INST_BITAND, 2, 1},
@@ -369,7 +373,10 @@ static const TalInstDesc TalInstructionTable[] = {
{"bitor", ASSEM_1BYTE, INST_BITOR, 2, 1},
{"bitxor", ASSEM_1BYTE, INST_BITXOR, 2, 1},
{"concat", ASSEM_CONCAT1, INST_CONCAT1, INT_MIN,1},
+ {"coroName", ASSEM_1BYTE, INST_COROUTINE_NAME, 0, 1},
+ {"currentNamespace",ASSEM_1BYTE, INST_NS_CURRENT, 0, 1},
{"dictAppend", ASSEM_LVT4, INST_DICT_APPEND, 2, 1},
+ {"dictExists", ASSEM_DICT_GET, INST_DICT_EXISTS, INT_MIN,1},
{"dictExpand", ASSEM_1BYTE, INST_DICT_EXPAND, 3, 1},
{"dictGet", ASSEM_DICT_GET, INST_DICT_GET, INT_MIN,1},
{"dictIncrImm", ASSEM_SINT4_LVT4,
@@ -406,6 +413,8 @@ static const TalInstDesc TalInstructionTable[] = {
{"incrStk", ASSEM_1BYTE, INST_INCR_SCALAR_STK, 2, 1},
{"incrStkImm", ASSEM_SINT1, INST_INCR_SCALAR_STK_IMM,
1, 1},
+ {"infoLevelArgs", ASSEM_1BYTE, INST_INFO_LEVEL_ARGS, 1, 1},
+ {"infoLevelNumber", ASSEM_1BYTE, INST_INFO_LEVEL_NUM, 0, 1},
{"invokeStk", ASSEM_INVOKE, (INST_INVOKE_STK1 << 8
| INST_INVOKE_STK4), INT_MIN,1},
{"jump", ASSEM_JUMP, INST_JUMP1, 0, 0},
@@ -457,6 +466,7 @@ static const TalInstDesc TalInstructionTable[] = {
0, 1},
{"pushResult", ASSEM_1BYTE, INST_PUSH_RESULT, 0, 1},
{"regexp", ASSEM_REGEXP, INST_REGEXP, 2, 1},
+ {"resolveCmd", ASSEM_1BYTE, INST_RESOLVE_COMMAND, 1, 1},
{"reverse", ASSEM_REVERSE, INST_REVERSE, INT_MIN,-1-0},
{"rshift", ASSEM_1BYTE, INST_RSHIFT, 2, 1},
{"store", ASSEM_LVT, (INST_STORE_SCALAR1<<8
@@ -467,11 +477,19 @@ static const TalInstDesc TalInstructionTable[] = {
{"storeStk", ASSEM_1BYTE, INST_STORE_SCALAR_STK, 2, 1},
{"strcmp", ASSEM_1BYTE, INST_STR_CMP, 2, 1},
{"streq", ASSEM_1BYTE, INST_STR_EQ, 2, 1},
+ {"strfind", ASSEM_1BYTE, INST_STR_FIND, 2, 1},
{"strindex", ASSEM_1BYTE, INST_STR_INDEX, 2, 1},
{"strlen", ASSEM_1BYTE, INST_STR_LEN, 1, 1},
+ {"strmap", ASSEM_1BYTE, INST_STR_MAP, 3, 1},
{"strmatch", ASSEM_BOOL, INST_STR_MATCH, 2, 1},
{"strneq", ASSEM_1BYTE, INST_STR_NEQ, 2, 1},
+ {"strrange", ASSEM_1BYTE, INST_STR_RANGE, 3, 1},
+ {"strrfind", ASSEM_1BYTE, INST_STR_FIND_LAST, 2, 1},
{"sub", ASSEM_1BYTE, INST_SUB, 2, 1},
+ {"tclooClass", ASSEM_1BYTE, INST_TCLOO_CLASS, 1, 1},
+ {"tclooIsObject", ASSEM_1BYTE, INST_TCLOO_IS_OBJECT, 1, 1},
+ {"tclooNamespace", ASSEM_1BYTE, INST_TCLOO_NS, 1, 1},
+ {"tclooSelf", ASSEM_1BYTE, INST_TCLOO_SELF, 0, 1},
{"tryCvtToNumeric", ASSEM_1BYTE, INST_TRY_CVT_TO_NUMERIC,1, 1},
{"uminus", ASSEM_1BYTE, INST_UMINUS, 1, 1},
{"unset", ASSEM_BOOL_LVT4,INST_UNSET_SCALAR, 0, 0},
@@ -481,6 +499,8 @@ static const TalInstDesc TalInstructionTable[] = {
{"uplus", ASSEM_1BYTE, INST_UPLUS, 1, 1},
{"upvar", ASSEM_LVT4, INST_UPVAR, 2, 1},
{"variable", ASSEM_LVT4, INST_VARIABLE, 1, 0},
+ {"verifyDict", ASSEM_1BYTE, INST_DICT_VERIFY, 1, 0},
+ {"yield", ASSEM_1BYTE, INST_YIELD, 1, 1},
{NULL, 0, 0, 0, 0}
};
@@ -499,7 +519,13 @@ static const unsigned char NonThrowingByteCodes[] = {
INST_OVER, /* 95 */
INST_PUSH_RETURN_OPTIONS, /* 108 */
INST_REVERSE, /* 126 */
- INST_NOP /* 132 */
+ INST_NOP, /* 132 */
+ INST_STR_MAP, /* 143 */
+ INST_STR_FIND, /* 144 */
+ INST_COROUTINE_NAME, /* 149 */
+ INST_NS_CURRENT, /* 151 */
+ INST_INFO_LEVEL_NUM, /* 152 */
+ INST_RESOLVE_COMMAND /* 154 */
};
/*
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index 3848d5b..bce6479 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -131,13 +131,11 @@ static Tcl_Obj * GetCommandSource(Interp *iPtr, int objc,
Tcl_Obj *const objv[], int lookup);
static void MathFuncWrongNumArgs(Tcl_Interp *interp, int expected,
int actual, Tcl_Obj *const *objv);
-static Tcl_NRPostProc NRCoroutineActivateCallback;
static Tcl_NRPostProc NRCoroutineCallerCallback;
static Tcl_NRPostProc NRCoroutineExitCallback;
static int NRCommand(ClientData data[], Tcl_Interp *interp, int result);
static Tcl_NRPostProc NRRunObjProc;
-static Tcl_NRPostProc NRTailcallEval;
static Tcl_ObjCmdProc OldMathFuncProc;
static void OldMathFuncDeleteProc(ClientData clientData);
static void ProcessUnexpectedResult(Tcl_Interp *interp,
@@ -219,7 +217,7 @@ static const CmdInfo builtInCmds[] = {
{"expr", Tcl_ExprObjCmd, TclCompileExprCmd, TclNRExprObjCmd, 1},
{"for", Tcl_ForObjCmd, TclCompileForCmd, TclNRForObjCmd, 1},
{"foreach", Tcl_ForeachObjCmd, TclCompileForeachCmd, TclNRForeachCmd, 1},
- {"format", Tcl_FormatObjCmd, NULL, NULL, 1},
+ {"format", Tcl_FormatObjCmd, TclCompileFormatCmd, NULL, 1},
{"global", Tcl_GlobalObjCmd, TclCompileGlobalCmd, NULL, 1},
{"if", Tcl_IfObjCmd, TclCompileIfCmd, TclNRIfObjCmd, 1},
{"incr", Tcl_IncrObjCmd, TclCompileIncrCmd, NULL, 1},
@@ -241,7 +239,7 @@ static const CmdInfo builtInCmds[] = {
{"package", Tcl_PackageObjCmd, NULL, NULL, 1},
{"proc", Tcl_ProcObjCmd, NULL, NULL, 1},
{"regexp", Tcl_RegexpObjCmd, TclCompileRegexpCmd, NULL, 1},
- {"regsub", Tcl_RegsubObjCmd, NULL, NULL, 1},
+ {"regsub", Tcl_RegsubObjCmd, TclCompileRegsubCmd, NULL, 1},
{"rename", Tcl_RenameObjCmd, NULL, NULL, 1},
{"return", Tcl_ReturnObjCmd, TclCompileReturnCmd, NULL, 1},
{"scan", Tcl_ScanObjCmd, NULL, NULL, 1},
@@ -249,7 +247,7 @@ static const CmdInfo builtInCmds[] = {
{"split", Tcl_SplitObjCmd, NULL, NULL, 1},
{"subst", Tcl_SubstObjCmd, TclCompileSubstCmd, TclNRSubstObjCmd, 1},
{"switch", Tcl_SwitchObjCmd, TclCompileSwitchCmd, TclNRSwitchObjCmd, 1},
- {"tailcall", NULL, NULL, TclNRTailcallObjCmd, 1},
+ {"tailcall", NULL, TclCompileTailcallCmd, TclNRTailcallObjCmd, 1},
{"throw", Tcl_ThrowObjCmd, TclCompileThrowCmd, NULL, 1},
{"trace", Tcl_TraceObjCmd, NULL, NULL, 1},
{"try", Tcl_TryObjCmd, TclCompileTryCmd, TclNRTryObjCmd, 1},
@@ -258,7 +256,7 @@ static const CmdInfo builtInCmds[] = {
{"upvar", Tcl_UpvarObjCmd, TclCompileUpvarCmd, NULL, 1},
{"variable", Tcl_VariableObjCmd, TclCompileVariableCmd, NULL, 1},
{"while", Tcl_WhileObjCmd, TclCompileWhileCmd, TclNRWhileObjCmd, 1},
- {"yield", NULL, NULL, TclNRYieldObjCmd, 1},
+ {"yield", NULL, TclCompileYieldCmd, TclNRYieldObjCmd, 1},
{"yieldto", NULL, NULL, TclNRYieldToObjCmd, 1},
/*
@@ -8323,7 +8321,7 @@ TclNRTailcallObjCmd(
return TCL_ERROR;
}
- if (!iPtr->varFramePtr->isProcCallFrame) { /* or is upleveled */
+ if (!(iPtr->varFramePtr->isProcCallFrame & 1)) { /* or is upleveled */
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"tailcall can only be called from a proc or lambda", -1));
Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "ILLEGAL", NULL);
@@ -8363,7 +8361,7 @@ TclNRTailcallObjCmd(
}
Tcl_IncrRefCount(nsObjPtr);
- TclNRAddCallback(interp, NRTailcallEval, listPtr, nsObjPtr,
+ TclNRAddCallback(interp, TclNRTailcallEval, listPtr, nsObjPtr,
NULL, NULL);
tailcallPtr = TOP_CB(interp);
TOP_CB(interp) = tailcallPtr->nextPtr;
@@ -8373,7 +8371,7 @@ TclNRTailcallObjCmd(
}
int
-NRTailcallEval(
+TclNRTailcallEval(
ClientData data[],
Tcl_Interp *interp,
int result)
@@ -8495,7 +8493,7 @@ TclNRYieldObjCmd(
}
NRE_ASSERT(!COR_IS_SUSPENDED(corPtr));
- TclNRAddCallback(interp, NRCoroutineActivateCallback, corPtr,
+ TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr,
clientData, NULL, NULL);
return TCL_OK;
}
@@ -8567,7 +8565,7 @@ YieldToCallback(
* yieldTo: invoke the command using tailcall tech.
*/
- TclNRAddCallback(interp, NRTailcallEval, listPtr, nsPtr, NULL, NULL);
+ TclNRAddCallback(interp, TclNRTailcallEval, listPtr, nsPtr, NULL, NULL);
cbPtr = TOP_CB(interp);
TOP_CB(interp) = cbPtr->nextPtr;
@@ -8712,7 +8710,7 @@ NRCoroutineExitCallback(
/*
*----------------------------------------------------------------------
*
- * NRCoroutineActivateCallback --
+ * TclNRCoroutineActivateCallback --
*
* This is the workhorse for coroutines: it implements both yield and
* resume.
@@ -8726,8 +8724,8 @@ NRCoroutineExitCallback(
*----------------------------------------------------------------------
*/
-static int
-NRCoroutineActivateCallback(
+int
+TclNRCoroutineActivateCallback(
ClientData data[],
Tcl_Interp *interp,
int result)
@@ -8902,7 +8900,7 @@ TclNRInterpCoroutine(
break;
}
- TclNRAddCallback(interp, NRCoroutineActivateCallback, corPtr,
+ TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr,
NULL, NULL, NULL);
return TCL_OK;
}
@@ -9059,7 +9057,7 @@ TclNRCoroutineObjCmd(
* Now just resume the coroutine.
*/
- TclNRAddCallback(interp, NRCoroutineActivateCallback, corPtr,
+ TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr,
NULL, NULL, NULL);
return TCL_OK;
}
diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c
index 14e0092..7be017d 100644
--- a/generic/tclCmdIL.c
+++ b/generic/tclCmdIL.c
@@ -164,9 +164,9 @@ static const EnsembleImplMap defaultInfoMap[] = {
{"args", InfoArgsCmd, NULL, NULL, NULL, 0},
{"body", InfoBodyCmd, NULL, NULL, NULL, 0},
{"cmdcount", InfoCmdCountCmd, NULL, NULL, NULL, 0},
- {"commands", InfoCommandsCmd, NULL, NULL, NULL, 0},
+ {"commands", InfoCommandsCmd, TclCompileInfoCommandsCmd, NULL, NULL, 0},
{"complete", InfoCompleteCmd, NULL, NULL, NULL, 0},
- {"coroutine", TclInfoCoroutineCmd, NULL, NULL, NULL, 0},
+ {"coroutine", TclInfoCoroutineCmd, TclCompileInfoCoroutineCmd, NULL, NULL, 0},
{"default", InfoDefaultCmd, NULL, NULL, NULL, 0},
{"errorstack", InfoErrorStackCmd, NULL, NULL, NULL, 0},
{"exists", TclInfoExistsCmd, TclCompileInfoExistsCmd, NULL, NULL, 0},
@@ -174,7 +174,7 @@ static const EnsembleImplMap defaultInfoMap[] = {
{"functions", InfoFunctionsCmd, NULL, NULL, NULL, 0},
{"globals", TclInfoGlobalsCmd, NULL, NULL, NULL, 0},
{"hostname", InfoHostnameCmd, NULL, NULL, NULL, 0},
- {"level", InfoLevelCmd, NULL, NULL, NULL, 0},
+ {"level", InfoLevelCmd, TclCompileInfoLevelCmd, NULL, NULL, 0},
{"library", InfoLibraryCmd, NULL, NULL, NULL, 0},
{"loaded", InfoLoadedCmd, NULL, NULL, NULL, 0},
{"locals", TclInfoLocalsCmd, NULL, NULL, NULL, 0},
diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c
index 88b3420..fc957c4 100644
--- a/generic/tclCmdMZ.c
+++ b/generic/tclCmdMZ.c
@@ -3327,14 +3327,14 @@ TclInitStringCmd(
{"bytelength", StringBytesCmd, NULL, NULL, NULL, 0},
{"compare", StringCmpCmd, TclCompileStringCmpCmd, NULL, NULL, 0},
{"equal", StringEqualCmd, TclCompileStringEqualCmd, NULL, NULL, 0},
- {"first", StringFirstCmd, NULL, NULL, NULL, 0},
+ {"first", StringFirstCmd, TclCompileStringFirstCmd, NULL, NULL, 0},
{"index", StringIndexCmd, TclCompileStringIndexCmd, NULL, NULL, 0},
{"is", StringIsCmd, NULL, NULL, NULL, 0},
- {"last", StringLastCmd, NULL, NULL, NULL, 0},
+ {"last", StringLastCmd, TclCompileStringLastCmd, NULL, NULL, 0},
{"length", StringLenCmd, TclCompileStringLenCmd, NULL, NULL, 0},
- {"map", StringMapCmd, NULL, NULL, NULL, 0},
+ {"map", StringMapCmd, TclCompileStringMapCmd, NULL, NULL, 0},
{"match", StringMatchCmd, TclCompileStringMatchCmd, NULL, NULL, 0},
- {"range", StringRangeCmd, NULL, NULL, NULL, 0},
+ {"range", StringRangeCmd, TclCompileStringRangeCmd, NULL, NULL, 0},
{"repeat", StringReptCmd, NULL, NULL, NULL, 0},
{"replace", StringRplcCmd, NULL, NULL, NULL, 0},
{"reverse", StringRevCmd, NULL, NULL, NULL, 0},
diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c
index fc60016..160fa3c 100644
--- a/generic/tclCompCmds.c
+++ b/generic/tclCompCmds.c
@@ -15,6 +15,7 @@
#include "tclInt.h"
#include "tclCompile.h"
+#include <assert.h>
/*
* Prototypes for procedures defined later in this file:
@@ -225,6 +226,245 @@ TclCompileAppendCmd(
/*
*----------------------------------------------------------------------
*
+ * TclCompileArray*Cmd --
+ *
+ * Functions called to compile "array" sucommands.
+ *
+ * Results:
+ * All return TCL_OK for a successful compile, and TCL_ERROR to defer
+ * evaluation to runtime.
+ *
+ * Side effects:
+ * Instructions are added to envPtr to execute the "array" subcommand at
+ * runtime.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclCompileArrayExistsCmd(
+ Tcl_Interp *interp, /* Used for looking up stuff. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr;
+ int simpleVarName, isScalar, localIndex;
+
+ if (parsePtr->numWords != 2) {
+ return TCL_ERROR;
+ }
+
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ PushVarNameWord(interp, tokenPtr, envPtr, 0,
+ &localIndex, &simpleVarName, &isScalar, 1);
+ if (!isScalar) {
+ return TCL_ERROR;
+ }
+
+ if (localIndex >= 0) {
+ TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
+ } else {
+ TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr);
+ }
+ return TCL_OK;
+}
+
+int
+TclCompileArraySetCmd(
+ Tcl_Interp *interp, /* Used for looking up stuff. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr;
+ int simpleVarName, isScalar, localIndex;
+ int dataVar, iterVar, keyVar, valVar, infoIndex;
+ int back, fwd, offsetBack, offsetFwd, savedStackDepth;
+ ForeachInfo *infoPtr;
+
+ if (parsePtr->numWords != 3) {
+ return TCL_ERROR;
+ }
+
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ PushVarNameWord(interp, tokenPtr, envPtr, 0,
+ &localIndex, &simpleVarName, &isScalar, 1);
+ if (!isScalar) {
+ return TCL_ERROR;
+ }
+ tokenPtr = TokenAfter(tokenPtr);
+
+ /*
+ * Special case: literal empty value argument is just an "ensure array"
+ * operation.
+ */
+
+ if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD && tokenPtr[1].size == 0) {
+ if (localIndex >= 0) {
+ TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
+ TclEmitInstInt1(INST_JUMP_TRUE1, 7, envPtr);
+ TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex, envPtr);
+ } else {
+ TclEmitOpcode( INST_DUP, envPtr);
+ TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr);
+ TclEmitInstInt1(INST_JUMP_TRUE1, 5, envPtr);
+ savedStackDepth = envPtr->currStackDepth;
+ TclEmitOpcode( INST_ARRAY_MAKE_STK, envPtr);
+ TclEmitInstInt1(INST_JUMP1, 3, envPtr);
+ envPtr->currStackDepth = savedStackDepth;
+ TclEmitOpcode( INST_POP, envPtr);
+ }
+ PushLiteral(envPtr, "", 0);
+ return TCL_OK;
+ }
+
+ /*
+ * Prepare for the internal foreach.
+ */
+
+ if (envPtr->procPtr == NULL) {
+ return TCL_ERROR;
+ }
+ dataVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
+ iterVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
+ keyVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
+ valVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
+
+ infoPtr = ckalloc(sizeof(ForeachInfo) + sizeof(ForeachVarList *));
+ infoPtr->numLists = 1;
+ infoPtr->firstValueTemp = dataVar;
+ infoPtr->loopCtTemp = iterVar;
+ infoPtr->varLists[0] = ckalloc(sizeof(ForeachVarList) * 2*sizeof(int));
+ infoPtr->varLists[0]->numVars = 2;
+ infoPtr->varLists[0]->varIndexes[0] = keyVar;
+ infoPtr->varLists[0]->varIndexes[1] = valVar;
+ infoIndex = TclCreateAuxData(infoPtr, &tclForeachInfoType, envPtr);
+
+ /*
+ * Start issuing instructions to write to the array.
+ */
+
+ CompileWord(envPtr, tokenPtr, interp, 2);
+ TclEmitOpcode( INST_DUP, envPtr);
+ TclEmitOpcode( INST_LIST_LENGTH, envPtr);
+ PushLiteral(envPtr, "1", 1);
+ TclEmitOpcode( INST_BITAND, envPtr);
+ offsetFwd = CurrentOffset(envPtr);
+ TclEmitInstInt1( INST_JUMP_FALSE1, 0, envPtr);
+ savedStackDepth = envPtr->currStackDepth;
+ PushLiteral(envPtr, "list must have an even number of elements",
+ strlen("list must have an even number of elements"));
+ PushLiteral(envPtr, "-errorCode {TCL ARGUMENT FORMAT}",
+ strlen("-errorCode {TCL ARGUMENT FORMAT}"));
+ TclEmitInstInt4( INST_RETURN_IMM, 1, envPtr);
+ TclEmitInt4( 0, envPtr);
+ envPtr->currStackDepth = savedStackDepth;
+ fwd = CurrentOffset(envPtr) - offsetFwd;
+ TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1);
+ Emit14Inst( INST_STORE_SCALAR, dataVar, envPtr);
+ TclEmitOpcode( INST_POP, envPtr);
+
+ if (localIndex >= 0) {
+ TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
+ TclEmitInstInt1(INST_JUMP_TRUE1, 7, envPtr);
+ TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex, envPtr);
+ TclEmitInstInt4(INST_FOREACH_START4, infoIndex, envPtr);
+ offsetBack = CurrentOffset(envPtr);
+ TclEmitInstInt4(INST_FOREACH_STEP4, infoIndex, envPtr);
+ offsetFwd = CurrentOffset(envPtr);
+ TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);
+ savedStackDepth = envPtr->currStackDepth;
+ Emit14Inst( INST_LOAD_SCALAR, keyVar, envPtr);
+ Emit14Inst( INST_LOAD_SCALAR, valVar, envPtr);
+ Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr);
+ TclEmitOpcode( INST_POP, envPtr);
+ back = offsetBack - CurrentOffset(envPtr);
+ TclEmitInstInt1(INST_JUMP1, back, envPtr);
+ fwd = CurrentOffset(envPtr) - offsetFwd;
+ TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1);
+ envPtr->currStackDepth = savedStackDepth;
+ } else {
+ TclEmitOpcode( INST_DUP, envPtr);
+ TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr);
+ TclEmitInstInt1(INST_JUMP_TRUE1, 4, envPtr);
+ TclEmitOpcode( INST_DUP, envPtr);
+ TclEmitOpcode( INST_ARRAY_MAKE_STK, envPtr);
+ TclEmitInstInt4(INST_FOREACH_START4, infoIndex, envPtr);
+ offsetBack = CurrentOffset(envPtr);
+ TclEmitInstInt4(INST_FOREACH_STEP4, infoIndex, envPtr);
+ offsetFwd = CurrentOffset(envPtr);
+ TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);
+ savedStackDepth = envPtr->currStackDepth;
+ TclEmitOpcode( INST_DUP, envPtr);
+ Emit14Inst( INST_LOAD_SCALAR, keyVar, envPtr);
+ Emit14Inst( INST_LOAD_SCALAR, valVar, envPtr);
+ TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr);
+ TclEmitOpcode( INST_POP, envPtr);
+ back = offsetBack - CurrentOffset(envPtr);
+ TclEmitInstInt1(INST_JUMP1, back, envPtr);
+ fwd = CurrentOffset(envPtr) - offsetFwd;
+ TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1);
+ envPtr->currStackDepth = savedStackDepth;
+ TclEmitOpcode( INST_POP, envPtr);
+ }
+ TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
+ TclEmitInt4( dataVar, envPtr);
+ PushLiteral(envPtr, "", 0);
+ return TCL_OK;
+}
+
+int
+TclCompileArrayUnsetCmd(
+ Tcl_Interp *interp, /* Used for looking up stuff. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ int simpleVarName, isScalar, localIndex, savedStackDepth;
+
+ if (parsePtr->numWords != 2) {
+ return TCL_ERROR;
+ }
+
+ PushVarNameWord(interp, tokenPtr, envPtr, 0,
+ &localIndex, &simpleVarName, &isScalar, 1);
+ if (!isScalar) {
+ return TCL_ERROR;
+ }
+
+ if (localIndex >= 0) {
+ TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
+ TclEmitInstInt1(INST_JUMP_FALSE1, 8, envPtr);
+ TclEmitInstInt1(INST_UNSET_SCALAR, 1, envPtr);
+ TclEmitInt4( localIndex, envPtr);
+ } else {
+ TclEmitOpcode( INST_DUP, envPtr);
+ TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr);
+ TclEmitInstInt1(INST_JUMP_FALSE1, 6, envPtr);
+ savedStackDepth = envPtr->currStackDepth;
+ TclEmitInstInt1(INST_UNSET_STK, 1, envPtr);
+ TclEmitInstInt1(INST_JUMP1, 3, envPtr);
+ envPtr->currStackDepth = savedStackDepth;
+ TclEmitOpcode( INST_POP, envPtr);
+ }
+ PushLiteral(envPtr, "", 0);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclCompileBreakCmd --
*
* Procedure called to compile the "break" command.
@@ -258,6 +498,7 @@ TclCompileBreakCmd(
*/
TclEmitOpcode(INST_BREAK, envPtr);
+ PushLiteral(envPtr, "", 0); /* Evil hack! */
return TCL_OK;
}
@@ -564,6 +805,7 @@ TclCompileContinueCmd(
*/
TclEmitOpcode(INST_CONTINUE, envPtr);
+ PushLiteral(envPtr, "", 0); /* Evil hack! */
return TCL_OK;
}
@@ -582,26 +824,6 @@ TclCompileContinueCmd(
* Instructions are added to envPtr to execute the "dict" subcommand at
* runtime.
*
- * Notes:
- * The following commands are in fairly common use and are possibly worth
- * bytecoding:
- * dict append
- * dict create [*]
- * dict exists [*]
- * dict for
- * dict get [*]
- * dict incr
- * dict keys [*]
- * dict lappend
- * dict map
- * dict set
- * dict unset
- *
- * In practice, those that are pure-value operators (marked with [*]) can
- * probably be left alone (except perhaps [dict get] which is very very
- * common) and [dict update] should be considered instead (really big
- * win!)
- *
*----------------------------------------------------------------------
*/
@@ -666,6 +888,7 @@ TclCompileDictSetCmd(
TclEmitInstInt4( INST_DICT_SET, numWords-2, envPtr);
TclEmitInt4( dictVarIndex, envPtr);
+ TclAdjustStackDepth(-1, envPtr);
return TCL_OK;
}
@@ -783,6 +1006,44 @@ TclCompileDictGetCmd(
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt4(INST_DICT_GET, numWords-1, envPtr);
+ TclAdjustStackDepth(-1, envPtr);
+ return TCL_OK;
+}
+
+int
+TclCompileDictExistsCmd(
+ Tcl_Interp *interp, /* Used for looking up stuff. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ Tcl_Token *tokenPtr;
+ int numWords, i;
+ DefineLineInformation; /* TIP #280 */
+
+ /*
+ * There must be at least two arguments after the command (the single-arg
+ * case is legal, but too special and magic for us to deal with here).
+ */
+
+ if (parsePtr->numWords < 3) {
+ return TCL_ERROR;
+ }
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ numWords = parsePtr->numWords-1;
+
+ /*
+ * Now we do the code generation.
+ */
+
+ for (i=0 ; i<numWords ; i++) {
+ CompileWord(envPtr, tokenPtr, interp, i);
+ tokenPtr = TokenAfter(tokenPtr);
+ }
+ TclEmitInstInt4(INST_DICT_EXISTS, numWords-1, envPtr);
+ TclAdjustStackDepth(-1, envPtr);
return TCL_OK;
}
@@ -843,7 +1104,212 @@ TclCompileDictUnsetCmd(
*/
TclEmitInstInt4( INST_DICT_UNSET, parsePtr->numWords-2, envPtr);
- TclEmitInt4( dictVarIndex, envPtr);
+ TclEmitInt4( dictVarIndex, envPtr);
+ return TCL_OK;
+}
+
+int
+TclCompileDictCreateCmd(
+ Tcl_Interp *interp, /* Used for looking up stuff. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ int worker; /* Temp var for building the value in. */
+ Tcl_Token *tokenPtr;
+ Tcl_Obj *keyObj, *valueObj, *dictObj;
+ const char *bytes;
+ int i, len;
+
+ if ((parsePtr->numWords & 1) == 0) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * See if we can build the value at compile time...
+ */
+
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ dictObj = Tcl_NewObj();
+ Tcl_IncrRefCount(dictObj);
+ for (i=1 ; i<parsePtr->numWords ; i+=2) {
+ keyObj = Tcl_NewObj();
+ Tcl_IncrRefCount(keyObj);
+ if (!TclWordKnownAtCompileTime(tokenPtr, keyObj)) {
+ Tcl_DecrRefCount(keyObj);
+ Tcl_DecrRefCount(dictObj);
+ goto nonConstant;
+ }
+ tokenPtr = TokenAfter(tokenPtr);
+ valueObj = Tcl_NewObj();
+ Tcl_IncrRefCount(valueObj);
+ if (!TclWordKnownAtCompileTime(tokenPtr, valueObj)) {
+ Tcl_DecrRefCount(keyObj);
+ Tcl_DecrRefCount(valueObj);
+ Tcl_DecrRefCount(dictObj);
+ goto nonConstant;
+ }
+ tokenPtr = TokenAfter(tokenPtr);
+ Tcl_DictObjPut(NULL, dictObj, keyObj, valueObj);
+ Tcl_DecrRefCount(keyObj);
+ Tcl_DecrRefCount(valueObj);
+ }
+
+ /*
+ * We did! Excellent. The "verifyDict" is to do type forcing.
+ */
+
+ bytes = Tcl_GetStringFromObj(dictObj, &len);
+ PushLiteral(envPtr, bytes, len);
+ TclEmitOpcode( INST_DUP, envPtr);
+ TclEmitOpcode( INST_DICT_VERIFY, envPtr);
+ Tcl_DecrRefCount(dictObj);
+ return TCL_OK;
+
+ /*
+ * Otherwise, we've got to issue runtime code to do the building, which we
+ * do by [dict set]ting into an unnamed local variable. This requires that
+ * we are in a context with an LVT.
+ */
+
+ nonConstant:
+ worker = TclFindCompiledLocal(NULL, 0, 1, envPtr);
+ if (worker < 0) {
+ return TCL_ERROR;
+ }
+
+ PushLiteral(envPtr, "", 0);
+ Emit14Inst( INST_STORE_SCALAR, worker, envPtr);
+ TclEmitOpcode( INST_POP, envPtr);
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ for (i=1 ; i<parsePtr->numWords ; i+=2) {
+ CompileWord(envPtr, tokenPtr, interp, i);
+ tokenPtr = TokenAfter(tokenPtr);
+ CompileWord(envPtr, tokenPtr, interp, i+1);
+ tokenPtr = TokenAfter(tokenPtr);
+ TclEmitInstInt4( INST_DICT_SET, 1, envPtr);
+ TclEmitInt4( worker, envPtr);
+ TclAdjustStackDepth(-1, envPtr);
+ TclEmitOpcode( INST_POP, envPtr);
+ }
+ Emit14Inst( INST_LOAD_SCALAR, worker, envPtr);
+ TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
+ TclEmitInt4( worker, envPtr);
+ return TCL_OK;
+}
+
+int
+TclCompileDictMergeCmd(
+ Tcl_Interp *interp, /* Used for looking up stuff. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr;
+ int i, workerIndex, infoIndex, outLoop;
+
+ /*
+ * Deal with some special edge cases. Note that in the case with one
+ * argument, the only thing to do is to verify the dict-ness.
+ */
+
+ if (parsePtr->numWords < 2) {
+ PushLiteral(envPtr, "", 0);
+ return TCL_OK;
+ } else if (parsePtr->numWords == 2) {
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ CompileWord(envPtr, tokenPtr, interp, 1);
+ TclEmitOpcode( INST_DUP, envPtr);
+ TclEmitOpcode( INST_DICT_VERIFY, envPtr);
+ return TCL_OK;
+ }
+
+ /*
+ * There's real merging work to do.
+ *
+ * Allocate some working space. This means we'll only ever compile this
+ * command when there's an LVT present.
+ */
+
+ workerIndex = TclFindCompiledLocal(NULL, 0, 1, envPtr);
+ if (workerIndex < 0) {
+ return TCL_ERROR;
+ }
+ infoIndex = TclFindCompiledLocal(NULL, 0, 1, envPtr);
+
+ /*
+ * Get the first dictionary and verify that it is so.
+ */
+
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ CompileWord(envPtr, tokenPtr, interp, 1);
+ TclEmitOpcode( INST_DUP, envPtr);
+ TclEmitOpcode( INST_DICT_VERIFY, envPtr);
+ Emit14Inst( INST_STORE_SCALAR, workerIndex, envPtr);
+ TclEmitOpcode( INST_POP, envPtr);
+
+ /*
+ * For each of the remaining dictionaries...
+ */
+
+ outLoop = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ TclEmitInstInt4( INST_BEGIN_CATCH4, outLoop, envPtr);
+ ExceptionRangeStarts(envPtr, outLoop);
+ for (i=2 ; i<parsePtr->numWords ; i++) {
+ /*
+ * Get the dictionary, and merge its pairs into the first dict (using
+ * a small loop).
+ */
+
+ tokenPtr = TokenAfter(tokenPtr);
+ CompileWord(envPtr, tokenPtr, interp, i);
+ TclEmitInstInt4( INST_DICT_FIRST, infoIndex, envPtr);
+ TclEmitInstInt1( INST_JUMP_TRUE1, 24, envPtr);
+ TclEmitInstInt4( INST_REVERSE, 2, envPtr);
+ TclEmitInstInt4( INST_DICT_SET, 1, envPtr);
+ TclEmitInt4( workerIndex, envPtr);
+ TclAdjustStackDepth(-1, envPtr);
+ TclEmitOpcode( INST_POP, envPtr);
+ TclEmitInstInt4( INST_DICT_NEXT, infoIndex, envPtr);
+ TclEmitInstInt1( INST_JUMP_FALSE1, -20, envPtr);
+ TclEmitOpcode( INST_POP, envPtr);
+ TclEmitOpcode( INST_POP, envPtr);
+ TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
+ TclEmitInt4( infoIndex, envPtr);
+ }
+ ExceptionRangeEnds(envPtr, outLoop);
+ TclEmitOpcode( INST_END_CATCH, envPtr);
+
+ /*
+ * Clean up any state left over.
+ */
+
+ Emit14Inst( INST_LOAD_SCALAR, workerIndex, envPtr);
+ TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
+ TclEmitInt4( workerIndex, envPtr);
+ TclEmitInstInt1( INST_JUMP1, 18, envPtr);
+
+ /*
+ * If an exception happens when starting to iterate over the second (and
+ * subsequent) dicts. This is strictly not necessary, but it is nice.
+ */
+
+ ExceptionRangeTarget(envPtr, outLoop, catchOffset);
+ TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
+ TclEmitOpcode( INST_PUSH_RESULT, envPtr);
+ TclEmitOpcode( INST_END_CATCH, envPtr);
+ TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
+ TclEmitInt4( workerIndex, envPtr);
+ TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
+ TclEmitInt4( infoIndex, envPtr);
+ TclEmitOpcode( INST_RETURN_STK, envPtr);
+
return TCL_OK;
}
@@ -1036,6 +1502,7 @@ CompileDictEachCmd(
TclEmitInstInt4(INST_OVER, 1, envPtr);
TclEmitInstInt4(INST_DICT_SET, 1, envPtr);
TclEmitInt4( collectVar, envPtr);
+ TclAdjustStackDepth(-1, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
TclEmitOpcode( INST_POP, envPtr);
@@ -1070,7 +1537,7 @@ CompileDictEachCmd(
ExceptionRangeTarget(envPtr, loopRange, breakOffset);
TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( infoIndex, envPtr);
+ TclEmitInt4( infoIndex, envPtr);
TclEmitOpcode( INST_END_CATCH, envPtr);
endTargetOffset = CurrentOffset(envPtr);
TclEmitInstInt4( INST_JUMP4, 0, envPtr);
@@ -1084,7 +1551,7 @@ CompileDictEachCmd(
TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
TclEmitOpcode( INST_PUSH_RESULT, envPtr);
TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
- TclEmitInt4( infoIndex, envPtr);
+ TclEmitInt4( infoIndex, envPtr);
TclEmitOpcode( INST_END_CATCH, envPtr);
if (collect == TCL_EACH_COLLECT) {
TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr);
@@ -1098,7 +1565,7 @@ CompileDictEachCmd(
* easy!) Note that we skip the END_CATCH. [Bug 1382528]
*/
- envPtr->currStackDepth = savedStackDepth+2;
+ envPtr->currStackDepth = savedStackDepth + 2;
jumpDisplacement = CurrentOffset(envPtr) - emptyTargetOffset;
TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDisplacement,
envPtr->codeStart + emptyTargetOffset);
@@ -1294,6 +1761,7 @@ TclCompileDictUpdateCmd(
(int) (CurrentOffset(envPtr) - jumpFixup.codeOffset));
}
TclStackFree(interp, keyTokenPtrs);
+ envPtr->currStackDepth = savedStackDepth + 1;
return TCL_OK;
}
@@ -1542,6 +2010,7 @@ TclCompileDictWithCmd(
PushLiteral(envPtr, "", 0);
}
}
+ envPtr->currStackDepth = savedStackDepth + 1;
return TCL_OK;
}
@@ -1660,6 +2129,7 @@ TclCompileDictWithCmd(
* Prepare for the start of the next command.
*/
+ envPtr->currStackDepth = savedStackDepth + 1;
if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
Tcl_Panic("TclCompileDictCmd(update): bad jump distance %d",
(int) (CurrentOffset(envPtr) - jumpFixup.codeOffset));
@@ -1759,6 +2229,7 @@ TclCompileErrorCmd(
* However, we only deal with the case where there is just a message.
*/
Tcl_Token *messageTokenPtr;
+ int savedStackDepth = envPtr->currStackDepth;
DefineLineInformation; /* TIP #280 */
if (parsePtr->numWords != 2) {
@@ -1769,6 +2240,7 @@ TclCompileErrorCmd(
PushLiteral(envPtr, "-code error -level 0", 20);
CompileWord(envPtr, messageTokenPtr, interp, 1);
TclEmitOpcode(INST_RETURN_STK, envPtr);
+ envPtr->currStackDepth = savedStackDepth + 1;
return TCL_OK;
}
@@ -2512,6 +2984,226 @@ PrintForeachInfo(
/*
*----------------------------------------------------------------------
*
+ * TclCompileFormatCmd --
+ *
+ * Procedure called to compile the "format" command. Handles cases that
+ * can be done as constants or simple string concatenation only.
+ *
+ * Results:
+ * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
+ * evaluation to runtime.
+ *
+ * Side effects:
+ * Instructions are added to envPtr to execute the "format" command at
+ * runtime.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclCompileFormatCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr = parsePtr->tokenPtr;
+ Tcl_Obj **objv, *formatObj, *tmpObj;
+ char *bytes, *start;
+ int i, j, len;
+
+ /*
+ * Don't handle any guaranteed-error cases.
+ */
+
+ if (parsePtr->numWords < 2) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Check if the argument words are all compile-time-known literals; that's
+ * a case we can handle by compiling to a constant.
+ */
+
+ formatObj = Tcl_NewObj();
+ Tcl_IncrRefCount(formatObj);
+ tokenPtr = TokenAfter(tokenPtr);
+ if (!TclWordKnownAtCompileTime(tokenPtr, formatObj)) {
+ Tcl_DecrRefCount(formatObj);
+ return TCL_ERROR;
+ }
+
+ objv = ckalloc((parsePtr->numWords-2) * sizeof(Tcl_Obj *));
+ for (i=0 ; i+2 < parsePtr->numWords ; i++) {
+ tokenPtr = TokenAfter(tokenPtr);
+ objv[i] = Tcl_NewObj();
+ Tcl_IncrRefCount(objv[i]);
+ if (!TclWordKnownAtCompileTime(tokenPtr, objv[i])) {
+ goto checkForStringConcatCase;
+ }
+ }
+
+ /*
+ * Everything is a literal, so the result is constant too (or an error if
+ * the format is broken). Do the format now.
+ */
+
+ tmpObj = Tcl_Format(interp, Tcl_GetString(formatObj),
+ parsePtr->numWords-2, objv);
+ for (; --i>=0 ;) {
+ Tcl_DecrRefCount(objv[i]);
+ }
+ ckfree(objv);
+ Tcl_DecrRefCount(formatObj);
+ if (tmpObj == NULL) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Not an error, always a constant result, so just push the result as a
+ * literal. Job done.
+ */
+
+ bytes = Tcl_GetStringFromObj(tmpObj, &len);
+ PushLiteral(envPtr, bytes, len);
+ Tcl_DecrRefCount(tmpObj);
+ return TCL_OK;
+
+ checkForStringConcatCase:
+ /*
+ * See if we can generate a sequence of things to concatenate. This
+ * requires that all the % sequences be %s or %%, as everything else is
+ * sufficiently complex that we don't bother.
+ *
+ * First, get the state of the system relatively sensible (cleaning up
+ * after our attempt to spot a literal).
+ */
+
+ for (; --i>=0 ;) {
+ Tcl_DecrRefCount(objv[i]);
+ }
+ ckfree(objv);
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ tokenPtr = TokenAfter(tokenPtr);
+ i = 0;
+
+ /*
+ * Now scan through and check for non-%s and non-%% substitutions.
+ */
+
+ for (bytes = Tcl_GetString(formatObj) ; *bytes ; bytes++) {
+ if (*bytes == '%') {
+ bytes++;
+ if (*bytes == 's') {
+ i++;
+ continue;
+ } else if (*bytes == '%') {
+ continue;
+ }
+ Tcl_DecrRefCount(formatObj);
+ return TCL_ERROR;
+ }
+ }
+
+ /*
+ * Check if the number of things to concatenate will fit in a byte.
+ */
+
+ if (i+2 != parsePtr->numWords || i > 125) {
+ Tcl_DecrRefCount(formatObj);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Generate the pushes of the things to concatenate, a sequence of
+ * literals and compiled tokens (of which at least one is non-literal or
+ * we'd have the case in the first half of this function) which we will
+ * concatenate.
+ */
+
+ i = 0; /* The count of things to concat. */
+ j = 2; /* The index into the argument tokens, for
+ * TIP#280 handling. */
+ start = Tcl_GetString(formatObj);
+ /* The start of the currently-scanned literal
+ * in the format string. */
+ tmpObj = Tcl_NewObj(); /* The buffer used to accumulate the literal
+ * being built. */
+ for (bytes = start ; *bytes ; bytes++) {
+ if (*bytes == '%') {
+ Tcl_AppendToObj(tmpObj, start, bytes - start);
+ if (*++bytes == '%') {
+ Tcl_AppendToObj(tmpObj, "%", 1);
+ } else {
+ char *b = Tcl_GetStringFromObj(tmpObj, &len);
+
+ /*
+ * If there is a non-empty literal from the format string,
+ * push it and reset.
+ */
+
+ if (len > 0) {
+ PushLiteral(envPtr, b, len);
+ Tcl_DecrRefCount(tmpObj);
+ tmpObj = Tcl_NewObj();
+ i++;
+ }
+
+ /*
+ * Push the code to produce the string that would be
+ * substituted with %s, except we'll be concatenating
+ * directly.
+ */
+
+ CompileWord(envPtr, tokenPtr, interp, j);
+ tokenPtr = TokenAfter(tokenPtr);
+ j++;
+ i++;
+ }
+ start = bytes + 1;
+ }
+ }
+
+ /*
+ * Handle the case of a trailing literal.
+ */
+
+ Tcl_AppendToObj(tmpObj, start, bytes - start);
+ bytes = Tcl_GetStringFromObj(tmpObj, &len);
+ if (len > 0) {
+ PushLiteral(envPtr, bytes, len);
+ i++;
+ }
+ Tcl_DecrRefCount(tmpObj);
+ Tcl_DecrRefCount(formatObj);
+
+ if (i > 1) {
+ /*
+ * Do the concatenation, which produces the result.
+ */
+
+ TclEmitInstInt1(INST_CONCAT1, i, envPtr);
+ } else {
+ /*
+ * EVIL HACK! Force there to be a string representation in the case
+ * where there's just a "%s" in the format; case covered by the test
+ * format-20.1 (and it is horrible...)
+ */
+
+ TclEmitOpcode(INST_DUP, envPtr);
+ PushLiteral(envPtr, "", 0);
+ TclEmitOpcode(INST_STR_EQ, envPtr);
+ TclEmitOpcode(INST_POP, envPtr);
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclCompileGlobalCmd --
*
* Procedure called to compile the "global" command.
@@ -3022,22 +3714,105 @@ TclCompileIncrCmd(
/*
*----------------------------------------------------------------------
*
- * TclCompileInfoExistsCmd --
+ * TclCompileInfo*Cmd --
*
- * Procedure called to compile the "info exists" subcommand.
+ * Procedures called to compile "info" subcommands.
*
* Results:
* Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
* evaluation to runtime.
*
* Side effects:
- * Instructions are added to envPtr to execute the "info exists"
- * subcommand at runtime.
+ * Instructions are added to envPtr to execute the "info" subcommand at
+ * runtime.
*
*----------------------------------------------------------------------
*/
int
+TclCompileInfoCommandsCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr)
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr;
+ Tcl_Obj *objPtr;
+ char *bytes;
+
+ /*
+ * We require one compile-time known argument for the case we can compile.
+ */
+
+ if (parsePtr->numWords != 2) {
+ return TCL_ERROR;
+ }
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ objPtr = Tcl_NewObj();
+ Tcl_IncrRefCount(objPtr);
+ if (!TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
+ goto notCompilable;
+ }
+ bytes = Tcl_GetString(objPtr);
+
+ /*
+ * We require that the argument start with "::" and not have any of "*\[?"
+ * in it. (Theoretically, we should look in only the final component, but
+ * the difference is so slight given current naming practices.)
+ */
+
+ if (bytes[0] != ':' || bytes[1] != ':' || !TclMatchIsTrivial(bytes)) {
+ goto notCompilable;
+ }
+ Tcl_DecrRefCount(objPtr);
+
+ /*
+ * Confirmed as a literal that will not frighten the horses. Compile. Note
+ * that the result needs to be list-ified.
+ */
+
+ CompileWord(envPtr, tokenPtr, interp, 1);
+ TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr);
+ TclEmitOpcode( INST_DUP, envPtr);
+ TclEmitOpcode( INST_STR_LEN, envPtr);
+ TclEmitInstInt1( INST_JUMP_FALSE1, 7, envPtr);
+ TclEmitInstInt4( INST_LIST, 1, envPtr);
+ return TCL_OK;
+
+ notCompilable:
+ Tcl_DecrRefCount(objPtr);
+ return TCL_ERROR;
+}
+
+int
+TclCompileInfoCoroutineCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ /*
+ * Only compile [info coroutine] without arguments.
+ */
+
+ if (parsePtr->numWords != 1) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Not much to do; we compile to a single instruction...
+ */
+
+ TclEmitOpcode( INST_COROUTINE_NAME, envPtr);
+ return TCL_OK;
+}
+
+int
TclCompileInfoExistsCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
@@ -3088,6 +3863,118 @@ TclCompileInfoExistsCmd(
return TCL_OK;
}
+
+int
+TclCompileInfoLevelCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ /*
+ * Only compile [info level] without arguments or with a single argument.
+ */
+
+ if (parsePtr->numWords == 1) {
+ /*
+ * Not much to do; we compile to a single instruction...
+ */
+
+ TclEmitOpcode( INST_INFO_LEVEL_NUM, envPtr);
+ } else if (parsePtr->numWords != 2) {
+ return TCL_ERROR;
+ } else {
+ DefineLineInformation; /* TIP #280 */
+
+ /*
+ * Compile the argument, then add the instruction to convert it into a
+ * list of arguments.
+ */
+
+ SetLineInformation(1);
+ CompileTokens(envPtr, TokenAfter(parsePtr->tokenPtr), interp);
+ TclEmitOpcode( INST_INFO_LEVEL_ARGS, envPtr);
+ }
+ return TCL_OK;
+}
+
+int
+TclCompileInfoObjectClassCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr)
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
+
+ if (parsePtr->numWords != 2) {
+ return TCL_ERROR;
+ }
+ CompileWord(envPtr, tokenPtr, interp, 1);
+ TclEmitOpcode( INST_TCLOO_CLASS, envPtr);
+ return TCL_OK;
+}
+
+int
+TclCompileInfoObjectIsACmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr)
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
+
+ /*
+ * We only handle [info object isa object <somevalue>]. The first three
+ * words are compressed to a single token by the ensemble compilation
+ * engine.
+ */
+
+ if (parsePtr->numWords != 3) {
+ return TCL_ERROR;
+ }
+ if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size < 1
+ || strncmp(tokenPtr[1].start, "object", tokenPtr[1].size)) {
+ return TCL_ERROR;
+ }
+ tokenPtr = TokenAfter(tokenPtr);
+
+ /*
+ * Issue the code.
+ */
+
+ CompileWord(envPtr, tokenPtr, interp, 2);
+ TclEmitOpcode( INST_TCLOO_IS_OBJECT, envPtr);
+ return TCL_OK;
+}
+
+int
+TclCompileInfoObjectNamespaceCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr)
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
+
+ if (parsePtr->numWords != 2) {
+ return TCL_ERROR;
+ }
+ CompileWord(envPtr, tokenPtr, interp, 1);
+ TclEmitOpcode( INST_TCLOO_NS, envPtr);
+ return TCL_OK;
+}
/*
*----------------------------------------------------------------------
@@ -3936,11 +4823,11 @@ TclCompileLmapCmd(
/*
*----------------------------------------------------------------------
*
- * TclCompileNamespaceCmd --
+ * TclCompileNamespace*Cmd --
*
- * Procedure called to compile the "namespace" command; currently, only
- * the subcommand "namespace upvar" is compiled to bytecodes, and then
- * only inside a procedure(-like) context.
+ * Procedures called to compile the "namespace" command; currently, only
+ * the subcommands "namespace current" and "namespace upvar" are compiled
+ * to bytecodes, and the latter only inside a procedure(-like) context.
*
* Results:
* Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
@@ -3954,6 +4841,154 @@ TclCompileLmapCmd(
*/
int
+TclCompileNamespaceCurrentCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ /*
+ * Only compile [namespace current] without arguments.
+ */
+
+ if (parsePtr->numWords != 1) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Not much to do; we compile to a single instruction...
+ */
+
+ TclEmitOpcode( INST_NS_CURRENT, envPtr);
+ return TCL_OK;
+}
+
+int
+TclCompileNamespaceCodeCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ Tcl_Token *tokenPtr;
+ DefineLineInformation; /* TIP #280 */
+
+ if (parsePtr->numWords != 2) {
+ return TCL_ERROR;
+ }
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+
+ /*
+ * The specification of [namespace code] is rather shocking, in that it is
+ * supposed to check if the argument is itself the result of [namespace
+ * code] and not apply itself in that case. Which is excessively cautious,
+ * but what the test suite checks for.
+ */
+
+ if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || (tokenPtr[1].size > 20
+ && strncmp(tokenPtr[1].start, "::namespace inscope ", 20) == 0)) {
+ /*
+ * Technically, we could just pass a literal '::namespace inscope '
+ * term through, but that's something which really shouldn't be
+ * occurring as something that the user writes so we'll just punt it.
+ */
+
+ return TCL_ERROR;
+ }
+
+ /*
+ * Now we can compile using the same strategy as [namespace code]'s normal
+ * implementation does internally. Note that we can't bind the namespace
+ * name directly here, because TclOO plays complex games with namespaces;
+ * the value needs to be determined at runtime for safety.
+ */
+
+ PushLiteral(envPtr, "::namespace", 11);
+ PushLiteral(envPtr, "inscope", 7);
+ TclEmitOpcode( INST_NS_CURRENT, envPtr);
+ CompileWord(envPtr, tokenPtr, interp, 1);
+ TclEmitInstInt4( INST_LIST, 4, envPtr);
+ return TCL_OK;
+}
+
+int
+TclCompileNamespaceQualifiersCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ DefineLineInformation; /* TIP #280 */
+ int off;
+
+ if (parsePtr->numWords != 2) {
+ return TCL_ERROR;
+ }
+
+ CompileWord(envPtr, tokenPtr, interp, 1);
+ PushLiteral(envPtr, "0", 1);
+ PushLiteral(envPtr, "::", 2);
+ TclEmitInstInt4( INST_OVER, 2, envPtr);
+ TclEmitOpcode( INST_STR_FIND_LAST, envPtr);
+ off = CurrentOffset(envPtr);
+ PushLiteral(envPtr, "1", 1);
+ TclEmitOpcode( INST_SUB, envPtr);
+ TclEmitInstInt4( INST_OVER, 2, envPtr);
+ TclEmitInstInt4( INST_OVER, 1, envPtr);
+ TclEmitOpcode( INST_STR_INDEX, envPtr);
+ PushLiteral(envPtr, ":", 1);
+ TclEmitOpcode( INST_STR_EQ, envPtr);
+ off = off - CurrentOffset(envPtr);
+ TclEmitInstInt1( INST_JUMP_TRUE1, off, envPtr);
+ TclEmitOpcode( INST_STR_RANGE, envPtr);
+ return TCL_OK;
+}
+
+int
+TclCompileNamespaceTailCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ DefineLineInformation; /* TIP #280 */
+ JumpFixup jumpFixup;
+
+ if (parsePtr->numWords != 2) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Take care; only add 2 to found index if the string was actually found.
+ */
+
+ CompileWord(envPtr, tokenPtr, interp, 1);
+ PushLiteral(envPtr, "::", 2);
+ TclEmitInstInt4( INST_OVER, 1, envPtr);
+ TclEmitOpcode( INST_STR_FIND_LAST, envPtr);
+ TclEmitOpcode( INST_DUP, envPtr);
+ PushLiteral(envPtr, "0", 1);
+ TclEmitOpcode( INST_GE, envPtr);
+ TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFixup);
+ PushLiteral(envPtr, "2", 1);
+ TclEmitOpcode( INST_ADD, envPtr);
+ TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127);
+ PushLiteral(envPtr, "end", 3);
+ TclEmitOpcode( INST_STR_RANGE, envPtr);
+ return TCL_OK;
+}
+
+int
TclCompileNamespaceUpvarCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
@@ -4015,6 +5050,52 @@ TclCompileNamespaceUpvarCmd(
PushLiteral(envPtr, "", 0);
return TCL_OK;
}
+
+int
+TclCompileNamespaceWhichCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr, *opt;
+ int idx;
+
+ if (parsePtr->numWords < 2 || parsePtr->numWords > 3) {
+ return TCL_ERROR;
+ }
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ idx = 1;
+
+ /*
+ * If there's an option, check that it's "-command". We don't handle
+ * "-variable" (currently) and anything else is an error.
+ */
+
+ if (parsePtr->numWords == 3) {
+ if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
+ return TCL_ERROR;
+ }
+ opt = tokenPtr + 1;
+ if (opt->size < 2 || opt->size > 8
+ || strncmp(opt->start, "-command", opt->size) != 0) {
+ return TCL_ERROR;
+ }
+ tokenPtr = TokenAfter(tokenPtr);
+ idx++;
+ }
+
+ /*
+ * Issue the bytecode.
+ */
+
+ CompileWord(envPtr, tokenPtr, interp, idx);
+ TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr);
+ return TCL_OK;
+}
/*
*----------------------------------------------------------------------
@@ -4184,6 +5265,180 @@ TclCompileRegexpCmd(
/*
*----------------------------------------------------------------------
*
+ * TclCompileRegsubCmd --
+ *
+ * Procedure called to compile the "regsub" command.
+ *
+ * Results:
+ * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
+ * evaluation to runtime.
+ *
+ * Side effects:
+ * Instructions are added to envPtr to execute the "regsub" command at
+ * runtime.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclCompileRegsubCmd(
+ Tcl_Interp *interp, /* Tcl interpreter for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the
+ * command. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds the resulting instructions. */
+{
+ /*
+ * We only compile the case with [regsub -all] where the pattern is both
+ * known at compile time and simple (i.e., no RE metacharacters). That is,
+ * the pattern must be translatable into a glob like "*foo*" with no other
+ * glob metacharacters inside it; there must be some "foo" in there too.
+ * The substitution string must also be known at compile time and free of
+ * metacharacters ("\digit" and "&"). Finally, there must not be a
+ * variable mentioned in the [regsub] to write the result back to (because
+ * we can't get the count of substitutions that would be the result in
+ * that case). The key is that these are the conditions under which a
+ * [string map] could be used instead, in particular a [string map] of the
+ * form we can compile to bytecode.
+ *
+ * In short, we look for:
+ *
+ * regsub -all [--] simpleRE string simpleReplacement
+ *
+ * The only optional part is the "--", and no other options are handled.
+ */
+
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr, *stringTokenPtr;
+ Tcl_Obj *patternObj = NULL, *replacementObj = NULL;
+ Tcl_DString pattern;
+ const char *bytes;
+ int len, exact, result = TCL_ERROR;
+
+ if (parsePtr->numWords < 5 || parsePtr->numWords > 6) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Parse the "-all", which must be the first argument (other options not
+ * supported, non-"-all" substitution we can't compile).
+ */
+
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size != 4
+ || strncmp(tokenPtr[1].start, "-all", 4)) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Get the pattern into patternObj, checking for "--" in the process.
+ */
+
+ Tcl_DStringInit(&pattern);
+ tokenPtr = TokenAfter(tokenPtr);
+ patternObj = Tcl_NewObj();
+ if (!TclWordKnownAtCompileTime(tokenPtr, patternObj)) {
+ goto done;
+ }
+ if (Tcl_GetString(patternObj)[0] == '-') {
+ if (strcmp(Tcl_GetString(patternObj), "--") != 0
+ || parsePtr->numWords == 5) {
+ goto done;
+ }
+ tokenPtr = TokenAfter(tokenPtr);
+ Tcl_DecrRefCount(patternObj);
+ patternObj = Tcl_NewObj();
+ if (!TclWordKnownAtCompileTime(tokenPtr, patternObj)) {
+ goto done;
+ }
+ } else if (parsePtr->numWords == 6) {
+ goto done;
+ }
+
+ /*
+ * Identify the code which produces the string to apply the substitution
+ * to (stringTokenPtr), and the replacement string (into replacementObj).
+ */
+
+ stringTokenPtr = TokenAfter(tokenPtr);
+ tokenPtr = TokenAfter(stringTokenPtr);
+ replacementObj = Tcl_NewObj();
+ if (!TclWordKnownAtCompileTime(tokenPtr, replacementObj)) {
+ goto done;
+ }
+
+ /*
+ * Next, higher-level checks. Is the RE a very simple glob? Is the
+ * replacement "simple"?
+ */
+
+ bytes = Tcl_GetStringFromObj(patternObj, &len);
+ if (TclReToGlob(NULL, bytes, len, &pattern, &exact) != TCL_OK || exact) {
+ goto done;
+ }
+ bytes = Tcl_DStringValue(&pattern);
+ if (*bytes++ != '*') {
+ goto done;
+ }
+ while (1) {
+ switch (*bytes) {
+ case '*':
+ if (bytes[1] == '\0') {
+ /*
+ * OK, we've proved there are no metacharacters except for the
+ * '*' at each end.
+ */
+
+ len = Tcl_DStringLength(&pattern) - 2;
+ if (len > 0) {
+ goto isSimpleGlob;
+ }
+
+ /*
+ * The pattern is "**"! I believe that should be impossible,
+ * but we definitely can't handle that at all.
+ */
+ }
+ case '\0': case '?': case '[': case '\\':
+ goto done;
+ }
+ bytes++;
+ }
+ isSimpleGlob:
+ for (bytes = Tcl_GetString(replacementObj); *bytes; bytes++) {
+ switch (*bytes) {
+ case '\\': case '&':
+ goto done;
+ }
+ }
+
+ /*
+ * Proved the simplicity constraints! Time to issue the code.
+ */
+
+ result = TCL_OK;
+ bytes = Tcl_DStringValue(&pattern) + 1;
+ PushLiteral(envPtr, bytes, len);
+ bytes = Tcl_GetStringFromObj(replacementObj, &len);
+ PushLiteral(envPtr, bytes, len);
+ CompileWord(envPtr, stringTokenPtr, interp, parsePtr->numWords-2);
+ TclEmitOpcode( INST_STR_MAP, envPtr);
+
+ done:
+ Tcl_DStringFree(&pattern);
+ if (patternObj) {
+ Tcl_DecrRefCount(patternObj);
+ }
+ if (replacementObj) {
+ Tcl_DecrRefCount(replacementObj);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclCompileReturnCmd --
*
* Procedure called to compile the "return" command.
@@ -4216,6 +5471,7 @@ TclCompileReturnCmd(
int numWords = parsePtr->numWords;
int explicitResult = (0 == (numWords % 2));
int numOptionWords = numWords - 1 - explicitResult;
+ int savedStackDepth = envPtr->currStackDepth;
Tcl_Obj *returnOpts, **objv;
Tcl_Token *wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
DefineLineInformation; /* TIP #280 */
@@ -4238,6 +5494,7 @@ TclCompileReturnCmd(
CompileWord(envPtr, optsTokenPtr, interp, 2);
CompileWord(envPtr, msgTokenPtr, interp, 3);
TclEmitOpcode(INST_RETURN_STK, envPtr);
+ envPtr->currStackDepth = savedStackDepth + 1;
return TCL_OK;
}
@@ -4662,6 +5919,69 @@ IndexTailVarIfKnown(
return localIndex;
}
+int
+TclCompileObjectSelfCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ /*
+ * We only handle [self] and [self object] (which is the same operation).
+ * These are the only very common operations on [self] for which
+ * bytecoding is at all reasonable.
+ */
+
+ if (parsePtr->numWords == 1) {
+ goto compileSelfObject;
+ } else if (parsePtr->numWords == 2) {
+ Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr), *subcmd;
+
+ if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size==0) {
+ return TCL_ERROR;
+ }
+
+ subcmd = tokenPtr + 1;
+ if (strncmp(subcmd->start, "object", subcmd->size) == 0) {
+ goto compileSelfObject;
+ } else if (strncmp(subcmd->start, "namespace", subcmd->size) == 0) {
+ goto compileSelfNamespace;
+ }
+ }
+
+ /*
+ * Can't compile; handle with runtime call.
+ */
+
+ return TCL_ERROR;
+
+ compileSelfObject:
+
+ /*
+ * This delegates the entire problem to a single opcode.
+ */
+
+ TclEmitOpcode( INST_TCLOO_SELF, envPtr);
+ return TCL_OK;
+
+ compileSelfNamespace:
+
+ /*
+ * This is formally only correct with TclOO methods as they are currently
+ * implemented; it assumes that the current namespace is invariably when a
+ * TclOO context is present is the object's namespace, and that's
+ * technically only something that's a matter of current policy. But it
+ * avoids creating another opcode, so that's all good!
+ */
+
+ TclEmitOpcode( INST_TCLOO_SELF, envPtr);
+ TclEmitOpcode( INST_POP, envPtr);
+ TclEmitOpcode( INST_NS_CURRENT, envPtr);
+ return TCL_OK;
+}
+
/*
*----------------------------------------------------------------------
*
diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c
index 8ed3a95..be63e0e 100644
--- a/generic/tclCompCmdsSZ.c
+++ b/generic/tclCompCmdsSZ.c
@@ -133,6 +133,8 @@ const AuxDataType tclJumptableInfoType = {
#define OP(name) TclEmitOpcode(INST_##name, envPtr)
#define OP1(name,val) TclEmitInstInt1(INST_##name,(val),envPtr)
#define OP4(name,val) TclEmitInstInt4(INST_##name,(val),envPtr)
+#define OP14(name,val1,val2) \
+ TclEmitInstInt1(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr)
#define OP44(name,val1,val2) \
TclEmitInstInt4(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr)
#define BODY(token,index) \
@@ -249,18 +251,18 @@ TclCompileSetCmd(
/*
*----------------------------------------------------------------------
*
- * TclCompileStringCmpCmd --
+ * TclCompileString*Cmd --
*
- * Procedure called to compile the simplest and most common form of the
- * "string compare" command.
+ * Procedures called to compile various subcommands of the "string"
+ * command.
*
* Results:
* Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
* evaluation to runtime.
*
* Side effects:
- * Instructions are added to envPtr to execute the "string compare"
- * command at runtime.
+ * Instructions are added to envPtr to execute the "string" command at
+ * runtime.
*
*----------------------------------------------------------------------
*/
@@ -296,25 +298,6 @@ TclCompileStringCmpCmd(
TclEmitOpcode(INST_STR_CMP, envPtr);
return TCL_OK;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileStringEqualCmd --
- *
- * Procedure called to compile the simplest and most common form of the
- * "string equal" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "string equal" command
- * at runtime.
- *
- *----------------------------------------------------------------------
- */
int
TclCompileStringEqualCmd(
@@ -347,25 +330,70 @@ TclCompileStringEqualCmd(
TclEmitOpcode(INST_STR_EQ, envPtr);
return TCL_OK;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileStringIndexCmd --
- *
- * Procedure called to compile the simplest and most common form of the
- * "string index" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "string index" command
- * at runtime.
- *
- *----------------------------------------------------------------------
- */
+
+int
+TclCompileStringFirstCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr;
+
+ /*
+ * We don't support any flags; the bytecode isn't that sophisticated.
+ */
+
+ if (parsePtr->numWords != 3) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Push the two operands onto the stack and then the test.
+ */
+
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ CompileWord(envPtr, tokenPtr, interp, 1);
+ tokenPtr = TokenAfter(tokenPtr);
+ CompileWord(envPtr, tokenPtr, interp, 2);
+ OP(STR_FIND);
+ return TCL_OK;
+}
+
+int
+TclCompileStringLastCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr;
+
+ /*
+ * We don't support any flags; the bytecode isn't that sophisticated.
+ */
+
+ if (parsePtr->numWords != 3) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Push the two operands onto the stack and then the test.
+ */
+
+ tokenPtr = TokenAfter(parsePtr->tokenPtr);
+ CompileWord(envPtr, tokenPtr, interp, 1);
+ tokenPtr = TokenAfter(tokenPtr);
+ CompileWord(envPtr, tokenPtr, interp, 2);
+ OP(STR_FIND_LAST);
+ return TCL_OK;
+}
int
TclCompileStringIndexCmd(
@@ -394,25 +422,6 @@ TclCompileStringIndexCmd(
TclEmitOpcode(INST_STR_INDEX, envPtr);
return TCL_OK;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileStringMatchCmd --
- *
- * Procedure called to compile the simplest and most common form of the
- * "string match" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "string match" command
- * at runtime.
- *
- *----------------------------------------------------------------------
- */
int
TclCompileStringMatchCmd(
@@ -494,25 +503,6 @@ TclCompileStringMatchCmd(
}
return TCL_OK;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCompileStringLenCmd --
- *
- * Procedure called to compile the simplest and most common form of the
- * "string length" command.
- *
- * Results:
- * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
- * evaluation to runtime.
- *
- * Side effects:
- * Instructions are added to envPtr to execute the "string length"
- * command at runtime.
- *
- *----------------------------------------------------------------------
- */
int
TclCompileStringLenCmd(
@@ -553,6 +543,158 @@ TclCompileStringLenCmd(
TclDecrRefCount(objPtr);
return TCL_OK;
}
+
+int
+TclCompileStringMapCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *mapTokenPtr, *stringTokenPtr;
+ Tcl_Obj *mapObj, **objv;
+ char *bytes;
+ int len;
+
+ /*
+ * We only handle the case:
+ *
+ * string map {foo bar} $thing
+ *
+ * That is, a literal two-element list (doesn't need to be brace-quoted,
+ * but does need to be compile-time knowable) and any old argument (the
+ * thing to map).
+ */
+
+ if (parsePtr->numWords != 3) {
+ return TCL_ERROR;
+ }
+ mapTokenPtr = TokenAfter(parsePtr->tokenPtr);
+ stringTokenPtr = TokenAfter(mapTokenPtr);
+ mapObj = Tcl_NewObj();
+ Tcl_IncrRefCount(mapObj);
+ if (!TclWordKnownAtCompileTime(mapTokenPtr, mapObj)) {
+ Tcl_DecrRefCount(mapObj);
+ return TCL_ERROR;
+ } else if (Tcl_ListObjGetElements(NULL, mapObj, &len, &objv) != TCL_OK) {
+ Tcl_DecrRefCount(mapObj);
+ return TCL_ERROR;
+ } else if (len != 2) {
+ Tcl_DecrRefCount(mapObj);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Now issue the opcodes. Note that in the case that we know that the
+ * first word is an empty word, we don't issue the map at all. That is the
+ * correct semantics for mapping.
+ */
+
+ bytes = Tcl_GetStringFromObj(objv[0], &len);
+ if (len == 0) {
+ CompileWord(envPtr, stringTokenPtr, interp, 2);
+ } else {
+ PushLiteral(envPtr, bytes, len);
+ bytes = Tcl_GetStringFromObj(objv[1], &len);
+ PushLiteral(envPtr, bytes, len);
+ CompileWord(envPtr, stringTokenPtr, interp, 2);
+ OP(STR_MAP);
+ }
+ Tcl_DecrRefCount(mapObj);
+ return TCL_OK;
+}
+
+int
+TclCompileStringRangeCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *stringTokenPtr, *fromTokenPtr, *toTokenPtr;
+ Tcl_Obj *tmpObj;
+ int idx1, idx2, result;
+
+ if (parsePtr->numWords != 4) {
+ return TCL_ERROR;
+ }
+ stringTokenPtr = TokenAfter(parsePtr->tokenPtr);
+ fromTokenPtr = TokenAfter(stringTokenPtr);
+ toTokenPtr = TokenAfter(fromTokenPtr);
+
+ /*
+ * Parse the first index. Will only compile if it is constant and not an
+ * _integer_ less than zero (since we reserve negative indices here for
+ * end-relative indexing).
+ */
+
+ tmpObj = Tcl_NewObj();
+ result = TCL_ERROR;
+ if (TclWordKnownAtCompileTime(fromTokenPtr, tmpObj)) {
+ if (TclGetIntFromObj(NULL, tmpObj, &idx1) == TCL_OK) {
+ if (idx1 >= 0) {
+ result = TCL_OK;
+ }
+ } else if (TclGetIntForIndexM(NULL, tmpObj, -2, &idx1) == TCL_OK) {
+ if (idx1 <= -2) {
+ result = TCL_OK;
+ }
+ }
+ }
+ TclDecrRefCount(tmpObj);
+ if (result != TCL_OK) {
+ goto nonConstantIndices;
+ }
+
+ /*
+ * Parse the second index. Will only compile if it is constant and not an
+ * _integer_ less than zero (since we reserve negative indices here for
+ * end-relative indexing).
+ */
+
+ tmpObj = Tcl_NewObj();
+ result = TCL_ERROR;
+ if (TclWordKnownAtCompileTime(toTokenPtr, tmpObj)) {
+ if (TclGetIntFromObj(NULL, tmpObj, &idx2) == TCL_OK) {
+ if (idx2 >= 0) {
+ result = TCL_OK;
+ }
+ } else if (TclGetIntForIndexM(NULL, tmpObj, -2, &idx2) == TCL_OK) {
+ if (idx2 <= -2) {
+ result = TCL_OK;
+ }
+ }
+ }
+ TclDecrRefCount(tmpObj);
+ if (result != TCL_OK) {
+ goto nonConstantIndices;
+ }
+
+ /*
+ * Push the operand onto the stack and then the substring operation.
+ */
+
+ CompileWord(envPtr, stringTokenPtr, interp, 1);
+ OP44( STR_RANGE_IMM, idx1, idx2);
+ return TCL_OK;
+
+ /*
+ * Push the operands onto the stack and then the substring operation.
+ */
+
+ nonConstantIndices:
+ CompileWord(envPtr, stringTokenPtr, interp, 1);
+ CompileWord(envPtr, fromTokenPtr, interp, 2);
+ CompileWord(envPtr, toTokenPtr, interp, 3);
+ OP( STR_RANGE);
+ return TCL_OK;
+}
/*
*----------------------------------------------------------------------
@@ -697,11 +839,11 @@ TclSubstCompile(
}
while (count > 255) {
- TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
+ OP1( CONCAT1, 255);
count -= 254;
}
if (count > 1) {
- TclEmitInstInt1(INST_CONCAT1, count, envPtr);
+ OP1( CONCAT1, count);
count = 1;
}
@@ -722,7 +864,7 @@ TclSubstCompile(
envPtr->line = bline;
catchRange = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
- TclEmitInstInt4(INST_BEGIN_CATCH4, catchRange, envPtr);
+ OP4( BEGIN_CATCH4, catchRange);
ExceptionRangeStarts(envPtr, catchRange);
switch (tokenPtr->type) {
@@ -743,20 +885,20 @@ TclSubstCompile(
ExceptionRangeEnds(envPtr, catchRange);
/* Substitution produced TCL_OK */
- TclEmitOpcode(INST_END_CATCH, envPtr);
+ OP( END_CATCH);
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &okFixup);
/* Exceptional return codes processed here */
ExceptionRangeTarget(envPtr, catchRange, catchOffset);
- TclEmitOpcode(INST_PUSH_RETURN_OPTIONS, envPtr);
- TclEmitOpcode(INST_PUSH_RESULT, envPtr);
- TclEmitOpcode(INST_PUSH_RETURN_CODE, envPtr);
- TclEmitOpcode(INST_END_CATCH, envPtr);
- TclEmitOpcode(INST_RETURN_CODE_BRANCH, envPtr);
+ OP( PUSH_RETURN_OPTIONS);
+ OP( PUSH_RESULT);
+ OP( PUSH_RETURN_CODE);
+ OP( END_CATCH);
+ OP( RETURN_CODE_BRANCH);
/* ERROR -> reraise it */
- TclEmitOpcode(INST_RETURN_STK, envPtr);
- TclEmitOpcode(INST_NOP, envPtr);
+ OP( RETURN_STK);
+ OP( NOP);
/* RETURN */
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &returnFixup);
@@ -775,14 +917,14 @@ TclSubstCompile(
Tcl_Panic("TclCompileSubstCmd: bad break jump distance %d",
(int) (CurrentOffset(envPtr) - breakFixup.codeOffset));
}
- TclEmitOpcode(INST_POP, envPtr);
- TclEmitOpcode(INST_POP, envPtr);
+ OP( POP);
+ OP( POP);
breakJump = CurrentOffset(envPtr) - breakOffset;
if (breakJump > 127) {
- TclEmitInstInt4(INST_JUMP4, -breakJump, envPtr);
+ OP4(JUMP4, -breakJump);
} else {
- TclEmitInstInt1(INST_JUMP1, -breakJump, envPtr);
+ OP1(JUMP1, -breakJump);
}
/* CONTINUE destination */
@@ -790,8 +932,8 @@ TclSubstCompile(
Tcl_Panic("TclCompileSubstCmd: bad continue jump distance %d",
(int) (CurrentOffset(envPtr) - continueFixup.codeOffset));
}
- TclEmitOpcode(INST_POP, envPtr);
- TclEmitOpcode(INST_POP, envPtr);
+ OP( POP);
+ OP( POP);
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &endFixup);
/* RETURN + other destination */
@@ -808,8 +950,8 @@ TclSubstCompile(
* Pull the result to top of stack, discard options dict.
*/
- TclEmitInstInt4(INST_REVERSE, 2, envPtr);
- TclEmitOpcode(INST_POP, envPtr);
+ OP4( REVERSE, 2);
+ OP( POP);
/*
* We've emitted several POP instructions, and the automatic
@@ -828,7 +970,7 @@ TclSubstCompile(
(int) (CurrentOffset(envPtr) - okFixup.codeOffset));
}
if (count > 1) {
- TclEmitInstInt1(INST_CONCAT1, count, envPtr);
+ OP1(CONCAT1, count);
count = 1;
}
@@ -840,13 +982,12 @@ TclSubstCompile(
bline = envPtr->line;
}
-
while (count > 255) {
- TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
+ OP1( CONCAT1, 255);
count -= 254;
}
if (count > 1) {
- TclEmitInstInt1(INST_CONCAT1, count, envPtr);
+ OP1( CONCAT1, count);
}
Tcl_FreeParse(&parse);
@@ -854,6 +995,7 @@ TclSubstCompile(
if (state != NULL) {
Tcl_RestoreInterpState(interp, state);
TclCompileSyntaxError(interp, envPtr);
+ TclAdjustStackDepth(-1, envPtr);
}
/* Final target of the multi-jump from all BREAKs */
@@ -1277,14 +1419,14 @@ IssueSwitchChainedTests(
switch (mode) {
case Switch_Exact:
- TclEmitOpcode(INST_DUP, envPtr);
+ OP( DUP);
TclCompileTokens(interp, bodyToken[i], 1, envPtr);
- TclEmitOpcode(INST_STR_EQ, envPtr);
+ OP( STR_EQ);
break;
case Switch_Glob:
TclCompileTokens(interp, bodyToken[i], 1, envPtr);
- TclEmitInstInt4(INST_OVER, 1, envPtr);
- TclEmitInstInt1(INST_STR_MATCH, noCase, envPtr);
+ OP4( OVER, 1);
+ OP1( STR_MATCH, noCase);
break;
case Switch_Regexp:
simple = exact = 0;
@@ -1323,7 +1465,7 @@ IssueSwitchChainedTests(
TclCompileTokens(interp, bodyToken[i], 1, envPtr);
}
- TclEmitInstInt4(INST_OVER, 1, envPtr);
+ OP4( OVER, 1);
if (!simple) {
/*
* Pass correct RE compile flags. We use only Int1
@@ -1335,11 +1477,11 @@ IssueSwitchChainedTests(
int cflags = TCL_REG_ADVANCED
| (noCase ? TCL_REG_NOCASE : 0);
- TclEmitInstInt1(INST_REGEXP, cflags, envPtr);
+ OP1(REGEXP, cflags);
} else if (exact && !noCase) {
- TclEmitOpcode(INST_STR_EQ, envPtr);
+ OP( STR_EQ);
} else {
- TclEmitInstInt1(INST_STR_MATCH, noCase, envPtr);
+ OP1(STR_MATCH, noCase);
}
break;
default:
@@ -1404,7 +1546,7 @@ IssueSwitchChainedTests(
* pattern.
*/
- TclEmitOpcode(INST_POP, envPtr);
+ OP( POP);
envPtr->currStackDepth = savedStackDepth + 1;
envPtr->line = bodyLines[i+1]; /* TIP #280 */
envPtr->clNext = bodyContLines[i+1]; /* TIP #280 */
@@ -1426,7 +1568,7 @@ IssueSwitchChainedTests(
*/
if (!foundDefault) {
- TclEmitOpcode(INST_POP, envPtr);
+ OP( POP);
PushLiteral(envPtr, "", 0);
}
@@ -1498,6 +1640,7 @@ IssueSwitchJumpTable(
int **bodyContLines) /* Array of continuation line info. */
{
JumptableInfo *jtPtr;
+ int savedStackDepth = envPtr->currStackDepth;
int infoIndex, isNew, *finalFixups, numRealBodies = 0, jumpLocation;
int mustGenerate, foundDefault, jumpToDefault, i;
Tcl_DString buffer;
@@ -1537,9 +1680,9 @@ IssueSwitchJumpTable(
*/
jumpLocation = CurrentOffset(envPtr);
- TclEmitInstInt4(INST_JUMP_TABLE, infoIndex, envPtr);
+ OP4( JUMP_TABLE, infoIndex);
jumpToDefault = CurrentOffset(envPtr);
- TclEmitInstInt4(INST_JUMP4, 0, envPtr);
+ OP4( JUMP4, 0);
for (i=0 ; i<numBodyTokens ; i+=2) {
/*
@@ -1610,6 +1753,7 @@ IssueSwitchJumpTable(
* Compile the body of the arm.
*/
+ envPtr->currStackDepth = savedStackDepth;
envPtr->line = bodyLines[i+1]; /* TIP #280 */
envPtr->clNext = bodyContLines[i+1]; /* TIP #280 */
TclCompileCmdWord(interp, bodyToken[i+1], 1, envPtr);
@@ -1630,7 +1774,7 @@ IssueSwitchJumpTable(
* rewriting when we fixed this all up.
*/
- TclEmitInstInt4(INST_JUMP4, 0, envPtr);
+ OP4( JUMP4, 0);
}
}
@@ -1641,6 +1785,7 @@ IssueSwitchJumpTable(
*/
if (!foundDefault) {
+ envPtr->currStackDepth = savedStackDepth;
TclStoreInt4AtPtr(CurrentOffset(envPtr)-jumpToDefault,
envPtr->codeStart+jumpToDefault+1);
PushLiteral(envPtr, "", 0);
@@ -1661,6 +1806,7 @@ IssueSwitchJumpTable(
*/
TclStackFree(interp, finalFixups);
+ envPtr->currStackDepth = savedStackDepth + 1;
}
/*
@@ -1746,6 +1892,50 @@ PrintJumptableInfo(
/*
*----------------------------------------------------------------------
*
+ * TclCompileTailcallCmd --
+ *
+ * Procedure called to compile the "tailcall" command.
+ *
+ * Results:
+ * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
+ * evaluation to runtime.
+ *
+ * Side effects:
+ * Instructions are added to envPtr to execute the "tailcall" command at
+ * runtime.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclCompileTailcallCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *tokenPtr = parsePtr->tokenPtr;
+ int i;
+
+ if (parsePtr->numWords < 2 || parsePtr->numWords > 256
+ || envPtr->procPtr == NULL) {
+ return TCL_ERROR;
+ }
+
+ for (i=1 ; i<parsePtr->numWords ; i++) {
+ tokenPtr = TokenAfter(tokenPtr);
+ CompileWord(envPtr, tokenPtr, interp, i);
+ }
+ TclEmitInstInt1( INST_TAILCALL, parsePtr->numWords-1, envPtr);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclCompileThrowCmd --
*
* Procedure called to compile the "throw" command.
@@ -1772,6 +1962,7 @@ TclCompileThrowCmd(
{
DefineLineInformation; /* TIP #280 */
int numWords = parsePtr->numWords;
+ int savedStackDepth = envPtr->currStackDepth;
Tcl_Token *codeToken, *msgToken;
Tcl_Obj *objPtr;
@@ -1802,6 +1993,7 @@ TclCompileThrowCmd(
CompileWord(envPtr, msgToken, interp, 2);
TclCompileSyntaxError(interp, envPtr);
Tcl_DecrRefCount(objPtr);
+ envPtr->currStackDepth = savedStackDepth + 1;
return TCL_OK;
}
if (len == 0) {
@@ -1822,6 +2014,7 @@ TclCompileThrowCmd(
PushLiteral(envPtr, string, len);
TclDecrRefCount(dictPtr);
OP44( RETURN_IMM, 1, 0);
+ envPtr->currStackDepth = savedStackDepth + 1;
} else {
/*
* When the code token is not known at compilation time, we need to do
@@ -1850,6 +2043,7 @@ TclCompileThrowCmd(
PUSH( "");
OP44( RETURN_IMM, 1, 0);
}
+ envPtr->currStackDepth = savedStackDepth + 1;
TclDecrRefCount(objPtr);
return TCL_OK;
}
@@ -2117,6 +2311,7 @@ IssueTryInstructions(
{
DefineLineInformation; /* TIP #280 */
int range, resultVar, optionsVar;
+ int savedStackDepth = envPtr->currStackDepth;
int i, j, len, forwardsNeedFixing = 0;
int *addrsToFix, *forwardsToFix, notCodeJumpSource, notECJumpSource;
char buf[TCL_INTEGER_SPACE];
@@ -2178,6 +2373,7 @@ IssueTryInstructions(
LOAD( optionsVar);
PUSH( "-errorcode");
OP4( DICT_GET, 1);
+ TclAdjustStackDepth(-1, envPtr);
OP44( LIST_RANGE_IMM, 0, len-1);
PUSH( TclGetString(matchClauses[i]));
OP( STR_EQ);
@@ -2218,6 +2414,7 @@ IssueTryInstructions(
forwardsToFix[j] = -1;
}
}
+ envPtr->currStackDepth = savedStackDepth;
BODY( handlerTokens[i], 5+i*4);
}
@@ -2249,6 +2446,7 @@ IssueTryInstructions(
}
TclStackFree(interp, forwardsToFix);
TclStackFree(interp, addrsToFix);
+ envPtr->currStackDepth = savedStackDepth + 1;
return TCL_OK;
}
@@ -2285,6 +2483,7 @@ IssueTryFinallyInstructions(
range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
+ envPtr->currStackDepth = savedStackDepth;
BODY( bodyToken, 1);
ExceptionRangeEnds(envPtr, range);
PUSH( "0");
@@ -2329,6 +2528,7 @@ IssueTryFinallyInstructions(
LOAD( optionsVar);
PUSH( "-errorcode");
OP4( DICT_GET, 1);
+ TclAdjustStackDepth(-1, envPtr);
OP44( LIST_RANGE_IMM, 0, len-1);
PUSH( TclGetString(matchClauses[i]));
OP( STR_EQ);
@@ -2401,6 +2601,7 @@ IssueTryFinallyInstructions(
}
OP4( BEGIN_CATCH4, range);
}
+ envPtr->currStackDepth = savedStackDepth;
BODY( handlerTokens[i], 5+i*4);
ExceptionRangeEnds(envPtr, range);
OP( PUSH_RETURN_OPTIONS);
@@ -2452,7 +2653,6 @@ IssueTryFinallyInstructions(
*/
OP( POP);
- envPtr->currStackDepth = savedStackDepth;
/*
* Process the finally clause (at last!) Note that we do not wrap this in
@@ -2462,11 +2662,13 @@ IssueTryFinallyInstructions(
* next command (or some inter-command manipulation).
*/
+ envPtr->currStackDepth = savedStackDepth;
BODY( finallyToken, 3 + 4*numHandlers);
OP( POP);
LOAD( optionsVar);
LOAD( resultVar);
OP( RETURN_STK);
+ envPtr->currStackDepth = savedStackDepth + 1;
return TCL_OK;
}
@@ -2547,20 +2749,18 @@ TclCompileUnsetCmd(
*/
if (!simpleVarName) {
- TclEmitInstInt1( INST_UNSET_STK, flags, envPtr);
+ OP1( UNSET_STK, flags);
} else if (isScalar) {
if (localIndex < 0) {
- TclEmitInstInt1(INST_UNSET_STK, flags, envPtr);
+ OP1( UNSET_STK, flags);
} else {
- TclEmitInstInt1(INST_UNSET_SCALAR, flags, envPtr);
- TclEmitInt4( localIndex, envPtr);
+ OP14( UNSET_SCALAR, flags, localIndex);
}
} else {
if (localIndex < 0) {
- TclEmitInstInt1(INST_UNSET_ARRAY_STK, flags, envPtr);
+ OP1( UNSET_ARRAY_STK, flags);
} else {
- TclEmitInstInt1(INST_UNSET_ARRAY, flags, envPtr);
- TclEmitInt4( localIndex, envPtr);
+ OP14( UNSET_ARRAY, flags, localIndex);
}
}
@@ -2697,7 +2897,7 @@ TclCompileWhileCmd(
CompileBody(envPtr, bodyTokenPtr, interp);
ExceptionRangeEnds(envPtr, range);
envPtr->currStackDepth = savedStackDepth + 1;
- TclEmitOpcode(INST_POP, envPtr);
+ OP( POP);
/*
* Compile the test expression then emit the conditional jump that
@@ -2752,6 +2952,49 @@ TclCompileWhileCmd(
/*
*----------------------------------------------------------------------
*
+ * TclCompileYieldCmd --
+ *
+ * Procedure called to compile the "yield" command.
+ *
+ * Results:
+ * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
+ * evaluation to runtime.
+ *
+ * Side effects:
+ * Instructions are added to envPtr to execute the "yield" command at
+ * runtime.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclCompileYieldCmd(
+ Tcl_Interp *interp, /* Used for error reporting. */
+ Tcl_Parse *parsePtr, /* Points to a parse structure for the command
+ * created by Tcl_ParseCommand. */
+ Command *cmdPtr, /* Points to defintion of command being
+ * compiled. */
+ CompileEnv *envPtr) /* Holds resulting instructions. */
+{
+ if (parsePtr->numWords < 1 || parsePtr->numWords > 2) {
+ return TCL_ERROR;
+ }
+
+ if (parsePtr->numWords == 1) {
+ PushLiteral(envPtr, "", 0);
+ } else {
+ DefineLineInformation; /* TIP #280 */
+ Tcl_Token *valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
+
+ CompileWord(envPtr, valueTokenPtr, interp, 1);
+ }
+ OP( YIELD);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* PushVarName --
*
* Procedure used in the compiling where pushing a variable name is
@@ -3074,7 +3317,7 @@ CompileAssociativeBinaryOpCmd(
* calcuations, including roundoff errors.
*/
- TclEmitInstInt4(INST_REVERSE, words-1, envPtr);
+ OP4( REVERSE, words-1);
}
while (--words > 1) {
TclEmitOpcode(instruction, envPtr);
@@ -3165,31 +3408,19 @@ CompileComparisonOpCmd(
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
- if (tmpIndex <= 255) {
- TclEmitInstInt1(INST_STORE_SCALAR1, tmpIndex, envPtr);
- } else {
- TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
- }
+ STORE(tmpIndex);
TclEmitOpcode(instruction, envPtr);
for (words=3 ; words<parsePtr->numWords ;) {
- if (tmpIndex <= 255) {
- TclEmitInstInt1(INST_LOAD_SCALAR1, tmpIndex, envPtr);
- } else {
- TclEmitInstInt4(INST_LOAD_SCALAR4, tmpIndex, envPtr);
- }
+ LOAD(tmpIndex);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, words);
if (++words < parsePtr->numWords) {
- if (tmpIndex <= 255) {
- TclEmitInstInt1(INST_STORE_SCALAR1, tmpIndex, envPtr);
- } else {
- TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
- }
+ STORE(tmpIndex);
}
TclEmitOpcode(instruction, envPtr);
}
for (; words>3 ; words--) {
- TclEmitOpcode(INST_BITAND, envPtr);
+ OP( BITAND);
}
/*
@@ -3197,13 +3428,7 @@ CompileComparisonOpCmd(
* might be expensive elsewhere.
*/
- PushLiteral(envPtr, "", 0);
- if (tmpIndex <= 255) {
- TclEmitInstInt1(INST_STORE_SCALAR1, tmpIndex, envPtr);
- } else {
- TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
- }
- TclEmitOpcode(INST_POP, envPtr);
+ OP14( UNSET_SCALAR, 0, tmpIndex);
}
return TCL_OK;
}
diff --git a/generic/tclCompile.c b/generic/tclCompile.c
index d4ca284..309682d 100644
--- a/generic/tclCompile.c
+++ b/generic/tclCompile.c
@@ -37,7 +37,7 @@ TCL_DECLARE_MUTEX(tableMutex)
int tclTraceCompile = 0;
static int traceInitialized = 0;
#endif
-
+
/*
* A table describing the Tcl bytecode instructions. Entries in this table
* must correspond to the instruction opcode definitions in tclCompile.h. The
@@ -372,13 +372,13 @@ InstructionDesc const tclInstructionTable[] = {
* Stack: ... value => ...
* Note that the jump table contains offsets relative to the PC when
* it points to this instruction; the code is relocatable. */
- {"upvar", 5, 0, 1, {OPERAND_LVT4}},
+ {"upvar", 5, -1, 1, {OPERAND_LVT4}},
/* finds level and otherName in stack, links to local variable at
* index op1. Leaves the level on stack. */
- {"nsupvar", 5, 0, 1, {OPERAND_LVT4}},
+ {"nsupvar", 5, -1, 1, {OPERAND_LVT4}},
/* finds namespace and otherName in stack, links to local variable at
* index op1. Leaves the namespace on stack. */
- {"variable", 5, 0, 1, {OPERAND_LVT4}},
+ {"variable", 5, -1, 1, {OPERAND_LVT4}},
/* finds namespace and otherName in stack, links to local variable at
* index op1. Leaves the namespace on stack. */
{"syntax", 9, -1, 2, {OPERAND_INT4, OPERAND_UINT4}},
@@ -434,6 +434,100 @@ InstructionDesc const tclInstructionTable[] = {
/* Map variable contents back into a dictionary in the local variable
* indicated by the LVT index. Part of [dict with].
* Stack: ... path keyList => ... */
+ {"dictExists", 5, INT_MIN, 1, {OPERAND_UINT4}},
+ /* The top op4 words (min 1) are a key path into the dictionary just
+ * below the keys on the stack, and all those values are replaced by a
+ * boolean indicating whether it is possible to read out a value from
+ * that key-path (like [dict exists]).
+ * Stack: ... dict key1 ... keyN => ... boolean */
+ {"verifyDict", 1, -1, 0, {OPERAND_NONE}},
+ /* Verifies that the word on the top of the stack is a dictionary,
+ * popping it if it is and throwing an error if it is not.
+ * Stack: ... value => ... */
+
+ {"strmap", 1, -2, 0, {OPERAND_NONE}},
+ /* Simplified version of [string map] that only applies one change
+ * string, and only case-sensitively.
+ * Stack: ... from to string => ... changedString */
+ {"strfind", 1, -1, 0, {OPERAND_NONE}},
+ /* Find the first index of a needle string in a haystack string,
+ * producing the index (integer) or -1 if nothing found.
+ * Stack: ... needle haystack => ... index */
+ {"strrfind", 1, -1, 0, {OPERAND_NONE}},
+ /* Find the last index of a needle string in a haystack string,
+ * producing the index (integer) or -1 if nothing found.
+ * Stack: ... needle haystack => ... index */
+ {"strrangeImm", 9, 0, 2, {OPERAND_IDX4, OPERAND_IDX4}},
+ /* String Range: push (string range stktop op4 op4) */
+ {"strrange", 1, -2, 0, {OPERAND_NONE}},
+ /* String Range with non-constant arguments.
+ * Stack: ... string idxA idxB => ... substring */
+
+ {"yield", 1, 0, 0, {OPERAND_NONE}},
+ /* Makes the current coroutine yield the value at the top of the
+ * stack, and places the response back on top of the stack when it
+ * resumes.
+ * Stack: ... valueToYield => ... resumeValue */
+ {"coroName", 1, +1, 0, {OPERAND_NONE}},
+ /* Push the name of the interpreter's current coroutine as an object
+ * on the stack. */
+ {"tailcall", 2, INT_MIN, 1, {OPERAND_UINT1}},
+ /* Do a tailcall with the opnd items on the stack as the thing to
+ * tailcall to; opnd must be greater than 0 for the semantics to work
+ * right. */
+
+ {"currentNamespace", 1, +1, 0, {OPERAND_NONE}},
+ /* Push the name of the interpreter's current namespace as an object
+ * on the stack. */
+ {"infoLevelNumber", 1, +1, 0, {OPERAND_NONE}},
+ /* Push the stack depth (i.e., [info level]) of the interpreter as an
+ * object on the stack. */
+ {"infoLevelArgs", 1, 0, 0, {OPERAND_NONE}},
+ /* Push the argument words to a stack depth (i.e., [info level <n>])
+ * of the interpreter as an object on the stack.
+ * Stack: ... depth => ... argList */
+ {"resolveCmd", 1, 0, 0, {OPERAND_NONE}},
+ /* Resolves the command named on the top of the stack to its fully
+ * qualified version, or produces the empty string if no such command
+ * exists. Never generates errors.
+ * Stack: ... cmdName => ... fullCmdName */
+ {"tclooSelf", 1, +1, 0, {OPERAND_NONE}},
+ /* Push the identity of the current TclOO object (i.e., the name of
+ * its current public access command) on the stack. */
+ {"tclooClass", 1, 0, 0, {OPERAND_NONE}},
+ /* Push the class of the TclOO object named at the top of the stack
+ * onto the stack.
+ * Stack: ... object => ... class */
+ {"tclooNamespace", 1, 0, 0, {OPERAND_NONE}},
+ /* Push the namespace of the TclOO object named at the top of the
+ * stack onto the stack.
+ * Stack: ... object => ... namespace */
+ {"tclooIsObject", 1, 0, 0, {OPERAND_NONE}},
+ /* Push whether the value named at the top of the stack is a TclOO
+ * object (i.e., a boolean). Can corrupt the interpreter result
+ * despite not throwing, so not safe for use in a post-exception
+ * context.
+ * Stack: ... value => ... boolean */
+
+ {"arrayExistsStk", 1, 0, 0, {OPERAND_NONE}},
+ /* Looks up the element on the top of the stack and tests whether it
+ * is an array. Pushes a boolean describing whether this is the
+ * case. Also runs the whole-array trace on the named variable, so can
+ * throw anything.
+ * Stack: ... varName => ... boolean */
+ {"arrayExistsImm", 5, +1, 1, {OPERAND_UINT4}},
+ /* Looks up the variable indexed by opnd and tests whether it is an
+ * array. Pushes a boolean describing whether this is the case. Also
+ * runs the whole-array trace on the named variable, so can throw
+ * anything.
+ * Stack: ... => ... boolean */
+ {"arrayMakeStk", 1, -1, 0, {OPERAND_NONE}},
+ /* Forces the element on the top of the stack to be the name of an
+ * array.
+ * Stack: ... varName => ... */
+ {"arrayMakeImm", 5, 0, 1, {OPERAND_UINT4}},
+ /* Forces the variable indexed by opnd to be an array. Does not touch
+ * the stack. */
{NULL, 0, 0, 0, {OPERAND_NONE}}
};
@@ -1673,10 +1767,13 @@ TclCompileScript(
&& !(cmdPtr->nsPtr->flags&NS_SUPPRESS_COMPILATION)
&& !(cmdPtr->flags & CMD_HAS_EXEC_TRACES)
&& !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) {
- int savedNumCmds = envPtr->numCommands;
+ int code, savedNumCmds = envPtr->numCommands;
unsigned savedCodeNext =
envPtr->codeNext - envPtr->codeStart;
- int update = 0, code;
+ int update = 0;
+#ifdef TCL_COMPILE_DEBUG
+ int startStackDepth = envPtr->currStackDepth;
+#endif
/*
* Mark the start of the command; the proper bytecode
@@ -1720,6 +1817,25 @@ TclCompileScript(
envPtr);
if (code == TCL_OK) {
+ /*
+ * Confirm that the command compiler generated a
+ * single value on the stack as its result. This
+ * is only done in debugging mode, as it *should*
+ * be correct and normal users have no reasonable
+ * way to fix it anyway.
+ */
+
+#ifdef TCL_COMPILE_DEBUG
+ int diff = envPtr->currStackDepth-startStackDepth;
+
+ if (diff != 1 && (diff != 0 ||
+ *(envPtr->codeNext-1) != INST_DONE)) {
+ Tcl_Panic("bad stack adjustment when compiling"
+ " %.*s (was %d instead of 1)",
+ parsePtr->tokenPtr->size,
+ parsePtr->tokenPtr->start, diff);
+ }
+#endif
if (update) {
/*
* Fix the bytecode length.
@@ -4620,6 +4736,5 @@ RecordByteCodeStats(
* c-basic-offset: 4
* fill-column: 78
* tab-width: 8
- * indent-tabs-mode: nil
* End:
*/
diff --git a/generic/tclCompile.h b/generic/tclCompile.h
index ba78c36..3302f9b 100644
--- a/generic/tclCompile.h
+++ b/generic/tclCompile.h
@@ -676,13 +676,43 @@ typedef struct ByteCode {
#define INST_UNSET_ARRAY_STK 136
#define INST_UNSET_STK 137
-/* For [dict with] compilation */
+/* For [dict with], [dict exists], [dict create] and [dict merge] */
#define INST_DICT_EXPAND 138
#define INST_DICT_RECOMBINE_STK 139
#define INST_DICT_RECOMBINE_IMM 140
+#define INST_DICT_EXISTS 141
+#define INST_DICT_VERIFY 142
+
+/* For [string map] and [regsub] compilation */
+#define INST_STR_MAP 143
+#define INST_STR_FIND 144
+#define INST_STR_FIND_LAST 145
+#define INST_STR_RANGE_IMM 146
+#define INST_STR_RANGE 147
+
+/* For operations to do with coroutines and other NRE-manipulators */
+#define INST_YIELD 148
+#define INST_COROUTINE_NAME 149
+#define INST_TAILCALL 150
+
+/* For compilation of basic information operations */
+#define INST_NS_CURRENT 151
+#define INST_INFO_LEVEL_NUM 152
+#define INST_INFO_LEVEL_ARGS 153
+#define INST_RESOLVE_COMMAND 154
+#define INST_TCLOO_SELF 155
+#define INST_TCLOO_CLASS 156
+#define INST_TCLOO_NS 157
+#define INST_TCLOO_IS_OBJECT 158
+
+/* For compilation of [array] subcommands */
+#define INST_ARRAY_EXISTS_STK 159
+#define INST_ARRAY_EXISTS_IMM 160
+#define INST_ARRAY_MAKE_STK 161
+#define INST_ARRAY_MAKE_IMM 162
/* The last opcode */
-#define LAST_INST_OPCODE 140
+#define LAST_INST_OPCODE 162
/*
* Table describing the Tcl bytecode instructions: their name (for displaying
diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c
index ea9411c..eb3625e 100644
--- a/generic/tclDictObj.c
+++ b/generic/tclDictObj.c
@@ -89,8 +89,8 @@ static int DictMapLoopCallback(ClientData data[],
static const EnsembleImplMap implementationMap[] = {
{"append", DictAppendCmd, TclCompileDictAppendCmd, NULL, NULL, 0 },
- {"create", DictCreateCmd, NULL, NULL, NULL, 0 },
- {"exists", DictExistsCmd, NULL, NULL, NULL, 0 },
+ {"create", DictCreateCmd, TclCompileDictCreateCmd, NULL, NULL, 0 },
+ {"exists", DictExistsCmd, TclCompileDictExistsCmd, NULL, NULL, 0 },
{"filter", DictFilterCmd, NULL, NULL, NULL, 0 },
{"for", NULL, TclCompileDictForCmd, DictForNRCmd, NULL, 0 },
{"get", DictGetCmd, TclCompileDictGetCmd, NULL, NULL, 0 },
@@ -99,7 +99,7 @@ static const EnsembleImplMap implementationMap[] = {
{"keys", DictKeysCmd, NULL, NULL, NULL, 0 },
{"lappend", DictLappendCmd, TclCompileDictLappendCmd, NULL, NULL, 0 },
{"map", NULL, TclCompileDictMapCmd, DictMapNRCmd, NULL, 0 },
- {"merge", DictMergeCmd, NULL, NULL, NULL, 0 },
+ {"merge", DictMergeCmd, TclCompileDictMergeCmd, NULL, NULL, 0 },
{"remove", DictRemoveCmd, NULL, NULL, NULL, 0 },
{"replace", DictReplaceCmd, NULL, NULL, NULL, 0 },
{"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL, 0 },
diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index 3c0b472..caf35ba 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -17,6 +17,7 @@
#include "tclInt.h"
#include "tclCompile.h"
+#include "tclOOInt.h"
#include "tommath.h"
#include <math.h>
@@ -2331,6 +2332,101 @@ TEBCresume(
cleanup = 1;
goto processExceptionReturn;
+ case INST_YIELD: {
+ CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
+
+ TRACE(("%.30s => ", O2S(OBJ_AT_TOS)));
+ if (!corPtr) {
+ TRACE_APPEND(("ERROR: yield outside coroutine\n"));
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "yield can only be called in a coroutine", -1));
+ Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ILLEGAL_YIELD",
+ NULL);
+ goto gotError;
+ }
+
+#ifdef TCL_COMPILE_DEBUG
+ TRACE_WITH_OBJ(("yield, result="), iPtr->objResultPtr);
+ if (traceInstructions) {
+ fprintf(stdout, "\n");
+ }
+#endif
+ /* TIP #280: Record the last piece of info needed by
+ * 'TclGetSrcInfoForPc', and push the frame.
+ */
+
+ bcFramePtr->data.tebc.pc = (char *) pc;
+ iPtr->cmdFramePtr = bcFramePtr;
+
+ if (iPtr->flags & INTERP_DEBUG_FRAME) {
+ TclArgumentBCEnter((Tcl_Interp *) iPtr, objv, objc,
+ codePtr, bcFramePtr, pc - codePtr->codeStart);
+ }
+
+ pc++;
+ cleanup = 1;
+ TEBC_YIELD();
+
+ Tcl_SetObjResult(interp, OBJ_AT_TOS);
+ TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr,
+ INT2PTR(0), NULL, NULL);
+
+ return TCL_OK;
+ }
+
+ case INST_TAILCALL: {
+ Tcl_Obj *listPtr, *nsObjPtr;
+ NRE_callback *tailcallPtr;
+
+ opnd = TclGetUInt1AtPtr(pc+1);
+
+ if (!(iPtr->varFramePtr->isProcCallFrame & 1)) {
+ TRACE(("%d => ERROR: tailcall in non-proc context\n", opnd));
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "tailcall can only be called from a proc or lambda", -1));
+ Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "ILLEGAL", NULL);
+ goto gotError;
+ }
+
+#ifdef TCL_COMPILE_DEBUG
+ {
+ register int i;
+
+ TRACE(("%d [", opnd));
+ for (i=opnd-1 ; i>=0 ; i++) {
+ TRACE_APPEND(("\"%.30s\"", O2S(OBJ_AT_DEPTH(i))));
+ if (i > 0) {
+ TRACE_APPEND((" "));
+ }
+ }
+ TRACE_APPEND(("] => RETURN..."));
+ }
+#endif
+
+ /*
+ * Push the evaluation of the called command into the NR callback
+ * stack.
+ */
+
+ listPtr = Tcl_NewListObj(opnd, &OBJ_AT_DEPTH(opnd-1));
+ nsObjPtr = Tcl_NewStringObj(iPtr->varFramePtr->nsPtr->fullName, -1);
+ Tcl_IncrRefCount(listPtr);
+ Tcl_IncrRefCount(nsObjPtr);
+ TclNRAddCallback(interp, TclNRTailcallEval, listPtr, nsObjPtr,
+ NULL, NULL);
+
+ /*
+ * Unstitch ourselves and do a [return].
+ */
+
+ tailcallPtr = TOP_CB(interp);
+ TOP_CB(interp) = tailcallPtr->nextPtr;
+ iPtr->varFramePtr->tailcallPtr = tailcallPtr;
+ result = TCL_RETURN;
+ cleanup = opnd;
+ goto processExceptionReturn;
+ }
+
case INST_DONE:
if (tosPtr > initTosPtr) {
/*
@@ -3785,6 +3881,104 @@ TEBCresume(
/*
* End of INST_UNSET instructions.
* -----------------------------------------------------------------
+ * Start of INST_ARRAY instructions.
+ */
+
+ case INST_ARRAY_EXISTS_IMM:
+ opnd = TclGetUInt4AtPtr(pc+1);
+ pcAdjustment = 5;
+ cleanup = 0;
+ part1Ptr = NULL;
+ arrayPtr = NULL;
+ TRACE(("%u => ", opnd));
+ varPtr = LOCAL(opnd);
+ while (TclIsVarLink(varPtr)) {
+ varPtr = varPtr->value.linkPtr;
+ }
+ goto doArrayExists;
+ case INST_ARRAY_EXISTS_STK:
+ opnd = -1;
+ pcAdjustment = 1;
+ cleanup = 1;
+ part1Ptr = OBJ_AT_TOS;
+ TRACE(("\"%.30s\" => ", O2S(part1Ptr)));
+ varPtr = TclObjLookupVarEx(interp, part1Ptr, NULL, 0, NULL,
+ /*createPart1*/0, /*createPart2*/0, &arrayPtr);
+ doArrayExists:
+ if (varPtr && (varPtr->flags & VAR_TRACED_ARRAY)
+ && (TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr))) {
+ DECACHE_STACK_INFO();
+ result = TclObjCallVarTraces(iPtr, arrayPtr, varPtr, part1Ptr,
+ NULL, (TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY|
+ TCL_GLOBAL_ONLY|TCL_TRACE_ARRAY), 1, opnd);
+ CACHE_STACK_INFO();
+ if (result == TCL_ERROR) {
+ TRACE_APPEND(("ERROR: %.30s\n",
+ O2S(Tcl_GetObjResult(interp))));
+ goto gotError;
+ }
+ }
+ if (varPtr && TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) {
+ objResultPtr = TCONST(1);
+ } else {
+ objResultPtr = TCONST(0);
+ }
+ TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
+ NEXT_INST_V(pcAdjustment, cleanup, 1);
+
+ case INST_ARRAY_MAKE_IMM:
+ opnd = TclGetUInt4AtPtr(pc+1);
+ pcAdjustment = 5;
+ cleanup = 0;
+ part1Ptr = NULL;
+ arrayPtr = NULL;
+ TRACE(("%u => ", opnd));
+ varPtr = LOCAL(opnd);
+ while (TclIsVarLink(varPtr)) {
+ varPtr = varPtr->value.linkPtr;
+ }
+ goto doArrayMake;
+ case INST_ARRAY_MAKE_STK:
+ opnd = -1;
+ pcAdjustment = 1;
+ cleanup = 1;
+ part1Ptr = OBJ_AT_TOS;
+ TRACE(("\"%.30s\" => ", O2S(part1Ptr)));
+ varPtr = TclObjLookupVarEx(interp, part1Ptr, NULL, TCL_LEAVE_ERR_MSG,
+ "set", /*createPart1*/1, /*createPart2*/0, &arrayPtr);
+ if (varPtr == NULL) {
+ TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
+ goto gotError;
+ }
+ doArrayMake:
+ if (varPtr && !TclIsVarArray(varPtr)) {
+ if (TclIsVarArrayElement(varPtr) || !TclIsVarUndefined(varPtr)) {
+ /*
+ * Either an array element, or a scalar: lose!
+ */
+
+ TclObjVarErrMsg(interp, part1Ptr, NULL, "array set",
+ "variable isn't array", opnd);
+ Tcl_SetErrorCode(interp, "TCL", "WRITE", "ARRAY", NULL);
+ TRACE_APPEND(("ERROR: bad array ref: %.30s\n",
+ O2S(Tcl_GetObjResult(interp))));
+ goto gotError;
+ }
+ TclSetVarArray(varPtr);
+ varPtr->value.tablePtr = ckalloc(sizeof(TclVarHashTable));
+ TclInitVarHashTable(varPtr->value.tablePtr,
+ TclGetVarNsPtr(varPtr));
+#ifdef TCL_COMPILE_DEBUG
+ TRACE_APPEND(("done\n"));
+ } else {
+ TRACE_APPEND(("nothing to do\n"));
+#endif
+ }
+ NEXT_INST_V(pcAdjustment, cleanup, 0);
+
+ /*
+ * End of INST_ARRAY instructions.
+ * -----------------------------------------------------------------
* Start of variable linking instructions.
*/
@@ -4045,6 +4239,136 @@ TEBCresume(
/*
* -----------------------------------------------------------------
+ * Start of general introspector instructions.
+ */
+
+ case INST_NS_CURRENT: {
+ Namespace *currNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
+
+ if (currNsPtr == (Namespace *) TclGetGlobalNamespace(interp)) {
+ TclNewLiteralStringObj(objResultPtr, "::");
+ } else {
+ TclNewStringObj(objResultPtr, currNsPtr->fullName,
+ strlen(currNsPtr->fullName));
+ }
+ TRACE_WITH_OBJ(("=> "), objResultPtr);
+ NEXT_INST_F(1, 0, 1);
+ }
+ case INST_COROUTINE_NAME: {
+ CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
+
+ TclNewObj(objResultPtr);
+ if (corPtr && !(corPtr->cmdPtr->flags & CMD_IS_DELETED)) {
+ Tcl_GetCommandFullName(interp, (Tcl_Command) corPtr->cmdPtr,
+ objResultPtr);
+ }
+ TRACE_WITH_OBJ(("=> "), objResultPtr);
+ NEXT_INST_F(1, 0, 1);
+ }
+ case INST_INFO_LEVEL_NUM:
+ TclNewIntObj(objResultPtr, iPtr->varFramePtr->level);
+ TRACE_WITH_OBJ(("=> "), objResultPtr);
+ NEXT_INST_F(1, 0, 1);
+ case INST_INFO_LEVEL_ARGS: {
+ int level;
+ register CallFrame *framePtr = iPtr->varFramePtr;
+ register CallFrame *rootFramePtr = iPtr->rootFramePtr;
+
+ valuePtr = OBJ_AT_TOS;
+ if (TclGetIntFromObj(interp, valuePtr, &level) != TCL_OK) {
+ TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)),
+ Tcl_GetObjResult(interp));
+ goto gotError;
+ }
+ TRACE(("%d => ", level));
+ if (level <= 0) {
+ level += framePtr->level;
+ }
+ for (; (framePtr->level!=level) && (framePtr!=rootFramePtr) ;
+ framePtr = framePtr->callerVarPtr) {
+ /* Empty loop body */
+ }
+ if (framePtr == rootFramePtr) {
+ Tcl_AppendResult(interp, "bad level \"", TclGetString(valuePtr),
+ "\"", NULL);
+ TRACE_APPEND(("ERROR: bad level\n"));
+ Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "STACK_LEVEL",
+ TclGetString(valuePtr), NULL);
+ goto gotError;
+ }
+ objResultPtr = Tcl_NewListObj(framePtr->objc, framePtr->objv);
+ TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
+ NEXT_INST_F(1, 1, 1);
+ }
+ case INST_RESOLVE_COMMAND: {
+ Tcl_Command cmd = Tcl_GetCommandFromObj(interp, OBJ_AT_TOS);
+
+ TclNewObj(objResultPtr);
+ if (cmd != NULL) {
+ Tcl_GetCommandFullName(interp, cmd, objResultPtr);
+ }
+ TRACE_WITH_OBJ(("\"%.20s\" => ", O2S(OBJ_AT_TOS)), objResultPtr);
+ NEXT_INST_F(1, 1, 1);
+ }
+ case INST_TCLOO_SELF: {
+ CallFrame *framePtr = iPtr->varFramePtr;
+ CallContext *contextPtr;
+
+ if (framePtr == NULL ||
+ !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
+ TRACE(("=> ERROR: no TclOO call context\n"));
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "self may only be called from inside a method",
+ -1));
+ Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL);
+ goto gotError;
+ }
+ contextPtr = framePtr->clientData;
+
+ /*
+ * Call out to get the name; it's expensive to compute but cached.
+ */
+
+ objResultPtr = TclOOObjectName(interp, contextPtr->oPtr);
+ TRACE_WITH_OBJ(("=> "), objResultPtr);
+ NEXT_INST_F(1, 0, 1);
+ }
+ {
+ Object *oPtr;
+
+ case INST_TCLOO_IS_OBJECT:
+ oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
+ objResultPtr = TCONST(oPtr != NULL ? 1 : 0);
+ TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr);
+ NEXT_INST_F(1, 1, 1);
+ case INST_TCLOO_CLASS:
+ oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
+ if (oPtr == NULL) {
+ TRACE(("%.30s => ERROR: not object\n", O2S(OBJ_AT_TOS)));
+ goto gotError;
+ }
+ objResultPtr = TclOOObjectName(interp, oPtr->selfCls->thisPtr);
+ TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr);
+ NEXT_INST_F(1, 1, 1);
+ case INST_TCLOO_NS:
+ oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
+ if (oPtr == NULL) {
+ TRACE(("%.30s => ERROR: not object\n", O2S(OBJ_AT_TOS)));
+ goto gotError;
+ }
+
+ /*
+ * TclOO objects *never* have the global namespace as their NS.
+ */
+
+ TclNewStringObj(objResultPtr, oPtr->namespacePtr->fullName,
+ strlen(oPtr->namespacePtr->fullName));
+ TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr);
+ NEXT_INST_F(1, 1, 1);
+ }
+
+ /*
+ * -----------------------------------------------------------------
* Start of INST_LIST and related instructions.
*/
@@ -4592,6 +4916,179 @@ TEBCresume(
O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
+ case INST_STR_RANGE:
+ TRACE(("\"%.20s\" %s %s =>",
+ O2S(OBJ_AT_DEPTH(2)), O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS)));
+ length = Tcl_GetCharLength(OBJ_AT_DEPTH(2)) - 1;
+ if (TclGetIntForIndexM(interp, OBJ_UNDER_TOS, length,
+ &fromIdx) != TCL_OK
+ || TclGetIntForIndexM(interp, OBJ_AT_TOS, length,
+ &toIdx) != TCL_OK) {
+ goto gotError;
+ }
+
+ if (fromIdx < 0) {
+ fromIdx = 0;
+ }
+ if (toIdx >= length) {
+ toIdx = length;
+ }
+ if (toIdx >= fromIdx) {
+ objResultPtr = Tcl_GetRange(OBJ_AT_DEPTH(2), fromIdx, toIdx);
+ } else {
+ TclNewObj(objResultPtr);
+ }
+ TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
+ NEXT_INST_V(1, 3, 1);
+
+ case INST_STR_RANGE_IMM:
+ valuePtr = OBJ_AT_TOS;
+ fromIdx = TclGetInt4AtPtr(pc+1);
+ toIdx = TclGetInt4AtPtr(pc+5);
+ length = Tcl_GetCharLength(valuePtr);
+ TRACE(("\"%.20s\" %d %d => ", O2S(valuePtr), fromIdx, toIdx));
+
+ /*
+ * Adjust indices for end-based indexing.
+ */
+
+ if (fromIdx < -1) {
+ fromIdx += 1 + length;
+ if (fromIdx < 0) {
+ fromIdx = 0;
+ }
+ } else if (fromIdx >= length) {
+ fromIdx = length;
+ }
+ if (toIdx < -1) {
+ toIdx += 1 + length;
+ if (toIdx < 0) {
+ toIdx = 0;
+ }
+ } else if (toIdx >= length) {
+ toIdx = length - 1;
+ }
+
+ /*
+ * Check if we can do a sane substring.
+ */
+
+ if (fromIdx <= toIdx) {
+ objResultPtr = Tcl_GetRange(valuePtr, fromIdx, toIdx);
+ } else {
+ TclNewObj(objResultPtr);
+ }
+ TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
+ NEXT_INST_F(9, 1, 1);
+
+ {
+ Tcl_UniChar *ustring1, *ustring2, *ustring3, *end, *p;
+ int length3;
+ Tcl_Obj *value3Ptr;
+
+ case INST_STR_MAP:
+ valuePtr = OBJ_AT_TOS; /* "Main" string. */
+ value3Ptr = OBJ_UNDER_TOS; /* "Target" string. */
+ value2Ptr = OBJ_AT_DEPTH(2); /* "Source" string. */
+ if (value3Ptr == value2Ptr) {
+ objResultPtr = valuePtr;
+ NEXT_INST_V(1, 3, 1);
+ } else if (valuePtr == value2Ptr) {
+ objResultPtr = value3Ptr;
+ NEXT_INST_V(1, 3, 1);
+ }
+ ustring1 = Tcl_GetUnicodeFromObj(valuePtr, &length);
+ if (length == 0) {
+ objResultPtr = valuePtr;
+ NEXT_INST_V(1, 3, 1);
+ }
+ ustring2 = Tcl_GetUnicodeFromObj(value2Ptr, &length2);
+ if (length2 > length || length2 == 0) {
+ objResultPtr = valuePtr;
+ NEXT_INST_V(1, 3, 1);
+ } else if (length2 == length) {
+ if (memcmp(ustring1, ustring2, sizeof(Tcl_UniChar) * length)) {
+ objResultPtr = valuePtr;
+ } else {
+ objResultPtr = value3Ptr;
+ }
+ NEXT_INST_V(1, 3, 1);
+ }
+ ustring3 = Tcl_GetUnicodeFromObj(value3Ptr, &length3);
+
+ objResultPtr = Tcl_NewUnicodeObj(ustring1, 0);
+ p = ustring1;
+ end = ustring1 + length;
+ for (; ustring1 < end; ustring1++) {
+ if ((*ustring1 == *ustring2) && (length2==1 ||
+ memcmp(ustring1, ustring2, sizeof(Tcl_UniChar) * length2)
+ == 0)) {
+ if (p != ustring1) {
+ Tcl_AppendUnicodeToObj(objResultPtr, p, ustring1-p);
+ p = ustring1 + length2;
+ } else {
+ p += length2;
+ }
+ ustring1 = p - 1;
+
+ Tcl_AppendUnicodeToObj(objResultPtr, ustring3, length3);
+ }
+ }
+ if (p != ustring1) {
+ /*
+ * Put the rest of the unmapped chars onto result.
+ */
+
+ Tcl_AppendUnicodeToObj(objResultPtr, p, ustring1 - p);
+ }
+ TRACE_WITH_OBJ(("%.20s %.20s %.20s => ",
+ O2S(value2Ptr), O2S(value3Ptr), O2S(valuePtr)), objResultPtr);
+ NEXT_INST_V(1, 3, 1);
+
+ case INST_STR_FIND:
+ ustring1 = Tcl_GetUnicodeFromObj(OBJ_AT_TOS, &length); /* Haystack */
+ ustring2 = Tcl_GetUnicodeFromObj(OBJ_UNDER_TOS, &length2);/* Needle */
+
+ match = -1;
+ if (length2 > 0 && length2 <= length) {
+ end = ustring1 + length - length2 + 1;
+ for (p=ustring1 ; p<end ; p++) {
+ if ((*p == *ustring2) &&
+ memcmp(ustring2,p,sizeof(Tcl_UniChar)*length2) == 0) {
+ match = p - ustring1;
+ break;
+ }
+ }
+ }
+
+ TRACE(("%.20s %.20s => %d\n",
+ O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), match));
+
+ TclNewIntObj(objResultPtr, match);
+ NEXT_INST_F(1, 2, 1);
+
+ case INST_STR_FIND_LAST:
+ ustring1 = Tcl_GetUnicodeFromObj(OBJ_AT_TOS, &length); /* Haystack */
+ ustring2 = Tcl_GetUnicodeFromObj(OBJ_UNDER_TOS, &length2);/* Needle */
+
+ match = -1;
+ if (length2 > 0 && length2 <= length) {
+ for (p=ustring1+length-length2 ; p>=ustring1 ; p--) {
+ if ((*p == *ustring2) &&
+ memcmp(ustring2,p,sizeof(Tcl_UniChar)*length2) == 0) {
+ match = p - ustring1;
+ break;
+ }
+ }
+ }
+
+ TRACE(("%.20s %.20s => %d\n",
+ O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), match));
+
+ TclNewIntObj(objResultPtr, match);
+ NEXT_INST_F(1, 2, 1);
+ }
+
case INST_STR_MATCH:
nocase = TclGetInt1AtPtr(pc+1);
valuePtr = OBJ_AT_TOS; /* String */
@@ -5648,23 +6145,48 @@ TEBCresume(
Tcl_DictSearch *searchPtr;
DictUpdateInfo *duiPtr;
+ case INST_DICT_VERIFY:
+ dictPtr = OBJ_AT_TOS;
+ TRACE(("=> "));
+ if (Tcl_DictObjSize(interp, dictPtr, &done) != TCL_OK) {
+ TRACE_APPEND(("ERROR verifying dictionary nature of \"%s\": %s\n",
+ O2S(OBJ_AT_DEPTH(opnd)), O2S(Tcl_GetObjResult(interp))));
+ goto gotError;
+ }
+ TRACE_APPEND(("OK\n"));
+ NEXT_INST_F(1, 1, 0);
+
case INST_DICT_GET:
+ case INST_DICT_EXISTS: {
+ register Tcl_Interp *interp2 = interp;
+
opnd = TclGetUInt4AtPtr(pc+1);
TRACE(("%u => ", opnd));
dictPtr = OBJ_AT_DEPTH(opnd);
+ if (*pc == INST_DICT_EXISTS) {
+ interp2 = NULL;
+ }
if (opnd > 1) {
- dictPtr = TclTraceDictPath(interp, dictPtr, opnd-1,
+ dictPtr = TclTraceDictPath(interp2, dictPtr, opnd-1,
&OBJ_AT_DEPTH(opnd-1), DICT_PATH_READ);
if (dictPtr == NULL) {
+ if (*pc == INST_DICT_EXISTS) {
+ goto dictNotExists;
+ }
TRACE_WITH_OBJ((
- "%u => ERROR tracing dictionary path into \"%s\": ",
- opnd, O2S(OBJ_AT_DEPTH(opnd))),
+ "ERROR tracing dictionary path into \"%s\": ",
+ O2S(OBJ_AT_DEPTH(opnd))),
Tcl_GetObjResult(interp));
goto gotError;
}
}
- if (Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS,
+ if (Tcl_DictObjGet(interp2, dictPtr, OBJ_AT_TOS,
&objResultPtr) == TCL_OK) {
+ if (*pc == INST_DICT_EXISTS) {
+ objResultPtr = TCONST(objResultPtr ? 1 : 0);
+ TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
+ NEXT_INST_V(5, opnd+1, 1);
+ }
if (objResultPtr) {
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd+1, 1);
@@ -5678,11 +6200,18 @@ TEBCresume(
CACHE_STACK_INFO();
TRACE_WITH_OBJ(("%u => ERROR ", opnd), Tcl_GetObjResult(interp));
} else {
+ if (*pc == INST_DICT_EXISTS) {
+ dictNotExists:
+ objResultPtr = TCONST(0);
+ TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
+ NEXT_INST_V(5, opnd+1, 1);
+ }
TRACE_WITH_OBJ((
"%u => ERROR reading leaf dictionary key \"%s\": ",
opnd, O2S(dictPtr)), Tcl_GetObjResult(interp));
}
goto gotError;
+ }
case INST_DICT_SET:
case INST_DICT_UNSET:
diff --git a/generic/tclInt.h b/generic/tclInt.h
index ea712b8..1d04c82 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -2797,7 +2797,9 @@ MODULE_SCOPE Tcl_ObjCmdProc TclNRUplevelObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRWhileObjCmd;
MODULE_SCOPE Tcl_NRPostProc TclNRForIterCallback;
+MODULE_SCOPE Tcl_NRPostProc TclNRCoroutineActivateCallback;
MODULE_SCOPE Tcl_ObjCmdProc TclNRTailcallObjCmd;
+MODULE_SCOPE Tcl_NRPostProc TclNRTailcallEval;
MODULE_SCOPE Tcl_ObjCmdProc TclNRCoroutineObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldmObjCmd;
@@ -3489,6 +3491,15 @@ MODULE_SCOPE int Tcl_WhileObjCmd(ClientData clientData,
MODULE_SCOPE int TclCompileAppendCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileArrayExistsCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileArraySetCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileArrayUnsetCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileBreakCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
@@ -3501,10 +3512,13 @@ MODULE_SCOPE int TclCompileContinueCmd(Tcl_Interp *interp,
MODULE_SCOPE int TclCompileDictAppendCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictForCmd(Tcl_Interp *interp,
+MODULE_SCOPE int TclCompileDictCreateCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
-MODULE_SCOPE int TclCompileDictMapCmd(Tcl_Interp *interp,
+MODULE_SCOPE int TclCompileDictExistsCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileDictForCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileDictGetCmd(Tcl_Interp *interp,
@@ -3516,6 +3530,12 @@ MODULE_SCOPE int TclCompileDictIncrCmd(Tcl_Interp *interp,
MODULE_SCOPE int TclCompileDictLappendCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileDictMapCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileDictMergeCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileDictSetCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
@@ -3543,15 +3563,36 @@ MODULE_SCOPE int TclCompileForCmd(Tcl_Interp *interp,
MODULE_SCOPE int TclCompileForeachCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileFormatCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileGlobalCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileIfCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileInfoCommandsCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileInfoCoroutineCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileInfoExistsCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileInfoLevelCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileInfoObjectClassCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileInfoObjectIsACmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileInfoObjectNamespaceCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileIncrCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
@@ -3582,15 +3623,36 @@ MODULE_SCOPE int TclCompileLreplaceCmd(Tcl_Interp *interp,
MODULE_SCOPE int TclCompileLsetCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileNamespaceCodeCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileNamespaceCurrentCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileNamespaceQualifiersCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileNamespaceTailCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileNamespaceUpvarCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileNamespaceWhichCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileNoOp(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileObjectSelfCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileRegexpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileRegsubCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileReturnCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
@@ -3603,21 +3665,36 @@ MODULE_SCOPE int TclCompileStringCmpCmd(Tcl_Interp *interp,
MODULE_SCOPE int TclCompileStringEqualCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileStringFirstCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStringIndexCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileStringLastCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStringLenCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileStringMapCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStringMatchCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileStringRangeCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileSubstCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileSwitchCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileTailcallCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileThrowCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
@@ -3636,6 +3713,9 @@ MODULE_SCOPE int TclCompileVariableCmd(Tcl_Interp *interp,
MODULE_SCOPE int TclCompileWhileCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+MODULE_SCOPE int TclCompileYieldCmd(Tcl_Interp *interp,
+ Tcl_Parse *parsePtr, Command *cmdPtr,
+ struct CompileEnv *envPtr);
MODULE_SCOPE int TclInvertOpCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c
index 3c93400..02d517f 100644
--- a/generic/tclNamesp.c
+++ b/generic/tclNamesp.c
@@ -104,7 +104,7 @@ static int NamespaceDeleteCmd(ClientData dummy,Tcl_Interp *interp,
static int NamespaceEvalCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
static int NRNamespaceEvalCmd(ClientData dummy,
- Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
+ Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
static int NamespaceExistsCmd(ClientData dummy,Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
static int NamespaceExportCmd(ClientData dummy,Tcl_Interp *interp,
@@ -160,25 +160,25 @@ static const Tcl_ObjType nsNameType = {
*/
static const EnsembleImplMap defaultNamespaceMap[] = {
- {"children", NamespaceChildrenCmd, NULL, NULL, NULL, 0},
- {"code", NamespaceCodeCmd, NULL, NULL, NULL, 0},
- {"current", NamespaceCurrentCmd, NULL, NULL, NULL, 0},
- {"delete", NamespaceDeleteCmd, NULL, NULL, NULL, 0},
- {"ensemble", TclNamespaceEnsembleCmd, NULL, NULL, NULL, 0},
- {"eval", NamespaceEvalCmd, NULL, NRNamespaceEvalCmd, NULL, 0},
- {"exists", NamespaceExistsCmd, NULL, NULL, NULL, 0},
- {"export", NamespaceExportCmd, NULL, NULL, NULL, 0},
- {"forget", NamespaceForgetCmd, NULL, NULL, NULL, 0},
- {"import", NamespaceImportCmd, NULL, NULL, NULL, 0},
- {"inscope", NamespaceInscopeCmd, NULL, NRNamespaceInscopeCmd, NULL, 0},
- {"origin", NamespaceOriginCmd, NULL, NULL, NULL, 0},
- {"parent", NamespaceParentCmd, NULL, NULL, NULL, 0},
- {"path", NamespacePathCmd, NULL, NULL, NULL, 0},
- {"qualifiers", NamespaceQualifiersCmd, NULL, NULL, NULL, 0},
- {"tail", NamespaceTailCmd, NULL, NULL, NULL, 0},
- {"unknown", NamespaceUnknownCmd, NULL, NULL, NULL, 0},
- {"upvar", NamespaceUpvarCmd, TclCompileNamespaceUpvarCmd, NULL, NULL, 0},
- {"which", NamespaceWhichCmd, NULL, NULL, NULL, 0},
+ {"children", NamespaceChildrenCmd, NULL, NULL, NULL, 0},
+ {"code", NamespaceCodeCmd, TclCompileNamespaceCodeCmd, NULL, NULL, 0},
+ {"current", NamespaceCurrentCmd, TclCompileNamespaceCurrentCmd, NULL, NULL, 0},
+ {"delete", NamespaceDeleteCmd, NULL, NULL, NULL, 0},
+ {"ensemble", TclNamespaceEnsembleCmd, NULL, NULL, NULL, 0},
+ {"eval", NamespaceEvalCmd, NULL, NRNamespaceEvalCmd, NULL, 0},
+ {"exists", NamespaceExistsCmd, NULL, NULL, NULL, 0},
+ {"export", NamespaceExportCmd, NULL, NULL, NULL, 0},
+ {"forget", NamespaceForgetCmd, NULL, NULL, NULL, 0},
+ {"import", NamespaceImportCmd, NULL, NULL, NULL, 0},
+ {"inscope", NamespaceInscopeCmd, NULL, NRNamespaceInscopeCmd, NULL, 0},
+ {"origin", NamespaceOriginCmd, NULL, NULL, NULL, 0},
+ {"parent", NamespaceParentCmd, NULL, NULL, NULL, 0},
+ {"path", NamespacePathCmd, NULL, NULL, NULL, 0},
+ {"qualifiers", NamespaceQualifiersCmd, TclCompileNamespaceQualifiersCmd, NULL, NULL, 0},
+ {"tail", NamespaceTailCmd, TclCompileNamespaceTailCmd, NULL, NULL, 0},
+ {"unknown", NamespaceUnknownCmd, NULL, NULL, NULL, 0},
+ {"upvar", NamespaceUpvarCmd, TclCompileNamespaceUpvarCmd, NULL, NULL, 0},
+ {"which", NamespaceWhichCmd, TclCompileNamespaceWhichCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
@@ -423,7 +423,7 @@ Tcl_PopCallFrame(
framePtr->nsPtr = NULL;
if (framePtr->tailcallPtr) {
- TclSpliceTailcall(interp, framePtr->tailcallPtr);
+ TclSpliceTailcall(interp, framePtr->tailcallPtr);
}
}
@@ -689,8 +689,8 @@ Tcl_CreateNamespace(
} else if (*name == '\0') {
Tcl_SetObjResult(interp, Tcl_NewStringObj("can't create namespace"
" \"\": only global namespace can have empty name", -1));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NAMESPACE",
- "CREATEGLOBAL", NULL);
+ Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NAMESPACE",
+ "CREATEGLOBAL", NULL);
return NULL;
} else {
/*
@@ -726,8 +726,8 @@ Tcl_CreateNamespace(
) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"can't create namespace \"%s\": already exists", name));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NAMESPACE",
- "CREATEEXISTING", NULL);
+ Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NAMESPACE",
+ "CREATEEXISTING", NULL);
return NULL;
}
}
@@ -1337,7 +1337,7 @@ Tcl_Export(
if ((exportNsPtr != nsPtr) || (strcmp(pattern, simplePattern) != 0)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("invalid export pattern"
" \"%s\": pattern can't specify a namespace", pattern));
- Tcl_SetErrorCode(interp, "TCL", "EXPORT", "INVALID", NULL);
+ Tcl_SetErrorCode(interp, "TCL", "EXPORT", "INVALID", NULL);
return TCL_ERROR;
}
@@ -1542,7 +1542,7 @@ Tcl_Import(
if (strlen(pattern) == 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("empty import pattern",-1));
- Tcl_SetErrorCode(interp, "TCL", "IMPORT", "EMPTY", NULL);
+ Tcl_SetErrorCode(interp, "TCL", "IMPORT", "EMPTY", NULL);
return TCL_ERROR;
}
TclGetNamespaceForQualName(interp, pattern, nsPtr,
@@ -1560,12 +1560,12 @@ Tcl_Import(
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"no namespace specified in import pattern \"%s\"",
pattern));
- Tcl_SetErrorCode(interp, "TCL", "IMPORT", "ORIGIN", NULL);
+ Tcl_SetErrorCode(interp, "TCL", "IMPORT", "ORIGIN", NULL);
} else {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"import pattern \"%s\" tries to import from namespace"
" \"%s\" into itself", pattern, importNsPtr->name));
- Tcl_SetErrorCode(interp, "TCL", "IMPORT", "SELF", NULL);
+ Tcl_SetErrorCode(interp, "TCL", "IMPORT", "SELF", NULL);
}
return TCL_ERROR;
}
@@ -1688,7 +1688,7 @@ DoImport(
" containing command \"%s\"",
pattern, Tcl_DStringValue(&ds)));
Tcl_DStringFree(&ds);
- Tcl_SetErrorCode(interp, "TCL", "IMPORT", "LOOP", NULL);
+ Tcl_SetErrorCode(interp, "TCL", "IMPORT", "LOOP", NULL);
return TCL_ERROR;
}
}
@@ -1728,7 +1728,7 @@ DoImport(
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"can't import command \"%s\": already exists", cmdName));
- Tcl_SetErrorCode(interp, "TCL", "IMPORT", "OVERWRITE", NULL);
+ Tcl_SetErrorCode(interp, "TCL", "IMPORT", "OVERWRITE", NULL);
return TCL_ERROR;
}
return TCL_OK;
@@ -3285,12 +3285,12 @@ NRNamespaceEvalCmd(
}
if (iPtr->ensembleRewrite.sourceObjs == NULL) {
- framePtr->objc = objc;
- framePtr->objv = objv;
+ framePtr->objc = objc;
+ framePtr->objv = objv;
} else {
- framePtr->objc = objc + iPtr->ensembleRewrite.numRemovedObjs
- - iPtr->ensembleRewrite.numInsertedObjs;
- framePtr->objv = iPtr->ensembleRewrite.sourceObjs;
+ framePtr->objc = objc + iPtr->ensembleRewrite.numRemovedObjs
+ - iPtr->ensembleRewrite.numInsertedObjs;
+ framePtr->objv = iPtr->ensembleRewrite.sourceObjs;
}
if (objc == 3) {
@@ -3748,12 +3748,12 @@ NRNamespaceInscopeCmd(
}
if (iPtr->ensembleRewrite.sourceObjs == NULL) {
- framePtr->objc = objc;
- framePtr->objv = objv;
+ framePtr->objc = objc;
+ framePtr->objv = objv;
} else {
- framePtr->objc = objc + iPtr->ensembleRewrite.numRemovedObjs
- - iPtr->ensembleRewrite.numInsertedObjs;
- framePtr->objv = iPtr->ensembleRewrite.sourceObjs;
+ framePtr->objc = objc + iPtr->ensembleRewrite.numRemovedObjs
+ - iPtr->ensembleRewrite.numInsertedObjs;
+ framePtr->objv = iPtr->ensembleRewrite.sourceObjs;
}
/*
@@ -3958,15 +3958,15 @@ NamespacePathCmd(
*/
if (objc == 1) {
- Tcl_Obj *resultObj = Tcl_NewObj();
+ Tcl_Obj *resultObj = Tcl_NewObj();
for (i=0 ; i<nsPtr->commandPathLength ; i++) {
if (nsPtr->commandPathArray[i].nsPtr != NULL) {
- Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj(
- nsPtr->commandPathArray[i].nsPtr->fullName, -1));
+ Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj(
+ nsPtr->commandPathArray[i].nsPtr->fullName, -1));
}
}
- Tcl_SetObjResult(interp, resultObj);
+ Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
}
@@ -4843,8 +4843,8 @@ TclLogCommandInfo(
int length, /* Number of bytes in command (-1 means use
* all bytes up to first null byte). */
const unsigned char *pc, /* Current pc of bytecode execution context */
- Tcl_Obj **tosPtr) /* Current stack of bytecode execution
- * context */
+ Tcl_Obj **tosPtr) /* Current stack of bytecode execution
+ * context */
{
register const char *p;
Interp *iPtr = (Interp *) interp;
@@ -4861,55 +4861,55 @@ TclLogCommandInfo(
}
if (command != NULL) {
- /*
- * Compute the line number where the error occurred.
- */
-
- iPtr->errorLine = 1;
- for (p = script; p != command; p++) {
- if (*p == '\n') {
- iPtr->errorLine++;
- }
- }
-
- if (length < 0) {
- length = strlen(command);
- }
- overflow = (length > limit);
- Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
+ /*
+ * Compute the line number where the error occurred.
+ */
+
+ iPtr->errorLine = 1;
+ for (p = script; p != command; p++) {
+ if (*p == '\n') {
+ iPtr->errorLine++;
+ }
+ }
+
+ if (length < 0) {
+ length = strlen(command);
+ }
+ overflow = (length > limit);
+ Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n %s\n\"%.*s%s\"", ((iPtr->errorInfo == NULL)
? "while executing" : "invoked from within"),
(overflow ? limit : length), command,
(overflow ? "..." : "")));
- varPtr = TclObjLookupVarEx(interp, iPtr->eiVar, NULL, TCL_GLOBAL_ONLY,
+ varPtr = TclObjLookupVarEx(interp, iPtr->eiVar, NULL, TCL_GLOBAL_ONLY,
NULL, 0, 0, &arrayPtr);
- if ((varPtr == NULL) || !TclIsVarTraced(varPtr)) {
- /*
- * Should not happen.
- */
-
- return;
- } else {
- Tcl_HashEntry *hPtr
+ if ((varPtr == NULL) || !TclIsVarTraced(varPtr)) {
+ /*
+ * Should not happen.
+ */
+
+ return;
+ } else {
+ Tcl_HashEntry *hPtr
= Tcl_FindHashEntry(&iPtr->varTraces, (char *) varPtr);
- VarTrace *tracePtr = Tcl_GetHashValue(hPtr);
+ VarTrace *tracePtr = Tcl_GetHashValue(hPtr);
- if (tracePtr->traceProc != EstablishErrorInfoTraces) {
- /*
- * The most recent trace set on ::errorInfo is not the one the
- * core itself puts on last. This means some other code is
+ if (tracePtr->traceProc != EstablishErrorInfoTraces) {
+ /*
+ * The most recent trace set on ::errorInfo is not the one the
+ * core itself puts on last. This means some other code is
* tracing the variable, and the additional trace(s) might be
* write traces that expect the timing of writes to
* ::errorInfo that existed Tcl releases before 8.5. To
* satisfy that compatibility need, we write the current
* -errorinfo value to the ::errorInfo variable.
- */
+ */
- Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, iPtr->errorInfo,
+ Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, iPtr->errorInfo,
TCL_GLOBAL_ONLY);
- }
- }
+ }
+ }
}
/*
@@ -4917,60 +4917,60 @@ TclLogCommandInfo(
*/
if (Tcl_IsShared(iPtr->errorStack)) {
- Tcl_Obj *newObj;
-
- newObj = Tcl_DuplicateObj(iPtr->errorStack);
- Tcl_DecrRefCount(iPtr->errorStack);
- Tcl_IncrRefCount(newObj);
- iPtr->errorStack = newObj;
+ Tcl_Obj *newObj;
+
+ newObj = Tcl_DuplicateObj(iPtr->errorStack);
+ Tcl_DecrRefCount(iPtr->errorStack);
+ Tcl_IncrRefCount(newObj);
+ iPtr->errorStack = newObj;
}
if (iPtr->resetErrorStack) {
int len;
- iPtr->resetErrorStack = 0;
+ iPtr->resetErrorStack = 0;
Tcl_ListObjLength(interp, iPtr->errorStack, &len);
- /*
- * Reset while keeping the list intrep as much as possible.
- */
-
- Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
- if (pc != NULL) {
- Tcl_Obj *innerContext;
-
- innerContext = TclGetInnerContext(interp, pc, tosPtr);
- if (innerContext != NULL) {
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
- iPtr->innerLiteral);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, innerContext);
- }
- } else if (command != NULL) {
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
- iPtr->innerLiteral);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
- Tcl_NewStringObj(command, length));
- }
+ /*
+ * Reset while keeping the list intrep as much as possible.
+ */
+
+ Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
+ if (pc != NULL) {
+ Tcl_Obj *innerContext;
+
+ innerContext = TclGetInnerContext(interp, pc, tosPtr);
+ if (innerContext != NULL) {
+ Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
+ iPtr->innerLiteral);
+ Tcl_ListObjAppendElement(NULL, iPtr->errorStack, innerContext);
+ }
+ } else if (command != NULL) {
+ Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
+ iPtr->innerLiteral);
+ Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
+ Tcl_NewStringObj(command, length));
+ }
}
if (!iPtr->framePtr->objc) {
- /*
- * Special frame, nothing to report.
- */
+ /*
+ * Special frame, nothing to report.
+ */
} else if (iPtr->varFramePtr != iPtr->framePtr) {
- /*
- * uplevel case, [lappend errorstack UP $relativelevel]
- */
+ /*
+ * uplevel case, [lappend errorstack UP $relativelevel]
+ */
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->upLiteral);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewIntObj(
+ Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->upLiteral);
+ Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewIntObj(
iPtr->framePtr->level - iPtr->varFramePtr->level));
} else if (iPtr->framePtr != iPtr->rootFramePtr) {
- /*
- * normal case, [lappend errorstack CALL [info level 0]]
- */
+ /*
+ * normal case, [lappend errorstack CALL [info level 0]]
+ */
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->callLiteral);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewListObj(
+ Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->callLiteral);
+ Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewListObj(
iPtr->framePtr->objc, iPtr->framePtr->objv));
}
}
@@ -4980,8 +4980,8 @@ TclLogCommandInfo(
*
* TclErrorStackResetIf --
*
- * The TIP 348 reset/no-bc part of TLCI, for specific use by
- * TclCompileSyntaxError.
+ * The TIP 348 reset/no-bc part of TLCI, for specific use by
+ * TclCompileSyntaxError.
*
* Results:
* None.
@@ -5002,27 +5002,27 @@ TclErrorStackResetIf(
Interp *iPtr = (Interp *) interp;
if (Tcl_IsShared(iPtr->errorStack)) {
- Tcl_Obj *newObj;
-
- newObj = Tcl_DuplicateObj(iPtr->errorStack);
- Tcl_DecrRefCount(iPtr->errorStack);
- Tcl_IncrRefCount(newObj);
- iPtr->errorStack = newObj;
+ Tcl_Obj *newObj;
+
+ newObj = Tcl_DuplicateObj(iPtr->errorStack);
+ Tcl_DecrRefCount(iPtr->errorStack);
+ Tcl_IncrRefCount(newObj);
+ iPtr->errorStack = newObj;
}
if (iPtr->resetErrorStack) {
int len;
- iPtr->resetErrorStack = 0;
+ iPtr->resetErrorStack = 0;
Tcl_ListObjLength(interp, iPtr->errorStack, &len);
- /*
- * Reset while keeping the list intrep as much as possible.
- */
+ /*
+ * Reset while keeping the list intrep as much as possible.
+ */
- Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral);
- Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
- Tcl_NewStringObj(msg, length));
+ Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
+ Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral);
+ Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
+ Tcl_NewStringObj(msg, length));
}
}
@@ -5065,6 +5065,5 @@ Tcl_LogCommandInfo(
* c-basic-offset: 4
* fill-column: 78
* tab-width: 8
- * indent-tabs-mode: nil
* End:
*/
diff --git a/generic/tclOO.c b/generic/tclOO.c
index 04a2bf7..d6d2d6a 100644
--- a/generic/tclOO.c
+++ b/generic/tclOO.c
@@ -314,6 +314,7 @@ InitFoundation(
Foundation *fPtr = ckalloc(sizeof(Foundation));
Tcl_Obj *namePtr, *argsPtr, *bodyPtr;
Tcl_DString buffer;
+ Command *cmdPtr;
int i;
/*
@@ -440,8 +441,9 @@ InitFoundation(
NULL);
Tcl_CreateObjCommand(interp, "::oo::Helpers::nextto", TclOONextToObjCmd,
NULL, NULL);
- Tcl_CreateObjCommand(interp, "::oo::Helpers::self", TclOOSelfObjCmd, NULL,
- NULL);
+ cmdPtr = (Command *) Tcl_CreateObjCommand(interp, "::oo::Helpers::self",
+ TclOOSelfObjCmd, NULL, NULL);
+ cmdPtr->compileProc = TclCompileObjectSelfCmd;
Tcl_CreateObjCommand(interp, "::oo::define", TclOODefineObjCmd, NULL,
NULL);
Tcl_CreateObjCommand(interp, "::oo::objdefine", TclOOObjDefObjCmd, NULL,
diff --git a/generic/tclOOInfo.c b/generic/tclOOInfo.c
index 1a94e69..e09ee4e 100644
--- a/generic/tclOOInfo.c
+++ b/generic/tclOOInfo.c
@@ -43,47 +43,45 @@ static Tcl_ObjCmdProc InfoClassSubsCmd;
static Tcl_ObjCmdProc InfoClassSupersCmd;
static Tcl_ObjCmdProc InfoClassVariablesCmd;
-struct NameProcMap { const char *name; Tcl_ObjCmdProc *proc; };
-
/*
* List of commands that are used to implement the [info object] subcommands.
*/
-static const struct NameProcMap infoObjectCmds[] = {
- {"::oo::InfoObject::call", InfoObjectCallCmd},
- {"::oo::InfoObject::class", InfoObjectClassCmd},
- {"::oo::InfoObject::definition", InfoObjectDefnCmd},
- {"::oo::InfoObject::filters", InfoObjectFiltersCmd},
- {"::oo::InfoObject::forward", InfoObjectForwardCmd},
- {"::oo::InfoObject::isa", InfoObjectIsACmd},
- {"::oo::InfoObject::methods", InfoObjectMethodsCmd},
- {"::oo::InfoObject::methodtype", InfoObjectMethodTypeCmd},
- {"::oo::InfoObject::mixins", InfoObjectMixinsCmd},
- {"::oo::InfoObject::namespace", InfoObjectNsCmd},
- {"::oo::InfoObject::variables", InfoObjectVariablesCmd},
- {"::oo::InfoObject::vars", InfoObjectVarsCmd},
- {NULL, NULL}
+static const EnsembleImplMap infoObjectCmds[] = {
+ {"call", InfoObjectCallCmd, NULL, NULL, NULL, 0},
+ {"class", InfoObjectClassCmd, TclCompileInfoObjectClassCmd, NULL, NULL, 0},
+ {"definition", InfoObjectDefnCmd, NULL, NULL, NULL, 0},
+ {"filters", InfoObjectFiltersCmd, NULL, NULL, NULL, 0},
+ {"forward", InfoObjectForwardCmd, NULL, NULL, NULL, 0},
+ {"isa", InfoObjectIsACmd, TclCompileInfoObjectIsACmd, NULL, NULL, 0},
+ {"methods", InfoObjectMethodsCmd, NULL, NULL, NULL, 0},
+ {"methodtype", InfoObjectMethodTypeCmd, NULL, NULL, NULL, 0},
+ {"mixins", InfoObjectMixinsCmd, NULL, NULL, NULL, 0},
+ {"namespace", InfoObjectNsCmd, TclCompileInfoObjectNamespaceCmd, NULL, NULL, 0},
+ {"variables", InfoObjectVariablesCmd, NULL, NULL, NULL, 0},
+ {"vars", InfoObjectVarsCmd, NULL, NULL, NULL, 0},
+ {NULL, NULL, NULL, NULL, NULL, 0}
};
/*
* List of commands that are used to implement the [info class] subcommands.
*/
-static const struct NameProcMap infoClassCmds[] = {
- {"::oo::InfoClass::call", InfoClassCallCmd},
- {"::oo::InfoClass::constructor", InfoClassConstrCmd},
- {"::oo::InfoClass::definition", InfoClassDefnCmd},
- {"::oo::InfoClass::destructor", InfoClassDestrCmd},
- {"::oo::InfoClass::filters", InfoClassFiltersCmd},
- {"::oo::InfoClass::forward", InfoClassForwardCmd},
- {"::oo::InfoClass::instances", InfoClassInstancesCmd},
- {"::oo::InfoClass::methods", InfoClassMethodsCmd},
- {"::oo::InfoClass::methodtype", InfoClassMethodTypeCmd},
- {"::oo::InfoClass::mixins", InfoClassMixinsCmd},
- {"::oo::InfoClass::subclasses", InfoClassSubsCmd},
- {"::oo::InfoClass::superclasses", InfoClassSupersCmd},
- {"::oo::InfoClass::variables", InfoClassVariablesCmd},
- {NULL, NULL}
+static const EnsembleImplMap infoClassCmds[] = {
+ {"call", InfoClassCallCmd, NULL, NULL, NULL, 0},
+ {"constructor", InfoClassConstrCmd, NULL, NULL, NULL, 0},
+ {"definition", InfoClassDefnCmd, NULL, NULL, NULL, 0},
+ {"destructor", InfoClassDestrCmd, NULL, NULL, NULL, 0},
+ {"filters", InfoClassFiltersCmd, NULL, NULL, NULL, 0},
+ {"forward", InfoClassForwardCmd, NULL, NULL, NULL, 0},
+ {"instances", InfoClassInstancesCmd, NULL, NULL, NULL, 0},
+ {"methods", InfoClassMethodsCmd, NULL, NULL, NULL, 0},
+ {"methodtype", InfoClassMethodTypeCmd, NULL, NULL, NULL, 0},
+ {"mixins", InfoClassMixinsCmd, NULL, NULL, NULL, 0},
+ {"subclasses", InfoClassSubsCmd, NULL, NULL, NULL, 0},
+ {"superclasses", InfoClassSupersCmd, NULL, NULL, NULL, 0},
+ {"variables", InfoClassVariablesCmd, NULL, NULL, NULL, 0},
+ {NULL, NULL, NULL, NULL, NULL, 0}
};
/*
@@ -101,33 +99,14 @@ void
TclOOInitInfo(
Tcl_Interp *interp)
{
- Tcl_Namespace *nsPtr;
Tcl_Command infoCmd;
- int i;
-
- /*
- * Build the ensemble used to implement [info object].
- */
-
- nsPtr = Tcl_CreateNamespace(interp, "::oo::InfoObject", NULL, NULL);
- Tcl_CreateEnsemble(interp, nsPtr->fullName, nsPtr, TCL_ENSEMBLE_PREFIX);
- Tcl_Export(interp, nsPtr, "[a-z]*", 1);
- for (i=0 ; infoObjectCmds[i].name!=NULL ; i++) {
- Tcl_CreateObjCommand(interp, infoObjectCmds[i].name,
- infoObjectCmds[i].proc, NULL, NULL);
- }
/*
- * Build the ensemble used to implement [info class].
+ * Build the ensembles used to implement [info object] and [info class].
*/
- nsPtr = Tcl_CreateNamespace(interp, "::oo::InfoClass", NULL, NULL);
- Tcl_CreateEnsemble(interp, nsPtr->fullName, nsPtr, TCL_ENSEMBLE_PREFIX);
- Tcl_Export(interp, nsPtr, "[a-z]*", 1);
- for (i=0 ; infoClassCmds[i].name!=NULL ; i++) {
- Tcl_CreateObjCommand(interp, infoClassCmds[i].name,
- infoClassCmds[i].proc, NULL, NULL);
- }
+ TclMakeEnsemble(interp, "::oo::InfoObject", infoObjectCmds);
+ TclMakeEnsemble(interp, "::oo::InfoClass", infoClassCmds);
/*
* Install into the master [info] ensemble.
diff --git a/generic/tclVar.c b/generic/tclVar.c
index e31e9cf..1c01e41 100644
--- a/generic/tclVar.c
+++ b/generic/tclVar.c
@@ -4224,15 +4224,15 @@ TclInitArrayCmd(
static const EnsembleImplMap arrayImplMap[] = {
{"anymore", ArrayAnyMoreCmd, NULL, NULL, NULL, 0},
{"donesearch", ArrayDoneSearchCmd, NULL, NULL, NULL, 0},
- {"exists", ArrayExistsCmd, NULL, NULL, NULL, 0},
+ {"exists", ArrayExistsCmd, TclCompileArrayExistsCmd, NULL, NULL, 0},
{"get", ArrayGetCmd, NULL, NULL, NULL, 0},
{"names", ArrayNamesCmd, NULL, NULL, NULL, 0},
{"nextelement", ArrayNextElementCmd, NULL, NULL, NULL, 0},
- {"set", ArraySetCmd, NULL, NULL, NULL, 0},
+ {"set", ArraySetCmd, TclCompileArraySetCmd, NULL, NULL, 0},
{"size", ArraySizeCmd, NULL, NULL, NULL, 0},
{"startsearch", ArrayStartSearchCmd, NULL, NULL, NULL, 0},
{"statistics", ArrayStatsCmd, NULL, NULL, NULL, 0},
- {"unset", ArrayUnsetCmd, NULL, NULL, NULL, 0},
+ {"unset", ArrayUnsetCmd, TclCompileArrayUnsetCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
diff --git a/tests/dict.test b/tests/dict.test
index 72f239e..22d652b 100644
--- a/tests/dict.test
+++ b/tests/dict.test
@@ -78,6 +78,24 @@ test dict-2.7 {dict create command - #-quoting in string rep} {
test dict-2.8 {dict create command - #-quoting in string rep} -body {
dict create #a x #b x
} -match glob -result {{#?} x #? x}
+test dict-2.9 {dict create command: compilation} {
+ apply {{} {dict create [format a] b}}
+} {a b}
+test dict-2.10 {dict create command: compilation} {
+ apply {{} {dict create [format a] b c d}}
+} {a b c d}
+test dict-2.11 {dict create command: compilation} {
+ apply {{} {dict create [format a] b c d a x}}
+} {a x c d}
+test dict-2.12 {dict create command: non-compilation} {
+ dict create [format a] b
+} {a b}
+test dict-2.13 {dict create command: non-compilation} {
+ dict create [format a] b c d
+} {a b c d}
+test dict-2.14 {dict create command: non-compilation} {
+ dict create [format a] b c d a x
+} {a x c d}
test dict-3.1 {dict get command} {dict get {a b} a} b
test dict-3.2 {dict get command} {dict get {a b c d} a} b
@@ -1160,6 +1178,36 @@ test dict-20.9 {dict merge command} {
test dict-20.10 {dict merge command} {
dict merge {a b c d e f} {a x 1 2 3 4} {a - 1 -}
} {a - c d e f 1 - 3 4}
+test dict-20.11 {dict merge command} {
+ apply {{} {dict merge}}
+} {}
+test dict-20.12 {dict merge command} {
+ apply {{} {dict merge {a b c d e f}}}
+} {a b c d e f}
+test dict-20.13 {dict merge command} -body {
+ apply {{} {dict merge {a b c d e}}}
+} -result {missing value to go with key} -returnCodes error
+test dict-20.14 {dict merge command} {
+ apply {{} {dict merge {a b c d} {e f g h}}}
+} {a b c d e f g h}
+test dict-20.15 {dict merge command} -body {
+ apply {{} {dict merge {a b c d e} {e f g h}}}
+} -result {missing value to go with key} -returnCodes error
+test dict-20.16 {dict merge command} -body {
+ apply {{} {dict merge {a b c d} {e f g h i}}}
+} -result {missing value to go with key} -returnCodes error
+test dict-20.17 {dict merge command} {
+ apply {{} {dict merge {a b c d e f} {e x g h}}}
+} {a b c d e x g h}
+test dict-20.18 {dict merge command} {
+ apply {{} {dict merge {a b c d} {a x c y}}}
+} {a x c y}
+test dict-20.19 {dict merge command} {
+ apply {{} {dict merge {a b c d} {c y a x}}}
+} {a x c y}
+test dict-20.20 {dict merge command} {
+ apply {{} {dict merge {a b c d e f} {a x 1 2 3 4} {a - 1 -}}}
+} {a - c d e f 1 - 3 4}
test dict-21.1 {dict update command} -returnCodes 1 -body {
dict update
diff --git a/tests/info.test b/tests/info.test
index 7dd63b7..5078e11 100644
--- a/tests/info.test
+++ b/tests/info.test
@@ -1955,6 +1955,12 @@ test info-38.2 {location information for uplevel, dl, direct-literal} -match glo
* {type source line 1951 file info.test cmd etrace level 1}
* {type source line 1949 file info.test cmd uplevel\\ \\\\ level 1}} -cleanup {interp delete sub}
+# This test at the end of this file _only_ to avoid disturbing above line
+# numbers. It _belongs_ after info-9.12
+test info-9.13 {info level option, value in global context} -body {
+ uplevel #0 {info level 2}
+} -returnCodes error -result {bad level "2"}
+
# -------------------------------------------------------------------------
unset -nocomplain res
begin{funcdesc}{isstdin}{}
- Returns true iff the last line was read from \code{sys.stdin}.
-\end{funcdesc}
-
-\begin{funcdesc}{nextfile}{}
- Close the current file so that the next iteration will read the
- first line from the next file (if any); lines not read from the file
- will not count towards the cumulative line count. The filename is
- not changed until after the first line of the next file has been
- read. Before the first line has been read, this function has no
- effect; it cannot be used to skip the first file. After the last
- line of the last file has been read, this function has no effect.
-\end{funcdesc}
-
-\begin{funcdesc}{close}{}
- Close the sequence.
-\end{funcdesc}
-
-
-The class which implements the sequence behavior provided by the
-module is available for subclassing as well:
-
-\begin{classdesc}{FileInput}{\optional{files\optional{,
- inplace\optional{, backup}}}}
- Class \class{FileInput} is the implementation; its methods
- \method{filename()}, \method{lineno()}, \method{fileline()},
- \method{isfirstline()}, \method{isstdin()}, \method{nextfile()} and
- \method{close()} correspond to the functions of the same name in the
- module. In addition it has a \method{readline()} method which
- returns the next input line, and a \method{__getitem__()} method
- which implements the sequence behavior. The sequence must be
- accessed in strictly sequential order; random access and
- \method{readline()} cannot be mixed.
-\end{classdesc}
-
-\strong{Optional in-place filtering:} if the keyword argument
-\code{\var{inplace}=1} is passed to \function{input()} or to the
-\class{FileInput} constructor, the file is moved to a backup file and
-standard output is directed to the input file.
-This makes it possible to write a filter that rewrites its input file
-in place. If the keyword argument \code{\var{backup}='.<some
-extension>'} is also given, it specifies the extension for the backup
-file, and the backup file remains around; by default, the extension is
-\code{'.bak'} and it is deleted when the output file is closed. In-place
-filtering is disabled when standard input is read.
-
-\strong{Caveat:} The current implementation does not work for MS-DOS
-8+3 filesystems.
diff --git a/Doc/libfl.tex b/Doc/libfl.tex
deleted file mode 100644
index 7ebec7d..0000000
--- a/Doc/libfl.tex
+++ /dev/null
@@ -1,491 +0,0 @@
-\section{Built-in Module \module{fl}}
-\label{module-fl}
-\bimodindex{fl}
-
-This module provides an interface to the FORMS Library\index{FORMS
-Library} by Mark Overmars\index{Overmars, Mark}. The source for the
-library can be retrieved by anonymous ftp from host
-\samp{ftp.cs.ruu.nl}, directory \file{SGI/FORMS}. It was last tested
-with version 2.0b.
-
-Most functions are literal translations of their \C{} equivalents,
-dropping the initial \samp{fl_} from their name. Constants used by
-the library are defined in module \module{FL} described below.
-
-The creation of objects is a little different in Python than in C:
-instead of the `current form' maintained by the library to which new
-FORMS objects are added, all functions that add a FORMS object to a
-form are methods of the Python object representing the form.
-Consequently, there are no Python equivalents for the C functions
-\cfunction{fl_addto_form()} and \cfunction{fl_end_form()}, and the
-equivalent of \cfunction{fl_bgn_form()} is called
-\function{fl.make_form()}.
-
-Watch out for the somewhat confusing terminology: FORMS uses the word
-\dfn{object} for the buttons, sliders etc. that you can place in a form.
-In Python, `object' means any value. The Python interface to FORMS
-introduces two new Python object types: form objects (representing an
-entire form) and FORMS objects (representing one button, slider etc.).
-Hopefully this isn't too confusing.
-
-There are no `free objects' in the Python interface to FORMS, nor is
-there an easy way to add object classes written in Python. The FORMS
-interface to GL event handling is available, though, so you can mix
-FORMS with pure GL windows.
-
-\strong{Please note:} importing \module{fl} implies a call to the GL
-function \cfunction{foreground()} and to the FORMS routine
-\cfunction{fl_init()}.
-
-\subsection{Functions Defined in Module \module{fl}}
-\nodename{FL Functions}
-
-Module \module{fl} defines the following functions. For more
-information about what they do, see the description of the equivalent
-\C{} function in the FORMS documentation:
-
-\begin{funcdesc}{make_form}{type, width, height}
-Create a form with given type, width and height. This returns a
-\dfn{form} object, whose methods are described below.
-\end{funcdesc}
-
-\begin{funcdesc}{do_forms}{}
-The standard FORMS main loop. Returns a Python object representing
-the FORMS object needing interaction, or the special value
-\constant{FL.EVENT}.
-\end{funcdesc}
-
-\begin{funcdesc}{check_forms}{}
-Check for FORMS events. Returns what \function{do_forms()} above
-returns, or \code{None} if there is no event that immediately needs
-interaction.
-\end{funcdesc}
-
-\begin{funcdesc}{set_event_call_back}{function}
-Set the event callback function.
-\end{funcdesc}
-
-\begin{funcdesc}{set_graphics_mode}{rgbmode, doublebuffering}
-Set the graphics modes.
-\end{funcdesc}
-
-\begin{funcdesc}{get_rgbmode}{}
-Return the current rgb mode. This is the value of the \C{} global
-variable \cdata{fl_rgbmode}.
-\end{funcdesc}
-
-\begin{funcdesc}{show_message}{str1, str2, str3}
-Show a dialog box with a three-line message and an OK button.
-\end{funcdesc}
-
-\begin{funcdesc}{show_question}{str1, str2, str3}
-Show a dialog box with a three-line message and YES and NO buttons.
-It returns \code{1} if the user pressed YES, \code{0} if NO.
-\end{funcdesc}
-
-\begin{funcdesc}{show_choice}{str1, str2, str3, but1\optional{,
- but2\optional{, but3}}}
-Show a dialog box with a three-line message and up to three buttons.
-It returns the number of the button clicked by the user
-(\code{1}, \code{2} or \code{3}).
-\end{funcdesc}
-
-\begin{funcdesc}{show_input}{prompt, default}
-Show a dialog box with a one-line prompt message and text field in
-which the user can enter a string. The second argument is the default
-input string. It returns the string value as edited by the user.
-\end{funcdesc}
-
-\begin{funcdesc}{show_file_selector}{message, directory, pattern, default}
-Show a dialog box in which the user can select a file. It returns
-the absolute filename selected by the user, or \code{None} if the user
-presses Cancel.
-\end{funcdesc}
-
-\begin{funcdesc}{get_directory}{}
-\funcline{get_pattern}{}
-\funcline{get_filename}{}
-These functions return the directory, pattern and filename (the tail
-part only) selected by the user in the last
-\function{show_file_selector()} call.
-\end{funcdesc}
-
-\begin{funcdesc}{qdevice}{dev}
-\funcline{unqdevice}{dev}
-\funcline{isqueued}{dev}
-\funcline{qtest}{}
-\funcline{qread}{}
-%\funcline{blkqread}{?}
-\funcline{qreset}{}
-\funcline{qenter}{dev, val}
-\funcline{get_mouse}{}
-\funcline{tie}{button, valuator1, valuator2}
-These functions are the FORMS interfaces to the corresponding GL
-functions. Use these if you want to handle some GL events yourself
-when using \function{fl.do_events()}. When a GL event is detected that
-FORMS cannot handle, \function{fl.do_forms()} returns the special value
-\constant{FL.EVENT} and you should call \function{fl.qread()} to read
-the event from the queue. Don't use the equivalent GL functions!
-\end{funcdesc}
-
-\begin{funcdesc}{color}{}
-\funcline{mapcolor}{}
-\funcline{getmcolor}{}
-See the description in the FORMS documentation of
-\cfunction{fl_color()}, \cfunction{fl_mapcolor()} and
-\cfunction{fl_getmcolor()}.
-\end{funcdesc}
-
-\subsection{Form Objects}
-\label{form-objects}
-
-Form objects (returned by \function{make_form()} above) have the
-following methods. Each method corresponds to a \C{} function whose
-name is prefixed with \samp{fl_}; and whose first argument is a form
-pointer; please refer to the official FORMS documentation for
-descriptions.
-
-All the \method{add_*()} methods return a Python object representing
-the FORMS object. Methods of FORMS objects are described below. Most
-kinds of FORMS object also have some methods specific to that kind;
-these methods are listed here.
-
-\begin{flushleft}
-
-\begin{methoddesc}[form]{show_form}{placement, bordertype, name}
- Show the form.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{hide_form}{}
- Hide the form.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{redraw_form}{}
- Redraw the form.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{set_form_position}{x, y}
-Set the form's position.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{freeze_form}{}
-Freeze the form.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{unfreeze_form}{}
- Unfreeze the form.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{activate_form}{}
- Activate the form.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{deactivate_form}{}
- Deactivate the form.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{bgn_group}{}
- Begin a new group of objects; return a group object.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{end_group}{}
- End the current group of objects.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{find_first}{}
- Find the first object in the form.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{find_last}{}
- Find the last object in the form.
-\end{methoddesc}
-
-%---
-
-\begin{methoddesc}[form]{add_box}{type, x, y, w, h, name}
-Add a box object to the form.
-No extra methods.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{add_text}{type, x, y, w, h, name}
-Add a text object to the form.
-No extra methods.
-\end{methoddesc}
-
-%\begin{methoddesc}[form]{add_bitmap}{type, x, y, w, h, name}
-%Add a bitmap object to the form.
-%\end{methoddesc}
-
-\begin{methoddesc}[form]{add_clock}{type, x, y, w, h, name}
-Add a clock object to the form. \\
-Method:
-\method{get_clock()}.
-\end{methoddesc}
-
-%---
-
-\begin{methoddesc}[form]{add_button}{type, x, y, w, h, name}
-Add a button object to the form. \\
-Methods:
-\method{get_button()},
-\method{set_button()}.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{add_lightbutton}{type, x, y, w, h, name}
-Add a lightbutton object to the form. \\
-Methods:
-\method{get_button()},
-\method{set_button()}.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{add_roundbutton}{type, x, y, w, h, name}
-Add a roundbutton object to the form. \\
-Methods:
-\method{get_button()},
-\method{set_button()}.
-\end{methoddesc}
-
-%---
-
-\begin{methoddesc}[form]{add_slider}{type, x, y, w, h, name}
-Add a slider object to the form. \\
-Methods:
-\method{set_slider_value()},
-\method{get_slider_value()},
-\method{set_slider_bounds()},
-\method{get_slider_bounds()},
-\method{set_slider_return()},
-\method{set_slider_size()},
-\method{set_slider_precision()},
-\method{set_slider_step()}.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{add_valslider}{type, x, y, w, h, name}
-Add a valslider object to the form. \\
-Methods:
-\method{set_slider_value()},
-\method{get_slider_value()},
-\method{set_slider_bounds()},
-\method{get_slider_bounds()},
-\method{set_slider_return()},
-\method{set_slider_size()},
-\method{set_slider_precision()},
-\method{set_slider_step()}.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{add_dial}{type, x, y, w, h, name}
-Add a dial object to the form. \\
-Methods:
-\method{set_dial_value()},
-\method{get_dial_value()},
-\method{set_dial_bounds()},
-\method{get_dial_bounds()}.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{add_positioner}{type, x, y, w, h, name}
-Add a positioner object to the form. \\
-Methods:
-\method{set_positioner_xvalue()},
-\method{set_positioner_yvalue()},
-\method{set_positioner_xbounds()},
-\method{set_positioner_ybounds()},
-\method{get_positioner_xvalue()},
-\method{get_positioner_yvalue()},
-\method{get_positioner_xbounds()},
-\method{get_positioner_ybounds()}.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{add_counter}{type, x, y, w, h, name}
-Add a counter object to the form. \\
-Methods:
-\method{set_counter_value()},
-\method{get_counter_value()},
-\method{set_counter_bounds()},
-\method{set_counter_step()},
-\method{set_counter_precision()},
-\method{set_counter_return()}.
-\end{methoddesc}
-
-%---
-
-\begin{methoddesc}[form]{add_input}{type, x, y, w, h, name}
-Add a input object to the form. \\
-Methods:
-\method{set_input()},
-\method{get_input()},
-\method{set_input_color()},
-\method{set_input_return()}.
-\end{methoddesc}
-
-%---
-
-\begin{methoddesc}[form]{add_menu}{type, x, y, w, h, name}
-Add a menu object to the form. \\
-Methods:
-\method{set_menu()},
-\method{get_menu()},
-\method{addto_menu()}.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{add_choice}{type, x, y, w, h, name}
-Add a choice object to the form. \\
-Methods:
-\method{set_choice()},
-\method{get_choice()},
-\method{clear_choice()},
-\method{addto_choice()},
-\method{replace_choice()},
-\method{delete_choice()},
-\method{get_choice_text()},
-\method{set_choice_fontsize()},
-\method{set_choice_fontstyle()}.
-\end{methoddesc}
-
-\begin{methoddesc}[form]{add_browser}{type, x, y, w, h, name}
-Add a browser object to the form. \\
-Methods:
-\method{set_browser_topline()},
-\method{clear_browser()},
-\method{add_browser_line()},
-\method{addto_browser()},
-\method{insert_browser_line()},
-\method{delete_browser_line()},
-\method{replace_browser_line()},
-\method{get_browser_line()},
-\method{load_browser()},
-\method{get_browser_maxline()},
-\method{select_browser_line()},
-\method{deselect_browser_line()},
-\method{deselect_browser()},
-\method{isselected_browser_line()},
-\method{get_browser()},
-\method{set_browser_fontsize()},
-\method{set_browser_fontstyle()},
-\method{set_browser_specialkey()}.
-\end{methoddesc}
-
-%---
-
-\begin{methoddesc}[form]{add_timer}{type, x, y, w, h, name}
-Add a timer object to the form. \\
-Methods:
-\method{set_timer()},
-\method{get_timer()}.
-\end{methoddesc}
-\end{flushleft}
-
-Form objects have the following data attributes; see the FORMS
-documentation:
-
-\begin{tableiii}{l|l|l}{member}{Name}{C Type}{Meaning}
- \lineiii{window}{int (read-only)}{GL window id}
- \lineiii{w}{float}{form width}
- \lineiii{h}{float}{form height}
- \lineiii{x}{float}{form x origin}
- \lineiii{y}{float}{form y origin}
- \lineiii{deactivated}{int}{nonzero if form is deactivated}
- \lineiii{visible}{int}{nonzero if form is visible}
- \lineiii{frozen}{int}{nonzero if form is frozen}
- \lineiii{doublebuf}{int}{nonzero if double buffering on}
-\end{tableiii}
-
-\subsection{FORMS Objects}
-\label{forms-objects}
-
-Besides methods specific to particular kinds of FORMS objects, all
-FORMS objects also have the following methods:
-
-\begin{methoddesc}[FORMS object]{set_call_back}{function, argument}
-Set the object's callback function and argument. When the object
-needs interaction, the callback function will be called with two
-arguments: the object, and the callback argument. (FORMS objects
-without a callback function are returned by \function{fl.do_forms()}
-or \function{fl.check_forms()} when they need interaction.) Call this
-method without arguments to remove the callback function.
-\end{methoddesc}
-
-\begin{methoddesc}[FORMS object]{delete_object}{}
- Delete the object.
-\end{methoddesc}
-
-\begin{methoddesc}[FORMS object]{show_object}{}
- Show the object.
-\end{methoddesc}
-
-\begin{methoddesc}[FORMS object]{hide_object}{}
- Hide the object.
-\end{methoddesc}
-
-\begin{methoddesc}[FORMS object]{redraw_object}{}
- Redraw the object.
-\end{methoddesc}
-
-\begin{methoddesc}[FORMS object]{freeze_object}{}
- Freeze the object.
-\end{methoddesc}
-
-\begin{methoddesc}[FORMS object]{unfreeze_object}{}
- Unfreeze the object.
-\end{methoddesc}
-
-%\begin{methoddesc}[FORMS object]{handle_object}{} XXX
-%\end{methoddesc}
-
-%\begin{methoddesc}[FORMS object]{handle_object_direct}{} XXX
-%\end{methoddesc}
-
-FORMS objects have these data attributes; see the FORMS documentation:
-
-\begin{tableiii}{l|l|l}{member}{Name}{C Type}{Meaning}
- \lineiii{objclass}{int (read-only)}{object class}
- \lineiii{type}{int (read-only)}{object type}
- \lineiii{boxtype}{int}{box type}
- \lineiii{x}{float}{x origin}
- \lineiii{y}{float}{y origin}
- \lineiii{w}{float}{width}
- \lineiii{h}{float}{height}
- \lineiii{col1}{int}{primary color}
- \lineiii{col2}{int}{secondary color}
- \lineiii{align}{int}{alignment}
- \lineiii{lcol}{int}{label color}
- \lineiii{lsize}{float}{label font size}
- \lineiii{label}{string}{label string}
- \lineiii{lstyle}{int}{label style}
- \lineiii{pushed}{int (read-only)}{(see FORMS docs)}
- \lineiii{focus}{int (read-only)}{(see FORMS docs)}
- \lineiii{belowmouse}{int (read-only)}{(see FORMS docs)}
- \lineiii{frozen}{int (read-only)}{(see FORMS docs)}
- \lineiii{active}{int (read-only)}{(see FORMS docs)}
- \lineiii{input}{int (read-only)}{(see FORMS docs)}
- \lineiii{visible}{int (read-only)}{(see FORMS docs)}
- \lineiii{radio}{int (read-only)}{(see FORMS docs)}
- \lineiii{automatic}{int (read-only)}{(see FORMS docs)}
-\end{tableiii}
-
-\section{Standard Module \module{FL}}
-\label{module-FLuppercase}
-\stmodindex{FL}
-
-This module defines symbolic constants needed to use the built-in
-module \module{fl} (see above); they are equivalent to those defined in
-the \C{} header file \code{<forms.h>} except that the name prefix
-\samp{FL_} is omitted. Read the module source for a complete list of
-the defined names. Suggested use:
-
-\begin{verbatim}
-import fl
-from FL import *
-\end{verbatim}
-
-\section{Standard Module \module{flp}}
-\label{module-flp}
-\stmodindex{flp}
-
-This module defines functions that can read form definitions created
-by the `form designer' (\program{fdesign}) program that comes with the
-FORMS library (see module \module{fl} above).
-
-For now, see the file \file{flp.doc} in the Python library source
-directory for a description.
-
-XXX A complete description should be inserted here!
diff --git a/Doc/libfm.tex b/Doc/libfm.tex
deleted file mode 100644
index abcbaa4..0000000
--- a/Doc/libfm.tex
+++ /dev/null
@@ -1,90 +0,0 @@
-\section{Built-in Module \module{fm}}
-\label{module-fm}
-\bimodindex{fm}
-
-This module provides access to the IRIS \emph{Font Manager} library.
-\index{Font Manager, IRIS}
-\index{IRIS Font Manager}
-It is available only on Silicon Graphics machines.
-See also: \emph{4Sight User's Guide}, Section 1, Chapter 5: ``Using
-the IRIS Font Manager.''
-
-This is not yet a full interface to the IRIS Font Manager.
-Among the unsupported features are: matrix operations; cache
-operations; character operations (use string operations instead); some
-details of font info; individual glyph metrics; and printer matching.
-
-It supports the following operations:
-
-\begin{funcdesc}{init}{}
-Initialization function.
-Calls \cfunction{fminit()}.
-It is normally not necessary to call this function, since it is called
-automatically the first time the \module{fm} module is imported.
-\end{funcdesc}
-
-\begin{funcdesc}{findfont}{fontname}
-Return a font handle object.
-Calls \code{fmfindfont(\var{fontname})}.
-\end{funcdesc}
-
-\begin{funcdesc}{enumerate}{}
-Returns a list of available font names.
-This is an interface to \cfunction{fmenumerate()}.
-\end{funcdesc}
-
-\begin{funcdesc}{prstr}{string}
-Render a string using the current font (see the \function{setfont()} font
-handle method below).
-Calls \code{fmprstr(\var{string})}.
-\end{funcdesc}
-
-\begin{funcdesc}{setpath}{string}
-Sets the font search path.
-Calls \code{fmsetpath(\var{string})}.
-(XXX Does not work!?!)
-\end{funcdesc}
-
-\begin{funcdesc}{fontpath}{}
-Returns the current font search path.
-\end{funcdesc}
-
-Font handle objects support the following operations:
-
-\setindexsubitem{(font handle method)}
-\begin{funcdesc}{scalefont}{factor}
-Returns a handle for a scaled version of this font.
-Calls \code{fmscalefont(\var{fh}, \var{factor})}.
-\end{funcdesc}
-
-\begin{funcdesc}{setfont}{}
-Makes this font the current font.
-Note: the effect is undone silently when the font handle object is
-deleted.
-Calls \code{fmsetfont(\var{fh})}.
-\end{funcdesc}
-
-\begin{funcdesc}{getfontname}{}
-Returns this font's name.
-Calls \code{fmgetfontname(\var{fh})}.
-\end{funcdesc}
-
-\begin{funcdesc}{getcomment}{}
-Returns the comment string associated with this font.
-Raises an exception if there is none.
-Calls \code{fmgetcomment(\var{fh})}.
-\end{funcdesc}
-
-\begin{funcdesc}{getfontinfo}{}
-Returns a tuple giving some pertinent data about this font.
-This is an interface to \code{fmgetfontinfo()}.
-The returned tuple contains the following numbers:
-\code{(}\var{printermatched}, \var{fixed_width}, \var{xorig},
-\var{yorig}, \var{xsize}, \var{ysize}, \var{height},
-\var{nglyphs}\code{)}.
-\end{funcdesc}
-
-\begin{funcdesc}{getstrwidth}{string}
-Returns the width, in pixels, of \var{string} when drawn in this font.
-Calls \code{fmgetstrwidth(\var{fh}, \var{string})}.
-\end{funcdesc}
diff --git a/Doc/libfnmatch.tex b/Doc/libfnmatch.tex
deleted file mode 100644
index f2f82ba..0000000
--- a/Doc/libfnmatch.tex
+++ /dev/null
@@ -1,40 +0,0 @@
-\section{Standard Module \module{fnmatch}}
-\label{module-fnmatch}
-\stmodindex{fnmatch}
-
-This module provides support for \UNIX{} shell-style wildcards, which
-are \emph{not} the same as regular expressions (which are documented
-in the \module{re}\refstmodindex{re} module). The special characters
-used in shell-style wildcards are:
-
-\begin{list}{}{\leftmargin 0.5in \labelwidth 0.45in}
-\item[\code{*}] matches everything
-\item[\code{?}] matches any single character
-\item[\code{[}\var{seq}\code{]}] matches any character in \var{seq}
-\item[\code{[!}\var{seq}\code{]}] matches any character not in \var{seq}
-\end{list}
-
-Note that the filename separator (\code{'/'} on \UNIX{}) is \emph{not}
-special to this module. See module \code{glob}\refstmodindex{glob}
-for pathname expansion (\module{glob} uses \function{fnmatch()} to
-match filename segments).
-
-
-\begin{funcdesc}{fnmatch}{filename, pattern}
-Test whether the \var{filename} string matches the \var{pattern}
-string, returning true or false. If the operating system is
-case-insensitive, then both parameters will be normalized to all
-lower- or upper-case before the comparision is performed. If you
-require a case-sensitive comparision regardless of whether that's
-standard for your operating system, use \function{fnmatchcase()}
-instead.
-\end{funcdesc}
-
-\begin{funcdesc}{fnmatchcase}{filename, pattern}
-Test whether \var{filename} matches \var{pattern}, returning true or
-false; the comparision is case-sensitive.
-\end{funcdesc}
-
-\begin{seealso}
-\seemodule{glob}{Shell-style path expansion}
-\end{seealso}
diff --git a/Doc/libformatter.tex b/Doc/libformatter.tex
deleted file mode 100644
index 6a97f80..0000000
--- a/Doc/libformatter.tex
+++ /dev/null
@@ -1,323 +0,0 @@
-\section{Standard Module \module{formatter}}
-\label{module-formatter}
-\stmodindex{formatter}
-
-
-This module supports two interface definitions, each with mulitple
-implementations. The \emph{formatter} interface is used by the
-\class{HTMLParser} class of the \module{htmllib} module, and the
-\emph{writer} interface is required by the formatter interface.
-\withsubitem{(class in htmllib)}{\ttindex{HTMLParser}}
-
-Formatter objects transform an abstract flow of formatting events into
-specific output events on writer objects. Formatters manage several
-stack structures to allow various properties of a writer object to be
-changed and restored; writers need not be able to handle relative
-changes nor any sort of ``change back'' operation. Specific writer
-properties which may be controlled via formatter objects are
-horizontal alignment, font, and left margin indentations. A mechanism
-is provided which supports providing arbitrary, non-exclusive style
-settings to a writer as well. Additional interfaces facilitate
-formatting events which are not reversible, such as paragraph
-separation.
-
-Writer objects encapsulate device interfaces. Abstract devices, such
-as file formats, are supported as well as physical devices. The
-provided implementations all work with abstract devices. The
-interface makes available mechanisms for setting the properties which
-formatter objects manage and inserting data into the output.
-
-
-\subsection{The Formatter Interface}
-
-Interfaces to create formatters are dependent on the specific
-formatter class being instantiated. The interfaces described below
-are the required interfaces which all formatters must support once
-initialized.
-
-One data element is defined at the module level:
-
-
-\begin{datadesc}{AS_IS}
-Value which can be used in the font specification passed to the
-\code{push_font()} method described below, or as the new value to any
-other \code{push_\var{property}()} method. Pushing the \code{AS_IS}
-value allows the corresponding \code{pop_\var{property}()} method to
-be called without having to track whether the property was changed.
-\end{datadesc}
-
-The following attributes are defined for formatter instance objects:
-
-
-\begin{memberdesc}[formatter]{writer}
-The writer instance with which the formatter interacts.
-\end{memberdesc}
-
-
-\begin{methoddesc}[formatter]{end_paragraph}{blanklines}
-Close any open paragraphs and insert at least \var{blanklines}
-before the next paragraph.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{add_line_break}{}
-Add a hard line break if one does not already exist. This does not
-break the logical paragraph.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{add_hor_rule}{*args, **kw}
-Insert a horizontal rule in the output. A hard break is inserted if
-there is data in the current paragraph, but the logical paragraph is
-not broken. The arguments and keywords are passed on to the writer's
-\method{send_line_break()} method.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{add_flowing_data}{data}
-Provide data which should be formatted with collapsed whitespaces.
-Whitespace from preceeding and successive calls to
-\method{add_flowing_data()} is considered as well when the whitespace
-collapse is performed. The data which is passed to this method is
-expected to be word-wrapped by the output device. Note that any
-word-wrapping still must be performed by the writer object due to the
-need to rely on device and font information.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{add_literal_data}{data}
-Provide data which should be passed to the writer unchanged.
-Whitespace, including newline and tab characters, are considered legal
-in the value of \var{data}.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{add_label_data}{format, counter}
-Insert a label which should be placed to the left of the current left
-margin. This should be used for constructing bulleted or numbered
-lists. If the \var{format} value is a string, it is interpreted as a
-format specification for \var{counter}, which should be an integer.
-The result of this formatting becomes the value of the label; if
-\var{format} is not a string it is used as the label value directly.
-The label value is passed as the only argument to the writer's
-\method{send_label_data()} method. Interpretation of non-string label
-values is dependent on the associated writer.
-
-Format specifications are strings which, in combination with a counter
-value, are used to compute label values. Each character in the format
-string is copied to the label value, with some characters recognized
-to indicate a transform on the counter value. Specifically, the
-character \character{1} represents the counter value formatter as an
-arabic number, the characters \character{A} and \character{a}
-represent alphabetic representations of the counter value in upper and
-lower case, respectively, and \character{I} and \character{i}
-represent the counter value in Roman numerals, in upper and lower
-case. Note that the alphabetic and roman transforms require that the
-counter value be greater than zero.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{flush_softspace}{}
-Send any pending whitespace buffered from a previous call to
-\method{add_flowing_data()} to the associated writer object. This
-should be called before any direct manipulation of the writer object.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{push_alignment}{align}
-Push a new alignment setting onto the alignment stack. This may be
-\constant{AS_IS} if no change is desired. If the alignment value is
-changed from the previous setting, the writer's \method{new_alignment()}
-method is called with the \var{align} value.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{pop_alignment}{}
-Restore the previous alignment.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{push_font}{\code{(}size, italic, bold, teletype\code{)}}
-Change some or all font properties of the writer object. Properties
-which are not set to \constant{AS_IS} are set to the values passed in
-while others are maintained at their current settings. The writer's
-\method{new_font()} method is called with the fully resolved font
-specification.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{pop_font}{}
-Restore the previous font.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{push_margin}{margin}
-Increase the number of left margin indentations by one, associating
-the logical tag \var{margin} with the new indentation. The initial
-margin level is \code{0}. Changed values of the logical tag must be
-true values; false values other than \constant{AS_IS} are not
-sufficient to change the margin.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{pop_margin}{}
-Restore the previous margin.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{push_style}{*styles}
-Push any number of arbitrary style specifications. All styles are
-pushed onto the styles stack in order. A tuple representing the
-entire stack, including \constant{AS_IS} values, is passed to the
-writer's \method{new_styles()} method.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{pop_style}{\optional{n\code{ = 1}}}
-Pop the last \var{n} style specifications passed to
-\method{push_style()}. A tuple representing the revised stack,
-including \constant{AS_IS} values, is passed to the writer's
-\method{new_styles()} method.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{set_spacing}{spacing}
-Set the spacing style for the writer.
-\end{methoddesc}
-
-\begin{methoddesc}[formatter]{assert_line_data}{\optional{flag\code{ = 1}}}
-Inform the formatter that data has been added to the current paragraph
-out-of-band. This should be used when the writer has been manipulated
-directly. The optional \var{flag} argument can be set to false if
-the writer manipulations produced a hard line break at the end of the
-output.
-\end{methoddesc}
-
-
-\subsection{Formatter Implementations}
-
-Two implementations of formatter objects are provided by this module.
-Most applications may use one of these classes without modification or
-subclassing.
-
-\begin{classdesc}{NullFormatter}{\optional{writer}}
-A formatter which does nothing. If \var{writer} is omitted, a
-\class{NullWriter} instance is created. No methods of the writer are
-called by \class{NullFormatter} instances. Implementations should
-inherit from this class if implementing a writer interface but don't
-need to inherit any implementation.
-\end{classdesc}
-
-\begin{classdesc}{AbstractFormatter}{writer}
-The standard formatter. This implementation has demonstrated wide
-applicability to many writers, and may be used directly in most
-circumstances. It has been used to implement a full-featured
-world-wide web browser.
-\end{classdesc}
-
-
-
-\subsection{The Writer Interface}
-
-Interfaces to create writers are dependent on the specific writer
-class being instantiated. The interfaces described below are the
-required interfaces which all writers must support once initialized.
-Note that while most applications can use the
-\class{AbstractFormatter} class as a formatter, the writer must
-typically be provided by the application.
-
-
-\begin{methoddesc}[writer]{flush}{}
-Flush any buffered output or device control events.
-\end{methoddesc}
-
-\begin{methoddesc}[writer]{new_alignment}{align}
-Set the alignment style. The \var{align} value can be any object,
-but by convention is a string or \code{None}, where \code{None}
-indicates that the writer's ``preferred'' alignment should be used.
-Conventional \var{align} values are \code{'left'}, \code{'center'},
-\code{'right'}, and \code{'justify'}.
-\end{methoddesc}
-
-\begin{methoddesc}[writer]{new_font}{font}
-Set the font style. The value of \var{font} will be \code{None},
-indicating that the device's default font should be used, or a tuple
-of the form \code{(}\var{size}, \var{italic}, \var{bold},
-\var{teletype}\code{)}. Size will be a string indicating the size of
-font that should be used; specific strings and their interpretation
-must be defined by the application. The \var{italic}, \var{bold}, and
-\var{teletype} values are boolean indicators specifying which of those
-font attributes should be used.
-\end{methoddesc}
-
-\begin{methoddesc}[writer]{new_margin}{margin, level}
-Set the margin level to the integer \var{level} and the logical tag
-to \var{margin}. Interpretation of the logical tag is at the
-writer's discretion; the only restriction on the value of the logical
-tag is that it not be a false value for non-zero values of
-\var{level}.
-\end{methoddesc}
-
-\begin{methoddesc}[writer]{new_spacing}{spacing}
-Set the spacing style to \var{spacing}.
-\end{methoddesc}
-
-\begin{methoddesc}[writer]{new_styles}{styles}
-Set additional styles. The \var{styles} value is a tuple of
-arbitrary values; the value \constant{AS_IS} should be ignored. The
-\var{styles} tuple may be interpreted either as a set or as a stack
-depending on the requirements of the application and writer
-implementation.
-\end{methoddesc}
-
-\begin{methoddesc}[writer]{send_line_break}{}
-Break the current line.
-\end{methoddesc}
-
-\begin{methoddesc}[writer]{send_paragraph}{blankline}
-Produce a paragraph separation of at least \var{blankline} blank
-lines, or the equivelent. The \var{blankline} value will be an
-integer.
-\end{methoddesc}
-
-\begin{methoddesc}[writer]{send_hor_rule}{*args, **kw}
-Display a horizontal rule on the output device. The arguments to this
-method are entirely application- and writer-specific, and should be
-interpreted with care. The method implementation may assume that a
-line break has already been issued via \method{send_line_break()}.
-\end{methoddesc}
-
-\begin{methoddesc}[writer]{send_flowing_data}{data}
-Output character data which may be word-wrapped and re-flowed as
-needed. Within any sequence of calls to this method, the writer may
-assume that spans of multiple whitespace characters have been
-collapsed to single space characters.
-\end{methoddesc}
-
-\begin{methoddesc}[writer]{send_literal_data}{data}
-Output character data which has already been formatted
-for display. Generally, this should be interpreted to mean that line
-breaks indicated by newline characters should be preserved and no new
-line breaks should be introduced. The data may contain embedded
-newline and tab characters, unlike data provided to the
-\method{send_formatted_data()} interface.
-\end{methoddesc}
-
-\begin{methoddesc}[writer]{send_label_data}{data}
-Set \var{data} to the left of the current left margin, if possible.
-The value of \var{data} is not restricted; treatment of non-string
-values is entirely application- and writer-dependent. This method
-will only be called at the beginning of a line.
-\end{methoddesc}
-
-
-\subsection{Writer Implementations}
-
-Three implementations of the writer object interface are provided as
-examples by this module. Most applications will need to derive new
-writer classes from the \class{NullWriter} class.
-
-\begin{classdesc}{NullWriter}{}
-A writer which only provides the interface definition; no actions are
-taken on any methods. This should be the base class for all writers
-which do not need to inherit any implementation methods.
-\end{classdesc}
-
-\begin{classdesc}{AbstractWriter}{}
-A writer which can be used in debugging formatters, but not much
-else. Each method simply announces itself by printing its name and
-arguments on standard output.
-\end{classdesc}
-
-\begin{classdesc}{DumbWriter}{\optional{file\optional{, maxcol\code{ = 72}}}}
-Simple writer class which writes output on the file object passed in
-as \var{file} or, if \var{file} is omitted, on standard output. The
-output is simply word-wrapped to the number of columns specified by
-\var{maxcol}. This class is suitable for reflowing a sequence of
-paragraphs.
-\end{classdesc}
diff --git a/Doc/libframework.tex b/Doc/libframework.tex
deleted file mode 100644
index 5bd2e2a..0000000
--- a/Doc/libframework.tex
+++ /dev/null
@@ -1,294 +0,0 @@
-\section{Standard Module \module{FrameWork}}
-\stmodindex{FrameWork}
-\label{module-FrameWork}
-
-The \module{FrameWork} module contains classes that together provide a
-framework for an interactive Macintosh application. The programmer
-builds an application by creating subclasses that override various
-methods of the bases classes, thereby implementing the functionality
-wanted. Overriding functionality can often be done on various
-different levels, i.e. to handle clicks in a single dialog window in a
-non-standard way it is not necessary to override the complete event
-handling.
-
-The \module{FrameWork} is still very much work-in-progress, and the
-documentation describes only the most important functionality, and not
-in the most logical manner at that. Examine the source or the examples
-for more details.
-
-The \module{FrameWork} module defines the following functions:
-
-
-\begin{funcdesc}{Application}{}
-An object representing the complete application. See below for a
-description of the methods. The default \method{__init__()} routine
-creates an empty window dictionary and a menu bar with an apple menu.
-\end{funcdesc}
-
-\begin{funcdesc}{MenuBar}{}
-An object representing the menubar. This object is usually not created
-by the user.
-\end{funcdesc}
-
-\begin{funcdesc}{Menu}{bar, title\optional{, after}}
-An object representing a menu. Upon creation you pass the
-\code{MenuBar} the menu appears in, the \var{title} string and a
-position (1-based) \var{after} where the menu should appear (default:
-at the end).
-\end{funcdesc}
-
-\begin{funcdesc}{MenuItem}{menu, title\optional{, shortcut, callback}}
-Create a menu item object. The arguments are the menu to crate the
-item it, the item title string and optionally the keyboard shortcut
-and a callback routine. The callback is called with the arguments
-menu-id, item number within menu (1-based), current front window and
-the event record.
-
-In stead of a callable object the callback can also be a string. In
-this case menu selection causes the lookup of a method in the topmost
-window and the application. The method name is the callback string
-with \code{'domenu_'} prepended.
-
-Calling the \code{MenuBar} \code{fixmenudimstate} method sets the
-correct dimming for all menu items based on the current front window.
-\end{funcdesc}
-
-\begin{funcdesc}{Separator}{menu}
-Add a separator to the end of a menu.
-\end{funcdesc}
-
-\begin{funcdesc}{SubMenu}{menu, label}
-Create a submenu named \var{label} under menu \var{menu}. The menu
-object is returned.
-\end{funcdesc}
-
-\begin{funcdesc}{Window}{parent}
-Creates a (modeless) window. \var{Parent} is the application object to
-which the window belongs. The window is not displayed until later.
-\end{funcdesc}
-
-\begin{funcdesc}{DialogWindow}{parent}
-Creates a modeless dialog window.
-\end{funcdesc}
-
-\begin{funcdesc}{windowbounds}{width, height}
-Return a \code{(left, top, right, bottom)} tuple suitable for creation
-of a window of given width and height. The window will be staggered
-with respect to previous windows, and an attempt is made to keep the
-whole window on-screen. The window will however always be exact the
-size given, so parts may be offscreen.
-\end{funcdesc}
-
-\begin{funcdesc}{setwatchcursor}{}
-Set the mouse cursor to a watch.
-\end{funcdesc}
-
-\begin{funcdesc}{setarrowcursor}{}
-Set the mouse cursor to an arrow.
-\end{funcdesc}
-
-\subsection{Application Objects}
-\label{application-objects}
-
-Application objects have the following methods, among others:
-
-\setindexsubitem{(Application method)}
-
-\begin{funcdesc}{makeusermenus}{}
-Override this method if you need menus in your application. Append the
-menus to the attribute \member{menubar}.
-\end{funcdesc}
-
-\begin{funcdesc}{getabouttext}{}
-Override this method to return a text string describing your
-application. Alternatively, override the \method{do_about()} method
-for more elaborate ``about'' messages.
-\end{funcdesc}
-
-\begin{funcdesc}{mainloop}{\optional{mask\optional{, wait}}}
-This routine is the main event loop, call it to set your application
-rolling. \var{Mask} is the mask of events you want to handle,
-\var{wait} is the number of ticks you want to leave to other
-concurrent application (default 0, which is probably not a good
-idea). While raising \code{self} to exit the mainloop is still
-supported it is not recommended, call \code{self._quit} instead.
-
-The event loop is split into many small parts, each of which can be
-overridden. The default methods take care of dispatching events to
-windows and dialogs, handling drags and resizes, Apple Events, events
-for non-FrameWork windows, etc.
-
-In general, all event handlers should return \code{1} if the event is fully
-handled and \code{0} otherwise (because the front window was not a FrameWork
-window, for instance). This is needed so that update events and such
-can be passed on to other windows like the Sioux console window.
-Calling \function{MacOS.HandleEvent()} is not allowed within
-\var{our_dispatch} or its callees, since this may result in an
-infinite loop if the code is called through the Python inner-loop
-event handler.
-\end{funcdesc}
-
-\begin{funcdesc}{asyncevents}{onoff}
-Call this method with a nonzero parameter to enable
-asynchronous event handling. This will tell the inner interpreter loop
-to call the application event handler \var{async_dispatch} whenever events
-are available. This will cause FrameWork window updates and the user
-interface to remain working during long computations, but will slow the
-interpreter down and may cause surprising results in non-reentrant code
-(such as FrameWork itself). By default \var{async_dispatch} will immedeately
-call \var{our_dispatch} but you may override this to handle only certain
-events asynchronously. Events you do not handle will be passed to Sioux
-and such.
-
-The old on/off value is returned.
-\end{funcdesc}
-
-\begin{funcdesc}{_quit}{}
-Terminate the running \method{mainloop()} call at the next convenient
-moment.
-\end{funcdesc}
-
-\begin{funcdesc}{do_char}{c, event}
-The user typed character \var{c}. The complete details of the event
-can be found in the \var{event} structure. This method can also be
-provided in a \code{Window} object, which overrides the
-application-wide handler if the window is frontmost.
-\end{funcdesc}
-
-\begin{funcdesc}{do_dialogevent}{event}
-Called early in the event loop to handle modeless dialog events. The
-default method simply dispatches the event to the relevant dialog (not
-through the the \code{DialogWindow} object involved). Override if you
-need special handling of dialog events (keyboard shortcuts, etc).
-\end{funcdesc}
-
-\begin{funcdesc}{idle}{event}
-Called by the main event loop when no events are available. The
-null-event is passed (so you can look at mouse position, etc).
-\end{funcdesc}
-
-\subsection{Window Objects}
-\label{window-objects}
-
-Window objects have the following methods, among others:
-
-\setindexsubitem{(Window method)}
-
-\begin{funcdesc}{open}{}
-Override this method to open a window. Store the MacOS window-id in
-\code{self.wid} and call \code{self.do_postopen} to register the
-window with the parent application.
-\end{funcdesc}
-
-\begin{funcdesc}{close}{}
-Override this method to do any special processing on window
-close. Call \code{self.do_postclose} to cleanup the parent state.
-\end{funcdesc}
-
-\begin{funcdesc}{do_postresize}{width, height, macoswindowid}
-Called after the window is resized. Override if more needs to be done
-than calling \code{InvalRect}.
-\end{funcdesc}
-
-\begin{funcdesc}{do_contentclick}{local, modifiers, event}
-The user clicked in the content part of a window. The arguments are
-the coordinates (window-relative), the key modifiers and the raw
-event.
-\end{funcdesc}
-
-\begin{funcdesc}{do_update}{macoswindowid, event}
-An update event for the window was received. Redraw the window.
-\end{funcdesc}
-
-\begin{funcdesc}{do_activate}{activate, event}
-The window was activated (\code{activate==1}) or deactivated
-(\code{activate==0}). Handle things like focus highlighting, etc.
-\end{funcdesc}
-
-\subsection{ControlsWindow Object}
-\label{controlswindow-object}
-
-ControlsWindow objects have the following methods besides those of
-\code{Window} objects:
-
-\setindexsubitem{(ControlsWindow method)}
-
-\begin{funcdesc}{do_controlhit}{window, control, pcode, event}
-Part \code{pcode} of control \code{control} was hit by the
-user. Tracking and such has already been taken care of.
-\end{funcdesc}
-
-\subsection{ScrolledWindow Object}
-\label{scrolledwindow-object}
-
-ScrolledWindow objects are ControlsWindow objects with the following
-extra methods:
-
-\setindexsubitem{(ScrolledWindow method)}
-
-\begin{funcdesc}{scrollbars}{\optional{wantx\optional{, wanty}}}
-Create (or destroy) horizontal and vertical scrollbars. The arguments
-specify which you want (default: both). The scrollbars always have
-minimum \code{0} and maximum \code{32767}.
-\end{funcdesc}
-
-\begin{funcdesc}{getscrollbarvalues}{}
-You must supply this method. It should return a tuple \code{(\var{x},
-\var{y})} giving the current position of the scrollbars (between
-\code{0} and \code{32767}). You can return \code{None} for either to
-indicate the whole document is visible in that direction.
-\end{funcdesc}
-
-\begin{funcdesc}{updatescrollbars}{}
-Call this method when the document has changed. It will call
-\method{getscrollbarvalues()} and update the scrollbars.
-\end{funcdesc}
-
-\begin{funcdesc}{scrollbar_callback}{which, what, value}
-Supplied by you and called after user interaction. \var{which} will
-be \code{'x'} or \code{'y'}, \var{what} will be \code{'-'},
-\code{'--'}, \code{'set'}, \code{'++'} or \code{'+'}. For
-\code{'set'}, \var{value} will contain the new scrollbar position.
-\end{funcdesc}
-
-\begin{funcdesc}{scalebarvalues}{absmin, absmax, curmin, curmax}
-Auxiliary method to help you calculate values to return from
-\method{getscrollbarvalues()}. You pass document minimum and maximum value
-and topmost (leftmost) and bottommost (rightmost) visible values and
-it returns the correct number or \code{None}.
-\end{funcdesc}
-
-\begin{funcdesc}{do_activate}{onoff, event}
-Takes care of dimming/highlighting scrollbars when a window becomes
-frontmost vv. If you override this method call this one at the end of
-your method.
-\end{funcdesc}
-
-\begin{funcdesc}{do_postresize}{width, height, window}
-Moves scrollbars to the correct position. Call this method initially
-if you override it.
-\end{funcdesc}
-
-\begin{funcdesc}{do_controlhit}{window, control, pcode, event}
-Handles scrollbar interaction. If you override it call this method
-first, a nonzero return value indicates the hit was in the scrollbars
-and has been handled.
-\end{funcdesc}
-
-\subsection{DialogWindow Objects}
-\label{dialogwindow-objects}
-
-DialogWindow objects have the following methods besides those of
-\code{Window} objects:
-
-\setindexsubitem{(DialogWindow method)}
-
-\begin{funcdesc}{open}{resid}
-Create the dialog window, from the DLOG resource with id
-\var{resid}. The dialog object is stored in \code{self.wid}.
-\end{funcdesc}
-
-\begin{funcdesc}{do_itemhit}{item, event}
-Item number \var{item} was hit. You are responsible for redrawing
-toggle buttons, etc.
-\end{funcdesc}
diff --git a/Doc/libftplib.tex b/Doc/libftplib.tex
deleted file mode 100644
index 8ba2c61..0000000
--- a/Doc/libftplib.tex
+++ /dev/null
@@ -1,240 +0,0 @@
-\section{Standard Module \module{ftplib}}
-\label{module-ftplib}
-\stmodindex{ftplib}
-\indexii{FTP}{protocol}
-
-
-This module defines the class \class{FTP} and a few related items.
-The \class{FTP} class implements the client side of the FTP protocol.
-You can use this to write Python programs that perform a variety of
-automated FTP jobs, such as mirroring other ftp servers. It is also
-used by the module \module{urllib} to handle URLs that use FTP. For
-more information on FTP (File Transfer Protocol), see Internet
-\rfc{959}.
-
-Here's a sample session using the \module{ftplib} module:
-
-\begin{verbatim}
->>> from ftplib import FTP
->>> ftp = FTP('ftp.cwi.nl') # connect to host, default port
->>> ftp.login() # user anonymous, passwd user@hostname
->>> ftp.retrlines('LIST') # list directory contents
-total 24418
-drwxrwsr-x 5 ftp-usr pdmaint 1536 Mar 20 09:48 .
-dr-xr-srwt 105 ftp-usr pdmaint 1536 Mar 21 14:32 ..
--rw-r--r-- 1 ftp-usr pdmaint 5305 Mar 20 09:48 INDEX
- .
- .
- .
->>> ftp.quit()
-\end{verbatim}
-
-The module defines the following items:
-
-\begin{classdesc}{FTP}{\optional{host\optional{, user\optional{,
- passwd\optional{, acct}}}}}
-Return a new instance of the \class{FTP} class. When
-\var{host} is given, the method call \code{connect(\var{host})} is
-made. When \var{user} is given, additionally the method call
-\code{login(\var{user}, \var{passwd}, \var{acct})} is made (where
-\var{passwd} and \var{acct} default to the empty string when not given).
-\end{classdesc}
-
-\begin{datadesc}{all_errors}
-The set of all exceptions (as a tuple) that methods of \class{FTP}
-instances may raise as a result of problems with the FTP connection
-(as opposed to programming errors made by the caller). This set
-includes the four exceptions listed below as well as
-\exception{socket.error} and \exception{IOError}.
-\end{datadesc}
-
-\begin{excdesc}{error_reply}
-Exception raised when an unexpected reply is received from the server.
-\end{excdesc}
-
-\begin{excdesc}{error_temp}
-Exception raised when an error code in the range 400--499 is received.
-\end{excdesc}
-
-\begin{excdesc}{error_perm}
-Exception raised when an error code in the range 500--599 is received.
-\end{excdesc}
-
-\begin{excdesc}{error_proto}
-Exception raised when a reply is received from the server that does
-not begin with a digit in the range 1--5.
-\end{excdesc}
-
-
-\subsection{FTP Objects}
-\label{ftp-objects}
-
-\class{FTP} instances have the following methods:
-
-\begin{methoddesc}{set_debuglevel}{level}
-Set the instance's debugging level. This controls the amount of
-debugging output printed. The default, \code{0}, produces no
-debugging output. A value of \code{1} produces a moderate amount of
-debugging output, generally a single line per request. A value of
-\code{2} or higher produces the maximum amount of debugging output,
-logging each line sent and received on the control connection.
-\end{methoddesc}
-
-\begin{methoddesc}{connect}{host\optional{, port}}
-Connect to the given host and port. The default port number is \code{21}, as
-specified by the FTP protocol specification. It is rarely needed to
-specify a different port number. This function should be called only
-once for each instance; it should not be called at all if a host was
-given when the instance was created. All other methods can only be
-used after a connection has been made.
-\end{methoddesc}
-
-\begin{methoddesc}{getwelcome}{}
-Return the welcome message sent by the server in reply to the initial
-connection. (This message sometimes contains disclaimers or help
-information that may be relevant to the user.)
-\end{methoddesc}
-
-\begin{methoddesc}{login}{\optional{user\optional{, passwd\optional{, acct}}}}
-Log in as the given \var{user}. The \var{passwd} and \var{acct}
-parameters are optional and default to the empty string. If no
-\var{user} is specified, it defaults to \code{'anonymous'}. If
-\var{user} is \code{anonymous}, the default \var{passwd} is
-\samp{\var{realuser}@\var{host}} where \var{realuser} is the real user
-name (glanced from the \envvar{LOGNAME} or \envvar{USER} environment
-variable) and \var{host} is the hostname as returned by
-\function{socket.gethostname()}. This function should be called only
-once for each instance, after a connection has been established; it
-should not be called at all if a host and user were given when the
-instance was created. Most FTP commands are only allowed after the
-client has logged in.
-\end{methoddesc}
-
-\begin{methoddesc}{abort}{}
-Abort a file transfer that is in progress. Using this does not always
-work, but it's worth a try.
-\end{methoddesc}
-
-\begin{methoddesc}{sendcmd}{command}
-Send a simple command string to the server and return the response
-string.
-\end{methoddesc}
-
-\begin{methoddesc}{voidcmd}{command}
-Send a simple command string to the server and handle the response.
-Return nothing if a response code in the range 200--299 is received.
-Raise an exception otherwise.
-\end{methoddesc}
-
-\begin{methoddesc}{retrbinary}{command, callback\optional{, maxblocksize}}
-Retrieve a file in binary transfer mode. \var{command} should be an
-appropriate \samp{RETR} command, i.e.\ \code{'RETR \var{filename}'}.
-The \var{callback} function is called for each block of data received,
-with a single string argument giving the data block.
-The optional \var{maxblocksize} argument specifies the maximum chunk size to
-read on the low-level socket object created to do the actual transfer
-(which will also be the largest size of the data blocks passed to
-\var{callback}). A reasonable default is chosen.
-\end{methoddesc}
-
-\begin{methoddesc}{retrlines}{command\optional{, callback}}
-Retrieve a file or directory listing in \ASCII{} transfer mode.
-\var{command} should be an appropriate \samp{RETR} command (see
-\method{retrbinary()} or a \samp{LIST} command (usually just the string
-\code{'LIST'}). The \var{callback} function is called for each line,
-with the trailing CRLF stripped. The default \var{callback} prints
-the line to \code{sys.stdout}.
-\end{methoddesc}
-
-\begin{methoddesc}{storbinary}{command, file, blocksize}
-Store a file in binary transfer mode. \var{command} should be an
-appropriate \samp{STOR} command, i.e.\ \code{"STOR \var{filename}"}.
-\var{file} is an open file object which is read until \EOF{} using its
-\method{read()} method in blocks of size \var{blocksize} to provide the
-data to be stored.
-\end{methoddesc}
-
-\begin{methoddesc}{storlines}{command, file}
-Store a file in \ASCII{} transfer mode. \var{command} should be an
-appropriate \samp{STOR} command (see \method{storbinary()}). Lines are
-read until \EOF{} from the open file object \var{file} using its
-\method{readline()} method to privide the data to be stored.
-\end{methoddesc}
-
-\begin{methoddesc}{transfercmd}{cmd}
-Initiate a transfer over the data connection. If the transfer is
-active, send a \samp{PORT} command and the transfer command specified
-by \var{cmd}, and accept the connection. If the server is passive,
-send a \samp{PASV} command, connect to it, and start the transfer
-command. Either way, return the socket for the connection.
-\end{methoddesc}
-
-\begin{methoddesc}{ntransfercmd}{cmd}
-Like \method{transfercmd()}, but returns a tuple of the data
-connection and the expected size of the data. If the expected size
-could not be computed, \code{None} will be returned as the expected
-size.
-\end{methoddesc}
-
-\begin{methoddesc}{nlst}{argument\optional{, \ldots}}
-Return a list of files as returned by the \samp{NLST} command. The
-optional \var{argument} is a directory to list (default is the current
-server directory). Multiple arguments can be used to pass
-non-standard options to the \samp{NLST} command.
-\end{methoddesc}
-
-\begin{methoddesc}{dir}{argument\optional{, \ldots}}
-Return a directory listing as returned by the \samp{LIST} command, as
-a list of lines. The optional \var{argument} is a directory to list
-(default is the current server directory). Multiple arguments can be
-used to pass non-standard options to the \samp{LIST} command. If the
-last argument is a function, it is used as a \var{callback} function
-as for \method{retrlines()}.
-\end{methoddesc}
-
-\begin{methoddesc}{rename}{fromname, toname}
-Rename file \var{fromname} on the server to \var{toname}.
-\end{methoddesc}
-
-\begin{methoddesc}{delete}{filename}
-Remove the file named \var{filename} from the server. If successful,
-returns the text of the response, otherwise raises
-\exception{error_perm} on permission errors or \exception{error_reply}
-on other errors.
-\end{methoddesc}
-
-\begin{methoddesc}{cwd}{pathname}
-Set the current directory on the server.
-\end{methoddesc}
-
-\begin{methoddesc}{mkd}{pathname}
-Create a new directory on the server.
-\end{methoddesc}
-
-\begin{methoddesc}{pwd}{}
-Return the pathname of the current directory on the server.
-\end{methoddesc}
-
-\begin{methoddesc}{rmd}{dirname}
-Remove the directory named \var{dirname} on the server.
-\end{methoddesc}
-
-\begin{methoddesc}{size}{filename}
-Request the size of the file named \var{filename} on the server. On
-success, the size of the file is returned as an integer, otherwise
-\code{None} is returned. Note that the \samp{SIZE} command is not
-standardized, but is supported by many common server implementations.
-\end{methoddesc}
-
-\begin{methoddesc}{quit}{}
-Send a \samp{QUIT} command to the server and close the connection.
-This is the ``polite'' way to close a connection, but it may raise an
-exception of the server reponds with an error to the \samp{QUIT}
-command.
-\end{methoddesc}
-
-\begin{methoddesc}{close}{}
-Close the connection unilaterally. This should not be applied to an
-already closed connection (e.g.\ after a successful call to
-\method{quit()}.
-\end{methoddesc}
diff --git a/Doc/libfuncs.tex b/Doc/libfuncs.tex
deleted file mode 100644
index 1345734..0000000
--- a/Doc/libfuncs.tex
+++ /dev/null
@@ -1,635 +0,0 @@
-\section{Built-in Functions}
-\label{built-in-funcs}
-
-The Python interpreter has a number of functions built into it that
-are always available. They are listed here in alphabetical order.
-
-
-\setindexsubitem{(built-in function)}
-
-\begin{funcdesc}{__import__}{name\optional{, globals\optional{, locals\optional{, fromlist}}}}
-This function is invoked by the \keyword{import} statement. It
-mainly exists so that you can replace it with another
-function that has a compatible interface, in order to change the
-semantics of the \keyword{import} statement. For examples of why and
-how you would do this, see the standard library modules
-\module{ihooks} and \module{rexec}. See also the built-in module
-\module{imp}, which defines some useful operations out of which you can
-build your own \function{__import__()} function.
-\stindex{import}
-\refstmodindex{ihooks}
-\refstmodindex{rexec}
-\refbimodindex{imp}
-
-For example, the statement `\code{import} \code{spam}' results in the
-following call:
-\code{__import__('spam',} \code{globals(),} \code{locals(), [])};
-the statement \code{from} \code{spam.ham import} \code{eggs} results
-in \code{__import__('spam.ham',} \code{globals(),} \code{locals(),}
-\code{['eggs'])}.
-Note that even though \code{locals()} and \code{['eggs']} are passed
-in as arguments, the \function{__import__()} function does not set the
-local variable named \code{eggs}; this is done by subsequent code that
-is generated for the import statement. (In fact, the standard
-implementation does not use its \var{locals} argument at all, and uses
-its \var{globals} only to determine the package context of the
-\keyword{import} statement.)
-
-When the \var{name} variable is of the form \code{package.module},
-normally, the top-level package (the name up till the first dot) is
-returned, \emph{not} the module named by \var{name}. However, when a
-non-empty \var{fromlist} argument is given, the module named by
-\var{name} is returned. This is done for compatibility with the
-bytecode generated for the different kinds of import statement; when
-using \samp{import spam.ham.eggs}, the top-level package \code{spam}
-must be placed in the importing namespace, but when using \samp{from
-spam.ham import eggs}, the \code{spam.ham} subpackage must be used to
-find the \code{eggs} variable.
-\end{funcdesc}
-
-\begin{funcdesc}{abs}{x}
- Return the absolute value of a number. The argument may be a plain
- or long integer or a floating point number. If the argument is a
- complex number, its magnitude is returned.
-\end{funcdesc}
-
-\begin{funcdesc}{apply}{function, args\optional{, keywords}}
-The \var{function} argument must be a callable object (a user-defined or
-built-in function or method, or a class object) and the \var{args}
-argument must be a tuple. The \var{function} is called with
-\var{args} as argument list; the number of arguments is the the length
-of the tuple. (This is different from just calling
-\code{\var{func}(\var{args})}, since in that case there is always
-exactly one argument.)
-If the optional \var{keywords} argument is present, it must be a
-dictionary whose keys are strings. It specifies keyword arguments to
-be added to the end of the the argument list.
-\end{funcdesc}
-
-\begin{funcdesc}{callable}{object}
-Return true if the \var{object} argument appears callable, false if
-not. If this returns true, it is still possible that a call fails,
-but if it is false, calling \var{object} will never succeed. Note
-that classes are callable (calling a class returns a new instance);
-class instances are callable if they have a \method{__call__()} method.
-\end{funcdesc}
-
-\begin{funcdesc}{chr}{i}
- Return a string of one character whose \ASCII{} code is the integer
- \var{i}, e.g., \code{chr(97)} returns the string \code{'a'}. This is the
- inverse of \function{ord()}. The argument must be in the range [0..255],
- inclusive.
-\end{funcdesc}
-
-\begin{funcdesc}{cmp}{x, y}
- Compare the two objects \var{x} and \var{y} and return an integer
- according to the outcome. The return value is negative if \code{\var{x}
- < \var{y}}, zero if \code{\var{x} == \var{y}} and strictly positive if
- \code{\var{x} > \var{y}}.
-\end{funcdesc}
-
-\begin{funcdesc}{coerce}{x, y}
- Return a tuple consisting of the two numeric arguments converted to
- a common type, using the same rules as used by arithmetic
- operations.
-\end{funcdesc}
-
-\begin{funcdesc}{compile}{string, filename, kind}
- Compile the \var{string} into a code object. Code objects can be
- executed by an \keyword{exec} statement or evaluated by a call to
- \function{eval()}. The \var{filename} argument should
- give the file from which the code was read; pass e.g. \code{'<string>'}
- if it wasn't read from a file. The \var{kind} argument specifies
- what kind of code must be compiled; it can be \code{'exec'} if
- \var{string} consists of a sequence of statements, \code{'eval'}
- if it consists of a single expression, or \code{'single'} if
- it consists of a single interactive statement (in the latter case,
- expression statements that evaluate to something else than
- \code{None} will printed).
-\end{funcdesc}
-
-\begin{funcdesc}{complex}{real\optional{, imag}}
- Create a complex number with the value \var{real} + \var{imag}*j.
- Each argument may be any numeric type (including complex).
- If \var{imag} is omitted, it defaults to zero and the function
- serves as a numeric conversion function like \function{int()},
- \function{long()} and \function{float()}.
-\end{funcdesc}
-
-\begin{funcdesc}{delattr}{object, name}
- This is a relative of \function{setattr()}. The arguments are an
- object and a string. The string must be the name
- of one of the object's attributes. The function deletes
- the named attribute, provided the object allows it. For example,
- \code{delattr(\var{x}, '\var{foobar}')} is equivalent to
- \code{del \var{x}.\var{foobar}}.
-\end{funcdesc}
-
-\begin{funcdesc}{dir}{\optional{object}}
- Without arguments, return the list of names in the current local
- symbol table. With an argument, attempts to return a list of valid
- attribute for that object. This information is gleaned from the
- object's \member{__dict__}, \member{__methods__} and \member{__members__}
- attributes, if defined. The list is not necessarily complete; e.g.,
- for classes, attributes defined in base classes are not included,
- and for class instances, methods are not included.
- The resulting list is sorted alphabetically. For example:
-
-\begin{verbatim}
->>> import sys
->>> dir()
-['sys']
->>> dir(sys)
-['argv', 'exit', 'modules', 'path', 'stderr', 'stdin', 'stdout']
->>>
-\end{verbatim}
-\end{funcdesc}
-
-\begin{funcdesc}{divmod}{a, b}
- Take two numbers as arguments and return a pair of numbers consisting
- of their quotient and remainder when using long division. With mixed
- operand types, the rules for binary arithmetic operators apply. For
- plain and long integers, the result is the same as
- \code{(\var{a} / \var{b}, \var{a} \%{} \var{b})}.
- For floating point numbers the result is the same as
- \code{(math.floor(\var{a} / \var{b}), \var{a} \%{} \var{b})}.
-\end{funcdesc}
-
-\begin{funcdesc}{eval}{expression\optional{, globals\optional{, locals}}}
- The arguments are a string and two optional dictionaries. The
- \var{expression} argument is parsed and evaluated as a Python
- expression (technically speaking, a condition list) using the
- \var{globals} and \var{locals} dictionaries as global and local name
- space. If the \var{locals} dictionary is omitted it defaults to
- the \var{globals} dictionary. If both dictionaries are omitted, the
- expression is executed in the environment where \keyword{eval} is
- called. The return value is the result of the evaluated expression.
- Syntax errors are reported as exceptions. Example:
-
-\begin{verbatim}
->>> x = 1
->>> print eval('x+1')
-2
->>>
-\end{verbatim}
-
- This function can also be used to execute arbitrary code objects
- (e.g.\ created by \function{compile()}). In this case pass a code
- object instead of a string. The code object must have been compiled
- passing \code{'eval'} to the \var{kind} argument.
-
- Hints: dynamic execution of statements is supported by the
- \keyword{exec} statement. Execution of statements from a file is
- supported by the \function{execfile()} function. The
- \function{globals()} and \function{locals()} functions returns the
- current global and local dictionary, respectively, which may be
- useful to pass around for use by \function{eval()} or
- \function{execfile()}.
-\end{funcdesc}
-
-\begin{funcdesc}{execfile}{file\optional{, globals\optional{, locals}}}
- This function is similar to the
- \keyword{exec} statement, but parses a file instead of a string. It
- is different from the \keyword{import} statement in that it does not
- use the module administration --- it reads the file unconditionally
- and does not create a new module.\footnote{It is used relatively
- rarely so does not warrant being made into a statement.}
-
- The arguments are a file name and two optional dictionaries. The
- file is parsed and evaluated as a sequence of Python statements
- (similarly to a module) using the \var{globals} and \var{locals}
- dictionaries as global and local name space. If the \var{locals}
- dictionary is omitted it defaults to the \var{globals} dictionary.
- If both dictionaries are omitted, the expression is executed in the
- environment where \function{execfile()} is called. The return value is
- \code{None}.
-\end{funcdesc}
-
-\begin{funcdesc}{filter}{function, list}
-Construct a list from those elements of \var{list} for which
-\var{function} returns true. If \var{list} is a string or a tuple,
-the result also has that type; otherwise it is always a list. If
-\var{function} is \code{None}, the identity function is assumed,
-i.e.\ all elements of \var{list} that are false (zero or empty) are
-removed.
-\end{funcdesc}
-
-\begin{funcdesc}{float}{x}
- Convert a string or a number to floating point. If the argument is a
- string, it must contain a possibly singed decimal or floating point
- number, possibly embedded in whitespace;
- this behaves identical to \code{string.atof(\var{x})}.
- Otherwise, the argument may be a plain or
- long integer or a floating point number, and a floating point number
- with the same value (within Python's floating point precision) is
- returned.
-\end{funcdesc}
-
-\begin{funcdesc}{getattr}{object, name}
- The arguments are an object and a string. The string must be the
- name of one of the object's attributes. The result is the value of
- that attribute. For example, \code{getattr(\var{x},
- '\var{foobar}')} is equivalent to \code{\var{x}.\var{foobar}}.
-\end{funcdesc}
-
-\begin{funcdesc}{globals}{}
-Return a dictionary representing the current global symbol table.
-This is always the dictionary of the current module (inside a
-function or method, this is the module where it is defined, not the
-module from which it is called).
-\end{funcdesc}
-
-\begin{funcdesc}{hasattr}{object, name}
- The arguments are an object and a string. The result is 1 if the
- string is the name of one of the object's attributes, 0 if not.
- (This is implemented by calling \code{getattr(\var{object},
- \var{name})} and seeing whether it raises an exception or not.)
-\end{funcdesc}
-
-\begin{funcdesc}{hash}{object}
- Return the hash value of the object (if it has one). Hash values
- are integers. They are used to quickly compare dictionary
- keys during a dictionary lookup. Numeric values that compare equal
- have the same hash value (even if they are of different types, e.g.
- 1 and 1.0).
-\end{funcdesc}
-
-\begin{funcdesc}{hex}{x}
- Convert an integer number (of any size) to a hexadecimal string.
- The result is a valid Python expression. Note: this always yields
- an unsigned literal, e.g. on a 32-bit machine, \code{hex(-1)} yields
- \code{'0xffffffff'}. When evaluated on a machine with the same
- word size, this literal is evaluated as -1; at a different word
- size, it may turn up as a large positive number or raise an
- \exception{OverflowError} exception.
-\end{funcdesc}
-
-\begin{funcdesc}{id}{object}
- Return the `identity' of an object. This is an integer which is
- guaranteed to be unique and constant for this object during its
- lifetime. (Two objects whose lifetimes are disjunct may have the
- same \function{id()} value.) (Implementation note: this is the
- address of the object.)
-\end{funcdesc}
-
-\begin{funcdesc}{input}{\optional{prompt}}
- Almost equivalent to \code{eval(raw_input(\var{prompt}))}. Like
- \function{raw_input()}, the \var{prompt} argument is optional, and the
- \module{readline} module is used when loaded. The difference
- is that a long input expression may be broken over multiple lines using
- the backslash convention.
-\end{funcdesc}
-
-\begin{funcdesc}{intern}{string}
- Enter \var{string} in the table of ``interned'' strings and return
- the interned string -- which is \var{string} itself or a copy.
- Interning strings is useful to gain a little performance on
- dictionary lookup -- if the keys in a dictionary are interned, and
- the lookup key is interned, the key comparisons (after hashing) can
- be done by a pointer compare instead of a string compare. Normally,
- the names used in Python programs are automatically interned, and
- the dictionaries used to hold module, class or instance attributes
- have interned keys. Interned strings are immortal (i.e. never get
- garbage collected).
-\end{funcdesc}
-
-\begin{funcdesc}{int}{x}
- Convert a string or number to a plain integer. If the argument is a
- string, it must contain a possibly singed decimal number
- representable as a Python integer, possibly embedded in whitespace;
- this behaves identical to \code{string.atoi(\var{x})}.
- Otherwise, the argument may be a plain or
- long integer or a floating point number. Conversion of floating
- point numbers to integers is defined by the C semantics; normally
- the conversion truncates towards zero.\footnote{This is ugly --- the
- language definition should require truncation towards zero.}
-\end{funcdesc}
-
-\begin{funcdesc}{isinstance}{object, class}
-Return true if the \var{object} argument is an instance of the
-\var{class} argument, or of a (direct or indirect) subclass thereof.
-Also return true if \var{class} is a type object and \var{object} is
-an object of that type. If \var{object} is not a class instance or a
-object of the given type, the function always returns false. If
-\var{class} is neither a class object nor a type object, a
-\exception{TypeError} exception is raised.
-\end{funcdesc}
-
-\begin{funcdesc}{issubclass}{class1, class2}
-Return true if \var{class1} is a subclass (direct or indirect) of
-\var{class2}. A class is considered a subclass of itself. If either
-argument is not a class object, a \exception{TypeError} exception is
-raised.
-\end{funcdesc}
-
-\begin{funcdesc}{len}{s}
- Return the length (the number of items) of an object. The argument
- may be a sequence (string, tuple or list) or a mapping (dictionary).
-\end{funcdesc}
-
-\begin{funcdesc}{list}{sequence}
-Return a list whose items are the same and in the same order as
-\var{sequence}'s items. If \var{sequence} is already a list,
-a copy is made and returned, similar to \code{\var{sequence}[:]}.
-For instance, \code{list('abc')} returns
-returns \code{['a', 'b', 'c']} and \code{list( (1, 2, 3) )} returns
-\code{[1, 2, 3]}.
-\end{funcdesc}
-
-\begin{funcdesc}{locals}{}
-Return a dictionary representing the current local symbol table.
-Inside a function, modifying this dictionary does not always have the
-desired effect.
-\end{funcdesc}
-
-\begin{funcdesc}{long}{x}
- Convert a string or number to a long integer. If the argument is a
- string, it must contain a possibly singed decimal number of
- arbitrary size, possibly embedded in whitespace;
- this behaves identical to \code{string.atol(\var{x})}.
- Otherwise, the argument may be a plain or
- long integer or a floating point number, and a long integer with
- the same value is returned. Conversion of floating
- point numbers to integers is defined by the C semantics;
- see the description of \function{int()}.
-\end{funcdesc}
-
-\begin{funcdesc}{map}{function, list, ...}
-Apply \var{function} to every item of \var{list} and return a list
-of the results. If additional \var{list} arguments are passed,
-\var{function} must take that many arguments and is applied to
-the items of all lists in parallel; if a list is shorter than another
-it is assumed to be extended with \code{None} items. If
-\var{function} is \code{None}, the identity function is assumed; if
-there are multiple list arguments, \function{map()} returns a list
-consisting of tuples containing the corresponding items from all lists
-(i.e. a kind of transpose operation). The \var{list} arguments may be
-any kind of sequence; the result is always a list.
-\end{funcdesc}
-
-\begin{funcdesc}{max}{s}
- Return the largest item of a non-empty sequence (string, tuple or
- list).
-\end{funcdesc}
-
-\begin{funcdesc}{min}{s}
- Return the smallest item of a non-empty sequence (string, tuple or
- list).
-\end{funcdesc}
-
-\begin{funcdesc}{oct}{x}
- Convert an integer number (of any size) to an octal string. The
- result is a valid Python expression. Note: this always yields
- an unsigned literal, e.g. on a 32-bit machine, \code{oct(-1)} yields
- \code{'037777777777'}. When evaluated on a machine with the same
- word size, this literal is evaluated as -1; at a different word
- size, it may turn up as a large positive number or raise an
- \exception{OverflowError} exception.
-\end{funcdesc}
-
-\begin{funcdesc}{open}{filename\optional{, mode\optional{, bufsize}}}
- Return a new file object (described earlier under Built-in Types).
- The first two arguments are the same as for \code{stdio}'s
- \cfunction{fopen()}: \var{filename} is the file name to be opened,
- \var{mode} indicates how the file is to be opened: \code{'r'} for
- reading, \code{'w'} for writing (truncating an existing file), and
- \code{'a'} opens it for appending (which on \emph{some} \UNIX{}
- systems means that \emph{all} writes append to the end of the file,
- regardless of the current seek position).
- Modes \code{'r+'}, \code{'w+'} and
- \code{'a+'} open the file for updating, provided the underlying
- \code{stdio} library understands this. On systems that differentiate
- between binary and text files, \code{'b'} appended to the mode opens
- the file in binary mode. If the file cannot be opened,
- \exception{IOError} is raised.
-If \var{mode} is omitted, it defaults to \code{'r'}.
-The optional \var{bufsize} argument specifies the file's desired
-buffer size: 0 means unbuffered, 1 means line buffered, any other
-positive value means use a buffer of (approximately) that size. A
-negative \var{bufsize} means to use the system default, which is
-usually line buffered for for tty devices and fully buffered for other
-files.%
-\footnote{Specifying a buffer size currently has no effect on systems
-that don't have \cfunction{setvbuf()}. The interface to specify the buffer
-size is not done using a method that calls \cfunction{setvbuf()}, because
-that may dump core when called after any I/O has been performed, and
-there's no reliable way to determine whether this is the case.}
-\end{funcdesc}
-
-\begin{funcdesc}{ord}{c}
- Return the \ASCII{} value of a string of one character. E.g.,
- \code{ord('a')} returns the integer \code{97}. This is the inverse of
- \function{chr()}.
-\end{funcdesc}
-
-\begin{funcdesc}{pow}{x, y\optional{, z}}
- Return \var{x} to the power \var{y}; if \var{z} is present, return
- \var{x} to the power \var{y}, modulo \var{z} (computed more
- efficiently than \code{pow(\var{x}, \var{y}) \%\ \var{z}}).
- The arguments must have
- numeric types. With mixed operand types, the rules for binary
- arithmetic operators apply. The effective operand type is also the
- type of the result; if the result is not expressible in this type, the
- function raises an exception; e.g., \code{pow(2, -1)} or \code{pow(2,
- 35000)} is not allowed.
-\end{funcdesc}
-
-\begin{funcdesc}{range}{\optional{start,} stop\optional{, step}}
- This is a versatile function to create lists containing arithmetic
- progressions. It is most often used in \keyword{for} loops. The
- arguments must be plain integers. If the \var{step} argument is
- omitted, it defaults to \code{1}. If the \var{start} argument is
- omitted, it defaults to \code{0}. The full form returns a list of
- plain integers \code{[\var{start}, \var{start} + \var{step},
- \var{start} + 2 * \var{step}, \ldots]}. If \var{step} is positive,
- the last element is the largest \code{\var{start} + \var{i} *
- \var{step}} less than \var{stop}; if \var{step} is negative, the last
- element is the largest \code{\var{start} + \var{i} * \var{step}}
- greater than \var{stop}. \var{step} must not be zero (or else
- \exception{ValueError} is raised). Example:
-
-\begin{verbatim}
->>> range(10)
-[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
->>> range(1, 11)
-[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
->>> range(0, 30, 5)
-[0, 5, 10, 15, 20, 25]
->>> range(0, 10, 3)
-[0, 3, 6, 9]
->>> range(0, -10, -1)
-[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
->>> range(0)
-[]
->>> range(1, 0)
-[]
->>>
-\end{verbatim}
-\end{funcdesc}
-
-\begin{funcdesc}{raw_input}{\optional{prompt}}
- If the \var{prompt} argument is present, it is written to standard output
- without a trailing newline. The function then reads a line from input,
- converts it to a string (stripping a trailing newline), and returns that.
- When \EOF{} is read, \exception{EOFError} is raised. Example:
-
-\begin{verbatim}
->>> s = raw_input('--> ')
---> Monty Python's Flying Circus
->>> s
-"Monty Python's Flying Circus"
->>>
-\end{verbatim}
-
-If the \module{readline} module was loaded, then
-\function{raw_input()} will use it to provide elaborate
-line editing and history features.
-\end{funcdesc}
-
-\begin{funcdesc}{reduce}{function, list\optional{, initializer}}
-Apply the binary \var{function} to the items of \var{list} so as to
-reduce the list to a single value. E.g.,
-\code{reduce(lambda x, y: x*y, \var{list}, 1)} returns the product of
-the elements of \var{list}. The optional \var{initializer} can be
-thought of as being prepended to \var{list} so as to allow reduction
-of an empty \var{list}. The \var{list} arguments may be any kind of
-sequence.
-\end{funcdesc}
-
-\begin{funcdesc}{reload}{module}
-Re-parse and re-initialize an already imported \var{module}. The
-argument must be a module object, so it must have been successfully
-imported before. This is useful if you have edited the module source
-file using an external editor and want to try out the new version
-without leaving the Python interpreter. The return value is the
-module object (i.e.\ the same as the \var{module} argument).
-
-There are a number of caveats:
-
-If a module is syntactically correct but its initialization fails, the
-first \keyword{import} statement for it does not bind its name locally,
-but does store a (partially initialized) module object in
-\code{sys.modules}. To reload the module you must first
-\keyword{import} it again (this will bind the name to the partially
-initialized module object) before you can \function{reload()} it.
-
-When a module is reloaded, its dictionary (containing the module's
-global variables) is retained. Redefinitions of names will override
-the old definitions, so this is generally not a problem. If the new
-version of a module does not define a name that was defined by the old
-version, the old definition remains. This feature can be used to the
-module's advantage if it maintains a global table or cache of objects
---- with a \keyword{try} statement it can test for the table's presence
-and skip its initialization if desired.
-
-It is legal though generally not very useful to reload built-in or
-dynamically loaded modules, except for \module{sys}, \module{__main__}
-and \module{__builtin__}. In certain cases, however, extension
-modules are not designed to be initialized more than once, and may
-fail in arbitrary ways when reloaded.
-
-If a module imports objects from another module using \keyword{from}
-\ldots{} \keyword{import} \ldots{}, calling \function{reload()} for
-the other module does not redefine the objects imported from it ---
-one way around this is to re-execute the \keyword{from} statement,
-another is to use \keyword{import} and qualified names
-(\var{module}.\var{name}) instead.
-
-If a module instantiates instances of a class, reloading the module
-that defines the class does not affect the method definitions of the
-instances --- they continue to use the old class definition. The same
-is true for derived classes.
-\end{funcdesc}
-
-\begin{funcdesc}{repr}{object}
-Return a string containing a printable representation of an object.
-This is the same value yielded by conversions (reverse quotes).
-It is sometimes useful to be able to access this operation as an
-ordinary function. For many types, this function makes an attempt
-to return a string that would yield an object with the same value
-when passed to \function{eval()}.
-\end{funcdesc}
-
-\begin{funcdesc}{round}{x, n}
- Return the floating point value \var{x} rounded to \var{n} digits
- after the decimal point. If \var{n} is omitted, it defaults to zero.
- The result is a floating point number. Values are rounded to the
- closest multiple of 10 to the power minus \var{n}; if two multiples
- are equally close, rounding is done away from 0 (so e.g.
- \code{round(0.5)} is \code{1.0} and \code{round(-0.5)} is \code{-1.0}).
-\end{funcdesc}
-
-\begin{funcdesc}{setattr}{object, name, value}
- This is the counterpart of \function{getattr()}. The arguments are an
- object, a string and an arbitrary value. The string must be the name
- of one of the object's attributes. The function assigns the value to
- the attribute, provided the object allows it. For example,
- \code{setattr(\var{x}, '\var{foobar}', 123)} is equivalent to
- \code{\var{x}.\var{foobar} = 123}.
-\end{funcdesc}
-
-\begin{funcdesc}{slice}{\optional{start,} stop\optional{, step}}
-Return a slice object representing the set of indices specified by
-\code{range(\var{start}, \var{stop}, \var{step})}. The \var{start}
-and \var{step} arguments default to None. Slice objects have
-read-only data attributes \member{start}, \member{stop} and \member{step}
-which merely return the argument values (or their default). They have
-no other explicit functionality; however they are used by Numerical
-Python\index{Numerical Python} and other third party extensions.
-Slice objects are also generated when extended indexing syntax is
-used, e.g. for \samp{a[start:stop:step]} or \samp{a[start:stop, i]}.
-\end{funcdesc}
-
-\begin{funcdesc}{str}{object}
-Return a string containing a nicely printable representation of an
-object. For strings, this returns the string itself. The difference
-with \code{repr(\var{object})} is that \code{str(\var{object})} does not
-always attempt to return a string that is acceptable to \function{eval()};
-its goal is to return a printable string.
-\end{funcdesc}
-
-\begin{funcdesc}{tuple}{sequence}
-Return a tuple whose items are the same and in the same order as
-\var{sequence}'s items. If \var{sequence} is already a tuple, it
-is returned unchanged. For instance, \code{tuple('abc')} returns
-returns \code{('a', 'b', 'c')} and \code{tuple([1, 2, 3])} returns
-\code{(1, 2, 3)}.
-\end{funcdesc}
-
-\begin{funcdesc}{type}{object}
-Return the type of an \var{object}. The return value is a type
-object. The standard module \module{types} defines names for all
-built-in types.
-\refstmodindex{types}
-\obindex{type}
-For instance:
-
-\begin{verbatim}
->>> import types
->>> if isinstance(x, types.StringType): print "It's a string"
-\end{verbatim}
-\end{funcdesc}
-
-\begin{funcdesc}{vars}{\optional{object}}
-Without arguments, return a dictionary corresponding to the current
-local symbol table. With a module, class or class instance object as
-argument (or anything else that has a \member{__dict__} attribute),
-returns a dictionary corresponding to the object's symbol table.
-The returned dictionary should not be modified: the effects on the
-corresponding symbol table are undefined.%
-\footnote{In the current implementation, local variable bindings
-cannot normally be affected this way, but variables retrieved from
-other scopes (e.g. modules) can be. This may change.}
-\end{funcdesc}
-
-\begin{funcdesc}{xrange}{\optional{start,} stop\optional{, step}}
-This function is very similar to \function{range()}, but returns an
-``xrange object'' instead of a list. This is an opaque sequence type
-which yields the same values as the corresponding list, without
-actually storing them all simultaneously. The advantage of
-\function{xrange()} over \function{range()} is minimal (since
-\function{xrange()} still has to create the values when asked for
-them) except when a very large range is used on a memory-starved
-machine (e.g. MS-DOS) or when all of the range's elements are never
-used (e.g. when the loop is usually terminated with \keyword{break}).
-\end{funcdesc}
diff --git a/Doc/libgdbm.tex b/Doc/libgdbm.tex
deleted file mode 100644
index 8f2d7d1..0000000
--- a/Doc/libgdbm.tex
+++ /dev/null
@@ -1,93 +0,0 @@
-\section{Built-in Module \module{gdbm}}
-\label{module-gdbm}
-\bimodindex{gdbm}
-
-% Note that if this section appears on the same page as the first
-% paragraph of the dbm module section, makeindex will produce the
-% warning:
-%
-% ## Warning (input = lib.idx, line = 1184; output = lib.ind, line = 852):
-% -- Conflicting entries: multiple encaps for the same page under same key.
-%
-% This is because the \bimodindex{gdbm} and \refbimodindex{gdbm}
-% entries in the .idx file are slightly different (the \bimodindex{}
-% version includes "|textbf" at the end to make the defining occurance
-% bold). There doesn't appear to be anything that can be done about
-% this; it's just a little annoying. The warning can be ignored, but
-% the index produced uses the non-bold version.
-
-This module is quite similar to the \code{dbm} module, but uses \code{gdbm}
-instead to provide some additional functionality. Please note that
-the file formats created by \code{gdbm} and \code{dbm} are incompatible.
-\refbimodindex{dbm}
-
-The \code{gdbm} module provides an interface to the GNU DBM
-library. \code{gdbm} objects behave like mappings
-(dictionaries), except that keys and values are always strings.
-Printing a \code{gdbm} object doesn't print the keys and values, and the
-\code{items()} and \code{values()} methods are not supported.
-
-The module defines the following constant and functions:
-
-\begin{excdesc}{error}
-Raised on \code{gdbm}-specific errors, such as I/O errors. \code{KeyError} is
-raised for general mapping errors like specifying an incorrect key.
-\end{excdesc}
-
-\begin{funcdesc}{open}{filename, \optional{flag, \optional{mode}}}
-Open a \code{gdbm} database and return a \code{gdbm} object. The
-\var{filename} argument is the name of the database file.
-
-The optional \var{flag} argument can be
-\code{'r'} (to open an existing database for reading only --- default),
-\code{'w'} (to open an existing database for reading and writing),
-\code{'c'} (which creates the database if it doesn't exist), or
-\code{'n'} (which always creates a new empty database).
-
-Appending \code{f} to the flag opens the database in fast mode;
-altered data will not automatically be written to the disk after every
-change. This results in faster writes to the database, but may result
-in an inconsistent database if the program crashes while the database
-is still open. Use the \code{sync()} method to force any unwritten
-data to be written to the disk.
-
-The optional \var{mode} argument is the \UNIX{} mode of the file, used
-only when the database has to be created. It defaults to octal
-\code{0666}.
-\end{funcdesc}
-
-In addition to the dictionary-like methods, \code{gdbm} objects have the
-following methods:
-
-\begin{funcdesc}{firstkey}{}
-It's possible to loop over every key in the database using this method
-and the \code{nextkey()} method. The traversal is ordered by \code{gdbm}'s
-internal hash values, and won't be sorted by the key values. This
-method returns the starting key.
-\end{funcdesc}
-
-\begin{funcdesc}{nextkey}{key}
-Returns the key that follows \var{key} in the traversal. The
-following code prints every key in the database \code{db}, without having to
-create a list in memory that contains them all:
-\begin{verbatim}
-k=db.firstkey()
-while k!=None:
- print k
- k=db.nextkey(k)
-\end{verbatim}
-\end{funcdesc}
-
-\begin{funcdesc}{reorganize}{}
-If you have carried out a lot of deletions and would like to shrink
-the space used by the \code{gdbm} file, this routine will reorganize the
-database. \code{gdbm} will not shorten the length of a database file except
-by using this reorganization; otherwise, deleted file space will be
-kept and reused as new (key,value) pairs are added.
-\end{funcdesc}
-
-\begin{funcdesc}{sync}{}
-When the database has been opened in fast mode, this method forces any
-unwritten data to be written to the disk.
-\end{funcdesc}
-
diff --git a/Doc/libgetopt.tex b/Doc/libgetopt.tex
deleted file mode 100644
index be00fef..0000000
--- a/Doc/libgetopt.tex
+++ /dev/null
@@ -1,80 +0,0 @@
-\section{Standard Module \module{getopt}}
-\label{module-getopt}
-\stmodindex{getopt}
-
-This module helps scripts to parse the command line arguments in
-\code{sys.argv}.
-It supports the same conventions as the \UNIX{} \cfunction{getopt()}
-function (including the special meanings of arguments of the form
-`\code{-}' and `\code{-}\code{-}').
-% That's to fool latex2html into leaving the two hyphens alone!
-Long options similar to those supported by
-GNU software may be used as well via an optional third argument.
-This module provides a single function and an exception:
-
-\begin{funcdesc}{getopt}{args, options\optional{, long_options}}
-Parses command line options and parameter list. \var{args} is the
-argument list to be parsed, without the leading reference to the
-running program. Typically, this means \samp{sys.argv[1:]}.
-\var{options} is the string of option letters that the script wants to
-recognize, with options that require an argument followed by a colon
-(i.e., the same format that \UNIX{} \cfunction{getopt()} uses). If
-specified, \var{long_options} is a list of strings with the names of
-the long options which should be supported. The leading
-\code{'-}\code{-'} characters should not be included in the option
-name. Options which require an argument should be followed by an
-equal sign (\code{'='}).
-
-The return value consists of two elements: the first is a list of
-\code{(\var{option}, \var{value})} pairs; the second is the list of
-program arguments left after the option list was stripped (this is a
-trailing slice of the first argument).
-Each option-and-value pair returned has the option as its first
-element, prefixed with a hyphen (e.g., \code{'-x'}), and the option
-argument as its second element, or an empty string if the option has
-no argument.
-The options occur in the list in the same order in which they were
-found, thus allowing multiple occurrences. Long and short options may
-be mixed.
-\end{funcdesc}
-
-\begin{excdesc}{error}
-This is raised when an unrecognized option is found in the argument
-list or when an option requiring an argument is given none.
-The argument to the exception is a string indicating the cause of the
-error. For long options, an argument given to an option which does
-not require one will also cause this exception to be raised.
-\end{excdesc}
-
-
-An example using only \UNIX{} style options:
-
-\begin{verbatim}
->>> import getopt, string
->>> args = string.split('-a -b -cfoo -d bar a1 a2')
->>> args
-['-a', '-b', '-cfoo', '-d', 'bar', 'a1', 'a2']
->>> optlist, args = getopt.getopt(args, 'abc:d:')
->>> optlist
-[('-a', ''), ('-b', ''), ('-c', 'foo'), ('-d', 'bar')]
->>> args
-['a1', 'a2']
->>>
-\end{verbatim}
-
-Using long option names is equally easy:
-
-\begin{verbatim}
->>> s = '--condition=foo --testing --output-file abc.def -x a1 a2'
->>> args = string.split(s)
->>> args
-['--condition=foo', '--testing', '--output-file', 'abc.def', '-x', 'a1', 'a2']
->>> optlist, args = getopt.getopt(args, 'x', [
-... 'condition=', 'output-file=', 'testing'])
->>> optlist
-[('--condition', 'foo'), ('--testing', ''), ('--output-file', 'abc.def'), ('-x',
- '')]
->>> args
-['a1', 'a2']
->>>
-\end{verbatim}
diff --git a/Doc/libgl.tex b/Doc/libgl.tex
deleted file mode 100644
index abbaf10..0000000
--- a/Doc/libgl.tex
+++ /dev/null
@@ -1,197 +0,0 @@
-\section{Built-in Module \module{gl}}
-\label{module-gl}
-\bimodindex{gl}
-
-This module provides access to the Silicon Graphics
-\emph{Graphics Library}.
-It is available only on Silicon Graphics machines.
-
-\strong{Warning:}
-Some illegal calls to the GL library cause the Python interpreter to dump
-core.
-In particular, the use of most GL calls is unsafe before the first
-window is opened.
-
-The module is too large to document here in its entirety, but the
-following should help you to get started.
-The parameter conventions for the C functions are translated to Python as
-follows:
-
-\begin{itemize}
-\item
-All (short, long, unsigned) int values are represented by Python
-integers.
-\item
-All float and double values are represented by Python floating point
-numbers.
-In most cases, Python integers are also allowed.
-\item
-All arrays are represented by one-dimensional Python lists.
-In most cases, tuples are also allowed.
-\item
-\begin{sloppypar}
-All string and character arguments are represented by Python strings,
-for instance,
-\code{winopen('Hi There!')}
-and
-\code{rotate(900, 'z')}.
-\end{sloppypar}
-\item
-All (short, long, unsigned) integer arguments or return values that are
-only used to specify the length of an array argument are omitted.
-For example, the C call
-
-\begin{verbatim}
-lmdef(deftype, index, np, props)
-\end{verbatim}
-%
-is translated to Python as
-
-\begin{verbatim}
-lmdef(deftype, index, props)
-\end{verbatim}
-%
-\item
-Output arguments are omitted from the argument list; they are
-transmitted as function return values instead.
-If more than one value must be returned, the return value is a tuple.
-If the C function has both a regular return value (that is not omitted
-because of the previous rule) and an output argument, the return value
-comes first in the tuple.
-Examples: the C call
-
-\begin{verbatim}
-getmcolor(i, &red, &green, &blue)
-\end{verbatim}
-%
-is translated to Python as
-
-\begin{verbatim}
-red, green, blue = getmcolor(i)
-\end{verbatim}
-%
-\end{itemize}
-
-The following functions are non-standard or have special argument
-conventions:
-
-\begin{funcdesc}{varray}{argument}
-%JHXXX the argument-argument added
-Equivalent to but faster than a number of
-\code{v3d()}
-calls.
-The \var{argument} is a list (or tuple) of points.
-Each point must be a tuple of coordinates
-\code{(\var{x}, \var{y}, \var{z})} or \code{(\var{x}, \var{y})}.
-The points may be 2- or 3-dimensional but must all have the
-same dimension.
-Float and int values may be mixed however.
-The points are always converted to 3D double precision points
-by assuming \code{\var{z} = 0.0} if necessary (as indicated in the man page),
-and for each point
-\code{v3d()}
-is called.
-\end{funcdesc}
-
-\begin{funcdesc}{nvarray}{}
-Equivalent to but faster than a number of
-\code{n3f}
-and
-\code{v3f}
-calls.
-The argument is an array (list or tuple) of pairs of normals and points.
-Each pair is a tuple of a point and a normal for that point.
-Each point or normal must be a tuple of coordinates
-\code{(\var{x}, \var{y}, \var{z})}.
-Three coordinates must be given.
-Float and int values may be mixed.
-For each pair,
-\code{n3f()}
-is called for the normal, and then
-\code{v3f()}
-is called for the point.
-\end{funcdesc}
-
-\begin{funcdesc}{vnarray}{}
-Similar to
-\code{nvarray()}
-but the pairs have the point first and the normal second.
-\end{funcdesc}
-
-\begin{funcdesc}{nurbssurface}{s_k, t_k, ctl, s_ord, t_ord, type}
-% XXX s_k[], t_k[], ctl[][]
-Defines a nurbs surface.
-The dimensions of
-\code{\var{ctl}[][]}
-are computed as follows:
-\code{[len(\var{s_k}) - \var{s_ord}]},
-\code{[len(\var{t_k}) - \var{t_ord}]}.
-\end{funcdesc}
-
-\begin{funcdesc}{nurbscurve}{knots, ctlpoints, order, type}
-Defines a nurbs curve.
-The length of ctlpoints is
-\code{len(\var{knots}) - \var{order}}.
-\end{funcdesc}
-
-\begin{funcdesc}{pwlcurve}{points, type}
-Defines a piecewise-linear curve.
-\var{points}
-is a list of points.
-\var{type}
-must be
-\code{N_ST}.
-\end{funcdesc}
-
-\begin{funcdesc}{pick}{n}
-\funcline{select}{n}
-The only argument to these functions specifies the desired size of the
-pick or select buffer.
-\end{funcdesc}
-
-\begin{funcdesc}{endpick}{}
-\funcline{endselect}{}
-These functions have no arguments.
-They return a list of integers representing the used part of the
-pick/select buffer.
-No method is provided to detect buffer overrun.
-\end{funcdesc}
-
-Here is a tiny but complete example GL program in Python:
-
-\begin{verbatim}
-import gl, GL, time
-
-def main():
- gl.foreground()
- gl.prefposition(500, 900, 500, 900)
- w = gl.winopen('CrissCross')
- gl.ortho2(0.0, 400.0, 0.0, 400.0)
- gl.color(GL.WHITE)
- gl.clear()
- gl.color(GL.RED)
- gl.bgnline()
- gl.v2f(0.0, 0.0)
- gl.v2f(400.0, 400.0)
- gl.endline()
- gl.bgnline()
- gl.v2f(400.0, 0.0)
- gl.v2f(0.0, 400.0)
- gl.endline()
- time.sleep(5)
-
-main()
-\end{verbatim}
-%
-\section{Standard Modules \module{GL} and \module{DEVICE}}
-\nodename{GL and DEVICE}
-\stmodindex{GL}
-\stmodindex{DEVICE}
-
-These modules define the constants used by the Silicon Graphics
-\emph{Graphics Library}
-that C programmers find in the header files
-\file{<gl/gl.h>}
-and
-\file{<gl/device.h>}.
-Read the module source files for details.
diff --git a/Doc/libglob.tex b/Doc/libglob.tex
deleted file mode 100644
index 10f667a..0000000
--- a/Doc/libglob.tex
+++ /dev/null
@@ -1,35 +0,0 @@
-\section{Standard Module \module{glob}}
-\label{module-glob}
-\stmodindex{glob}
-
-The \module{glob} module finds all the pathnames matching a specified
-pattern according to the rules used by the \UNIX{} shell. No tilde
-expansion is done, but \code{*}, \code{?}, and character ranges
-expressed with \code{[]} will be correctly matched. This is done by
-using the \function{os.listdir()} and \function{fnmatch.fnmatch()}
-functions in concert, and not by actually invoking a subshell. (For
-tilde and shell variable expansion, use \function{os.path.expanduser()}
-and \function{os.path.expandvars()}.)
-
-\begin{funcdesc}{glob}{pathname}
-Returns a possibly-empty list of path names that match \var{pathname},
-which must be a string containing a path specification.
-\var{pathname} can be either absolute (like
-\file{/usr/src/Python-1.5/Makefile}) or relative (like
-\file{../../Tools/*.gif}), and can contain shell-style wildcards.
-\end{funcdesc}
-
-For example, consider a directory containing only the following files:
-\file{1.gif}, \file{2.txt}, and \file{card.gif}. \function{glob()}
-will produce the following results. Notice how any leading components
-of the path are preserved.
-
-\begin{verbatim}
->>> import glob
->>> glob.glob('./[0-9].*')
-['./1.gif', './2.txt']
->>> glob.glob('*.gif')
-['1.gif', 'card.gif']
->>> glob.glob('?.gif')
-['1.gif']
-\end{verbatim}
diff --git a/Doc/libgopherlib.tex b/Doc/libgopherlib.tex
deleted file mode 100644
index 156d6d7..0000000
--- a/Doc/libgopherlib.tex
+++ /dev/null
@@ -1,31 +0,0 @@
-\section{Standard Module \module{gopherlib}}
-\label{module-gopherlib}
-\stmodindex{gopherlib}
-\indexii{Gopher}{protocol}
-
-
-This module provides a minimal implementation of client side of the
-the Gopher protocol. It is used by the module \code{urllib} to handle
-URLs that use the Gopher protocol.
-
-The module defines the following functions:
-
-\begin{funcdesc}{send_selector}{selector, host\optional{, port}}
-Send a \var{selector} string to the gopher server at \var{host} and
-\var{port} (default \code{70}). Returns an open file object from
-which the returned document can be read.
-\end{funcdesc}
-
-\begin{funcdesc}{send_query}{selector, query, host\optional{, port}}
-Send a \var{selector} string and a \var{query} string to a gopher
-server at \var{host} and \var{port} (default \code{70}). Returns an
-open file object from which the returned document can be read.
-\end{funcdesc}
-
-Note that the data returned by the Gopher server can be of any type,
-depending on the first character of the selector string. If the data
-is text (first character of the selector is \samp{0}), lines are
-terminated by CRLF, and the data is terminated by a line consisting of
-a single \samp{.}, and a leading \samp{.} should be stripped from
-lines that begin with \samp{..}. Directory listings (first character
-of the selector is \samp{1}) are transferred using the same protocol.
diff --git a/Doc/libgrp.tex b/Doc/libgrp.tex
deleted file mode 100644
index 551171b..0000000
--- a/Doc/libgrp.tex
+++ /dev/null
@@ -1,32 +0,0 @@
-\section{Built-in Module \module{grp}}
-\label{module-grp}
-
-\bimodindex{grp}
-This module provides access to the \UNIX{} group database.
-It is available on all \UNIX{} versions.
-
-Group database entries are reported as 4-tuples containing the
-following items from the group database (see \file{<grp.h>}), in order:
-\code{gr_name},
-\code{gr_passwd},
-\code{gr_gid},
-\code{gr_mem}.
-The gid is an integer, name and password are strings, and the member
-list is a list of strings.
-(Note that most users are not explicitly listed as members of the
-group they are in according to the password database.)
-A \code{KeyError} exception is raised if the entry asked for cannot be found.
-
-It defines the following items:
-
-\begin{funcdesc}{getgrgid}{gid}
-Return the group database entry for the given numeric group ID.
-\end{funcdesc}
-
-\begin{funcdesc}{getgrnam}{name}
-Return the group database entry for the given group name.
-\end{funcdesc}
-
-\begin{funcdesc}{getgrall}{}
-Return a list of all available group entries, in arbitrary order.
-\end{funcdesc}
diff --git a/Doc/libgzip.tex b/Doc/libgzip.tex
deleted file mode 100644
index fd2bc28..0000000
--- a/Doc/libgzip.tex
+++ /dev/null
@@ -1,47 +0,0 @@
-\section{Standard Module \module{gzip}}
-\label{module-gzip}
-\stmodindex{gzip}
-
-The data compression provided by the \code{zlib} module is compatible
-with that used by the GNU compression program \program{gzip}.
-Accordingly, the \module{gzip} module provides the \class{GzipFile}
-class to read and write \program{gzip}-format files, automatically
-compressing or decompressing the data so it looks like an ordinary
-file object.
-
-\class{GzipFile} objects simulate most of the methods of a file
-object, though it's not possible to use the \method{seek()} and
-\method{tell()} methods to access the file randomly.
-\withsubitem{(class in gzip)}{\ttindex{GzipFile}}
-
-
-\begin{funcdesc}{open}{fileobj\optional{, filename\optional{,
- mode\optional{, compresslevel}}}}
- Returns a new \class{GzipFile} object on top of \var{fileobj}, which
- can be a regular file, a \class{StringIO} object, or any object which
- simulates a file.
-
- The \program{gzip} file format includes the original filename of the
- uncompressed file; when opening a \class{GzipFile} object for
- writing, it can be set by the \var{filename} argument. The default
- value is an empty string.
-
- \var{mode} can be either \code{'r'} or \code{'w'} depending on
- whether the file will be read or written. \var{compresslevel} is an
- integer from \code{1} to \code{9} controlling the level of
- compression; \code{1} is fastest and produces the least compression,
- and \code{9} is slowest and produces the most compression. The
- default value of \var{compresslevel} is \code{9}.
-
- Calling a \class{GzipFile} object's \method{close()} method does not
- close \var{fileobj}, since you might wish to append more material
- after the compressed data. This also allows you to pass a
- \class{StringIO} object opened for writing as \var{fileobj}, and
- retrieve the resulting memory buffer using the \class{StringIO}
- object's \method{getvalue()} method.
-\end{funcdesc}
-
-\begin{seealso}
-\seemodule{zlib}{the basic data compression module}
-\end{seealso}
-
diff --git a/Doc/libhtmllib.tex b/Doc/libhtmllib.tex
deleted file mode 100644