4 * Contains support for ensembles (see TIP#112), which provide simple
5 * mechanism for creating composite commands on top of namespaces.
7 * Copyright (c) 2005-2013 Donal K. Fellows.
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 #include "tclCompile.h"
17 * Declarations for functions local to this file:
20 static inline Tcl_Obj * NewNsObj(Tcl_Namespace *namespacePtr);
21 static inline int EnsembleUnknownCallback(Tcl_Interp *interp,
22 EnsembleConfig *ensemblePtr, int objc,
23 Tcl_Obj *const objv[], Tcl_Obj **prefixObjPtr);
24 static int NsEnsembleImplementationCmd(ClientData clientData,
25 Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
26 static int NsEnsembleImplementationCmdNR(ClientData clientData,
27 Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
28 static void BuildEnsembleConfig(EnsembleConfig *ensemblePtr);
29 static int NsEnsembleStringOrder(const void *strPtr1,
31 static void DeleteEnsembleConfig(ClientData clientData);
32 static void MakeCachedEnsembleCommand(Tcl_Obj *objPtr,
33 EnsembleConfig *ensemblePtr, Tcl_HashEntry *hPtr,
35 static void FreeEnsembleCmdRep(Tcl_Obj *objPtr);
36 static void DupEnsembleCmdRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr);
37 static void CompileToInvokedCommand(Tcl_Interp *interp,
38 Tcl_Parse *parsePtr, Tcl_Obj *replacements,
39 Command *cmdPtr, CompileEnv *envPtr);
40 static int CompileBasicNArgCommand(Tcl_Interp *interp,
41 Tcl_Parse *parsePtr, Command *cmdPtr,
44 static Tcl_NRPostProc FreeER;
47 * The lists of subcommands and options for the [namespace ensemble] command.
50 static const char *const ensembleSubcommands[] = {
51 "configure", "create", "exists", NULL
54 ENS_CONFIG, ENS_CREATE, ENS_EXISTS
57 static const char *const ensembleCreateOptions[] = {
58 "-command", "-map", "-parameters", "-prefixes", "-subcommands",
62 CRT_CMD, CRT_MAP, CRT_PARAM, CRT_PREFIX, CRT_SUBCMDS, CRT_UNKNOWN
65 static const char *const ensembleConfigOptions[] = {
66 "-map", "-namespace", "-parameters", "-prefixes", "-subcommands",
70 CONF_MAP, CONF_NAMESPACE, CONF_PARAM, CONF_PREFIX, CONF_SUBCMDS,
75 * This structure defines a Tcl object type that contains a reference to an
76 * ensemble subcommand (e.g. the "length" in [string length ab]). It is used
77 * to cache the mapping between the subcommand itself and the real command
81 static const Tcl_ObjType ensembleCmdType = {
82 "ensembleCommand", /* the type's name */
83 FreeEnsembleCmdRep, /* freeIntRepProc */
84 DupEnsembleCmdRep, /* dupIntRepProc */
85 NULL, /* updateStringProc */
86 NULL /* setFromAnyProc */
90 * The internal rep for caching ensemble subcommand lookups and
95 int epoch; /* Used to confirm when the data in this
96 * really structure matches up with the
98 Command *token; /* Reference to the command for which this
99 * structure is a cache of the resolution. */
100 Tcl_Obj *fix; /* Corrected spelling, if needed. */
101 Tcl_HashEntry *hPtr; /* Direct link to entry in the subcommand
106 static inline Tcl_Obj *
108 Tcl_Namespace *namespacePtr)
110 Namespace *nsPtr = (Namespace *) namespacePtr;
112 if (namespacePtr == TclGetGlobalNamespace(nsPtr->interp)) {
113 return Tcl_NewStringObj("::", 2);
115 return Tcl_NewStringObj(nsPtr->fullName, -1);
120 *----------------------------------------------------------------------
122 * TclNamespaceEnsembleCmd --
124 * Invoked to implement the "namespace ensemble" command that creates and
125 * manipulates ensembles built on top of namespaces. Handles the
128 * namespace ensemble name ?dictionary?
131 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong.
134 * Creates the ensemble for the namespace if one did not previously
135 * exist. Alternatively, alters the way that the ensemble's subcommand =>
136 * implementation prefix is configured.
138 *----------------------------------------------------------------------
142 TclNamespaceEnsembleCmd(
146 Tcl_Obj *const objv[])
148 Tcl_Namespace *namespacePtr;
149 Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp), *cxtPtr,
150 *foundNsPtr, *altFoundNsPtr, *actualCxtPtr;
152 Tcl_DictSearch search;
154 const char *simpleName;
157 if (nsPtr == NULL || nsPtr->flags & NS_DYING) {
158 if (!Tcl_InterpDeleted(interp)) {
159 Tcl_SetObjResult(interp, Tcl_NewStringObj(
160 "tried to manipulate ensemble of deleted namespace",
162 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "DEAD", NULL);
168 Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?arg ...?");
171 if (Tcl_GetIndexFromObj(interp, objv[1], ensembleSubcommands,
172 "subcommand", 0, &index) != TCL_OK) {
176 switch ((enum EnsSubcmds) index) {
179 int len, allocatedMapFlag = 0;
183 Tcl_Obj *subcmdObj = NULL;
184 Tcl_Obj *mapObj = NULL;
185 int permitPrefix = 1;
186 Tcl_Obj *unknownObj = NULL;
187 Tcl_Obj *paramObj = NULL;
190 * Check that we've got option-value pairs... [Bug 1558654]
194 Tcl_WrongNumArgs(interp, 2, objv, "?option value ...?");
201 cxtPtr = (Namespace *) nsPtr->parentPtr;
204 * Parse the option list, applying type checks as we go. Note that we
205 * are not incrementing any reference counts in the objects at this
206 * stage, so the presence of an option multiple times won't cause any
210 for (; objc>1 ; objc-=2,objv+=2) {
211 if (Tcl_GetIndexFromObj(interp, objv[0], ensembleCreateOptions,
212 "option", 0, &index) != TCL_OK) {
213 if (allocatedMapFlag) {
214 Tcl_DecrRefCount(mapObj);
218 switch ((enum EnsCreateOpts) index) {
220 name = TclGetString(objv[1]);
224 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
225 if (allocatedMapFlag) {
226 Tcl_DecrRefCount(mapObj);
230 subcmdObj = (len > 0 ? objv[1] : NULL);
233 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
234 if (allocatedMapFlag) {
235 Tcl_DecrRefCount(mapObj);
239 paramObj = (len > 0 ? objv[1] : NULL);
242 Tcl_Obj *patchedDict = NULL, *subcmdWordsObj;
245 * Verify that the map is sensible.
248 if (Tcl_DictObjFirst(interp, objv[1], &search,
249 &subcmdWordsObj, &listObj, &done) != TCL_OK) {
250 if (allocatedMapFlag) {
251 Tcl_DecrRefCount(mapObj);
263 if (TclListObjGetElements(interp, listObj, &len,
265 Tcl_DictObjDone(&search);
267 Tcl_DecrRefCount(patchedDict);
269 if (allocatedMapFlag) {
270 Tcl_DecrRefCount(mapObj);
275 Tcl_SetObjResult(interp, Tcl_NewStringObj(
276 "ensemble subcommand implementations "
277 "must be non-empty lists", -1));
278 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE",
279 "EMPTY_TARGET", NULL);
280 Tcl_DictObjDone(&search);
282 Tcl_DecrRefCount(patchedDict);
284 if (allocatedMapFlag) {
285 Tcl_DecrRefCount(mapObj);
289 cmd = TclGetString(listv[0]);
290 if (!(cmd[0] == ':' && cmd[1] == ':')) {
291 Tcl_Obj *newList = Tcl_NewListObj(len, listv);
292 Tcl_Obj *newCmd = NewNsObj((Tcl_Namespace *) nsPtr);
294 if (nsPtr->parentPtr) {
295 Tcl_AppendStringsToObj(newCmd, "::", NULL);
297 Tcl_AppendObjToObj(newCmd, listv[0]);
298 Tcl_ListObjReplace(NULL, newList, 0, 1, 1, &newCmd);
299 if (patchedDict == NULL) {
300 patchedDict = Tcl_DuplicateObj(objv[1]);
302 Tcl_DictObjPut(NULL, patchedDict, subcmdWordsObj,
305 Tcl_DictObjNext(&search, &subcmdWordsObj,&listObj, &done);
308 if (allocatedMapFlag) {
309 Tcl_DecrRefCount(mapObj);
311 mapObj = (patchedDict ? patchedDict : objv[1]);
313 allocatedMapFlag = 1;
318 if (Tcl_GetBooleanFromObj(interp, objv[1],
319 &permitPrefix) != TCL_OK) {
320 if (allocatedMapFlag) {
321 Tcl_DecrRefCount(mapObj);
327 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
328 if (allocatedMapFlag) {
329 Tcl_DecrRefCount(mapObj);
333 unknownObj = (len > 0 ? objv[1] : NULL);
338 TclGetNamespaceForQualName(interp, name, cxtPtr,
339 TCL_CREATE_NS_IF_UNKNOWN, &foundNsPtr, &altFoundNsPtr, &actualCxtPtr,
343 * Create the ensemble. Note that this might delete another ensemble
344 * linked to the same namespace, so we must be careful. However, we
345 * should be OK because we only link the namespace into the list once
346 * we've created it (and after any deletions have occurred.)
349 token = TclCreateEnsembleInNs(interp, simpleName,
350 (Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr,
351 (permitPrefix ? TCL_ENSEMBLE_PREFIX : 0));
352 Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj);
353 Tcl_SetEnsembleMappingDict(interp, token, mapObj);
354 Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj);
355 Tcl_SetEnsembleParameterList(interp, token, paramObj);
358 * Tricky! Must ensure that the result is not shared (command delete
359 * traces could have corrupted the pristine object that we started
360 * with). [Snit test rename-1.5]
363 Tcl_ResetResult(interp);
364 Tcl_GetCommandFullName(interp, token, Tcl_GetObjResult(interp));
370 Tcl_WrongNumArgs(interp, 2, objv, "cmdname");
373 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
374 Tcl_FindEnsemble(interp, objv[2], 0) != NULL));
378 if (objc < 3 || (objc != 4 && !(objc & 1))) {
379 Tcl_WrongNumArgs(interp, 2, objv,
380 "cmdname ?-option value ...? ?arg ...?");
383 token = Tcl_FindEnsemble(interp, objv[2], TCL_LEAVE_ERR_MSG);
389 Tcl_Obj *resultObj = NULL; /* silence gcc 4 warning */
391 if (Tcl_GetIndexFromObj(interp, objv[3], ensembleConfigOptions,
392 "option", 0, &index) != TCL_OK) {
395 switch ((enum EnsConfigOpts) index) {
397 Tcl_GetEnsembleSubcommandList(NULL, token, &resultObj);
398 if (resultObj != NULL) {
399 Tcl_SetObjResult(interp, resultObj);
403 Tcl_GetEnsembleParameterList(NULL, token, &resultObj);
404 if (resultObj != NULL) {
405 Tcl_SetObjResult(interp, resultObj);
409 Tcl_GetEnsembleMappingDict(NULL, token, &resultObj);
410 if (resultObj != NULL) {
411 Tcl_SetObjResult(interp, resultObj);
415 namespacePtr = NULL; /* silence gcc 4 warning */
416 Tcl_GetEnsembleNamespace(NULL, token, &namespacePtr);
417 Tcl_SetObjResult(interp, NewNsObj(namespacePtr));
420 int flags = 0; /* silence gcc 4 warning */
422 Tcl_GetEnsembleFlags(NULL, token, &flags);
423 Tcl_SetObjResult(interp,
424 Tcl_NewBooleanObj(flags & TCL_ENSEMBLE_PREFIX));
428 Tcl_GetEnsembleUnknownHandler(NULL, token, &resultObj);
429 if (resultObj != NULL) {
430 Tcl_SetObjResult(interp, resultObj);
434 } else if (objc == 3) {
436 * Produce list of all information.
439 Tcl_Obj *resultObj, *tmpObj = NULL; /* silence gcc 4 warning */
440 int flags = 0; /* silence gcc 4 warning */
442 TclNewObj(resultObj);
445 Tcl_ListObjAppendElement(NULL, resultObj,
446 Tcl_NewStringObj(ensembleConfigOptions[CONF_MAP], -1));
447 Tcl_GetEnsembleMappingDict(NULL, token, &tmpObj);
448 Tcl_ListObjAppendElement(NULL, resultObj,
449 (tmpObj != NULL) ? tmpObj : Tcl_NewObj());
451 /* -namespace option */
452 Tcl_ListObjAppendElement(NULL, resultObj,
453 Tcl_NewStringObj(ensembleConfigOptions[CONF_NAMESPACE],
455 namespacePtr = NULL; /* silence gcc 4 warning */
456 Tcl_GetEnsembleNamespace(NULL, token, &namespacePtr);
457 Tcl_ListObjAppendElement(NULL, resultObj, NewNsObj(namespacePtr));
459 /* -parameters option */
460 Tcl_ListObjAppendElement(NULL, resultObj,
461 Tcl_NewStringObj(ensembleConfigOptions[CONF_PARAM], -1));
462 Tcl_GetEnsembleParameterList(NULL, token, &tmpObj);
463 Tcl_ListObjAppendElement(NULL, resultObj,
464 (tmpObj != NULL) ? tmpObj : Tcl_NewObj());
467 Tcl_ListObjAppendElement(NULL, resultObj,
468 Tcl_NewStringObj(ensembleConfigOptions[CONF_PREFIX], -1));
469 Tcl_GetEnsembleFlags(NULL, token, &flags);
470 Tcl_ListObjAppendElement(NULL, resultObj,
471 Tcl_NewBooleanObj(flags & TCL_ENSEMBLE_PREFIX));
473 /* -subcommands option */
474 Tcl_ListObjAppendElement(NULL, resultObj,
475 Tcl_NewStringObj(ensembleConfigOptions[CONF_SUBCMDS],-1));
476 Tcl_GetEnsembleSubcommandList(NULL, token, &tmpObj);
477 Tcl_ListObjAppendElement(NULL, resultObj,
478 (tmpObj != NULL) ? tmpObj : Tcl_NewObj());
480 /* -unknown option */
481 Tcl_ListObjAppendElement(NULL, resultObj,
482 Tcl_NewStringObj(ensembleConfigOptions[CONF_UNKNOWN],-1));
483 Tcl_GetEnsembleUnknownHandler(NULL, token, &tmpObj);
484 Tcl_ListObjAppendElement(NULL, resultObj,
485 (tmpObj != NULL) ? tmpObj : Tcl_NewObj());
487 Tcl_SetObjResult(interp, resultObj);
489 int len, allocatedMapFlag = 0;
490 Tcl_Obj *subcmdObj = NULL, *mapObj = NULL, *paramObj = NULL,
491 *unknownObj = NULL; /* Defaults, silence gcc 4 warnings */
492 int permitPrefix, flags = 0; /* silence gcc 4 warning */
494 Tcl_GetEnsembleSubcommandList(NULL, token, &subcmdObj);
495 Tcl_GetEnsembleMappingDict(NULL, token, &mapObj);
496 Tcl_GetEnsembleParameterList(NULL, token, ¶mObj);
497 Tcl_GetEnsembleUnknownHandler(NULL, token, &unknownObj);
498 Tcl_GetEnsembleFlags(NULL, token, &flags);
499 permitPrefix = (flags & TCL_ENSEMBLE_PREFIX) != 0;
505 * Parse the option list, applying type checks as we go. Note that
506 * we are not incrementing any reference counts in the objects at
507 * this stage, so the presence of an option multiple times won't
508 * cause any memory leaks.
511 for (; objc>0 ; objc-=2,objv+=2) {
512 if (Tcl_GetIndexFromObj(interp, objv[0],ensembleConfigOptions,
513 "option", 0, &index) != TCL_OK) {
515 if (allocatedMapFlag) {
516 Tcl_DecrRefCount(mapObj);
520 switch ((enum EnsConfigOpts) index) {
522 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
523 goto freeMapAndError;
525 subcmdObj = (len > 0 ? objv[1] : NULL);
528 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
529 goto freeMapAndError;
531 paramObj = (len > 0 ? objv[1] : NULL);
534 Tcl_Obj *patchedDict = NULL, *subcmdWordsObj, **listv;
538 * Verify that the map is sensible.
541 if (Tcl_DictObjFirst(interp, objv[1], &search,
542 &subcmdWordsObj, &listObj, &done) != TCL_OK) {
543 goto freeMapAndError;
550 if (TclListObjGetElements(interp, listObj, &len,
552 Tcl_DictObjDone(&search);
554 Tcl_DecrRefCount(patchedDict);
556 goto freeMapAndError;
559 Tcl_SetObjResult(interp, Tcl_NewStringObj(
560 "ensemble subcommand implementations "
561 "must be non-empty lists", -1));
562 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE",
563 "EMPTY_TARGET", NULL);
564 Tcl_DictObjDone(&search);
566 Tcl_DecrRefCount(patchedDict);
568 goto freeMapAndError;
570 cmd = TclGetString(listv[0]);
571 if (!(cmd[0] == ':' && cmd[1] == ':')) {
572 Tcl_Obj *newList = Tcl_DuplicateObj(listObj);
573 Tcl_Obj *newCmd = NewNsObj((Tcl_Namespace*)nsPtr);
575 if (nsPtr->parentPtr) {
576 Tcl_AppendStringsToObj(newCmd, "::", NULL);
578 Tcl_AppendObjToObj(newCmd, listv[0]);
579 Tcl_ListObjReplace(NULL, newList, 0,1, 1,&newCmd);
580 if (patchedDict == NULL) {
581 patchedDict = Tcl_DuplicateObj(objv[1]);
583 Tcl_DictObjPut(NULL, patchedDict, subcmdWordsObj,
586 Tcl_DictObjNext(&search, &subcmdWordsObj, &listObj,
589 if (allocatedMapFlag) {
590 Tcl_DecrRefCount(mapObj);
592 mapObj = (patchedDict ? patchedDict : objv[1]);
594 allocatedMapFlag = 1;
599 Tcl_SetObjResult(interp, Tcl_NewStringObj(
600 "option -namespace is read-only", -1));
601 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "READ_ONLY",
603 goto freeMapAndError;
605 if (Tcl_GetBooleanFromObj(interp, objv[1],
606 &permitPrefix) != TCL_OK) {
607 goto freeMapAndError;
611 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
612 goto freeMapAndError;
614 unknownObj = (len > 0 ? objv[1] : NULL);
620 * Update the namespace now that we've finished the parsing stage.
623 flags = (permitPrefix ? flags|TCL_ENSEMBLE_PREFIX
624 : flags&~TCL_ENSEMBLE_PREFIX);
625 Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj);
626 Tcl_SetEnsembleMappingDict(interp, token, mapObj);
627 Tcl_SetEnsembleParameterList(interp, token, paramObj);
628 Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj);
629 Tcl_SetEnsembleFlags(interp, token, flags);
634 Tcl_Panic("unexpected ensemble command");
640 *----------------------------------------------------------------------
642 * TclCreateEnsembleInNs --
644 * Like Tcl_CreateEnsemble, but additionally accepts as an argument the
645 * name of the namespace to create the command in.
647 *----------------------------------------------------------------------
651 TclCreateEnsembleInNs(
654 const char *name, /* Simple name of command to create (no */
655 /* namespace components). */
656 Tcl_Namespace /* Name of namespace to create the command in. */
659 *ensembleNsPtr, /* Name of the namespace for the ensemble. */
663 Namespace *nsPtr = (Namespace *) ensembleNsPtr;
664 EnsembleConfig *ensemblePtr;
667 ensemblePtr = ckalloc(sizeof(EnsembleConfig));
668 token = TclNRCreateCommandInNs(interp, name,
669 (Tcl_Namespace *) nameNsPtr, NsEnsembleImplementationCmd,
670 NsEnsembleImplementationCmdNR, ensemblePtr, DeleteEnsembleConfig);
676 ensemblePtr->nsPtr = nsPtr;
677 ensemblePtr->epoch = 0;
678 Tcl_InitHashTable(&ensemblePtr->subcommandTable, TCL_STRING_KEYS);
679 ensemblePtr->subcommandArrayPtr = NULL;
680 ensemblePtr->subcmdList = NULL;
681 ensemblePtr->subcommandDict = NULL;
682 ensemblePtr->flags = flags;
683 ensemblePtr->numParameters = 0;
684 ensemblePtr->parameterList = NULL;
685 ensemblePtr->unknownHandler = NULL;
686 ensemblePtr->token = token;
687 ensemblePtr->next = (EnsembleConfig *) nsPtr->ensembles;
688 nsPtr->ensembles = (Tcl_Ensemble *) ensemblePtr;
691 * Trigger an eventual recomputation of the ensemble command set. Note
692 * that this is slightly tricky, as it means that we are not actually
693 * counting the number of namespace export actions, but it is the simplest
697 nsPtr->exportLookupEpoch++;
699 if (flags & ENSEMBLE_COMPILE) {
700 ((Command *) ensemblePtr->token)->compileProc = TclCompileEnsemble;
703 return ensemblePtr->token;
709 *----------------------------------------------------------------------
713 * Create a simple ensemble attached to the given namespace.
715 * Deprecated by TclCreateEnsembleInNs.
719 * The token for the command created.
722 * The ensemble is created and marked for compilation.
725 *----------------------------------------------------------------------
732 Tcl_Namespace *namespacePtr,
735 Namespace *nsPtr = (Namespace *)namespacePtr, *foundNsPtr, *altNsPtr,
737 const char * simpleName;
740 nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
743 TclGetNamespaceForQualName(interp, name, nsPtr, TCL_CREATE_NS_IF_UNKNOWN,
744 &foundNsPtr, &altNsPtr, &actualNsPtr, &simpleName);
745 return TclCreateEnsembleInNs(interp, simpleName,
746 (Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr, flags);
751 *----------------------------------------------------------------------
753 * Tcl_SetEnsembleSubcommandList --
755 * Set the subcommand list for a particular ensemble.
758 * Tcl result code (error if command token does not indicate an ensemble
759 * or the subcommand list - if non-NULL - is not a list).
762 * The ensemble is updated and marked for recompilation.
764 *----------------------------------------------------------------------
768 Tcl_SetEnsembleSubcommandList(
773 Command *cmdPtr = (Command *) token;
774 EnsembleConfig *ensemblePtr;
777 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
778 Tcl_SetObjResult(interp, Tcl_NewStringObj(
779 "command is not an ensemble", -1));
780 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
783 if (subcmdList != NULL) {
786 if (TclListObjLength(interp, subcmdList, &length) != TCL_OK) {
794 ensemblePtr = cmdPtr->objClientData;
795 oldList = ensemblePtr->subcmdList;
796 ensemblePtr->subcmdList = subcmdList;
797 if (subcmdList != NULL) {
798 Tcl_IncrRefCount(subcmdList);
800 if (oldList != NULL) {
801 TclDecrRefCount(oldList);
805 * Trigger an eventual recomputation of the ensemble command set. Note
806 * that this is slightly tricky, as it means that we are not actually
807 * counting the number of namespace export actions, but it is the simplest
811 ensemblePtr->nsPtr->exportLookupEpoch++;
814 * Special hack to make compiling of [info exists] work when the
815 * dictionary is modified.
818 if (cmdPtr->compileProc != NULL) {
819 ((Interp *) interp)->compileEpoch++;
826 *----------------------------------------------------------------------
828 * Tcl_SetEnsembleParameterList --
830 * Set the parameter list for a particular ensemble.
833 * Tcl result code (error if command token does not indicate an ensemble
834 * or the parameter list - if non-NULL - is not a list).
837 * The ensemble is updated and marked for recompilation.
839 *----------------------------------------------------------------------
843 Tcl_SetEnsembleParameterList(
848 Command *cmdPtr = (Command *) token;
849 EnsembleConfig *ensemblePtr;
853 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
854 Tcl_SetObjResult(interp, Tcl_NewStringObj(
855 "command is not an ensemble", -1));
856 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
859 if (paramList == NULL) {
862 if (TclListObjLength(interp, paramList, &length) != TCL_OK) {
870 ensemblePtr = cmdPtr->objClientData;
871 oldList = ensemblePtr->parameterList;
872 ensemblePtr->parameterList = paramList;
873 if (paramList != NULL) {
874 Tcl_IncrRefCount(paramList);
876 if (oldList != NULL) {
877 TclDecrRefCount(oldList);
879 ensemblePtr->numParameters = length;
882 * Trigger an eventual recomputation of the ensemble command set. Note
883 * that this is slightly tricky, as it means that we are not actually
884 * counting the number of namespace export actions, but it is the simplest
888 ensemblePtr->nsPtr->exportLookupEpoch++;
891 * Special hack to make compiling of [info exists] work when the
892 * dictionary is modified.
895 if (cmdPtr->compileProc != NULL) {
896 ((Interp *) interp)->compileEpoch++;
903 *----------------------------------------------------------------------
905 * Tcl_SetEnsembleMappingDict --
907 * Set the mapping dictionary for a particular ensemble.
910 * Tcl result code (error if command token does not indicate an ensemble
911 * or the mapping - if non-NULL - is not a dict).
914 * The ensemble is updated and marked for recompilation.
916 *----------------------------------------------------------------------
920 Tcl_SetEnsembleMappingDict(
925 Command *cmdPtr = (Command *) token;
926 EnsembleConfig *ensemblePtr;
929 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
930 Tcl_SetObjResult(interp, Tcl_NewStringObj(
931 "command is not an ensemble", -1));
932 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
935 if (mapDict != NULL) {
937 Tcl_DictSearch search;
940 if (Tcl_DictObjSize(interp, mapDict, &size) != TCL_OK) {
944 for (Tcl_DictObjFirst(NULL, mapDict, &search, NULL, &valuePtr, &done);
945 !done; Tcl_DictObjNext(&search, NULL, &valuePtr, &done)) {
949 if (Tcl_ListObjIndex(interp, valuePtr, 0, &cmdObjPtr) != TCL_OK) {
950 Tcl_DictObjDone(&search);
953 bytes = TclGetString(cmdObjPtr);
954 if (bytes[0] != ':' || bytes[1] != ':') {
955 Tcl_SetObjResult(interp, Tcl_NewStringObj(
956 "ensemble target is not a fully-qualified command",
958 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE",
959 "UNQUALIFIED_TARGET", NULL);
960 Tcl_DictObjDone(&search);
970 ensemblePtr = cmdPtr->objClientData;
971 oldDict = ensemblePtr->subcommandDict;
972 ensemblePtr->subcommandDict = mapDict;
973 if (mapDict != NULL) {
974 Tcl_IncrRefCount(mapDict);
976 if (oldDict != NULL) {
977 TclDecrRefCount(oldDict);
981 * Trigger an eventual recomputation of the ensemble command set. Note
982 * that this is slightly tricky, as it means that we are not actually
983 * counting the number of namespace export actions, but it is the simplest
987 ensemblePtr->nsPtr->exportLookupEpoch++;
990 * Special hack to make compiling of [info exists] work when the
991 * dictionary is modified.
994 if (cmdPtr->compileProc != NULL) {
995 ((Interp *) interp)->compileEpoch++;
1002 *----------------------------------------------------------------------
1004 * Tcl_SetEnsembleUnknownHandler --
1006 * Set the unknown handler for a particular ensemble.
1009 * Tcl result code (error if command token does not indicate an ensemble
1010 * or the unknown handler - if non-NULL - is not a list).
1013 * The ensemble is updated and marked for recompilation.
1015 *----------------------------------------------------------------------
1019 Tcl_SetEnsembleUnknownHandler(
1022 Tcl_Obj *unknownList)
1024 Command *cmdPtr = (Command *) token;
1025 EnsembleConfig *ensemblePtr;
1028 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
1029 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1030 "command is not an ensemble", -1));
1031 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
1034 if (unknownList != NULL) {
1037 if (TclListObjLength(interp, unknownList, &length) != TCL_OK) {
1045 ensemblePtr = cmdPtr->objClientData;
1046 oldList = ensemblePtr->unknownHandler;
1047 ensemblePtr->unknownHandler = unknownList;
1048 if (unknownList != NULL) {
1049 Tcl_IncrRefCount(unknownList);
1051 if (oldList != NULL) {
1052 TclDecrRefCount(oldList);
1056 * Trigger an eventual recomputation of the ensemble command set. Note
1057 * that this is slightly tricky, as it means that we are not actually
1058 * counting the number of namespace export actions, but it is the simplest
1062 ensemblePtr->nsPtr->exportLookupEpoch++;
1068 *----------------------------------------------------------------------
1070 * Tcl_SetEnsembleFlags --
1072 * Set the flags for a particular ensemble.
1075 * Tcl result code (error if command token does not indicate an
1079 * The ensemble is updated and marked for recompilation.
1081 *----------------------------------------------------------------------
1085 Tcl_SetEnsembleFlags(
1090 Command *cmdPtr = (Command *) token;
1091 EnsembleConfig *ensemblePtr;
1094 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
1095 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1096 "command is not an ensemble", -1));
1097 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
1101 ensemblePtr = cmdPtr->objClientData;
1102 wasCompiled = ensemblePtr->flags & ENSEMBLE_COMPILE;
1105 * This API refuses to set the ENSEMBLE_DEAD flag...
1108 ensemblePtr->flags &= ENSEMBLE_DEAD;
1109 ensemblePtr->flags |= flags & ~ENSEMBLE_DEAD;
1112 * Trigger an eventual recomputation of the ensemble command set. Note
1113 * that this is slightly tricky, as it means that we are not actually
1114 * counting the number of namespace export actions, but it is the simplest
1118 ensemblePtr->nsPtr->exportLookupEpoch++;
1121 * If the ENSEMBLE_COMPILE flag status was changed, install or remove the
1122 * compiler function and bump the interpreter's compilation epoch so that
1123 * bytecode gets regenerated.
1126 if (flags & ENSEMBLE_COMPILE) {
1128 ((Command*) ensemblePtr->token)->compileProc = TclCompileEnsemble;
1129 ((Interp *) interp)->compileEpoch++;
1133 ((Command *) ensemblePtr->token)->compileProc = NULL;
1134 ((Interp *) interp)->compileEpoch++;
1142 *----------------------------------------------------------------------
1144 * Tcl_GetEnsembleSubcommandList --
1146 * Get the list of subcommands associated with a particular ensemble.
1149 * Tcl result code (error if command token does not indicate an
1150 * ensemble). The list of subcommands is returned by updating the
1151 * variable pointed to by the last parameter (NULL if this is to be
1152 * derived from the mapping dictionary or the associated namespace's
1153 * exported commands).
1158 *----------------------------------------------------------------------
1162 Tcl_GetEnsembleSubcommandList(
1165 Tcl_Obj **subcmdListPtr)
1167 Command *cmdPtr = (Command *) token;
1168 EnsembleConfig *ensemblePtr;
1170 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
1171 if (interp != NULL) {
1172 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1173 "command is not an ensemble", -1));
1174 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
1179 ensemblePtr = cmdPtr->objClientData;
1180 *subcmdListPtr = ensemblePtr->subcmdList;
1185 *----------------------------------------------------------------------
1187 * Tcl_GetEnsembleParameterList --
1189 * Get the list of parameters associated with a particular ensemble.
1192 * Tcl result code (error if command token does not indicate an
1193 * ensemble). The list of parameters is returned by updating the
1194 * variable pointed to by the last parameter (NULL if there are
1200 *----------------------------------------------------------------------
1204 Tcl_GetEnsembleParameterList(
1207 Tcl_Obj **paramListPtr)
1209 Command *cmdPtr = (Command *) token;
1210 EnsembleConfig *ensemblePtr;
1212 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
1213 if (interp != NULL) {
1214 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1215 "command is not an ensemble", -1));
1216 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
1221 ensemblePtr = cmdPtr->objClientData;
1222 *paramListPtr = ensemblePtr->parameterList;
1227 *----------------------------------------------------------------------
1229 * Tcl_GetEnsembleMappingDict --
1231 * Get the command mapping dictionary associated with a particular
1235 * Tcl result code (error if command token does not indicate an
1236 * ensemble). The mapping dict is returned by updating the variable
1237 * pointed to by the last parameter (NULL if none is installed).
1242 *----------------------------------------------------------------------
1246 Tcl_GetEnsembleMappingDict(
1249 Tcl_Obj **mapDictPtr)
1251 Command *cmdPtr = (Command *) token;
1252 EnsembleConfig *ensemblePtr;
1254 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
1255 if (interp != NULL) {
1256 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1257 "command is not an ensemble", -1));
1258 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
1263 ensemblePtr = cmdPtr->objClientData;
1264 *mapDictPtr = ensemblePtr->subcommandDict;
1269 *----------------------------------------------------------------------
1271 * Tcl_GetEnsembleUnknownHandler --
1273 * Get the unknown handler associated with a particular ensemble.
1276 * Tcl result code (error if command token does not indicate an
1277 * ensemble). The unknown handler is returned by updating the variable
1278 * pointed to by the last parameter (NULL if no handler is installed).
1283 *----------------------------------------------------------------------
1287 Tcl_GetEnsembleUnknownHandler(
1290 Tcl_Obj **unknownListPtr)
1292 Command *cmdPtr = (Command *) token;
1293 EnsembleConfig *ensemblePtr;
1295 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
1296 if (interp != NULL) {
1297 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1298 "command is not an ensemble", -1));
1299 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
1304 ensemblePtr = cmdPtr->objClientData;
1305 *unknownListPtr = ensemblePtr->unknownHandler;
1310 *----------------------------------------------------------------------
1312 * Tcl_GetEnsembleFlags --
1314 * Get the flags for a particular ensemble.
1317 * Tcl result code (error if command token does not indicate an
1318 * ensemble). The flags are returned by updating the variable pointed to
1319 * by the last parameter.
1324 *----------------------------------------------------------------------
1328 Tcl_GetEnsembleFlags(
1333 Command *cmdPtr = (Command *) token;
1334 EnsembleConfig *ensemblePtr;
1336 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
1337 if (interp != NULL) {
1338 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1339 "command is not an ensemble", -1));
1340 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
1345 ensemblePtr = cmdPtr->objClientData;
1346 *flagsPtr = ensemblePtr->flags;
1351 *----------------------------------------------------------------------
1353 * Tcl_GetEnsembleNamespace --
1355 * Get the namespace associated with a particular ensemble.
1358 * Tcl result code (error if command token does not indicate an
1359 * ensemble). Namespace is returned by updating the variable pointed to
1360 * by the last parameter.
1365 *----------------------------------------------------------------------
1369 Tcl_GetEnsembleNamespace(
1372 Tcl_Namespace **namespacePtrPtr)
1374 Command *cmdPtr = (Command *) token;
1375 EnsembleConfig *ensemblePtr;
1377 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
1378 if (interp != NULL) {
1379 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1380 "command is not an ensemble", -1));
1381 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
1386 ensemblePtr = cmdPtr->objClientData;
1387 *namespacePtrPtr = (Tcl_Namespace *) ensemblePtr->nsPtr;
1392 *----------------------------------------------------------------------
1394 * Tcl_FindEnsemble --
1396 * Given a command name, get the ensemble token for it, allowing for
1397 * [namespace import]s. [Bug 1017022]
1400 * The token for the ensemble command with the given name, or NULL if the
1401 * command either does not exist or is not an ensemble (when an error
1402 * message will be written into the interp if thats non-NULL).
1407 *----------------------------------------------------------------------
1412 Tcl_Interp *interp, /* Where to do the lookup, and where to write
1413 * the errors if TCL_LEAVE_ERR_MSG is set in
1415 Tcl_Obj *cmdNameObj, /* Name of command to look up. */
1416 int flags) /* Either 0 or TCL_LEAVE_ERR_MSG; other flags
1417 * are probably not useful. */
1421 cmdPtr = (Command *)
1422 Tcl_FindCommand(interp, TclGetString(cmdNameObj), NULL, flags);
1423 if (cmdPtr == NULL) {
1427 if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
1429 * Reuse existing infrastructure for following import link chains
1430 * rather than duplicating it.
1433 cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr);
1435 if (cmdPtr == NULL || cmdPtr->objProc != NsEnsembleImplementationCmd){
1436 if (flags & TCL_LEAVE_ERR_MSG) {
1437 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1438 "\"%s\" is not an ensemble command",
1439 TclGetString(cmdNameObj)));
1440 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENSEMBLE",
1441 TclGetString(cmdNameObj), NULL);
1447 return (Tcl_Command) cmdPtr;
1451 *----------------------------------------------------------------------
1455 * Simple test for ensemble-hood that takes into account imported
1456 * ensemble commands as well.
1464 *----------------------------------------------------------------------
1471 Command *cmdPtr = (Command *) token;
1473 if (cmdPtr->objProc == NsEnsembleImplementationCmd) {
1476 cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr);
1477 if (cmdPtr == NULL || cmdPtr->objProc != NsEnsembleImplementationCmd) {
1484 *----------------------------------------------------------------------
1486 * TclMakeEnsemble --
1488 * Create an ensemble from a table of implementation commands. The
1489 * ensemble will be subject to (limited) compilation if any of the
1490 * implementation commands are compilable.
1492 * The 'name' parameter may be a single command name or a list if
1493 * creating an ensemble subcommand (see the binary implementation).
1495 * Currently, the TCL_ENSEMBLE_PREFIX ensemble flag is only used on
1496 * top-level ensemble commands.
1499 * Handle for the new ensemble, or NULL on failure.
1502 * May advance the bytecode compilation epoch.
1504 *----------------------------------------------------------------------
1510 const char *name, /* The ensemble name (as explained above) */
1511 const EnsembleImplMap map[]) /* The subcommands to create */
1513 Tcl_Command ensemble;
1515 Tcl_DString buf, hiddenBuf;
1516 const char **nameParts = NULL;
1517 const char *cmdName = NULL;
1518 int i, nameCount = 0, ensembleFlags = 0, hiddenLen;
1521 * Construct the path for the ensemble namespace and create it.
1524 Tcl_DStringInit(&buf);
1525 Tcl_DStringInit(&hiddenBuf);
1526 TclDStringAppendLiteral(&hiddenBuf, "tcl:");
1527 Tcl_DStringAppend(&hiddenBuf, name, -1);
1528 TclDStringAppendLiteral(&hiddenBuf, ":");
1529 hiddenLen = Tcl_DStringLength(&hiddenBuf);
1530 if (name[0] == ':' && name[1] == ':') {
1532 * An absolute name, so use it directly.
1536 Tcl_DStringAppend(&buf, name, -1);
1537 ensembleFlags = TCL_ENSEMBLE_PREFIX;
1540 * Not an absolute name, so do munging of it. Note that this treats a
1541 * multi-word list differently to a single word.
1544 TclDStringAppendLiteral(&buf, "::tcl");
1546 if (Tcl_SplitList(NULL, name, &nameCount, &nameParts) != TCL_OK) {
1547 Tcl_Panic("invalid ensemble name '%s'", name);
1550 for (i = 0; i < nameCount; ++i) {
1551 TclDStringAppendLiteral(&buf, "::");
1552 Tcl_DStringAppend(&buf, nameParts[i], -1);
1556 ns = Tcl_FindNamespace(interp, Tcl_DStringValue(&buf), NULL,
1557 TCL_CREATE_NS_IF_UNKNOWN);
1559 Tcl_Panic("unable to find or create %s namespace!",
1560 Tcl_DStringValue(&buf));
1564 * Create the named ensemble in the correct namespace
1567 if (cmdName == NULL) {
1568 if (nameCount == 1) {
1569 ensembleFlags = TCL_ENSEMBLE_PREFIX;
1570 cmdName = Tcl_DStringValue(&buf) + 5;
1573 cmdName = nameParts[nameCount - 1];
1578 * Switch on compilation always for core ensembles now that we can do
1579 * nice bytecode things with them. Do it now. Waiting until later will
1580 * just cause pointless epoch bumps.
1583 ensembleFlags |= ENSEMBLE_COMPILE;
1584 ensemble = Tcl_CreateEnsemble(interp, cmdName, ns, ensembleFlags);
1587 * Create the ensemble mapping dictionary and the ensemble command procs.
1590 if (ensemble != NULL) {
1591 Tcl_Obj *mapDict, *fromObj, *toObj;
1594 TclDStringAppendLiteral(&buf, "::");
1596 for (i=0 ; map[i].name != NULL ; i++) {
1597 fromObj = Tcl_NewStringObj(map[i].name, -1);
1598 TclNewStringObj(toObj, Tcl_DStringValue(&buf),
1599 Tcl_DStringLength(&buf));
1600 Tcl_AppendToObj(toObj, map[i].name, -1);
1601 Tcl_DictObjPut(NULL, mapDict, fromObj, toObj);
1603 if (map[i].proc || map[i].nreProc) {
1605 * If the command is unsafe, hide it when we're in a safe
1606 * interpreter. The code to do this is really hokey! It also
1607 * doesn't work properly yet; this function is always
1608 * currently called before the safe-interp flag is set so the
1609 * Tcl_IsSafe check fails.
1612 if (map[i].unsafe && Tcl_IsSafe(interp)) {
1613 cmdPtr = (Command *)
1614 Tcl_NRCreateCommand(interp, "___tmp", map[i].proc,
1615 map[i].nreProc, map[i].clientData, NULL);
1616 Tcl_DStringSetLength(&hiddenBuf, hiddenLen);
1617 if (Tcl_HideCommand(interp, "___tmp",
1618 Tcl_DStringAppend(&hiddenBuf, map[i].name, -1))) {
1619 Tcl_Panic("%s", Tcl_GetString(Tcl_GetObjResult(interp)));
1623 * Not hidden, so just create it. Yay!
1626 cmdPtr = (Command *)
1627 Tcl_NRCreateCommand(interp, TclGetString(toObj),
1628 map[i].proc, map[i].nreProc, map[i].clientData,
1631 cmdPtr->compileProc = map[i].compileProc;
1634 Tcl_SetEnsembleMappingDict(interp, ensemble, mapDict);
1637 Tcl_DStringFree(&buf);
1638 Tcl_DStringFree(&hiddenBuf);
1639 if (nameParts != NULL) {
1640 ckfree((char *) nameParts);
1646 *----------------------------------------------------------------------
1648 * NsEnsembleImplementationCmd --
1650 * Implements an ensemble of commands (being those exported by a
1651 * namespace other than the global namespace) as a command with the same
1652 * (short) name as the namespace in the parent namespace.
1655 * A standard Tcl result code. Will be TCL_ERROR if the command is not an
1656 * unambiguous prefix of any command exported by the ensemble's
1660 * Depends on the command within the namespace that gets executed. If the
1661 * ensemble itself returns TCL_ERROR, a descriptive error message will be
1662 * placed in the interpreter's result.
1664 *----------------------------------------------------------------------
1668 NsEnsembleImplementationCmd(
1669 ClientData clientData,
1672 Tcl_Obj *const objv[])
1674 return Tcl_NRCallObjProc(interp, NsEnsembleImplementationCmdNR,
1675 clientData, objc, objv);
1679 NsEnsembleImplementationCmdNR(
1680 ClientData clientData,
1683 Tcl_Obj *const objv[])
1685 EnsembleConfig *ensemblePtr = clientData;
1686 /* The ensemble itself. */
1687 Tcl_Obj *prefixObj; /* An object containing the prefix words of
1688 * the command that implements the
1690 Tcl_HashEntry *hPtr; /* Used for efficient lookup of fully
1691 * specified but not yet cached command
1693 int reparseCount = 0; /* Number of reparses. */
1694 Tcl_Obj *errorObj; /* Used for building error messages. */
1699 * Must recheck objc, since numParameters might have changed. Cf. test
1703 restartEnsembleParse:
1704 subIdx = 1 + ensemblePtr->numParameters;
1705 if (objc < subIdx + 1) {
1707 * We don't have a subcommand argument. Make error message.
1710 Tcl_DString buf; /* Message being built */
1712 Tcl_DStringInit(&buf);
1713 if (ensemblePtr->parameterList) {
1714 Tcl_DStringAppend(&buf,
1715 TclGetString(ensemblePtr->parameterList), -1);
1716 TclDStringAppendLiteral(&buf, " ");
1718 TclDStringAppendLiteral(&buf, "subcommand ?arg ...?");
1719 Tcl_WrongNumArgs(interp, 1, objv, Tcl_DStringValue(&buf));
1720 Tcl_DStringFree(&buf);
1725 if (ensemblePtr->nsPtr->flags & NS_DYING) {
1727 * Don't know how we got here, but make things give up quickly.
1730 if (!Tcl_InterpDeleted(interp)) {
1731 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1732 "ensemble activated for deleted namespace", -1));
1733 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "DEAD", NULL);
1739 * Determine if the table of subcommands is right. If so, we can just look
1740 * up in there and go straight to dispatch.
1743 subObj = objv[subIdx];
1745 if (ensemblePtr->epoch == ensemblePtr->nsPtr->exportLookupEpoch) {
1747 * Table of subcommands is still valid; therefore there might be a
1748 * valid cache of discovered information which we can reuse. Do the
1749 * check here, and if we're still valid, we can jump straight to the
1750 * part where we do the invocation of the subcommand.
1753 if (subObj->typePtr==&ensembleCmdType){
1754 EnsembleCmdRep *ensembleCmd = subObj->internalRep.twoPtrValue.ptr1;
1756 if (ensembleCmd->epoch == ensemblePtr->epoch &&
1757 ensembleCmd->token == (Command *)ensemblePtr->token) {
1758 prefixObj = Tcl_GetHashValue(ensembleCmd->hPtr);
1759 Tcl_IncrRefCount(prefixObj);
1760 if (ensembleCmd->fix) {
1761 TclSpellFix(interp, objv, objc, subIdx, subObj, ensembleCmd->fix);
1763 goto runResultingSubcommand;
1767 BuildEnsembleConfig(ensemblePtr);
1768 ensemblePtr->epoch = ensemblePtr->nsPtr->exportLookupEpoch;
1772 * Look in the hashtable for the subcommand name; this is the fastest way
1773 * of all if there is no cache in operation.
1776 hPtr = Tcl_FindHashEntry(&ensemblePtr->subcommandTable,
1777 TclGetString(subObj));
1781 * Cache for later in the subcommand object.
1784 MakeCachedEnsembleCommand(subObj, ensemblePtr, hPtr, NULL);
1785 } else if (!(ensemblePtr->flags & TCL_ENSEMBLE_PREFIX)) {
1787 * Could not map, no prefixing, go to unknown/error handling.
1790 goto unknownOrAmbiguousSubcommand;
1793 * If we've not already confirmed the command with the hash as part of
1794 * building our export table, we need to scan the sorted array for
1798 const char *subcmdName; /* Name of the subcommand, or unique prefix of
1799 * it (will be an error for a non-unique
1801 char *fullName = NULL; /* Full name of the subcommand. */
1802 int stringLength, i;
1803 int tableLength = ensemblePtr->subcommandTable.numEntries;
1806 subcmdName = Tcl_GetStringFromObj(subObj, &stringLength);
1807 for (i=0 ; i<tableLength ; i++) {
1808 int cmp = strncmp(subcmdName,
1809 ensemblePtr->subcommandArrayPtr[i],
1810 (unsigned) stringLength);
1813 if (fullName != NULL) {
1815 * Since there's never the exact-match case to worry about
1816 * (hash search filters this), getting here indicates that
1817 * our subcommand is an ambiguous prefix of (at least) two
1818 * exported subcommands, which is an error case.
1821 goto unknownOrAmbiguousSubcommand;
1823 fullName = ensemblePtr->subcommandArrayPtr[i];
1824 } else if (cmp < 0) {
1826 * Because we are searching a sorted table, we can now stop
1827 * searching because we have gone past anything that could
1834 if (fullName == NULL) {
1836 * The subcommand is not a prefix of anything, so bail out!
1839 goto unknownOrAmbiguousSubcommand;
1841 hPtr = Tcl_FindHashEntry(&ensemblePtr->subcommandTable, fullName);
1843 Tcl_Panic("full name %s not found in supposedly synchronized hash",
1848 * Record the spelling correction for usage message.
1851 fix = Tcl_NewStringObj(fullName, -1);
1854 * Cache for later in the subcommand object.
1857 MakeCachedEnsembleCommand(subObj, ensemblePtr, hPtr, fix);
1858 TclSpellFix(interp, objv, objc, subIdx, subObj, fix);
1861 prefixObj = Tcl_GetHashValue(hPtr);
1862 Tcl_IncrRefCount(prefixObj);
1863 runResultingSubcommand:
1866 * Do the real work of execution of the subcommand by building an array of
1867 * objects (note that this is potentially not the same length as the
1868 * number of arguments to this ensemble command), populating it and then
1869 * feeding it back through the main command-lookup engine. In theory, we
1870 * could look up the command in the namespace ourselves, as we already
1871 * have the namespace in which it is guaranteed to exist,
1873 * ((Q: That's not true if the -map option is used, is it?))
1875 * but we don't do that (the cacheing of the command object used should
1880 Tcl_Obj *copyPtr; /* The actual list of words to dispatch to.
1881 * Will be freed by the dispatch engine. */
1883 int copyObjc, prefixObjc;
1885 Tcl_ListObjLength(NULL, prefixObj, &prefixObjc);
1888 copyPtr = TclListObjCopy(NULL, prefixObj);
1890 copyPtr = Tcl_NewListObj(objc - 2 + prefixObjc, NULL);
1891 Tcl_ListObjAppendList(NULL, copyPtr, prefixObj);
1892 Tcl_ListObjReplace(NULL, copyPtr, LIST_MAX, 0,
1893 ensemblePtr->numParameters, objv + 1);
1894 Tcl_ListObjReplace(NULL, copyPtr, LIST_MAX, 0,
1895 objc - 2 - ensemblePtr->numParameters,
1896 objv + 2 + ensemblePtr->numParameters);
1898 Tcl_IncrRefCount(copyPtr);
1899 TclNRAddCallback(interp, TclNRReleaseValues, copyPtr, NULL, NULL, NULL);
1900 TclDecrRefCount(prefixObj);
1903 * Record what arguments the script sent in so that things like
1904 * Tcl_WrongNumArgs can give the correct error message. Parameters
1905 * count both as inserted and removed arguments.
1908 if (TclInitRewriteEnsemble(interp, 2 + ensemblePtr->numParameters,
1909 prefixObjc + ensemblePtr->numParameters, objv)) {
1910 TclNRAddCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL,
1915 * Hand off to the target command.
1918 TclSkipTailcall(interp);
1919 Tcl_ListObjGetElements(NULL, copyPtr, ©Objc, ©Objv);
1920 ((Interp *)interp)->lookupNsPtr = ensemblePtr->nsPtr;
1921 return TclNREvalObjv(interp, copyObjc, copyObjv, TCL_EVAL_INVOKE, NULL);
1924 unknownOrAmbiguousSubcommand:
1926 * Have not been able to match the subcommand asked for with a real
1927 * subcommand that we export. See whether a handler has been registered
1928 * for dealing with this situation. Will only call (at most) once for any
1929 * particular ensemble invocation.
1932 if (ensemblePtr->unknownHandler != NULL && reparseCount++ < 1) {
1933 switch (EnsembleUnknownCallback(interp, ensemblePtr, objc, objv,
1936 goto runResultingSubcommand;
1940 goto restartEnsembleParse;
1945 * We cannot determine what subcommand to hand off to, so generate a
1946 * (standard) failure message. Note the one odd case compared with
1947 * standard ensemble-like command, which is where a namespace has no
1948 * exported commands at all...
1951 Tcl_ResetResult(interp);
1952 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND",
1953 TclGetString(subObj), NULL);
1954 if (ensemblePtr->subcommandTable.numEntries == 0) {
1955 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1956 "unknown subcommand \"%s\": namespace %s does not"
1957 " export any commands", TclGetString(subObj),
1958 ensemblePtr->nsPtr->fullName));
1961 errorObj = Tcl_ObjPrintf("unknown%s subcommand \"%s\": must be ",
1962 (ensemblePtr->flags & TCL_ENSEMBLE_PREFIX ? " or ambiguous" : ""),
1963 TclGetString(subObj));
1964 if (ensemblePtr->subcommandTable.numEntries == 1) {
1965 Tcl_AppendToObj(errorObj, ensemblePtr->subcommandArrayPtr[0], -1);
1969 for (i=0 ; i<ensemblePtr->subcommandTable.numEntries-1 ; i++) {
1970 Tcl_AppendToObj(errorObj, ensemblePtr->subcommandArrayPtr[i], -1);
1971 Tcl_AppendToObj(errorObj, ", ", 2);
1973 Tcl_AppendPrintfToObj(errorObj, "or %s",
1974 ensemblePtr->subcommandArrayPtr[i]);
1976 Tcl_SetObjResult(interp, errorObj);
1981 TclClearRootEnsemble(
1986 TclResetRewriteEnsemble(interp, 1);
1991 *----------------------------------------------------------------------
1993 * TclInitRewriteEnsemble --
1995 * Applies a rewrite of arguments so that an ensemble subcommand will
1996 * report error messages correctly for the overall command.
1999 * Whether this is the first rewrite applied, a value which must be
2000 * passed to TclResetRewriteEnsemble when undoing this command's
2006 *----------------------------------------------------------------------
2010 TclInitRewriteEnsemble(
2014 Tcl_Obj *const *objv)
2016 Interp *iPtr = (Interp *) interp;
2018 int isRootEnsemble = (iPtr->ensembleRewrite.sourceObjs == NULL);
2020 if (isRootEnsemble) {
2021 iPtr->ensembleRewrite.sourceObjs = objv;
2022 iPtr->ensembleRewrite.numRemovedObjs = numRemoved;
2023 iPtr->ensembleRewrite.numInsertedObjs = numInserted;
2025 int numIns = iPtr->ensembleRewrite.numInsertedObjs;
2027 if (numIns < numRemoved) {
2028 iPtr->ensembleRewrite.numRemovedObjs += numRemoved - numIns;
2029 iPtr->ensembleRewrite.numInsertedObjs = numInserted;
2031 iPtr->ensembleRewrite.numInsertedObjs += numInserted - numRemoved;
2034 return isRootEnsemble;
2038 *----------------------------------------------------------------------
2040 * TclResetRewriteEnsemble --
2042 * Removes any rewrites applied to support proper reporting of error
2043 * messages used in ensembles. Should be paired with
2044 * TclInitRewriteEnsemble.
2052 *----------------------------------------------------------------------
2056 TclResetRewriteEnsemble(
2060 Interp *iPtr = (Interp *) interp;
2062 if (isRootEnsemble) {
2063 iPtr->ensembleRewrite.sourceObjs = NULL;
2064 iPtr->ensembleRewrite.numRemovedObjs = 0;
2065 iPtr->ensembleRewrite.numInsertedObjs = 0;
2070 *----------------------------------------------------------------------
2074 * Record a spelling correction that needs making in the generation of
2075 * the WrongNumArgs usage message.
2081 * Can create an alternative ensemble rewrite structure.
2083 *----------------------------------------------------------------------
2092 Tcl_Obj **tmp = (Tcl_Obj **) data[0];
2093 Tcl_Obj **store = (Tcl_Obj **) data[1];
2103 Tcl_Obj *const *objv,
2109 Interp *iPtr = (Interp *) interp;
2110 Tcl_Obj *const *search;
2115 if (iPtr->ensembleRewrite.sourceObjs == NULL) {
2116 iPtr->ensembleRewrite.sourceObjs = objv;
2117 iPtr->ensembleRewrite.numRemovedObjs = 0;
2118 iPtr->ensembleRewrite.numInsertedObjs = 0;
2122 * Compute the valid length of the ensemble root.
2125 size = iPtr->ensembleRewrite.numRemovedObjs + objc
2126 - iPtr->ensembleRewrite.numInsertedObjs;
2128 search = iPtr->ensembleRewrite.sourceObjs;
2129 if (search[0] == NULL) {
2131 * Awful casting abuse here!
2134 search = (Tcl_Obj *const *) search[1];
2137 if (badIdx < iPtr->ensembleRewrite.numInsertedObjs) {
2139 * Misspelled value was inserted. We cannot directly jump to the bad
2140 * value, but have to search.
2144 while (idx < size) {
2145 if (search[idx] == bad) {
2155 * Jump to the misspelled value.
2158 idx = iPtr->ensembleRewrite.numRemovedObjs + badIdx
2159 - iPtr->ensembleRewrite.numInsertedObjs;
2162 if (search[idx] != bad) {
2163 Tcl_Panic("SpellFix: programming error");
2167 search = iPtr->ensembleRewrite.sourceObjs;
2168 if (search[0] == NULL) {
2169 store = (Tcl_Obj **) search[2];
2171 Tcl_Obj **tmp = ckalloc(3 * sizeof(Tcl_Obj *));
2173 store = ckalloc(size * sizeof(Tcl_Obj *));
2174 memcpy(store, iPtr->ensembleRewrite.sourceObjs,
2175 size * sizeof(Tcl_Obj *));
2178 * Awful casting abuse here! Note that the NULL in the first element
2179 * indicates that the initial objects are a raw array in the second
2180 * element and the rewritten ones are a raw array in the third.
2184 tmp[1] = (Tcl_Obj *) iPtr->ensembleRewrite.sourceObjs;
2185 tmp[2] = (Tcl_Obj *) store;
2186 iPtr->ensembleRewrite.sourceObjs = (Tcl_Obj *const *) tmp;
2188 TclNRAddCallback(interp, FreeER, tmp, store, NULL, NULL);
2192 Tcl_IncrRefCount(fix);
2193 TclNRAddCallback(interp, TclNRReleaseValues, fix, NULL, NULL, NULL);
2196 Tcl_Obj *const *TclEnsembleGetRewriteValues(
2197 Tcl_Interp *interp /* Current interpreter. */
2200 Interp *iPtr = (Interp *) interp;
2201 Tcl_Obj *const *origObjv = iPtr->ensembleRewrite.sourceObjs;
2202 if (origObjv[0] == NULL) {
2203 origObjv = (Tcl_Obj *const *)origObjv[2];
2209 *----------------------------------------------------------------------
2211 * TclFetchEnsembleRoot --
2213 * Returns the root of ensemble rewriting, if any.
2214 * If no root exists, returns objv instead.
2222 *----------------------------------------------------------------------
2226 TclFetchEnsembleRoot(
2228 Tcl_Obj *const *objv,
2232 Tcl_Obj *const *sourceObjs;
2233 Interp *iPtr = (Interp *) interp;
2235 if (iPtr->ensembleRewrite.sourceObjs) {
2236 *objcPtr = objc + iPtr->ensembleRewrite.numRemovedObjs
2237 - iPtr->ensembleRewrite.numInsertedObjs;
2238 if (iPtr->ensembleRewrite.sourceObjs[0] == NULL) {
2239 sourceObjs = (Tcl_Obj *const *)iPtr->ensembleRewrite.sourceObjs[1];
2241 sourceObjs = iPtr->ensembleRewrite.sourceObjs;
2250 * ----------------------------------------------------------------------
2252 * EnsmebleUnknownCallback --
2254 * Helper for the ensemble engine that handles the procesing of unknown
2255 * callbacks. See the user documentation of the ensemble unknown handler
2256 * for details; this function is only ever called when such a function is
2257 * defined, and is only ever called once per ensemble dispatch (i.e. if a
2258 * reparse still fails, this isn't called again).
2261 * TCL_OK - *prefixObjPtr contains the command words to dispatch
2263 * TCL_CONTINUE - Need to reparse (*prefixObjPtr is invalid).
2264 * TCL_ERROR - Something went wrong! Error message in interpreter.
2267 * Calls the Tcl interpreter, so arbitrary.
2269 * ----------------------------------------------------------------------
2273 EnsembleUnknownCallback(
2275 EnsembleConfig *ensemblePtr,
2277 Tcl_Obj *const objv[],
2278 Tcl_Obj **prefixObjPtr)
2280 int paramc, i, result, prefixObjc;
2281 Tcl_Obj **paramv, *unknownCmd, *ensObj;
2284 * Create the unknown command callback to determine what to do.
2287 unknownCmd = Tcl_DuplicateObj(ensemblePtr->unknownHandler);
2289 Tcl_GetCommandFullName(interp, ensemblePtr->token, ensObj);
2290 Tcl_ListObjAppendElement(NULL, unknownCmd, ensObj);
2291 for (i=1 ; i<objc ; i++) {
2292 Tcl_ListObjAppendElement(NULL, unknownCmd, objv[i]);
2294 TclListObjGetElements(NULL, unknownCmd, ¶mc, ¶mv);
2295 Tcl_IncrRefCount(unknownCmd);
2298 * Now call the unknown handler. (We don't bother NRE-enabling this; deep
2299 * recursing through unknown handlers is horribly perverse.) Note that it
2300 * is always an error for an unknown handler to delete its ensemble; don't
2304 Tcl_Preserve(ensemblePtr);
2305 TclSkipTailcall(interp);
2306 result = Tcl_EvalObjv(interp, paramc, paramv, 0);
2307 if ((result == TCL_OK) && (ensemblePtr->flags & ENSEMBLE_DEAD)) {
2308 if (!Tcl_InterpDeleted(interp)) {
2309 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2310 "unknown subcommand handler deleted its ensemble", -1));
2311 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "UNKNOWN_DELETED",
2316 Tcl_Release(ensemblePtr);
2319 * If we succeeded, we should either have a list of words that form the
2320 * command to be executed, or an empty list. In the empty-list case, the
2321 * ensemble is believed to be updated so we should ask the ensemble engine
2322 * to reparse the original command.
2325 if (result == TCL_OK) {
2326 *prefixObjPtr = Tcl_GetObjResult(interp);
2327 Tcl_IncrRefCount(*prefixObjPtr);
2328 TclDecrRefCount(unknownCmd);
2329 Tcl_ResetResult(interp);
2332 * Namespace is still there. Check if the result is a valid list. If
2333 * it is, and it is non-empty, that list is what we are using as our
2337 if (TclListObjLength(interp, *prefixObjPtr, &prefixObjc) != TCL_OK) {
2338 TclDecrRefCount(*prefixObjPtr);
2339 Tcl_AddErrorInfo(interp, "\n while parsing result of "
2340 "ensemble unknown subcommand handler");
2343 if (prefixObjc > 0) {
2348 * Namespace alive & empty result => reparse.
2351 TclDecrRefCount(*prefixObjPtr);
2352 return TCL_CONTINUE;
2356 * Oh no! An exceptional result. Convert to an error.
2359 if (!Tcl_InterpDeleted(interp)) {
2360 if (result != TCL_ERROR) {
2361 Tcl_ResetResult(interp);
2362 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2363 "unknown subcommand handler returned bad code: ", -1));
2366 Tcl_AppendToObj(Tcl_GetObjResult(interp), "return", -1);
2369 Tcl_AppendToObj(Tcl_GetObjResult(interp), "break", -1);
2372 Tcl_AppendToObj(Tcl_GetObjResult(interp), "continue", -1);
2375 Tcl_AppendPrintfToObj(Tcl_GetObjResult(interp), "%d", result);
2377 Tcl_AddErrorInfo(interp, "\n result of "
2378 "ensemble unknown subcommand handler: ");
2379 Tcl_AppendObjToErrorInfo(interp, unknownCmd);
2380 Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "UNKNOWN_RESULT",
2383 Tcl_AddErrorInfo(interp,
2384 "\n (ensemble unknown subcommand handler)");
2387 TclDecrRefCount(unknownCmd);
2392 *----------------------------------------------------------------------
2394 * MakeCachedEnsembleCommand --
2396 * Cache what we've computed so far; it's not nice to repeatedly copy
2397 * strings about. Note that to do this, we start by deleting any old
2398 * representation that there was (though if it was an out of date
2399 * ensemble rep, we can skip some of the deallocation process.)
2405 * Alters the internal representation of the first object parameter.
2407 *----------------------------------------------------------------------
2411 MakeCachedEnsembleCommand(
2413 EnsembleConfig *ensemblePtr,
2414 Tcl_HashEntry *hPtr,
2417 EnsembleCmdRep *ensembleCmd;
2419 if (objPtr->typePtr == &ensembleCmdType) {
2420 ensembleCmd = objPtr->internalRep.twoPtrValue.ptr1;
2421 TclCleanupCommandMacro(ensembleCmd->token);
2422 if (ensembleCmd->fix) {
2423 Tcl_DecrRefCount(ensembleCmd->fix);
2427 * Kill the old internal rep, and replace it with a brand new one of
2431 TclFreeIntRep(objPtr);
2432 ensembleCmd = ckalloc(sizeof(EnsembleCmdRep));
2433 objPtr->internalRep.twoPtrValue.ptr1 = ensembleCmd;
2434 objPtr->typePtr = &ensembleCmdType;
2438 * Populate the internal rep.
2441 ensembleCmd->epoch = ensemblePtr->epoch;
2442 ensembleCmd->token = (Command *) ensemblePtr->token;
2443 ensembleCmd->token->refCount++;
2445 Tcl_IncrRefCount(fix);
2447 ensembleCmd->fix = fix;
2448 ensembleCmd->hPtr = hPtr;
2452 *----------------------------------------------------------------------
2454 * DeleteEnsembleConfig --
2456 * Destroys the data structure used to represent an ensemble. This is
2457 * called when the ensemble's command is deleted (which happens
2458 * automatically if the ensemble's namespace is deleted.) Maintainers
2459 * should note that ensembles should be deleted by deleting their
2466 * Memory is (eventually) deallocated.
2468 *----------------------------------------------------------------------
2473 EnsembleConfig *ensemblePtr)
2475 Tcl_HashTable *hash = &ensemblePtr->subcommandTable;
2477 if (hash->numEntries != 0) {
2478 Tcl_HashSearch search;
2479 Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(hash, &search);
2481 while (hPtr != NULL) {
2482 Tcl_Obj *prefixObj = Tcl_GetHashValue(hPtr);
2483 Tcl_DecrRefCount(prefixObj);
2484 hPtr = Tcl_NextHashEntry(&search);
2486 ckfree((char *) ensemblePtr->subcommandArrayPtr);
2488 Tcl_DeleteHashTable(hash);
2492 DeleteEnsembleConfig(
2493 ClientData clientData)
2495 EnsembleConfig *ensemblePtr = clientData;
2496 Namespace *nsPtr = ensemblePtr->nsPtr;
2499 * Unlink from the ensemble chain if it has not been marked as having been
2503 if (ensemblePtr->next != ensemblePtr) {
2504 EnsembleConfig *ensPtr = (EnsembleConfig *) nsPtr->ensembles;
2506 if (ensPtr == ensemblePtr) {
2507 nsPtr->ensembles = (Tcl_Ensemble *) ensemblePtr->next;
2509 while (ensPtr != NULL) {
2510 if (ensPtr->next == ensemblePtr) {
2511 ensPtr->next = ensemblePtr->next;
2514 ensPtr = ensPtr->next;
2520 * Mark the namespace as dead so code that uses Tcl_Preserve() can tell
2521 * whether disaster happened anyway.
2524 ensemblePtr->flags |= ENSEMBLE_DEAD;
2527 * Kill the pointer-containing fields.
2530 ClearTable(ensemblePtr);
2531 if (ensemblePtr->subcmdList != NULL) {
2532 Tcl_DecrRefCount(ensemblePtr->subcmdList);
2534 if (ensemblePtr->parameterList != NULL) {
2535 Tcl_DecrRefCount(ensemblePtr->parameterList);
2537 if (ensemblePtr->subcommandDict != NULL) {
2538 Tcl_DecrRefCount(ensemblePtr->subcommandDict);
2540 if (ensemblePtr->unknownHandler != NULL) {
2541 Tcl_DecrRefCount(ensemblePtr->unknownHandler);
2545 * Arrange for the structure to be reclaimed. Note that this is complex
2546 * because we have to make sure that we can react sensibly when an
2547 * ensemble is deleted during the process of initialising the ensemble
2548 * (especially the unknown callback.)
2551 Tcl_EventuallyFree(ensemblePtr, TCL_DYNAMIC);
2555 *----------------------------------------------------------------------
2557 * BuildEnsembleConfig --
2559 * Create the internal data structures that describe how an ensemble
2560 * looks, being a hash mapping from the simple command name to the Tcl list
2561 * that describes the implementation prefix words, and a sorted array of
2562 * the names to allow for reasonably efficient unambiguous prefix handling.
2568 * Reallocates and rebuilds the hash table and array stored at the
2569 * ensemblePtr argument. For large ensembles or large namespaces, this is
2570 * a potentially expensive operation.
2572 *----------------------------------------------------------------------
2576 BuildEnsembleConfig(
2577 EnsembleConfig *ensemblePtr)
2579 Tcl_HashSearch search; /* Used for scanning the set of commands in
2580 * the namespace that backs up this
2583 Tcl_HashTable *hash = &ensemblePtr->subcommandTable;
2584 Tcl_HashEntry *hPtr;
2585 Tcl_Obj *mapDict = ensemblePtr->subcommandDict;
2586 Tcl_Obj *subList = ensemblePtr->subcmdList;
2588 ClearTable(ensemblePtr);
2589 Tcl_InitHashTable(hash, TCL_STRING_KEYS);
2593 Tcl_Obj **subv, *target, *cmdObj, *cmdPrefixObj;
2597 * There is a list of exactly what subcommands go in the table.
2598 * Must determine the target for each.
2601 Tcl_ListObjGetElements(NULL, subList, &subc, &subv);
2602 if (subList == mapDict) {
2604 * Strange case where explicit list of subcommands is same value
2605 * as the dict mapping to targets.
2608 for (i = 0; i < subc; i += 2) {
2609 name = TclGetString(subv[i]);
2610 hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
2612 cmdObj = (Tcl_Obj *)Tcl_GetHashValue(hPtr);
2613 Tcl_DecrRefCount(cmdObj);
2615 Tcl_SetHashValue(hPtr, subv[i+1]);
2616 Tcl_IncrRefCount(subv[i+1]);
2618 name = TclGetString(subv[i+1]);
2619 hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
2621 cmdObj = Tcl_NewStringObj(name, -1);
2622 cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
2623 Tcl_SetHashValue(hPtr, cmdPrefixObj);
2624 Tcl_IncrRefCount(cmdPrefixObj);
2628 /* Usual case where we can freely act on the list and dict. */
2630 for (i = 0; i < subc; i++) {
2631 name = TclGetString(subv[i]);
2632 hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
2637 /* Lookup target in the dictionary */
2639 Tcl_DictObjGet(NULL, mapDict, subv[i], &target);
2641 Tcl_SetHashValue(hPtr, target);
2642 Tcl_IncrRefCount(target);
2648 * target was not in the dictionary so map onto the namespace.
2649 * Note in this case that we do not guarantee that the
2650 * command is actually there; that is the programmer's
2651 * responsibility (or [::unknown] of course).
2653 cmdObj = Tcl_NewStringObj(name, -1);
2654 cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
2655 Tcl_SetHashValue(hPtr, cmdPrefixObj);
2656 Tcl_IncrRefCount(cmdPrefixObj);
2659 } else if (mapDict) {
2661 * No subcmd list, but we do have a mapping dictionary so we should
2662 * use the keys of that. Convert the dictionary's contents into the
2663 * form required for the ensemble's internal hashtable.
2666 Tcl_DictSearch dictSearch;
2667 Tcl_Obj *keyObj, *valueObj;
2670 Tcl_DictObjFirst(NULL, ensemblePtr->subcommandDict, &dictSearch,
2671 &keyObj, &valueObj, &done);
2673 char *name = TclGetString(keyObj);
2675 hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
2676 Tcl_SetHashValue(hPtr, valueObj);
2677 Tcl_IncrRefCount(valueObj);
2678 Tcl_DictObjNext(&dictSearch, &keyObj, &valueObj, &done);
2682 * Discover what commands are actually exported by the namespace.
2683 * What we have is an array of patterns and a hash table whose keys
2684 * are the command names exported by the namespace (the contents do
2685 * not matter here.) We must find out what commands are actually
2686 * exported by filtering each command in the namespace against each of
2687 * the patterns in the export list. Note that we use an intermediate
2688 * hash table to make memory management easier, and because that makes
2689 * exact matching far easier too.
2691 * Suggestion for future enhancement: compute the unique prefixes and
2692 * place them in the hash too, which should make for even faster
2696 hPtr = Tcl_FirstHashEntry(&ensemblePtr->nsPtr->cmdTable, &search);
2697 for (; hPtr!= NULL ; hPtr=Tcl_NextHashEntry(&search)) {
2698 char *nsCmdName = /* Name of command in namespace. */
2699 Tcl_GetHashKey(&ensemblePtr->nsPtr->cmdTable, hPtr);
2701 for (i=0 ; i<ensemblePtr->nsPtr->numExportPatterns ; i++) {
2702 if (Tcl_StringMatch(nsCmdName,
2703 ensemblePtr->nsPtr->exportArrayPtr[i])) {
2704 hPtr = Tcl_CreateHashEntry(hash, nsCmdName, &isNew);
2707 * Remember, hash entries have a full reference to the
2708 * substituted part of the command (as a list) as their
2713 Tcl_Obj *cmdObj, *cmdPrefixObj;
2716 Tcl_AppendStringsToObj(cmdObj,
2717 ensemblePtr->nsPtr->fullName,
2718 (ensemblePtr->nsPtr->parentPtr ? "::" : ""),
2720 cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
2721 Tcl_SetHashValue(hPtr, cmdPrefixObj);
2722 Tcl_IncrRefCount(cmdPrefixObj);
2730 if (hash->numEntries == 0) {
2731 ensemblePtr->subcommandArrayPtr = NULL;
2736 * Create a sorted array of all subcommands in the ensemble; hash tables
2737 * are all very well for a quick look for an exact match, but they can't
2738 * determine things like whether a string is a prefix of another (not
2739 * without lots of preparation anyway) and they're no good for when we're
2740 * generating the error message either.
2742 * We do this by filling an array with the names (we use the hash keys
2743 * directly to save a copy, since any time we change the array we change
2744 * the hash too, and vice versa) and running quicksort over the array.
2747 ensemblePtr->subcommandArrayPtr =
2748 ckalloc(sizeof(char *) * hash->numEntries);
2751 * Fill array from both ends as this makes us less likely to end up with
2752 * performance problems in qsort(), which is good. Note that doing this
2753 * makes this code much more opaque, but the naive alternatve:
2755 * for (hPtr=Tcl_FirstHashEntry(hash,&search),i=0 ;
2756 * hPtr!=NULL ; hPtr=Tcl_NextHashEntry(&search),i++) {
2757 * ensemblePtr->subcommandArrayPtr[i] = Tcl_GetHashKey(hash, &hPtr);
2760 * can produce long runs of precisely ordered table entries when the
2761 * commands in the namespace are declared in a sorted fashion (an ordering
2762 * some people like) and the hashing functions (or the command names
2763 * themselves) are fairly unfortunate. By filling from both ends, it
2764 * requires active malice (and probably a debugger) to get qsort() to have
2765 * awful runtime behaviour.
2769 j = hash->numEntries;
2770 hPtr = Tcl_FirstHashEntry(hash, &search);
2771 while (hPtr != NULL) {
2772 ensemblePtr->subcommandArrayPtr[i++] = Tcl_GetHashKey(hash, hPtr);
2773 hPtr = Tcl_NextHashEntry(&search);
2777 ensemblePtr->subcommandArrayPtr[--j] = Tcl_GetHashKey(hash, hPtr);
2778 hPtr = Tcl_NextHashEntry(&search);
2780 if (hash->numEntries > 1) {
2781 qsort(ensemblePtr->subcommandArrayPtr, (unsigned) hash->numEntries,
2782 sizeof(char *), NsEnsembleStringOrder);
2787 *----------------------------------------------------------------------
2789 * NsEnsembleStringOrder --
2791 * Helper function to compare two pointers to two strings for use with
2795 * -1 if the first string is smaller, 1 if the second string is smaller,
2796 * and 0 if they are equal.
2801 *----------------------------------------------------------------------
2805 NsEnsembleStringOrder(
2806 const void *strPtr1,
2807 const void *strPtr2)
2809 return strcmp(*(const char **)strPtr1, *(const char **)strPtr2);
2813 *----------------------------------------------------------------------
2815 * FreeEnsembleCmdRep --
2817 * Destroys the internal representation of a Tcl_Obj that has been
2818 * holding information about a command in an ensemble.
2824 * Memory is deallocated. If this held the last reference to a
2825 * namespace's main structure, that main structure will also be
2828 *----------------------------------------------------------------------
2835 EnsembleCmdRep *ensembleCmd = objPtr->internalRep.twoPtrValue.ptr1;
2837 TclCleanupCommandMacro(ensembleCmd->token);
2838 if (ensembleCmd->fix) {
2839 Tcl_DecrRefCount(ensembleCmd->fix);
2841 ckfree(ensembleCmd);
2842 objPtr->typePtr = NULL;
2846 *----------------------------------------------------------------------
2848 * DupEnsembleCmdRep --
2850 * Makes one Tcl_Obj into a copy of another that is a subcommand of an
2857 * Memory is allocated, and the namespace that the ensemble is built on
2858 * top of gains another reference.
2860 *----------------------------------------------------------------------
2868 EnsembleCmdRep *ensembleCmd = objPtr->internalRep.twoPtrValue.ptr1;
2869 EnsembleCmdRep *ensembleCopy = ckalloc(sizeof(EnsembleCmdRep));
2871 copyPtr->typePtr = &ensembleCmdType;
2872 copyPtr->internalRep.twoPtrValue.ptr1 = ensembleCopy;
2873 ensembleCopy->epoch = ensembleCmd->epoch;
2874 ensembleCopy->token = ensembleCmd->token;
2875 ensembleCopy->token->refCount++;
2876 ensembleCopy->fix = ensembleCmd->fix;
2877 if (ensembleCopy->fix) {
2878 Tcl_IncrRefCount(ensembleCopy->fix);
2880 ensembleCopy->hPtr = ensembleCmd->hPtr;
2884 *----------------------------------------------------------------------
2886 * TclCompileEnsemble --
2888 * Procedure called to compile an ensemble command. Note that most
2889 * ensembles are not compiled, since modifying a compiled ensemble causes
2890 * a invalidation of all existing bytecode (expensive!) which is not
2891 * normally warranted.
2894 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
2895 * evaluation to runtime.
2898 * Instructions are added to envPtr to execute the subcommands of the
2899 * ensemble at runtime if a compile-time mapping is possible.
2901 *----------------------------------------------------------------------
2906 Tcl_Interp *interp, /* Used for error reporting. */
2907 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
2908 * created by Tcl_ParseCommand. */
2909 Command *cmdPtr, /* Points to defintion of command being
2911 CompileEnv *envPtr) /* Holds resulting instructions. */
2913 DefineLineInformation;
2914 Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
2915 Tcl_Obj *mapObj, *subcmdObj, *targetCmdObj, *listObj, **elems;
2916 Tcl_Obj *replaced = Tcl_NewObj(), *replacement;
2917 Tcl_Command ensemble = (Tcl_Command) cmdPtr;
2918 Command *oldCmdPtr = cmdPtr, *newCmdPtr;
2919 int len, result, flags = 0, i, depth = 1, invokeAnyway = 0;
2920 int ourResult = TCL_ERROR;
2924 Tcl_IncrRefCount(replaced);
2925 if (parsePtr->numWords < depth + 1) {
2928 if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
2937 * This is where we return to if we are parsing multiple nested compiled
2938 * ensembles. [info object] is such a beast.
2942 word = tokenPtr[1].start;
2943 numBytes = tokenPtr[1].size;
2946 * There's a sporting chance we'll be able to compile this. But now we
2947 * must check properly. To do that, check that we're compiling an ensemble
2948 * that has a compilable command as its appropriate subcommand.
2951 if (Tcl_GetEnsembleMappingDict(NULL, ensemble, &mapObj) != TCL_OK
2952 || mapObj == NULL) {
2954 * Either not an ensemble or a mapping isn't installed. Crud. Too hard
2962 * Also refuse to compile anything that uses a formal parameter list for
2963 * now, on the grounds that it is too complex.
2966 if (Tcl_GetEnsembleParameterList(NULL, ensemble, &listObj) != TCL_OK
2967 || listObj != NULL) {
2969 * Figuring out how to compile this has become too much. Bail out.
2976 * Next, get the flags. We need them on several code paths so that we can
2977 * know whether we're to do prefix matching.
2980 (void) Tcl_GetEnsembleFlags(NULL, ensemble, &flags);
2983 * Check to see if there's also a subcommand list; must check to see if
2984 * the subcommand we are calling is in that list if it exists, since that
2985 * list filters the entries in the map.
2988 (void) Tcl_GetEnsembleSubcommandList(NULL, ensemble, &listObj);
2989 if (listObj != NULL) {
2992 Tcl_Obj *matchObj = NULL;
2994 if (Tcl_ListObjGetElements(NULL, listObj, &len, &elems) != TCL_OK) {
2997 for (i=0 ; i<len ; i++) {
2998 str = Tcl_GetStringFromObj(elems[i], &sclen);
2999 if ((sclen == (int) numBytes) && !memcmp(word, str, numBytes)) {
3001 * Exact match! Excellent!
3004 result = Tcl_DictObjGet(NULL, mapObj,elems[i], &targetCmdObj);
3005 if (result != TCL_OK || targetCmdObj == NULL) {
3008 replacement = elems[i];
3013 * Check to see if we've got a prefix match. A single prefix match
3014 * is fine, and allows us to refine our dictionary lookup, but
3015 * multiple prefix matches is a Bad Thing and will prevent us from
3016 * making progress. Note that we cannot do the lookup immediately
3017 * in the prefix case; might be another entry later in the list
3018 * that causes things to fail.
3021 if ((flags & TCL_ENSEMBLE_PREFIX)
3022 && strncmp(word, str, numBytes) == 0) {
3023 if (matchObj != NULL) {
3026 matchObj = elems[i];
3029 if (matchObj == NULL) {
3032 result = Tcl_DictObjGet(NULL, mapObj, matchObj, &targetCmdObj);
3033 if (result != TCL_OK || targetCmdObj == NULL) {
3036 replacement = matchObj;
3043 * No map, so check the dictionary directly.
3046 TclNewStringObj(subcmdObj, word, (int) numBytes);
3047 result = Tcl_DictObjGet(NULL, mapObj, subcmdObj, &targetCmdObj);
3048 if (result == TCL_OK && targetCmdObj != NULL) {
3050 * Got it. Skip the fiddling around with prefixes.
3053 replacement = subcmdObj;
3056 TclDecrRefCount(subcmdObj);
3059 * We've not literally got a valid subcommand. But maybe we have a
3060 * prefix. Check if prefix matches are allowed.
3063 if (!(flags & TCL_ENSEMBLE_PREFIX)) {
3068 * Iterate over the keys in the dictionary, checking to see if we're a
3072 Tcl_DictObjFirst(NULL, mapObj, &s, &subcmdObj, &tmpObj, &done);
3074 replacement = NULL; /* Silence, fool compiler! */
3076 if (strncmp(TclGetString(subcmdObj), word, numBytes) == 0) {
3079 * Must have matched twice! Not unique, so no point
3085 replacement = subcmdObj;
3086 targetCmdObj = tmpObj;
3088 Tcl_DictObjNext(&s, &subcmdObj, &tmpObj, &done);
3090 Tcl_DictObjDone(&s);
3093 * If we have anything other than a single match, we've failed the
3094 * unique prefix check.
3104 * OK, we definitely map to something. But what?
3106 * The command we map to is the first word out of the map element. Note
3107 * that we also reject dealing with multi-element rewrites if we are in a
3108 * safe interpreter, as there is otherwise a (highly gnarly!) way to make
3109 * Tcl crash open to exploit.
3113 Tcl_ListObjAppendElement(NULL, replaced, replacement);
3114 if (Tcl_ListObjGetElements(NULL, targetCmdObj, &len, &elems) != TCL_OK) {
3116 } else if (len != 1) {
3118 * Note that at this point we know we can't issue any special
3119 * instruction sequence as the mapping isn't one that we support at
3120 * the compiled level.
3125 targetCmdObj = elems[0];
3128 Tcl_IncrRefCount(targetCmdObj);
3129 newCmdPtr = (Command *) Tcl_GetCommandFromObj(interp, targetCmdObj);
3130 TclDecrRefCount(targetCmdObj);
3131 if (newCmdPtr == NULL || Tcl_IsSafe(interp)
3132 || newCmdPtr->nsPtr->flags & NS_SUPPRESS_COMPILATION
3133 || newCmdPtr->flags & CMD_HAS_EXEC_TRACES
3134 || ((Interp *)interp)->flags & DONT_COMPILE_CMDS_INLINE) {
3136 * Maps to an undefined command or a command without a compiler.
3146 * See whether we have a nested ensemble. If we do, we can go round the
3147 * mulberry bush again, consuming the next word.
3150 if (cmdPtr->compileProc == TclCompileEnsemble) {
3151 tokenPtr = TokenAfter(tokenPtr);
3152 if (parsePtr->numWords < depth + 1
3153 || tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
3155 * Too hard because the user has done something unpleasant like
3156 * omitting the sub-ensemble's command name or used a non-constant
3157 * name for a sub-ensemble's command name; we respond by bailing
3158 * out completely (this is a rare case). [Bug 6d2f249a01]
3163 ensemble = (Tcl_Command) cmdPtr;
3168 * Now we've done the mapping process, can now actually try to compile.
3169 * If there is a subcommand compiler and that successfully produces code,
3170 * we'll use that. Otherwise, we fall back to generating opcodes to do the
3171 * invoke at runtime.
3175 if (TCL_OK == TclAttemptCompileProc(interp, parsePtr, depth, cmdPtr,
3182 * Throw out any line information generated by the failed compile attempt.
3185 while (mapPtr->nuloc - 1 > eclIndex) {
3187 ckfree(mapPtr->loc[mapPtr->nuloc].line);
3188 mapPtr->loc[mapPtr->nuloc].line = NULL;
3192 * Reset the index of next command. Toss out any from failed nested
3196 envPtr->numCommands = mapPtr->nuloc;
3199 * Failed to do a full compile for some reason. Try to do a direct invoke
3200 * instead of going through the ensemble lookup process again.
3206 if (!invokeAnyway) {
3212 * The length of the "replaced" list must be depth-1. Trim back
3213 * any extra elements that might have been appended by failing
3216 (void) Tcl_ListObjReplace(NULL, replaced, depth-1, LIST_MAX, 0, NULL);
3219 * TODO: Reconsider whether we ought to call CompileToInvokedCommand()
3220 * when depth==1. In that case we are choosing to emit the
3221 * INST_INVOKE_REPLACE bytecode when there is in fact no replacing
3222 * to be done. It would be equally functional and presumably more
3223 * performant to fall through to cleanup below, return TCL_ERROR,
3224 * and let the compiler harness emit the INST_INVOKE_STK
3225 * implementation for us.
3228 CompileToInvokedCommand(interp, parsePtr, replaced, cmdPtr, envPtr);
3233 * Release the memory we allocated. If we've got here, we've either done
3234 * something useful or we're in a case that we can't compile at all and
3235 * we're just giving up.
3239 Tcl_DecrRefCount(replaced);
3244 TclAttemptCompileProc(
3246 Tcl_Parse *parsePtr,
3249 CompileEnv *envPtr) /* Holds resulting instructions. */
3251 DefineLineInformation;
3253 Tcl_Token *saveTokenPtr = parsePtr->tokenPtr;
3254 int savedStackDepth = envPtr->currStackDepth;
3255 unsigned savedCodeNext = envPtr->codeNext - envPtr->codeStart;
3256 int savedAuxDataArrayNext = envPtr->auxDataArrayNext;
3257 int savedExceptArrayNext = envPtr->exceptArrayNext;
3258 #ifdef TCL_COMPILE_DEBUG
3259 int savedExceptDepth = envPtr->exceptDepth;
3262 if (cmdPtr->compileProc == NULL) {
3267 * Advance parsePtr->tokenPtr so that it points at the last subcommand.
3268 * This will be wrong, but it will not matter, and it will put the
3269 * tokens for the arguments in the right place without the needed to
3270 * allocate a synthetic Tcl_Parse struct, or copy tokens around.
3273 for (i = 0; i < depth - 1; i++) {
3274 parsePtr->tokenPtr = TokenAfter(parsePtr->tokenPtr);
3276 parsePtr->numWords -= (depth - 1);
3279 * Shift the line information arrays to account for different word
3283 mapPtr->loc[eclIndex].line += (depth - 1);
3284 mapPtr->loc[eclIndex].next += (depth - 1);
3287 * Hand off compilation to the subcommand compiler. At last!
3290 result = cmdPtr->compileProc(interp, parsePtr, cmdPtr, envPtr);
3296 mapPtr->loc[eclIndex].line -= (depth - 1);
3297 mapPtr->loc[eclIndex].next -= (depth - 1);
3299 parsePtr->numWords += (depth - 1);
3300 parsePtr->tokenPtr = saveTokenPtr;
3303 * If our target failed to compile, revert any data from failed partial
3304 * compiles. Note that envPtr->numCommands need not be checked because
3305 * we avoid compiling subcommands that recursively call TclCompileScript().
3308 #ifdef TCL_COMPILE_DEBUG
3309 if (envPtr->exceptDepth != savedExceptDepth) {
3310 Tcl_Panic("ExceptionRange Starts and Ends do not balance");
3314 if (result != TCL_OK) {
3315 ExceptionAux *auxPtr = envPtr->exceptAuxArrayPtr;
3317 for (i = 0; i < savedExceptArrayNext; i++) {
3318 while (auxPtr->numBreakTargets > 0
3319 && auxPtr->breakTargets[auxPtr->numBreakTargets - 1]
3321 auxPtr->numBreakTargets--;
3323 while (auxPtr->numContinueTargets > 0
3324 && auxPtr->continueTargets[auxPtr->numContinueTargets - 1]
3326 auxPtr->numContinueTargets--;
3330 envPtr->exceptArrayNext = savedExceptArrayNext;
3332 if (savedAuxDataArrayNext != envPtr->auxDataArrayNext) {
3333 AuxData *auxDataPtr = envPtr->auxDataArrayPtr;
3334 AuxData *auxDataEnd = auxDataPtr;
3336 auxDataPtr += savedAuxDataArrayNext;
3337 auxDataEnd += envPtr->auxDataArrayNext;
3339 while (auxDataPtr < auxDataEnd) {
3340 if (auxDataPtr->type->freeProc != NULL) {
3341 auxDataPtr->type->freeProc(auxDataPtr->clientData);
3345 envPtr->auxDataArrayNext = savedAuxDataArrayNext;
3347 envPtr->currStackDepth = savedStackDepth;
3348 envPtr->codeNext = envPtr->codeStart + savedCodeNext;
3349 #ifdef TCL_COMPILE_DEBUG
3352 * Confirm that the command compiler generated a single value on
3353 * the stack as its result. This is only done in debugging mode,
3354 * as it *should* be correct and normal users have no reasonable
3355 * way to fix it anyway.
3358 int diff = envPtr->currStackDepth - savedStackDepth;
3361 Tcl_Panic("bad stack adjustment when compiling"
3362 " %.*s (was %d instead of 1)", parsePtr->tokenPtr->size,
3363 parsePtr->tokenPtr->start, diff);
3372 * How to compile a subcommand to a _replacing_ invoke of its implementation
3377 CompileToInvokedCommand(
3379 Tcl_Parse *parsePtr,
3380 Tcl_Obj *replacements,
3382 CompileEnv *envPtr) /* Holds resulting instructions. */
3384 DefineLineInformation;
3386 Tcl_Obj *objPtr, **words;
3388 int length, i, numWords, cmdLit, extraLiteralFlags = LITERAL_CMD_NAME;
3391 * Push the words of the command. Take care; the command words may be
3392 * scripts that have backslashes in them, and [info frame 0] can see the
3393 * difference. Hence the call to TclContinuationsEnterDerived...
3396 Tcl_ListObjGetElements(NULL, replacements, &numWords, &words);
3397 for (i = 0, tokPtr = parsePtr->tokenPtr; i < parsePtr->numWords;
3398 i++, tokPtr = TokenAfter(tokPtr)) {
3399 if (i > 0 && i < numWords+1) {
3400 bytes = Tcl_GetStringFromObj(words[i-1], &length);
3401 PushLiteral(envPtr, bytes, length);
3405 SetLineInformation(i);
3406 if (tokPtr->type == TCL_TOKEN_SIMPLE_WORD) {
3407 int literal = TclRegisterNewLiteral(envPtr,
3408 tokPtr[1].start, tokPtr[1].size);
3410 if (envPtr->clNext) {
3411 TclContinuationsEnterDerived(
3412 TclFetchLiteral(envPtr, literal),
3413 tokPtr[1].start - envPtr->source,
3416 TclEmitPush(literal, envPtr);
3418 CompileTokens(envPtr, tokPtr, interp);
3423 * Push the name of the command we're actually dispatching to as part of
3424 * the implementation.
3427 objPtr = Tcl_NewObj();
3428 Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr);
3429 bytes = Tcl_GetStringFromObj(objPtr, &length);
3430 if ((cmdPtr != NULL) && (cmdPtr->flags & CMD_VIA_RESOLVER)) {
3431 extraLiteralFlags |= LITERAL_UNSHARED;
3433 cmdLit = TclRegisterLiteral(envPtr, (char *)bytes, length, extraLiteralFlags);
3434 TclSetCmdNameObj(interp, TclFetchLiteral(envPtr, cmdLit), cmdPtr);
3435 TclEmitPush(cmdLit, envPtr);
3436 TclDecrRefCount(objPtr);
3439 * Do the replacing dispatch.
3442 TclEmitInvoke(envPtr, INST_INVOKE_REPLACE, parsePtr->numWords,numWords+1);
3446 * Helpers that do issuing of instructions for commands that "don't have
3447 * compilers" (well, they do; these). They all work by just generating base
3448 * code to invoke the command; they're intended for ensemble subcommands so
3449 * that the costs of INST_INVOKE_REPLACE can be avoided where we can work out
3450 * that they're not needed.
3452 * Note that these are NOT suitable for commands where there's an argument
3453 * that is a script, as an [info level] or [info frame] in the inner context
3454 * can see the difference.
3458 CompileBasicNArgCommand(
3459 Tcl_Interp *interp, /* Used for error reporting. */
3460 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3461 * created by Tcl_ParseCommand. */
3462 Command *cmdPtr, /* Points to defintion of command being
3464 CompileEnv *envPtr) /* Holds resulting instructions. */
3466 Tcl_Obj *objPtr = Tcl_NewObj();
3468 Tcl_IncrRefCount(objPtr);
3469 Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr);
3470 TclCompileInvocation(interp, parsePtr->tokenPtr, objPtr,
3471 parsePtr->numWords, envPtr);
3472 Tcl_DecrRefCount(objPtr);
3477 TclCompileBasic0ArgCmd(
3478 Tcl_Interp *interp, /* Used for error reporting. */
3479 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3480 * created by Tcl_ParseCommand. */
3481 Command *cmdPtr, /* Points to defintion of command being
3483 CompileEnv *envPtr) /* Holds resulting instructions. */
3486 * Verify that the number of arguments is correct; that's the only case
3487 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3488 * which is the only code that sees the shenanigans of ensemble dispatch.
3491 if (parsePtr->numWords != 1) {
3495 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
3499 TclCompileBasic1ArgCmd(
3500 Tcl_Interp *interp, /* Used for error reporting. */
3501 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3502 * created by Tcl_ParseCommand. */
3503 Command *cmdPtr, /* Points to defintion of command being
3505 CompileEnv *envPtr) /* Holds resulting instructions. */
3508 * Verify that the number of arguments is correct; that's the only case
3509 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3510 * which is the only code that sees the shenanigans of ensemble dispatch.
3513 if (parsePtr->numWords != 2) {
3517 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
3521 TclCompileBasic2ArgCmd(
3522 Tcl_Interp *interp, /* Used for error reporting. */
3523 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3524 * created by Tcl_ParseCommand. */
3525 Command *cmdPtr, /* Points to defintion of command being
3527 CompileEnv *envPtr) /* Holds resulting instructions. */
3530 * Verify that the number of arguments is correct; that's the only case
3531 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3532 * which is the only code that sees the shenanigans of ensemble dispatch.
3535 if (parsePtr->numWords != 3) {
3539 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
3543 TclCompileBasic3ArgCmd(
3544 Tcl_Interp *interp, /* Used for error reporting. */
3545 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3546 * created by Tcl_ParseCommand. */
3547 Command *cmdPtr, /* Points to defintion of command being
3549 CompileEnv *envPtr) /* Holds resulting instructions. */
3552 * Verify that the number of arguments is correct; that's the only case
3553 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3554 * which is the only code that sees the shenanigans of ensemble dispatch.
3557 if (parsePtr->numWords != 4) {
3561 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
3565 TclCompileBasic0Or1ArgCmd(
3566 Tcl_Interp *interp, /* Used for error reporting. */
3567 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3568 * created by Tcl_ParseCommand. */
3569 Command *cmdPtr, /* Points to defintion of command being
3571 CompileEnv *envPtr) /* Holds resulting instructions. */
3574 * Verify that the number of arguments is correct; that's the only case
3575 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3576 * which is the only code that sees the shenanigans of ensemble dispatch.
3579 if (parsePtr->numWords != 1 && parsePtr->numWords != 2) {
3583 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
3587 TclCompileBasic1Or2ArgCmd(
3588 Tcl_Interp *interp, /* Used for error reporting. */
3589 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3590 * created by Tcl_ParseCommand. */
3591 Command *cmdPtr, /* Points to defintion of command being
3593 CompileEnv *envPtr) /* Holds resulting instructions. */
3596 * Verify that the number of arguments is correct; that's the only case
3597 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3598 * which is the only code that sees the shenanigans of ensemble dispatch.
3601 if (parsePtr->numWords != 2 && parsePtr->numWords != 3) {
3605 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
3609 TclCompileBasic2Or3ArgCmd(
3610 Tcl_Interp *interp, /* Used for error reporting. */
3611 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3612 * created by Tcl_ParseCommand. */
3613 Command *cmdPtr, /* Points to defintion of command being
3615 CompileEnv *envPtr) /* Holds resulting instructions. */
3618 * Verify that the number of arguments is correct; that's the only case
3619 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3620 * which is the only code that sees the shenanigans of ensemble dispatch.
3623 if (parsePtr->numWords != 3 && parsePtr->numWords != 4) {
3627 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
3631 TclCompileBasic0To2ArgCmd(
3632 Tcl_Interp *interp, /* Used for error reporting. */
3633 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3634 * created by Tcl_ParseCommand. */
3635 Command *cmdPtr, /* Points to defintion of command being
3637 CompileEnv *envPtr) /* Holds resulting instructions. */
3640 * Verify that the number of arguments is correct; that's the only case
3641 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3642 * which is the only code that sees the shenanigans of ensemble dispatch.
3645 if (parsePtr->numWords < 1 || parsePtr->numWords > 3) {
3649 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
3653 TclCompileBasic1To3ArgCmd(
3654 Tcl_Interp *interp, /* Used for error reporting. */
3655 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3656 * created by Tcl_ParseCommand. */
3657 Command *cmdPtr, /* Points to defintion of command being
3659 CompileEnv *envPtr) /* Holds resulting instructions. */
3662 * Verify that the number of arguments is correct; that's the only case
3663 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3664 * which is the only code that sees the shenanigans of ensemble dispatch.
3667 if (parsePtr->numWords < 2 || parsePtr->numWords > 4) {
3671 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
3675 TclCompileBasicMin0ArgCmd(
3676 Tcl_Interp *interp, /* Used for error reporting. */
3677 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3678 * created by Tcl_ParseCommand. */
3679 Command *cmdPtr, /* Points to defintion of command being
3681 CompileEnv *envPtr) /* Holds resulting instructions. */
3684 * Verify that the number of arguments is correct; that's the only case
3685 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3686 * which is the only code that sees the shenanigans of ensemble dispatch.
3689 if (parsePtr->numWords < 1) {
3693 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
3697 TclCompileBasicMin1ArgCmd(
3698 Tcl_Interp *interp, /* Used for error reporting. */
3699 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3700 * created by Tcl_ParseCommand. */
3701 Command *cmdPtr, /* Points to defintion of command being
3703 CompileEnv *envPtr) /* Holds resulting instructions. */
3706 * Verify that the number of arguments is correct; that's the only case
3707 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3708 * which is the only code that sees the shenanigans of ensemble dispatch.
3711 if (parsePtr->numWords < 2) {
3715 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
3719 TclCompileBasicMin2ArgCmd(
3720 Tcl_Interp *interp, /* Used for error reporting. */
3721 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
3722 * created by Tcl_ParseCommand. */
3723 Command *cmdPtr, /* Points to defintion of command being
3725 CompileEnv *envPtr) /* Holds resulting instructions. */
3728 * Verify that the number of arguments is correct; that's the only case
3729 * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
3730 * which is the only code that sees the shenanigans of ensemble dispatch.
3733 if (parsePtr->numWords < 3) {
3737 return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);