PageRenderTime 200ms CodeModel.GetById 131ms app.highlight 58ms RepoModel.GetById 1ms app.codeStats 0ms

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

#
Java | 1064 lines | 533 code | 119 blank | 412 comment | 61 complexity | 57ec5e017dc18b82682a0513784c05bd 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.2b3";
  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    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	Parser parser;
 124    NameSpace globalNameSpace;
 125    Reader in;
 126    PrintStream out;
 127    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		Do we override exit on EOF as normally done in iteractive mode?
 138		(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 the console thusly... ;)
 246	*/
 247	public void setConsole( ConsoleInterface console ) {
 248		this.console = console;
 249		setu( "bsh.console", console );
 250	}
 251
 252	private void initRootSystemObject() 
 253	{
 254		// bsh
 255		setu("bsh", new NameSpace( "Bsh Object" ).getThis( this ) );
 256
 257		// init the static shared systemObject if it's not there yet
 258		if ( systemObject == null )
 259			systemObject = new NameSpace( 
 260				"Bsh System Object" ).getThis( this );
 261		// bsh.system
 262		setu( "bsh.system", systemObject );
 263
 264		// bsh.help
 265		This helpText = new NameSpace( 
 266			"Bsh Command Help Text" ).getThis( this );
 267		setu( "bsh.help", helpText );
 268
 269		// bsh.cwd
 270		try {
 271			setu( "bsh.cwd", System.getProperty("user.dir") );
 272		} catch ( SecurityException e ) { 
 273			// applets can't see sys props
 274			setu( "bsh.cwd", "." );
 275		}
 276
 277		// bsh.interactive
 278		setu( "bsh.interactive", new Primitive(interactive) );
 279		// bsh.evalOnly
 280		setu( "bsh.evalOnly", new Primitive(evalOnly) );
 281	}
 282
 283	/**
 284		Set the global namespace for this interpreter.
 285		<p>
 286
 287		Note: This is here for completeness.  If you're using this a lot 
 288		it may be an indication that you are doing more work than you have 
 289		to.  For example, caching the interpreter instance rather than the 
 290		namespace should not add a significant overhead.  No state other 
 291		than the debug status is stored in the interpreter.
 292		<p>
 293
 294		All features of the namespace can also be accessed using the 
 295		interpreter via eval() and the script variable 'this.namespace'
 296		(or global.namespace as necessary).
 297	*/
 298	public void setNameSpace( NameSpace globalNameSpace ) {
 299		this.globalNameSpace = globalNameSpace;
 300	}
 301
 302	/**
 303		Get the global namespace of this interpreter.
 304		<p>
 305
 306		Note: This is here for completeness.  If you're using this a lot 
 307		it may be an indication that you are doing more work than you have 
 308		to.  For example, caching the interpreter instance rather than the 
 309		namespace should not add a significant overhead.  No state other than 
 310		the debug status is stored in the interpreter.  
 311		<p>
 312
 313		All features of the namespace can also be accessed using the 
 314		interpreter via eval() and the script variable 'this.namespace'
 315		(or global.namespace as necessary).
 316	*/
 317	public NameSpace getNameSpace() {
 318		return globalNameSpace;
 319	}
 320
 321	/**
 322		Run the text only interpreter on the command line or specify a file.
 323	*/
 324    public static void main( String [] args ) 
 325	{
 326        if ( args.length > 0 ) {
 327			String filename = args[0];
 328
 329			String [] bshArgs;
 330			if ( args.length > 1 ) {
 331				bshArgs = new String [ args.length -1 ];
 332				System.arraycopy( args, 1, bshArgs, 0, args.length-1 );
 333			} else
 334				bshArgs = new String [0];
 335
 336            Interpreter interpreter = new Interpreter();
 337			interpreter.setu( "bsh.args", bshArgs );
 338			try {
 339				interpreter.source( filename, interpreter.globalNameSpace );
 340			} catch ( FileNotFoundException e ) {
 341				System.out.println("File not found: "+e);
 342			} catch ( TargetError e ) {
 343				System.out.println("Script threw exception: "+e);
 344				if ( e.inNativeCode() )
 345					e.printStackTrace( DEBUG, System.err );
 346			} catch ( EvalError e ) {
 347				System.out.println("Evaluation Error: "+e);
 348			} catch ( IOException e ) {
 349				System.out.println("I/O Error: "+e);
 350			}
 351        } else {
 352			// Workaround for JDK bug 4071281, where system.in.available() 
 353			// returns too large a value. This bug has been fixed in JDK 1.2.
 354			InputStream src;
 355			if ( System.getProperty("os.name").startsWith("Windows") 
 356				&& System.getProperty("java.version").startsWith("1.1."))
 357			{
 358				src = new FilterInputStream(System.in) {
 359					public int available() throws IOException {
 360						return 0;
 361					}
 362				};
 363			}
 364			else
 365				src = System.in;
 366
 367            Reader in = new CommandLineReader( new InputStreamReader(src));
 368            Interpreter interpreter = 
 369				new Interpreter( in, System.out, System.err, true );
 370        	interpreter.run();
 371        }
 372    }
 373
 374	/**
 375		Run interactively.  (printing prompts, etc.)
 376	*/
 377    public void run() {
 378        if(evalOnly)
 379            throw new RuntimeException("bsh Interpreter: No stream");
 380
 381        /*
 382          We'll print our banner using eval(String) in order to
 383          exercise the parser and get the basic expression classes loaded...
 384          This ameliorates the delay after typing the first statement.
 385        */
 386        if ( interactive )
 387			try { 
 388				eval("printBanner();"); 
 389			} catch ( EvalError e ) {
 390				println(
 391					"BeanShell "+VERSION+" - by Pat Niemeyer (pat@pat.net)");
 392			}
 393
 394        boolean eof = false;
 395
 396		// init the callstack.  
 397		CallStack callstack = new CallStack();
 398		callstack.push( globalNameSpace );
 399
 400        while(!eof)
 401        {
 402            try
 403            {
 404                // try to sync up the console
 405                System.out.flush();
 406                System.err.flush();
 407                Thread.yield();  // this helps a little
 408                if(interactive)
 409                    print("bsh % ");
 410
 411                eof = Line();
 412
 413                if(get_jjtree().nodeArity() > 0)  // number of child nodes 
 414                {
 415                    SimpleNode node = (SimpleNode)(get_jjtree().rootNode());
 416
 417                    if(DEBUG)
 418                        node.dump(">");
 419
 420                    Object ret = node.eval( callstack, this );
 421				
 422					// sanity check during development
 423					if ( callstack.depth() > 1 )
 424						throw new InterpreterError(
 425							"Callstack growing: "+callstack);
 426
 427                    if(ret instanceof ReturnControl)
 428                        ret = ((ReturnControl)ret).value;
 429                    if(ret != Primitive.VOID)
 430                    {
 431                        setVariable("$_", ret);
 432                        Object show = getu("bsh.show");
 433                        if(show instanceof Boolean &&
 434                            ((Boolean)show).booleanValue() == true)
 435                            println("<" + ret + ">");
 436                    }
 437                }
 438            }
 439            catch(ParseException e)
 440            {
 441                error("Parser Error: " + e.getMessage(DEBUG));
 442				if ( DEBUG )
 443                	e.printStackTrace();
 444                if(!interactive)
 445                    eof = true;
 446
 447                parser.reInitInput(in);
 448            }
 449            catch(InterpreterError e)
 450            {
 451                error("Internal Error: " + e.getMessage());
 452                e.printStackTrace();
 453                if(!interactive)
 454                    eof = true;
 455            }
 456            catch(TargetError e)
 457            {
 458                error("// Uncaught Exception: " + e );
 459				if ( e.inNativeCode() )
 460					e.printStackTrace( DEBUG, err );
 461                if(!interactive)
 462                    eof = true;
 463				setVariable("$_e", e.getTarget());
 464            }
 465            catch (EvalError e)
 466            {
 467				if ( interactive )
 468					error( e.toString() );
 469				else
 470					error( e.getMessage() );
 471                if(DEBUG)
 472                    e.printStackTrace();
 473                if(!interactive)
 474                    eof = true;
 475            }
 476            catch(Exception e)
 477            {
 478                error("Unknown error: " + e);
 479                e.printStackTrace();
 480                if(!interactive)
 481                    eof = true;
 482            }
 483            catch(TokenMgrError e)
 484            {
 485				error("Error parsing input: " + e);
 486
 487				/*
 488					We get stuck in infinite loops here when unicode escapes
 489					fail.  Must re-init the char stream reader 
 490					(ASCII_UCodeESC_CharStream.java)
 491				*/
 492				parser.reInitTokenInput( in );
 493
 494                if(!interactive)
 495                    eof = true;
 496            }
 497            finally
 498            {
 499                get_jjtree().reset();
 500				// reinit the callstack
 501				if ( callstack.depth() > 1 ) {
 502					callstack.clear();
 503					callstack.push( globalNameSpace );
 504				}
 505            }
 506        }
 507
 508		if ( interactive && !noExitOnEOF ) 
 509			System.exit(0);
 510    }
 511
 512	// begin source and eval
 513
 514	/**
 515		Read text from fileName and eval it.
 516	*/
 517    public Object source( String filename, NameSpace nameSpace ) 
 518		throws FileNotFoundException, IOException, EvalError 
 519	{
 520		File file = pathToFile( filename );
 521		debug("Sourcing file: "+file);
 522		Reader in = new BufferedReader( new FileReader(file) );
 523		return eval( in, nameSpace, filename );
 524	}
 525
 526	/**
 527		Read text from fileName and eval it.
 528		Convenience method.  Use the global namespace.
 529	*/
 530    public Object source( String filename ) 
 531		throws FileNotFoundException, IOException, EvalError 
 532	{
 533		return source( filename, globalNameSpace );
 534	}
 535
 536    /**
 537        Spawn a non-interactive local interpreter to evaluate text in the 
 538		specified namespace.  
 539
 540		Return value is the evaluated object (or corresponding primitive 
 541		wrapper).
 542
 543		@param sourceFileInfo is for information purposes only.  It is used to
 544		display error messages (and in the future may be made available to
 545		the script).
 546		@throws EvalError on script problems
 547		@throws TargetError on unhandled exceptions from the script
 548    */
 549	/*
 550		Note: we need a form of eval that passes the callstack through...
 551	*/
 552	/*
 553	Can't this be combined with run() ?
 554	run seems to have stuff in it for interactive vs. non-interactive...
 555	compare them side by side and see what they do differently, aside from the
 556	exception handling.
 557	*/
 558
 559    public Object eval( 
 560		Reader in, NameSpace nameSpace, String sourceFileInfo ) 
 561		throws EvalError 
 562	{
 563		Object retVal = null;
 564		debug("eval: nameSpace = "+nameSpace);
 565
 566		/* 
 567			Create non-interactive local interpreter for this namespace
 568			with source from the input stream and out/err same as 
 569			this interpreter.
 570		*/
 571        Interpreter localInterpreter = 
 572			new Interpreter( 
 573				in, out, err, false, nameSpace, this, sourceFileInfo  );
 574
 575		CallStack callstack = new CallStack();
 576		callstack.push( nameSpace );
 577
 578        boolean eof = false;
 579        while(!eof)
 580        {
 581			SimpleNode node = null;
 582            try
 583            {
 584                eof = localInterpreter.Line();
 585                if (localInterpreter.get_jjtree().nodeArity() > 0)
 586                {
 587                    node = (SimpleNode)localInterpreter.get_jjtree().rootNode();
 588					// nodes remember from where they were sourced
 589					node.setSourceFile( sourceFileInfo );
 590
 591					if ( TRACE )
 592						println( "// " +node.getText() );
 593
 594                    retVal = node.eval( callstack, localInterpreter );
 595
 596					// sanity check during development
 597					if ( callstack.depth() > 1 )
 598						throw new InterpreterError(
 599							"Callstack growing: "+callstack);
 600
 601                    if ( retVal instanceof ReturnControl ) {
 602                        retVal = ((ReturnControl)retVal).value;
 603						break; // non-interactive, return control now
 604					}
 605                }
 606            } catch(ParseException e) {
 607				/*
 608                throw new EvalError(
 609					"Sourced file: "+sourceFileInfo+" parser Error: " 
 610					+ e.getMessage( DEBUG ), node );
 611				*/
 612				if ( DEBUG )
 613					// show extra "expecting..." info
 614					error( e.getMessage(DEBUG) );
 615
 616				// add the source file info and throw again
 617				e.setErrorSourceFile( sourceFileInfo );
 618				throw e;
 619
 620            } catch(InterpreterError e) {
 621                e.printStackTrace();
 622                throw new EvalError(
 623					"Sourced file: "+sourceFileInfo+" internal Error: " 
 624					+ e.getMessage(), node);
 625            } catch( TargetError e ) {
 626				// failsafe, set the Line as the origin of the error.
 627				if ( e.getNode()==null )
 628					e.setNode( node );
 629				e.reThrow("Sourced file: "+sourceFileInfo);
 630            } catch(EvalError e) {
 631                if(DEBUG)
 632                    e.printStackTrace();
 633				// failsafe, set the Line as the origin of the error.
 634				if ( e.getNode()==null )
 635					e.setNode( node );
 636				e.reThrow( "Sourced file: "+sourceFileInfo );
 637            } catch(Exception e) {
 638                e.printStackTrace();
 639                throw new EvalError(
 640					"Sourced file: "+sourceFileInfo+" unknown error: " 
 641					+ e.getMessage(), node);
 642            } catch(TokenMgrError e) {
 643                throw new EvalError(
 644					"Sourced file: "+sourceFileInfo+" Token Parsing Error: " 
 645					+ e.getMessage(), node );
 646            } finally {
 647                localInterpreter.get_jjtree().reset();
 648
 649				// reinit the callstack
 650				if ( callstack.depth() > 1 ) {
 651					callstack.clear();
 652					callstack.push( nameSpace );
 653				}
 654            }
 655        }
 656		return Primitive.unwrap( retVal );
 657    }
 658
 659	/**
 660		Evaluate the inputstream in this interpreter's global namespace.
 661	*/
 662    public Object eval( Reader in ) throws EvalError 
 663	{
 664		return eval( in, globalNameSpace, "eval stream" );
 665	}
 666
 667	/**
 668		Evaluate the string in this interpreter's global namespace.
 669	*/
 670    public Object eval( String statement ) throws EvalError {
 671		debug("eval(String): "+statement);
 672		return eval(statement, globalNameSpace);
 673	}
 674
 675	/**
 676		Evaluate the string in the specified namespace.
 677	*/
 678    public Object eval( String statement, NameSpace nameSpace ) 
 679		throws EvalError {
 680
 681		String s = ( statement.endsWith(";") ? statement : statement+";" );
 682        return eval( 
 683			new StringReader(s), nameSpace, "<Inline eval of: "+s+" >" );
 684    }
 685
 686	// end source and eval
 687
 688	/**
 689		Print an error message in a standard format on the output stream
 690		associated with this interpreter. On the GUI console this will appear 
 691		in red, etc.
 692	*/
 693    public final void error(String s) {
 694		if ( console != null )
 695				console.error( "// Error: " + s +"\n" );
 696		else {
 697			err.println("// Error: " + s);
 698			err.flush();
 699		}
 700    }
 701
 702	// ConsoleInterface
 703	// The interpreter reflexively implements the console interface that it 
 704	// uses.  Should clean this up by using an inner class to implement the
 705	// console for us.
 706
 707	/** 
 708		Get the input stream associated with this interpreter.
 709		This may be be stdin or the GUI console.
 710	*/
 711	public Reader getIn() { return in; }
 712
 713	/** 
 714		Get the outptut stream associated with this interpreter.
 715		This may be be stdout or the GUI console.
 716	*/
 717	public PrintStream getOut() { return out; }
 718
 719	/** 
 720		Get the error output stream associated with this interpreter.
 721		This may be be stderr or the GUI console.
 722	*/
 723	public PrintStream getErr() { return err; }
 724
 725    public final void println(String s)
 726    {
 727        print(s + "\n");
 728    }
 729
 730    public final void print(String s)
 731    {
 732		if (console != null) {
 733            console.print(s);
 734        } else {
 735            out.print(s);
 736            out.flush();
 737        }
 738    }
 739
 740	// End ConsoleInterface
 741
 742	/**
 743		Print a debug message on debug stream associated with this interpreter
 744		only if debugging is turned on.
 745	*/
 746    public final static void debug(String s)
 747    {
 748        if(DEBUG)
 749            debug.println("// Debug: " + s);
 750    }
 751
 752	/* 
 753		Primary interpreter set and get variable methods
 754		Note: These are squeltching errors... should they?
 755	*/
 756
 757	/**
 758		Get the value of the name.
 759		name may be any value. e.g. a variable or field
 760	*/
 761    public Object get( String name ) throws EvalError {
 762		Object ret = globalNameSpace.get( name, this );
 763		return Primitive.unwrap( ret );
 764	}
 765
 766	/**
 767		Unchecked get for internal use
 768	*/
 769    Object getu( String name ) {
 770		try { 
 771			return get( name );
 772		} catch ( EvalError e ) { 
 773			throw new InterpreterError("set: "+e);
 774		}
 775	}
 776
 777	/**
 778		Assign the value to the name.	
 779		name may evaluate to anything assignable. e.g. a variable or field.
 780	*/
 781    public void set(String name, Object value) 
 782		throws EvalError 
 783	{
 784		// map null to Primtive.NULL coming in...
 785		if ( value == null )
 786			value = Primitive.NULL;
 787
 788		CallStack callstack = new CallStack();
 789		LHS lhs = globalNameSpace.getNameResolver( name ).toLHS( 
 790			callstack, this );
 791		lhs.assign( value );
 792	}
 793
 794	/**
 795		Unchecked set for internal use
 796	*/
 797    void setu(String name, Object value) {
 798		try { 
 799			set(name, value);
 800		} catch ( EvalError e ) { 
 801			throw new InterpreterError("set: "+e);
 802		}
 803	}
 804
 805    public void set(String name, long value) throws EvalError {
 806        set(name, new Primitive(value));
 807	}
 808    public void set(String name, int value) throws EvalError {
 809        set(name, new Primitive(value));
 810	}
 811    public void set(String name, double value) throws EvalError {
 812        set(name, new Primitive(value));
 813	}
 814    public void set(String name, float value) throws EvalError {
 815        set(name, new Primitive(value));
 816	}
 817    public void set(String name, boolean value) throws EvalError {
 818        set(name, new Primitive(value));
 819	}
 820
 821	/**
 822		Unassign the variable name.	
 823		Name should evaluate to a variable.
 824	*/
 825    public void unset( String name ) 
 826		throws EvalError 
 827	{
 828		CallStack callstack = new CallStack();
 829		LHS lhs = globalNameSpace.getNameResolver( name ).toLHS( 
 830			callstack, this );
 831
 832		if ( lhs.type != LHS.VARIABLE )
 833			throw new EvalError("Can't unset, not a variable: "+name);
 834
 835		// null means remove it
 836		lhs.assign( null );
 837	}
 838
 839
 840	/**
 841		@deprecated does not properly evaluate compound names
 842	*/
 843    public Object getVariable(String name)
 844    {
 845        Object obj = globalNameSpace.getVariable(name);
 846		return Primitive.unwrap( obj );
 847    }
 848
 849	/**
 850		@deprecated does not properly evaluate compound names
 851	*/
 852    public void setVariable(String name, Object value)
 853    {
 854        try { globalNameSpace.setVariable(name, value); }
 855        catch(EvalError e) { error(e.toString()); }
 856    }
 857
 858	/**
 859		@deprecated does not properly evaluate compound names
 860	*/
 861    public void setVariable(String name, int value)
 862    {
 863        try { globalNameSpace.setVariable(name, new Primitive(value)); }
 864        catch(EvalError e) { error(e.toString()); }
 865    }
 866
 867	/**
 868		@deprecated does not properly evaluate compound names
 869	*/
 870    public void setVariable(String name, float value)
 871    {
 872        try { globalNameSpace.setVariable(name, new Primitive(value)); }
 873        catch(EvalError e) { error(e.toString()); }
 874    }
 875
 876	/**
 877		@deprecated does not properly evaluate compound names
 878	*/
 879    public void setVariable(String name, boolean value)
 880    {
 881        try { globalNameSpace.setVariable(name, new Primitive(value)); }
 882        catch(EvalError e) { error(e.toString()); }
 883    }
 884
 885	// end primary set and get methods
 886
 887	/**
 888		Fetch a reference to the interpreter (global namespace), and cast it 
 889		to the specified type of interface type.  Assuming the appropriate 
 890		methods of the interface are defined in the interpreter, then you may 
 891		use this interface from Java, just like any other Java object.
 892		<p>
 893
 894		For example:
 895		<pre>
 896			Interpreter interpreter = new Interpreter();
 897			// define a method called run()
 898			interpreter.eval("run() { ... }");
 899		
 900			// Fetch a reference to the interpreter as a Runnable
 901			Runnable runnable = 
 902				(Runnable)interpreter.getInterface( Runnable.class );
 903		</pre>
 904		<p>
 905
 906		Note that the interpreter does *not* require that any or all of the
 907		methods of the interface be defined at the time the interface is
 908		generated.  However if you attempt to invoke one that is not defined
 909		you will get a runtime exception.
 910		<p>
 911
 912		Note also that this convenience method has exactly the same effect as 
 913		evaluating the script:
 914		<pre>
 915			(Type)this;
 916		</pre>
 917		<p>
 918
 919		For example, the following is identical to the previous example:
 920		<p>
 921
 922		<pre>
 923			// Fetch a reference to the interpreter as a Runnable
 924			Runnable runnable = 
 925				(Runnable)interpreter.eval( "(Runnable)this" );
 926		</pre>
 927		<p>
 928
 929		<em>Version requirement</em> Although standard Java interface types 
 930		are always available, to be used with arbitrary interfaces this 
 931		feature requires that you are using Java 1.3 or greater.
 932		<p>
 933
 934		@throws EvalError if the interface cannot be generated because the
 935		version of Java does not support the proxy mechanism. 
 936	*/
 937	public Object getInterface( Class interf ) throws EvalError
 938	{
 939		return globalNameSpace.getThis( this ).getInterface( interf );
 940	}
 941
 942	/*	Methods for interacting with Parser */
 943
 944	private JJTParserState get_jjtree() {
 945		return parser.jjtree;
 946	}
 947
 948  	private ASCII_UCodeESC_CharStream get_jj_input_stream() {
 949		return parser.jj_input_stream;
 950	}
 951
 952  	private boolean Line() throws ParseException {
 953		return parser.Line();
 954	}
 955
 956	/*	End methods for interacting with Parser */
 957
 958	void loadRCFiles() {
 959		try {
 960			String rcfile = 
 961				// Default is c:\windows under win98, $HOME under Unix
 962				System.getProperty("user.home") + File.separator + ".bshrc";
 963			source( rcfile, globalNameSpace );
 964		} catch ( Exception e ) { 
 965			// squeltch security exception, filenotfoundexception
 966			debug("Could not find rc file: "+e);
 967		}
 968	}
 969
 970	/**
 971		Localize a path to the file name based on the bsh.cwd interpreter 
 972		working directory.
 973	*/
 974    public File pathToFile( String fileName ) 
 975		throws IOException
 976	{
 977		File file = new File( fileName );
 978
 979		// if relative, fix up to bsh.cwd
 980		if ( !file.isAbsolute() ) {
 981			String cwd = (String)getu("bsh.cwd");
 982			file = new File( cwd + File.separator + fileName );
 983		}
 984
 985		return new File( file.getCanonicalPath() );
 986	}
 987
 988	public static void redirectOutputToFile( String filename ) 
 989	{
 990		try {
 991			PrintStream pout = new PrintStream( 
 992				new FileOutputStream( filename ) );
 993			System.setOut( pout );
 994			System.setErr( pout );
 995		} catch ( IOException e ) {
 996			System.err.println("Can't redirect output to file: "+filename );
 997		}
 998	}
 999
1000	/**
1001		Set an external class loader to be used for all basic class loading
1002		in BeanShell.  
1003		<p>
1004
1005		BeanShell will use this at the same point it would otherwise use the 
1006		plain Class.forName().
1007		i.e. if no explicit classpath management is done from the script
1008		(addClassPath(), setClassPath(), reloadClasses()) then BeanShell will
1009		only use the supplied classloader.  If additional classpath management
1010		is done then BeanShell will perform that in addition to the supplied
1011		external classloader.  
1012		However BeanShell is not currently able to reload
1013		classes supplied through the external classloader.
1014		<p>
1015
1016		@see BshClassManager.setClassLoader()
1017	*/
1018	public void setClassLoader( ClassLoader externalCL ) {
1019		BshClassManager.setClassLoader( externalCL );
1020	}
1021
1022	static void staticInit() {
1023	/* 
1024		Apparently in some environments you can't catch the security exception
1025		at all...  e.g. as an applet in IE  ... will probably have to work 
1026		around 
1027	*/
1028		try {
1029    		debug = System.err;
1030    		DEBUG = Boolean.getBoolean("debug");
1031    		TRACE = Boolean.getBoolean("trace");
1032			String outfilename = System.getProperty("outfile");
1033			if ( outfilename != null )
1034				redirectOutputToFile( outfilename );
1035		} catch ( SecurityException e ) { 
1036			System.err.println("Could not init static:"+e);
1037		} catch ( Exception e ) {
1038			System.err.println("Could not init static(2):"+e);
1039		} catch ( Throwable e ) { 
1040			System.err.println("Could not init static(3):"+e);
1041		}
1042	}
1043
1044	/**
1045		Specify the source of the text from which this interpreter is reading.
1046		Note: there is a difference between what file the interrpeter is 
1047		sourcing and from what file a method was originally parsed.  One
1048		file may call a method sourced from another file.  See SimpleNode
1049		for origination file info.
1050		@see SimpleNode.getSourceFile 
1051	*/
1052	public String getSourceFileInfo() { 
1053		if ( sourceFileInfo != null )
1054			return sourceFileInfo;
1055		else
1056			return "<unknown source>";
1057	}
1058
1059	public Interpreter getParent() {
1060		return parent;
1061	}
1062
1063}
1064