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