PageRenderTime 355ms CodeModel.GetById 291ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/bsh/Interpreter.java

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