Pnuts API Overview

Introduction

Pnuts API is a set of classes that provides methods to use the scripting functionalities of Pnuts. There is no initialization procedure 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 space with the Java program that call the API.

Pnuts

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() method.

public static Pnuts parse( InputStream in ) throws ParseException;
public static Pnuts parse( Reader in ) 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());
  }
}

PnutsFunction

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.*", "*"]

Package

Package is a name space which can be used to prevent name conficts among scripts. Package can also be used to define a module, which is a set of re-usable functions.

Packages are identified by the name and the Package name can not be changed after it is created. Usually Packages are managed in a static hashtable and it is garranteed that their names are unique.

To create a Package use the following method. If Package with the name pkgName does not exists it creates the Package.

public static Package getPackage(String pkgName);

The default constructor of pnuts.lang.Package also makes a new Package but the name is initialized to null. In this case, the created Package is not managed by the hashtable, which means that the Package can never conflict but the names in the Package can not be refered by other Packages.

public Package();

Hierarchy of Packages can be made by specifying the parent package to the following constructor. The global package is the default parameter.

public Package(String name, Package parent);

The following methods are access methods to symbols in the Package. See apidoc for details.

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 );

Context

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(String pkgName);
public Context(Context template);

The default constructor of Context creates a Context object with the global Package. The constructors Context(String pkgName) and Context(Package anPackage) create a Context and set the default Package. If Package with the name pkgName does not exists it creates the Package.

One Context object can be passed among several interpreters. Also a context can be used from different threads at the same time.

public static Object eval( String exp, Context context );
public static Object load ( String rsrc , Context context );
public static Object load ( InputStream in , Context context );
public static Object load ( Reader in , Context context );
public static Object load ( InputStream in , boolean interactive , Context context );
public static Object load ( Reader in , boolean interactive , Context context );

When eval(),load(), or loadFile() is called from a script, a clone of the Context being used is made and passed to the function. A clone of a context can be made by calling Context.clone() method directly.

Some of the attributes are shared among the clones, and some of them are copied.

AttributesWhat happened when a clone is made
OutputStream for messages copied
Context-local Variables copied
Class Loader shared
PnutsImpl object copied
Modules added by use() shared
Symbols registered by autoload() shared
The list of files loaded by load() shared
Imported Java package list copied

If all attributes need to be copied, use the constructor Context(Context) instead of clone().

OutputStream for Messages

As shown below, three kinds of output stream can be specified for a Context.

Context-local Variables

Context-local variable is a kind of environment variable bound to a context.

public void set (String key , Object value);
public Object get (String key );

ClassLoader

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 ();

PnutsImpl Object

See "On-the-fly Compiler and Pure Interpreter".

public void setPnutsImpl (PnutsImpl impl );
public PnutsImpl getPnutsImpl ();

Modules

use() function registers a module to the executing context. The registered modules are managed and shared by a family of Context clones.

public void usePackage (String name );
public String[] usedPackages ();

usePackage() registers a module to the context. usedPackages() returns the list of registered module names.

Difference between eval() and Pnuts::eval()

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.

Exception handling

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);
	 }
      }
   }
}

Back