 |
Free EcmaScript Interpreter.
A JavaScript interpreter written
in Java. |
The Java library (package FESI.jslib) |
Capabilities
The library can be used to extend the capabilities of the EcmaScript interpreter,
allowing a Java program to create an interpreter, to evaluate scripts,
and to set and get properties of EcmaScript objects. It is largely compatible
with the Netscape JSObject and JSExeption classes, simplifying
the development of common code.
The library is very simple, and only provide access to basic capabilities
of the interpreter. However it is quite independent of the internal structure
of the interpreter, so the programs are not impacted by changes of FESI.
See the Java Access page on how to
access Java objects from an EcmaScript program.
The API documentation
The API documentation is in jslib
package.
The API functionality is implemented in:
|
The generic type of EcmaScript objects, allowing to access the member
properties, evaluate strings, call EcmaScript functions and find the global
object of the interpreter. |
|
The global object representing the interpreter. Used to create new
objects and arrays, and to evaluate strings or call functions in the global
environment. |
|
The interface that a loadable extension must implement |
|
The interface that a function callable by EcmaScript must implement. |
|
An utility adapter to create new functions. |
|
The package containing the static evaluator creation and routine to
access version information. |
|
The exception wrapping all exceptions. |
Creating an interpreter
The simplest example (listed below) is in SimpleIntrp.java in
the directory examples/jslib. You can create an interpreter simply
following this pattern:
import java.io.*;
import FESI.jslib.*;
public class SimpleIntrp {
public static void main(String args[]) {
// Create the interpreter
JSGlobalObject global
= null;
try {
global = JSUtil.makeEvaluator();
} catch (JSException
e) {
System.err.println(e);
System.exit(1);
}
DataInputStream ins
= new DataInputStream(System.in);
String input = null;
// read eval print loop
while (true) {
System.out.print("> "); System.out.flush();
try {
input = ins.readLine();
} catch (IOException e) {
System.exit(0);
}
if (input == null) break;
try {
Object result = global.eval(input);
if (result!=null) System.out.println(result.toString());
} catch (JSException e) {
System.out.println(e.getMessage());
if (DEBUG)
e.printStackTrace();
Exception oe = e.getOriginalException();
if (oe!=null) {
oe.printStackTrace();
};
System.out.println(e.getMessage());
System.out.println(e.getMessage());
}
} // while
}
}
The source file in the example directory is more complete, initializing
some extensions.
Java object as an EcmaScript object
It is sometime useful to force a Java object to be considered an EcmaScript
object, to use the JSObject functions on it (for example eval). This can
be done as follow::
JButton jb = new JButton();
JSObject jsjb = global.makeObjectWrapper(jb);
jsjb.eval("this.setLabel(Date())");
The function makeObjectWrapper has no effect if the object is
already a JSObject. It will respect the bean handling flag as set by makeBeanWrapper.
An important restriction is that such an object cannot be considered
a full interpreter. Especially it is not possible to create new properties
on a java object from an EcmaScript script.
Java object and Java beans in EcmaScript
If you set a property value to a Java object (which cannot be converted
to an EcmaScript value), then it can be used as any object created via
the Package system, including the access of bean properties which
are not public fields (see the JavaAccess
extension for details). If you want an object set as a bean (only allowing
access to bean properties and method), you can use the routine JSGlobalObject.makeBeanWrapper.
For example, in java:
dialogBean db = new DialogBean();
o.setMember("dialog", global.makeBeanWrapper(db));
Where o is some JSObject. Then the object db
(the dialog property of the object o) will be handled as
a java bean rather than a java object, and only the bean declared properties
and methods can be called on it. makeBeanWrapper does not
return a JSObject, but a general object. If you want to use the bean as
a JSObject (to call eval on it), you must wrap the result of makeBeanWrapper
using makeObjectWrapper.
Specifying extensions to load
Extensions are specified via an array of String, as the optional second
parameter of makeEvaluator.
For example:
String[] extensions = new String[] {"FESI.Extensions.BasicIO",
"FESI.Extensions.JavaAccess"};
JSObject global = JSObject.makeEvaluator(extensions);
See as well the function loadExtension in the JavaAccess
extension.
Creating an extended script host
A script host need not be (and usually is not) an extended interpreter.
The example SampleFunc.javain the
directory examples/jslib demonstrate how a main program can extend
and use EcmaScript. See the documentation of JSObject
for more details.
// Create interpreter
JSGlobalObject global = JSUtil.makeEvaluator();
// Declare a function
global.setMember("loadPage",
new JSFunctionAdapter() {
public Object doCall(JSObject
thisObject, Object args[]) throws JSException {
if (args.length == 0) throw new JSException("loadPage: At least one argument
needed (page name)");
return loadPage(args[0].toString());
}
});
// Interpret some user macro
String userCommand = ...
global.eval(userCommand);
// Routine implementing the core of the function (need not be public!)
private Object loadPage(String pageName) {
// Create an EcmaScript object to store the page attributes
JSObject page = global.makeJSObject();
page.setMemeber("name", pageName);
page.setMember("data", loadPageFromFile("pageName");
}
There can be more than one interpreter created in each program. Access
to an interpreter is synchronized. Each JSObject
belongs to a specific interpreter.
Creating a dynamically loadable extension
The example FesiPop demonstrate how to create
an extension which can then be loaded in any interpreter or script host
program. An extension is created by implementing the JSExtension
interface, and then using the standard JSObject
capabilities. Using an extension allow you to adapt the capabilities of
a Java package to the specific need of the EcmaScript user, and have specific
error handling.
Use of code as function
It is sometime convenient to have the code fragments of a script be implemented
as anonymous parameterless function, rather than main program. This allow
to sue the return statement, for example in a conditional statement,
which can simplify the code. To achieve this goal, simply use evalAsFunction
instead of eval
when calling the interpreter. Then code as:
if (tag == "H") return 1;
else if (tag == "A" return 2;
else return -1;
will work as expected.
In addition it is possible as well to build a function on the fly with
specified parameter names and values. This is useful for code which must
look like an event handler. The function evalAsFunction
with parameters names and values serves this purpose. For example an event
handler could look like:
String names[] = {"event", "timeStamp"};
Object values [] = {event, new Date(event.getTimeStamp)};
target.evalAsFunction(script, names, values);
Where the script could be for example:
var _c = event.getChar();
if (_c == "t") alert("t received at: " + timeStamp);
This execute has if the code fragment was a function of two parameters:
event
and timeStamp.
Return to the main page
Last update: 13 March 1999