Running Prolog code in the JVM
Last edited: 23 February 2018
The JLog/BSF integration library (or BSF engine) was developed by myself. JLog was developed by Glendon Holst, and can be found at http://jlogic.sourceforge.net/. It's also licensed under the GPL.
Sections in this document:
JLogBSFEngine? defines a number of Prolog predicates that can be used for interactions between both languages.
- bsf_register (Name, Bean)
- Stores the object in variable Bean under the given name in the registry. Name must be a string or a variable bound to a string. Bean must be a bound variable.
- bsf_lookup (Name, ResultVar)
- Looks up the object of this name in the registry, and binds it to the variable ResultVar. Name must be a string or a variable bound to a string.
- bsf_unregister (Name)
- Removes the object with this name from the registry. Name must be a string or a variable bound to a string.
- bsf_import (Package)
- Adds the given package name to the lists of imports, so that all Java objects in that package can be referenced just by their classname, instead of by their fully qualified name. java.lang is imported automatically. Package must be a string or a variable bound to a string.
- bsf_static (Class, ResultVar)
- Retrieves a class and stores it in variable ResultVar, so that static methods can be invoked on it (e.g. Integer.valueOf). Can also be used to retrieve static fields of classes (e.g. java.lang.System.out). Class must be a string or a variable bound to a string.
- bsf_create (ResultVar, Class, Parameters [, Types])
- Prolog wrapper for a Java constructor. The resulting object of class Class is put in the variable ResultVar. Parameters is the list of parameters. The Java equivalent would be ResultVar = new Class(Parameters). bsf_create/3 (w/o the Types parameter) tries to figure out the correct method signature based on the types of the given parameters. This works in most cases, but not always. If it can't decide which constructor to use, an exception is thrown that advises to use bsf_create/4 instead. That means that the list of parameters is needed to select the correct one.
- bsf_invoke (ResultVar, Bean, Method, Parameters [, Types])
- Prolog wrapper for a Java method invocation. Its Java equivalent would be ResultVar = Bean.Method(Parameters). bsf_invoke/4 (w/o the Types parameter) tries to figure out the correct method signature based on the types of the given parameters. This works in most cases, but not always. If it can‘t decide which method to use, an exception is thrown that advises to use bsf_invoke/5 instead. That means that the list of parameters is needed to select the correct one.
- bsf_addevent (Bean, Action, Script)
- This causes the Prolog code in Script to be executed whenever the Java object Bean fires an Action event. The ScriptedUI example demonstrates this. Bean must be bound to a Java object. Action and Script must be strings or bound to a string.
- bsf_j2p (Object, Term)
- Converts Object -which must be bound to a Java object- to a Prolog term.
- bsf_p2j (Term, Object)
- Converts Term -which must be bound to a Prolog term- to a Java object.
The following is a list of all examples that come with the distribution, with notes on how to run them and what they demonstrate.
- Demonstrates scripting use of JLogBSFEngine?. The application is really just a shell for running external scripts, which in this case calculates the mathematical constant π. The pi.plog script creates a piiterator Object, and invokes its calcPi method to do the calculation. Usage is: java -classpath build/JLog.jar:lib/bsf-2.3.0-rc1.jar:Examples/bsf PiApp? Examples/bsf/bsf_pi.plog. Since the name of the script to run is passed as parameter to the program, this application can be used to run any script, in any language supported by BSF. The language to use is inferred from the file extension; for Prolog it's either .plog or .prolog.
- Ant <script> task
- The Ant build file (build.xml) also includes an example of how Ant can be scripted via the <script> task that comes as part of Ant. For this to work, the various jar files that come with JLog need to be in Ants CLASSPATH, which can be accomplished by copying them into the lib directory of your Ant installation. Usage is ant script. Besides demonstrating how to create Java objects and invoke methods on them, the Ant project object is manipulated via its getProperty, setProperty, createTask and log methods. project is put into the common object registry by the script task precisely for this reason: so that scripts can access it, and influence the way Ant executes. Two examples can be found in the build.xml file that comes with JLog. The first calculates the n-th number of the Fibonacci sequence, with n being supplied on the command line.
% ant fib -Dn=15 Buildfile: build.xml ensure-fib-n: fib: 15 610 BUILD SUCCESSFUL
- The second example has two parts: first, a property is read from Ant, incremented by 11, and stored in another Ant property. Then the current date is retrieved and printed to the console using the Ant projects' log method.
% ant script Buildfile: build.xml script: [echo] prop=42 [echo] prop2=53 Sun Jul 31 18:50:36 CEST 2005 BUILD SUCCESSFUL
- Web Page Scripting
- The Jakarta Taglibs project provides a JSP tag library that allows BSF-enabled languages to be used as scripting languages in a JSP page. The library is part of the Jakarta Taglibs project, and can be downloaded at http://attic.apache.org/projects/jakarta-taglibs.html. The library provides the <bsf:scriptlet> tag, which sources a Prolog script and evaluates its last term. The following is the adapted version of an example that ships with the tag library. It prints a table of Fahrenheit and Celsius temperatures. This is not so much a practicable example, but rather a demonstration that wherever BSF is used, Prolog code can run. Note that the BSF taglib has been deprecated, and should no longer be used.
<bsf:scriptlet language="prolog"> f2c(Start, End) :- Start =< End, bsf_lookup('out', OUT), bsf_static('Math', MATH), bsf_invoke(_, OUT, 'print', ['<tr><td>']), bsf_invoke(_, OUT, 'print', [Start]), bsf_invoke(_, OUT, 'print', ['</td><td>']), T is (Start-32) * 5/9, bsf_invoke(T1, MATH, 'round', [T]), bsf_invoke(_, OUT, 'print', [T1]), bsf_invoke(_, OUT, 'println', ['</td></tr>']), Start1 is Start + 10, f2c(Start1, End). f2c(30, 100). </bsf:scriptlet>
Restrictions and Problems
This section lists some of the restrictions one should be aware of.
- Custom events are not supported by bsf_addevent/3. Only the events in java.awt.event can be used, as well as java.beans.VetoableChange? and java.beans.PropertyChange?.
- Array parameters can only be of type Object or String, everything else is not handled and will fail.
- Declared beans are not supported, since Prolog has no notion of variables outside of predicates. Declaring beans simply registers them. Note that BSF allows engines not to support declared beans if they're not applicable to a specific language.
- 11/24/07: Updated to JLog 1.3.6
- 1/6/07: Fixed a bug in create/3 and invoke/4 that would lead to the wrong constructors or methods being selected when matching the types of parameters.
- 9/18/05: Better handling of null parameters in method invocations: null parameters now match all formal parameters, except for primitive types.
- 7/13/05: Added Prolog <--> Java object conversion predicates. The BSF library no longer needs to be loaded explicitly; it's bootstrapped if necessary. Enhanced type matching for bsf_create and bsf_invoke: Object and String can always be matched to Prolog terms.
- 4/10/05: Ported from JLog 1.1 to JLog 1.3. No longer 'kind of' supports declaring beans; they're just not applicable in Prolog. Beans are now referred to as standard Prolog variables, not by their name as a string. Phased out the generic 'bsf' predicate with its action dispatch parameters; all predicates start with bsf_ followed by their name. Note that if you have used the earlier version built upon JLog-1.1.5, you will need to adapt your Prolog code, as the syntax has changed.
- 2/16/05: Methods can now be invoked on static fields (e.g. System.out). Added JUnit tests to check the array handling bugs and the static field functionality. java.lang is now imported automatically. Verified and documented that this package works with the Apache BSF taglib. Cleaned up code according to suggestions by various code checkers.
- 2/9/05: Fixed a problem that prevented array parameter types from being handled correctly.
- 1/30/05: Fixed a problem that prevented array return types with null objects from being handled correctly.