Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: bsh/Interpreter.java


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;
37  import java.io.*;
38  import java.io.File;            // why? I don't know
39  import bsh.util.BshCompleter;
40  import bsh.util.NameCompletionTable;
41  import bsh.classpath.ClassManagerImpl;
42  import org.gnu.readline.Readline;
43  import org.gnu.readline.ReadlineReader;
44  
45  /**
46          The BeanShell script interpreter.
47  
48          An instance of Interpreter can be used to source scripts and evaluate 
49          statements or expressions.  
50          <p>
51          Here are some examples:
52  
53          <p><blockquote><pre>
54                  Interpeter bsh = new Interpreter();
55  
56                  // Evaluate statements and expressions
57                  bsh.eval("foo=Math.sin(0.5)");
58                  bsh.eval("bar=foo*5; bar=Math.cos(bar);");
59                  bsh.eval("for(i=0; i<10; i++) { print(\"hello\"); }");
60                  // same as above using java syntax and apis only
61                  bsh.eval("for(int i=0; i<10; i++) { System.out.println(\"hello\"); }");
62  
63                  // Source from files or streams
64                  bsh.source("myscript.bsh");  // or bsh.eval("source(\"myscript.bsh\")");
65  
66                  // Use set() and get() to pass objects in and out of variables
67                  bsh.set( "date", new Date() );
68                  Date date = (Date)bsh.get( "date" );
69                  // This would also work:
70                  Date date = (Date)bsh.eval( "date" );
71  
72                  bsh.eval("year = date.getYear()");
73                  Integer year = (Integer)bsh.get("year");  // primitives use wrappers
74  
75                  // With Java1.3+ scripts can implement arbitrary interfaces...
76                  // Script an awt event handler (or source it from a file, more likely)
77                  bsh.eval( "actionPerformed( e ) { print( e ); }");
78                  // Get a reference to the script object (implementing the interface)
79                  ActionListener scriptedHandler = 
80                          (ActionListener)bsh.eval("return (ActionListener)this");
81                  // Use the scripted event handler normally...
82                  new JButton.addActionListener( script );
83          </pre></blockquote>
84          <p>
85  
86          In the above examples we showed a single interpreter instance, however 
87          you may wish to use many instances, depending on the application and how
88          you structure your scripts.  Interpreter instances are very light weight
89          to create, however if you are going to execute the same script repeatedly
90          and require maximum performance you should consider scripting the code as 
91          a method and invoking the scripted method each time on the same interpreter
92          instance (using eval()). 
93          <p>
94  
95          See the BeanShell User's Manual for more information.
96  */
97  public class Interpreter 
98      implements Runnable, ConsoleInterface /*,Serializable*/ 
99  {
100     /* --- Begin static stuff --- */
101 
102     public static final String VERSION = "1.1a16";
103     /* 
104        Debug utils are static so that they are reachable by code that doesn't
105        necessarily have an interpreter reference (e.g. tracing in utils).
106        In the future we may want to allow debug/trace to be turned on on
107        a per interpreter basis, in which case we'll need to use the parent 
108        reference in some way to determine the scope of the command that 
109        turns it on or off...
110         */
111 
112     public static boolean DEBUG, TRACE;
113     // This should be per instance
114     static PrintStream debug;
115     static { 
116         staticInit();
117     }
118 
119     /** Shared system object visible under bsh.system */
120     static This systemObject;
121 
122     /* --- end static stuff --- */
123 
124         /* --- Instance data --- */
125 
126     Parser parser;
127     NameSpace globalNameSpace;
128     Reader in;
129     PrintStream out;
130     PrintStream err;
131     ConsoleInterface console; 
132 
133         /** If this interpeter is a child of another, the parent */
134     Interpreter parent;
135 
136     /** The name of the file or other source that this interpreter is reading */
137     String sourceFileInfo;
138 
139     /** 
140                 Do we override exit on EOF as normally done in iteractive mode?
141                 (This is used by Sessiond)
142         */
143     public boolean noExitOnEOF;
144 
145     private boolean 
146         evalOnly,               // Interpreter has no input stream, use eval() only
147         interactive;    // Interpreter has a user, print prompts, etc.
148 
149         /* --- End instance data --- */
150 
151         /**
152                 The main constructor.
153                 All constructors should now pass through here.
154 
155                 @param namespace If namespace is non-null then this interpreter's 
156                 root namespace will be set to the one provided.  If it is null a new 
157                 one will be created for it.
158                 @param parent The parent interpreter if this interpreter is a child 
159                         of another.  May be null.
160                 @param sourceFileInfo An informative string holding the filename 
161                 or other description of the source from which this interpreter is
162                 reading... used for debugging.  May be null.
163         */
164     public Interpreter(
165                        Reader in, PrintStream out, PrintStream err, 
166                        boolean interactive, NameSpace namespace,
167                        Interpreter parent, String sourceFileInfo )
168     {
169         parser = new Parser( in );
170         long t1=System.currentTimeMillis();
171         this.in = in;
172         this.out = out;
173         this.err = err;
174         this.interactive = interactive;
175         debug = err;
176         this.parent = parent;
177         this.sourceFileInfo = sourceFileInfo;
178 
179         if ( namespace == null )
180             this.globalNameSpace = new NameSpace("global");
181         else
182             this.globalNameSpace = namespace;
183 
184         // The classes which are imported by default
185         globalNameSpace.loadDefaultImports();
186 
187         /* 
188            Create the root "bsh" system object if it doesn't exist.
189         */
190         if ( ! ( getu("bsh") instanceof bsh.This ) )
191             initRootSystemObject();
192 
193         if ( interactive )
194             loadRCFiles();
195 
196         long t2=System.currentTimeMillis();
197         Interpreter.debug("Time to initialize interpreter: "+(t2-t1));
198     }
199 
200     public Interpreter(
201                        Reader in, PrintStream out, PrintStream err, 
202                        boolean interactive, NameSpace namespace)
203     {
204         this( in, out, err, interactive, namespace, null, null );
205     }
206 
207     public Interpreter(
208                        Reader in, PrintStream out, PrintStream err, boolean interactive)
209     {
210         this(in, out, err, interactive, null);
211     }
212 
213     /**
214                 Construct a new interactive interpreter attached to the specified 
215                 console using the specified parent namespace.
216         */
217     public Interpreter(ConsoleInterface console, NameSpace globalNameSpace) {
218 
219         this( console.getIn(), console.getOut(), console.getErr(), 
220               true, globalNameSpace );
221 
222         setConsole( console );
223     }
224 
225     /**
226                 Construct a new interactive interpreter attached to the specified 
227                 console.
228         */
229 
230     public Interpreter(ConsoleInterface console) {
231         this(console, null);
232     }
233 
234 
235     /**
236                 Create an interpreter for evaluation only.
237         */
238     public Interpreter()
239     {
240         this( new StringReader(""), 
241               System.out, System.err, false, null );
242         evalOnly = true;
243         setu( "bsh.evalOnly", new Primitive(true) );
244     }
245 
246     // End constructors
247 
248         /**
249                 Attach the console thusly... ;)
250         */
251     public void setConsole( ConsoleInterface console ) {
252         this.console = console;
253         setu( "bsh.console", console );
254     }
255 
256     private void initRootSystemObject() 
257     {
258         // bsh
259         setu("bsh", new NameSpace( "Bsh Object" ).getThis( this ) );
260 
261                 // init the static shared systemObject if it's not there yet
262         if ( systemObject == null )
263             systemObject = new NameSpace( 
264                                          "Bsh System Object" ).getThis( this );
265         // bsh.system
266         setu( "bsh.system", systemObject );
267 
268         // bsh.help
269         This helpText = new NameSpace( 
270                                       "Bsh Command Help Text" ).getThis( this );
271         setu( "bsh.help", helpText );
272 
273                 // bsh.cwd
274         try {
275             setu( "bsh.cwd", System.getProperty("user.dir") );
276         } catch ( SecurityException e ) { 
277             // applets can't see sys props
278             setu( "bsh.cwd", "." );
279         }
280 
281         // bsh.interactive
282         setu( "bsh.interactive", new Primitive(interactive) );
283         // bsh.evalOnly
284         setu( "bsh.evalOnly", new Primitive(evalOnly) );
285     }
286 
287     /**
288                 Set the global namespace for this interpreter.
289                 <p>
290 
291                 Note: This is here for completeness.  If you're using this a lot 
292                 it may be an indication that you are doing more work than you have 
293                 to.  For example, caching the interpreter instance rather than the 
294                 namespace should not add a significant overhead.  No state other 
295                 than the debug status is stored in the interpreter.
296                 <p>
297 
298                 All features of the namespace can also be accessed using the 
299                 interpreter via eval() and the script variable 'this.namespace'
300                 (or global.namespace as necessary).
301         */
302     public void setNameSpace( NameSpace globalNameSpace ) {
303         this.globalNameSpace = globalNameSpace;
304     }
305 
306     /**
307                 Get the global namespace of this interpreter.
308                 <p>
309 
310                 Note: This is here for completeness.  If you're using this a lot 
311                 it may be an indication that you are doing more work than you have 
312                 to.  For example, caching the interpreter instance rather than the 
313                 namespace should not add a significant overhead.  No state other than 
314                 the debug status is stored in the interpreter.  
315                 <p>
316 
317                 All features of the namespace can also be accessed using the 
318                 interpreter via eval() and the script variable 'this.namespace'
319                 (or global.namespace as necessary).
320         */
321     public NameSpace getNameSpace() {
322         return globalNameSpace;
323     }
324 
325     /**
326                 Run the text only interpreter on the command line or specify a file.
327         */
328     public static void main( String [] args ) 
329     {
330         if ( args.length > 0 ) {
331             String filename = args[0];
332 
333             String [] bshArgs;
334             if ( args.length > 1 ) {
335                 bshArgs = new String [ args.length -1 ];
336                 System.arraycopy( args, 1, bshArgs, 0, args.length-1 );
337             } else
338                 bshArgs = new String [0];
339 
340             Interpreter interpreter = new Interpreter();
341             interpreter.setu( "bsh.args", bshArgs );
342             try {
343                 interpreter.source( filename, interpreter.globalNameSpace );
344             } catch ( FileNotFoundException e ) {
345                 System.out.println("File not found: "+e);
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 = null;
368             boolean usingReadline = false;
369             try {
370                 File history = new File(System.getProperty("user.home") +
371                                         File.separator + ".bsh_history");
372                 if (!history.exists()) {
373                     try {
374                         history.createNewFile();
375                     } catch(IOException ioe) {
376                         debug("Unable to create history file: " + history.getAbsolutePath());
377                     }
378                 }
379                 // should I wrap CommandLineReader around it?
380                 if (history.canWrite() && history.canRead()) {
381                     in = new ReadlineReader("bsh % ", history,ReadlineLibrary.Editline);
382                 } else {
383                     in = new ReadlineReader("bsh % ",ReadlineLibrary.Editline);
384                     debug("Unable to read/write history file: " + history.getAbsolutePath());
385                 }
386             } catch (IOException ioe) {
387                 System.err.println("Unable to invoke ReadlineReader " +
388                                    "due to: " + ioe);
389             }
390             if (in == null)
391                 in = new CommandLineReader( new InputStreamReader(src));
392             else 
393                 usingReadline = true;
394             Interpreter interpreter = 
395                 new Interpreter( in, System.out, System.err, true );
396             if (usingReadline) {
397                 NameCompletionTable nct = new NameCompletionTable();
398                 nct.add(interpreter.getNameSpace());
399 
400                 /** ClassManager does a lot of chatting to the stdout,
401                  *  so this has been commented out for the time being
402                  **/
403 
404 //              try {
405 //                  BshClassManager bcm = BshClassManager.getClassManager();
406 //                      if (bcm != null) {
407 //                          nct.add(((ClassManagerImpl)bcm).getClassPath());
408 //                      }
409 //                  } catch(ClassPathException cpe) {
410 //                      debug("classpath exception in name compl:" + cpe);
411 //                  } 
412 
413                 Readline.setCompleter(new BshCompleter(nct));
414             }
415             interpreter.run();
416         }
417     }
418 
419     /**
420                 Run interactively.  (printing prompts, etc.)
421         */
422     public void run() {
423         if(evalOnly)
424             throw new RuntimeException("bsh Interpreter: No stream");
425 
426         /*
427           We'll print our banner using eval(String) in order to
428           exercise the parser and get the basic expression classes loaded...
429           This ameliorates the delay after typing the first statement.
430         */
431         if ( interactive )
432             try { 
433                 eval("printBanner();"); 
434             } catch ( EvalError e ) {
435                 println(
436                         "BeanShell "+VERSION+" - by Pat Niemeyer (pat@pat.net)");
437             }
438 
439         boolean eof = false;
440 
441         // init the callstack.  
442         CallStack callstack = new CallStack();
443         callstack.push( globalNameSpace );
444 
445         while(!eof)
446             {
447                 try
448                     {
449                         // try to sync up the console
450                         System.out.flush();
451                         System.err.flush();
452                         Thread.yield();  // this helps a little
453                         if(interactive && !(in instanceof ReadlineReader))
454                             print("bsh % ");
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 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                                 if(ret != Primitive.VOID)
475                                     {
476                                         setVariable("$_", ret);
477                                         Object show = getu("bsh.show");
478                                         if(show instanceof Boolean &&
479                                            ((Boolean)show).booleanValue() == true)
480                                             println("<" + ret + ">");
481                                     }
482                             }
483                     }
484                 catch(ParseException e)
485                     {
486                         error("Parser Error: " + e.getMessage(DEBUG));
487                         if(DEBUG)
488                             e.printStackTrace();
489                         if(!interactive)
490                             eof = true;
491 
492                         parser.reInitInput(in);
493                     }
494                 catch(InterpreterError e)
495                     {
496                         error("Internal Error: " + e.getMessage());
497                         e.printStackTrace();
498                         if(!interactive)
499                             eof = true;
500                     }
501                 catch(TargetError e)
502                     {
503                         error("// Uncaught Exception: " + e );
504                         if(DEBUG)
505                             e.printStackTrace();
506                         if(!interactive)
507                             eof = true;
508                     }
509                 catch (EvalError e)
510                     {
511                         if ( interactive )
512                             error( e.toString() );
513                         else
514                             error( e.getMessage() );
515                         if(DEBUG)
516                             e.printStackTrace();
517                         if(!interactive)
518                             eof = true;
519                     }
520                 catch(Exception e)
521                     {
522                         error("Unknown error: " + e);
523                         e.printStackTrace();
524                         if(!interactive)
525                             eof = true;
526                     }
527                 catch(TokenMgrError e)
528                     {
529                         error("Error parsing input: " + e);
530 
531                                 /*
532                                   We get stuck in infinite loops here when unicode escapes
533                                   fail.  Must re-init the char stream reader 
534                                   (ASCII_UCodeESC_CharStream.java)
535                                 */
536                         parser.reInitTokenInput( in );
537 
538                         if(!interactive)
539                             eof = true;
540                     }
541                 finally
542                     {
543                         get_jjtree().reset();
544                                 // reinit the callstack
545                         callstack.clear();
546                         callstack.push( globalNameSpace );
547                     }
548             }
549 
550         if ( interactive && !noExitOnEOF ) {
551             /* should be done for all streams in general, but this
552              * ensures that the history for readline is flushed */
553             try {
554                 in.close();
555             } catch (IOException ioe) {
556             }
557             System.exit(0);
558         }
559     }
560 
561     // begin source and eval
562 
563         /**
564                 Read text from fileName and eval it.
565         */
566     public Object source( String filename, NameSpace nameSpace ) 
567         throws FileNotFoundException, IOException, EvalError 
568     {
569         File file = pathToFile( filename );
570         debug("Sourcing file: "+file);
571         Reader in = new BufferedReader( new FileReader(file) );
572         return eval( in, nameSpace, filename );
573     }
574 
575     /**
576                 Read text from fileName and eval it.
577                 Convenience method.  Use the global namespace.
578         */
579     public Object source( String filename ) 
580         throws FileNotFoundException, IOException, EvalError 
581     {
582         return source( filename, globalNameSpace );
583     }
584 
585     /**
586         Spawn a non-interactive local interpreter to evaluate text in the 
587                 specified namespace.  
588 
589                 Return value is the evaluated object (or corresponding primitive 
590                 wrapper).
591 
592                 @param sourceFileInfo is for information purposes only.  It is used to
593                 display error messages (and in the future may be made available to
594                 the script).
595                 @throws EvalError on script problems
596                 @throws TargetError on unhandled exceptions from the script
597     */
598         /*
599                 Note: we need a form of eval that passes the callstack through...
600         */
601         /*
602         Can't this be combined with run() ?
603         run seems to have stuff in it for interactive vs. non-interactive...
604         compare them side by side and see what they do differently, aside from the
605         exception handling.
606         */
607 
608     public Object eval( 
609                        Reader in, NameSpace nameSpace, String sourceFileInfo ) 
610         throws EvalError 
611     {
612         Object retVal = null;
613         debug("eval: nameSpace = "+nameSpace);
614 
615         /* 
616            Create non-interactive local interpreter for this namespace
617            with source from the input stream and out/err same as 
618            this interpreter.
619         */
620         Interpreter localInterpreter = 
621             new Interpreter( 
622                             in, out, err, false, nameSpace, this, sourceFileInfo  );
623 
624         CallStack callstack = new CallStack();
625         callstack.push( 
626                        new NameSpace("Evaluation global for: "+sourceFileInfo) );
627         callstack.push( 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() > 2 )
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                     } catch(ParseException e) {
658                         throw new EvalError(
659                                             "Sourced file: "+sourceFileInfo+" parser Error: " 
660                                             + e.getMessage( DEBUG ), node );
661                     } catch(InterpreterError e) {
662                         e.printStackTrace();
663                         throw new EvalError(
664                                             "Sourced file: "+sourceFileInfo+" internal Error: " 
665                                             + e.getMessage(), node);
666                     } catch( TargetError e ) {
667                         if(DEBUG)
668                             e.printStackTrace();
669                                 // failsafe, set the Line as the origin of the error.
670                         if ( e.getNode()==null )
671                             e.setNode( node );
672                         e.reThrow("Sourced file: "+sourceFileInfo);
673                     } catch(EvalError e) {
674                         if(DEBUG)
675                             e.printStackTrace();
676                                 // failsafe, set the Line as the origin of the error.
677                         if ( e.getNode()==null )
678                             e.setNode( node );
679                         e.reThrow( "Sourced file: "+sourceFileInfo );
680                     } catch(Exception e) {
681                         e.printStackTrace();
682                         throw new EvalError(
683                                             "Sourced file: "+sourceFileInfo+" unknown error: " 
684                                             + e.getMessage(), node);
685                     } catch(TokenMgrError e) {
686                         throw new EvalError(
687                                             "Sourced file: "+sourceFileInfo+" Token Parsing Error: " 
688                                             + e.getMessage(), node );
689                     } finally {
690                         localInterpreter.get_jjtree().reset();
691                         callstack.clear();
692                         callstack.push( nameSpace );
693                     }
694             }
695         return Primitive.unwrap( retVal );
696     }
697 
698     /**
699                 Evaluate the inputstream in this interpreter's global namespace.
700         */
701     public Object eval( Reader in ) throws EvalError 
702     {
703         return eval( in, globalNameSpace, "eval stream" );
704     }
705 
706     /**
707                 Evaluate the string in this interpreter's global namespace.
708         */
709     public Object eval( String statement ) throws EvalError {
710         return eval(statement, globalNameSpace);
711     }
712 
713     /**
714                 Evaluate the string in the specified namespace.
715         */
716     public Object eval( String statement, NameSpace nameSpace ) 
717         throws EvalError {
718 
719         String s = ( statement.endsWith(";") ? statement : statement+";" );
720         return eval( 
721                     new StringReader(s), nameSpace, "<Inline eval of: "+s+" >" );
722     }
723 
724     // end source and eval
725 
726         /**
727                 Print an error message in a standard format on the output stream
728                 associated with this interpreter. On the GUI console this will appear 
729                 in red, etc.
730         */
731     public final void error(String s) {
732         if ( console != null )
733             console.error( "// Error: " + s +"\n" );
734         else {
735             err.println("// Error: " + s);
736             err.flush();
737         }
738     }
739 
740     // ConsoleInterface
741     // The interpreter reflexively implements the console interface that it 
742     // uses.  Should clean this up by using an inner class to implement the
743     // console for us.
744 
745     /** 
746                 Get the input stream associated with this interpreter.
747                 This may be be stdin or the GUI console.
748         */
749     public Reader getIn() { return in; }
750 
751     /** 
752                 Get the outptut stream associated with this interpreter.
753                 This may be be stdout or the GUI console.
754         */
755     public PrintStream getOut() { return out; }
756 
757     /** 
758                 Get the error output stream associated with this interpreter.
759                 This may be be stderr or the GUI console.
760         */
761     public PrintStream getErr() { return err; }
762 
763     public final void println(String s)
764     {
765         print(s + "\n");
766     }
767 
768     public final void print(String s)
769     {
770         if (console != null) {
771             console.print(s);
772         } else {
773             out.print(s);
774             out.flush();
775         }
776     }
777 
778     // End ConsoleInterface
779 
780         /**
781                 Print a debug message on debug stream associated with this interpreter
782                 only if debugging is turned on.
783         */
784     public final static void debug(String s)
785     {
786         if(DEBUG)
787             debug.println("// Debug: " + s);
788     }
789 
790     /* 
791                 Primary interpreter set and get variable methods
792                 Note: These are squeltching errors... should they?
793         */
794 
795         /**
796                 Get the value of the name.
797                 name may be any value. e.g. a variable or field
798         */
799     public Object get( String name ) throws EvalError {
800         Object ret = globalNameSpace.get( name, this );
801         return Primitive.unwrap( ret );
802     }
803 
804     /**
805                 Unchecked get for internal use
806         */
807     Object getu( String name ) {
808         try { 
809             return get( name );
810         } catch ( EvalError e ) { 
811             throw new InterpreterError("set: "+e);
812         }
813     }
814 
815     /**
816                 Assign the value to the name.   
817                 name may evaluate to anything assignable. e.g. a variable or field.
818         */
819     public void set(String name, Object value) throws EvalError {
820         CallStack callstack = new CallStack();
821         LHS lhs = globalNameSpace.getNameResolver( name ).toLHS( 
822                                                                 callstack, this );
823         lhs.assign( value );
824     }
825 
826     /**
827                 Unchecked set for internal use
828         */
829     void setu(String name, Object value) {
830         try { 
831             set(name, value);
832         } catch ( EvalError e ) { 
833             throw new InterpreterError("set: "+e);
834         }
835     }
836 
837     public void set(String name, long value) throws EvalError {
838         set(name, new Primitive(value));
839     }
840     public void set(String name, int value) throws EvalError {
841         set(name, new Primitive(value));
842     }
843     public void set(String name, double value) throws EvalError {
844         set(name, new Primitive(value));
845     }
846     public void set(String name, float value) throws EvalError {
847         set(name, new Primitive(value));
848     }
849     public void set(String name, boolean value) throws EvalError {
850         set(name, new Primitive(value));
851     }
852 
853 
854 
855     /**
856                 @deprecated does not properly evaluate compound names
857         */
858     public Object getVariable(String name)
859     {
860         Object obj = globalNameSpace.getVariable(name);
861         return Primitive.unwrap( obj );
862     }
863 
864     /**
865                 @deprecated does not properly evaluate compound names
866         */
867     public void setVariable(String name, Object value)
868     {
869         try { globalNameSpace.setVariable(name, value); }
870         catch(EvalError e) { error(e.toString()); }
871     }
872 
873     /**
874                 @deprecated does not properly evaluate compound names
875         */
876     public void setVariable(String name, int value)
877     {
878         try { globalNameSpace.setVariable(name, new Primitive(value)); }
879         catch(EvalError e) { error(e.toString()); }
880     }
881 
882     /**
883                 @deprecated does not properly evaluate compound names
884         */
885     public void setVariable(String name, float value)
886     {
887         try { globalNameSpace.setVariable(name, new Primitive(value)); }
888         catch(EvalError e) { error(e.toString()); }
889     }
890 
891     /**
892                 @deprecated does not properly evaluate compound names
893         */
894     public void setVariable(String name, boolean value)
895     {
896         try { globalNameSpace.setVariable(name, new Primitive(value)); }
897         catch(EvalError e) { error(e.toString()); }
898     }
899 
900     // end primary set and get methods
901 
902         /*      Methods for interacting with Parser */
903 
904     private JJTParserState get_jjtree() {
905         return parser.jjtree;
906     }
907 
908     private ASCII_UCodeESC_CharStream get_jj_input_stream() {
909         return parser.jj_input_stream;
910     }
911 
912     private boolean Line() throws ParseException {
913         return parser.Line();
914     }
915 
916     /*      End methods for interacting with Parser */
917 
918     void loadRCFiles() {
919         try {
920             String rcfile = 
921                                 // Default is c:\windows under win98, $HOME under Unix
922                 System.getProperty("user.home") + File.separator + ".bshrc";
923             source( rcfile, globalNameSpace );
924         } catch ( Exception e ) { 
925             // squeltch security exception, filenotfoundexception
926             debug("Could not find rc file: "+e);
927         }
928     }
929 
930     /**
931                 Localize a path to the file name based on the bsh.cwd interpreter 
932                 working directory.
933         */
934     public File pathToFile( String fileName ) 
935         throws IOException
936     {
937         File file = new File( fileName );
938 
939         // if relative, fix up to bsh.cwd
940         if ( !file.isAbsolute() ) {
941             String cwd = (String)getu("bsh.cwd");
942             file = new File( cwd + File.separator + fileName );
943         }
944 
945         return new File( file.getCanonicalPath() );
946     }
947 
948     public static void redirectOutputToFile( String filename ) 
949     {
950         try {
951             PrintStream pout = new PrintStream( 
952                                                new FileOutputStream( filename ) );
953             System.setOut( pout );
954             System.setErr( pout );
955         } catch ( IOException e ) {
956             System.err.println("Can't redirect output to file: "+filename );
957         }
958     }
959 
960     static void staticInit() {
961         /* 
962            Apparently in some environments you can't catch the security exception
963            at all...  e.g. as an applet in IE  ... will probably have to work 
964            around 
965         */
966         try {
967             debug = System.err;
968             DEBUG = Boolean.getBoolean("debug");
969             TRACE = Boolean.getBoolean("trace");
970             String outfilename = System.getProperty("outfile");
971             if ( outfilename != null )
972                 redirectOutputToFile( outfilename );
973         } catch ( SecurityException e ) { 
974             System.err.println("Could not init static:"+e);
975         } catch ( Exception e ) {
976             System.err.println("Could not init static(2):"+e);
977         } catch ( Throwable e ) { 
978             System.err.println("Could not init static(3):"+e);
979         }
980     }
981 
982     /**
983                 Specify the source of the text from which this interpreter is reading.
984                 Note: there is a difference between what file the interrpeter is 
985                 sourcing and from what file a method was originally parsed.  One
986                 file may call a method sourced from another file.  See SimpleNode
987                 for origination file info.
988                 @see SimpleNode.getSourceFile 
989         */
990     public String getSourceFileInfo() { 
991         if ( sourceFileInfo != null )
992             return sourceFileInfo;
993         else
994             return "<unknown source>";
995     }
996 
997     public Interpreter getParent() {
998         return parent;
999     }
1000
1001}
1002