protected internal CallFrame newCallFrame( Procedure proc, TclObject[] objv )
 {
   return new CallFrame( this, proc, objv );
 }
Beispiel #2
0
		/// <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 );
        }
      }
    }
    private string wrongNumProcArgs( TclObject name, Procedure proc )
    {
      int i;
      StringBuilder sbuf = new StringBuilder( 200 );
      sbuf.Append( "wrong # args: should be \"" );

      sbuf.Append( name.ToString() );
      for ( i = 0; i < proc.argList.Length; i++ )
      {
        TclObject arg = proc.argList[i][0];
        TclObject def = proc.argList[i][1];

        sbuf.Append( " " );
        if ( def != null )
          sbuf.Append( "?" );

        sbuf.Append( arg.ToString() );
        if ( def != null )
          sbuf.Append( "?" );
      }
      sbuf.Append( "\"" );
      throw new TclException( interp, sbuf.ToString() );
    }
    /// <summary> Creates a CallFrame. It changes the following variables:
    /// 
    /// <ul>
    /// <li> this.caller
    /// <li> this.callerVar
    /// <li> interp.frame
    /// <li> interp.varFrame
    /// </ul>
    /// </summary>
    /// <param name="i">current interpreter.
    /// </param>
    /// <param name="proc">the procedure to invoke in this call frame.
    /// </param>
    /// <param name="objv">the arguments to the procedure.
    /// </param>
    /// <exception cref=""> TclException if error occurs in parameter bindings.
    /// </exception>
    internal CallFrame( Interp i, Procedure proc, TclObject[] objv )
      : this( i )
    {

      try
      {
        chain( proc, objv );
      }
      catch ( TclException e )
      {
        dispose();
        throw;
      }
    }