/// <summary> Chain this frame into the call frame stack and binds the parameters /// values to the formal parameters of the procedure. /// /// </summary> /// <param name="proc">the procedure. /// </param> /// <param name="proc">argv the parameter values. /// </param> /// <exception cref=""> TclException if wrong number of arguments. /// </exception> internal void chain( Procedure proc, TclObject[] objv ) { // FIXME: double check this ns thing in case where proc is renamed to different ns. this.ns = proc.ns; this.objv = objv; // FIXME : quick level hack : fix later level = ( interp.varFrame == null ) ? 1 : ( interp.varFrame.level + 1 ); caller = interp.frame; callerVar = interp.varFrame; interp.frame = this; interp.varFrame = this; // parameter bindings int numArgs = proc.argList.Length; if ( ( !proc.isVarArgs ) && ( objv.Length - 1 > numArgs ) ) { wrongNumProcArgs( objv[0], proc ); } int i, j; for ( i = 0, j = 1; i < numArgs; i++, j++ ) { // Handle the special case of the last formal being // "args". When it occurs, assign it a list consisting of // all the remaining actual arguments. TclObject varName = proc.argList[i][0]; TclObject value = null; if ( ( i == ( numArgs - 1 ) ) && proc.isVarArgs ) { value = TclList.newInstance(); value.preserve(); for ( int k = j; k < objv.Length; k++ ) { TclList.append( interp, value, objv[k] ); } interp.setVar( varName, value, 0 ); value.release(); } else { if ( j < objv.Length ) { value = objv[j]; } else if ( proc.argList[i][1] != null ) { value = proc.argList[i][1]; } else { wrongNumProcArgs( objv[0], proc ); } interp.setVar( varName, value, 0 ); } } }
internal Procedure(Interp interp, NamespaceCmd.Namespace ns, string name, TclObject args, TclObject b, string sFileName, int sLineNumber) { this.NS = ns; srcFileName = sFileName; srcLineNumber = sLineNumber; // Break up the argument list into argument specifiers, then process // each argument specifier. int numArgs = TclList.getLength(interp, args); ArgList = new TclObject[numArgs][]; for (int i = 0; i < numArgs; i++) { ArgList[i] = new TclObject[2]; } for (int i = 0; i < numArgs; i++) { // Now divide the specifier up into name and default. TclObject argSpec = TclList.index(interp, args, i); int specLen = TclList.getLength(interp, argSpec); if (specLen == 0) { throw new TclException(interp, "procedure \"" + name + "\" has argument with no name"); } if (specLen > 2) { throw new TclException(interp, "too many fields in argument " + "specifier \"" + argSpec + "\""); } ArgList[i][0] = TclList.index(interp, argSpec, 0); ArgList[i][0].Preserve(); if (specLen == 2) { ArgList[i][1] = TclList.index(interp, argSpec, 1); ArgList[i][1].Preserve(); } else { ArgList[i][1] = null; } } if (numArgs > 0 && (ArgList[numArgs - 1][0].ToString().Equals("args"))) { isVarArgs = true; } else { isVarArgs = false; } body = new CharPointer(b.ToString()); body_length = body.Length(); }
protected internal Hashtable VarTable; // Stores the variables of this CallFrame. /// <summary> /// Creates a CallFrame for the global variables.</summary> /// <param name="interp"> /// current interpreter. /// </param> internal CallFrame(Interp i) { Interp = i; NS = i.GlobalNS; VarTable = new Hashtable(); Caller = null; CallerVar = null; Objv = null; Level = 0; IsProcCallFrame = true; }
/// <summary> Creates a CallFrame for the global variables.</summary> /// <param name="interp">current interpreter. /// </param> internal CallFrame(Interp i) { interp = i; ns = i.globalNs; varTable = new Hashtable(); caller = null; callerVar = null; objv = null; level = 0; isProcCallFrame = true; }
/// <summary> /// Chain this frame into the call frame stack and binds the parameters values to the formal parameters of the procedure. /// </summary> /// <param name="proc"> /// the procedure. /// </param> /// <param name="proc"> /// argv the parameter values. /// </param> /// <exception cref=""> /// TclException if wrong number of arguments. /// </exception> internal void Chain(Procedure proc, TclObject[] objv) { // FIXME: double check this ns thing in case where proc is renamed to different ns. NS = proc.NS; Objv = objv; // FIXME : quick level hack : fix later Level = (Interp.VarFrame == null ? 1 : Interp.VarFrame.Level + 1); Caller = Interp.Frame; CallerVar = Interp.VarFrame; Interp.Frame = this; Interp.VarFrame = this; // parameter bindings int numArgs = proc.ArgList.Length; if (!proc.isVarArgs && objv.Length - 1 > numArgs) { WrongNumProcArgs(objv[0], proc); } for (int i = 0, j = 1; i < numArgs; i++, j++) { // Handle the special case of the last formal being "args". When it occurs, assign it a list consisting of // all the remaining actual arguments. TclObject varName = proc.ArgList[i][0]; TclObject value = null; if (i == (numArgs - 1) && proc.isVarArgs) { value = TclList.NewInstance(); value.Preserve(); for (int k = j; k < objv.Length; k++) { TclList.Append(Interp, value, objv[k]); } Interp.SetVar(varName, value, 0); value.Release(); } else { if (j < objv.Length) { value = objv[j]; } else if (proc.ArgList[i][1] != null) { value = proc.ArgList[i][1]; } else { WrongNumProcArgs(objv[0], proc); } Interp.SetVar(varName, value, 0); } } }
/* *---------------------------------------------------------------------- * * InfoProcsCmd -- * * Called to implement the "info procs" command that returns the * procedures in the current namespace that match an optional pattern. * Handles the following syntax: * * info procs ?pattern? * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoProcsCmd(Interp interp, TclObject[] objv) { string cmdName, pattern; NamespaceCmd.Namespace currNs = NamespaceCmd.getCurrentNamespace(interp); IDictionaryEnumerator search; WrappedCommand cmd, realCmd; TclObject list; if (objv.Length == 2) { pattern = null; } else if (objv.Length == 3) { pattern = objv[2].ToString(); } else { throw new TclNumArgsException(interp, 2, objv, "?pattern?"); } // Scan through the current namespace's command table and return a list // of all procs that match the pattern. list = TclList.newInstance(); for (search = currNs.cmdTable.GetEnumerator(); search.MoveNext();) { cmdName = ((string)search.Key); cmd = (WrappedCommand)search.Value; // If the command isn't itself a proc, it still might be an // imported command that points to a "real" proc in a different // namespace. realCmd = NamespaceCmd.getOriginalCommand(cmd); if (Procedure.isProc(cmd) || ((realCmd != null) && Procedure.isProc(realCmd))) { if (((System.Object)pattern == null) || Util.stringMatch(cmdName, pattern)) { TclList.append(interp, list, TclString.newInstance(cmdName)); } } } interp.setResult(list); return; }
/* *---------------------------------------------------------------------- * * InfoGlobalsCmd -- * * Called to implement the "info globals" command that returns the list * of global variables matching an optional pattern. Handles the * following syntax: * * info globals ?pattern?* * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoGlobalsCmd(Interp interp, TclObject[] objv) { string varName, pattern; NamespaceCmd.Namespace globalNs = NamespaceCmd.getGlobalNamespace(interp); IDictionaryEnumerator search; Var var; TclObject list; if (objv.Length == 2) { pattern = null; } else if (objv.Length == 3) { pattern = objv[2].ToString(); } else { throw new TclNumArgsException(interp, 2, objv, "?pattern?"); } // Scan through the global :: namespace's variable table and create a // list of all global variables that match the pattern. list = TclList.newInstance(); for (search = globalNs.varTable.GetEnumerator(); search.MoveNext();) { varName = ((string)search.Key); var = (Var)search.Value; if (var.isVarUndefined()) { continue; } if (((System.Object)pattern == null) || Util.stringMatch(varName, pattern)) { TclList.append(interp, list, TclString.newInstance(varName)); } } interp.setResult(list); return; }
/* *---------------------------------------------------------------------- * * InfoCommandsCmd -- * * Called to implement the "info commands" command that returns the * list of commands in the interpreter that match an optional pattern. * The pattern, if any, consists of an optional sequence of namespace * names separated by "::" qualifiers, which is followed by a * glob-style pattern that restricts which commands are returned. * Handles the following syntax: * * info commands ?pattern? * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoCommandsCmd(Interp interp, TclObject[] objv) { string cmdName, pattern, simplePattern; IDictionaryEnumerator search; NamespaceCmd.Namespace ns; NamespaceCmd.Namespace globalNs = NamespaceCmd.getGlobalNamespace(interp); NamespaceCmd.Namespace currNs = NamespaceCmd.getCurrentNamespace(interp); TclObject list, elemObj; bool specificNsInPattern = false; // Init. to avoid compiler warning. WrappedCommand cmd; // Get the pattern and find the "effective namespace" in which to // list commands. if (objv.Length == 2) { simplePattern = null; ns = currNs; specificNsInPattern = false; } else if (objv.Length == 3) { // From the pattern, get the effective namespace and the simple // pattern (no namespace qualifiers or ::'s) at the end. If an // error was found while parsing the pattern, return it. Otherwise, // if the namespace wasn't found, just leave ns NULL: we will // return an empty list since no commands there can be found. pattern = objv[2].ToString(); // Java does not support passing an address so we pass // an array of size 1 and then assign arr[0] to the value NamespaceCmd.Namespace[] nsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummy1Arr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummy2Arr = new NamespaceCmd.Namespace[1]; string[] simplePatternArr = new string[1]; NamespaceCmd.getNamespaceForQualName(interp, pattern, null, 0, nsArr, dummy1Arr, dummy2Arr, simplePatternArr); // Get the values out of the arrays! ns = nsArr[0]; simplePattern = simplePatternArr[0]; if (ns != null) { // we successfully found the pattern's ns specificNsInPattern = (simplePattern.CompareTo(pattern) != 0); } } else { throw new TclNumArgsException(interp, 2, objv, "?pattern?"); } // Scan through the effective namespace's command table and create a // list with all commands that match the pattern. If a specific // namespace was requested in the pattern, qualify the command names // with the namespace name. list = TclList.newInstance(); if (ns != null) { search = ns.cmdTable.GetEnumerator(); while (search.MoveNext()) { cmdName = ((string)search.Key); if (((System.Object)simplePattern == null) || Util.stringMatch(cmdName, simplePattern)) { if (specificNsInPattern) { cmd = (WrappedCommand)search.Value; elemObj = TclString.newInstance(interp.getCommandFullName(cmd)); } else { elemObj = TclString.newInstance(cmdName); } TclList.append(interp, list, elemObj); } } // If the effective namespace isn't the global :: namespace, and a // specific namespace wasn't requested in the pattern, then add in // all global :: commands that match the simple pattern. Of course, // we add in only those commands that aren't hidden by a command in // the effective namespace. if ((ns != globalNs) && !specificNsInPattern) { search = globalNs.cmdTable.GetEnumerator(); while (search.MoveNext()) { cmdName = ((string)search.Key); if (((System.Object)simplePattern == null) || Util.stringMatch(cmdName, simplePattern)) { if (ns.cmdTable[cmdName] == null) { TclList.append(interp, list, TclString.newInstance(cmdName)); } } } } } interp.setResult(list); return; }
/* *---------------------------------------------------------------------- * * InfoVarsCmd -- * * Called to implement the "info vars" command that returns the * list of variables in the interpreter that match an optional pattern. * The pattern, if any, consists of an optional sequence of namespace * names separated by "::" qualifiers, which is followed by a * glob-style pattern that restricts which variables are returned. * Handles the following syntax: * * info vars ?pattern? * * Results: * Returns if successful, raises TclException otherwise. * * Side effects: * Returns a result in the interpreter's result object. * *---------------------------------------------------------------------- */ private static void InfoVarsCmd(Interp interp, TclObject[] objv) { string varName, pattern, simplePattern; IDictionaryEnumerator search; Var var; NamespaceCmd.Namespace ns; NamespaceCmd.Namespace globalNs = NamespaceCmd.getGlobalNamespace(interp); NamespaceCmd.Namespace currNs = NamespaceCmd.getCurrentNamespace(interp); TclObject list, elemObj; bool specificNsInPattern = false; // Init. to avoid compiler warning. // Get the pattern and find the "effective namespace" in which to // list variables. We only use this effective namespace if there's // no active Tcl procedure frame. if (objv.Length == 2) { simplePattern = null; ns = currNs; specificNsInPattern = false; } else if (objv.Length == 3) { // From the pattern, get the effective namespace and the simple // pattern (no namespace qualifiers or ::'s) at the end. If an // error was found while parsing the pattern, return it. Otherwise, // if the namespace wasn't found, just leave ns = null: we will // return an empty list since no variables there can be found. pattern = objv[2].ToString(); // Java does not support passing an address so we pass // an array of size 1 and then assign arr[0] to the value NamespaceCmd.Namespace[] nsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummy1Arr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummy2Arr = new NamespaceCmd.Namespace[1]; string[] simplePatternArr = new string[1]; NamespaceCmd.getNamespaceForQualName(interp, pattern, null, 0, nsArr, dummy1Arr, dummy2Arr, simplePatternArr); // Get the values out of the arrays! ns = nsArr[0]; simplePattern = simplePatternArr[0]; if (ns != null) { // we successfully found the pattern's ns specificNsInPattern = (simplePattern.CompareTo(pattern) != 0); } } else { throw new TclNumArgsException(interp, 2, objv, "?pattern?"); } // If the namespace specified in the pattern wasn't found, just return. if (ns == null) { return; } list = TclList.newInstance(); if ((interp.varFrame == null) || !interp.varFrame.isProcCallFrame || specificNsInPattern) { // There is no frame pointer, the frame pointer was pushed only // to activate a namespace, or we are in a procedure call frame // but a specific namespace was specified. Create a list containing // only the variables in the effective namespace's variable table. search = ns.varTable.GetEnumerator(); while (search.MoveNext()) { varName = ((string)search.Key); var = (Var)search.Value; if (!var.isVarUndefined() || ((var.flags & VarFlags.NAMESPACE_VAR) != 0)) { if (((System.Object)simplePattern == null) || Util.stringMatch(varName, simplePattern)) { if (specificNsInPattern) { elemObj = TclString.newInstance(Var.getVariableFullName(interp, var)); } else { elemObj = TclString.newInstance(varName); } TclList.append(interp, list, elemObj); } } } // If the effective namespace isn't the global :: namespace, and a // specific namespace wasn't requested in the pattern (i.e., the // pattern only specifies variable names), then add in all global :: // variables that match the simple pattern. Of course, add in only // those variables that aren't hidden by a variable in the effective // namespace. if ((ns != globalNs) && !specificNsInPattern) { search = globalNs.varTable.GetEnumerator(); while (search.MoveNext()) { varName = ((string)search.Key); var = (Var)search.Value; if (!var.isVarUndefined() || ((var.flags & VarFlags.NAMESPACE_VAR) != 0)) { if (((System.Object)simplePattern == null) || Util.stringMatch(varName, simplePattern)) { // Skip vars defined in current namespace if (ns.varTable[varName] == null) { TclList.append(interp, list, TclString.newInstance(varName)); } } } } } } else { AppendLocals(interp, list, simplePattern, true); } interp.setResult(list); return; }
/// <summary> /// Chain this frame into the call frame stack and binds the parameters values to the formal parameters of the procedure. /// </summary> /// <param name="proc"> /// the procedure. /// </param> /// <param name="proc"> /// argv the parameter values. /// </param> /// <exception cref=""> /// TclException if wrong number of arguments. /// </exception> internal void Chain(Procedure proc, TclObject[] objv) { // FIXME: double check this ns thing in case where proc is renamed to different ns. NS = proc.NS; Objv = objv; // FIXME : quick level hack : fix later Level = (Interp.VarFrame == null ? 1 : Interp.VarFrame.Level + 1); Caller = Interp.Frame; CallerVar = Interp.VarFrame; Interp.Frame = this; Interp.VarFrame = this; // parameter bindings int numArgs = proc.ArgList.Length; if (!proc.isVarArgs && objv.Length - 1 > numArgs) WrongNumProcArgs(objv[0], proc); for (int i = 0, j = 1; i < numArgs; i++, j++) { // Handle the special case of the last formal being "args". When it occurs, assign it a list consisting of // all the remaining actual arguments. TclObject varName = proc.ArgList[i][0]; TclObject value = null; if (i == (numArgs - 1) && proc.isVarArgs) { value = TclList.NewInstance(); value.Preserve(); for (int k = j; k < objv.Length; k++) TclList.Append(Interp, value, objv[k]); Interp.SetVar(varName, value, 0); value.Release(); } else { if (j < objv.Length) value = objv[j]; else if (proc.ArgList[i][1] != null) value = proc.ArgList[i][1]; else WrongNumProcArgs(objv[0], proc); Interp.SetVar(varName, value, 0); } } }
public Interp() { InitBlock(); //freeProc = null; _errorLine = 0; // An empty result is used pretty often. We will use a shared TclObject instance to represent the empty result so that we // don't need to create a new TclObject instance every time the interpreter result is set to empty. _nullResult = TclString.NewInstance(string.Empty); _nullResult.Preserve(); // Increment refCount to 1 _nullResult.Preserve(); // Increment refCount to 2 (shared) _result = TclString.NewInstance(string.Empty); // _nullResult; // correcponds to iPtr->objResultPtr _result.Preserve(); // _expr = new Expression(); _nestLevel = 0; _maxNestingDepth = 1000; // Frame = null; VarFrame = null; // _returnCode = TCL.CompletionCode.OK; _errorInfo = null; _errorCode = null; // _packageTable = new Hashtable(); _packageUnknown = null; _cmdCount = 0; _termOffset = 0; _resolvers = null; _evalFlags = 0; _scriptFile = null; _flags = 0; _isSafe = false; _assocData = null; // GlobalNS = NamespaceCmd.createNamespace(this, null, null); if (GlobalNS == null) throw new TclRuntimeError("Interp(): can't create global namespace"); // Init things that are specific to the Jacl implementation _workingDir = new FileInfo(System.Environment.CurrentDirectory); NoEval = 0; // _notifier = Notifier.GetNotifierForThread(System.Threading.Thread.CurrentThread); _notifier.Preserve(); // RandSeedInit = false; // _deleted = false; _errInProgress = false; _errAlreadyLogged = false; _errCodeSet = false; // _dbg = initDebugInfo(); // _slaveTable = new Hashtable(); _targetTable = new Hashtable(); _aliasTable = new Hashtable(); // init parser variables Parser.init(this); TclParse.init(this); // Initialize the Global (static) channel table and the local interp channel table. _interpChanTable = TclIO.getInterpChanTable(this); // Sets up the variable trace for tcl_precision. Util.setupPrecisionTrace(this); // Create the built-in commands. CreateCommands(); try { // Set up tcl_platform, tcl_version, tcl_library and other global variables. SetVar("tcl_platform", "platform", "windows", TCL.VarFlag.GLOBAL_ONLY); SetVar("tcl_platform", "byteOrder", "bigEndian", TCL.VarFlag.GLOBAL_ONLY); SetVar("tcl_platform", "os", Environment.OSVersion.Platform.ToString(), TCL.VarFlag.GLOBAL_ONLY); SetVar("tcl_platform", "osVersion", Environment.OSVersion.Version.ToString(), TCL.VarFlag.GLOBAL_ONLY); SetVar("tcl_platform", "machine", Util.tryGetSystemProperty("os.arch", "?"), TCL.VarFlag.GLOBAL_ONLY); SetVar("tcl_version", TCL_VERSION, TCL.VarFlag.GLOBAL_ONLY); SetVar("tcl_patchLevel", TCL_PATCH_LEVEL, TCL.VarFlag.GLOBAL_ONLY); SetVar("tcl_library", "resource:/tcl/lang/library", TCL.VarFlag.GLOBAL_ONLY); if (Util.Windows) SetVar("tcl_platform", "host_platform", "windows", TCL.VarFlag.GLOBAL_ONLY); else if (Util.Mac) SetVar("tcl_platform", "host_platform", "macintosh", TCL.VarFlag.GLOBAL_ONLY); else SetVar("tcl_platform", "host_platform", "unix", TCL.VarFlag.GLOBAL_ONLY); // Create the env array an populated it with proper values. Env.initialize(this); // Register Tcl's version number. Note: This MUST be done before the call to evalResource, otherwise // calls to "package require tcl" will fail. pkgProvide("Tcl", TCL_VERSION); // Source the init.tcl script to initialize auto-loading. evalResource("/tcl/lang/library/init.tcl"); } catch (TclException e) { Debug.WriteLine(GetResult().ToString()); SupportClass.WriteStackTrace(e, Console.Error); throw new TclRuntimeError("unexpected TclException: " + e.Message, e); } }
protected internal void renameCommand(string oldName, string newName) { Interp interp = this; string newTail; NamespaceCmd.Namespace cmdNs, newNs; WrappedCommand cmd; Hashtable table, oldTable; string hashKey, oldHashKey; // Find the existing command. An error is returned if cmdName can't // be found. cmd = NamespaceCmd.findCommand(interp, oldName, null, 0); if (cmd == null) { throw new TclException(interp, "can't " + ((((System.Object)newName == null) || (newName.Length == 0)) ? "delete" : "rename") + " \"" + oldName + "\": command doesn't exist"); } cmdNs = cmd.ns; // If the new command name is NULL or empty, delete the command. Do this // with Tcl_DeleteCommandFromToken, since we already have the command. if (((System.Object)newName == null) || (newName.Length == 0)) { DeleteCommandFromToken(cmd); return; } // Make sure that the destination command does not already exist. // The rename operation is like creating a command, so we should // automatically create the containing namespaces just like // Tcl_CreateCommand would. NamespaceCmd.Namespace[] newNsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummyArr = new NamespaceCmd.Namespace[1]; string[] newTailArr = new string[1]; NamespaceCmd.getNamespaceForQualName(interp, newName, null, TCL.VarFlag.CREATE_NS_IF_UNKNOWN, newNsArr, dummyArr, dummyArr, newTailArr); newNs = newNsArr[0]; newTail = newTailArr[0]; if ((newNs == null) || ((System.Object)newTail == null)) { throw new TclException(interp, "can't rename to \"" + newName + "\": bad command name"); } if (newNs.cmdTable[newTail] != null) { throw new TclException(interp, "can't rename to \"" + newName + "\": command already exists"); } // Warning: any changes done in the code here are likely // to be needed in Tcl_HideCommand() code too. // (until the common parts are extracted out) --dl // Put the command in the new namespace so we can check for an alias // loop. Since we are adding a new command to a namespace, we must // handle any shadowing of the global commands that this might create. oldTable = cmd.table; oldHashKey = cmd.hashKey; newNs.cmdTable.Add(newTail, cmd); cmd.table = newNs.cmdTable; cmd.hashKey = newTail; cmd.ns = newNs; // FIXME : this is a nasty hack that fixes renaming for Procedures // that move from one namespace to another, but the real problem // is that a rename does not work for Command instances in general if (cmd.cmd is Procedure) { Procedure p = (Procedure)cmd.cmd; p.NS = cmd.ns; } // Now check for an alias loop. If we detect one, put everything back // the way it was and report the error. try { interp.preventAliasLoop(interp, cmd); } catch (TclException e) { newNs.cmdTable.Remove(newTail); cmd.table = oldTable; cmd.hashKey = oldHashKey; cmd.ns = cmdNs; throw; } // The new command name is okay, so remove the command from its // current namespace. This is like deleting the command, so bump // the cmdEpoch to invalidate any cached references to the command. SupportClass.HashtableRemove(oldTable, oldHashKey); return; }
public void createObjCommand(string cmdName, dxObjCmdProc proc, object clientData, dxCmdDeleteProc deleteProc) // Command object to associate with cmdName. { ImportRef oldRef = null; NamespaceCmd.Namespace ns; WrappedCommand cmd, refCmd; string tail; ImportedCmdData data; int _new; if (_deleted) { // The interpreter is being deleted. Don't create any new // commands; it's not safe to muck with the interpreter anymore. return; } // Determine where the command should reside. If its name contains // namespace qualifiers, we put it in the specified namespace; // otherwise, we always put it in the global namespace. if (cmdName.IndexOf("::") != -1) { // Java does not support passing an address so we pass // an array of size 1 and then assign arr[0] to the value NamespaceCmd.Namespace[] nsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummyArr = new NamespaceCmd.Namespace[1]; string[] tailArr = new string[1]; NamespaceCmd.getNamespaceForQualName(this, cmdName, null, TCL.VarFlag.CREATE_NS_IF_UNKNOWN, nsArr, dummyArr, dummyArr, tailArr); ns = nsArr[0]; tail = tailArr[0]; if ((ns == null) || ((System.Object)tail == null)) { return; } } else { ns = GlobalNS; tail = cmdName; } cmd = (WrappedCommand)ns.cmdTable[tail]; if (cmd != null) { /* * Command already exists. If its object-based Tcl_ObjCmdProc is * TclInvokeStringCommand, we just set its Tcl_ObjCmdProc to the * argument "proc". Otherwise, we delete the old command. */ if (cmd.objProc != null && cmd.objProc.GetType().Name == "TclInvokeStringCommand") { cmd.objProc = proc; cmd.objClientData = clientData; cmd.deleteProc = deleteProc; cmd.deleteData = clientData; return; } /* * Otherwise, we delete the old command. Be careful to preserve * any existing import links so we can restore them down below. * That way, you can redefine a command and its import status * will remain intact. */ oldRef = cmd.ImportRef; cmd.ImportRef = null; DeleteCommandFromToken(cmd); // FIXME : create a test case for this condition! cmd = (WrappedCommand)ns.cmdTable[tail]; if (cmd != null) { // If the deletion callback recreated the command, just throw // away the new command (if we try to delete it again, we // could get stuck in an infinite loop). SupportClass.HashtableRemove(cmd.table, cmd.hashKey); } } cmd = new WrappedCommand(); ns.cmdTable.Add(tail, cmd); cmd.table = ns.cmdTable; cmd.hashKey = tail; cmd.ns = ns; cmd.cmd = null; cmd.deleted = false; // FIXME : import feature not implemented //cmd.importRef = null; // TODO -- Determine if this is all correct cmd.objProc = proc; cmd.objClientData = clientData; //cmd.proc = TclInvokeObjectCommand; cmd.clientData = (object)cmd; cmd.deleteProc = deleteProc; cmd.deleteData = clientData; cmd.flags = 0; // Plug in any existing import references found above. Be sure // to update all of these references to point to the new command. if (oldRef != null) { cmd.ImportRef = oldRef; while (oldRef != null) { refCmd = oldRef.ImportedCmd; data = (ImportedCmdData)refCmd.cmd; data.RealCmd = cmd; oldRef = oldRef.Next; } } // There are no shadowed commands in Jacl because they are only // used in the 8.0 compiler return; }
public void CreateCommand(string cmdName, ICommand cmdImpl) // Command object to associate with cmdName. { ImportRef oldRef = null; NamespaceCmd.Namespace ns; WrappedCommand cmd, refCmd; string tail; ImportedCmdData data; // The interpreter is being deleted. Don't create any new commands; it's not safe to muck with the interpreter anymore. if (_deleted) return; // Determine where the command should reside. If its name contains namespace qualifiers, we put it in the specified namespace; // otherwise, we always put it in the global namespace. if (cmdName.IndexOf("::") != -1) { // C# does not support passing an address so we pass an array of size 1 and then assign arr[0] to the value NamespaceCmd.Namespace[] nsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummyArr = new NamespaceCmd.Namespace[1]; string[] tailArr = new string[1]; NamespaceCmd.getNamespaceForQualName(this, cmdName, null, TCL.VarFlag.CREATE_NS_IF_UNKNOWN, nsArr, dummyArr, dummyArr, tailArr); ns = nsArr[0]; tail = tailArr[0]; if (ns == null || (object)tail == null) return; } else { ns = GlobalNS; tail = cmdName; } cmd = (WrappedCommand)ns.cmdTable[tail]; if (cmd != null) { // Command already exists. Delete the old one. Be careful to preserve any existing import links so we can // restore them down below. That way, you can redefine a command and its import status will remain intact. oldRef = cmd.ImportRef; cmd.ImportRef = null; DeleteCommandFromToken(cmd); // FIXME : create a test case for this condition! cmd = (WrappedCommand)ns.cmdTable[tail]; // If the deletion callback recreated the command, just throw away the new command (if we try to delete it again, we could get stuck in an infinite loop). if (cmd != null) SupportClass.HashtableRemove(cmd.table, cmd.hashKey); } cmd = new WrappedCommand(); ns.cmdTable.Add(tail, cmd); cmd.table = ns.cmdTable; cmd.hashKey = tail; cmd.ns = ns; cmd.cmd = cmdImpl; cmd.deleted = false; // FIXME : import feature not implemented //cmd.importRef = null; // Plug in any existing import references found above. Be sure // to update all of these references to point to the new command. if (oldRef != null) { cmd.ImportRef = oldRef; while (oldRef != null) { refCmd = oldRef.ImportedCmd; data = (ImportedCmdData)refCmd.cmd; data.RealCmd = cmd; oldRef = oldRef.Next; } } // There are no shadowed commands in Jacl because they are only // used in the 8.0 compiler return; }
public override void EventuallyDispose() { if (_deleted) return; _deleted = true; if (_nestLevel > 0) { } //-- TODO -- Determine why this is an error throw new TclRuntimeError("dispose() called with active evals"); // Remove our association with the notifer (if we had one). if (_notifier != null) { _notifier.Release(); _notifier = null; } // Dismantle everything in the global namespace except for the "errorInfo" and "errorCode" variables. These might be needed // later on if errors occur while deleting commands. We are careful to destroy and recreate the "errorInfo" and "errorCode" // variables, in case they had any traces on them. // Dismantle the namespace here, before we clear the assocData. If any background errors occur here, they will be deleted below. // FIXME : check impl of TclTeardownNamespace NamespaceCmd.TeardownNamespace(GlobalNS); // Delete all variables. TclObject errorInfoObj = null, errorCodeObj = null; try { errorInfoObj = GetVar("errorInfo", null, TCL.VarFlag.GLOBAL_ONLY); } catch (TclException) { } // Do nothing when var does not exist. if (errorInfoObj != null) errorInfoObj.Preserve(); try { errorCodeObj = GetVar("errorCode", null, TCL.VarFlag.GLOBAL_ONLY); } catch (TclException) { } // Do nothing when var does not exist. if (errorCodeObj != null) errorCodeObj.Preserve(); Frame = null; VarFrame = null; try { if (errorInfoObj != null) { SetVar("errorInfo", null, errorInfoObj, TCL.VarFlag.GLOBAL_ONLY); errorInfoObj.Release(); } if (errorCodeObj != null) { SetVar("errorCode", null, errorCodeObj, TCL.VarFlag.GLOBAL_ONLY); errorCodeObj.Release(); } } catch (TclException) { } // Ignore it -- same behavior as Tcl 8.0. // Tear down the math function table. _expr = null; // Remove all the assoc data tied to this interp and invoke deletion callbacks; note that a callback can create new callbacks, so we iterate. if (_assocData != null) { foreach (IAssocData data in _assocData.Values) data.Dispose(this); _assocData.Clear(); } // Close any remaining channels for (IDictionaryEnumerator e = _interpChanTable.GetEnumerator(); e.MoveNext(); ) { Object key = e.Key; Channel chan = (Channel)e.Value; try { chan.Close(); } catch (IOException) { } // Ignore any IO errors } // Finish deleting the global namespace. NamespaceCmd.DeleteNamespace(GlobalNS); GlobalNS = null; // FIXME : check impl of Tcl_DeleteNamespace // Free up the result *after* deleting variables, since variable deletion could have transferred ownership of the result string to Tcl. Frame = null; VarFrame = null; _resolvers = null; ResetResult(); }
/// <summary> /// Tcl_ProcObjCmd -> ProcCmd.cmdProc /// /// Creates a new Tcl procedure. /// /// </summary> /// <param name="interp">the current interpreter. /// </param> /// <param name="objv">command arguments. /// </param> /// <exception cref=""> TclException If incorrect number of arguments. /// </exception> public TCL.CompletionCode cmdProc(Interp interp, TclObject[] objv) { Procedure proc; string fullName, procName; NamespaceCmd.Namespace ns, altNs, cxtNs; Command cmd; StringBuilder ds; if (objv.Length != 4) { throw new TclNumArgsException(interp, 1, objv, "name args body"); } // Determine the namespace where the procedure should reside. Unless // the command name includes namespace qualifiers, this will be the // current namespace. fullName = objv[1].ToString(); // Java does not support passing an address so we pass // an array of size 1 and then assign arr[0] to the value NamespaceCmd.Namespace[] nsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] altNsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] cxtNsArr = new NamespaceCmd.Namespace[1]; string[] procNameArr = new string[1]; NamespaceCmd.getNamespaceForQualName(interp, fullName, null, 0, nsArr, altNsArr, cxtNsArr, procNameArr); // Get the values out of the arrays ns = nsArr[0]; altNs = altNsArr[0]; cxtNs = cxtNsArr[0]; procName = procNameArr[0]; if (ns == null) { throw new TclException(interp, "can't create procedure \"" + fullName + "\": unknown namespace"); } if ((System.Object)procName == null) { throw new TclException(interp, "can't create procedure \"" + fullName + "\": bad procedure name"); } // FIXME : could there be a problem with a command named ":command" ? if ((ns != NamespaceCmd.getGlobalNamespace(interp)) && ((System.Object)procName != null) && ((procName.Length > 0) && (procName[0] == ':'))) { throw new TclException(interp, "can't create procedure \"" + procName + "\" in non-global namespace with name starting with \":\""); } // Create the data structure to represent the procedure. proc = new Procedure(interp, ns, procName, objv[2], objv[3], interp.ScriptFile, interp.getArgLineNumber(3)); // Now create a command for the procedure. This will initially be in // the current namespace unless the procedure's name included namespace // qualifiers. To create the new command in the right namespace, we // generate a fully qualified name for it. ds = new StringBuilder(); if (ns != NamespaceCmd.getGlobalNamespace(interp)) { ds.Append(ns.fullName); ds.Append("::"); } ds.Append(procName); interp.createCommand(ds.ToString(), proc); // Now initialize the new procedure's cmdPtr field. This will be used // later when the procedure is called to determine what namespace the // procedure will run in. This will be different than the current // namespace if the proc was renamed into a different namespace. // FIXME : we do not handle renaming into another namespace correctly yet! //procPtr->cmdPtr = (Command *) cmd; return(TCL.CompletionCode.RETURN); }
/// <summary> /// Tcl_ProcObjCmd -> ProcCmd.cmdProc /// /// Creates a new Tcl procedure. /// /// </summary> /// <param name="interp">the current interpreter. /// </param> /// <param name="objv">command arguments. /// </param> /// <exception cref=""> TclException If incorrect number of arguments. /// </exception> public TCL.CompletionCode CmdProc(Interp interp, TclObject[] objv) { Procedure proc; string fullName, procName; NamespaceCmd.Namespace ns, altNs, cxtNs; ICommand cmd; StringBuilder ds; if (objv.Length != 4) { throw new TclNumArgsException(interp, 1, objv, "name args body"); } // Determine the namespace where the procedure should reside. Unless // the command name includes namespace qualifiers, this will be the // current namespace. fullName = objv[1].ToString(); // Java does not support passing an address so we pass // an array of size 1 and then assign arr[0] to the value NamespaceCmd.Namespace[] nsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] altNsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] cxtNsArr = new NamespaceCmd.Namespace[1]; string[] procNameArr = new string[1]; NamespaceCmd.getNamespaceForQualName(interp, fullName, null, 0, nsArr, altNsArr, cxtNsArr, procNameArr); // Get the values out of the arrays ns = nsArr[0]; altNs = altNsArr[0]; cxtNs = cxtNsArr[0]; procName = procNameArr[0]; if (ns == null) { throw new TclException(interp, "can't create procedure \"" + fullName + "\": unknown namespace"); } if ((System.Object)procName == null) { throw new TclException(interp, "can't create procedure \"" + fullName + "\": bad procedure name"); } // FIXME : could there be a problem with a command named ":command" ? if ((ns != NamespaceCmd.getGlobalNamespace(interp)) && ((System.Object)procName != null) && ((procName.Length > 0) && (procName[0] == ':'))) { throw new TclException(interp, "can't create procedure \"" + procName + "\" in non-global namespace with name starting with \":\""); } // Create the data structure to represent the procedure. proc = new Procedure(interp, ns, procName, objv[2], objv[3], interp.ScriptFile, interp.getArgLineNumber(3)); // Now create a command for the procedure. This will initially be in // the current namespace unless the procedure's name included namespace // qualifiers. To create the new command in the right namespace, we // generate a fully qualified name for it. ds = new StringBuilder(); if (ns != NamespaceCmd.getGlobalNamespace(interp)) { ds.Append(ns.fullName); ds.Append("::"); } ds.Append(procName); interp.CreateCommand(ds.ToString(), proc); // Now initialize the new procedure's cmdPtr field. This will be used // later when the procedure is called to determine what namespace the // procedure will run in. This will be different than the current // namespace if the proc was renamed into a different namespace. // FIXME : we do not handle renaming into another namespace correctly yet! //procPtr->cmdPtr = (Command *) cmd; return TCL.CompletionCode.RETURN; }