KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > bsh > Interpreter


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
34 package bsh;
35
36 import java.util.Vector JavaDoc;
37 import java.io.*;
38 import java.lang.reflect.Method JavaDoc;
39 import java.lang.reflect.InvocationTargetException JavaDoc;
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 */

93 public class Interpreter
94     implements Runnable JavaDoc, ConsoleInterface,Serializable
95 {
96     /* --- Begin static members --- */
97
98     public static final String JavaDoc VERSION = "2.0b4-jedit";
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 JavaDoc 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 JavaDoc 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     /** Control the verbose printing of results for the show() command. */
151     private boolean showResults;
152
153     /* --- End instance data --- */
154
155     /**
156         The main constructor.
157         All constructors should now pass through here.
158
159         @param namespace If namespace is non-null then this interpreter's
160         root namespace will be set to the one provided. If it is null a new
161         one will be created for it.
162         @param parent The parent interpreter if this interpreter is a child
163             of another. May be null. Children share a BshClassManager with
164             their parent instance.
165         @param sourceFileInfo An informative string holding the filename
166         or other description of the source from which this interpreter is
167         reading... used for debugging. May be null.
168     */

169     public Interpreter(
170         Reader in, PrintStream out, PrintStream err,
171         boolean interactive, NameSpace namespace,
172         Interpreter parent, String JavaDoc sourceFileInfo )
173     {
174         //System.out.println("New Interpreter: "+this +", sourcefile = "+sourceFileInfo );
175
parser = new Parser( in );
176         long t1=System.currentTimeMillis();
177         this.in = in;
178         this.out = out;
179         this.err = err;
180         this.interactive = interactive;
181         debug = err;
182         this.parent = parent;
183         if ( parent != null )
184             setStrictJava( parent.getStrictJava() );
185         this.sourceFileInfo = sourceFileInfo;
186
187         BshClassManager bcm = BshClassManager.createClassManager( this );
188         if ( namespace == null )
189             this.globalNameSpace = new NameSpace( bcm, "global");
190         else
191             this.globalNameSpace = namespace;
192
193         // now done in NameSpace automatically when root
194
// The classes which are imported by default
195
//globalNameSpace.loadDefaultImports();
196

197         /*
198             Create the root "bsh" system object if it doesn't exist.
199         */

200         if ( ! ( getu("bsh") instanceof bsh.This ) )
201             initRootSystemObject();
202
203         if ( interactive )
204             loadRCFiles();
205
206         long t2=System.currentTimeMillis();
207         if ( Interpreter.DEBUG )
208             Interpreter.debug("Time to initialize interpreter: "+(t2-t1));
209     }
210
211     public Interpreter(
212         Reader in, PrintStream out, PrintStream err,
213         boolean interactive, NameSpace namespace)
214     {
215         this( in, out, err, interactive, namespace, null, null );
216     }
217
218     public Interpreter(
219         Reader in, PrintStream out, PrintStream err, boolean interactive)
220     {
221         this(in, out, err, interactive, null);
222     }
223
224     /**
225         Construct a new interactive interpreter attached to the specified
226         console using the specified parent namespace.
227     */

228     public Interpreter(ConsoleInterface console, NameSpace globalNameSpace) {
229
230         this( console.getIn(), console.getOut(), console.getErr(),
231             true, globalNameSpace );
232
233         setConsole( console );
234     }
235
236     /**
237         Construct a new interactive interpreter attached to the specified
238         console.
239     */

240     public Interpreter(ConsoleInterface console) {
241         this(console, null);
242     }
243
244     /**
245         Create an interpreter for evaluation only.
246     */

247     public Interpreter()
248     {
249         this( new StringReader(""),
250             System.out, System.err, false, null );
251         evalOnly = true;
252         setu( "bsh.evalOnly", new Primitive(true) );
253     }
254
255     // End constructors
256

257     /**
258         Attach a console
259         Note: this method is incomplete.
260     */

261     public void setConsole( ConsoleInterface console ) {
262         this.console = console;
263         setu( "bsh.console", console );
264         // redundant with constructor
265
setOut( console.getOut() );
266         setErr( console.getErr() );
267         // need to set the input stream - reinit the parser?
268
}
269
270     private void initRootSystemObject()
271     {
272         BshClassManager bcm = getClassManager();
273         // bsh
274
setu("bsh", new NameSpace( bcm, "Bsh Object" ).getThis( this ) );
275
276         // init the static shared sharedObject if it's not there yet
277
if ( sharedObject == null )
278             sharedObject = new NameSpace(
279                 bcm, "Bsh Shared System Object" ).getThis( this );
280         // bsh.system
281
setu( "bsh.system", sharedObject );
282         setu( "bsh.shared", sharedObject ); // alias
283

284         // bsh.help
285
This helpText = new NameSpace(
286             bcm, "Bsh Command Help Text" ).getThis( this );
287         setu( "bsh.help", helpText );
288
289         // bsh.cwd
290
try {
291             setu( "bsh.cwd", System.getProperty("user.dir") );
292         } catch ( SecurityException JavaDoc e ) {
293             // applets can't see sys props
294
setu( "bsh.cwd", "." );
295         }
296
297         // bsh.interactive
298
setu( "bsh.interactive", new Primitive(interactive) );
299         // bsh.evalOnly
300
setu( "bsh.evalOnly", new Primitive(evalOnly) );
301     }
302
303     /**
304         Set the global namespace for this interpreter.
305         <p>
306
307         Note: This is here for completeness. If you're using this a lot
308         it may be an indication that you are doing more work than you have
309         to. For example, caching the interpreter instance rather than the
310         namespace should not add a significant overhead. No state other
311         than the debug status is stored in the interpreter.
312         <p>
313
314         All features of the namespace can also be accessed using the
315         interpreter via eval() and the script variable 'this.namespace'
316         (or global.namespace as necessary).
317     */

318     public void setNameSpace( NameSpace globalNameSpace ) {
319         this.globalNameSpace = globalNameSpace;
320     }
321
322     /**
323         Get the global namespace of this interpreter.
324         <p>
325
326         Note: This is here for completeness. If you're using this a lot
327         it may be an indication that you are doing more work than you have
328         to. For example, caching the interpreter instance rather than the
329         namespace should not add a significant overhead. No state other than
330         the debug status is stored in the interpreter.
331         <p>
332
333         All features of the namespace can also be accessed using the
334         interpreter via eval() and the script variable 'this.namespace'
335         (or global.namespace as necessary).
336     */

337     public NameSpace getNameSpace() {
338         return globalNameSpace;
339     }
340
341     /**
342         Run the text only interpreter on the command line or specify a file.
343     */

344     public static void main( String JavaDoc [] args )
345     {
346         if ( args.length > 0 ) {
347             String JavaDoc filename = args[0];
348
349             String JavaDoc [] bshArgs;
350             if ( args.length > 1 ) {
351                 bshArgs = new String JavaDoc [ args.length -1 ];
352                 System.arraycopy( args, 1, bshArgs, 0, args.length-1 );
353             } else
354                 bshArgs = new String JavaDoc [0];
355
356             Interpreter interpreter = new Interpreter();
357             //System.out.println("run i = "+interpreter);
358
interpreter.setu( "bsh.args", bshArgs );
359             try {
360                 Object JavaDoc result =
361                     interpreter.source( filename, interpreter.globalNameSpace );
362                 if ( result instanceof Class JavaDoc )
363                     try {
364                         invokeMain( (Class JavaDoc)result, bshArgs );
365                     } catch ( Exception JavaDoc e )
366                     {
367                         Object JavaDoc o = e;
368                         if ( e instanceof InvocationTargetException JavaDoc )
369                             o = ((InvocationTargetException JavaDoc)e)
370                                 .getTargetException();
371                         System.err.println(
372                             "Class: "+result+" main method threw exception:"+o);
373                     }
374             } catch ( FileNotFoundException e ) {
375                 System.out.println("File not found: "+e);
376             } catch ( TargetError e ) {
377                 System.out.println("Script threw exception: "+e);
378                 if ( e.inNativeCode() )
379                     e.printStackTrace( DEBUG, System.err );
380             } catch ( EvalError e ) {
381                 System.out.println("Evaluation Error: "+e);
382             } catch ( IOException e ) {
383                 System.out.println("I/O Error: "+e);
384             }
385         } else
386         {
387             // Workaround for JDK bug 4071281, where system.in.available()
388
// returns too large a value. This bug has been fixed in JDK 1.2.
389
InputStream src;
390             if ( System.getProperty("os.name").startsWith("Windows")
391                 && System.getProperty("java.version").startsWith("1.1."))
392             {
393                 src = new FilterInputStream(System.in) {
394                     public int available() throws IOException {
395                         return 0;
396                     }
397                 };
398             }
399             else
400                 src = System.in;
401
402             Reader in = new CommandLineReader( new InputStreamReader(src));
403             Interpreter interpreter =
404                 new Interpreter( in, System.out, System.err, true );
405             interpreter.run();
406         }
407     }
408
409     public static void invokeMain( Class JavaDoc clas, String JavaDoc [] args )
410         throws Exception JavaDoc
411     {
412         Method JavaDoc main = Reflect.resolveJavaMethod(
413             null/*BshClassManager*/, clas, "main",
414             new Class JavaDoc [] { String JavaDoc [].class }, true/*onlyStatic*/ );
415         if ( main != null )
416             main.invoke( null, new Object JavaDoc [] { args } );
417     }
418
419     /**
420         Run interactively. (printing prompts, etc.)
421     */

422     public void run()
423     {
424         if(evalOnly)
425             throw new RuntimeException JavaDoc("bsh Interpreter: No stream");
426
427         /*
428           We'll print our banner using eval(String) in order to
429           exercise the parser and get the basic expression classes loaded...
430           This ameliorates the delay after typing the first statement.
431         */

432         if ( interactive )
433             try {
434                 eval("printBanner();");
435             } catch ( EvalError e ) {
436                 println(
437                     "BeanShell "+VERSION+" - by Pat Niemeyer (pat@pat.net)");
438             }
439
440         // init the callstack.
441
CallStack callstack = new CallStack( globalNameSpace );
442
443         boolean eof = false;
444         while( !eof )
445         {
446             try
447             {
448                 // try to sync up the console
449
System.out.flush();
450                 System.err.flush();
451                 Thread.yield(); // this helps a little
452

453                 if ( interactive )
454                     print( getBshPrompt() );
455
456                 eof = Line();
457
458                 if( get_jjtree().nodeArity() > 0 ) // number of child nodes
459
{
460                     SimpleNode node = (SimpleNode)(get_jjtree().rootNode());
461
462                     if(DEBUG)
463                         node.dump(">");
464
465                     Object JavaDoc ret = node.eval( callstack, this );
466
467                     // sanity check during development
468
if ( callstack.depth() > 1 )
469                         throw new InterpreterError(
470                             "Callstack growing: "+callstack);
471
472                     if(ret instanceof ReturnControl)
473                         ret = ((ReturnControl)ret).value;
474
475                     if( ret != Primitive.VOID )
476                     {
477                         setu("$_", ret);
478                         if ( showResults )
479                             println("<" + ret + ">");
480                     }
481                 }
482             }
483             catch(ParseException e)
484             {
485                 error("Parser Error: " + e.getMessage(DEBUG));
486                 if ( DEBUG )
487                     e.printStackTrace();
488                 if(!interactive)
489                     eof = true;
490
491                 parser.reInitInput(in);
492             }
493             catch(InterpreterError e)
494             {
495                 error("Internal Error: " + e.getMessage());
496                 e.printStackTrace();
497                 if(!interactive)
498                     eof = true;
499             }
500             catch(TargetError e)
501             {
502                 error("// Uncaught Exception: " + e );
503                 if ( e.inNativeCode() )
504                     e.printStackTrace( DEBUG, err );
505                 if(!interactive)
506                     eof = true;
507                 setu("$_e", e.getTarget());
508             }
509             catch (EvalError e)
510             {
511                 if ( interactive )
512                     error( "EvalError: "+e.toString() );
513                 else
514                     error( "EvalError: "+e.getMessage() );
515
516                 if(DEBUG)
517                     e.printStackTrace();
518
519                 if(!interactive)
520                     eof = true;
521             }
522             catch(Exception JavaDoc e)
523             {
524                 error("Unknown error: " + e);
525                 if ( DEBUG )
526                     e.printStackTrace();
527                 if(!interactive)
528                     eof = true;
529             }
530             catch(TokenMgrError e)
531             {
532                 error("Error parsing input: " + e);
533
534                 /*
535                     We get stuck in infinite loops here when unicode escapes
536                     fail. Must re-init the char stream reader
537                     (ASCII_UCodeESC_CharStream.java)
538                 */

539                 parser.reInitTokenInput( in );
540
541                 if(!interactive)
542                     eof = true;
543             }
544             finally
545             {
546                 get_jjtree().reset();
547                 // reinit the callstack
548
if ( callstack.depth() > 1 ) {
549                     callstack.clear();
550                     callstack.push( globalNameSpace );
551                 }
552             }
553         }
554
555         if ( interactive && exitOnEOF )
556             System.exit(0);
557     }
558
559     // begin source and eval
560

561     /**
562         Read text from fileName and eval it.
563     */

564     public Object JavaDoc source( String JavaDoc filename, NameSpace nameSpace )
565         throws FileNotFoundException, IOException, EvalError
566     {
567         File file = pathToFile( filename );
568         if ( Interpreter.DEBUG ) debug("Sourcing file: "+file);
569         Reader sourceIn = new BufferedReader( new FileReader(file) );
570         try {
571             return eval( sourceIn, nameSpace, filename );
572         } finally {
573             sourceIn.close();
574         }
575     }
576
577     /**
578         Read text from fileName and eval it.
579         Convenience method. Use the global namespace.
580     */

581     public Object JavaDoc source( String JavaDoc filename )
582         throws FileNotFoundException, IOException, EvalError
583     {
584         return source( filename, globalNameSpace );
585     }
586
587     /**
588         Spawn a non-interactive local interpreter to evaluate text in the
589         specified namespace.
590
591         Return value is the evaluated object (or corresponding primitive
592         wrapper).
593
594         @param sourceFileInfo is for information purposes only. It is used to
595         display error messages (and in the future may be made available to
596         the script).
597         @throws EvalError on script problems
598         @throws TargetError on unhandled exceptions from the script
599     */

600     /*
601         Note: we need a form of eval that passes the callstack through...
602     */

603     /*
604     Can't this be combined with run() ?
605     run seems to have stuff in it for interactive vs. non-interactive...
606     compare them side by side and see what they do differently, aside from the
607     exception handling.
608     */

609
610     public Object JavaDoc eval(
611         Reader in, NameSpace nameSpace, String JavaDoc sourceFileInfo
612             /*, CallStack callstack */ )
613         throws EvalError
614     {
615         Object JavaDoc retVal = null;
616         if ( Interpreter.DEBUG ) debug("eval: nameSpace = "+nameSpace);
617
618         /*
619             Create non-interactive local interpreter for this namespace
620             with source from the input stream and out/err same as
621             this interpreter.
622         */

623         Interpreter localInterpreter =
624             new Interpreter(
625                 in, out, err, false, nameSpace, this, sourceFileInfo );
626
627         CallStack callstack = new CallStack( nameSpace );
628
629         boolean eof = false;
630         while(!eof)
631         {
632             SimpleNode node = null;
633             try
634             {
635                 eof = localInterpreter.Line();
636                 if (localInterpreter.get_jjtree().nodeArity() > 0)
637                 {
638                     node = (SimpleNode)localInterpreter.get_jjtree().rootNode();
639                     // nodes remember from where they were sourced
640
node.setSourceFile( sourceFileInfo );
641
642                     if ( TRACE )
643                         println( "// " +node.getText() );
644
645                     retVal = node.eval( callstack, localInterpreter );
646
647                     // sanity check during development
648
if ( callstack.depth() > 1 )
649                         throw new InterpreterError(
650                             "Callstack growing: "+callstack);
651
652                     if ( retVal instanceof ReturnControl ) {
653                         retVal = ((ReturnControl)retVal).value;
654                         break; // non-interactive, return control now
655
}
656
657                     if ( localInterpreter.showResults
658                         && retVal != Primitive.VOID )
659                         println("<" + retVal + ">");
660                 }
661             } catch(ParseException e) {
662                 /*
663                 throw new EvalError(
664                     "Sourced file: "+sourceFileInfo+" parser Error: "
665                     + e.getMessage( DEBUG ), node, callstack );
666                 */

667                 if ( DEBUG )
668                     // show extra "expecting..." info
669
error( e.getMessage(DEBUG) );
670
671                 // add the source file info and throw again
672
e.setErrorSourceFile( sourceFileInfo );
673                 throw e;
674
675             } catch ( InterpreterError e ) {
676                 e.printStackTrace();
677                 throw new EvalError(
678                     "Sourced file: "+sourceFileInfo+" internal Error: "
679                     + e.getMessage(), node, callstack);
680             } catch ( TargetError e ) {
681                 // failsafe, set the Line as the origin of the error.
682
if ( e.getNode()==null )
683                     e.setNode( node );
684                 e.reThrow("Sourced file: "+sourceFileInfo);
685             } catch ( EvalError e) {
686                 if ( DEBUG)
687                     e.printStackTrace();
688                 // failsafe, set the Line as the origin of the error.
689
if ( e.getNode()==null )
690                     e.setNode( node );
691                 e.reThrow( "Sourced file: "+sourceFileInfo );
692             } catch ( Exception JavaDoc e) {
693                 if ( DEBUG)
694                     e.printStackTrace();
695                 throw new EvalError(
696                     "Sourced file: "+sourceFileInfo+" unknown error: "
697                     + e.getMessage(), node, callstack);
698             } catch(TokenMgrError e) {
699                 throw new EvalError(
700                     "Sourced file: "+sourceFileInfo+" Token Parsing Error: "
701                     + e.getMessage(), node, callstack );
702             } finally {
703                 localInterpreter.get_jjtree().reset();
704
705                 // reinit the callstack
706
if ( callstack.depth() > 1 ) {
707                     callstack.clear();
708                     callstack.push( nameSpace );
709                 }
710             }
711         }
712         return Primitive.unwrap( retVal );
713     }
714
715     /**
716         Evaluate the inputstream in this interpreter's global namespace.
717     */

718     public Object JavaDoc eval( Reader in ) throws EvalError
719     {
720         return eval( in, globalNameSpace, "eval stream" );
721     }
722
723     /**
724         Evaluate the string in this interpreter's global namespace.
725     */

726     public Object JavaDoc eval( String JavaDoc statements ) throws EvalError {
727         if ( Interpreter.DEBUG ) debug("eval(String): "+statements);
728         return eval(statements, globalNameSpace);
729     }
730
731     /**
732         Evaluate the string in the specified namespace.
733     */

734     public Object JavaDoc eval( String JavaDoc statements, NameSpace nameSpace )
735         throws EvalError
736     {
737
738         String JavaDoc s = ( statements.endsWith(";") ? statements : statements+";" );
739         return eval(
740             new StringReader(s), nameSpace,
741             "inline evaluation of: ``"+ showEvalString(s)+"''" );
742     }
743
744     private String JavaDoc showEvalString( String JavaDoc s ) {
745         s = s.replace('\n', ' ');
746         s = s.replace('\r', ' ');
747         if ( s.length() > 80 )
748             s = s.substring( 0, 80 ) + " . . . ";
749         return s;
750     }
751
752     // end source and eval
753

754     /**
755         Print an error message in a standard format on the output stream
756         associated with this interpreter. On the GUI console this will appear
757         in red, etc.
758     */

759     public final void error( Object JavaDoc o ) {
760         if ( console != null )
761                 console.error( "// Error: " + o +"\n" );
762         else {
763             err.println("// Error: " + o );
764             err.flush();
765         }
766     }
767
768     // ConsoleInterface
769
// The interpreter reflexively implements the console interface that it
770
// uses. Should clean this up by using an inner class to implement the
771
// console for us.
772

773     /**
774         Get the input stream associated with this interpreter.
775         This may be be stdin or the GUI console.
776     */

777     public Reader getIn() { return in; }
778
779     /**
780         Get the outptut stream associated with this interpreter.
781         This may be be stdout or the GUI console.
782     */

783     public PrintStream getOut() { return out; }
784
785     /**
786         Get the error output stream associated with this interpreter.
787         This may be be stderr or the GUI console.
788     */

789     public PrintStream getErr() { return err; }
790
791     public final void println( Object JavaDoc o )
792     {
793         print( String.valueOf(o) + systemLineSeparator );
794     }
795
796     public final void print( Object JavaDoc o )
797     {
798         if (console != null) {
799             console.print(o);
800         } else {
801             out.print(o);
802             out.flush();
803         }
804     }
805
806     // End ConsoleInterface
807

808     /**
809         Print a debug message on debug stream associated with this interpreter
810         only if debugging is turned on.
811     */

812     public final static void debug(String JavaDoc s)
813     {
814         if ( DEBUG )
815             debug.println("// Debug: " + s);
816     }
817
818     /*
819         Primary interpreter set and get variable methods
820         Note: These are squeltching errors... should they?
821     */

822
823     /**
824         Get the value of the name.
825         name may be any value. e.g. a variable or field
826     */

827     public Object JavaDoc get( String JavaDoc name ) throws EvalError {
828         try {
829             Object JavaDoc ret = globalNameSpace.get( name, this );
830             return Primitive.unwrap( ret );
831         } catch ( UtilEvalError e ) {
832             throw e.toEvalError( SimpleNode.JAVACODE, new CallStack() );
833         }
834     }
835
836     /**
837         Unchecked get for internal use
838     */

839     Object JavaDoc getu( String JavaDoc name ) {
840         try {
841             return get( name );
842         } catch ( EvalError e ) {
843             throw new InterpreterError("set: "+e);
844         }
845     }
846
847     /**
848         Assign the value to the name.
849         name may evaluate to anything assignable. e.g. a variable or field.
850     */

851     public void set( String JavaDoc name, Object JavaDoc value )
852         throws EvalError
853     {
854         // map null to Primtive.NULL coming in...
855
if ( value == null )
856             value = Primitive.NULL;
857
858         CallStack callstack = new CallStack();
859         try {
860             if ( Name.isCompound( name ) )
861             {
862                 LHS lhs = globalNameSpace.getNameResolver( name ).toLHS(
863                     callstack, this );
864                 lhs.assign( value, false );
865             } else // optimization for common case
866
globalNameSpace.setVariable( name, value, false );
867         } catch ( UtilEvalError e ) {
868             throw e.toEvalError( SimpleNode.JAVACODE, callstack );
869         }
870     }
871
872     /**
873         Unchecked set for internal use
874     */

875     void setu(String JavaDoc name, Object JavaDoc value) {
876         try {
877             set(name, value);
878         } catch ( EvalError e ) {
879             throw new InterpreterError("set: "+e);
880         }
881     }
882
883     public void set(String JavaDoc name, long value) throws EvalError {
884         set(name, new Primitive(value));
885     }
886     public void set(String JavaDoc name, int value) throws EvalError {
887         set(name, new Primitive(value));
888     }
889     public void set(String JavaDoc name, double value) throws EvalError {
890         set(name, new Primitive(value));
891     }
892     public void set(String JavaDoc name, float value) throws EvalError {
893         set(name, new Primitive(value));
894     }
895     public void set(String JavaDoc name, boolean value) throws EvalError {
896         set(name, new Primitive(value));
897     }
898
899     /**
900         Unassign the variable name.
901         Name should evaluate to a variable.
902     */

903     public void unset( String JavaDoc name )
904         throws EvalError
905     {
906         /*
907             We jump through some hoops here to handle arbitrary cases like
908             unset("bsh.foo");
909         */

910         CallStack callstack = new CallStack();
911         try {
912             LHS lhs = globalNameSpace.getNameResolver( name ).toLHS(
913                 callstack, this );
914
915             if ( lhs.type != LHS.VARIABLE )
916                 throw new EvalError("Can't unset, not a variable: "+name,
917                     SimpleNode.JAVACODE, new CallStack() );
918
919             //lhs.assign( null, false );
920
lhs.nameSpace.unsetVariable( name );
921         } catch ( UtilEvalError e ) {
922             throw new EvalError( e.getMessage(),
923                 SimpleNode.JAVACODE, new CallStack() );
924         }
925     }
926
927     // end primary set and get methods
928

929     /**
930         Get a reference to the interpreter (global namespace), cast
931         to the specified interface type. Assuming the appropriate
932         methods of the interface are defined in the interpreter, then you may
933         use this interface from Java, just like any other Java object.
934         <p>
935
936         For example:
937         <pre>
938             Interpreter interpreter = new Interpreter();
939             // define a method called run()
940             interpreter.eval("run() { ... }");
941
942             // Fetch a reference to the interpreter as a Runnable
943             Runnable runnable =
944                 (Runnable)interpreter.getInterface( Runnable.class );
945         </pre>
946         <p>
947
948         Note that the interpreter does *not* require that any or all of the
949         methods of the interface be defined at the time the interface is
950         generated. However if you attempt to invoke one that is not defined
951         you will get a runtime exception.
952         <p>
953
954         Note also that this convenience method has exactly the same effect as
955         evaluating the script:
956         <pre>
957             (Type)this;
958         </pre>
959         <p>
960
961         For example, the following is identical to the previous example:
962         <p>
963
964         <pre>
965             // Fetch a reference to the interpreter as a Runnable
966             Runnable runnable =
967                 (Runnable)interpreter.eval( "(Runnable)this" );
968         </pre>
969         <p>
970
971         <em>Version requirement</em> Although standard Java interface types
972         are always available, to be used with arbitrary interfaces this
973         feature requires that you are using Java 1.3 or greater.
974         <p>
975
976         @throws EvalError if the interface cannot be generated because the
977         version of Java does not support the proxy mechanism.
978     */

979     public Object JavaDoc getInterface( Class JavaDoc interf ) throws EvalError
980     {
981         try {
982             return globalNameSpace.getThis( this ).getInterface( interf );
983         } catch ( UtilEvalError e ) {
984             throw e.toEvalError( SimpleNode.JAVACODE, new CallStack() );
985         }
986     }
987
988     /* Methods for interacting with Parser */
989
990     private JJTParserState get_jjtree() {
991         return parser.jjtree;
992     }
993
994     private JavaCharStream get_jj_input_stream() {
995         return parser.jj_input_stream;
996     }
997
998     private boolean Line() throws ParseException {
999         return parser.Line();
1000    }
1001
1002    /* End methods for interacting with Parser */
1003
1004    void loadRCFiles() {
1005        try {
1006            String JavaDoc rcfile =
1007                // Default is c:\windows under win98, $HOME under Unix
1008
System.getProperty("user.home") + File.separator + ".bshrc";
1009            source( rcfile, globalNameSpace );
1010        } catch ( Exception JavaDoc e ) {
1011            // squeltch security exception, filenotfoundexception
1012
if ( Interpreter.DEBUG ) debug("Could not find rc file: "+e);
1013        }
1014    }
1015
1016    /**
1017        Localize a path to the file name based on the bsh.cwd interpreter
1018        working directory.
1019    */

1020    public File pathToFile( String JavaDoc fileName )
1021        throws IOException
1022    {
1023        File file = new File( fileName );
1024
1025        // if relative, fix up to bsh.cwd
1026
if ( !file.isAbsolute() ) {
1027            String JavaDoc cwd = (String JavaDoc)getu("bsh.cwd");
1028            file = new File( cwd + File.separator + fileName );
1029        }
1030
1031        // The canonical file name is also absolute.
1032
// No need for getAbsolutePath() here...
1033
return new File( file.getCanonicalPath() );
1034    }
1035
1036    public static void redirectOutputToFile( String JavaDoc filename )
1037    {
1038        try {
1039            PrintStream pout = new PrintStream(
1040                new FileOutputStream( filename ) );
1041            System.setOut( pout );
1042            System.setErr( pout );
1043        } catch ( IOException e ) {
1044            System.err.println("Can't redirect output to file: "+filename );
1045        }
1046    }
1047
1048    /**
1049        Set an external class loader to be used as the base classloader
1050        for BeanShell. The base classloader is used for all classloading
1051        unless/until the addClasspath()/setClasspath()/reloadClasses()
1052        commands are called to modify the interpreter's classpath. At that
1053        time the new paths /updated paths are added on top of the base
1054        classloader.
1055        <p>
1056
1057        BeanShell will use this at the same point it would otherwise use the
1058        plain Class.forName().
1059        i.e. if no explicit classpath management is done from the script
1060        (addClassPath(), setClassPath(), reloadClasses()) then BeanShell will
1061        only use the supplied classloader. If additional classpath management
1062        is done then BeanShell will perform that in addition to the supplied
1063        external classloader.
1064        However BeanShell is not currently able to reload
1065        classes supplied through the external classloader.
1066        <p>
1067
1068        @see BshClassManager#setClassLoader( ClassLoader )
1069    */

1070    public void setClassLoader( ClassLoader JavaDoc externalCL ) {
1071        getClassManager().setClassLoader( externalCL );
1072    }
1073
1074    /**
1075        Get the class manager associated with this interpreter
1076        (the BshClassManager of this interpreter's global namespace).
1077        This is primarily a convenience method.
1078    */

1079    public BshClassManager getClassManager()
1080    {
1081        return getNameSpace().getClassManager();
1082    }
1083
1084    /**
1085        Set strict Java mode on or off.
1086        This mode attempts to make BeanShell syntax behave as Java
1087        syntax, eliminating conveniences like loose variables, etc.
1088        When enabled, variables are required to be declared or initialized
1089        before use and method arguments are reqired to have types.
1090        <p>
1091
1092        This mode will become more strict in a future release when
1093        classes are interpreted and there is an alternative to scripting
1094        objects as method closures.
1095    */

1096    public void setStrictJava( boolean b ) {
1097        this.strictJava = b;
1098    }
1099
1100    /**
1101        @see #setStrictJava( boolean )
1102    */

1103    public boolean getStrictJava() {
1104        return this.strictJava;
1105    }
1106
1107    static void staticInit()
1108    {
1109    /*
1110        Apparently in some environments you can't catch the security exception
1111        at all... e.g. as an applet in IE ... will probably have to work
1112        around
1113    */

1114        try {
1115            systemLineSeparator = System.getProperty("line.separator");
1116            debug = System.err;
1117            DEBUG = Boolean.getBoolean("debug");
1118            TRACE = Boolean.getBoolean("trace");
1119            LOCALSCOPING = Boolean.getBoolean("localscoping");
1120            String JavaDoc outfilename = System.getProperty("outfile");
1121            if ( outfilename != null )
1122                redirectOutputToFile( outfilename );
1123        } catch ( SecurityException JavaDoc e ) {
1124            System.err.println("Could not init static:"+e);
1125        } catch ( Exception JavaDoc e ) {
1126            System.err.println("Could not init static(2):"+e);
1127        } catch ( Throwable JavaDoc e ) {
1128            System.err.println("Could not init static(3):"+e);
1129        }
1130    }
1131
1132    /**
1133        Specify the source of the text from which this interpreter is reading.
1134        Note: there is a difference between what file the interrpeter is
1135        sourcing and from what file a method was originally parsed. One
1136        file may call a method sourced from another file. See SimpleNode
1137        for origination file info.
1138        @see bsh.SimpleNode#getSourceFile()
1139    */

1140    public String JavaDoc getSourceFileInfo() {
1141        if ( sourceFileInfo != null )
1142            return sourceFileInfo;
1143        else
1144            return "<unknown source>";
1145    }
1146
1147    /**
1148        Get the parent Interpreter of this interpreter, if any.
1149        Currently this relationship implies the following:
1150            1) Parent and child share a BshClassManager
1151            2) Children indicate the parent's source file information in error
1152            reporting.
1153        When created as part of a source() / eval() the child also shares
1154        the parent's namespace. But that is not necessary in general.
1155    */

1156    public Interpreter getParent() {
1157        return parent;
1158    }
1159
1160    public void setOut( PrintStream out ) {
1161        this.out = out;
1162    }
1163    public void setErr( PrintStream err ) {
1164        this.err = err;
1165    }
1166
1167    /**
1168        De-serialization setup.
1169        Default out and err streams to stdout, stderr if they are null.
1170    */

1171    private void readObject(ObjectInputStream stream)
1172        throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc
1173    {
1174        stream.defaultReadObject();
1175
1176        // set transient fields
1177
if ( console != null ) {
1178            setOut( console.getOut() );
1179            setErr( console.getErr() );
1180        } else {
1181            setOut( System.out );
1182            setErr( System.err );
1183        }
1184    }
1185
1186    /**
1187        Get the prompt string defined by the getBshPrompt() method in the
1188        global namespace. This may be from the getBshPrompt() command or may
1189        be defined by the user as with any other method.
1190        Defaults to "bsh % " if the method is not defined or there is an error.
1191    */

1192    private String JavaDoc getBshPrompt()
1193    {
1194        try {
1195            return (String JavaDoc)eval("getBshPrompt()");
1196        } catch ( Exception JavaDoc e ) {
1197            return "bsh % ";
1198        }
1199    }
1200
1201    /**
1202        Specify whether, in interactive mode, the interpreter exits Java upon
1203        end of input. If true, when in interactive mode the interpreter will
1204        issue a System.exit(0) upon eof. If false the interpreter no
1205        System.exit() will be done.
1206        <p/>
1207        Note: if you wish to cause an EOF externally you can try closing the
1208        input stream. This is not guaranteed to work in older versions of Java
1209        due to Java limitations, but should work in newer JDK/JREs. (That was
1210        the motivation for the Java NIO package).
1211    */

1212    public void setExitOnEOF( boolean value ) {
1213        exitOnEOF = value; // ug
1214
}
1215
1216    /**
1217        Turn on/off the verbose printing of results as for the show()
1218         command.
1219        If this interpreter has a parent the call is delegated.
1220        See the BeanShell show() command.
1221    */

1222    public void setShowResults( boolean showResults ) {
1223        this.showResults = showResults;
1224    }
1225    /**
1226     Show on/off verbose printing status for the show() command.
1227     See the BeanShell show() command.
1228     If this interpreter has a parent the call is delegated.
1229     */

1230    public boolean getShowResults() {
1231        return showResults;
1232    }
1233}
1234
1235
Popular Tags