All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bsh.Interpreter Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * The AIBench Shell Plugin
 * %%
 * Copyright (C) 2006 - 2017 Daniel Glez-Peña and Florentino Fdez-Riverola
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */
/*****************************************************************************
 *                                                                           *
 *  This file is part of the BeanShell Java Scripting distribution.          *
 *  Documentation and updates may be found at http://www.beanshell.org/      *
 *                                                                           *
 *  Sun Public License Notice:                                               *
 *                                                                           *
 *  The contents of this file are subject to the Sun Public License Version  *
 *  1.0 (the "License"); you may not use this file except in compliance with *
 *  the License. A copy of the License is available at http://www.sun.com    * 
 *                                                                           *
 *  The Original Code is BeanShell. The Initial Developer of the Original    *
 *  Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright     *
 *  (C) 2000.  All Rights Reserved.                                          *
 *                                                                           *
 *  GNU Public License Notice:                                               *
 *                                                                           *
 *  Alternatively, the contents of this file may be used under the terms of  *
 *  the GNU Lesser General Public License (the "LGPL"), in which case the    *
 *  provisions of LGPL are applicable instead of those above. If you wish to *
 *  allow use of your version of this file only under the  terms of the LGPL *
 *  and not to allow others to use your version of this file under the SPL,  *
 *  indicate your decision by deleting the provisions above and replace      *
 *  them with the notice and other provisions required by the LGPL.  If you  *
 *  do not delete the provisions above, a recipient may use your version of  *
 *  this file under either the SPL or the LGPL.                              *
 *                                                                           *
 *  Patrick Niemeyer ([email protected])                                           *
 *  Author of Learning Java, O'Reilly & Associates                           *
 *  http://www.pat.net/~pat/                                                 *
 *                                                                           *
 *****************************************************************************/

package bsh;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * The BeanShell script interpreter.
 * 
 * An instance of Interpreter can be used to source scripts and evaluate
 * statements or expressions.
 * 

* Here are some examples: * *

* *
 * Interpeter bsh = new Interpreter();
 * 
 * // Evaluate statements and expressions
 * bsh.eval("foo=Math.sin(0.5)");
 * bsh.eval("bar=foo*5; bar=Math.cos(bar);");
 * bsh.eval("for(i=0; i<10; i++) { print(\"hello\"); }");
 * // same as above using java syntax and apis only
 * bsh.eval("for(int i=0; i<10; i++) { System.out.println(\"hello\"); }");
 * 
 * // Source from files or streams
 * bsh.source("myscript.bsh"); // or bsh.eval("source(\"myscript.bsh\")");
 * 
 * // Use set() and get() to pass objects in and out of variables
 * bsh.set("date", new Date());
 * Date date = (Date) bsh.get("date");
 * // This would also work:
 * Date date = (Date) bsh.eval("date");
 * 
 * bsh.eval("year = date.getYear()");
 * Integer year = (Integer) bsh.get("year"); // primitives use wrappers
 * 
 * // With Java1.3+ scripts can implement arbitrary interfaces...
 * // Script an awt event handler (or source it from a file, more likely)
 * bsh.eval("actionPerformed( e ) { print( e ); }");
 * // Get a reference to the script object (implementing the interface)
 * ActionListener scriptedHandler = (ActionListener) bsh.eval("return (ActionListener)this");
 * // Use the scripted event handler normally...
 * new JButton.addActionListener(script);
 * 
* *
*

* * In the above examples we showed a single interpreter instance, however you * may wish to use many instances, depending on the application and how you * structure your scripts. Interpreter instances are very light weight to * create, however if you are going to execute the same script repeatedly and * require maximum performance you should consider scripting the code as a * method and invoking the scripted method each time on the same interpreter * instance (using eval()). *

* * See the BeanShell User's Manual for more information. */ public class Interpreter implements Runnable, ConsoleInterface, Serializable { /* --- Begin static members --- */ public static final String VERSION = "2.0b4"; /* * Debug utils are static so that they are reachable by code that doesn't * necessarily have an interpreter reference (e.g. tracing in utils). In the * future we may want to allow debug/trace to be turned on on a per * interpreter basis, in which case we'll need to use the parent reference * in some way to determine the scope of the command that turns it on or * off. */ public static boolean DEBUG, TRACE, LOCALSCOPING; // This should be per instance transient static PrintStream debug; static String systemLineSeparator = "\n"; // default static { staticInit(); } /** Shared system object visible under bsh.system */ static This sharedObject; /** * Strict Java mode * * @see #setStrictJava( boolean ) */ private boolean strictJava = false; /* --- End static members --- */ /* --- Instance data --- */ transient Parser parser; NameSpace globalNameSpace; transient Reader in; transient PrintStream out; transient PrintStream err; ConsoleInterface console; /** If this interpeter is a child of another, the parent */ Interpreter parent; /** The name of the file or other source that this interpreter is reading */ String sourceFileInfo; /** by default in interactive mode System.exit() on EOF */ private boolean exitOnEOF = true; protected boolean evalOnly, // Interpreter has no input stream, use // eval() only interactive; // Interpreter has a user, print // prompts, etc. /** Control the verbose printing of results for the show() command. */ private boolean showResults; /* --- End instance data --- */ /** * The main constructor. All constructors should now pass through here. * * @param in * the standard input. * @param out * the standard output. * @param err * the error output. * @param interactive * whether the interactive mode is on or off. * @param namespace * If namespace is non-null then this interpreter's root * namespace will be set to the one provided. If it is null a new * one will be created for it. * @param parent * The parent interpreter if this interpreter is a child of * another. May be null. Children share a BshClassManager with * their parent instance. * @param sourceFileInfo * An informative string holding the filename or other * description of the source from which this interpreter is * reading... used for debugging. May be null. */ public Interpreter(Reader in, PrintStream out, PrintStream err, boolean interactive, NameSpace namespace, Interpreter parent, String sourceFileInfo) { // System.out.println("New Interpreter: "+this +", sourcefile = // "+sourceFileInfo ); parser = new Parser(in); long t1 = System.currentTimeMillis(); this.in = in; this.out = out; this.err = err; this.interactive = interactive; debug = err; this.parent = parent; if (parent != null) setStrictJava(parent.getStrictJava()); this.sourceFileInfo = sourceFileInfo; BshClassManager bcm = BshClassManager.createClassManager(this); if (namespace == null) this.globalNameSpace = new NameSpace(bcm, "global"); else this.globalNameSpace = namespace; // now done in NameSpace automatically when root // The classes which are imported by default // globalNameSpace.loadDefaultImports(); /* * Create the root "bsh" system object if it doesn't exist. */ if (!(getu("bsh") instanceof bsh.This)) initRootSystemObject(); if (interactive) loadRCFiles(); long t2 = System.currentTimeMillis(); if (Interpreter.DEBUG) Interpreter.debug("Time to initialize interpreter: " + (t2 - t1)); } public Interpreter(Reader in, PrintStream out, PrintStream err, boolean interactive, NameSpace namespace) { this(in, out, err, interactive, namespace, null, null); } public Interpreter(Reader in, PrintStream out, PrintStream err, boolean interactive) { this(in, out, err, interactive, null); } /** * Construct a new interactive interpreter attached to the specified console * using the specified parent namespace. * * @param console * the consoled to attach. * @param globalNameSpace * the global namespace associated. */ public Interpreter(ConsoleInterface console, NameSpace globalNameSpace) { this(console.getIn(), console.getOut(), console.getErr(), true, globalNameSpace); setConsole(console); } /** * Construct a new interactive interpreter attached to the specified * console. * * @param console * the consoled to attach. */ public Interpreter(ConsoleInterface console) { this(console, null); } /** * Create an interpreter for evaluation only. */ public Interpreter() { this(new StringReader(""), System.out, System.err, false, null); evalOnly = true; setu("bsh.evalOnly", new Primitive(true)); } // End constructors /** * Attach a console Note: this method is incomplete. * * @param console * the console to attach. */ public void setConsole(ConsoleInterface console) { this.console = console; setu("bsh.console", console); // redundant with constructor setOut(console.getOut()); setErr(console.getErr()); // need to set the input stream - reinit the parser? } private void initRootSystemObject() { BshClassManager bcm = getClassManager(); // bsh setu("bsh", new NameSpace(bcm, "Bsh Object").getThis(this)); // init the static shared sharedObject if it's not there yet if (sharedObject == null) sharedObject = new NameSpace(bcm, "Bsh Shared System Object").getThis(this); // bsh.system setu("bsh.system", sharedObject); setu("bsh.shared", sharedObject); // alias // bsh.help This helpText = new NameSpace(bcm, "Bsh Command Help Text").getThis(this); setu("bsh.help", helpText); // bsh.cwd try { setu("bsh.cwd", System.getProperty("user.dir")); } catch (SecurityException e) { // applets can't see sys props setu("bsh.cwd", "."); } // bsh.interactive setu("bsh.interactive", new Primitive(interactive)); // bsh.evalOnly setu("bsh.evalOnly", new Primitive(evalOnly)); } /** * Set the global namespace for this interpreter. *

* * Note: This is here for completeness. If you're using this a lot it may be * an indication that you are doing more work than you have to. For example, * caching the interpreter instance rather than the namespace should not add * a significant overhead. No state other than the debug status is stored in * the interpreter. *

* * All features of the namespace can also be accessed using the interpreter * via eval() and the script variable 'this.namespace' (or global.namespace * as necessary). * * @param globalNameSpace * the global namespace of this interpreter. */ public void setNameSpace(NameSpace globalNameSpace) { this.globalNameSpace = globalNameSpace; } /** * Returns the global namespace of this interpreter. * *

* Note: This is here for completeness. If you're using this a lot it may be * an indication that you are doing more work than you have to. For example, * caching the interpreter instance rather than the namespace should not add * a significant overhead. No state other than the debug status is stored in * the interpreter. *

* * All features of the namespace can also be accessed using the interpreter * via eval() and the script variable 'this.namespace' (or global.namespace * as necessary). * * @return the global namespace of this interpreter. */ public NameSpace getNameSpace() { return globalNameSpace; } /** * Run the text only interpreter on the command line or specify a file. * * @param args * the program parameters. */ public static void main(String[] args) { if (args.length > 0) { String filename = args[0]; String[] bshArgs; if (args.length > 1) { bshArgs = new String[args.length - 1]; System.arraycopy(args, 1, bshArgs, 0, args.length - 1); } else bshArgs = new String[0]; Interpreter interpreter = new Interpreter(); // System.out.println("run i = "+interpreter); interpreter.setu("bsh.args", bshArgs); try { Object result = interpreter.source(filename, interpreter.globalNameSpace); if (result instanceof Class) try { invokeMain((Class) result, bshArgs); } catch (Exception e) { Object o = e; if (e instanceof InvocationTargetException) o = ((InvocationTargetException) e).getTargetException(); System.err.println("Class: " + result + " main method threw exception:" + o); } } catch (FileNotFoundException e) { System.out.println("File not found: " + e); } catch (TargetError e) { System.out.println("Script threw exception: " + e); if (e.inNativeCode()) e.printStackTrace(DEBUG, System.err); } catch (EvalError e) { System.out.println("Evaluation Error: " + e); } catch (IOException e) { System.out.println("I/O Error: " + e); } } else { // Workaround for JDK bug 4071281, where // system.in.available() // returns too large a value. This bug has been fixed in // JDK 1.2. InputStream src; if (System.getProperty("os.name").startsWith("Windows") && System.getProperty("java.version").startsWith("1.1.")) { src = new FilterInputStream(System.in) { public int available() throws IOException { return 0; } }; } else src = System.in; Reader in = new CommandLineReader(new InputStreamReader(src)); Interpreter interpreter = new Interpreter(in, System.out, System.err, true); interpreter.run(); } } public static void invokeMain(Class clas, String[] args) throws Exception { Method main = Reflect.resolveJavaMethod( null/* BshClassManager */, clas, "main", new Class[] { String[].class }, true/* onlyStatic */ ); if (main != null) main.invoke( null, new Object[] { args } ); } /** * Run interactively. (printing prompts, etc.) */ public void run() { if (evalOnly) throw new RuntimeException("bsh Interpreter: No stream"); /* * We'll print our banner using eval(String) in order to exercise the * parser and get the basic expression classes loaded... This * ameliorates the delay after typing the first statement. */ if (interactive) try { eval("printBanner();"); } catch (EvalError e) { println("BeanShell " + VERSION + " - by Pat Niemeyer ([email protected])"); } // init the callstack. CallStack callstack = new CallStack(globalNameSpace); boolean eof = false; while (!eof) { try { // try to sync up the console System.out.flush(); System.err.flush(); Thread.yield(); // this helps a little if (interactive) print(getBshPrompt()); eof = Line(); if (get_jjtree().nodeArity() > 0) // number // of // child // nodes { SimpleNode node = (SimpleNode) (get_jjtree().rootNode()); if (DEBUG) node.dump(">"); Object ret = node.eval(callstack, this); // sanity check during development if (callstack.depth() > 1) throw new InterpreterError("Callstack growing: " + callstack); if (ret instanceof ReturnControl) ret = ((ReturnControl) ret).value; if (ret != Primitive.VOID) { setu("$_", ret); if (showResults) println("<" + ret + ">"); } } } catch (ParseException e) { error("Parser Error: " + e.getMessage(DEBUG)); if (DEBUG) e.printStackTrace(); if (!interactive) eof = true; parser.reInitInput(in); } catch (InterpreterError e) { error("Internal Error: " + e.getMessage()); e.printStackTrace(); if (!interactive) eof = true; } catch (TargetError e) { error("// Uncaught Exception: " + e); if (e.inNativeCode()) e.printStackTrace(DEBUG, err); if (!interactive) eof = true; setu("$_e", e.getTarget()); } catch (EvalError e) { if (interactive) error("EvalError: " + e.toString()); else error("EvalError: " + e.getMessage()); if (DEBUG) e.printStackTrace(); if (!interactive) eof = true; } catch (Exception e) { error("Unknown error: " + e); if (DEBUG) e.printStackTrace(); if (!interactive) eof = true; } catch (TokenMgrError e) { error("Error parsing input: " + e); /* * We get stuck in infinite loops here when unicode escapes * fail. Must re-init the char stream reader * (ASCII_UCodeESC_CharStream.java) */ parser.reInitTokenInput(in); if (!interactive) eof = true; } finally { get_jjtree().reset(); // reinit the callstack if (callstack.depth() > 1) { callstack.clear(); callstack.push(globalNameSpace); } } } if (interactive && exitOnEOF) System.exit(0); } // begin source and eval /** * Read text from fileName and eval it. * * @param filename * the name of the source file. * @param nameSpace * the associated namespace. * @return the result of the source evaluation. * @throws FileNotFoundException * if the source file does not exists. * @throws IOException * if an error occurs during file reading. * @throws EvalError * if an error occurs during evaluation. */ public Object source(String filename, NameSpace nameSpace) throws FileNotFoundException, IOException, EvalError { File file = pathToFile(filename); if (Interpreter.DEBUG) debug("Sourcing file: " + file); Reader sourceIn = new BufferedReader(new FileReader(file)); try { return eval(sourceIn, nameSpace, filename); } finally { sourceIn.close(); } } /** * Read text from fileName and eval it. Convenience method. Use the global * namespace. * * @param filename * the name of the source file. * @return the result of the source evaluation. * @throws FileNotFoundException * if the source file does not exists. * @throws IOException * if an error occurs during file reading. * @throws EvalError * if an error occurs during evaluation. */ public Object source(String filename) throws FileNotFoundException, IOException, EvalError { return source(filename, globalNameSpace); } /** * Spawn a non-interactive local interpreter to evaluate text in the * specified namespace. * * Return value is the evaluated object (or corresponding primitive * wrapper). * * @param in * the input reader. * @param nameSpace * the associated namespace. * @param sourceFileInfo * is for information purposes only. It is used to display error * messages (and in the future may be made available to the * script). * @return value is the evaluated object (or corresponding primitive * wrapper). * @throws EvalError * on script problems */ /* * Note: we need a form of eval that passes the callstack through... */ /* * Can't this be combined with run() ? run seems to have stuff in it for * interactive vs. non-interactive... compare them side by side and see what * they do differently, aside from the exception handling. */ public Object eval(Reader in, NameSpace nameSpace, String sourceFileInfo /* , CallStack callstack */) throws EvalError { Object retVal = null; if (Interpreter.DEBUG) debug("eval: nameSpace = " + nameSpace); /* * Create non-interactive local interpreter for this namespace with * source from the input stream and out/err same as this interpreter. */ Interpreter localInterpreter = new Interpreter(in, out, err, false, nameSpace, this, sourceFileInfo); CallStack callstack = new CallStack(nameSpace); boolean eof = false; while (!eof) { SimpleNode node = null; try { eof = localInterpreter.Line(); if (localInterpreter.get_jjtree().nodeArity() > 0) { node = (SimpleNode) localInterpreter.get_jjtree().rootNode(); // nodes remember from where they were // sourced node.setSourceFile(sourceFileInfo); if (TRACE) println("// " + node.getText()); retVal = node.eval(callstack, localInterpreter); // sanity check during development if (callstack.depth() > 1) throw new InterpreterError("Callstack growing: " + callstack); if (retVal instanceof ReturnControl) { retVal = ((ReturnControl) retVal).value; break; // non-interactive, // return control now } if (localInterpreter.showResults && retVal != Primitive.VOID) println("<" + retVal + ">"); } } catch (ParseException e) { /* * throw new EvalError( "Sourced file: "+sourceFileInfo+" parser * Error: " + e.getMessage( DEBUG ), node, callstack ); */ if (DEBUG) // show extra "expecting..." info error(e.getMessage(DEBUG)); // add the source file info and throw again e.setErrorSourceFile(sourceFileInfo); throw e; } catch (InterpreterError e) { e.printStackTrace(); throw new EvalError("Sourced file: " + sourceFileInfo + " internal Error: " + e.getMessage(), node, callstack); } catch (TargetError e) { // failsafe, set the Line as the origin of the // error. if (e.getNode() == null) e.setNode(node); e.reThrow("Sourced file: " + sourceFileInfo); } catch (EvalError e) { if (DEBUG) e.printStackTrace(); // failsafe, set the Line as the origin of the // error. if (e.getNode() == null) e.setNode(node); e.reThrow("Sourced file: " + sourceFileInfo); } catch (Exception e) { if (DEBUG) e.printStackTrace(); throw new EvalError("Sourced file: " + sourceFileInfo + " unknown error: " + e.getMessage(), node, callstack); } catch (TokenMgrError e) { throw new EvalError("Sourced file: " + sourceFileInfo + " Token Parsing Error: " + e.getMessage(), node, callstack); } finally { localInterpreter.get_jjtree().reset(); // reinit the callstack if (callstack.depth() > 1) { callstack.clear(); callstack.push(nameSpace); } } } return Primitive.unwrap(retVal); } /** * Evaluate the input stream in this interpreter's global namespace. * * @param in * the input stream. * @return the result of the evaluation. * @throws EvalError * if an error occurs during evaluation. */ public Object eval(Reader in) throws EvalError { return eval(in, globalNameSpace, "eval stream"); } /** * Evaluate the string in this interpreter's global namespace. * * @param statements * the statements. * @return the result of the evaluation. * @throws EvalError * if an error occurs during evaluation. */ public Object eval(String statements) throws EvalError { if (Interpreter.DEBUG) debug("eval(String): " + statements); return eval(statements, globalNameSpace); } /** * Evaluate the string in the specified namespace. * * @param statements * the statements. * @param nameSpace * the namespace. * @return the result of the validation. * @throws EvalError * if an error occurs during evaluation. */ public Object eval(String statements, NameSpace nameSpace) throws EvalError { String s = (statements.endsWith(";") ? statements : statements + ";"); return eval(new StringReader(s), nameSpace, "inline evaluation of: ``" + showEvalString(s) + "''"); } private String showEvalString(String s) { s = s.replace('\n', ' '); s = s.replace('\r', ' '); if (s.length() > 80) s = s.substring(0, 80) + " . . . "; return s; } // end source and eval /** * Print an error message in a standard format on the output stream * associated with this interpreter. On the GUI console this will appear in * red, etc. * * @param o * an object associated with the error. */ public final void error(Object o) { if (console != null) console.error("// Error: " + o + "\n"); else { err.println("// Error: " + o); err.flush(); } } // ConsoleInterface // The interpreter reflexively implements the console interface that it // uses. Should clean this up by using an inner class to implement the // console for us. /** * Returns the input stream associated with this interpreter. This may be be * stdin or the GUI console. * * @return the input stream associated with this interpreter. This may be be * stdin or the GUI console. */ public Reader getIn() { return in; } /** * Returns the outptut stream associated with this interpreter. This may be * be stdout or the GUI console. * * @return the outptut stream associated with this interpreter. This may be * be stdout or the GUI console. */ public PrintStream getOut() { return out; } /** * Returns the error output stream associated with this interpreter. This * may be be stderr or the GUI console. * * @return the error output stream associated with this interpreter. This * may be be stderr or the GUI console. */ public PrintStream getErr() { return err; } public final void println(Object o) { print(String.valueOf(o) + systemLineSeparator); } public final void print(Object o) { if (console != null) { console.print(o); } else { out.print(o); out.flush(); } } // End ConsoleInterface /** * Print a debug message on debug stream associated with this interpreter * only if debugging is turned on. * * @param s * the debug message. */ public final static void debug(String s) { if (DEBUG) debug.println("// Debug: " + s); } /* * Primary interpreter set and get variable methods Note: These are * squeltching errors... should they? */ /** * Returns the value of the name. name may be any value. e.g. a variable or * field. * * @param name * the name of the value. * @return the value associated with the name. * @throws EvalError * if an error occurs during evaluation. */ public Object get(String name) throws EvalError { try { Object ret = globalNameSpace.get(name, this); return Primitive.unwrap(ret); } catch (UtilEvalError e) { throw e.toEvalError(SimpleNode.JAVACODE, new CallStack()); } } /** * Unchecked get for internal use. * * @param name * the name of the value. * @return the value associated with the name. */ Object getu(String name) { try { return get(name); } catch (EvalError e) { throw new InterpreterError("set: " + e); } } /** * Assign the value to the name. name may evaluate to anything assignable. * e.g. a variable or field. * * @param name * the name of the value. * @param value * the value associated with the name. * @throws EvalError * if an error occurs during evaluation. */ public void set(String name, Object value) throws EvalError { // map null to Primtive.NULL coming in... if (value == null) value = Primitive.NULL; CallStack callstack = new CallStack(); try { if (Name.isCompound(name)) { LHS lhs = globalNameSpace.getNameResolver(name).toLHS(callstack, this); lhs.assign(value, false); } else // optimization for common case globalNameSpace.setVariable(name, value, false); } catch (UtilEvalError e) { throw e.toEvalError(SimpleNode.JAVACODE, callstack); } } /** * Unchecked set for internal use. * * @param name * the name of the value. * @param value * the value associated with the name. */ void setu(String name, Object value) { try { set(name, value); } catch (EvalError e) { throw new InterpreterError("set: " + e); } } public void set(String name, long value) throws EvalError { set(name, new Primitive(value)); } public void set(String name, int value) throws EvalError { set(name, new Primitive(value)); } public void set(String name, double value) throws EvalError { set(name, new Primitive(value)); } public void set(String name, float value) throws EvalError { set(name, new Primitive(value)); } public void set(String name, boolean value) throws EvalError { set(name, new Primitive(value)); } /** * Unassign the variable name. Name should evaluate to a variable. * * @param name * the name of the variable to unassign. * @throws EvalError * if an error occurs during evaluation. */ public void unset(String name) throws EvalError { /* * We jump through some hoops here to handle arbitrary cases like * unset("bsh.foo"); */ CallStack callstack = new CallStack(); try { LHS lhs = globalNameSpace.getNameResolver(name).toLHS(callstack, this); if (lhs.type != LHS.VARIABLE) throw new EvalError("Can't unset, not a variable: " + name, SimpleNode.JAVACODE, new CallStack()); // lhs.assign( null, false ); lhs.nameSpace.unsetVariable(name); } catch (UtilEvalError e) { throw new EvalError(e.getMessage(), SimpleNode.JAVACODE, new CallStack()); } } // end primary set and get methods /** * Returns a reference to the interpreter (global namespace), cast to the * specified interface type. Assuming the appropriate methods of the * interface are defined in the interpreter, then you may use this interface * from Java, just like any other Java object. *

* * For example: * *

	 * Interpreter interpreter = new Interpreter();
	 * // define a method called run()
	 * interpreter.eval("run() { ... }");
	 * 
	 * // Fetch a reference to the interpreter as a Runnable
	 * Runnable runnable = (Runnable) interpreter.getInterface(Runnable.class);
	 * 
* *

* * Note that the interpreter does *not* require that any or all of the * methods of the interface be defined at the time the interface is * generated. However if you attempt to invoke one that is not defined you * will get a runtime exception. *

* * Note also that this convenience method has exactly the same effect as * evaluating the script: * *

	 *           (Type)this;
	 * 
* * For example, the following is identical to the previous example: * *
	 * // Fetch a reference to the interpreter as a Runnable
	 * Runnable runnable = (Runnable) interpreter.eval("(Runnable)this");
	 * 
* *

* * Version requirement Although standard Java interface types are * always available, to be used with arbitrary interfaces this feature * requires that you are using Java 1.3 or greater. *

* * @param interf * the class of an interface. * @return a reference to the interpreter (global namespace), cast to the * specified interface type. Assuming the appropriate methods of the * interface are defined in the interpreter, then you may use this * interface from Java, just like any other Java object. * @throws EvalError * if the interface cannot be generated because the version of * Java does not support the proxy mechanism. */ public Object getInterface(Class interf) throws EvalError { try { return globalNameSpace.getThis(this).getInterface(interf); } catch (UtilEvalError e) { throw e.toEvalError(SimpleNode.JAVACODE, new CallStack()); } } /* Methods for interacting with Parser */ private JJTParserState get_jjtree() { return parser.jjtree; } private JavaCharStream get_jj_input_stream() { return parser.jj_input_stream; } private boolean Line() throws ParseException { return parser.Line(); } /* End methods for interacting with Parser */ void loadRCFiles() { try { String rcfile = // Default is c:\windows under win98, $HOME under Unix System.getProperty("user.home") + File.separator + ".bshrc"; source(rcfile, globalNameSpace); } catch (Exception e) { // squeltch security exception, filenotfoundexception if (Interpreter.DEBUG) debug("Could not find rc file: " + e); } } /** * Localize a path to the file name based on the bsh.cwd interpreter working * directory. * * @param fileName * the name of a file. * @return a File associated with the file name provided. * @throws IOException * if the canonical path of the file is not valid. */ public File pathToFile(String fileName) throws IOException { File file = new File(fileName); // if relative, fix up to bsh.cwd if (!file.isAbsolute()) { String cwd = (String) getu("bsh.cwd"); file = new File(cwd + File.separator + fileName); } // The canonical file name is also absolute. // No need for getAbsolutePath() here... return new File(file.getCanonicalPath()); } public static void redirectOutputToFile(String filename) { try { PrintStream pout = new PrintStream(new FileOutputStream(filename)); System.setOut(pout); System.setErr(pout); } catch (IOException e) { System.err.println("Can't redirect output to file: " + filename); } } /** * Set an external class loader to be used as the base classloader for * BeanShell. The base classloader is used for all classloading unless/until * the addClasspath()/setClasspath()/reloadClasses() commands are called to * modify the interpreter's classpath. At that time the new paths /updated * paths are added on top of the base classloader. *

* * BeanShell will use this at the same point it would otherwise use the * plain Class.forName(). i.e. if no explicit classpath management is done * from the script (addClassPath(), setClassPath(), reloadClasses()) then * BeanShell will only use the supplied classloader. If additional classpath * management is done then BeanShell will perform that in addition to the * supplied external classloader. However BeanShell is not currently able to * reload classes supplied through the external classloader. *

* * @param externalCL * an external class loader. * @see BshClassManager#setClassLoader( ClassLoader ) */ public void setClassLoader(ClassLoader externalCL) { getClassManager().setClassLoader(externalCL); } /** * Returns the class manager associated with this interpreter (the * BshClassManager of this interpreter's global namespace). This is * primarily a convenience method. * * @return the class manager associated with this interpreter (the * BshClassManager of this interpreter's global namespace). This is * primarily a convenience method. */ public BshClassManager getClassManager() { return getNameSpace().getClassManager(); } /** *

* Set strict Java mode on or off. This mode attempts to make BeanShell * syntax behave as Java syntax, eliminating conveniences like loose * variables, etc. When enabled, variables are required to be declared or * initialized before use and method arguments are reqired to have types. *

* *

* This mode will become more strict in a future release when classes are * interpreted and there is an alternative to scripting objects as method * closures. *

* * @param b * activation value of the strict Java mode. */ public void setStrictJava(boolean b) { this.strictJava = b; } /** * Returns whether the strict Java mode is on or off. * * @return whether the strict Java mode is on or off. * @see #setStrictJava( boolean ) */ public boolean getStrictJava() { return this.strictJava; } static void staticInit() { /* * Apparently in some environments you can't catch the security * exception at all... e.g. as an applet in IE ... will probably have to * work around */ try { systemLineSeparator = System.getProperty("line.separator"); debug = System.err; DEBUG = Boolean.getBoolean("debug"); TRACE = Boolean.getBoolean("trace"); LOCALSCOPING = Boolean.getBoolean("localscoping"); String outfilename = System.getProperty("outfile"); if (outfilename != null) redirectOutputToFile(outfilename); } catch (SecurityException e) { System.err.println("Could not init static:" + e); } catch (Exception e) { System.err.println("Could not init static(2):" + e); } catch (Throwable e) { System.err.println("Could not init static(3):" + e); } } /** * Specify the source of the text from which this interpreter is reading. * Note: there is a difference between what file the interrpeter is sourcing * and from what file a method was originally parsed. One file may call a * method sourced from another file. See SimpleNode for origination file * info. * * @return the source file. * @see bsh.SimpleNode#getSourceFile() */ public String getSourceFileInfo() { if (sourceFileInfo != null) return sourceFileInfo; else return ""; } /** * Get the parent Interpreter of this interpreter, if any. Currently this * relationship implies the following: 1) Parent and child share a * BshClassManager 2) Children indicate the parent's source file information * in error reporting. When created as part of a source() / eval() the child * also shares the parent's namespace. But that is not necessary in general. * * @return the parent interpreter. */ public Interpreter getParent() { return parent; } public void setOut(PrintStream out) { this.out = out; } public void setErr(PrintStream err) { this.err = err; } /** * De-serialization setup. Default out and err streams to stdout, stderr if * they are {@code null}. * * @param stream the stream that contains the object. * @throws IOException if an error occurs while reading the object. * @throws ClassNotFoundException if the class of the object is not loaded. */ private void readObject(ObjectInputStream stream) throws java.io.IOException, ClassNotFoundException { stream.defaultReadObject(); // set transient fields if (console != null) { setOut(console.getOut()); setErr(console.getErr()); } else { setOut(System.out); setErr(System.err); } } /** * Returns the prompt string defined by the getBshPrompt() method in the * global namespace. This may be from the getBshPrompt() command or may be * defined by the user as with any other method. Defaults to "bsh % " if the * method is not defined or there is an error. * * @return the prompt string. */ private String getBshPrompt() { try { return (String) eval("getBshPrompt()"); } catch (Exception e) { return "bsh % "; } } /** * Specify whether, in interactive mode, the interpreter exits Java upon end * of input. If true, when in interactive mode the interpreter will issue a * System.exit(0) upon eof. If false the interpreter no System.exit() will * be done. *

* Note: if you wish to cause an EOF externally you can try closing the * input stream. This is not guaranteed to work in older versions of Java * due to Java limitations, but should work in newer JDK/JREs. (That was the * motivation for the Java NIO package). *

* * @param value * whether, in interactive mode, the interpreter exits Java upon * end of input. */ public void setExitOnEOF(boolean value) { exitOnEOF = value; // ug } /** * Turn on/off the verbose printing of results as for the show() command. If * this interpreter has a parent the call is delegated. See the BeanShell * show() command. * * @param showResults * whether the verbose printing of the results should be * activated or not. */ public void setShowResults(boolean showResults) { this.showResults = showResults; } /** * Show on/off verbose printing status for the show() command. See the * BeanShell show() command. If this interpreter has a parent the call is * delegated. * * @return the status of the verbose printing of the results. */ public boolean getShowResults() { return showResults; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy