/// <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 ); } } }
/// <summary> Tcl_UpvarObjCmd -> UpvarCmd.cmdProc /// /// This procedure is invoked to process the "upvar" Tcl command. /// See the user documentation for details on what it does. /// </summary> public TCL.CompletionCode cmdProc( Interp interp, TclObject[] objv ) { CallFrame frame; string frameSpec, otherVarName, myVarName; int p; int objc = objv.Length, objv_index; int result; if ( objv.Length < 3 ) { throw new TclNumArgsException( interp, 1, objv, "?level? otherVar localVar ?otherVar localVar ...?" ); } // Find the call frame containing each of the "other variables" to be // linked to. frameSpec = objv[1].ToString(); // Java does not support passing a reference by refernece so use an array CallFrame[] frameArr = new CallFrame[1]; result = CallFrame.getFrame( interp, frameSpec, frameArr ); frame = frameArr[0]; objc -= ( result + 1 ); if ( ( objc & 1 ) != 0 ) { throw new TclNumArgsException( interp, 1, objv, "?level? otherVar localVar ?otherVar localVar ...?" ); } objv_index = result + 1; // Iterate over each (other variable, local variable) pair. // Divide the other variable name into two parts, then call // MakeUpvar to do all the work of linking it to the local variable. for ( ; objc > 0; objc -= 2, objv_index += 2 ) { myVarName = objv[objv_index + 1].ToString(); otherVarName = objv[objv_index].ToString(); int otherLength = otherVarName.Length; p = otherVarName.IndexOf( (System.Char)'(' ); if ( ( p != -1 ) && ( otherVarName[otherLength - 1] == ')' ) ) { // This is an array variable name Var.makeUpvar( interp, frame, otherVarName.Substring( 0, ( p ) - ( 0 ) ), otherVarName.Substring( p + 1, ( otherLength - 1 ) - ( p + 1 ) ), 0, myVarName, 0 ); } else { // This is a scalar variable name Var.makeUpvar( interp, frame, otherVarName, null, 0, myVarName, 0 ); } } interp.resetResult(); return TCL.CompletionCode.RETURN; }
/// <summary> Tcl_UpvarObjCmd -> UpvarCmd.cmdProc /// /// This procedure is invoked to process the "upvar" Tcl command. /// See the user documentation for details on what it does. /// </summary> public TCL.CompletionCode cmdProc(Interp interp, TclObject[] objv) { CallFrame frame; string frameSpec, otherVarName, myVarName; int p; int objc = objv.Length, objv_index; int result; if (objv.Length < 3) { throw new TclNumArgsException(interp, 1, objv, "?level? otherVar localVar ?otherVar localVar ...?"); } // Find the call frame containing each of the "other variables" to be // linked to. frameSpec = objv[1].ToString(); // Java does not support passing a reference by refernece so use an array CallFrame[] frameArr = new CallFrame[1]; result = CallFrame.getFrame(interp, frameSpec, frameArr); frame = frameArr[0]; objc -= (result + 1); if ((objc & 1) != 0) { throw new TclNumArgsException(interp, 1, objv, "?level? otherVar localVar ?otherVar localVar ...?"); } objv_index = result + 1; // Iterate over each (other variable, local variable) pair. // Divide the other variable name into two parts, then call // MakeUpvar to do all the work of linking it to the local variable. for (; objc > 0; objc -= 2, objv_index += 2) { myVarName = objv[objv_index + 1].ToString(); otherVarName = objv[objv_index].ToString(); int otherLength = otherVarName.Length; p = otherVarName.IndexOf((System.Char) '('); if ((p != -1) && (otherVarName[otherLength - 1] == ')')) { // This is an array variable name Var.makeUpvar(interp, frame, otherVarName.Substring(0, (p) - (0)), otherVarName.Substring(p + 1, (otherLength - 1) - (p + 1)), 0, myVarName, 0); } else { // This is a scalar variable name Var.makeUpvar(interp, frame, otherVarName, null, 0, myVarName, 0); } } interp.resetResult(); return(TCL.CompletionCode.RETURN); }
/// <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> This method is called when this CallFrame is no longer needed. /// Removes the reference of this object from the interpreter so /// that this object can be garbage collected. /// <p> /// For this procedure to work correctly, it must not be possible /// for any of the variable in the table to be accessed from Tcl /// commands (e.g. from trace procedures). /// </summary> protected internal void dispose() { // Unchain this frame from the call stack. interp.frame = caller; interp.varFrame = callerVar; caller = null; callerVar = null; if (varTable != null) { Var.deleteVars(interp, varTable); varTable.Clear(); varTable = null; } }
public TCL.CompletionCode cmdProc( Interp interp, TclObject[] objv ) { string optLevel; int result; CallFrame savedVarFrame, frame; int objc = objv.Length; int objv_index; TclObject cmd; if ( objv.Length < 2 ) { throw new TclNumArgsException( interp, 1, objv, "?level? command ?arg ...?" ); } // Find the level to use for executing the command. optLevel = objv[1].ToString(); // Java does not support passing a reference by refernece so use an array CallFrame[] frameArr = new CallFrame[1]; result = CallFrame.getFrame( interp, optLevel, frameArr ); frame = frameArr[0]; objc -= ( result + 1 ); if ( objc == 0 ) { throw new TclNumArgsException( interp, 1, objv, "?level? command ?arg ...?" ); } objv_index = ( result + 1 ); // Modify the interpreter state to execute in the given frame. savedVarFrame = interp.varFrame; interp.varFrame = frame; // Execute the residual arguments as a command. if ( objc == 1 ) { cmd = objv[objv_index]; } else { cmd = TclString.newInstance( Util.concat( objv_index, objv.Length - 1, objv ) ); } cmd.preserve(); try { interp.eval( cmd, 0 ); } catch ( TclException e ) { if ( e.getCompletionCode() == TCL.CompletionCode.ERROR ) { interp.addErrorInfo( "\n (\"uplevel\" body line " + interp.errorLine + ")" ); } throw; } finally { interp.varFrame = savedVarFrame; cmd.release(); } return TCL.CompletionCode.RETURN; }
/// <summary> MakeUpvar -> makeUpvar /// /// Create a reference of a variable in otherFrame in the current /// CallFrame, given a two-part name consisting of array name and /// element within array. /// /// </summary> /// <param name="interp">Interp containing the variables /// </param> /// <param name="frame">CallFrame containing "other" variable. /// null means use global context. /// </param> /// <param name="otherP1">the 1st part name of the variable in the "other" frame. /// </param> /// <param name="otherP2">the 2nd part name of the variable in the "other" frame. /// </param> /// <param name="otherFlags">the flags for scaope of "other" variable /// </param> /// <param name="myName">Name of scalar variable which will refer to otherP1/otherP2. /// </param> /// <param name="myFlags">only the TCL.VarFlag.GLOBAL_ONLY bit matters, /// indicating the scope of myName. /// </param> /// <exception cref=""> TclException if the upvar cannot be created. /// </exception> protected internal static void makeUpvar( Interp interp, CallFrame frame, string otherP1, string otherP2, TCL.VarFlag otherFlags, string myName, TCL.VarFlag myFlags ) { Var other, var, array; Var[] result; CallFrame varFrame; CallFrame savedFrame = null; Hashtable table; NamespaceCmd.Namespace ns, altNs; string tail; bool newvar = false; // Find "other" in "frame". If not looking up other in just the // current namespace, temporarily replace the current var frame // pointer in the interpreter in order to use TclLookupVar. if ( ( otherFlags & TCL.VarFlag.NAMESPACE_ONLY ) == 0 ) { savedFrame = interp.varFrame; interp.varFrame = frame; } result = lookupVar( interp, otherP1, otherP2, ( otherFlags | TCL.VarFlag.LEAVE_ERR_MSG ), "access", true, true ); if ( ( otherFlags & TCL.VarFlag.NAMESPACE_ONLY ) == 0 ) { interp.varFrame = savedFrame; } other = result[0]; array = result[1]; if ( other == null ) { // FIXME : leave error message thing again throw new TclRuntimeError( "unexpected null reference" ); } // Now create a hashtable entry for "myName". Create it as either a // namespace variable or as a local variable in a procedure call // frame. Interpret myName as a namespace variable if: // 1) so requested by a TCL.VarFlag.GLOBAL_ONLY or TCL.VarFlag.NAMESPACE_ONLY flag, // 2) there is no active frame (we're at the global :: scope), // 3) the active frame was pushed to define the namespace context // for a "namespace eval" or "namespace inscope" command, // 4) the name has namespace qualifiers ("::"s). // If creating myName in the active procedure, look in its // hashtable for runtime-created local variables. Create that // procedure's local variable hashtable if necessary. varFrame = interp.varFrame; if ( ( ( myFlags & ( TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.NAMESPACE_ONLY ) ) != 0 ) || ( varFrame == null ) || !varFrame.isProcCallFrame || ( myName.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[] altNsArr = new NamespaceCmd.Namespace[1]; NamespaceCmd.Namespace[] dummyNsArr = new NamespaceCmd.Namespace[1]; string[] tailArr = new string[1]; NamespaceCmd.getNamespaceForQualName( interp, myName, null, myFlags, nsArr, altNsArr, dummyNsArr, tailArr ); // Get the values out of the arrays! ns = nsArr[0]; altNs = altNsArr[0]; tail = tailArr[0]; if ( ns == null ) { ns = altNs; } if ( ns == null ) { throw new TclException( interp, "bad variable name \"" + myName + "\": unknown namespace" ); } // Check that we are not trying to create a namespace var linked to // a local variable in a procedure. If we allowed this, the local // variable in the shorter-lived procedure frame could go away // leaving the namespace var's reference invalid. if ( ( ( (System.Object)otherP2 != null ) ? array.ns : other.ns ) == null ) { throw new TclException( interp, "bad variable name \"" + myName + "\": upvar won't create namespace variable that refers to procedure variable" ); } // AKT var = (Var) ns.varTable.get(tail); var = (Var)ns.varTable[tail]; if ( var == null ) { // we are adding a new entry newvar = true; var = new Var(); // ATK ns.varTable.put(tail, var); ns.varTable.Add( tail, var ); // There is no hPtr member in Jacl, The hPtr combines the table // and the key used in a table lookup. var.hashKey = tail; var.table = ns.varTable; var.ns = ns; } } else { // Skip Compiled Local stuff var = null; if ( var == null ) { // look in frame's local var hashtable table = varFrame.varTable; if ( table == null ) { table = new Hashtable(); varFrame.varTable = table; } var = (Var)table[myName]; if ( var == null ) { // we are adding a new entry newvar = true; var = new Var(); SupportClass.PutElement( table, myName, var ); // There is no hPtr member in Jacl, The hPtr combines the table // and the key used in a table lookup. var.hashKey = myName; var.table = table; var.ns = varFrame.ns; } } } if ( !newvar ) { // The variable already exists. Make sure this variable "var" // isn't the same as "other" (avoid circular links). Also, if // it's not an upvar then it's an error. If it is an upvar, then // just disconnect it from the thing it currently refers to. if ( var == other ) { throw new TclException( interp, "can't upvar from variable to itself" ); } if ( var.isVarLink() ) { Var link = (Var)var.value; if ( link == other ) { return; } link.refCount--; if ( link.isVarUndefined() ) { cleanupVar( link, null ); } } else if ( !var.isVarUndefined() ) { throw new TclException( interp, "variable \"" + myName + "\" already exists" ); } else if ( var.traces != null ) { throw new TclException( interp, "variable \"" + myName + "\" has traces: can't use for upvar" ); } } var.setVarLink(); var.clearVarUndefined(); var.value = other; other.refCount++; return; }
public TCL.CompletionCode cmdProc(Interp interp, TclObject[] argv) { // Create the call frame and parameter bindings CallFrame frame = interp.newCallFrame(this, argv); // Execute the body interp.pushDebugStack(srcFileName, srcLineNumber); try { Parser.eval2(interp, body.array, body.index, body_length, 0); } catch (TclException e) { TCL.CompletionCode code = e.getCompletionCode(); if (code == TCL.CompletionCode.RETURN) { TCL.CompletionCode realCode = interp.updateReturnInfo(); if (realCode != TCL.CompletionCode.OK) { e.setCompletionCode(realCode); throw; } } else if (code == TCL.CompletionCode.ERROR) { interp.addErrorInfo("\n (procedure \"" + argv[0] + "\" line " + interp.errorLine + ")"); throw; } else if (code == TCL.CompletionCode.BREAK) { throw new TclException(interp, "invoked \"break\" outside of a loop"); } else if (code == TCL.CompletionCode.CONTINUE) { throw new TclException(interp, "invoked \"continue\" outside of a loop"); } else { throw; } } finally { interp.popDebugStack(); // The check below is a hack. The problem is that there // could be unset traces on the variables, which cause // scripts to be evaluated. This will clear the // errInProgress flag, losing stack trace information if // the procedure was exiting with an error. The code // below preserves the flag. Unfortunately, that isn't // really enough: we really should preserve the errorInfo // variable too (otherwise a nested error in the trace // script will trash errorInfo). What's really needed is // a general-purpose mechanism for saving and restoring // interpreter state. if (interp.errInProgress) { frame.dispose(); interp.errInProgress = true; } else { frame.dispose(); } } return(TCL.CompletionCode.RETURN); }
/// <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; }
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. m_nullResult = TclString.newInstance( "" ); m_nullResult.preserve(); // Increment refCount to 1 m_nullResult.preserve(); // Increment refCount to 2 (shared) m_result = TclString.newInstance( "" ); //m_nullResult; // correcponds to iPtr->objResultPtr m_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 = null; // force creation of global ns below 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 ) { System.Diagnostics.Debug.WriteLine( getResult().ToString() ); SupportClass.WriteStackTrace( e, Console.Error ); throw new TclRuntimeError( "unexpected TclException: " + e.Message, e ); } }
internal TCL.CompletionCode invokeGlobal( TclObject[] objv, int flags ) { CallFrame savedVarFrame = varFrame; try { varFrame = null; return invoke( objv, flags ); } finally { varFrame = savedVarFrame; } }
/* *---------------------------------------------------------------------- * * Tcl_PushCallFrame -> pushCallFrame * * Pushes a new call frame onto the interpreter's Tcl call stack. * Called when executing a Tcl procedure or a "namespace eval" or * "namespace inscope" command. * * Results: * Returns if successful, raises TclException if something goes wrong. * * Side effects: * Modifies the interpreter's Tcl call stack. * *---------------------------------------------------------------------- */ internal static void pushCallFrame(Interp interp, CallFrame frame, Namespace namespace_Renamed, bool isProcCallFrame) // If true, the frame represents a // called Tcl procedure and may have local // vars. Vars will ordinarily be looked up // in the frame. If new variables are // created, they will be created in the // frame. If false, the frame is for a // "namespace eval" or "namespace inscope" // command and var references are treated // as references to namespace variables. { Namespace ns; if (namespace_Renamed == null) { ns = getCurrentNamespace(interp); } else { ns = namespace_Renamed; if ((ns.flags & NS_DEAD) != 0) { throw new TclRuntimeError("Trying to push call frame for dead namespace"); } } ns.activationCount++; frame.ns = ns; frame.isProcCallFrame = isProcCallFrame; frame.objv = null; frame.caller = interp.frame; frame.callerVar = interp.varFrame; if (interp.varFrame != null) { frame.level = (interp.varFrame.level + 1); } else { frame.level = 1; } // FIXME : does Jacl need a procPtr in the CallFrame class? //frame.procPtr = null; // no called procedure frame.varTable = null; // and no local variables // Compiled locals are not part of Jacl's CallFrame // Push the new call frame onto the interpreter's stack of procedure // call frames making it the current frame. interp.frame = frame; interp.varFrame = frame; }
/// <summary> This method is called when this CallFrame is no longer needed. /// Removes the reference of this object from the interpreter so /// that this object can be garbage collected. /// <p> /// For this procedure to work correctly, it must not be possible /// for any of the variable in the table to be accessed from Tcl /// commands (e.g. from trace procedures). /// </summary> protected internal void dispose() { // Unchain this frame from the call stack. interp.frame = caller; interp.varFrame = callerVar; caller = null; callerVar = null; if ( varTable != null ) { Var.deleteVars( interp, varTable ); varTable.Clear(); varTable = null; } }
/// <returns> an Vector the names of the (defined) variables /// in this CallFrame. /// </returns> /// <summary> Tcl_GetFrame -> getFrame /// /// Given a description of a procedure frame, such as the first /// argument to an "uplevel" or "upvar" command, locate the /// call frame for the appropriate level of procedure. /// /// The return value is 1 if string was either a number or a number /// preceded by "#" and it specified a valid frame. 0 is returned /// if string isn't one of the two things above (in this case, /// the lookup acts as if string were "1"). The frameArr[0] reference /// will be filled by the reference of the desired frame (unless an /// error occurs, in which case it isn't modified). /// /// </summary> /// <param name="string">a string that specifies the level. /// </param> /// <exception cref=""> TclException if s is a valid level specifier but /// refers to a bad level that doesn't exist. /// </exception> internal static int getFrame( Interp interp, string inString, CallFrame[] frameArr ) { int curLevel, level, result; CallFrame frame; // Parse string to figure out which level number to go to. result = 1; curLevel = ( interp.varFrame == null ) ? 0 : interp.varFrame.level; if ( ( inString.Length > 0 ) && ( inString[0] == '#' ) ) { level = Util.getInt( interp, inString.Substring( 1 ) ); if ( level < 0 ) { throw new TclException( interp, "bad level \"" + inString + "\"" ); } } else if ( ( inString.Length > 0 ) && System.Char.IsDigit( inString[0] ) ) { level = Util.getInt( interp, inString ); level = curLevel - level; } else { level = curLevel - 1; result = 0; } // FIXME: is this a bad comment from some other proc? // Figure out which frame to use, and modify the interpreter so // its variables come from that frame. if ( level == 0 ) { frame = null; } else { for ( frame = interp.varFrame; frame != null; frame = frame.callerVar ) { if ( frame.level == level ) { break; } } if ( frame == null ) { throw new TclException( interp, "bad level \"" + inString + "\"" ); } } frameArr[0] = frame; return result; }
public TCL.CompletionCode cmdProc(Interp interp, TclObject[] objv) { string optLevel; int result; CallFrame savedVarFrame, frame; int objc = objv.Length; int objv_index; TclObject cmd; if (objv.Length < 2) { throw new TclNumArgsException(interp, 1, objv, "?level? command ?arg ...?"); } // Find the level to use for executing the command. optLevel = objv[1].ToString(); // Java does not support passing a reference by refernece so use an array CallFrame[] frameArr = new CallFrame[1]; result = CallFrame.getFrame(interp, optLevel, frameArr); frame = frameArr[0]; objc -= (result + 1); if (objc == 0) { throw new TclNumArgsException(interp, 1, objv, "?level? command ?arg ...?"); } objv_index = (result + 1); // Modify the interpreter state to execute in the given frame. savedVarFrame = interp.varFrame; interp.varFrame = frame; // Execute the residual arguments as a command. if (objc == 1) { cmd = objv[objv_index]; } else { cmd = TclString.newInstance(Util.concat(objv_index, objv.Length - 1, objv)); } cmd.preserve(); try { interp.eval(cmd, 0); } catch (TclException e) { if (e.getCompletionCode() == TCL.CompletionCode.ERROR) { interp.addErrorInfo("\n (\"uplevel\" body line " + interp.errorLine + ")"); } throw; } finally { interp.varFrame = savedVarFrame; cmd.release(); } return(TCL.CompletionCode.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 e ) { // Do nothing when var does not exist. } if ( errorInfoObj != null ) { errorInfoObj.preserve(); } try { errorCodeObj = getVar( "errorCode", null, TCL.VarFlag.GLOBAL_ONLY ); } catch ( TclException e ) { // 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 e ) { // 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. // ATK The java code was somethink strong if ( assocData != null ) { foreach ( AssocData data in assocData.Values ) { data.disposeAssocData( 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 ex ) { // Ignore any IO errors } } // Finish deleting the global namespace. // FIXME : check impl of Tcl_DeleteNamespace NamespaceCmd.deleteNamespace( globalNs ); globalNs = null; // 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(); }