PageRenderTime 210ms CodeModel.GetById 178ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-1-pre5/bsh/Interpreter.java

#
Java | 1095 lines | 553 code | 122 blank | 420 comment | 64 complexity | fb421a27c582122a814a028e07fcb095 MD5 | raw file
   1/*****************************************************************************
   2 *                                                                           *
   3 *  This file is part of the BeanShell Java Scripting distribution.          *
   4 *  Documentation and updates may be found at http://www.beanshell.org/      *
   5 *                                                                           *
   6 *  Sun Public License Notice:                                               *
   7 *                                                                           *
   8 *  The contents of this file are subject to the Sun Public License Version  *
   9 *  1.0 (the "License"); you may not use this file except in compliance with *
  10 *  the License. A copy of the License is available at http://www.sun.com    * 
  11 *                                                                           *
  12 *  The Original Code is BeanShell. The Initial Developer of the Original    *
  13 *  Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright     *
  14 *  (C) 2000.  All Rights Reserved.                                          *
  15 *                                                                           *
  16 *  GNU Public License Notice:                                               *
  17 *                                                                           *
  18 *  Alternatively, the contents of this file may be used under the terms of  *
  19 *  the GNU Lesser General Public License (the "LGPL"), in which case the    *
  20 *  provisions of LGPL are applicable instead of those above. If you wish to *
  21 *  allow use of your version of this file only under the  terms of the LGPL *
  22 *  and not to allow others to use your version of this file under the SPL,  *
  23 *  indicate your decision by deleting the provisions above and replace      *
  24 *  them with the notice and other provisions required by the LGPL.  If you  *
  25 *  do not delete the provisions above, a recipient may use your version of  *
  26 *  this file under either the SPL or the LGPL.                              *
  27 *                                                                           *
  28 *  Patrick Niemeyer (pat@pat.net)                                           *
  29 *  Author of Learning Java, O'Reilly & Associates                           *
  30 *  http://www.pat.net/~pat/                                                 *
  31 *                                                                           *
  32 *****************************************************************************/
  33
  34package bsh;
  35
  36import java.util.Vector;
  37import java.io.*;
  38
  39/**
  40	The BeanShell script interpreter.
  41
  42	An instance of Interpreter can be used to source scripts and evaluate 
  43	statements or expressions.  
  44	<p>
  45	Here are some examples:
  46
  47	<p><blockquote><pre>
  48		Interpeter bsh = new Interpreter();
  49
  50		// Evaluate statements and expressions
  51		bsh.eval("foo=Math.sin(0.5)");
  52		bsh.eval("bar=foo*5; bar=Math.cos(bar);");
  53		bsh.eval("for(i=0; i<10; i++) { print(\"hello\"); }");
  54		// same as above using java syntax and apis only
  55		bsh.eval("for(int i=0; i<10; i++) { System.out.println(\"hello\"); }");
  56
  57		// Source from files or streams
  58		bsh.source("myscript.bsh");  // or bsh.eval("source(\"myscript.bsh\")");
  59
  60		// Use set() and get() to pass objects in and out of variables
  61		bsh.set( "date", new Date() );
  62		Date date = (Date)bsh.get( "date" );
  63		// This would also work:
  64		Date date = (Date)bsh.eval( "date" );
  65
  66		bsh.eval("year = date.getYear()");
  67		Integer year = (Integer)bsh.get("year");  // primitives use wrappers
  68
  69		// With Java1.3+ scripts can implement arbitrary interfaces...
  70		// Script an awt event handler (or source it from a file, more likely)
  71		bsh.eval( "actionPerformed( e ) { print( e ); }");
  72		// Get a reference to the script object (implementing the interface)
  73		ActionListener scriptedHandler = 
  74			(ActionListener)bsh.eval("return (ActionListener)this");
  75		// Use the scripted event handler normally...
  76		new JButton.addActionListener( script );
  77	</pre></blockquote>
  78	<p>
  79
  80	In the above examples we showed a single interpreter instance, however 
  81	you may wish to use many instances, depending on the application and how
  82	you structure your scripts.  Interpreter instances are very light weight
  83	to create, however if you are going to execute the same script repeatedly
  84	and require maximum performance you should consider scripting the code as 
  85	a method and invoking the scripted method each time on the same interpreter
  86	instance (using eval()). 
  87	<p>
  88
  89	See the BeanShell User's Manual for more information.
  90*/
  91public class Interpreter 
  92	implements Runnable, ConsoleInterface,Serializable
  93{
  94	/* --- Begin static stuff --- */
  95
  96	public static final String VERSION = "1.2b6";
  97	/* 
  98		Debug utils are static so that they are reachable by code that doesn't
  99		necessarily have an interpreter reference (e.g. tracing in utils).
 100		In the future we may want to allow debug/trace to be turned on on
 101		a per interpreter basis, in which case we'll need to use the parent 
 102		reference in some way to determine the scope of the command that 
 103		turns it on or off...
 104	*/
 105    public static boolean DEBUG, TRACE;
 106
 107	// This should be per instance
 108    transient static PrintStream debug;
 109	static { 
 110		staticInit();
 111	}
 112
 113	/** Shared system object visible under bsh.system */
 114	static This systemObject;
 115
 116	/** Strict Java mode */
 117	public static boolean strictJava = false;
 118
 119	/* --- end static stuff --- */
 120
 121	/* --- Instance data --- */
 122
 123	transient Parser parser;
 124    NameSpace globalNameSpace;
 125    transient Reader in;
 126    transient PrintStream out;
 127    transient PrintStream err;
 128    ConsoleInterface console; 
 129
 130	/** If this interpeter is a child of another, the parent */
 131	Interpreter parent;
 132
 133	/** The name of the file or other source that this interpreter is reading */
 134	String sourceFileInfo;
 135
 136	/** 
 137		Specify whether we override exit on EOF as normally done in 
 138		iteractive mode.  (This is used by Sessiond)
 139	*/
 140	public boolean noExitOnEOF;
 141
 142    private boolean 
 143		evalOnly, 		// Interpreter has no input stream, use eval() only
 144		interactive;	// Interpreter has a user, print prompts, etc.
 145
 146	/* --- End instance data --- */
 147
 148	/**
 149		The main constructor.
 150		All constructors should now pass through here.
 151
 152		@param namespace If namespace is non-null then this interpreter's 
 153		root namespace will be set to the one provided.  If it is null a new 
 154		one will be created for it.
 155		@param parent The parent interpreter if this interpreter is a child 
 156			of another.  May be null.
 157		@param sourceFileInfo An informative string holding the filename 
 158		or other description of the source from which this interpreter is
 159		reading... used for debugging.  May be null.
 160	*/
 161    public Interpreter(
 162		Reader in, PrintStream out, PrintStream err, 
 163		boolean interactive, NameSpace namespace,
 164		Interpreter parent, String sourceFileInfo )
 165    {
 166		parser = new Parser( in );
 167		long t1=System.currentTimeMillis();
 168        this.in = in;
 169        this.out = out;
 170        this.err = err;
 171        this.interactive = interactive;
 172		debug = err;
 173		this.parent = parent;
 174		this.sourceFileInfo = sourceFileInfo;
 175
 176		if ( namespace == null )
 177        	this.globalNameSpace = new NameSpace("global");
 178		else
 179			this.globalNameSpace = namespace;
 180
 181		// now done in NameSpace automatically when root
 182		// The classes which are imported by default
 183		//globalNameSpace.loadDefaultImports();
 184
 185		/* 
 186			Create the root "bsh" system object if it doesn't exist.
 187		*/
 188		if ( ! ( getu("bsh") instanceof bsh.This ) )
 189			initRootSystemObject();
 190
 191		if ( interactive )
 192			loadRCFiles();
 193
 194		long t2=System.currentTimeMillis();
 195		Interpreter.debug("Time to initialize interpreter: "+(t2-t1));
 196    }
 197
 198    public Interpreter(
 199		Reader in, PrintStream out, PrintStream err, 
 200		boolean interactive, NameSpace namespace)
 201    {
 202		this( in, out, err, interactive, namespace, null, null );
 203	}
 204
 205    public Interpreter(
 206		Reader in, PrintStream out, PrintStream err, boolean interactive)
 207    {
 208        this(in, out, err, interactive, null);
 209    }
 210
 211	/**
 212		Construct a new interactive interpreter attached to the specified 
 213		console using the specified parent namespace.
 214	*/
 215    public Interpreter(ConsoleInterface console, NameSpace globalNameSpace) {
 216
 217        this( console.getIn(), console.getOut(), console.getErr(), 
 218			true, globalNameSpace );
 219
 220		setConsole( console );
 221    }
 222
 223	/**
 224		Construct a new interactive interpreter attached to the specified 
 225		console.
 226	*/
 227    public Interpreter(ConsoleInterface console) {
 228        this(console, null);
 229    }
 230
 231	/**
 232		Create an interpreter for evaluation only.
 233	*/
 234    public Interpreter()
 235    {
 236		this( new StringReader(""), 
 237			System.out, System.err, false, null );
 238        evalOnly = true;
 239		setu( "bsh.evalOnly", new Primitive(true) );
 240    }
 241
 242	// End constructors
 243
 244	/**
 245		Attach a console
 246		Note: this method is incomplete.
 247	*/
 248	public void setConsole( ConsoleInterface console ) {
 249		this.console = console;
 250		setu( "bsh.console", console );
 251		// redundant with constructor
 252		setOut( console.getOut() );
 253		setErr( console.getErr() );
 254		// need to set the input stream - reinit the parser?
 255	}
 256
 257	private void initRootSystemObject() 
 258	{
 259		// bsh
 260		setu("bsh", new NameSpace( "Bsh Object" ).getThis( this ) );
 261
 262		// init the static shared systemObject if it's not there yet
 263		if ( systemObject == null )
 264			systemObject = new NameSpace( 
 265				"Bsh System Object" ).getThis( this );
 266		// bsh.system
 267		setu( "bsh.system", systemObject );
 268
 269		// bsh.help
 270		This helpText = new NameSpace( 
 271			"Bsh Command Help Text" ).getThis( this );
 272		setu( "bsh.help", helpText );
 273
 274		// bsh.cwd
 275		try {
 276			setu( "bsh.cwd", System.getProperty("user.dir") );
 277		} catch ( SecurityException e ) { 
 278			// applets can't see sys props
 279			setu( "bsh.cwd", "." );
 280		}
 281
 282		// bsh.interactive
 283		setu( "bsh.interactive", new Primitive(interactive) );
 284		// bsh.evalOnly
 285		setu( "bsh.evalOnly", new Primitive(evalOnly) );
 286	}
 287
 288	/**
 289		Set the global namespace for this interpreter.
 290		<p>
 291
 292		Note: This is here for completeness.  If you're using this a lot 
 293		it may be an indication that you are doing more work than you have 
 294		to.  For example, caching the interpreter instance rather than the 
 295		namespace should not add a significant overhead.  No state other 
 296		than the debug status is stored in the interpreter.
 297		<p>
 298
 299		All features of the namespace can also be accessed using the 
 300		interpreter via eval() and the script variable 'this.namespace'
 301		(or global.namespace as necessary).
 302	*/
 303	public void setNameSpace( NameSpace globalNameSpace ) {
 304		this.globalNameSpace = globalNameSpace;
 305	}
 306
 307	/**
 308		Get the global namespace of this interpreter.
 309		<p>
 310
 311		Note: This is here for completeness.  If you're using this a lot 
 312		it may be an indication that you are doing more work than you have 
 313		to.  For example, caching the interpreter instance rather than the 
 314		namespace should not add a significant overhead.  No state other than 
 315		the debug status is stored in the interpreter.  
 316		<p>
 317
 318		All features of the namespace can also be accessed using the 
 319		interpreter via eval() and the script variable 'this.namespace'
 320		(or global.namespace as necessary).
 321	*/
 322	public NameSpace getNameSpace() {
 323		return globalNameSpace;
 324	}
 325
 326	/**
 327		Run the text only interpreter on the command line or specify a file.
 328	*/
 329    public static void main( String [] args ) 
 330	{
 331        if ( args.length > 0 ) {
 332			String filename = args[0];
 333
 334			String [] bshArgs;
 335			if ( args.length > 1 ) {
 336				bshArgs = new String [ args.length -1 ];
 337				System.arraycopy( args, 1, bshArgs, 0, args.length-1 );
 338			} else
 339				bshArgs = new String [0];
 340
 341            Interpreter interpreter = new Interpreter();
 342			interpreter.setu( "bsh.args", bshArgs );
 343			try {
 344				interpreter.source( filename, interpreter.globalNameSpace );
 345			} catch ( FileNotFoundException e ) {
 346				System.out.println("File not found: "+e);
 347			} catch ( TargetError e ) {
 348				System.out.println("Script threw exception: "+e);
 349				if ( e.inNativeCode() )
 350					e.printStackTrace( DEBUG, System.err );
 351			} catch ( EvalError e ) {
 352				System.out.println("Evaluation Error: "+e);
 353			} catch ( IOException e ) {
 354				System.out.println("I/O Error: "+e);
 355			}
 356        } else {
 357			// Workaround for JDK bug 4071281, where system.in.available() 
 358			// returns too large a value. This bug has been fixed in JDK 1.2.
 359			InputStream src;
 360			if ( System.getProperty("os.name").startsWith("Windows") 
 361				&& System.getProperty("java.version").startsWith("1.1."))
 362			{
 363				src = new FilterInputStream(System.in) {
 364					public int available() throws IOException {
 365						return 0;
 366					}
 367				};
 368			}
 369			else
 370				src = System.in;
 371
 372            Reader in = new CommandLineReader( new InputStreamReader(src));
 373            Interpreter interpreter = 
 374				new Interpreter( in, System.out, System.err, true );
 375        	interpreter.run();
 376        }
 377    }
 378
 379	/**
 380		Run interactively.  (printing prompts, etc.)
 381	*/
 382    public void run() {
 383        if(evalOnly)
 384            throw new RuntimeException("bsh Interpreter: No stream");
 385
 386        /*
 387          We'll print our banner using eval(String) in order to
 388          exercise the parser and get the basic expression classes loaded...
 389          This ameliorates the delay after typing the first statement.
 390        */
 391        if ( interactive )
 392			try { 
 393				eval("printBanner();"); 
 394			} catch ( EvalError e ) {
 395				println(
 396					"BeanShell "+VERSION+" - by Pat Niemeyer (pat@pat.net)");
 397			}
 398
 399        boolean eof = false;
 400
 401		// init the callstack.  
 402		CallStack callstack = new CallStack();
 403		callstack.push( globalNameSpace );
 404
 405        while(!eof)
 406        {
 407            try
 408            {
 409                // try to sync up the console
 410                System.out.flush();
 411                System.err.flush();
 412                Thread.yield();  // this helps a little
 413                if(interactive)
 414                    print("bsh % ");
 415
 416                eof = Line();
 417
 418                if(get_jjtree().nodeArity() > 0)  // number of child nodes 
 419                {
 420                    SimpleNode node = (SimpleNode)(get_jjtree().rootNode());
 421
 422                    if(DEBUG)
 423                        node.dump(">");
 424
 425                    Object ret = node.eval( callstack, this );
 426				
 427					// sanity check during development
 428					if ( callstack.depth() > 1 )
 429						throw new InterpreterError(
 430							"Callstack growing: "+callstack);
 431
 432                    if(ret instanceof ReturnControl)
 433                        ret = ((ReturnControl)ret).value;
 434                    if(ret != Primitive.VOID)
 435                    {
 436                        setVariable("$_", ret);
 437                        Object show = getu("bsh.show");
 438                        if(show instanceof Boolean &&
 439                            ((Boolean)show).booleanValue() == true)
 440                            println("<" + ret + ">");
 441                    }
 442                }
 443            }
 444            catch(ParseException e)
 445            {
 446                error("Parser Error: " + e.getMessage(DEBUG));
 447				if ( DEBUG )
 448                	e.printStackTrace();
 449                if(!interactive)
 450                    eof = true;
 451
 452                parser.reInitInput(in);
 453            }
 454            catch(InterpreterError e)
 455            {
 456                error("Internal Error: " + e.getMessage());
 457                e.printStackTrace();
 458                if(!interactive)
 459                    eof = true;
 460            }
 461            catch(TargetError e)
 462            {
 463                error("// Uncaught Exception: " + e );
 464				if ( e.inNativeCode() )
 465					e.printStackTrace( DEBUG, err );
 466                if(!interactive)
 467                    eof = true;
 468				setVariable("$_e", e.getTarget());
 469            }
 470            catch (EvalError e)
 471            {
 472				if ( interactive )
 473					error( e.toString() );
 474				else
 475					error( e.getMessage() );
 476                if(DEBUG)
 477                    e.printStackTrace();
 478                if(!interactive)
 479                    eof = true;
 480            }
 481            catch(Exception e)
 482            {
 483                error("Unknown error: " + e);
 484                e.printStackTrace();
 485                if(!interactive)
 486                    eof = true;
 487            }
 488            catch(TokenMgrError e)
 489            {
 490				error("Error parsing input: " + e);
 491
 492				/*
 493					We get stuck in infinite loops here when unicode escapes
 494					fail.  Must re-init the char stream reader 
 495					(ASCII_UCodeESC_CharStream.java)
 496				*/
 497				parser.reInitTokenInput( in );
 498
 499                if(!interactive)
 500                    eof = true;
 501            }
 502            finally
 503            {
 504                get_jjtree().reset();
 505				// reinit the callstack
 506				if ( callstack.depth() > 1 ) {
 507					callstack.clear();
 508					callstack.push( globalNameSpace );
 509				}
 510            }
 511        }
 512
 513		if ( interactive && !noExitOnEOF ) 
 514			System.exit(0);
 515    }
 516
 517	// begin source and eval
 518
 519	/**
 520		Read text from fileName and eval it.
 521	*/
 522    public Object source( String filename, NameSpace nameSpace ) 
 523		throws FileNotFoundException, IOException, EvalError 
 524	{
 525		File file = pathToFile( filename );
 526		debug("Sourcing file: "+file);
 527		Reader in = new BufferedReader( new FileReader(file) );
 528		return eval( in, nameSpace, filename );
 529	}
 530
 531	/**
 532		Read text from fileName and eval it.
 533		Convenience method.  Use the global namespace.
 534	*/
 535    public Object source( String filename ) 
 536		throws FileNotFoundException, IOException, EvalError 
 537	{
 538		return source( filename, globalNameSpace );
 539	}
 540
 541    /**
 542        Spawn a non-interactive local interpreter to evaluate text in the 
 543		specified namespace.  
 544
 545		Return value is the evaluated object (or corresponding primitive 
 546		wrapper).
 547
 548		@param sourceFileInfo is for information purposes only.  It is used to
 549		display error messages (and in the future may be made available to
 550		the script).
 551		@throws EvalError on script problems
 552		@throws TargetError on unhandled exceptions from the script
 553    */
 554	/*
 555		Note: we need a form of eval that passes the callstack through...
 556	*/
 557	/*
 558	Can't this be combined with run() ?
 559	run seems to have stuff in it for interactive vs. non-interactive...
 560	compare them side by side and see what they do differently, aside from the
 561	exception handling.
 562	*/
 563
 564    public Object eval( 
 565		Reader in, NameSpace nameSpace, String sourceFileInfo ) 
 566		throws EvalError 
 567	{
 568		Object retVal = null;
 569		debug("eval: nameSpace = "+nameSpace);
 570
 571		/* 
 572			Create non-interactive local interpreter for this namespace
 573			with source from the input stream and out/err same as 
 574			this interpreter.
 575		*/
 576        Interpreter localInterpreter = 
 577			new Interpreter( 
 578				in, out, err, false, nameSpace, this, sourceFileInfo  );
 579
 580		CallStack callstack = new CallStack();
 581		callstack.push( nameSpace );
 582
 583        boolean eof = false;
 584        while(!eof)
 585        {
 586			SimpleNode node = null;
 587            try
 588            {
 589                eof = localInterpreter.Line();
 590                if (localInterpreter.get_jjtree().nodeArity() > 0)
 591                {
 592                    node = (SimpleNode)localInterpreter.get_jjtree().rootNode();
 593					// nodes remember from where they were sourced
 594					node.setSourceFile( sourceFileInfo );
 595
 596					if ( TRACE )
 597						println( "// " +node.getText() );
 598
 599                    retVal = node.eval( callstack, localInterpreter );
 600
 601					// sanity check during development
 602					if ( callstack.depth() > 1 )
 603						throw new InterpreterError(
 604							"Callstack growing: "+callstack);
 605
 606                    if ( retVal instanceof ReturnControl ) {
 607                        retVal = ((ReturnControl)retVal).value;
 608						break; // non-interactive, return control now
 609					}
 610                }
 611            } catch(ParseException e) {
 612				/*
 613                throw new EvalError(
 614					"Sourced file: "+sourceFileInfo+" parser Error: " 
 615					+ e.getMessage( DEBUG ), node );
 616				*/
 617				if ( DEBUG )
 618					// show extra "expecting..." info
 619					error( e.getMessage(DEBUG) );
 620
 621				// add the source file info and throw again
 622				e.setErrorSourceFile( sourceFileInfo );
 623				throw e;
 624
 625            } catch(InterpreterError e) {
 626                e.printStackTrace();
 627                throw new EvalError(
 628					"Sourced file: "+sourceFileInfo+" internal Error: " 
 629					+ e.getMessage(), node);
 630            } catch( TargetError e ) {
 631				// failsafe, set the Line as the origin of the error.
 632				if ( e.getNode()==null )
 633					e.setNode( node );
 634				e.reThrow("Sourced file: "+sourceFileInfo);
 635            } catch(EvalError e) {
 636                if(DEBUG)
 637                    e.printStackTrace();
 638				// failsafe, set the Line as the origin of the error.
 639				if ( e.getNode()==null )
 640					e.setNode( node );
 641				e.reThrow( "Sourced file: "+sourceFileInfo );
 642            } catch(Exception e) {
 643                e.printStackTrace();
 644                throw new EvalError(
 645					"Sourced file: "+sourceFileInfo+" unknown error: " 
 646					+ e.getMessage(), node);
 647            } catch(TokenMgrError e) {
 648                throw new EvalError(
 649					"Sourced file: "+sourceFileInfo+" Token Parsing Error: " 
 650					+ e.getMessage(), node );
 651            } finally {
 652                localInterpreter.get_jjtree().reset();
 653
 654				// reinit the callstack
 655				if ( callstack.depth() > 1 ) {
 656					callstack.clear();
 657					callstack.push( nameSpace );
 658				}
 659            }
 660        }
 661		return Primitive.unwrap( retVal );
 662    }
 663
 664	/**
 665		Evaluate the inputstream in this interpreter's global namespace.
 666	*/
 667    public Object eval( Reader in ) throws EvalError 
 668	{
 669		return eval( in, globalNameSpace, "eval stream" );
 670	}
 671
 672	/**
 673		Evaluate the string in this interpreter's global namespace.
 674	*/
 675    public Object eval( String statement ) throws EvalError {
 676		debug("eval(String): "+statement);
 677		return eval(statement, globalNameSpace);
 678	}
 679
 680	/**
 681		Evaluate the string in the specified namespace.
 682	*/
 683    public Object eval( String statement, NameSpace nameSpace ) 
 684		throws EvalError {
 685
 686		String s = ( statement.endsWith(";") ? statement : statement+";" );
 687        return eval( 
 688			new StringReader(s), nameSpace, "<Inline eval of: "+s+" >" );
 689    }
 690
 691	// end source and eval
 692
 693	/**
 694		Print an error message in a standard format on the output stream
 695		associated with this interpreter. On the GUI console this will appear 
 696		in red, etc.
 697	*/
 698    public final void error(String s) {
 699		if ( console != null )
 700				console.error( "// Error: " + s +"\n" );
 701		else {
 702			err.println("// Error: " + s);
 703			err.flush();
 704		}
 705    }
 706
 707	// ConsoleInterface
 708	// The interpreter reflexively implements the console interface that it 
 709	// uses.  Should clean this up by using an inner class to implement the
 710	// console for us.
 711
 712	/** 
 713		Get the input stream associated with this interpreter.
 714		This may be be stdin or the GUI console.
 715	*/
 716	public Reader getIn() { return in; }
 717
 718	/** 
 719		Get the outptut stream associated with this interpreter.
 720		This may be be stdout or the GUI console.
 721	*/
 722	public PrintStream getOut() { return out; }
 723
 724	/** 
 725		Get the error output stream associated with this interpreter.
 726		This may be be stderr or the GUI console.
 727	*/
 728	public PrintStream getErr() { return err; }
 729
 730    public final void println(String s)
 731    {
 732        print(s + "\n");
 733    }
 734
 735    public final void print(String s)
 736    {
 737		if (console != null) {
 738            console.print(s);
 739        } else {
 740            out.print(s);
 741            out.flush();
 742        }
 743    }
 744
 745	// End ConsoleInterface
 746
 747	/**
 748		Print a debug message on debug stream associated with this interpreter
 749		only if debugging is turned on.
 750	*/
 751    public final static void debug(String s)
 752    {
 753        if(DEBUG)
 754            debug.println("// Debug: " + s);
 755    }
 756
 757	/* 
 758		Primary interpreter set and get variable methods
 759		Note: These are squeltching errors... should they?
 760	*/
 761
 762	/**
 763		Get the value of the name.
 764		name may be any value. e.g. a variable or field
 765	*/
 766    public Object get( String name ) throws EvalError {
 767		Object ret = globalNameSpace.get( name, this );
 768		return Primitive.unwrap( ret );
 769	}
 770
 771	/**
 772		Unchecked get for internal use
 773	*/
 774    Object getu( String name ) {
 775		try { 
 776			return get( name );
 777		} catch ( EvalError e ) { 
 778			throw new InterpreterError("set: "+e);
 779		}
 780	}
 781
 782	/**
 783		Assign the value to the name.	
 784		name may evaluate to anything assignable. e.g. a variable or field.
 785	*/
 786    public void set(String name, Object value) 
 787		throws EvalError 
 788	{
 789		// map null to Primtive.NULL coming in...
 790		if ( value == null )
 791			value = Primitive.NULL;
 792
 793		CallStack callstack = new CallStack();
 794		LHS lhs = globalNameSpace.getNameResolver( name ).toLHS( 
 795			callstack, this );
 796		lhs.assign( value );
 797	}
 798
 799	/**
 800		Unchecked set for internal use
 801	*/
 802    void setu(String name, Object value) {
 803		try { 
 804			set(name, value);
 805		} catch ( EvalError e ) { 
 806			throw new InterpreterError("set: "+e);
 807		}
 808	}
 809
 810    public void set(String name, long value) throws EvalError {
 811        set(name, new Primitive(value));
 812	}
 813    public void set(String name, int value) throws EvalError {
 814        set(name, new Primitive(value));
 815	}
 816    public void set(String name, double value) throws EvalError {
 817        set(name, new Primitive(value));
 818	}
 819    public void set(String name, float value) throws EvalError {
 820        set(name, new Primitive(value));
 821	}
 822    public void set(String name, boolean value) throws EvalError {
 823        set(name, new Primitive(value));
 824	}
 825
 826	/**
 827		Unassign the variable name.	
 828		Name should evaluate to a variable.
 829	*/
 830    public void unset( String name ) 
 831		throws EvalError 
 832	{
 833		CallStack callstack = new CallStack();
 834		LHS lhs = globalNameSpace.getNameResolver( name ).toLHS( 
 835			callstack, this );
 836
 837		if ( lhs.type != LHS.VARIABLE )
 838			throw new EvalError("Can't unset, not a variable: "+name);
 839
 840		// null means remove it
 841		lhs.assign( null );
 842	}
 843
 844
 845	/**
 846		@deprecated does not properly evaluate compound names
 847	*/
 848    public Object getVariable(String name)
 849    {
 850        Object obj = globalNameSpace.getVariable(name);
 851		return Primitive.unwrap( obj );
 852    }
 853
 854	/**
 855		@deprecated does not properly evaluate compound names
 856	*/
 857    public void setVariable(String name, Object value)
 858    {
 859        try { globalNameSpace.setVariable(name, value); }
 860        catch(EvalError e) { error(e.toString()); }
 861    }
 862
 863	/**
 864		@deprecated does not properly evaluate compound names
 865	*/
 866    public void setVariable(String name, int value)
 867    {
 868        try { globalNameSpace.setVariable(name, new Primitive(value)); }
 869        catch(EvalError e) { error(e.toString()); }
 870    }
 871
 872	/**
 873		@deprecated does not properly evaluate compound names
 874	*/
 875    public void setVariable(String name, float value)
 876    {
 877        try { globalNameSpace.setVariable(name, new Primitive(value)); }
 878        catch(EvalError e) { error(e.toString()); }
 879    }
 880
 881	/**
 882		@deprecated does not properly evaluate compound names
 883	*/
 884    public void setVariable(String name, boolean value)
 885    {
 886        try { globalNameSpace.setVariable(name, new Primitive(value)); }
 887        catch(EvalError e) { error(e.toString()); }
 888    }
 889
 890	// end primary set and get methods
 891
 892	/**
 893		Fetch a reference to the interpreter (global namespace), and cast it 
 894		to the specified type of interface type.  Assuming the appropriate 
 895		methods of the interface are defined in the interpreter, then you may 
 896		use this interface from Java, just like any other Java object.
 897		<p>
 898
 899		For example:
 900		<pre>
 901			Interpreter interpreter = new Interpreter();
 902			// define a method called run()
 903			interpreter.eval("run() { ... }");
 904		
 905			// Fetch a reference to the interpreter as a Runnable
 906			Runnable runnable = 
 907				(Runnable)interpreter.getInterface( Runnable.class );
 908		</pre>
 909		<p>
 910
 911		Note that the interpreter does *not* require that any or all of the
 912		methods of the interface be defined at the time the interface is
 913		generated.  However if you attempt to invoke one that is not defined
 914		you will get a runtime exception.
 915		<p>
 916
 917		Note also that this convenience method has exactly the same effect as 
 918		evaluating the script:
 919		<pre>
 920			(Type)this;
 921		</pre>
 922		<p>
 923
 924		For example, the following is identical to the previous example:
 925		<p>
 926
 927		<pre>
 928			// Fetch a reference to the interpreter as a Runnable
 929			Runnable runnable = 
 930				(Runnable)interpreter.eval( "(Runnable)this" );
 931		</pre>
 932		<p>
 933
 934		<em>Version requirement</em> Although standard Java interface types 
 935		are always available, to be used with arbitrary interfaces this 
 936		feature requires that you are using Java 1.3 or greater.
 937		<p>
 938
 939		@throws EvalError if the interface cannot be generated because the
 940		version of Java does not support the proxy mechanism. 
 941	*/
 942	public Object getInterface( Class interf ) throws EvalError
 943	{
 944		return globalNameSpace.getThis( this ).getInterface( interf );
 945	}
 946
 947	/*	Methods for interacting with Parser */
 948
 949	private JJTParserState get_jjtree() {
 950		return parser.jjtree;
 951	}
 952
 953  	private ASCII_UCodeESC_CharStream get_jj_input_stream() {
 954		return parser.jj_input_stream;
 955	}
 956
 957  	private boolean Line() throws ParseException {
 958		return parser.Line();
 959	}
 960
 961	/*	End methods for interacting with Parser */
 962
 963	void loadRCFiles() {
 964		try {
 965			String rcfile = 
 966				// Default is c:\windows under win98, $HOME under Unix
 967				System.getProperty("user.home") + File.separator + ".bshrc";
 968			source( rcfile, globalNameSpace );
 969		} catch ( Exception e ) { 
 970			// squeltch security exception, filenotfoundexception
 971			debug("Could not find rc file: "+e);
 972		}
 973	}
 974
 975	/**
 976		Localize a path to the file name based on the bsh.cwd interpreter 
 977		working directory.
 978	*/
 979    public File pathToFile( String fileName ) 
 980		throws IOException
 981	{
 982		File file = new File( fileName );
 983
 984		// if relative, fix up to bsh.cwd
 985		if ( !file.isAbsolute() ) {
 986			String cwd = (String)getu("bsh.cwd");
 987			file = new File( cwd + File.separator + fileName );
 988		}
 989
 990		return new File( file.getCanonicalPath() );
 991	}
 992
 993	public static void redirectOutputToFile( String filename ) 
 994	{
 995		try {
 996			PrintStream pout = new PrintStream( 
 997				new FileOutputStream( filename ) );
 998			System.setOut( pout );
 999			System.setErr( pout );
1000		} catch ( IOException e ) {
1001			System.err.println("Can't redirect output to file: "+filename );
1002		}
1003	}
1004
1005	/**
1006		Set an external class loader to be used for all basic class loading
1007		in BeanShell.  
1008		<p>
1009
1010		BeanShell will use this at the same point it would otherwise use the 
1011		plain Class.forName().
1012		i.e. if no explicit classpath management is done from the script
1013		(addClassPath(), setClassPath(), reloadClasses()) then BeanShell will
1014		only use the supplied classloader.  If additional classpath management
1015		is done then BeanShell will perform that in addition to the supplied
1016		external classloader.  
1017		However BeanShell is not currently able to reload
1018		classes supplied through the external classloader.
1019		<p>
1020
1021		@see BshClassManager#setClassLoader( ClassLoader )
1022	*/
1023	public void setClassLoader( ClassLoader externalCL ) {
1024		BshClassManager.setClassLoader( externalCL );
1025	}
1026
1027	static void staticInit() {
1028	/* 
1029		Apparently in some environments you can't catch the security exception
1030		at all...  e.g. as an applet in IE  ... will probably have to work 
1031		around 
1032	*/
1033		try {
1034    		debug = System.err;
1035    		DEBUG = Boolean.getBoolean("debug");
1036    		TRACE = Boolean.getBoolean("trace");
1037			String outfilename = System.getProperty("outfile");
1038			if ( outfilename != null )
1039				redirectOutputToFile( outfilename );
1040		} catch ( SecurityException e ) { 
1041			System.err.println("Could not init static:"+e);
1042		} catch ( Exception e ) {
1043			System.err.println("Could not init static(2):"+e);
1044		} catch ( Throwable e ) { 
1045			System.err.println("Could not init static(3):"+e);
1046		}
1047	}
1048
1049	/**
1050		Specify the source of the text from which this interpreter is reading.
1051		Note: there is a difference between what file the interrpeter is 
1052		sourcing and from what file a method was originally parsed.  One
1053		file may call a method sourced from another file.  See SimpleNode
1054		for origination file info.
1055		@see bsh.SimpleNode#getSourceFile()
1056	*/
1057	public String getSourceFileInfo() { 
1058		if ( sourceFileInfo != null )
1059			return sourceFileInfo;
1060		else
1061			return "<unknown source>";
1062	}
1063
1064	public Interpreter getParent() {
1065		return parent;
1066	}
1067	
1068	public void setOut( PrintStream out ) {
1069		this.out = out;
1070	}
1071	public void setErr( PrintStream out ) {
1072		this.err = err;
1073	}
1074
1075	/**
1076		De-serialization setup.
1077		Default out and err streams to stdout, stderr if they are null.
1078	*/
1079	private void readObject(ObjectInputStream stream) 
1080		throws java.io.IOException, ClassNotFoundException
1081	{
1082		stream.defaultReadObject();
1083
1084		// set transient fields
1085		if ( console != null ) {
1086			setOut( console.getOut() );
1087			setErr( console.getErr() );
1088		} else {
1089			setOut( System.out );
1090			setErr( System.err );
1091		}
1092	}
1093
1094}
1095