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();
    }
    /// <summary> TclLookupVar -> lookupVar
    /// 
    /// This procedure is used by virtually all of the variable
    /// code to locate a variable given its name(s).
    /// 
    /// </summary>
    /// <param name="part1">if part2 isn't NULL, this is the name of an array.
    /// Otherwise, this is a full variable name that could include 
    /// a parenthesized array elemnt or a scalar.
    /// </param>
    /// <param name="part2">Name of an element within array, or null.
    /// </param>
    /// <param name="flags">Only the TCL.VarFlag.GLOBAL_ONLY bit matters.
    /// </param>
    /// <param name="msg">Verb to use in error messages, e.g.  "read" or "set".
    /// </param>
    /// <param name="create">OR'ed combination of CRT_PART1 and CRT_PART2.
    /// Tells which entries to create if they don't already exist.
    /// </param>
    /// <param name="throwException">true if an exception should be throw if the
    /// variable cannot be found.
    /// </param>
    /// <returns> a two element array. a[0] is the variable indicated by
    /// part1 and part2, or null if the variable couldn't be
    /// found and throwException is false.
    /// <p>
    /// If the variable is found, a[1] is the array that
    /// contains the variable (or null if the variable is a scalar).
    /// If the variable can't be found and either createPart1 or
    /// createPart2 are true, a new as-yet-undefined (VAR_UNDEFINED)
    /// variable instance is created, entered into a hash
    /// table, and returned.
    /// Note: it's possible that var.value of the returned variable
    /// may be null (variable undefined), even if createPart1 or createPart2
    /// are true (these only cause the hash table entry or array to be created).
    /// For example, the variable might be a global that has been unset but
    /// is still referenced by a procedure, or a variable that has been unset
    /// but it only being kept in existence by a trace.
    /// </returns>
    /// <exception cref=""> TclException if the variable cannot be found and 
    /// throwException is true.
    /// 
    /// </exception>

    internal static Var[] lookupVar( Interp interp, string part1, string part2, TCL.VarFlag flags, string msg, bool createPart1, bool createPart2 )
    {
      CallFrame varFrame = interp.varFrame;
      // Reference to the procedure call frame whose
      // variables are currently in use. Same as
      // the current procedure's frame, if any,
      // unless an "uplevel" is executing.
      Hashtable table; //  to the hashtable, if any, in which
      // to look up the variable.
      Var var; // Used to search for global names.
      string elName; // Name of array element or null.
      int openParen;
      // If this procedure parses a name into
      // array and index, these point to the
      // parens around the index.  Otherwise they
      // are -1. These are needed to restore
      // the parens after parsing the name.
      NamespaceCmd.Namespace varNs, cxtNs;
      int p;
      int i, result;

      var = null;
      openParen = -1;
      varNs = null; // set non-null if a nonlocal variable

      // Parse part1 into array name and index.
      // Always check if part1 is an array element name and allow it only if
      // part2 is not given.   
      // (if one does not care about creating array elements that can't be used
      // from tcl, and prefer slightly better performance, one can put
      // the following in an   if (part2 == null) { ... } block and remove
      // the part2's test and error reporting  or move that code in array set)
      elName = part2;
      int len = part1.Length;
      for ( p = 0; p < len; p++ )
      {
        if ( part1[p] == '(' )
        {
          openParen = p;
          p = len - 1;
          if ( part1[p] == ')' )
          {
            if ( (System.Object)part2 != null )
            {
              if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
              {
                throw new TclVarException( interp, part1, part2, msg, needArray );
              }
              return null;
            }
            elName = part1.Substring( openParen + 1, ( len - 1 ) - ( openParen + 1 ) );
            part2 = elName; // same as elName, only used in error reporting
            part1 = part1.Substring( 0, ( openParen ) - ( 0 ) );
          }
          break;
        }
      }



      // If this namespace has a variable resolver, then give it first
      // crack at the variable resolution.  It may return a Var
      // value, it may signal to continue onward, or it may signal
      // an error.

      if ( ( ( flags & TCL.VarFlag.GLOBAL_ONLY ) != 0 ) || ( interp.varFrame == null ) )
      {
        cxtNs = interp.globalNs;
      }
      else
      {
        cxtNs = interp.varFrame.ns;
      }

      if ( cxtNs.resolver != null || interp.resolvers != null )
      {
        try
        {
          if ( cxtNs.resolver != null )
          {
            var = cxtNs.resolver.resolveVar( interp, part1, cxtNs, flags );
          }
          else
          {
            var = null;
          }

          if ( var == null && interp.resolvers != null )
          {
            IEnumerator enum_Renamed = interp.resolvers.GetEnumerator();
            foreach ( Interp.ResolverScheme res in interp.resolvers )
            {
              var = res.resolver.resolveVar( interp, part1, cxtNs, flags );
              if ( var != null )
                break;
            }
          }
        }
        catch ( TclException e )
        {
          var = null;
        }
      }

      // Look up part1. Look it up as either a namespace variable or as a
      // local variable in a procedure call frame (varFrame).
      // Interpret part1 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).
      // Otherwise, if part1 is a local variable, search first in the
      // frame's array of compiler-allocated local variables, then in its
      // hashtable for runtime-created local variables.
      //
      // If createPart1 and the variable isn't found, create the variable and,
      // if necessary, create varFrame's local var hashtable.

      if ( ( ( flags & ( TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.NAMESPACE_ONLY ) ) != 0 ) || ( varFrame == null ) || !varFrame.isProcCallFrame || ( part1.IndexOf( "::" ) != -1 ) )
      {
        string tail;

        // Don't pass TCL.VarFlag.LEAVE_ERR_MSG, we may yet create the variable,
        // or otherwise generate our own error!

        var = NamespaceCmd.findNamespaceVar( interp, part1, null, flags & ~TCL.VarFlag.LEAVE_ERR_MSG );
        if ( var == null )
        {
          if ( createPart1 )
          {
            // var wasn't found so create it

            // 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[] varNsArr = new NamespaceCmd.Namespace[1];
            NamespaceCmd.Namespace[] dummyArr = new NamespaceCmd.Namespace[1];
            string[] tailArr = new string[1];

            NamespaceCmd.getNamespaceForQualName( interp, part1, null, flags, varNsArr, dummyArr, dummyArr, tailArr );

            // Get the values out of the arrays!
            varNs = varNsArr[0];
            tail = tailArr[0];

            if ( varNs == null )
            {
              if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
              {
                throw new TclVarException( interp, part1, part2, msg, badNamespace );
              }
              return null;
            }
            if ( (System.Object)tail == null )
            {
              if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
              {
                throw new TclVarException( interp, part1, part2, msg, missingName );
              }
              return null;
            }
            var = new Var();
            varNs.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 = varNs.varTable;

            var.ns = varNs;
          }
          else
          {
            // var wasn't found and not to create it
            if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
            {
              throw new TclVarException( interp, part1, part2, msg, noSuchVar );
            }
            return null;
          }
        }
      }
      else
      {
        // local var: look in frame varFrame
        // removed code block that searches for local compiled vars

        if ( var == null )
        {
          // look in the frame's var hash table
          table = varFrame.varTable;
          if ( createPart1 )
          {
            if ( table == null )
            {
              table = new Hashtable();
              varFrame.varTable = table;
            }
            var = (Var)table[part1];
            if ( var == null )
            {
              // we are adding a new entry
              var = new Var();
              SupportClass.PutElement( table, part1, var );

              // There is no hPtr member in Jacl, The hPtr combines
              // the table and the key used in a table lookup.
              var.hashKey = part1;
              var.table = table;

              var.ns = null; // a local variable
            }
          }
          else
          {
            if ( table != null )
            {
              var = (Var)table[part1];
            }
            if ( var == null )
            {
              if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
              {
                throw new TclVarException( interp, part1, part2, msg, noSuchVar );
              }
              return null;
            }
          }
        }
      }

      // If var is a link variable, we have a reference to some variable
      // that was created through an "upvar" or "global" command. Traverse
      // through any links until we find the referenced variable.

      while ( var.isVarLink() )
      {
        var = (Var)var.value;
      }

      // If we're not dealing with an array element, return var.

      if ( (System.Object)elName == null )
      {
        var ret = new Var[2];
        ret[0] = var;
        ret[1] = null;
        return ret;
      }

      // We're dealing with an array element. Make sure the variable is an
      // array and look up the element (create the element if desired).

      if ( var.isVarUndefined() && !var.isVarArrayElement() )
      {
        if ( !createPart1 )
        {
          if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
          {
            throw new TclVarException( interp, part1, part2, msg, noSuchVar );
          }
          return null;
        }

        // Make sure we are not resurrecting a namespace variable from a
        // deleted namespace!

        if ( ( ( var.flags & VarFlags.IN_HASHTABLE ) != 0 ) && ( var.table == null ) )
        {
          if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
          {
            throw new TclVarException( interp, part1, part2, msg, danglingVar );
          }
          return null;
        }

        var.setVarArray();
        var.clearVarUndefined();
        var.value = new Hashtable();
      }
      else if ( !var.isVarArray() )
      {
        if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
        {
          throw new TclVarException( interp, part1, part2, msg, needArray );
        }
        return null;
      }

      Var arrayVar = var;
      Hashtable arrayTable = (Hashtable)var.value;
      if ( createPart2 )
      {
        Var searchvar = (Var)arrayTable[elName];

        if ( searchvar == null )
        {
          // new entry
          if ( var.sidVec != null )
          {
            deleteSearches( var );
          }

          var = new Var();
          SupportClass.PutElement( arrayTable, elName, var );

          // There is no hPtr member in Jacl, The hPtr combines the table
          // and the key used in a table lookup.
          var.hashKey = elName;
          var.table = arrayTable;

          var.ns = varNs;
          var.setVarArrayElement();
        }
        else
        {
          var = searchvar;
        }
      }
      else
      {
        var = (Var)arrayTable[elName];
        if ( var == null )
        {
          if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 )
          {
            throw new TclVarException( interp, part1, part2, msg, noSuchElement );
          }
          return null;
        }
      }

      var ret2 = new Var[2];
      ret2[0] = var; // The Var in the array
      ret2[1] = arrayVar; // The array (Hashtable) Var
      return ret2;
    }
    /// <summary> NewVar -> Var
    /// 
    /// Construct a variable and initialize its fields.
    /// </summary>

    internal Var()
    {
      value = null;
      //name     = null; // Like hashKey in Jacl
      ns = null;
      hashKey = null; // Like hPtr in the C implementation
      table = null; // Like hPtr in the C implementation
      refCount = 0;
      traces = null;
      //search   = null;
      sidVec = null; // Like search in the C implementation
      flags = ( VarFlags.SCALAR | VarFlags.UNDEFINED | VarFlags.IN_HASHTABLE );
    }
    /// <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 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();
    }
    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;
    }
    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 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 );
      }
    }
예제 #9
0
    /*
    *----------------------------------------------------------------------
    *
    * 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;
    }
예제 #10
0
    /*
    *----------------------------------------------------------------------
    *
    * 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;
    }
예제 #11
0
파일: ProcCmd.cs 프로젝트: Belxjander/Asuna
		/// <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;
			System.Text.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 System.Text.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> 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> 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;
    }