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. Conceptually, a Pnuts interpreter is created every time a method is called to evaluate a script and it returns the result to the Java program. The interpreters share 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 );
public static Object load ( InputStream in );
public static Object load ( Reader in );
public static Object load ( String rsrc ) 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[]){
       BigInteger bint = (BigInteger)Pnuts.eval("1<<100");
       ...
   }
}

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. Also parsed scripts can be retrieved from the instance by unparse() method.

public static Pnuts parse( InputStream in ) throws ParseException;
public static Pnuts parse( Reader in ) throws ParseException;
public Object run();
public Object run(Context context);
public void unparse();
public void unparse(PrintWriter out);

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

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[]);
public static Object call(String name, Object args[], String pkg);
public static Object call(String name, Object args[], Context context);
import pnuts.lang.*;

class Foo {
   public static void main(String arg[]){
       Pnuts.eval("function foo() 100");
       ...
       System.out.println(PnutsFunction.call("foo", new Object[]{}));
   }
}
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);
public Object call(Object[] args, Context context);
import pnuts.lang.*;

class Foo {
   public static void main(String arg[]){
       PnutsFunction func = (PnutsFunction)Pnuts.eval("function foo() 100");
       ...
       System.out.println(func.call(new Object[]{}));
   }
}

unparse(int) method retrieves the function definition from a PnutsFunction object.

public Object[] unparse(int narg);

The return value is Object array of following elements.

  1. Package in which the function is defined
  2. Array of imported Java package names and class names
  3. function definition
function f(n) n * n
f.unparse(1) ==> [package "", ["java.lang.*", "*"], "function f(n) n * n"]

Package

Package provides separate naming spaces for an interpreter to make extensibility of the scripting environment. The naming spaces prevent name conflicts among the scripts.

Also, Package provides separate naming spaces used by several interpreters. If each interpreter uses a unique Package, they will not interfere with each other in their execution.

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

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

public Object get(String symbol);
public void set(String symbol, Object value);
public boolean defined(String symbol);
public void clear(String symbol);

Context

As noted previously, A Context represents an internal state in the Pnuts runtime environment. It holds the following information.

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.

public Context();
public Context(Package pkg);
public Context(String pkgName);

One Context object can be passed among several interpreters by specifying in Pnuts.eval() and load() method. 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 );

The following method creates a Context which has package "pkg" by default, then evaluates str.

public static Object eval (String str, String pkg)

The following two statements are equivalent.

Pnuts.eval(str, "pkg");
Pnuts.eval(str, new Context("pkg"));

Message

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

The default values can be changed by accessing the following static variables:

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 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 pnuts.lang.ManualContext is passed to a static method of pnuts.lang.Pnuts class, an exception thrown by an interpreter is not caught in the interpreter and it is thrown out of Pnuts API so that it can be caught and handled in Java. Otherwise, the exception is shown immediately and the exception is not thrown out of the static method call.

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 ManualContext());
	 System.out.println("ret = " + ret);
      } catch (PnuteException e){
	 if (e.getThrowable() instanceof IOException){
	   e.printStackTrace();
	 } else {
	   System.out.println("caught: " + e);
	 }
      }
   }
}

Back