Exemple #1
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.
      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 );
        }
      }
    }
Exemple #2
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;
    }
Exemple #3
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);
        }
Exemple #4
0
        /// <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;
        }
Exemple #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.
        /// <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;
    }
Exemple #8
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);
        }
    /// <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;
      }
    }
Exemple #12
0
		/*
		*----------------------------------------------------------------------
		*
		* 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;
    }
    /// <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 );
        }
      }
    }
Exemple #16
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);
        }
    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();
    }