Пример #1
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);
        }
Пример #2
0
        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;
        }
Пример #3
0
        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;
        }
Пример #4
0
        /// <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);
                }
            }
        }
Пример #5
0
 /// <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.
 ///
 /// 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;
     }
 }
Пример #6
0
        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);
        }
Пример #7
0
 /// <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.
 ///
 /// 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;
     }
 }
Пример #8
0
 /// <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>
 /// <returns>
 /// an Vector the names of the (defined) variables in this CallFrame.
 /// </returns>
 /// <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)
 {
     // Parse string to figure out which level number to go to.
     int level;
     int result = 1;
     int 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 && 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.
     CallFrame 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;
 }
Пример #9
0
 /// <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);
         }
     }
 }
Пример #10
0
        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();
        }
Пример #11
0
        internal TCL.CompletionCode invokeGlobal(TclObject[] objv, int flags)
        {
            CallFrame savedVarFrame = VarFrame;

            try
            {
                VarFrame = null;
                return invoke(objv, flags);
            }
            finally
            {
                VarFrame = savedVarFrame;
            }
        }
Пример #12
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);
            }
        }
Пример #13
0
        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);
        }