Pnuts API is a set of classes that provides methods to use the scripting functionalities of Pnuts. No initialization step is required to use the API and it can be called at any place in a Java program. Pnuts interpreter shares the thread resource and the object heap with the Java program that call the API.
Class Description pnuts.lang.Pnuts provides public static methods to execute scripts pnuts.lang.Context environment of script execution pnuts.lang.Package non-local name space pnuts.lang.PnutsFunction represents a Pnuts function pnuts.lang.PnutsException exception during script execution Core classes of Pnuts API
pnuts.lang.Pnuts class has static methods which starts an interpreter. Pnuts.eval() and Pnuts.load() are two of the most important methods to call Pnuts script from Java.
- public static Object eval ( String exp, Context context );
- public static Object load ( InputStream in , Context context );
- public static Object load ( Reader in , Context context );
- public static Object load ( URL scriptURL , Context context );
- public static Object load ( String rsrc , Context context ) throws FileNotFoundException;
The following example illustrates a simple usage of Pnuts.eval() method.
import pnuts.lang.*;
import java.math.*;
class Foo {
public static void main(String arg[]){
Context context = new Context();
BigInteger bint = (BigInteger)Pnuts.eval("1<<100", context);
...
}
}
pnuts.lang.Pnuts class can be instantiated only by Pnuts::parse(InputStream/Reader) methods. The instance of pnuts.lang.Pnuts can be executed by run(Context) method.
- public static Pnuts parse( InputStream in ) throws ParseException;
- public static Pnuts parse( Reader in ) throws ParseException;
- public static Pnuts parse( Reader in, Object scriptSource, Context context) throws ParseException;
- public Object run( Context context);
The following program illustrates how to parse a Pnuts script first and execute it later.
import pnuts.lang.*;
import java.io.*;
class ParseTest {
public static void main(String a[]){
Pnuts p = null;
try {
p = Pnuts.parse(new FileInputStream(a[0]));
} catch (ParseException e1){
...
} catch (IOException e2){
...
}
...
p.run(new Context());
}
}
One of the following methods is used to handle multiple parse errors.
- public static Pnuts parse( Reader in , ParseEnvironment env) throws ParseException;
- public static Pnuts parse( Reader in, Object scriptSource, Context context, ParseEnvironment env) throws ParseException;
import pnuts.lang.*;
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException {
try {
FileReader r = new FileReader(args[0]);
Pnuts.parse(r, new ParseEnvironment(){
public void handleParseException(ParseException e) throws ParseException {
System.out.println(e);
}
});
} catch (ParseException e){
throw new Error(); // never happens
}
}
}
Script source is an attribute of Pnuts object, which denotes the origin of the script, usually a URL object.
- public Object getScriptSource();
- public void setScriptSource(Object scriptSource);
Script source information is mainly used by debugger.
PnutsFunction is another entry point into the Pnuts interpreter. It is used to call a Pnuts function from Java.
- public static Object call(String name, Object args[], Context context);
import pnuts.lang.*;
class Foo {
public static void main(String arg[]){
Context context = new Context();
Pnuts.eval("function foo() 100", context);
...
System.out.println(PnutsFunction.call("foo", new Object[]{}, context));
}
}
If a Java program holds a reference to PnutsFunction object, the function can be called directly by the following instance methods.
- public Object call(Object[] args, Context context);
import pnuts.lang.*;
class Foo {
public static void main(String arg[]){
Context context = new Context();
PnutsFunction func = (PnutsFunction)Pnuts.eval("function foo() 100", context);
...
System.out.println(func.call(new Object[]{}, context));
}
}
The following methods retrieve the function definition from a PnutsFunction object.
- public String unparse(int narg);
- The body of function definition.
- public String[] getImportEnv(int narg);
- Array of imported Java package names and class names
- public Package getPackage();
- Package in which the function is defined.
function f(n) n * n f.unparse(1) ==> "function f(n) n * n" f.getPackage() ==> package "" f.getImportEnv(1) ==> ["java.lang.*", "*"]
See also "Defining Functions in Java".
Package is a name space which can be used for preventing name conficts among scripts. Each Package has a symbol table to store non-local names.
Package class has consturctors that takes the package name and the parent Package as the parameters. A package hierarchy is implicitly or explicitly created by calling a constructor.
- public Package();
- public Package(String name);
- public Package(String name, Package parent );
Root package is the topmost package in a package hierarchy. If null is specified as the parent, it becomes a new root package. When a script file is loaded, it is executed with the root package as the current package.
When parent is not explicitly specified, the global package is used as the parent Package. pnuts command uses the global package as the default root package. As long as pnuts command is used, there is almost no need to create a new root package.
Root packages need to be created to build multiple isolated scripting environments. For each isolated scripting environment, a root package is created. Each root package builds a separate package tree. Non-local names used by each scripting environment are stored in some package of a package tree, in such a way that variables in a scripting environment do not interfere with other scripting environments.
The global package is the default root package provided by Pnuts API. It is referenced by a static field of pnuts.lang.Package class. Therefore, the global package is never reclaimed by GC. Other root packages can be reclaimed by GC if they are no longer referenced and ready for GC.
The following method is used for creating a Package. If Package with the name pkgName does not exists it creates the Package. The created package is managed by the root package (of the current package) and identified by the package name.
- public static Package getPackage(String pkgName , Context context);
The following methods are access methods to the symbol table in a Package.
- public Object get(String symbol , Context context );
- public void set(String symbol, Object value , Context context );
- public boolean defined(String symbol , Context context );
- public void clear(String symbol , Context context );
Note that symbol in these methods must be an interned String object.
If the variable is undefined in the symbol table when Package.get(String, Context) method is called, and a AutoloadHook for the variable has been registered by autoload() method, the AutoloadHook is invoked. When either no AutoloadHook is registered for the variable or the variable was not defined by invoking the AutoloadHook, Package.get(String, Context) method does the same thing for the parent Package.
- public void autoload( String symbol, String file, Context context );
- public void autoload( String symbol, AutoloadHook hook );
When Context.usePackage() method is called to install a module, the module initialization script is executed. A sub-package bound to the module is created if it does not exist, and the module functions are stored in the package.
Package objects maintains a list of exported names, when the package is used as a module. Module initialization scripts should register the exported names with Package.export() method.
- public void export( String symbol );
If no names are exported by the initialization script of a module, all named functions defined in the package is implicitly exported.
When a module is implemented with pnuts.ext.ModuleBase
class, it does not have to call export() method directly, because autoload() method or a
A Context represents an internal state in the Pnuts runtime environment. It holds the following information.
A Context object need to be created when evaluating a script.
- public Context();
- public Context(Package pkg);
- public Context(Package pkg, Object source);
- public Context(Context template);
The default constructor of Context creates a Context object with the global Package. The constructor Context(Package anPackage) creates a Context and set the default Package.
A Context object can be passed around several interpreters specifying the object as the parameter of Pnuts.eval(), Pnuts.load(), or Pnuts.loadFile() method. Also a context can be used from different threads at the same time.
When one of the built-in functions, eval(),load(), require(), and loadFile() is called from a script, a clone of the Context being used is made and passed to the function.
When one of the built-in functions, load(), require(), and loadFile() is called, the specified script is executed setting the current package to the top of the package hierarchy (usually the global package).
Some of the attributes are shared among the clones, and some of them are copied.
Attribute What happens when a clone is made The classloader associated with the context shared Modules added by use() shared The list of files loaded by load() shared OutputStream for messages copied Context-local Variables copied Implementation object copied Configuration copied Encoding copied Imported Java package list reset Current package reset
If all attributes need to be copied, use the constructor Context(Context) instead of clone().
As shown below, three kinds of output stream can be specified for a Context.
- public OutputStream getOutputStream ();
- public void setOutputStream (OutputStream out);
- public PrintWriter getWriter ();
- public void setWriter (Writer writer);
- public PrintWriter getErrorWriter ();
- public void setErrorWriter (Writer out );
- public PrintWriter getTerminalWriter ();
- public void setTerminalWriter (Writer writer );
Context-local variable is a kind of environment variable bound to a context.
- public void set (String symbol , Object value);
- public Object get (String symbol );
Note that the parameter symbol must be an interned string.
Context-local variables can be accessed with field access expression on a Context object.
context = getContext() context.foo ==> null context.foo = date()
Context may declare a script encoding with setScriptEncoding() method.
- public void setScriptEncoding (String encodingName );
- public String getScriptEncoding ();
A class loader can be associated with the context. It is used to resolve class names, and finds scripts when load() function is used.
- public void setClassLoader (ClassLoader loader );
- public ClassLoader getClassLoader ();
See "Customizing the Interpreter's Implementation".
- public void setImplementation (Implementation impl );
- public Implementation getImplementation ();
Configuration defines how to find method/field candidates, and semantics of field access.
- context . setConfiguration ( Configuration impl )
- context . getConfiguration ( )
See "Customizing the Behavior of Java API Access".
use() function registers a module to the executing context. The registered modules are managed and shared by a family of Context clones.
- public boolean usePackage (String name );
- public String[] usedPackages ();
- public void clearPackages ();
usePackage() registers a module to the context and executes the initialization script of the module.
usedPackages() returns the list of registered module names.
clearPackages() resets the module list back to empty.
- eval(expr)
- Evaluates expr with a copy of the current Context
- eval(expr, context)
- Evaluates expr with a copy of context
- Pnuts::eval(expr)
- Evaluates expr with a newly created Context
- same as Pnuts::eval(expr, Context())
- Pnuts::eval(expr, context)
- Evaluates expr with context
When a Context object is passed to Pnuts::eval(expr, context), import() and some other functions can modify the caller's context. On the other hand, the original Context object can not be modified by primitive function eval(), because it uses a copy of a Context.
When an exception is thrown during executing script through Pnuts.eval(), Pnuts.load(), or Pnuts.loadFile() method, the exception is propagated to the caller of the methods.
The exception is encapsulated in a pnuts.lang.PnutsException object and can be retrieved with the PnutsException.getThrowable() method.
- public Throwable getThrowable();
import pnuts.lang.*;
import java.io.*;
class Foo {
public static void main(String arg[]){
try {
Object ret = Pnuts.eval(arg[0], new Context());
System.out.println("ret = " + ret);
} catch (PnuteException e){
if (e.getThrowable() instanceof IOException){
e.printStackTrace();
} else {
System.out.println("caught: " + e);
}
}
}
}
getScriptSource() returns the source of the script where the error occured, which is usually a URL object. getLine() returns the line number where the error occured.
- public Object getScriptSource();
- public int getLine();
To obtain the positional information of an error thrown by Pnuts.run(Context), the script source has to be set using Pnuts.setScriptSource() method before executing the script.
import pnuts.lang.*;
import java.io.*;
class Foo {
public static void main(String arg[]) throws IOException {
try {
File file = new File(arg[0]);
FileInputStream in = new FileInputStream(file);
Pnuts expr = Pnuts.parse(in);
expr.setScriptSource(file);
expr.run(new Context());
} catch (PnutsException e){
System.out.println(e.getScriptSource() + ": " + e.getLine());
}
}
}