From be83a4a3090845e609eef8e2e82450c09b49041a Mon Sep 17 00:00:00 2001 From: vsc Date: Fri, 27 Aug 2004 20:27:56 +0000 Subject: [PATCH] jpl stuff git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@1120 b08c6af1-5177-4d33-ba66-4b1c6b8b522a --- LGPL/JPL/java/Makefile.in | 97 + LGPL/JPL/java/jpl/Atom.java | 157 + LGPL/JPL/java/jpl/Compound.java | 324 ++ LGPL/JPL/java/jpl/Float.java | 295 + LGPL/JPL/java/jpl/Integer.java | 269 + LGPL/JPL/java/jpl/JBoolean.java | 217 + LGPL/JPL/java/jpl/JPL.java | 199 + LGPL/JPL/java/jpl/JPLException.java | 61 + LGPL/JPL/java/jpl/JRef.java | 215 + LGPL/JPL/java/jpl/JVoid.java | 185 + LGPL/JPL/java/jpl/PrologException.java | 74 + LGPL/JPL/java/jpl/Query.java | 791 +++ LGPL/JPL/java/jpl/Term.java | 671 +++ LGPL/JPL/java/jpl/Util.java | 172 + LGPL/JPL/java/jpl/Variable.java | 301 + LGPL/JPL/java/jpl/Version.java | 9 + LGPL/JPL/java/jpl/fli/BooleanHolder.java | 60 + LGPL/JPL/java/jpl/fli/DoubleHolder.java | 60 + LGPL/JPL/java/jpl/fli/IntHolder.java | 60 + LGPL/JPL/java/jpl/fli/LongHolder.java | 61 + LGPL/JPL/java/jpl/fli/ObjectHolder.java | 60 + LGPL/JPL/java/jpl/fli/PointerHolder.java | 63 + LGPL/JPL/java/jpl/fli/Prolog.java | 240 + LGPL/JPL/java/jpl/fli/StringHolder.java | 60 + LGPL/JPL/java/jpl/fli/atom_t.java | 82 + LGPL/JPL/java/jpl/fli/engine_t.java | 56 + LGPL/JPL/java/jpl/fli/fid_t.java | 60 + LGPL/JPL/java/jpl/fli/functor_t.java | 61 + LGPL/JPL/java/jpl/fli/module_t.java | 61 + LGPL/JPL/java/jpl/fli/predicate_t.java | 61 + LGPL/JPL/java/jpl/fli/qid_t.java | 60 + LGPL/JPL/java/jpl/fli/term_t.java | 133 + LGPL/JPL/jpl.yap | 4255 ++++++++++++++ LGPL/JPL/src/Makefile.in | 63 + LGPL/JPL/src/jpl.c | 6649 ++++++++++++++++++++++ 35 files changed, 16242 insertions(+) create mode 100644 LGPL/JPL/java/Makefile.in create mode 100644 LGPL/JPL/java/jpl/Atom.java create mode 100644 LGPL/JPL/java/jpl/Compound.java create mode 100644 LGPL/JPL/java/jpl/Float.java create mode 100644 LGPL/JPL/java/jpl/Integer.java create mode 100644 LGPL/JPL/java/jpl/JBoolean.java create mode 100644 LGPL/JPL/java/jpl/JPL.java create mode 100644 LGPL/JPL/java/jpl/JPLException.java create mode 100644 LGPL/JPL/java/jpl/JRef.java create mode 100644 LGPL/JPL/java/jpl/JVoid.java create mode 100644 LGPL/JPL/java/jpl/PrologException.java create mode 100644 LGPL/JPL/java/jpl/Query.java create mode 100644 LGPL/JPL/java/jpl/Term.java create mode 100644 LGPL/JPL/java/jpl/Util.java create mode 100644 LGPL/JPL/java/jpl/Variable.java create mode 100644 LGPL/JPL/java/jpl/Version.java create mode 100644 LGPL/JPL/java/jpl/fli/BooleanHolder.java create mode 100644 LGPL/JPL/java/jpl/fli/DoubleHolder.java create mode 100644 LGPL/JPL/java/jpl/fli/IntHolder.java create mode 100644 LGPL/JPL/java/jpl/fli/LongHolder.java create mode 100644 LGPL/JPL/java/jpl/fli/ObjectHolder.java create mode 100644 LGPL/JPL/java/jpl/fli/PointerHolder.java create mode 100644 LGPL/JPL/java/jpl/fli/Prolog.java create mode 100644 LGPL/JPL/java/jpl/fli/StringHolder.java create mode 100644 LGPL/JPL/java/jpl/fli/atom_t.java create mode 100644 LGPL/JPL/java/jpl/fli/engine_t.java create mode 100644 LGPL/JPL/java/jpl/fli/fid_t.java create mode 100644 LGPL/JPL/java/jpl/fli/functor_t.java create mode 100644 LGPL/JPL/java/jpl/fli/module_t.java create mode 100644 LGPL/JPL/java/jpl/fli/predicate_t.java create mode 100644 LGPL/JPL/java/jpl/fli/qid_t.java create mode 100644 LGPL/JPL/java/jpl/fli/term_t.java create mode 100644 LGPL/JPL/jpl.yap create mode 100644 LGPL/JPL/src/Makefile.in create mode 100644 LGPL/JPL/src/jpl.c diff --git a/LGPL/JPL/java/Makefile.in b/LGPL/JPL/java/Makefile.in new file mode 100644 index 000000000..ce359d463 --- /dev/null +++ b/LGPL/JPL/java/Makefile.in @@ -0,0 +1,97 @@ +################################################################ +# Build jpl.jar +################################################################ + +.SUFFIXES: .java .class + +# +# default base directory for YAP installation +# +ROOTDIR = @prefix@ +# +# where the binary should be +# +BINDIR = $(ROOTDIR)/bin +# +# where YAP should look for binary libraries +# +LIBDIR=$(ROOTDIR)/lib/Yap +# +# where YAP should look for architecture-independent Prolog libraries +# +SHAREDIR=$(ROOTDIR)/share +# +# +# You shouldn't need to change what follows. +# +INSTALL=@INSTALL@ +INSTALL_DATA=@INSTALL_DATA@ +INSTALL_PROGRAM=@INSTALL_PROGRAM@ +SHELL=/bin/sh +RANLIB=@RANLIB@ +srcdir=@srcdir@ +SHLIB_CFLAGS=@SHLIB_CFLAGS@ +SHLIB_SUFFIX=@SHLIB_SUFFIX@ +#4.1VPATH=@srcdir@:@srcdir@/OPTYap +CWD=$(PWD) +# +JAVAC=@JAVAC@ +JAR=@JAR@ +JPL=jpl.jar + +CLS= jpl/Atom.java \ + jpl/Compound.java \ + jpl/Float.java \ + jpl/Integer.java \ + jpl/JBoolean.java \ + jpl/JPLException.java \ + jpl/JPL.java \ + jpl/JRef.java \ + jpl/JVoid.java \ + jpl/PrologException.java \ + jpl/Query.java \ + jpl/Term.java \ + jpl/Util.java \ + jpl/Variable.java \ + jpl/Version.java + +FLI= jpl/fli/atom_t.java \ + jpl/fli/BooleanHolder.java \ + jpl/fli/DoubleHolder.java \ + jpl/fli/engine_t.java \ + jpl/fli/fid_t.java \ + jpl/fli/functor_t.java \ + jpl/fli/IntHolder.java \ + jpl/fli/LongHolder.java \ + jpl/fli/module_t.java \ + jpl/fli/ObjectHolder.java \ + jpl/fli/PointerHolder.java \ + jpl/fli/predicate_t.java \ + jpl/fli/Prolog.java \ + jpl/fli/qid_t.java \ + jpl/fli/StringHolder.java \ + jpl/fli/term_t.java + + +JAVA=$(CLS) $(FLI) +CLASSES=$(JAVA:.java=.class) + +all: $(JPL) + +$(JAVA): + -@ ( cd jpl ; @LN_S@ ../$(srcdir)/jpl/*.java .) + -@ ( cd jpl/fli ; @LN_S@ ../../$(srcdir)/jpl/fli/*.java .) + +$(JPL): $(JAVA) + $(JAVAC) $(JAVA) + $(JAR) cf $(JPL) $(CLASSES) + +clean:: + rm -f *~ $(CLASSES) + +distclean: clean + rm -r $(JPL) +install: $(JPL) + mkdir -p $(DESTDIR)$(SHAREDIR)/Yap + $(INSTALL_DATA) $(JPL) $(DESTDIR)$(SHAREDIR)/Yap + diff --git a/LGPL/JPL/java/jpl/Atom.java b/LGPL/JPL/java/jpl/Atom.java new file mode 100644 index 000000000..792acbc22 --- /dev/null +++ b/LGPL/JPL/java/jpl/Atom.java @@ -0,0 +1,157 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: Atom.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import java.util.Map; + +import jpl.fli.Prolog; +import jpl.fli.StringHolder; +import jpl.fli.term_t; + +//----------------------------------------------------------------------/ +// Atom +/** + * Atom is a specialised Compound with zero arguments, representing a Prolog atom with the same name. + * An Atom is constructed with a String parameter (its name, unquoted), which cannot thereafter be changed. + *
Atom a = new Atom("hello");
+ * An Atom can be used (and re-used) as an argument of Compound Terms. + * Two Atom instances are equal (by equals()) iff they have equal names. + * + *
+ * Copyright (C) 2004 Paul Singleton

+ * Copyright (C) 1998 Fred Dushin

+ * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

+ * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

+ *


+ * @author Fred Dushin + * @version $Revision: 1.1 $ + * @see jpl.Term + * @see jpl.Compound + */ +public class Atom extends Compound { + + //==================================================================/ + // Attributes (none) + //==================================================================/ + + //==================================================================/ + // Constructors + //==================================================================/ + + /** + * @param name the Atom's name (unquoted) + */ + public Atom(String name) { + super(name); + } + + //==================================================================/ + // Methods (common) + //==================================================================/ + + // these are all inherited from Compound + + public final int type() { + return Prolog.ATOM; + } + + //==================================================================/ + // Methods (deprecated) + //==================================================================/ + + /** + * Returns a debug-friendly String representation of an Atom. + * + * @return a debug-friendly String representation of an Atom + * @deprecated + */ + public String debugString() { + return "(Atom " + toString() + ")"; + } + + //==================================================================/ + // Converting JPL Terms to Prolog terms + //==================================================================/ + + // (this is done with the put() method inherited from Compound) + + //==================================================================/ + // Converting Prolog terms to JPL Terms + //==================================================================/ + + /** + * Converts a Prolog term to a JPL Atom. This is only called from Term.getTerm(), + * and we can assume the term_t refers to a Prolog atom, + * so we just create a new Atom object with the atom's name. + * + * @param vars_to_Vars A Map from Prolog variables to JPL Variables. + * @param term The Prolog term to be converted + * @return A new Atom instance + */ + protected static Term getTerm(Map vars_to_Vars, term_t term) { + StringHolder holder = new StringHolder(); + Prolog.get_atom_chars(term, holder); // ignore return val; assume success... + + return new Atom(holder.value); + } + + /** + * Converts a term_t to an Atom, knowing that it refers to a SWI-Prolog string, + * so we just create a new Atom object initialised with the string's value. + * JPL users should avoid SWI-Prolog's non-ISO strings, but in some obscure + * circumstances they are returned unavoidably, so we have to handle them + * (and this is how). + * + * @param vars_to_Vars A Map from Prolog variables to JPL Variables. + * @param term The term_t to convert + * @return A new Atom instance + */ + protected static Term getString(Map vars_to_Vars, term_t term) { + StringHolder holder = new StringHolder(); + Prolog.get_string_chars(term, holder); // ignore return val; assume success... + // System.err.println("Warning: Prolog returns a string: \"" + holder.value + "\""); + return new Atom(holder.value); + } + + //==================================================================/ + // Computing substitutions + //==================================================================/ + + // (done with the inherited Compound.getSubst() method) + +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/Compound.java b/LGPL/JPL/java/jpl/Compound.java new file mode 100644 index 000000000..1f53de658 --- /dev/null +++ b/LGPL/JPL/java/jpl/Compound.java @@ -0,0 +1,324 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: Compound.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import java.util.Map; + +import jpl.fli.IntHolder; +import jpl.fli.Prolog; +import jpl.fli.StringHolder; +import jpl.fli.term_t; + +//----------------------------------------------------------------------/ +// Compound +/** + * A Compound represents a structured term, + * comprising a functor and arguments (Terms). + * Atom is a subclass of Compound, whose instances have zero arguments. + * Direct instances of Compound must have one or more arguments + * (it is an error to attempt to construct a Compound with zero args; + * a JPLException will be thrown). + * For example, this Java expression yields + * a representation of the term f(a): + *
+ * new Compound( "f", new Term[] { new Atom("a") } )
+ * 
+ * Note the use of the "anonymous array" notation to denote the arguments + * (an anonymous array of Term). + *
+ * Alternatively, construct the Term from Prolog source syntax: + *
+ * Util.textToTerm("f(a)")
+ * 
+ * The arity of a Compound is the quantity of its arguments. + * Once constructed, neither the name, arity nor any argument of a Compound can be altered. + *
+ * Copyright (C) 2004 Paul Singleton

+ * Copyright (C) 1998 Fred Dushin

+ * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

+ * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

+ *


+ * @author Fred Dushin + * @version $Revision: 1.1 $ + * @see jpl.Term + * @see jpl.Atom + */ +public class Compound extends Term { + + //==================================================================/ + // Attributes + //==================================================================/ + + /** + * the name of this Compound + */ + protected final String name; + + /** + * the arguments of this Compound + */ + protected final Term[] args; + + //==================================================================/ + // Constructors + //==================================================================/ + + /** + * Creates a Compound with name but no args (i.e. an Atom). + * + * @param name the name of this Compound + * @param args the arguments of this Compound + */ + protected Compound(String name) { + if (name == null) { + throw new JPLException("jpl.Atom: cannot construct with null name"); + } + this.name = name; + this.args = new Term[] { + }; + } + + /** + * Creates a Compound with name and args. + * + * @param name the name of this Compound + * @param args the arguments of this Compound + */ + public Compound(String name, Term[] args) { + if (name == null) { + throw new JPLException("jpl.Compound: cannot construct with null name"); + } + if (args == null) { + throw new JPLException("jpl.Compound: cannot construct with null args"); + } + if (args.length == 0) { + throw new JPLException("jpl.Compound: cannot construct with zero args"); + } + this.name = name; + this.args = args; + } + + //==================================================================/ + // Methods (common) + //==================================================================/ + + /** + * Returns the ith argument (counting from 1) of this Compound; + * throws an ArrayIndexOutOfBoundsException if i is inappropriate. + * + * @return the ith argument (counting from 1) of this Compound + */ + public final Term arg(int i) { + return args[i - 1]; + } + + /** + * Tests whether this Compound's functor has (String) 'name' and 'arity'. + * + * @return whether this Compound's functor has (String) 'name' and 'arity' + */ + public final boolean hasFunctor(String name, int arity) { + return name.equals(name) && arity == args.length; + } + + /** + * Returns the name (unquoted) of this Compound. + * + * @return the name (unquoted) of this Compound + */ + public final String name() { + return name; + } + + /** + * Returns the arity (1+) of this Compound. + * + * @return the arity (1+) of this Compound + */ + public final int arity() { + return args.length; + } + + /** + * Returns a prefix functional representation of a Compound of the form name(arg1,...), + * where each argument is represented according to its toString() method. + *
+ * NB 'name' should be quoted iff necessary, and Term.toString(Term[]) is not + * really a Term method, more a utility... + * + * @return string representation of an Compound + */ + public String toString() { + return quotedName() + (args.length > 0 ? "(" + Term.toString(args) + ")" : ""); + } + + /** + * Two Compounds are equal if they are identical (same object) or their names and arities are equal and their + * respective arguments are equal. + * + * @param obj the Object to compare (not necessarily another Compound) + * @return true if the Object satisfies the above condition + */ + public final boolean equals(Object obj) { + return (this == obj || (obj instanceof Compound && name.equals(((Compound) obj).name) && Term.terms_equals(args, ((Compound) obj).args))); + } + + public int type() { + return Prolog.COMPOUND; + } + + public String typeName(){ + return "Compound"; + } + + //==================================================================/ + // Methods (protected) + //==================================================================/ + + /** + * Returns a quoted (iff necessary) form of the Atom's name, as understood by Prolog read/1 + * + * @return a quoted form of the Atom's name, as understood by Prolog read/1 + */ + protected String quotedName() { + return ((Atom) (new Query(new Compound("sformat", new Term[] { new Variable("S"), new Atom("~q"), new Compound(".", new Term[] { new Atom(this.name), new Atom("[]")}) + }))) + .oneSolution() + .get( + "S")).name; + } + + //==================================================================/ + // Methods (deprecated) + //==================================================================/ + + /** + * Returns the arguments of this Compound. + * + * @return the arguments of this Compound + * @deprecated + */ + public final Term[] args() { + return args; + } + + /** + * Returns the ith argument (counting from 0) of this Compound. + * + * @return the ith argument (counting from 0) of this Compound + * @deprecated + */ + public final Term arg0(int i) { + return args[i]; + } + + /** + * Returns a debug-friendly representation of a Compound. + * + * @return a debug-friendly representation of a Compound + * @deprecated + */ + public String debugString() { + return "(Compound " + name + " " + Term.debugString(args) + ")"; + } + + //==================================================================/ + // Converting JPL Terms to Prolog terms + //==================================================================/ + + /** + * To put a Compound in a term, we create a sequence of term_t + * references from the Term.terms_to_term_ts() method, and then + * use the Prolog.cons_functor_v() method to create a Prolog compound + * term. + * + * @param varnames_to_vars A Map from variable names to Prolog variables + * @param term A (previously created) term_t which is to be + * set to a Prolog term corresponding to the Term subtype + * (Atom, Variable, Compound, etc.) on which the method is invoked. + */ + protected final void put(Map varnames_to_vars, term_t term) { + + Prolog.cons_functor_v(term, Prolog.new_functor(Prolog.new_atom(name), args.length), Term.putTerms(varnames_to_vars, args)); + } + + //==================================================================/ + // Converting Prolog terms to JPL Terms + //==================================================================/ + + /** + * Converts the Prolog term in term_t (known to be a compound) to a JPL Compound. + * In this case, we create a list of Terms by calling Term.getTerm for each + * term_t reference we get from Prolog.get_arg + * (Not sure why we couldn't get a sequence from there, but...).

+ * + * @param varnames_to_vars A Map from variable names to Prolog variables + * @param term The Prolog term to convert + * @return A new Compound + */ + protected static Term getTerm(Map varnames_to_vars, term_t term) { + + // we need holders to get the term's name and arity back from the FLI: + StringHolder name_holder = new StringHolder(); + IntHolder arity_holder = new IntHolder(); + Prolog.get_name_arity(term, name_holder, arity_holder); // assume it succeeds + + Term args[] = new Term[arity_holder.value]; + for (int i = 1; i <= arity_holder.value; i++) { + term_t termi = Prolog.new_term_ref(); + Prolog.get_arg(i, term, termi); + args[i - 1] = Term.getTerm(varnames_to_vars, termi); + } + return new Compound(name_holder.value, args); + } + + //==================================================================/ + // Computing Substitutions + //==================================================================/ + + /** + * Nothing needs to be done except to pass the buck to this Compound's args. + * + * @param varnames_to_Terms A Map from variable names to JPL Terms + * @param vars_to_Vars A Map from Prolog variables to JPL Variables + */ + protected final void getSubst(Map varnames_to_Terms, Map vars_to_Vars) { + Term.getSubsts(varnames_to_Terms, vars_to_Vars, args); + } + +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/Float.java b/LGPL/JPL/java/jpl/Float.java new file mode 100644 index 000000000..fa4ebd7c3 --- /dev/null +++ b/LGPL/JPL/java/jpl/Float.java @@ -0,0 +1,295 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: Float.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import java.util.Map; + +import jpl.fli.DoubleHolder; +import jpl.fli.Prolog; +import jpl.fli.term_t; + +//----------------------------------------------------------------------/ +// Float +/** + * Float is a specialised Term with a double field, representing a Prolog 64-bit ISO/IEC floating point value. + * Once constructed, a Float's value cannot be altered. + *

+ * Float f = new Float( 3.14159265 );
+ * 
+ * A Float can be used (and re-used) in Compound Terms. + * Two Float instances are equal (by .equals()) iff their (double) values are equal. + * + *
+ * Copyright (C) 2004 Paul Singleton

+ * Copyright (C) 1998 Fred Dushin

+ * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

+ * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

+ *


+ * @author Fred Dushin + * @version $Revision: 1.1 $ + * @see jpl.Term + * @see jpl.Compound + */ +public class Float extends Term { + + //==================================================================/ + // Attributes + //==================================================================/ + + /** + * the Float's immutable value + */ + protected final double value; + + //==================================================================/ + // Constructors and Initialization + //==================================================================/ + + /** + * This constructor creates a Float with the supplied + * (double) value. + * + * @param value this Float's value + */ + public Float(double value) { + this.value = value; + } + + //==================================================================/ + // Methods (common) + //==================================================================/ + + /** + * throws a JPLException (arg(int) is defined only for Compound and Atom) + * + * @return the ith argument (counting from 1) of this Float (never) + */ + public final Term arg(int i) { + throw new JPLException("jpl.Float.arg(int) is undefined"); + } + + /** + * Tests whether this Float's functor has (String) 'name' and 'arity' (never) + * + * @return whether this Float's functor has (String) 'name' and 'arity' (never) + */ + public final boolean hasFunctor(String name, int arity) { + return false; + } + + /** + * Tests whether this Float's functor has (int) 'name' and 'arity' (never) + * + * @return whether this Float's functor has (int) 'name' and 'arity' (never) + */ + public final boolean hasFunctor(int val, int arity) { + return false; + } + + /** + * Tests whether this Float's functor has (double) 'name' and 'arity' + * + * @return whether this Float's functor has (double) 'name' and 'arity' + */ + public final boolean hasFunctor(double val, int arity) { + return val == this.value && arity == 0; + } + + /** + * throws a JPLException (name() is defined only for Compound, Atom and Variable) + * + * @return the name of this Float (never) + */ + public final String name() { + throw new JPLException("jpl.Float.name() is undefined"); + } + + /** + * Returns the arity (0) of this Float + * + * @return the arity (0) of this Float + */ + public final int arity() { + return 0; + } + + /** + * returns the (double) value of this Float, converted to an int + * + * @return the (double) value of this Float, converted to an int + */ + public final int intValue() { + return (new Double(value)).intValue(); + } + + /** + * returns the (double) value of this Float, converted to a long + * + * @return the (double) value of this Float, converted to a long + */ + public final long longValue() { + return (new Double(value)).longValue(); + } + + /** + * returns the (double) value of this Float, converted to a float + * + * @return the (double) value of this Float, converted to a float + */ + public final float floatValue() { + return (new Double(value)).floatValue(); + } + + /** + * returns the (double) value of this Float + * + * @return the (double) value of this Float + */ + public final double doubleValue() { + return this.value; + } + + /** + * Returns a Prolog source text representation of this Float + * + * @return a Prolog source text representation of this Float + */ + public String toString() { + return "" + value + ""; + } + + /** + * Two Floats are equal if they are the same object, or their values are equal + * + * @param obj The Object to compare + * @return true if the Object satisfies the above condition + */ + public final boolean equals(Object obj) { + return this == obj || (obj instanceof Float && value == ((Float) obj).value); + } + + public final int type() { + return Prolog.FLOAT; + } + + public String typeName(){ + return "Float"; + } + + //==================================================================/ + // Methods (deprecated) + //==================================================================/ + + /** + * The (nonexistent) args of this Float + * + * @return the (nonexistent) args of this Float + * @deprecated + */ + public Term[] args() { + return new Term[] {}; + } + + /** + * The immutable value of this jpl.Float object, as a Java double + * + * @return the Float's value + * @deprecated + */ + public double value() { + return value; + } + + /** + * Returns a debug-friendly String representation of this Float + * + * @return a debug-friendly String representation of this Float + * @deprecated + */ + public String debugString() { + return "(Float " + toString() + ")"; + } + + //==================================================================/ + // Converting JPL Terms to Prolog terms + //==================================================================/ + + /** + * To convert a JPL Float to a Prolog term, we put its value field into the + * term_t as a float. + * + * @param varnames_to_vars A Map from variable names to Prolog variables. + * @param term A (previously created) term_t which is to be + * set to a Prolog float corresponding to this Float's value + */ + protected final void put(Map varnames_to_vars, term_t term) { + Prolog.put_float(term, value); + } + + //==================================================================/ + // Converting Prolog terms to JPL Terms + //==================================================================/ + + /** + * Converts a Prolog term (known to be a float) to a JPL Float. + * + * @param vars_to_Vars A Map from Prolog variables to JPL Variables + * @param term The Prolog term (a float) to convert + * @return A new Float instance + */ + protected static Term getTerm(Map vars_to_Vars, term_t term) { + DoubleHolder double_holder = new DoubleHolder(); + + Prolog.get_float(term, double_holder); // assume it succeeds... + return new jpl.Float(double_holder.value); + } + + //==================================================================/ + // Computing Substitutions + //==================================================================/ + + /** + * Nothing needs to be done if the Term is an Atom, Integer or (as in this case) a Float + * + * @param varnames_to_Terms A Map from variable names to JPL Terms + * @param vars_to_Vars A Map from Prolog variables to JPL Variables + */ + protected final void getSubst(Map varnames_to_Terms, Map vars_to_Vars) { + } + +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/Integer.java b/LGPL/JPL/java/jpl/Integer.java new file mode 100644 index 000000000..cb1b719a1 --- /dev/null +++ b/LGPL/JPL/java/jpl/Integer.java @@ -0,0 +1,269 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: Integer.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import java.util.Map; + +import jpl.fli.IntHolder; +import jpl.fli.Prolog; +import jpl.fli.term_t; + +//----------------------------------------------------------------------/ +// Integer +/** + * Integer is a specialised Term with a long field, representing a Prolog integer value. + *
+ * Integer i = new Integer(1024);
+ * 
+ * Once constructed, the value of an Integer instance cannot be altered. + * An Integer can be used (and re-used) as an argument of Compounds. + * Beware confusing jpl.Integer with java.lang.Integer. + * + *
+ * Copyright (C) 2004 Paul Singleton

+ * Copyright (C) 1998 Fred Dushin

+ * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

+ * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

+ *


+ * @author Fred Dushin + * @version $Revision: 1.1 $ + * @see jpl.Term + * @see jpl.Compound + */ +public class Integer extends Term { + + //==================================================================/ + // Attributes + //==================================================================/ + + /** + * the Integer's immutable long value + */ + protected final long value; + + //==================================================================/ + // Constructors + //==================================================================/ + + /** + * @param value This Integer's (long) value + */ + public Integer(long value) { + this.value = value; + } + + /** + * @param value This Integer's (int) value + */ + public Integer(int value) { + this.value = value; + } + + //==================================================================/ + // Methods (common) + //==================================================================/ + + /** + * Tests whether this Integer's functor has (int) 'name' and 'arity' + * + * @return whether this Integer's functor has (int) 'name' and 'arity' + */ + public final boolean hasFunctor(int val, int arity) { + return val == this.value && arity == 0; + } + + /** + * Returns the arity (0) of this jpl.Integer + * + * @return the arity (0) of this jpl.Integer + */ + public final int arity() { + return 0; + } + + /** + * Returns the value of this Integer as an int if possible, else throws exception + * + * @return the int value of this Integer (if representable) + */ + public final int intValue() { + if (value < java.lang.Integer.MIN_VALUE || value > java.lang.Integer.MAX_VALUE) { + throw new JPLException("cannot represent Integer value as an int"); + } else { + return (int) value; + } + } + + /** + * Returns the value of this Integer converted to a long + * + * @return the value of this Integer converted to a long + */ + public final long longValue() { + return (new java.lang.Long(value)).longValue(); // safe but inefficient... + } + + /** + * Returns the value of this Integer converted to a float + * + * @return the value of this Integer converted to a float + */ + public final float floatValue() { + return (new java.lang.Long(value)).floatValue(); // safe but inefficient... + } + + /** + * Returns the value of this Integer converted to a double + * + * @return the value of this Integer converted to a double + */ + public final double doubleValue() { + return (new java.lang.Long(value)).doubleValue(); // safe but inefficient... + } + + /** + * Returns a Prolog source text representation of this Integer's value + * + * @return a Prolog source text representation of this Integer's value + */ + public String toString() { + return "" + value + ""; // hopefully invokes Integer.toString() or equivalent + } + + //------------------------------------------------------------------/ + // equals + /** + * Two Integer instances are equal if they are the same object, or if their values are equal + * + * @param obj The Object to compare (not necessarily an Integer) + * @return true if the Object satisfies the above condition + */ + public final boolean equals(Object obj) { + return this == obj || (obj instanceof Integer && value == ((Integer) obj).value); + } + + public final int type() { + return Prolog.INTEGER; + } + + public String typeName(){ + return "Integer"; + } + + //==================================================================/ + // Methods (deprecated) + //==================================================================/ + + /** + * Returns the int value of this jpl.Integer + * + * @return the Integer's value + * @deprecated + */ + public final int value() { + return (int) value; + } + + /** + * The (nonexistent) args of this Integer + * + * @return the (nonexistent) args of this Integer + * @deprecated + */ + public Term[] args() { + return new Term[] { + }; + } + + /** + * Returns a debug-friendly representation of this Integer's value + * + * @return a debug-friendly representation of this Integer's value + * @deprecated + */ + public String debugString() { + return "(Integer " + toString() + ")"; + } + + //==================================================================/ + // Converting JPL Terms to Prolog terms + //==================================================================/ + + /** + * To convert an Integer into a Prolog term, we put its value into the term_t. + * + * @param varnames_to_vars A Map from variable names to Prolog variables. + * @param term A (previously created) term_t which is to be + * set to a Prolog integer + */ + protected final void put(Map varnames_to_vars, term_t term) { + Prolog.put_integer(term, value); + } + + //==================================================================/ + // Converting Prolog terms to JPL Terms + //==================================================================/ + + /** + * Converts a Prolog term (known to be an integer) to a new Integer instance. + * + * @param vars_to_Vars A Map from Prolog variables to JPL Variables + * @param term The Prolog term (an integer) which is to be converted + * @return A new Integer instance + */ + protected static Term getTerm(Map vars_to_Vars, term_t term) { + IntHolder int_holder = new IntHolder(); + + Prolog.get_integer(term, int_holder); // assume it succeeds... + return new jpl.Integer(int_holder.value); + } + + //==================================================================/ + // Computing Substitutions + //==================================================================/ + + /** + * Nothing needs to be done if the Term is an Atom, Integer or Float + * + * @param varnames_to_Terms A Map from variable names to Terms. + * @param vars_to_Vars A Map from Prolog variables to JPL Variables. + */ + protected final void getSubst(Map varnames_to_Terms, Map vars_to_Vars) { + } + +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/JBoolean.java b/LGPL/JPL/java/jpl/JBoolean.java new file mode 100644 index 000000000..d5688ff9b --- /dev/null +++ b/LGPL/JPL/java/jpl/JBoolean.java @@ -0,0 +1,217 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: JBoolean.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import java.util.Map; + +import jpl.fli.BooleanHolder; +import jpl.fli.Prolog; +import jpl.fli.term_t; + +//----------------------------------------------------------------------/ +// JBoolean +/** + * A jpl.JBoolean is a specialised Term with a boolean field, representing JPL's Prolog representation of a Java boolean value. + *
+ * JBoolean b = new JBoolean( true or false );
+ * 
+ * A JBoolean can be used (and re-used) in Compound Terms. + * + *
+ * Copyright (C) 2004 Paul Singleton

+ * Copyright (C) 1998 Fred Dushin

+ * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

+ * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

+ *


+ * @author Fred Dushin + * @version $Revision: 1.1 $ + * @see jpl.Term + * @see jpl.Compound + */ +public class JBoolean extends Term { + + //==================================================================/ + // Attributes + //==================================================================/ + + /** + * the JBoolean's value (a boolean) + */ + protected final boolean value; + + //==================================================================/ + // Constructors + //==================================================================/ + + /** + * Constructs a JBoolean with the supplied boolean value. + * + * @param b this JBoolean's value (a boolean) + */ + public JBoolean(boolean b) { + this.value = b; + } + + //==================================================================/ + // Methods (common) + //==================================================================/ + + /** + * Tests whether this JBoolean's functor has (String) 'name' and 'arity' + * + * @return whether this JBoolean's functor has (String) 'name' and 'arity' + */ + public final boolean hasFunctor(String name, int arity) { + return name.equals("@") && arity==1; + } + + /** + * Returns a Prolog source text representation of this JBoolean + * + * @return a Prolog source text representation of this JBoolean + */ + public String toString() { + return (value ? "@(true)" : "@(false)"); + } + + /** + * Two JBooleans are equal if their values are equal + * + * @param obj The Object to compare (not necessarily a JBoolean) + * @return true if the Object satisfies the above condition + */ + public final boolean equals(Object obj) { + return this == obj || (obj instanceof JBoolean && value == ((JBoolean) obj).value); + } + + //==================================================================/ + // Methods (peculiar) + //==================================================================/ + + /** + * The boolean value which this jpl.JBoolean object represents + * + * @return the boolean value which this jpl.JBoolean object represents + */ + public boolean boolValue() { + return value; + } + + public final int type() { + return Prolog.JBOOLEAN; + } + + public String typeName(){ + return "JBoolean"; + } + + //==================================================================/ + // Methods (deprecated) + //==================================================================/ + + /** + * The (nonexistent) args of this JBoolean + * + * @return the (nonexistent) args of this JBoolean + * @deprecated + */ + public Term[] args() { + throw new JPLException("jpl.JBoolean.args() is undefined"); + } + + /** + * Returns a debug-friendly representation of this JBoolean + * + * @return a debug-friendly representation of this JBoolean + * @deprecated + */ + public String debugString() { + return "(JBoolean " + toString() + ")"; + } + + //==================================================================/ + // Converting JPL Terms to Prolog terms + //==================================================================/ + + /** + * To convert a JBoolean to a term, we unify the (freshly created, hence unbound) + * term_t with either @(false) or @(true) as appropriate. + * + * @param varnames_to_vars A Map from variable names to Prolog variables. + * @param term A (newly created) term_t which is to be + * set to a Prolog @(false) or @(true) structure denoting the + * .value of this JBoolean instance + */ + protected final void put(Map varnames_to_vars, term_t term) { + Prolog.put_jboolean(term, value); + } + + //==================================================================/ + // Converting Prolog terms to JPL Terms + //==================================================================/ + + /** + * Converts a term_t to a JBoolean. If the Prolog term is either + * @(false) or @(true), we just create a new JBoolean with a corresponding value. + * NB This conversion is only invoked if "JPL-aware" term import is specified. + * + * @param vars_to_Vars A Map from Prolog variable to JPL Variables. + * @param term The term (either @(false) or @(true)) to convert + * @return A new JBoolean instance + */ + protected static Term getTerm(Map vars_to_Vars, term_t term) { + BooleanHolder b = new BooleanHolder(); + + Prolog.get_jboolean(term, b); // assume it succeeds... + return new jpl.JBoolean(b.value); + } + + //==================================================================/ + // Computing Substitutions + //==================================================================/ + + /** + * Nothing needs to be done if the Term denotes an Atom, Integer, Float, JRef or JBoolean + * + * @param varnames_to_Terms A Map from variable names to Terms. + * @param vars_to_Vars A Map from Prolog variables to JPL Variables. + */ + protected final void getSubst(Map varnames_to_Terms, Map vars_to_Vars) { + } + +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/JPL.java b/LGPL/JPL/java/jpl/JPL.java new file mode 100644 index 000000000..fd3e504b8 --- /dev/null +++ b/LGPL/JPL/java/jpl/JPL.java @@ -0,0 +1,199 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: JPL.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import jpl.fli.Prolog; + +//----------------------------------------------------------------------/ +// JPL +/** + * The jpl.JPL class contains methods which allow (i) inspection and alteration + * of the "default" initialisation arguments (ii) explicit initialisation + * (iii) discovery of whether the Prolog engine is already initialised, + * and if so, with what arguments. + * The Prolog engine must be initialized + * before any queries are made, but this will happen automatically + * (upon the first call to a Prolog FLI routine) if it has not already + * been done explicitly. + * + *
+ * Copyright (C) 2004 Paul Singleton

+ * Copyright (C) 1998 Fred Dushin

+ * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

+ * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

+ *


+ * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +public class JPL { + protected static final boolean DEBUG = false; + + protected static boolean modeDontTellMe = true; + + //------------------------------------------------------------------/ + // setDTMMode + /** + * Sets the global "dont-tell-me" mode (default value: true). + * When 'true', bindings will *not* be returned for any variable (in a Query's goal) + * whose name begins with an underscore character (except for "anonymous" variables, + * i.e. those whose name comprises just the underscore character, whose bindings are never returned). + * When 'false', bindings are returned for *all* variables except anonymous ones; + * this mode may be useful when traditional top-level interpreter behaviour is wanted, + * e.g. in a Java-based Prolog IDE or debugger.

+ * This method should be regarded as experimental, and may subsequently be deprecated + * in favour of some more general mechanism for setting options, perhaps per-Query and + * per-call as well as globally. + * + * @param dtm new "dont-tell-me" mode value + */ + public static void setDTMMode( boolean dtm){ + modeDontTellMe = dtm; + } + + //------------------------------------------------------------------/ + // getDefaultInitArgs + /** + * Returns, in an array of String, the sequence of command-line + * arguments that would be used if the Prolog engine were to be initialised now. + * Returns null if the Prolog VM has already been initialised (in which + * case the default init args are irrelevant and the actual init args are of interest)

+ * + * @see jpl.JPL#getActualInitArgs + * @return current default initialisation arguments, or null if already initialised + */ + public static String[] getDefaultInitArgs() { + return Prolog.get_default_init_args(); + } + + //------------------------------------------------------------------/ + // setDefaultInitArgs + /** + * Specifies, in an array of String, the sequence of command-line + * arguments that should be used if the Prolog engine is subsequently initialised.

+ * + * @param args new default initialization arguments + */ + public static void setDefaultInitArgs(String[] args) { + Prolog.set_default_init_args(args); + } + + //------------------------------------------------------------------/ + // getActualInitArgs + /** + * Returns, in an array of String, the sequence of command-line + * arguments that were actually used when the Prolog engine was formerly initialised. + * + * This method returns null if the Prolog engine has not yet been initialised, + * and thus may be used to test this condition. + * + * @return actual initialization arguments + */ + public static String[] getActualInitArgs() { + return Prolog.get_actual_init_args(); + } + + //------------------------------------------------------------------/ + // init + /** + * Initializes the Prolog engine, using the String argument + * parameters passed. This method need be called only if you want to both + * (i) initialise the Prolog engine with parameters other than the default ones + * and (ii) force initialisation to occur + * (rather than allow it to occur automatically at the first query). + * For parameter options, consult your local + * Prolog documentation. The parameter values are passed directly + * to initialization routines for the Prolog environment.

+ * + * This method must be called before making any queries. + * + * @param args Initialization parameter list + */ + public static boolean init(String[] args) { + return Prolog.set_default_init_args(args) && init(); + } + + //------------------------------------------------------------------/ + // init + /** + * Initialises the Prolog engine using the current default initialisation parameters, + * and returns 'true' (or 'false' if already initialised). + */ + public static boolean init() { + return Prolog.initialise(); + } + + //------------------------------------------------------------------/ + // halt + /** + * Terminates the Prolog session.

+ * + * Note. This method calls the FLI halt() method with a + * status of 0, but the halt method currently is a no-op in SWI. + * @deprecated + */ + public static void halt() { + Prolog.halt(0); + } + + // a static reference to the current Version + private static final Version version_ = new Version(); + + //------------------------------------------------------------------/ + // version + /** + * Returns (as a Version) an identification of this version of JPL. + * @return the running version of JPL. + */ + public static Version version() { + return version_; + } + + //------------------------------------------------------------------/ + // version_string + /** + * Returns a String (eg "3.0.0-alpha") identifying this version of JPL. + * @return a String (eg "3.0.0-alpha") identifying this version of JPL. + */ + public static String version_string() { + return version_.major + "." + version_.minor + "." + version_.patch + "-" + version_.status; + } + + public static void main(String[] args) { + System.out.println(version_string()); + } +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/JPLException.java b/LGPL/JPL/java/jpl/JPLException.java new file mode 100644 index 000000000..955af23a2 --- /dev/null +++ b/LGPL/JPL/java/jpl/JPLException.java @@ -0,0 +1,61 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: JPLException.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +//----------------------------------------------------------------------/ +// JPLException +/** + * This is the base class for exceptions thrown by JPL's Java-calls-Prolog interface. + * Such exceptions represent errors and exceptional conditions within the interface code itself; + * see jpl.PrologException for the way Prolog exceptions are returned to calling Java code. + *


+ * Copyright (C) 2004 Paul Singleton

+ * Copyright (C) 1998 Fred Dushin

+ * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

+ * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

+ *


+ * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +public class JPLException extends RuntimeException { + public JPLException() { + super(); + } + + public JPLException(String s) { + super(s); + } +} diff --git a/LGPL/JPL/java/jpl/JRef.java b/LGPL/JPL/java/jpl/JRef.java new file mode 100644 index 000000000..4dac2049c --- /dev/null +++ b/LGPL/JPL/java/jpl/JRef.java @@ -0,0 +1,215 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: JRef.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import java.util.Map; + +import jpl.fli.ObjectHolder; +import jpl.fli.Prolog; +import jpl.fli.term_t; + +//----------------------------------------------------------------------/ +// JRef +/** + * JRef is a specialised Term with an Object field, representing JPL's Prolog references to Java objects (or to null). + *
+ * JRef r = new JRef( non_String_object_or_null );
+ * 
+ * A JRef can be used (and re-used) in Compound Terms. + * + *
+ * Copyright (C) 2004 Paul Singleton

+ * Copyright (C) 1998 Fred Dushin

+ * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

+ * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

+ *


+ * @author Fred Dushin + * @version $Revision: 1.1 $ + * @see jpl.Term + * @see jpl.Compound + */ +public class JRef extends Term { + + //==================================================================/ + // Attributes + //==================================================================/ + + /** + * the JRef's value (a non-String Object or null) + */ + protected final Object ref; + + //==================================================================/ + // Constructors + //==================================================================/ + + /** + * This constructor creates a JRef, initialized with the supplied + * non-String object (or null). + * + * @param ref this JRef's value (a non-String object, or null) + */ + public JRef(Object ref) { + if (ref instanceof String) { + throw new JPLException("a JRef cannot have a String value (String maps to atom)"); + } else { + this.ref = ref; + } + } + + //==================================================================/ + // Methods (common) + //==================================================================/ + + /** + * Returns a Prolog source text representation of this JRef + * + * @return a Prolog source text representation of this JRef + */ + public String toString() { + return "" + ref + ""; // WRONG + } + + /** + * Two JRefs are equal if their references are identical (?) + * + * @param obj The Object to compare + * @return true if the Object satisfies the above condition + */ + public final boolean equals(Object obj) { + return this == obj || (obj instanceof JRef && ref == ((JRef) obj).ref); + } + + public final int type() { + return Prolog.JREF; + } + + public String typeName(){ + return "JRef"; + } + + //==================================================================/ + // Methods (peculiar) + //==================================================================/ + + /** + * The non-String object (or null) which this jpl.JRef represents + * + * @return the non-String object (or null) which this jpl.JRef represents + */ + public Object ref() { + return ref; + } + + //==================================================================/ + // Methods (deprecated) + //==================================================================/ + + /** + * The (nonexistent) args of this JRef + * + * @return the (nonexistent) args of this JRef + * @deprecated + */ + public Term[] args() { + return new Term[] { + }; + } + + /** + * Returns a debug-friendly representation of this JRef + * + * @return a debug-friendly representation of this JRef + * @deprecated + */ + public String debugString() { + return "(JRef " + toString() + ")"; + } + + //==================================================================/ + // Converting JPL Terms to Prolog terms + //==================================================================/ + + /** + * To convert a JRef to a term, we put its Object field (.value) into the + * term_t as a JPL ref (i.e. @/1) structure. + * + * @param varnames_to_vars A Map from variable names to Prolog variables. + * @param term A (newly created) term_t which is to be + * set to a Prolog 'ref' (i.e. @/1) structure denoting the + * .value of this JRef instance + */ + protected final void put(Map varnames_to_vars, term_t term) { + + Prolog.put_jref(term, ref); + } + + //==================================================================/ + // Converting Prolog terms to JPL Terms + //==================================================================/ + + /** + * Converts a term_t to a JRef. Assuming the Prolog term is a + * ref, we just create a new JRef using the term_t's value. + * NB This conversion is only invoked if "JPL-aware" term import is specified. + * + * @param vars_to_Vars A Map from Prolog variables to JPL Variables. + * @param term The term (a ref) to convert + * @return A new JRef instance + */ + protected static Term getTerm(Map vars_to_Vars, term_t term) { + ObjectHolder obj = new ObjectHolder(); + + Prolog.get_jref(term, obj); // assume it succeeds... + return new jpl.JRef(obj.value); + } + + //==================================================================/ + // Computing Substitutions + //==================================================================/ + + /** + * Nothing needs to be done if the Term is an Atom, Integer, Float or JRef + * + * @param varnames_to_Terms A Map from variable names to Terms. + * @param vars_to_Vars A Map from Prolog variables to JPL Variables. + */ + protected final void getSubst(Map varnames_to_Terms, Map vars_to_Vars) { + } + +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/JVoid.java b/LGPL/JPL/java/jpl/JVoid.java new file mode 100644 index 000000000..5ada281ce --- /dev/null +++ b/LGPL/JPL/java/jpl/JVoid.java @@ -0,0 +1,185 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: JVoid.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import java.util.Map; + +import jpl.fli.Prolog; +import jpl.fli.term_t; + +//----------------------------------------------------------------------/ +// JVoid +/** + * A jpl.JVoid is a specialised Term. Instances of this class + * denote JPL 'jvoid' values in Prolog, i.e. @(void): + *
+ * JVoid b = new JVoid();
+ * 
+ * A JVoid can be used (and re-used) in Compound Terms. + * + *
+ * Copyright (C) 2004 Paul Singleton

+ * Copyright (C) 1998 Fred Dushin

+ * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

+ * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

+ *


+ * @author Fred Dushin + * @version $Revision: 1.1 $ + * @see jpl.Term + * @see jpl.Compound + */ +public class JVoid extends Term { + + //==================================================================/ + // Attributes (none) + //==================================================================/ + + //==================================================================/ + // Constructors + //==================================================================/ + + /** + * This constructor creates a JVoid. + * + */ + public JVoid() { + } + + //==================================================================/ + // Methods (common) + //==================================================================/ + + /** + * Returns a Prolog source text representation of this JVoid + * + * @return a Prolog source text representation of this JVoid + */ + public String toString() { + return "@(void)"; + } + + /** + * Two JVoids are equal + * + * @param obj The Object to compare (not necessarily another JVoid) + * @return true if the Object satisfies the above condition + */ + public final boolean equals(Object obj) { + return this == obj || (obj instanceof JVoid); + } + + public final int type() { + return Prolog.JVOID; + } + + public String typeName(){ + return "JVoid"; + } + + //==================================================================/ + // Methods (deprecated) + //==================================================================/ + + /** + * The (nonexistent) args of this JVoid + * + * @return the (nonexistent) args of this JVoid + * @deprecated + */ + public Term[] args() { + return new Term[] {}; + } + + /** + * Returns a debug-friendly representation of this JVoid + * + * @return a debug-friendly representation of this JVoid + * @deprecated + */ + public String debugString() { + return "(JVoid)"; + } + + //==================================================================/ + // Converting JPL Terms to Prolog terms + //==================================================================/ + + /** + * To convert a JVoid to a term, we unify the (freshly created, hence unbound) + * term_t with @(void). + * + * @param varnames_to_vars A Map from variable names to Prolog variables. + * @param term A (previously created and unbound) term_t which is to be + * assigned a Prolog @(void) structure + */ + protected final void put(Map varnames_to_vars, term_t term) { + Prolog.put_jvoid(term); + } + + //==================================================================/ + // Converting Prolog terms to JPL Terms + //==================================================================/ + + /** + * Converts a term_t to a JVoid. Assuming the Prolog term to be + * @(void), we just create a new JVoid instance. + * NB This conversion is only invoked if "JPL-aware" term import is specified. + * + * @param vars_to_Vars A Map from Prolog variables to JPL Variables. + * @param term The term_t to convert + * @return A new JVoid instance + */ + protected static Term getTerm(Map vars_to_Vars, term_t term) { + return new jpl.JVoid(); + } + + //==================================================================/ + // Computing Substitutions + //==================================================================/ + + /** + * Nothing needs to be done if the Term denotes an Atom, Integer, Float, JRef, JBoolean or JVoid + * + * @param varnames_to_Terms A Map from variable names to Terms. + * @param vars_to_Vars A Map from Prolog variables to JPL Variables. + * Variables. + */ + protected final void getSubst(Map varnames_to_Terms, Map vars_to_Vars) { + } + +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/PrologException.java b/LGPL/JPL/java/jpl/PrologException.java new file mode 100644 index 000000000..4e0a88522 --- /dev/null +++ b/LGPL/JPL/java/jpl/PrologException.java @@ -0,0 +1,74 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: PrologException.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +//----------------------------------------------------------------------/ +// PrologException +/** + * PrologException instances wrap Prolog exceptions thrown (either by a Prolog engine or by user code) + * in the course of finding a solution to a Query. See JPLException for the handling of errors within the JPL Java-calls-Prolog interface. + *

+ * This class allows Java code which uses JPL's Java-calls-Prolog API to handle + * Prolog exceptions, which is in general necessary for hybrid Java+Prolog programming. + *

+ * Use the term() accessor to obtain a Term representation of the term that was + * thrown from within Prolog. + * + *


+ * Copyright (C) 2004 Paul Singleton

+ * Copyright (C) 1998 Fred Dushin

+ * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

+ * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

+ *


+ * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +public final class PrologException extends JPLException { + private Term term_ = null; + + protected PrologException(Term term) { + super("PrologException: " + term.toString()); + + this.term_ = term; + } + + /** + * @return a reference to the Term thrown by the call to throw/1 + */ + public Term term() { + return this.term_; + } +} diff --git a/LGPL/JPL/java/jpl/Query.java b/LGPL/JPL/java/jpl/Query.java new file mode 100644 index 000000000..60a270290 --- /dev/null +++ b/LGPL/JPL/java/jpl/Query.java @@ -0,0 +1,791 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: Query.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Map; +import java.util.Vector; + +import jpl.fli.*; + +//----------------------------------------------------------------------/ +// Query +/** + * A Query instance is created by an application in order to query the Prolog engine. + * It is initialised with a + * Compound (or Atom) denoting the goal which is to be called, and also contains assorted private state + * relating to solutions. In some future version, it will contain details of the module + * in which the goal is to be called.

+ * A Query is either open or closed: when closed, it has no connection to the Prolog engine; + * when open, it is linked to an active goal within the Prolog engine. + * Only one Query can be open at any one time

+ * The Query class implements the Enumeration interface, and it is + * through this interface that one obtains successive solutions. The Enumeration + * hasMoreElements() method returns true if the call or redo succeeded (otherwise + * false), and if the call or redo did succeed, the nextElement() method returns + * a Hashtable representing variable bindings; the elements in the + * Hashtable are Terms, indexed by the Variables with which they are associated. + * For example, if p(a) and p(b) are facts in the Prolog + * database, then the following is equivalent to printing all + * the solutions to the Prolog query p(X): + *

+ * Variable X = new Variable();
+ * Term arg[] = { X };
+ * Query    q = new Query( "p", arg );
+ * 
+ * while ( q.hasMoreElements() ){
+ *     Term bound_to_x = ((Hashtable)q.nextElement()).get( X );
+ *     System.out.println( bound_to_x );
+ * }
+ * 
+ * Make sure to close the Query (using the rewind() method) if you do not need + * any further solutions which it may have. + * It is safe (although redundant) to close a Query whose solutions are already exhausted, + * or which is already closed. + * + * To obtain just one solution from a Query, use the oneSolution() method. + * + * To obtain all solutions, use the allSolutions() method. + * + * To determine merely whether the Query is provable, + * use the query() method (soon to be deprecated in favour of hasSolution()). + * (i.e. has at least one solution). + *
+ * + * Copyright (C) 2004 Paul Singleton

+ * Copyright (C) 1998 Fred Dushin + *

+ * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

+ * + *


+ * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class Query implements Enumeration { + + //==================================================================/ + // Attributes + //==================================================================/ + + private static Map m = new Hashtable(); // maps (engine_t) engine handle to (Query) topmost query + + /** + * the Compound (hence perhaps an Atom, but not Integer, Float or Variable) corresponding to the goal of this Query + */ + protected final Compound goal_; // set by all initialisers + protected final String hostModule = "user"; // until revised constructors allow this to be specified + protected final String contextModule = "user"; // until revised constructors allow this to be specified + + /** + * @deprecated Use .goal().name() instead. + * @return the name of this Query's goal (redundant, deprecated) + */ + public final String name() { + return goal_.name(); // it can only be a Compound or Atom + } + + /** + * @deprecated Use .goal().args() instead. + * @return the arguments of this Query's goal (redundant, deprecated) + */ + public final Term[] args() { + return goal_.args(); + } + + /** + * Returns the Compound (hence perhaps an Atom) which is the goal of this Query + * @return a Term representing the goal of this Query + */ + public final Compound goal() { + return goal_; + } + + //==================================================================/ + // Constructors and Initialization + //==================================================================/ + + //------------------------------------------------------------------/ + // Query + /** + * This constructor creates a Query whose goal is the specified Term. + * The Query is initially closed. + * NB Creating an instance of the Query class does not + * result in a call to a Prolog engine. + * NB The goal can be an Atom (Atom extends Compound), but cannot be an instance + * of jpl.Float, jpl.Integer or jpl.Variable. + * @param t the goal of this Query + */ + public Query(Term t) { // formerly insisted (confusingly) on a Compound (or Atom) + this.goal_ = Query1( t); + } + + private Compound Query1( Term t ) { + if (t instanceof Compound) { + return (Compound) t; + } else if (t instanceof Integer) { + throw new JPLException("a Query's goal must be an Atom or Compound (not an Integer)"); + } else if (t instanceof Float) { + throw new JPLException("a Query's goal must be an Atom or Compound (not a Float)"); + } else if (t instanceof Variable) { + throw new JPLException("a Query's goal must be an Atom or Compound (not a Variable)"); + } else { + throw new JPLException("a Query's goal must be an Atom or Compound"); + } + } + + // Query + /** + * If text denotes an atom, this constructor is shorthand for + * new Query(new Compound(name,args)), + * but if text denotes a term containing N query symbols + * and there are N args, each query is replaced by its corresponding arg + * to provide the new Query's goal. + * + * @param text the name of the principal functor of this Query's goal + * @param args the arguments of this Query's goal + */ + public Query(String text, Term[] args) { + this(Query1(text, args)); + } + + // convenience case for a single arg + public Query(String text, Term arg) { + this(Query1(text, new Term[] {arg})); + } + + private static Term Query1( String text, Term[] args) { + Term t = Util.textToTerm(text); + if ( t instanceof Atom ){ + return new Compound(text,args); + } else { + return t.putParams(args); + } + } + + // Query + /** + * This constructor builds a Query from the given Prolog source text + * + * @param text the Prolog source text of this Query + */ + public Query(String text) { + this(Util.textToTerm(text)); + } + + //==================================================================/ + // Making Prolog Queries + //==================================================================/ + + /** + * These variables are used and set across the hasMoreElements + * and nextElement Enumeration interface implementation + */ + private boolean open = false; + // the following state variables are used and defined only if this query is open: + private boolean called = false; // open/get/close vs. hasMoreSolutions/nextSolution + private engine_t engine = null; // handle of attached Prolog engine iff open, else null + private Query subQuery = null; // the open Query (if any) on top of which this open Query is stacked, else null + private predicate_t predicate = null; // handle of this Query's predicate iff open, else undefined + private fid_t fid = null; // id of current Prolog foreign frame iff open, else null + private term_t term0 = null; // term refs of this Query's args iff open, else undefined + private qid_t qid = null; // id of current Prolog query iff open, else null + + //------------------------------------------------------------------/ + // hasMoreSolutions + /** + * This method returns true if JPL was able to initiate a "call" of this + * Query within the Prolog engine. It is designed to be used + * with the nextSolution() method to retrieve one or + * more substitutions in the form of Hashtables. To iterate through + * all the solutions to a Query, for example, one might write + *
+	 * Query q = // obtain Query reference
+	 * while ( q.hasMoreSolutions() ){
+	 *     Hashtable solution = q.nextSolution();
+	 *     // process solution...
+	 * }
+	 * 
+ * To ensure thread-safety, you should wrap sequential calls to + * this method in a synchronized block, using the static + * lock method to obtain the monitor. + *
+	 * Query q = // obtain Query reference
+	 * synchronized ( jpl.Query.lock() ){
+	 *     while ( q.hasMoreElements() ){
+	 *          Hashtable solution = q.nextSolution();
+	 *          // process solution...
+	 *     }
+	 * }
+	 * 
+ *

+ * If this method is called on an already-open Query, + * or while another Query is open, then a + * QueryInProgressException will be thrown, containing a reference to the currently + * open Query. + * + * @return true if the Prolog query succeeds; otherwise false. + */ + public synchronized final boolean hasMoreSolutions() { + + if (!open) { + open(); + } + return get1(); + } + + //------------------------------------------------------------------/ + // open + /** + * This method returns true if JPL was able to initiate a "call" of this + * Query within the Prolog engine. It is designed to be used + * with the getSolution() and close() methods to retrieve one or + * more substitutions in the form of Hashtables. + * To ensure thread-safety, you should wrap sequential calls to + * this method in a synchronized block, using the static + * lock method to obtain the monitor. + *

+	 * Query q = // obtain Query reference
+	 * synchronized ( jpl.Query.lock() ){
+	 *     while ( q.hasMoreElements() ){
+	 *          Hashtable solution = q.nextSolution();
+	 *          // process solution...
+	 *     }
+	 * }
+	 * 
+ *

+ * If this method is called on an already-open Query, + * or if the query cannot be set up for whatever reason, + * then a JPLException will be thrown. + */ + public synchronized final void open() { + + if (open) { + throw new JPLException("Query is already open"); + } + int self = Prolog.thread_self(); + // System.out.println("JPL thread_self()=" + self); + if (Prolog.thread_self() == -1) { // this Java thread has no attached Prolog engine? + engine = Prolog.attach_pool_engine(); // may block for a while, or fail + // System.out.println("JPL attaching engine[" + engine.value + "] for " + this.hashCode() + ":" + this.toString()); + } else { // this Java thread has an attached engine + engine = Prolog.current_engine(); + // System.out.println("JPL reusing engine[" + engine.value + "] for " + this.hashCode() + ":" + this.toString()); + } + if (m.containsKey(new Long(engine.value))) { + subQuery = (Query) m.get(new Long(engine.value)); // get this engine's previous topmost query + // System.out.println("JPL reusing engine[" + engine.value + "] pushing " + subQuery.hashCode() + ":" + subQuery.toString()); + } else { + subQuery = null; + } + m.put(new Long(engine.value), this); // update this engine's topmost query + predicate = Prolog.predicate(goal_.name(), goal_.args.length, hostModule); + fid = Prolog.open_foreign_frame(); // always succeeds? + Map varnames_to_vars = new Hashtable(); + term0 = Term.putTerms(varnames_to_vars, goal_.args); + // THINKS: invert varnames_to_Vars and use it when getting substitutions? + qid = Prolog.open_query(Prolog.new_module(Prolog.new_atom(contextModule)), Prolog.Q_NORMAL, predicate, term0); + open = true; + called = false; + } + + private final boolean get1() { + + // try to get the next solution; if none, close the query; + if (Prolog.next_solution(qid)) { + called = true; // OK to call get2() + return true; + } else { + // if failure was due to throw/1, build exception term and throw it + term_t exception_term_t = Prolog.exception(qid); + if (exception_term_t.value != 0L) { + Term exception_term = Term.getTerm(new Hashtable(), exception_term_t); + close(); + throw new PrologException(exception_term); + } else { + close(); + return false; + } + } + } + + //------------------------------------------------------------------/ + // getSolution + /** + * This method returns a java.util.Hashtable, which represents + * a set of bindings from the names of query variables to terms within the solution. + * The Hashtable contains instances of Terms, keyed on those + * Variables which were referenced in this Query's goal. + *

+ * For example, if a Query has an occurrence of a jpl.Variable, + * say, named X, one can obtain the Term bound to X in the solution + * by looking up X in the Hashtable. + *

+	 * Variable X = new Variable();
+	 * Query q = // obtain Query reference (with X in the Term array)
+	 * while ( q.hasMoreSolutions() ){
+	 *     Hashtable solution = q.nextSolution();
+	 *     // make t the Term bound to X in the solution
+	 *     Term t = (Term)solution.get( X );
+	 *     // ...
+	 * }
+	 * 
+ * Programmers should obey the following rules when using this method. + * + *
  • The nextSolution() method should only be called after the + * hasMoreSolutions() method returns true; otherwise a JPLException + * will be raised, indicating that no Query is in progress. + *
  • The nextSolution() and hasMoreSolutions() should be called + * in the same thread of execution, at least for a given Query + * instance. + *
  • The nextSolution() method should not be called while + * another Thread is in the process of evaluating a Query. The + * JPL High-Level interface is designed to be thread safe, and + * is thread-safe as long as the previous two rules are obeyed. + *
  • + * + * This method will throw a JPLException if no query is in progress. + * It will throw a QueryInProgressException if another Query + * (besides this one) is in progress while this method is called. + * + * @return A Hashtable representing a substitution, or null + */ + public synchronized final Hashtable getSolution() { + // oughta check: Query is open and thread has its engine + if (get1()) { + return get2(); + } else { + return null; + } + } + + public synchronized final Hashtable getSubstWithNameVars() { + // oughta check: Query is open and thread has its engine + if (get1()) { + return get2WithNameVars(); + } else { + return null; + } + } + + //------------------------------------------------------------------/ + // nextSolution + /** + * This method returns a java.util.Hashtable, which represents + * a binding from the names of query variables to terms within the solution. + * The Hashtable contains instances of Terms, keyed on those + * Variables which were referenced in this Query's goal. + *

    + * For example, if a Query has an occurrence of a jpl.Variable, + * say, named X, one can obtain the Term bound to X in the solution + * by looking up X in the Hashtable. + *

    +	 * Variable X = new Variable();
    +	 * Query q = // obtain Query reference (with X in the Term array)
    +	 * while ( q.hasMoreSolutions() ){
    +	 *     Hashtable solution = q.nextSolution();
    +	 *     // make t the Term bound to X in the solution
    +	 *     Term t = (Term)solution.get( X );
    +	 *     // ...
    +	 * }
    +	 * 
    + * Programmers should obey the following rules when using this method. + * + *
  • The nextSolution() method should only be called after the + * hasMoreSolutions() method returns true; otherwise a JPLException + * will be raised, indicating that no Query is in progress. + *
  • The nextSolution() and hasMoreSolutions() should be called + * in the same thread of execution, at least for a given Query + * instance. + *
  • The nextSolution() method should not be called while + * another Thread is in the process of evaluating a Query. The + * JPL High-Level interface is designed to be thread safe, and + * is thread-safe as long as the previous two rules are obeyed. + *
  • + * + * This method will throw a JPLException if no query is in progress. + * It will throw a QueryInProgressException if another Query + * (besides this one) is in progress while this method is called. + * + * @return A Hashtable representing a substitution. + */ + public synchronized final Hashtable nextSolution() { + return get2(); + } + + private final Hashtable get2() { + if (!open) { + throw new JPLException("Query is not open"); + } else { + Hashtable substitution = new Hashtable(); + // NB I reckon computeSubstitutions needn't be in Term (but where else?) + Term.getSubsts(substitution, new Hashtable(), goal_.args); + return substitution; + } + } + + // assumes that Query's last arg is a Variable which will be bound to a [Name=Var,..] dict + private final Hashtable get2WithNameVars() { + if (!open) { + throw new JPLException("Query is not open"); + } else { + Term[] args = goal_.args; // for slight convenience below + Term argNV = args[args.length - 1]; // the Query's last arg + String nameNV = ((Variable) argNV).name; // its name + + // get the [Name=Var,..] dict from the last arg + Map varnames_to_Terms1 = new Hashtable(); + Map vars_to_Vars1 = new Hashtable(); + args[args.length - 1].getSubst(varnames_to_Terms1, vars_to_Vars1); + + Hashtable varnames_to_Terms2 = new Hashtable(); + Term nvs = (Term) varnames_to_Terms1.get(nameNV); + Map vars_to_Vars2 = Util.namevarsToMap(nvs); + for (int i = 0; i < args.length - 1; ++i) { + args[i].getSubst(varnames_to_Terms2, vars_to_Vars2); + } + + return varnames_to_Terms2; + } + } + + //------------------------------------------------------------------/ + // hasMoreElements + /** + * This method is completes the java.util.Enumeration + * interface. It is a wrapper for hasMoreSolutions. + * + * @return true if the Prolog query succeeds; false, o/w. + */ + public synchronized final boolean hasMoreElements() { + return hasMoreSolutions(); + } + + //------------------------------------------------------------------/ + // nextElement + /** + * This method completes the java.util.Enumeration + * interface. It is a wrapper for nextSolution. + *

    + * This method will throw a QueryInProgressException if another Query + * (besides this one) is in progress while this method is called. + * + * @return A Hashtable representing a substitution. + */ + public synchronized final Object nextElement() { + return nextSolution(); + } + + public synchronized final void rewind() { + close(); + } + + //------------------------------------------------------------------/ + // close + /** + * This method is used to close an open query so that the query + * may be re-run, even if the Query's Enumeration has more + * elements. Calling rewind() on an exhausted Enumeration has + * no effect.

    + * + * Here is a way to get the first three solutions to a Query, + * while subsequently being able to use the same Query object to + * obtain new solutions: + *

    +	 * Query q = new Query( predicate, args );
    +	 * int i = 0;
    +	 * for ( int i = 0; i < 3 && q.hasMoreSolutions();  ++i ){
    +	 *     Hasthable sub = (Hashtable) q.nextSolution();
    +	 *     ...
    +	 * }
    +	 * q.close();
    +	 * 

    + */ + public synchronized final void close() { + if (!open) { + return; // it is not an error to attempt to close a closed Query + } + if (Prolog.thread_self() == -1) { + throw new JPLException("no engine is attached to this thread"); + } + if (Prolog.current_engine().value != engine.value) { + throw new JPLException("this Query's engine is not that which is attached to this thread"); + } + Query topmost = (Query) m.get(new Long(engine.value)); + if (topmost != this) { + throw new JPLException( + "this Query (" + + this.hashCode() + + ":" + + this.toString() + + ") is not topmost (" + + topmost.hashCode() + + ":" + + topmost.toString() + + ") within its engine[" + + engine.value + + "]"); + } + Prolog.close_query(qid); + qid = null; // for tidiness + Prolog.discard_foreign_frame(fid); + fid = null; // for tidiness + m.remove(new Long(engine.value)); + if (subQuery == null) { // only Query open in this engine? + if (Prolog.current_engine_is_pool()) { // this (Query's) engine is from the pool? + Prolog.release_pool_engine(); + // System.out.println("JPL releasing engine[" + engine.value + "]"); + } else { + // System.out.println("JPL leaving engine[" + engine.value + "]"); + } + } else { + m.put(new Long(engine.value), subQuery); + // System.out.println("JPL retaining engine[" + engine.value + "] popping subQuery(" + subQuery.hashCode() + ":" + subQuery.toString() + ")"); + } + // eid = -1; // for tidiness + engine = null; + subQuery = null; + open = false; + called = false; + + } + + //------------------------------------------------------------------/ + // allSolutions + /** + * calls the Query's goal to exhaustion and returns an array containing every solution + * (in the order in which they were found). + * @return an array of Hashtables (possibly none), each of which is a solution + * (in the order in which they were found) of the Query. + * NB in JPL 1.0.1, this method returned null when a Query had no solutions; + * in JPL 2.x.x it returns an emprt array (thus the length of the array is, in every case, + * the quantity of solutions).

    + * + * This method will throw a QueryInProgressException if this or another Query + * is already open. + * + * @see jpl.Query#hasMoreElements + * @see jpl.Query#nextElement + * @see jpl.Query#hasMoreSolutions + * @see jpl.Query#nextSolution + * @see jpl.Query#rewind + * @see jpl.Query#oneSolution + * @see jpl.Query#allSolutions + * @see jpl.Query#query + */ + public synchronized final Hashtable[] allSolutions() { + if (open) { + throw new JPLException("Query is already open"); + } else { + // get a vector of solutions: + Vector v = new Vector(); + while (hasMoreSolutions()) { + v.addElement(nextSolution()); + } + + // turn the vector into an array: + Hashtable solutions[] = new Hashtable[v.size()]; // 0 solutions -> Hashtable[0] + v.copyInto(solutions); + + return solutions; + } + } + + //------------------------------------------------------------------/ + // oneSolution + /** + * Returns the first solution, if any, as a (possibly empty) Hashtable. + * + * This method will throw a JPLException if this Query + * is already open, and the Query will remain open as before. + * Otherwise, upon return, the Query will be closed. + * @return the first solution, if the query has one, as a (possibly empty) Hashtable. + * If the return value is null, this means that the Query has no solutions.

    + * + * @see jpl.Query#hasMoreElements + * @see jpl.Query#nextElement + * @see jpl.Query#hasMoreSolutions + * @see jpl.Query#nextSolution + * @see jpl.Query#rewind + * @see jpl.Query#oneSolution + * @see jpl.Query#allSolutions + * @see jpl.Query#query + */ + public synchronized final Hashtable oneSolution() { + if (open) { + throw new JPLException("Query is already open"); + } else { + Hashtable solution = null; + if (hasMoreSolutions()) { + solution = nextSolution(); + } + rewind(); + return solution; + } + } + + //------------------------------------------------------------------/ + // query + /** + * @deprecated Use .hasSolution() instead. + * JPL will attempt to call this Query's goal within the attached Prolog engine. + * @return the provability of the Query, i.e. 'true' if it has at least + * one solution, 'false' if the call fails without finding a solution.

    + * + * Only the first solution (if there is one) will be found; + * any bindings will be discarded, and the Query will be closed.

    + * This method will throw a QueryInProgressException if this or another Query + * is already open. + * + * @see jpl.Query#hasMoreElements + * @see jpl.Query#nextElement + * @see jpl.Query#hasMoreSolutions + * @see jpl.Query#nextSolution + * @see jpl.Query#rewind + * @see jpl.Query#oneSolution + * @see jpl.Query#allSolutions + * @see jpl.Query#query + */ + public synchronized final boolean query() { + return oneSolution() != null; + } + + //------------------------------------------------------------------/ + // hasSolution + /** + * JPL will attempt to call this Query's goal within the attached Prolog engine. + * @return the provability of the Query, i.e. 'true' if it has at least + * one solution, 'false' if the call fails without finding a solution.

    + * + * Only the first solution (if there is one) will be found; + * any bindings will be discarded, and the Query will be closed.

    + * This method will throw a QueryInProgressException if this or another Query + * is already open. + * + * @see jpl.Query#hasMoreElements + * @see jpl.Query#nextElement + * @see jpl.Query#hasMoreSolutions + * @see jpl.Query#nextSolution + * @see jpl.Query#rewind + * @see jpl.Query#oneSolution + * @see jpl.Query#allSolutions + * @see jpl.Query#query + */ + public synchronized final boolean hasSolution() { + return oneSolution() != null; + } + + public final int abort() { + if (open) { + (new Thread(new Runnable() { + public void run() { + try { + int rc1 = Prolog.attach_engine(engine); + System.out.println("q.abort(): attach_engine() returns " + rc1); + int rc2 = Prolog.action_abort(); + System.out.println("q.abort(): action_abort() returns " + rc2); + // int rc3 = Prolog.release_pool_engine(); + // System.out.println("q.abort(): release_pool_engine() returns " + rc3); + } catch (Exception e) { + + } + } + })).start(); // call the query in a separate thread + /* + int rc0a = Prolog.pool_engine_id(this.engine); + System.out.println("q.abort(): this.engine has id=" + rc0a); + + engine_t e = Prolog.current_engine(); + System.out.println("q.abort(): " + (e == null ? "no current engine" : "current engine id=" + Prolog.pool_engine_id(e))); + + int rc0b = Prolog.release_pool_engine(); + System.err.println("q.abort(): release_pool_engine() returns " + rc0b); + + engine_t e2 = Prolog.current_engine(); + System.out.println("q.abort(): " + (e == null ? "no current engine" : "current engine id=" + Prolog.pool_engine_id(e2))); + + int rc1 = Prolog.attach_engine(this.engine); + System.out.println("q.abort(): attach_engine() returns " + rc1); + + engine_t e3 = Prolog.current_engine(); + System.out.println("q.abort(): " + (e == null ? "no current engine" : "current engine id=" + Prolog.pool_engine_id(e3))); + + int rc2 = Prolog.action_abort(); + System.out.println("q.abort(): action_abort() returns " + rc2); + + int rc3 = Prolog.release_pool_engine(); + System.out.println("q.abort(): release_pool_engine() returns " + rc3); + + int rc4 = Prolog.attach_engine(e); + System.out.println("q.abort(): attach_engine() returns " + rc4); + */ + return 0; + } else { + System.out.println("q.abort(): query is not open"); + return -1; + } + } + + //==================================================================/ + // misc + //==================================================================/ + + /** + * Returns the String representation of a Query. + * + * @return the String representation of a Query + */ + public String toString() { + return goal_.name + "( " + Term.toString(goal_.args) + " )"; + } + + //==================================================================/ + // Methods (deprecated) + //==================================================================/ + + /** + * Returns a debug-friendly representation of a Query + * + * @return a debug-friendly representation of a Query + * @deprecated + */ + public String debugString() { + return "(Query " + goal_.name + " " + Term.debugString(goal_.args) + ")"; + } +} diff --git a/LGPL/JPL/java/jpl/Term.java b/LGPL/JPL/java/jpl/Term.java new file mode 100644 index 000000000..ba54416f0 --- /dev/null +++ b/LGPL/JPL/java/jpl/Term.java @@ -0,0 +1,671 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: Term.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import java.util.Map; + +import jpl.fli.IntHolder; +import jpl.fli.Prolog; +import jpl.fli.term_t; + +//----------------------------------------------------------------------/ +// Term +/** + * Term is the abstract base class for + * Compound, Atom, Variable, Integer and Float, which comprise a Java-oriented concrete syntax for Prolog. + * You cannot create instances of Term directly; rather, you should create + * instances of Term's concrete subclasses. + * Alternatively, use textToTerm() to construct a Term from its conventional + * Prolog source text representation. + * + *


    + * Copyright (C) 2004 Paul Singleton

    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +public abstract class Term { + //==================================================================/ + // Attributes + //==================================================================/ + + //==================================================================/ + // Constructors + //==================================================================/ + + /** + * This default constructor is provided in order for subclasses + * to be able to define their own default constructors. + */ + protected Term() { + } + + //==================================================================/ + // Methods (abstract, common) + //==================================================================/ + + /** + * returns the ano-th (1+) argument of a (Compound) Term + * throws a JPLException for any other subclass + * + * @return the ano-th argument of a (Compound) Term + */ + public Term arg(int ano) { + throw new JPLException("jpl." + this.typeName() + ".arg() is undefined"); + }; + + /** + * Tests whether this Term's functor has (String) 'name' and 'arity' + * Returns false if called inappropriately + * + * @return whether this Term's functor has (String) 'name' and 'arity' + */ + public boolean hasFunctor(String name, int arity) { + return false; + } + + /** + * Tests whether this Term's functor has (int) 'name' and 'arity' + * Returns false if called inappropriately + * + * @return whether this Term's functor has (int) 'name' and 'arity' + */ + public boolean hasFunctor(int value, int arity) { + return false; + } + + /** + * Tests whether this Term's functor has (double) 'name' and 'arity' + * Returns false if called inappropriately + * + * @return whether this Term's functor has (double) 'name' and 'arity' + */ + public boolean hasFunctor(double value, int arity) { + return false; + } + + /** + * returns, as a String, the name of a Compound, Atom or Variable + * throws a JPLException from an Integer or Float + * + * @return the name of a Compound, Atom or Variable + */ + public String name() { + throw new JPLException("jpl." + this.typeName() + ".name() is undefined"); + }; + + /** + * returns, as an int, the arity of a Compound, Atom, Integer or Float + * throws a JPLException from a Variable + * + * @return the arity of a Compound, Atom, Integer or Float + */ + public int arity() { + throw new JPLException("jpl." + this.typeName() + ".arity() is undefined"); + }; + + /** + * returns the value (as an int) of an Integer or Float + * throws a JPLException from a Compound, Atom or Variable + * + * @return the value (as an int) of an Integer or Float + */ + public int intValue() { + throw new JPLException("jpl." + this.typeName() + ".intValue() is undefined"); + } + /** + * returns the value (as a long) of an Integer or Float + * throws a JPLException from a Compound, Atom or Variable + * + * @return the value (as a long) of an Integer or Float + */ + public long longValue() { + throw new JPLException("jpl." + this.typeName() + ".longValue() is undefined"); + } + /** + * returns the value (as a float) of an Integer or Float + * throws a JPLException from a Compound, Atom or Variable + * + * @return the value (as a float) of an Integer or Float + */ + public float floatValue() { + throw new JPLException("jpl." + this.typeName() + ".floatValue() is undefined"); + } + + /** + * returns the value (as a double) of an Integer or Float + * throws a JPLException from any other subclass + * + * @return the value (as an double) of an Integer or Float + */ + public double doubleValue() { + throw new JPLException("jpl." + this.typeName() + ".doubleValue() is undefined"); + } + + //==================================================================/ + // Methods (common) + //==================================================================/ + + /** + * returns the type of this term, as one of jpl.fli.Prolog.COMPOUND, .ATOM, .VARIABLE, .INTEGER, .FLOAT etc + * + * @return the type of this term, as one of jpl.fli.Prolog.COMPOUND, .ATOM, .VARIABLE, .INTEGER, .FLOAT etc + */ + public abstract int type(); + + /** + * returns the name of the type of this term, as one of "Compound", "Atom", "Variable", "Integer", "Float" etc + * + * @return the name of the type of this term, as one of "Compound", "Atom", "Variable", "Integer", "Float" etc + */ + public abstract String typeName(); + + /** + * whether this Term represents an atom + * + * @return whether this Term represents an atom + */ + public boolean isAtom() { + return this instanceof Atom; + } + + /** + * whether this Term represents a compound term + * + * @return whether this Term represents a compound atom + */ + public boolean isCompound() { + return this instanceof Compound; + } + + /** + * whether this Term represents an atom + * + * @return whether this Term represents an atom + */ + public boolean isFloat() { + return this instanceof Float; + } + + /** + * whether this Term represents an atom + * + * @return whether this Term represents an atom + */ + public boolean isInteger() { + return this instanceof Integer; + } + + /** + * whether this Term is a JBoolean + * + * @return whether this Term is a JBoolean + */ + public boolean isJBoolean() { + return this instanceof JBoolean; + } + + /** + * whether this Term is a JRef + * + * @return whether this Term is a JRef + */ + public boolean isJRef() { + return this instanceof JRef; + } + + /** + * whether this Term is a JVoid + * + * @return whether this Term is a JVoid + */ + public boolean isJVoid() { + return this instanceof JVoid; + } + + /** + * whether this Term is a variable + * + * @return whether this Term is a variable + */ + public boolean isVariable() { + return this instanceof Variable; + } + + public Term putParams(Term[] ps) { + IntHolder next = new IntHolder(); + next.value = 0; + Term t2 = this.putParams1(next, ps); + if (next.value != ps.length) { + throw new JPLException("Term.putParams: more actual params than formal"); + } + return t2; + } + + public Term putParams(Term plist) { + Term[] ps = plist.toTermArray(); + return putParams(ps); + } + + protected Term putParams1(IntHolder next, Term[] ps) { + switch (this.type()) { + case Prolog.COMPOUND : + return new Compound(this.name(), putParams2(this.args(), next, ps)); + case Prolog.ATOM : + if (this.name().equals("?")) { + if (next.value >= ps.length) { + throw new JPLException("Term.putParams: fewer actual params than formal params"); + } + return ps[next.value++]; + } // else drop through to default + default : + return this; + } + } + + static protected Term[] putParams2(Term[] ts, IntHolder next, Term[] ps) { + int n = ts.length; + Term[] ts2 = new Term[n]; + for (int i = 0; i < n; i++) { + ts2[i] = ts[i].putParams1(next, ps); + } + return ts2; + } + + /** + * the length of this list, iff it is one, else an exception is thrown + * + * @throws JPLException + * @return the length (as an int) of this list, iff it is one + */ + public int listLength() { + int len = 0; + + if (this.hasFunctor(".", 2)) { + return 1 + this.arg(2).listLength(); + } else if (this.hasFunctor("[]", 0)) { + return 0; + } else { + throw new JPLException("Term.listLength: term is not a list"); + } + } + + /** returns an array of terms which are the successive members of this list, if it is a list, else throws an exception + * + * @throws JPLException + * @return an array of terms which are the successive members of this list, if it is a list + */ + public Term[] toTermArray() { + try { + int len = this.listLength(); + Term[] ts = new Term[len]; + Term t = this; + + for (int i = 0; i < len; i++) { + ts[i] = t.arg(1); + t = t.arg(2); + } + return ts; + } catch (JPLException e) { + throw new JPLException("Term.toTermArray: term is not a proper list"); + } + } + + //==================================================================/ + // Methods (deprecated) + //==================================================================/ + + /** + * returns, as a Term[], the arguments of a Compound + * returns an empty Term[] from an Atom, Integer or Float + * throws a JPLException from a Variable + * + * @return the arguments of a Compound as a Term[ + * @deprecated + */ + public abstract Term[] args(); + + /** + * Returns a debug-friendly representation of a Term + * + * @return a debug-friendly representation of a Term + * @deprecated + */ + public abstract String debugString(); + + /** + * Returns a debug-friendly representation of a list of Terms + * + * @return a debug-friendly representation of a list of Terms + * @deprecated + */ + public static String debugString(Term arg[]) { + String s = "["; + + for (int i = 0; i < arg.length; ++i) { + s += arg[i].debugString(); + if (i != arg.length - 1) { + s += ", "; + } + } + return s + "]"; + } + + //==================================================================/ + // Converting JPL Terms to Prolog terms + // + // To convert a Term to a term_t, we need to traverse the Term + // structure and build a corresponding Prolog term_t object. + // There are some issues: + // + // - Prolog term_ts rely on the *consecutive* nature of term_t + // references. In particular, to build a compound structure + // in the Prolog FLI, one must *first* determine the arity of the + // compound, create a *sequence* of term_t references, and then + // put atoms, functors, etc. into those term references. We + // do this in these methods by first determining the arity of the + // Compound, and then by "put"-ing a type into a term_t. + // The "put" method is implemented differently in each of Term's + // five subclasses. + // + // - What if we are trying to make a term_t from a Term, but the + // Term has multiple instances of the same Variable? We want + // to ensure that _one_ Prolog variable will be created, or else + // queries will give incorrect answers. We thus pass a Hashtable + // (var_table) through these methods. The table contains term_t + // instances, keyed on Variable instances. + //==================================================================/ + + /** + * Cache the reference to the Prolog term_t here. + * + * @param varnames_to_vars A Map from variable names to JPL Variables. + * @param term A (previously created) term_t which is to be + * put with a Prolog term-type appropriate to the Term type + * (e.g., Atom, Variable, Compound, etc.) on which the method is + * invoked.) + */ + protected abstract void put(Map varnames_to_vars, term_t term); + + /** + * This static method converts an array of Terms to a *consecutive* + * sequence of term_t objects. Note that the first term_t object + * returned is a term_t class (structure); the succeeding term_t + * objects are consecutive references obtained by incrementing the + * *value* field of the term_t. + * + * @param varnames_to_vars Map from variable names to JPL Variables. + * @param args An array of jpl.Term references. + * @return consecutive term_t references (first of which is + * a structure) + */ + protected static term_t putTerms(Map varnames_to_vars, Term[] args) { + + // first create a sequence of term_ts. The 0th term_t + // will be a jpl.fli.term_t. Successive Prolog term_t + // references will reside in the Prolog engine, and + // can be obtained by term0.value+i. + // + term_t term0 = Prolog.new_term_refs(args.length); + + // for each new term reference, construct a Prolog term + // by putting an appropriate Prolog type into the reference. + // + long ith_term_t = term0.value; + for (int i = 0; i < args.length; ++i, ++ith_term_t) { + term_t term = new term_t(); + term.value = ith_term_t; + args[i].put(varnames_to_vars, term); // each subclass defines its own put() + } + + return term0; + } + + //==================================================================/ + // Converting Prolog terms to JPL Terms + // + // Converting back from term_ts to Terms is simple, since + // the (simplified) Term representation is canonical (there is only one + // correct structure for any given Prolog term). + // + // One problem concerns variable bindings. We illustrate + // with several examples. First, consider the Prolog fact + // + // p( f(X,X)). + // + // And the query + // + // ?- p( Y). + // + // A solution should be + // + // y = f(X,X) + // + // and indeed, if this query is run, the term_t to which Y will + // be unified is a compound, f(X,X). The problem is, how do + // we know, in converting the term_ts to Terms in the compound f/2 + // whether we should create one Variable or two? This begs the + // question, how do we _identify_ Variables in JPL? The answer + // to the latter question is, by reference; two Variable (Java) + // references refer to the same variable iff they are, in memory, + // the same Variable object. That is, they satisfy the Java == relation. + // (Note that this condition is _not_ true of the other Term types.) + // + // Given this design decision, therefore, we should create a + // single Variable instance and a Compound instance whose two arg + // values refer to the same Variable object. We therefore need to keep + // track, in converting a term_t to a Term (in particular, in + // converting a term_t whose type is variable to a Variable), of + // which Variables have been created. We do this by using the vars + // Hashtable, which gets passed recursively though the from_term_t + // methods; this table holds the Variable instances that have been + // created, keyed by the unique and internal-to-Prolog string + // representation of the variable (I'm not sure about this...). + //==================================================================/ + + /** + * This method calls from_term_t on each term in the n consecutive term_ts. + * A temporary jpl.term_t "holder" (byref) structure must be created + * in order to extract type information from the Prolog engine. + * + * @param vars_to_Vars A Map from Prolog variables to jpl.Variable instances + * @param n The number of consecutive term_ts + * @param term0 The 0th term_t (structure); subsequent + * term_ts are not structures. + * @return An array of converted Terms + */ + /* + protected static Term[] from_term_ts(Map vars_to_Vars, int n, term_t term0) { + + // create an (uninitialised) array of n Term references + Term[] terms = new Term[n]; + + // for each term_t (from 0...n-1), create a term_t + // (temporary) structure and dispatch the translation + // to a Term to the static from_term_t method of the Term + // class. This will perform (Prolog) type analysis on the + // term_t and call the appropriate static method to create + // a Term of the right type (e.g., Atom, Variable, List, etc.) + // + long ith_term_t = term0.value; + for (int i = 0; i < n; ++i, ++ith_term_t) { + term_t term = new term_t(); + term.value = ith_term_t; + + terms[i] = Term.from_term_t(vars_to_Vars, term); + } + + return terms; + } + */ + + /** + * We discover the Prolog type of the term, then forward the + * call to the appropriate subclass + * + * @param vars A Map from Prolog variables to jpl.Variable instances + * @param term The Prolog term (in a term_t holder) to convert + * @return The converted Term subtype instance. + */ + protected static Term getTerm(Map vars_to_Vars, term_t term) { + int type = Prolog.term_type(term); + + switch (type) { + case Prolog.VARIABLE : + return Variable.getTerm(vars_to_Vars, term); + case Prolog.ATOM : + return Atom.getTerm(vars_to_Vars, term); + case Prolog.STRING : + return Atom.getString(vars_to_Vars, term); + case Prolog.INTEGER : + return Integer.getTerm(vars_to_Vars, term); + case Prolog.FLOAT : + return Float.getTerm(vars_to_Vars, term); + case Prolog.COMPOUND : + return Compound.getTerm(vars_to_Vars, term); + default : + // should never happen... + throw new JPLException("Term.from_term_t: unknown term type=" + type); + } + } + + //==================================================================/ + // Computing Substitutions + // + // Once a solution has been found, the Prolog term_t references + // will have been instantiated and will refer to new terms. To compute + // a substitution, we traverse the (original) Term structure, looking + // at the term_t reference in the Term. The only case we really care + // about is if the (original) Term is a Variable; if so, the term_t + // back in the Prolog engine may be instantiated (non Variable parts + // of the original Term cannot change or become uninstantiated). In + // this case, we can store this term in a Hashtable, keyed by the + // Variable with which the term was unified. + //==================================================================/ + + //------------------------------------------------------------------/ + // getSubst + /** + * This method computes a substitution from a Term. The bindings + * Hashtable stores Terms, keyed by Variables. Thus, a + * substitution is as it is in mathematical logic, a sequence + * of the form \sigma = {t_0/x_0, ..., t_n/x_n}. Once the + * substitution is computed, the substitution should satisfy + * + * \sigma T = t + * + * where T is the Term from which the substitution is computed, + * and t is the term_t which results from the Prolog query.

    + * + * A second Hashtable, vars, is required; this table holds + * the Variables that occur (thus far) in the unified term. + * The Variable instances in this table are guaranteed to be + * unique and are keyed on Strings which are Prolog internal + * representations of the variables. + * + * @param bindings table holding Term substitutions, keyed on + * Variables. + * @param vars A Hashtable holding the Variables that occur + * thus far in the term; keyed by internal (Prolog) string rep. + */ + protected abstract void getSubst(Map varnames_to_Terms, Map vars_to_Vars); + + //------------------------------------------------------------------/ + // getSubsts + /** + * Just calls computeSubstitution for each Term in the array. + * + * @param varnames_to_Terms a Map from variable names to Terms + * @param vars_to_Vars a Map from Prolog variables to JPL Variables + * @param arg a list of Terms + */ + protected static void getSubsts(Map varnames_to_Terms, Map vars_to_Vars, Term[] args) { + for (int i = 0; i < args.length; ++i) { + args[i].getSubst(varnames_to_Terms, vars_to_Vars); + } + } + + //------------------------------------------------------------------/ + // terms_equals + /** + * This method is used (by Compound.equals) to determine the Terms in two Term arrays + * are pairwise equal, where two Terms are equal if they satisfy + * the equals predicate (defined differently in each Term subclass). + * + * @param t1 an array of Terms + * @param t2 another array of Terms + * @return true if all of the Terms in the (same-length) arrays are pairwise equal + */ + protected static boolean terms_equals(Term[] t1, Term[] t2) { + if (t1.length != t2.length) { + return false; + } + + for (int i = 0; i < t1.length; ++i) { + if (!t1[i].equals(t2[i])) { + return false; + } + } + return true; + } + + //------------------------------------------------------------------/ + // toString + /** + * Converts a list of Terms to a String. + * + * @param args An array of Terms to convert + * @return String representation of a list of Terms + */ + public static String toString(Term[] args) { + String s = ""; + + for (int i = 0; i < args.length; ++i) { + s += args[i].toString(); + if (i != args.length - 1) { + s += ", "; + } + } + + return s; + } + +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/Util.java b/LGPL/JPL/java/jpl/Util.java new file mode 100644 index 000000000..af5c78395 --- /dev/null +++ b/LGPL/JPL/java/jpl/Util.java @@ -0,0 +1,172 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: Util.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import java.util.Hashtable; +import java.util.Map; + +//----------------------------------------------------------------------/ +// Util +/** + * This class provides a bunch of static utility methods for the JPL + * High-Level Interface. + * + *


    + * Copyright (C) 2004 Paul Singleton

    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +public final class Util { + //------------------------------------------------------------------/ + // termArrayToList + /** + * Converts an array of Terms to a JPL representation of a Prolog list of terms + * whose members correspond to the respective array elements. + * + * @param terms An array of Term + * @return Term a list of the array elements + */ + public static Term termArrayToList(Term[] terms) { + Term list = new Atom("[]"); + + for (int i = terms.length - 1; i >= 0; --i) { + list = new Compound(".", new Term[] { terms[i], list }); + } + return list; + } + + /** + * Converts a solution hashtable to an array of Terms. + * + * @param varnames_to_Terms A Map from variable names to Terms + * @return Term[] An array of the Terms to which successive variables are bound + */ + public static Term[] bindingsToTermArray(Map varnames_to_Terms) { + Term[] ts = new Term[varnames_to_Terms.size()]; + + for (java.util.Iterator i = varnames_to_Terms.keySet().iterator(); i.hasNext();) { + Variable k = (Variable) i.next(); + ts[k.index] = (Term) (varnames_to_Terms.get(k)); + } + return ts; + } + + //------------------------------------------------------------------/ + // toString + /** + * Converts a substitution, in the form of a Map from variable names to Terms, to a String. + * + * @param varnames_to_Terms A Map from variable names to Terms. + * @return String A String representation of the variable bindings + */ + public static String toString(Map varnames_to_Terms) { + if (varnames_to_Terms == null) { + return "[no solution]"; + } + java.util.Iterator varnames = varnames_to_Terms.keySet().iterator(); + + String s = "Bindings: "; + while (varnames.hasNext()) { + String varname = (String) varnames.next(); + s += varname + "=" + varnames_to_Terms.get(varname).toString() + "; "; + } + return s; + } + + //------------------------------------------------------------------/ + // namevarsToMap + /** + * Converts a (JPL) list of Name=Var pairs (as yielded by atom_to_term/3) + * to a Map from Prolog variables (necessarily in term_t holders) to named JPL Variables + * + * @param nvs A JPL list of Name=Var pairs (as yielded by atom_to_term/3) + * @return Map A Map from Prolog variables (necessarily in term_t holders) to named JPL Variables + */ + public static Map namevarsToMap(Term nvs) { + + try { + Map vars_to_Vars = new Hashtable(); + + /* + while (nvs.hasFunctor(".", 2) && ((Compound) nvs).arg(1).hasFunctor("=", 2)) { + Atom name = (Atom) ((Compound) ((Compound) nvs).arg(1)).arg(1); // get the Name of the =/2 pair + Variable var = (Variable) ((Compound) ((Compound) nvs).arg(1)).arg(2); // get the Var of the =/2 pair + + vars_to_Vars.put(var.term_, new Variable(name.name())); // map the Prolog variable to a new, named Variable + nvs = ((Compound) nvs).arg(2); // advance to next list cell + } + */ + while (nvs.hasFunctor(".", 2) && nvs.arg(1).hasFunctor("=", 2)) { + // the cast to Variable is necessary to access the (protected) .term_ field + vars_to_Vars.put(((Variable)nvs.arg(1).arg(2)).term_, new Variable(nvs.arg(1).arg(1).name())); // map the Prolog variable to a new, named Variable + nvs = nvs.arg(2); // advance to next list cell + } + + // maybe oughta check that nvs is [] ? + return vars_to_Vars; + } catch (java.lang.ClassCastException e) { // nvs is not of the expected structure + return null; + } + } + + //------------------------------------------------------------------/ + // textToTerm + /** + * Converts a Prolog source text to a corresponding JPL Term + * (in which each Variable has the appropriate name from the source text). + * Throws PrologException containing error(syntax_error(_),_) if text is invalid. + * + * @param text A Prolog source text denoting a term + * @return Term a JPL Term equivalent to the given source text + */ + public static Term textToTerm(String text) { + // it might be better to use PL_chars_to_term() + Query q = new Query(new Compound("atom_to_term", new Term[] { new Atom(text), new Variable("Term"), new Variable("NVdict")})); + q.open(); + Map s = q.getSubstWithNameVars(); + if (s != null) { + q.close(); + return (Term) s.get("Term"); + } else { + return null; + } + } + +} diff --git a/LGPL/JPL/java/jpl/Variable.java b/LGPL/JPL/java/jpl/Variable.java new file mode 100644 index 000000000..1e7b59bfb --- /dev/null +++ b/LGPL/JPL/java/jpl/Variable.java @@ -0,0 +1,301 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: Variable.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 2004 Paul Singleton +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl; + +import java.util.Iterator; +import java.util.Map; + +import jpl.fli.Prolog; +import jpl.fli.term_t; + +//----------------------------------------------------------------------/ +// Variable +/** + * This class supports Java representations of Prolog variables.

    + * + * A jpl.Variable instance is equivalent to a variable in a fragment of Prolog source text: + * it is *not* a "live" variable within a Prolog stack or heap. + * A corresponding Prolog variable is created only upon opening + * a Query whose goal refers to a Variable (and then only temporarily). + * + *


    + * Copyright (C) 2004 Paul Singleton

    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class Variable extends Term { + + //==================================================================/ + // Attributes + //==================================================================/ + + private static long n = 0; // the integral part of the next automatic variable name to be allocated + + public final String name; // the name of this Variable + + protected transient term_t term_ = null; // defined between Query.open() and Query.get2() + protected transient int index; // only used by (redundant?) + + //==================================================================/ + // Constructors + //==================================================================/ + + /** + * Create a new Variable with 'name' (which must not be null or ""), + * and may one day be constrained to comply with traditional Prolog syntax. + * + * @param name the source name of this Variable + */ + public Variable(String name) { + if (name == null) { + throw new JPLException("constructor jpl.Variable(name): name cannot be null"); + } + if (!isValidName(name)) { + throw new JPLException("constructor jpl.Variable(name): name cannot be empty String"); + } + this.name = name; + } + + //==================================================================/ + // Constructors (deprecated) + //==================================================================/ + + /** + * Create a new Variable with new sequential name of the form "_261". + * + * @deprecated use Variable(String name) instead + */ + public Variable() { + this.name = "_" + Long.toString(n++); // e.g. _0, _1 etc. + } + + //==================================================================/ + // Methods (common) + //==================================================================/ + + /** + * returns the lexical name of this Variable + * + * @return the lexical name of this Variable + */ + public final String name() { + return this.name; + } + + /** + * Returns a Prolog source text representation of this Variable + * + * @return a Prolog source text representation of this Variable + */ + public String toString() { + return this.name; + } + + /** + * A Variable is equal to another if their names are the same and they are not anonymous. + * + * @param obj The Object to compare. + * @return true if the Object is a Variable and the above condition apply. + */ + public final boolean equals(Object obj) { + return obj instanceof Variable && !this.name.equals("_") && this.name.equals(((Variable) obj).name); + } + + public final int type() { + return Prolog.VARIABLE; + } + + public String typeName() { + return "Variable"; + } + + //==================================================================/ + // Methods (private) + //==================================================================/ + + /** + * Tests the lexical validity of s as a variable's name + * + * @return the lexical validity of s as a variable's name + * @deprecated + */ + private boolean isValidName(String s) { + if (s == null) { + throw new java.lang.NullPointerException(); // JPL won't call it this way + } + int len = s.length(); + if (len == 0) { + throw new JPLException("invalid variable name"); + } + char c = s.charAt(0); + if (!(c == '_' || c >= 'A' && c <= 'Z')) { + return false; + } + for (int i = 1; i < len; i++) { + c = s.charAt(i); + if (!(c == '_' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9')) { + return false; + } + } + return true; + } + + //==================================================================/ + // Methods (deprecated) + //==================================================================/ + + /** + * The (nonexistent) args of this Variable + * + * @return the (nonexistent) args of this Variable + * @deprecated + */ + public Term[] args() { + return new Term[] { + }; + } + + /** + * Returns a debug-friendly String representation of an Atom. + * + * @return a debug-friendly String representation of an Atom + * @deprecated + */ + public String debugString() { + return "(Variable " + toString() + ")"; + } + + //==================================================================/ + // Converting JPL Terms to Prolog terms + //==================================================================/ + + /** + * To put a Variable, we must check whether a (non-anonymous) variable with the same name + * has already been put in the Term. If one has, then the corresponding Prolog variable has + * been stashed in the varnames_to_vars Map, keyed by the Variable name, so we can look + * it up and reuse it (this way, the sharing of variables in the Prolog term + * reflects the sharing of Variable names in the Term. + * Otherwise, if this Variable name has not + * already been seen in the Term, then we put a new Prolog variable and add it into the Map + * (keyed by this Variable name). + * + * @param varnames_to_vars A Map from variable names to Prolog variables. + * @param term A (previously created) term_t which is to be + * set to a (new or reused) Prolog variable. + */ + protected final void put(Map varnames_to_vars, term_t term) { + term_t var; + // if this var is anonymous or as yet unseen, put a new Prolog variable + if (this.name.equals("_") || (var = (term_t) varnames_to_vars.get(this.name)) == null) { + this.term_ = term; + this.index = varnames_to_vars.size(); // i.e. first var in is #0 etc. + Prolog.put_variable(term); + if (!this.name.equals("_")) { + varnames_to_vars.put(this.name, term); + } + } else { + this.term_ = var; + Prolog.put_term(term, var); + } + } + + //==================================================================/ + // Converting Prolog terms to JPL Terms + //==================================================================/ + + /** + * Converts a term_t (known to refer to a Prolog variable) to a Variable. + * If the variable has already been seen (and hence converted), + * return its corresponding Variable from the map, + * else create a new Variable, stash it in the map (keyed by the Prolog variable), + * and return it. + * + * @param vars_to_Vars a map from Prolog to JPL variables + * @param var The term_t (known to be a variable) to convert + * @return A new or reused Variable + */ + protected static Term getTerm(Map vars_to_Vars, term_t var) { + + for (Iterator i = vars_to_Vars.keySet().iterator(); i.hasNext();) { + term_t varX = (term_t) i.next(); // a previously seen Prolog variable + if (Prolog.compare(varX, var) == 0) { // identical Prolog variables? + return (Term) vars_to_Vars.get(varX); // return the associated JPL Variable + } + } + // otherwise, the Prolog variable in term has not been seen before + Variable Var = new Variable(); // allocate a new (sequentially named) Variable to represent it + Var.term_ = var; // this should become redundant... + vars_to_Vars.put(var, Var); // use Hashtable(var,null), but only need set(var) + return Var; + } + + //==================================================================/ + // Computing Substitutions + //==================================================================/ + + /** + * If this Variable instance is not an anonymous or (in dont-tell-me mode) a dont-tell-me variable, and its binding is not already in the varnames_to_Terms Map, + * put the result of converting the term_t to which this variable + * has been unified to a Term in the Map, keyed on this Variable's name. + * + * @param varnames_to_Terms A Map of bindings from variable names to JPL Terms. + * @param vars_to_Vars A Map from Prolog variables to JPL Variables. + */ + protected final void getSubst(Map varnames_to_Terms, Map vars_to_Vars) { + // NB a Variable.name cannot be "" i.e. of 0 length + // if (!(this.name.charAt(0) == '_') && varnames_to_Terms.get(this.name) == null) { + if (tellThem() && varnames_to_Terms.get(this.name) == null) { + varnames_to_Terms.put(this.name, Term.getTerm(vars_to_Vars, this.term_)); + } + } + + // whether, according to prevailing policy and theis Variable's name, + // any binding should be returned + // (yes, unless it's anonymous or we're in dont-tell-me mode and its a dont-tell-me variable) + private final boolean tellThem() { + return !(this.name.equals("_") || jpl.JPL.modeDontTellMe && this.name.charAt(0) == '_'); + // return !this.name.equals("_"); + } +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/Version.java b/LGPL/JPL/java/jpl/Version.java new file mode 100644 index 000000000..77cca3801 --- /dev/null +++ b/LGPL/JPL/java/jpl/Version.java @@ -0,0 +1,9 @@ +// $Id: Version.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +package jpl; +class Version +{ + public final int major = 3; + public final int minor = 0; + public final int patch = 3; + public final String status = "alpha"; +} diff --git a/LGPL/JPL/java/jpl/fli/BooleanHolder.java b/LGPL/JPL/java/jpl/fli/BooleanHolder.java new file mode 100644 index 000000000..c0f64d962 --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/BooleanHolder.java @@ -0,0 +1,60 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: BooleanHolder.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// BooleanHolder +/** + * A BooleanHolder is merely a Holder class for a boolean value. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class BooleanHolder +{ + public boolean value; +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/DoubleHolder.java b/LGPL/JPL/java/jpl/fli/DoubleHolder.java new file mode 100644 index 000000000..a1b59832a --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/DoubleHolder.java @@ -0,0 +1,60 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: DoubleHolder.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// DoubleHolder +/** + * A DoubleHolder is merely a Holder class for a double value. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class DoubleHolder +{ + public double value; +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/IntHolder.java b/LGPL/JPL/java/jpl/fli/IntHolder.java new file mode 100644 index 000000000..2d98d5dca --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/IntHolder.java @@ -0,0 +1,60 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: IntHolder.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// IntHolder +/** + * An IntHolder is merely a Holder class for an Int value. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class IntHolder +{ + public int value; +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/LongHolder.java b/LGPL/JPL/java/jpl/fli/LongHolder.java new file mode 100644 index 000000000..40c54c1c9 --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/LongHolder.java @@ -0,0 +1,61 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: LongHolder.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + +//----------------------------------------------------------------------/ +// LongHolder +/** + * A Long Holder merely holds a long value. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class LongHolder { + public long value = 0L; + + public boolean equals(LongHolder lh) { + return lh.value == this.value; + } +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/ObjectHolder.java b/LGPL/JPL/java/jpl/fli/ObjectHolder.java new file mode 100644 index 000000000..e2617d2ec --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/ObjectHolder.java @@ -0,0 +1,60 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: ObjectHolder.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// ObjectHolder +/** + * A ObjectHolder is merely a Holder class for an Object reference (or null). + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class ObjectHolder +{ + public Object value; +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/PointerHolder.java b/LGPL/JPL/java/jpl/fli/PointerHolder.java new file mode 100644 index 000000000..df3002915 --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/PointerHolder.java @@ -0,0 +1,63 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: PointerHolder.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// PointerHolder +/** + * A PointerHolder is a trivial extension of a LongHolder. This is sort of + * a no-no in Java, as the long value stored herein is sometimes a + * machine address. (Don't tell Sun.) + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// There could be issues in the future with signedness, since Java +// does not have an unsigned type; make sure not to do any arithmetic +// with the stored value. +//----------------------------------------------------------------------/ +public class PointerHolder extends LongHolder +{ +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/Prolog.java b/LGPL/JPL/java/jpl/fli/Prolog.java new file mode 100644 index 000000000..33be75c2f --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/Prolog.java @@ -0,0 +1,240 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: Prolog.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + +//----------------------------------------------------------------------/ +// Prolog +/** + * This class consists only of constants (static finals) and static + * native methods. The constants and methods defined herein are in + * (almost) strict 1-1 correspondence with the functions in the Prolog + * FLI by the same name (except without the PL_, SQ_, etc. prefixes).

    + * + * See the file jpl_fli_Prolog.c for the native implementations of these + * methods. Refer to your local Prolog FLI documentations for the meanings + * of these methods, and observe the following:

    + * + *

    + *
  • The types and signatures of the following methods are almost + * in 1-1 correspondence with the Prolog FLI. The Prolog types + * term_t, atom_t, functor_t, etc. are mirrored in this package with + * classes by the same name, making the C and Java uses of these + * interfaces similar.
  • + *
  • As term_t, functor_t, etc. types are Java classes, they are + * passed to these methods by value; however, calling these + * methods on such class instances does have side effects. In general, + * the value fields of these instances will be modified, in much the + * same way the term_t, functor_t, etc. Prolog instances would be + * modified.
  • + *
  • The exceptions to this rule occur when maintaining the same + * signature would be impossible, e.g., when the Prolog FLI functions + * require pointers; in this case, the signatures have been + * modified to take *Holder classes (Int, Double, String, etc.), + * to indicate a call by reference parameter. + *
  • Functions which take variable-length argument lists in C + * take arrays in Java; from Java 1.1 onwards, anonymous arrays + * can be used e.g. Term[] { new Atom("a"), new Atom ("b") } + *
  • + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +public final class Prolog { + static { + System.loadLibrary("jpl"); + } + + /* term types */ + public static final int VARIABLE = 1; + public static final int ATOM = 2; + public static final int INTEGER = 3; + public static final int FLOAT = 4; + public static final int STRING = 5; + public static final int COMPOUND = 6; + + public static final int JBOOLEAN = 101; + public static final int JREF = 102; + public static final int JVOID = 103; + + /** + * @deprecated use Prolog.COMPOUND + */ + public static final int TERM = 6; + + public static final int succeed = 1; + public static final int fail = 0; + + /* query flags */ + public static final int Q_NORMAL = 0x02; + public static final int Q_NODEBUG = 0x04; + public static final int Q_CATCH_EXCEPTION = 0x08; + public static final int Q_PASS_EXCEPTION = 0x10; + + /* conversion flags */ + public static final int CVT_ATOM = 0x0001; + public static final int CVT_STRING = 0x0002; + public static final int CVT_LIST = 0x0004; + public static final int CVT_INTEGER = 0x0008; + public static final int CVT_FLOAT = 0x0010; + public static final int CVT_VARIABLE = 0x0020; + public static final int CVT_NUMBER = (CVT_INTEGER | CVT_FLOAT); + public static final int CVT_ATOMIC = (CVT_NUMBER | CVT_ATOM | CVT_STRING); + public static final int CVT_ALL = 0x00ff; + public static final int BUF_DISCARDABLE = 0x0000; + public static final int BUF_RING = 0x0100; + public static final int BUF_MALLOC = 0x0200; + + /* new, for revised term_t-to-Variable stuff */ + public static native int compare(term_t t1, term_t t2); // returns -1, 0 or 1 + + /* Creating and destroying term-refs */ + public static native term_t new_term_ref(); + public static native term_t new_term_refs(int n); + public static native term_t copy_term_ref(term_t from); + public static native void reset_term_refs(term_t r); + + /* Constants */ + public static native atom_t new_atom(String s); + public static native String atom_chars(atom_t a); + public static native functor_t new_functor(atom_t f, int a); + public static native atom_t functor_name(functor_t f); + public static native int functor_arity(functor_t f); + + public static native void unregister_atom(atom_t a); // called from atom_t's finalize() + + /* Get Java-values from Prolog terms */ + public static native boolean get_atom(term_t t, atom_t a); + public static native boolean get_atom_chars(term_t t, StringHolder a); + public static native boolean get_string_chars(term_t t, StringHolder s); + public static native boolean get_integer(term_t t, IntHolder i); + public static native boolean get_pointer(term_t t, PointerHolder ptr); + public static native boolean get_float(term_t t, DoubleHolder d); + public static native boolean get_functor(term_t t, functor_t f); + public static native boolean get_name_arity(term_t t, StringHolder name, IntHolder arity); + public static native boolean get_module(term_t t, module_t module); + public static native boolean get_arg(int index, term_t t, term_t a); + + public static native boolean get_jref(term_t t, ObjectHolder obj); + public static native boolean get_jboolean(term_t t, BooleanHolder b); + + /* Verify types */ + public static native int term_type(term_t t); + public static native boolean is_variable(term_t t); + public static native boolean is_atom(term_t t); + public static native boolean is_integer(term_t t); + public static native boolean is_float(term_t t); + public static native boolean is_compound(term_t t); + public static native boolean is_functor(term_t t, functor_t f); + public static native boolean is_atomic(term_t t); + public static native boolean is_number(term_t t); + + /* Assign to term-references */ + public static native void put_variable(term_t t); + public static native void put_atom(term_t t, atom_t a); + public static native void put_integer(term_t t, long i); + public static native void put_pointer(term_t t, PointerHolder ptr); + public static native void put_float(term_t t, double f); + public static native void put_functor(term_t t, functor_t functor); + public static native void put_term(term_t t1, term_t t2); + public static native void put_jref(term_t t, Object ref); + public static native void put_jboolean(term_t t, boolean b); + public static native void put_jvoid(term_t t); + + /* ... */ + public static native void cons_functor_v(term_t h, functor_t fd, term_t a0); + public static native void cons_list(term_t l, term_t h, term_t t); + + // unification: + // public static native int unify(term_t t1, term_t t2); + + // predicates: + public static native predicate_t pred(functor_t f, module_t m); + public static native predicate_t predicate(String name, int arity, String module); + public static native int predicate_info(predicate_t pred, atom_t name, IntHolder arity, module_t module); + + // querying (general): + public static native qid_t open_query(module_t m, int flags, predicate_t pred, term_t t0); + public static native boolean next_solution(qid_t qid); + public static native void close_query(qid_t qid); + public static native void cut_query(qid_t qid); + + // querying (simplified): + public static native boolean call(term_t t, module_t m); + public static native boolean call_predicate(module_t m, int debug, predicate_t pred, term_t t0); + + // foreign frames: + public static native fid_t open_foreign_frame(); + public static native void close_foreign_frame(fid_t cid); + public static native void discard_foreign_frame(fid_t cid); + + // modules: + public static native module_t context(); + public static native atom_t module_name(module_t module); + public static native module_t new_module(atom_t name); + public static native int strip_module(term_t in, module_t m, term_t out); + + // not yet mapped: raise_exception() + // not yet mapped: throw() + + // exceptions: + public static native term_t exception(qid_t qid); + + // initialisation: + public static native String[] get_default_init_args(); + public static native boolean set_default_init_args(String argv[]); + public static native boolean initialise(); + public static native String[] get_actual_init_args(); + public static native void halt(int status); + + // thread & engine management: + public static native int thread_self(); + public static native engine_t attach_pool_engine(); + public static native int release_pool_engine(); + public static native engine_t current_engine(); + public static native boolean current_engine_is_pool(); + public static native String get_c_lib_version(); + + public static native int action_abort(); + public static native int attach_engine(engine_t e); + public static native int pool_engine_id(engine_t e); + +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/StringHolder.java b/LGPL/JPL/java/jpl/fli/StringHolder.java new file mode 100644 index 000000000..ac5fcd292 --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/StringHolder.java @@ -0,0 +1,60 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: StringHolder.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// StringHolder +/** + * A StringHolder is merely a Holder class for a String value. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class StringHolder +{ + public String value; +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/atom_t.java b/LGPL/JPL/java/jpl/fli/atom_t.java new file mode 100644 index 000000000..1ee007ae3 --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/atom_t.java @@ -0,0 +1,82 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: atom_t.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// atom_t +/** + * An atom_t is a specialised LongHolder which decrements its atom's + * reference count when garbage-collected (finalized). + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class atom_t +extends LongHolder +{ + //------------------------------------------------------------------/ + // toString + /** + * The String representation of an atom_t is just the atom's name. + * + * @return atom's name + */ + // Implementation notes: + // + //------------------------------------------------------------------/ + public String + toString() + { + return Prolog.atom_chars( this ); + } + + protected void finalize() throws Throwable { + + super.finalize(); + Prolog.unregister_atom( this); + } +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/engine_t.java b/LGPL/JPL/java/jpl/fli/engine_t.java new file mode 100644 index 000000000..0063cd786 --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/engine_t.java @@ -0,0 +1,56 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: engine_t.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + +//----------------------------------------------------------------------/ +// engine_t +/** + * A engine_t holds a reference to a Prolog engine. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: Note that a engine_t is not a term, +// consistent with the treatment in the Prolog FLI. +//----------------------------------------------------------------------/ +public class engine_t extends LongHolder { +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/fid_t.java b/LGPL/JPL/java/jpl/fli/fid_t.java new file mode 100644 index 000000000..f16cc301c --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/fid_t.java @@ -0,0 +1,60 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: fid_t.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// fid_t +/** + * An fid_t holds the value of a frame id in the Prolog Engine. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class fid_t +extends LongHolder +{ +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/functor_t.java b/LGPL/JPL/java/jpl/fli/functor_t.java new file mode 100644 index 000000000..b112ba0b0 --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/functor_t.java @@ -0,0 +1,61 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: functor_t.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// functor_t +/** + * A functor_t holds a reference to a Prolog functor_t in the + * Prolog engine. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: Note that a functor_t is not a term, +// consistent with the treatment in the Prolog FLI. +//----------------------------------------------------------------------/ +public class functor_t +extends LongHolder +{ +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/module_t.java b/LGPL/JPL/java/jpl/fli/module_t.java new file mode 100644 index 000000000..08f7fc61b --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/module_t.java @@ -0,0 +1,61 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: module_t.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// module_t +/** + * A module_t is a PointerHolder type which holds a reference to a Prolog + * module_t reference. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class module_t +extends PointerHolder +{ +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/predicate_t.java b/LGPL/JPL/java/jpl/fli/predicate_t.java new file mode 100644 index 000000000..18d99edd2 --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/predicate_t.java @@ -0,0 +1,61 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: predicate_t.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// predicate_t +/** + * A predicate_t is a PointerHolder class whose value is a reference to a + * Prolog predicate_t. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class predicate_t +extends PointerHolder +{ +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/qid_t.java b/LGPL/JPL/java/jpl/fli/qid_t.java new file mode 100644 index 000000000..1005b8eab --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/qid_t.java @@ -0,0 +1,60 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: qid_t.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// qid_t +/** + * A qid_t holds a reference to a Prolog qid_t. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class qid_t +extends LongHolder +{ +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/java/jpl/fli/term_t.java b/LGPL/JPL/java/jpl/fli/term_t.java new file mode 100644 index 000000000..070559475 --- /dev/null +++ b/LGPL/JPL/java/jpl/fli/term_t.java @@ -0,0 +1,133 @@ +//tabstop=4 +//*****************************************************************************/ +// Project: jpl +// +// File: $Id: term_t.java,v 1.1 2004-08-27 20:27:56 vsc Exp $ +// Date: $Date: 2004-08-27 20:27:56 $ +// Author: Fred Dushin +// +// +// Description: +// +// +// ------------------------------------------------------------------------- +// Copyright (c) 1998 Fred Dushin +// All rights reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library Public License for more details. +//*****************************************************************************/ +package jpl.fli; + + + +//----------------------------------------------------------------------/ +// term_t +/** + * A term_t is a simple class which mirrors the term_t type in + * the Prolog FLI. All it really does is hold a term reference, + * which is an internal representation of a term in the Prolog + * Engine. + * + *
    + * Copyright (C) 1998 Fred Dushin

    + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.

    + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details.

    + *


    + * @author Fred Dushin + * @version $Revision: 1.1 $ + */ +// Implementation notes: +// +//----------------------------------------------------------------------/ +public class term_t +extends LongHolder +{ + public static final long UNASSIGNED = -1L; + + public + term_t() + { + value = UNASSIGNED; + } + + //------------------------------------------------------------------/ + // toString + /** + * This static method converts a term_t, which is assumed to contain + * a reference to a *consecutive* list of term_t references to a + * String representation of a list of terms, in this case, a comma + * separated list. + * + * @param n the number of consecutive term_ts + * @param term0 a term_t whose value is the 0th term_t. + */ + // Implementation notes: + // + //------------------------------------------------------------------/ + public static String + toString( int n, term_t term0 ) + { + String s = ""; + int i; + long ith_term_t; + + for ( i = 0, ith_term_t = term0.value; i < n; ++i, ++ith_term_t ){ + term_t term = new term_t(); + term.value = ith_term_t; + s += term.toString(); + + if ( i != n - 1 ){ + s += ", "; + } + } + + return s; + } + + + //------------------------------------------------------------------/ + // equals + /** + * Instances of term_ts are stored in Term objects (see jpl.Term), + * and these term_ts are in some cases stored in Hashtables. + * Supplying this predicate provides the right behavior in Hashtable + * lookup (see the rules for Hashtable lookup in java.util).

    + * + * Note. Two term_ts are *not* equal if their values have not + * been assigned. (Since Prolog FLI term_ts are unsigned values and + * the UNASSIGNED value is -1, this should work). + * + * @param obj the Object to comapre. + * @return true if the supplied object is a term_t instances + * and the long values are the same + */ + // Implementation notes: + // + //------------------------------------------------------------------/ + public boolean + equals( Object obj ) + { + return + (obj instanceof term_t) && + this.value == ((term_t)obj).value && + this.value != UNASSIGNED; + } +} + +//345678901234567890123456789012346578901234567890123456789012345678901234567890 diff --git a/LGPL/JPL/jpl.yap b/LGPL/JPL/jpl.yap new file mode 100644 index 000000000..15e4d0ccd --- /dev/null +++ b/LGPL/JPL/jpl.yap @@ -0,0 +1,4255 @@ +/* $Id: jpl.yap,v 1.1 2004-08-27 20:27:56 vsc Exp $ + + Part of JPL -- SWI-Prolog/Java interface + + Author: Paul Singleton, Fred Dushin and Jan Wielemaker + E-mail: paul@jbgb.com + WWW: http://www.swi-prolog.org + Copyright (C): 1985-2004, Paul Singleton + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + As a special exception, if you link this library with other files, + compiled with a Free Software compiler, to produce an executable, this + library does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however + invalidate any other reasons why the executable file might be covered by + the GNU General Public License. +*/ + +:- module(jpl, + [ jpl_pl_lib_version/1, + jpl_c_lib_version/1, + jpl_new/3, + jpl_call/4, + jpl_get/3, + jpl_set/3, + jpl_servlet_byref/3, + jpl_servlet_byval/3, + jpl_class_to_classname/2, + jpl_class_to_type/2, + jpl_classname_to_class/2, + jpl_classname_to_type/2, + jpl_datum_to_type/2, + jpl_false/1, + jpl_is_class/1, + jpl_is_false/1, + jpl_is_null/1, + jpl_is_object/1, + jpl_is_object_type/1, + jpl_is_ref/1, + jpl_is_true/1, + jpl_is_type/1, + jpl_is_void/1, + jpl_null/1, + jpl_object_to_class/2, + jpl_object_to_type/2, + jpl_primitive_type/1, + jpl_ref_to_type/2, + jpl_true/1, + jpl_type_to_class/2, + jpl_type_to_classname/2, + jpl_void/1, + jpl_array_to_length/2, + jpl_array_to_list/2, + jpl_datums_to_array/2, + jpl_enumeration_element/2, + jpl_enumeration_to_list/2, + jpl_hashtable_pair/2, + jpl_iterator_element/2, + jpl_list_to_array/2, + jpl_map_element/2, + jpl_set_element/2 + ]). + +:- use_module(library(lists)). + +:- use_module(library(swi)). + +% suppress debugging this library +:- set_prolog_flag(generate_debug_info, false). + +:- load_foreign_files([jpl], ['/opt/j2sdk1.4.2_04/jre/lib/i386/client/libjvm.so'], jpl_install). +%:- load_foreign_files([jpl], [], jpl_install). + +%------------------------------------------------------------------------------ + +% term_to_chars(+Term, ?Chars) +% unifies Chars with a printed representation of Term. It is not at all +% clear what representation should be used. On the grounds that it is +% supposed to be re-readable, I have chosen to use write_canonical. +% Giving Chars to chars_to_term/2 will yield a *copy* of Term. + +term_to_chars(Term, Chars) :- + % start_output_to_handle(Handle, Stream), + % write_canonical(Stream, Term), + % close(Stream), + % byte_stream_to_chars(Handle, Chars0), + % free_byte_stream(Handle), + % Chars = Chars0. + ( atom(Term) + -> Term = A % avoid superfluous quotes + ; system:term_to_atom(Term, A) % port + ), + atom_codes(A, Chars). + +%------------------------------------------------------------------------------ + +% jpl_call(+X, +Mspec, +Args, -R) :- +% X can be: +% a type, class object or classname +% (for static methods of the denoted class, +% or for static or instance methods of java.lang.Class) +% a class instance or array +% (for static or instance methods) +% +% Mspec can be: +% an atomic method name +% (may involve dynamic overload resolution) +% an integral method index +% (untested: for static overload resolution) +% a methodID/1 structure +% (ditto) +% +% Args must be a proper list (poss empty) of ground arguments; +% +% finally, an attempt will be made to unify R with the returned result + +jpl_call(X, Mspec, Args, R) :- + ( ground(X) + -> ( jpl_is_object(X) % ie class(_,_) or array(_) instance + -> Obj = X, + jpl_object_to_type(Obj, Type) + ; (X=class(_,_) ; X=array(_) ) % ie an object type + -> jpl_type_to_class(X, Obj), + Type = class([java,lang],['Class']) + ; jpl_classname_to_type(X, Tx) % eg 'java.lang.String' or '[L' + -> jpl_type_to_class(Tx, Obj), + Type = class([java,lang],['Class']) + ; throw(error(type_error(jpl_receiver, X), + context(jpl_call/4, + 'must be type, class object or class name'))) + ) + ; var(X) + -> throw(error(instantiation_error, + context(jpl_call/4, _))) + ; throw(error(type_error(jpl_receiver, X), + context(jpl_call/4, + 'must be type, class object or class name'))) + ), + ground(Args), % check in jpl_call_1/5 instead? + jpl_call_1(Type, Obj, Mspec, Args, Rx), + + R = Rx. + +%------------------------------------------------------------------------------ + +% jpl_call_1(+Type, +Object, +MethodSpec, +Argz, -Result) :- +% serves only jpl_call/4 +% Object may be a class object, in which case Type is class([java,lang],['Class']) +% Argz (certain to be ground) can be: +% a proper list of arguments Args +% (their qty and types help resolve the method) +% a single argument Arg +% (defaulty corrected to Args = [Arg]) +% +% at call, Result is unbound +% at exit, Result is bound to the returned result datum (or @void) + +jpl_call_1(Tx, X, Mspec, Argz, Rx) :- % a static method call? + Tx = class([java,lang],['Class']), % a class object... + jpl_class_to_type(X, Tx2), + Tx2 \== class([java,lang],['Class']), % ...other than java.lang.Class + !, + ( integer(Mspec) % i.e. a method index + -> I = Mspec + ; atom(Mspec) % i.e. a method name + -> N = Mspec + ; jpl_is_methodID(Mspec) % i.e. a method ID + -> MID = Mspec + ), + ( is_list(Argz) + -> Args = Argz, + length(Args, A) + ; Args = [Argz], % ugh: defaulty (?) single arg + A = 1 + ), + % consider all methods of java.lang.Class + % and static methods of the denoted class + findall( + z8(T,I,N,A,Mods,MID,Tr,Tps), + ( T = Tx, + jpl_method_spec(T, I, N, A, Mods, MID, Tr, Tps) + ; T = Tx2, + jpl_method_spec(T, I, N, A, Mods, MID, Tr, Tps), + member(static, Mods) + ), + Z8s + ), + ( Z8s = [] + -> write('Warning: no arity-matching methods'), nl, fail + ; Z8s = [z8(T,I,N,A,Mods,MID,Tr,Tps)] + -> true % exactly one method + ; jpl_datums_to_types(Args, Tas), % most specific types + findall( + z5(I,Mods,MID,Tr,Tps), + ( member(z8(T,I,N,A,Mods,MID,Tr,Tps), Z8s), + jpl_types_fit_types(Tas, Tps) % assignability test + ), + Z5sA % Args-assignable methods + ), + ( Z5sA == [] + -> write('Warning: no type-assignable methods'), nl, fail + ; Z5sA = [z5(I,Mods,MID,Tr,Tps)] + -> true % exactly one applicable method + ; jpl_z5s_to_most_specific_z5(Z5sA, z5(I,Mods,MID,Tr,Tps)) + -> true % exactly one most-specific applicable method + ; write('Error: no single most-specific method'), nl, fail + ) + ), + ( T = Tx + -> jpl_type_to_class(Tx, Cc), + ( member(static, Mods) + -> jpl_call_static(Tr, Cc, MID, Tps, Args, Rx) + ; jpl_call_instance(Tr, Cc, MID, Tps, Args, Rx) + ) + ; T = Tx2 + -> jpl_call_static(Tr, X, MID, Tps, Args, Rx) + ). + +jpl_call_1(Tx, X, Mspec, Argz, Rx) :- % regular instance object, + ( Tx = class(_,_) + ; Tx = array(_) + ), + !, % or instance of java.lang.Class + ( integer(Mspec) % i.e. a method index + -> I = Mspec + ; atom(Mspec) % i.e. a method name + -> N = Mspec + ; jpl_is_methodID(Mspec) % i.e. a method ID + -> MID = Mspec + ), + ( is_list(Argz) + -> Args = Argz, + length(Args, A) + ; Args = [Argz], + A = 1 + ), + % Tx = class(Ps,Cs), + findall( + z5(I,Mods,MID,Tr,Tps), + jpl_method_spec(Tx, I, N, A, Mods, MID, Tr, Tps), + Z5s + ), + ( Z5s = [] + -> write('Warning: no arity-matching methods'), nl, fail + ; Z5s = [z5(I,Mods,MID,Tr,Tps)] + -> true % exactly one static method + ; jpl_datums_to_types(Args, Tas), % most specific types + findall( + z5(I,Mods,MID,Tr,Tps), % those to which Args is assignable + ( member(z5(I,Mods,MID,Tr,Tps), Z5s), + jpl_types_fit_types(Tas, Tps) % assignability test + ), + Z5sA % Args-assignable methods + ), + ( Z5sA == [] + -> write('Warning: no type-assignable methods'), nl, fail + ; Z5sA = [z5(I,Mods,MID,Tr,Tps)] + -> true % exactly one applicable method + ; jpl_z5s_to_most_specific_z5(Z5sA, z5(I,Mods,MID,Tr,Tps)) + -> true % exactly one most-specific applicable method + ; write('Error: no single most-specific method'), nl, fail + ) + ), + ( member(static, Mods) + -> jpl_object_to_class(X, Cx), + jpl_call_static(Tr, Cx, MID, Tps, Args, Rx) + ; jpl_call_instance(Tr, X, MID, Tps, Args, Rx) + ). + +%------------------------------------------------------------------------------ + +jpl_call_instance(void, Class, MID, Ts, As, R) :- + jCallVoidMethod(Class, MID, Ts, As), + R = @(void). + +jpl_call_instance(boolean, Class, MID, Ts, As, R) :- + jCallBooleanMethod(Class, MID, Ts, As, R). + +jpl_call_instance(byte, Class, MID, Ts, As, R) :- + jCallByteMethod(Class, MID, Ts, As, R). + +jpl_call_instance(char, Class, MID, Ts, As, R) :- + jCallCharMethod(Class, MID, Ts, As, R). + +jpl_call_instance(short, Class, MID, Ts, As, R) :- + jCallShortMethod(Class, MID, Ts, As, R). + +jpl_call_instance(int, Class, MID, Ts, As, R) :- + jCallIntMethod(Class, MID, Ts, As, R). + +jpl_call_instance(long, Class, MID, Ts, As, R) :- + jCallLongMethod(Class, MID, Ts, As, R). + +jpl_call_instance(float, Class, MID, Ts, As, R) :- + jCallFloatMethod(Class, MID, Ts, As, R). + +jpl_call_instance(double, Class, MID, Ts, As, R) :- + jCallDoubleMethod(Class, MID, Ts, As, R). + +jpl_call_instance(array(_), Class, MID, Ts, As, R) :- + jCallObjectMethod(Class, MID, Ts, As, R). + +jpl_call_instance(class(_,_), Class, MID, Ts, As, R) :- + jCallObjectMethod(Class, MID, Ts, As, R). + +%------------------------------------------------------------------------------ + +jpl_call_static(void, Class, MID, Ts, As, R) :- + jCallStaticVoidMethod(Class, MID, Ts, As), + R = @(void). + +jpl_call_static(boolean, Class, MID, Ts, As, R) :- + jCallStaticBooleanMethod(Class, MID, Ts, As, R). + +jpl_call_static(byte, Class, MID, Ts, As, R) :- + jCallStaticByteMethod(Class, MID, Ts, As, R). + +jpl_call_static(char, Class, MID, Ts, As, R) :- + jCallStaticCharMethod(Class, MID, Ts, As, R). + +jpl_call_static(short, Class, MID, Ts, As, R) :- + jCallStaticShortMethod(Class, MID, Ts, As, R). + +jpl_call_static(int, Class, MID, Ts, As, R) :- + jCallStaticIntMethod(Class, MID, Ts, As, R). + +jpl_call_static(long, Class, MID, Ts, As, R) :- + jCallStaticLongMethod(Class, MID, Ts, As, R). + +jpl_call_static(float, Class, MID, Ts, As, R) :- + jCallStaticFloatMethod(Class, MID, Ts, As, R). + +jpl_call_static(double, Class, MID, Ts, As, R) :- + jCallStaticDoubleMethod(Class, MID, Ts, As, R). + +jpl_call_static(array(_), Class, MID, Ts, As, R) :- + jCallStaticObjectMethod(Class, MID, Ts, As, R). + +jpl_call_static(class(_,_), Class, MID, Ts, As, R) :- + jCallStaticObjectMethod(Class, MID, Ts, As, R). + +%------------------------------------------------------------------------------ + +%type jpl_fergus_find_candidate(list(T), T, T, list(T)) + +jpl_fergus_find_candidate([], Candidate, Candidate, []). + +jpl_fergus_find_candidate([X|Xs], Candidate0, Candidate, Rest) :- + ( jpl_fergus_greater(X, Candidate0) + -> Candidate1 = X, + Rest = [Candidate0|Rest1] + ; Candidate1 = Candidate0, + Rest = [X|Rest1] + ), + jpl_fergus_find_candidate(Xs, Candidate1, Candidate, Rest1). + +%------------------------------------------------------------------------------ + +jpl_fergus_greater(z5(_,_,_,_,Tps1), z5(_,_,_,_,Tps2)) :- + jpl_types_fit_types(Tps1, Tps2). +jpl_fergus_greater(z3(_,_,Tps1), z3(_,_,Tps2)) :- + jpl_types_fit_types(Tps1, Tps2). + +%------------------------------------------------------------------------------ + +%type jpl_fergus_is_the_greatest(list(T), T) + +% jpl_fergus_is_the_greatest(Xs, GreatestX) :- +% Xs is a list of things for which jpl_fergus_greater/2 defines a partial ordering; +% GreatestX is one of those, than which none is greater; +% fails if there is more than one such; +% this algorithm was contributed to c.l.p by Fergus Henderson in response to my +% "there must be a better way" challenge: there was, this is it + +jpl_fergus_is_the_greatest([X|Xs], Greatest) :- + jpl_fergus_find_candidate(Xs, X, Greatest, Rest), + forall(member(R, Rest), + jpl_fergus_greater(Greatest, R)). + +%------------------------------------------------------------------------------ + +% jpl_get(+X, +Fspec, -V) :- +% X can be: +% a class object, a classname, or an (object or array) type +% (for static fields, or java.lang.Class fields); +% a class instance +% (for non-static fields) +% an array +% (for 'length' pseudo field, or indexed element retrieval), +% but not: +% a String +% (clashes with class name; anyway, String has no fields to retrieve) +% +% Fspec can be an atomic field name, +% or an integral field index, +% or a fieldID/1 +% or a variable (field names, or array indices, are generated +% or a pair I-J of integers or variables (array subranges are generated) +% +% finally, an attempt will be made to unify V with the retrieved value + +jpl_get(X, Fspec, V) :- + ( jpl_is_object(X) % i.e. instance of class(_,_) or array(_) type + -> jpl_object_to_type(X, Type), + Obj = X + ; jpl_is_type(X) % e.g. class([java,lang],['String']), array(int) + -> jpl_type_to_class(X, Obj), + Type = class([java,lang],['Class']) + ; atom(X) % e.g. 'java.lang.String', '[L' + -> jpl_classname_to_type(X, Tx), + jpl_type_to_class(Tx, Obj), + Type = class([java,lang],['Class']) + ), + jpl_get_1(Type, Obj, Fspec, Vx), + V = Vx. + +%------------------------------------------------------------------------------ + +% jpl_get_1(+Type, +Object, +FieldSpec, -ResultValue) :- +% Object may be a class object, in which case Type is class([java,lang],['Class']) +% ResultValue (Vx below) is guaranteed unbound on entry, +% and will, before exit, be unified with the retrieved value + +jpl_get_1(Tx, X, Fspec, Vx) :- % static field? + Tx = class([java,lang],['Class']), % a class object... + jpl_class_to_type(X, Tx2), + Tx2 \== Tx, % ...other than java.lang.Class itself + !, + ( integer(Fspec) % assume it's a field or array index + -> I = Fspec + ; atom(Fspec) % assume it's a field name + -> N = Fspec + ; jpl_is_fieldID(Fspec) % assume it's a JNI field ID + -> FID = Fspec + ; var(Fspec) % experimentally... + -> N = Fspec % we'll generate field names + ), + % consider static and instance fields of java.lang.Class + % and static fields of the denoted class + findall( + z2(T,I,N,Mods,FID,Tf), + ( T = Tx, + jpl_field_spec(T, I, N, Mods, FID, Tf) + ; T = Tx2, + jpl_field_spec(T, I, N, Mods, FID, Tf), + member(static, Mods) + ), + Z2s + ), + ( Z2s = [], + nonvar(Fspec) + -> write('Warning: no matching fields'), nl, fail + ; member(z2(T,I,N,Mods,FID,Tf), Z2s), % generate one or many + ( T = Tx + -> jpl_type_to_class(Tx, Cc), + ( member(static, Mods) + -> jpl_get_static_field(Tf, Cc, FID, Vx) + ; jpl_get_field(Tf, Cc, FID, Vx) + ) + ; T = Tx2 + -> jpl_get_static_field(Tf, X, FID, Vx) + ) + ). + +jpl_get_1(Tx, X, Fspec, Vx) :- + Tx = class(_,_), + !, + ( integer(Fspec) % assume it's a field or array index + -> I = Fspec + ; atom(Fspec) % assume it's a field name + -> N = Fspec + ; jpl_is_fieldID(Fspec) % assume it's a JNI field ID (???) + -> FID = Fspec + ; var(Fspec) + -> N = Fspec % we'll generate field names + ), + % instance object, or the java.lang.Class object itself + findall(z(I,N,Mods,FID,Tf), + jpl_field_spec(Tx, I, N, Mods, FID, Tf), + Zs + ), + ( Zs = [] + -> write('Warning: no matching fields'), nl, fail + ; member(z(I,N,Mods,FID,Tf), Zs), % generate one or many + ( member(static, Mods) + -> jpl_object_to_class(X, Cx), + jpl_get_static_field(Tf, Cx, FID, Vx) + ; jpl_get_field(Tf, X, FID, Vx) + ) + ). + +jpl_get_1(array(T), X, Fspec, Vx) :- + ( integer(Fspec), + Fspec >= 0 % leave HiBound check to Java... + -> jpl_get_array_element(T, X, Fspec, Vx) + ; Fspec == length % special-case this solitary array "method" + -> jGetArrayLength(X, Len), + Vx = Len + ; var(Fspec) + -> jGetArrayLength(X, Len), % generate length field and elements + Max is Len-1, + ( Fspec = length, + Vx = Len + ; between(0, Max, Fspec), + jpl_get_array_element(T, X, Fspec, Vx) + ) + ; Fspec = N-M, + (integer(N) ; var(N) ), + (integer(M) ; var(M) ) + -> jGetArrayLength(X, Len), + Max is Len-1, + between(0, Max, N), + % Mmin is N-1, % generates many empty sublists + Mmin is N, % generates no empty sublists + % you want _one_ empty sublist? which one? ... + between(Mmin, Max, M), + jpl_get_array_elements(T, X, N, M, Vx) + ). + +%------------------------------------------------------------------------------ + +% jpl_get_array_element(+JspType, +Obj, +N, -Vc) :- +% Obj is an array of JspType; +% Vc is (unified with a JPL repn of) its Nth element (numbered from 0) +% NB the nonsense with Xhi and Xlo should be expunged: +% values should be converted to terms within foreign code + +jpl_get_array_element(T, Obj, N, Vc) :- + ( ( T = class(_,_) + ; T = array(_) + ) + -> jGetObjectArrayElement(Obj, N, Vr) + ; jpl_primitive_type(T) + -> jni_type_to_xput_code(T, Xc), + jni_alloc_buffer(Xc, 1, Bp), % one-element buf for a T + jpl_get_primitive_array_region(T, Obj, N, 1, Bp), + jni_fetch_buffer_value(Bp, 0, Xhi, Xlo, Xc), % zero-th element + jni_convert_primitive_in(T, Vr, Xhi, Xlo), + jni_free_buffer(Bp) + ), + Vr = Vc. + +%------------------------------------------------------------------------------ + +% jpl_get_array_elements(+Type, +Object, +N, +M, -Rs) :- +% serves only jpl_get_1 +% Rs will always be unbound on entry + +jpl_get_array_elements(T, Obj, N, M, Rs) :- + ( ( T = class(_,_) + ; T = array(_) + ) + -> jpl_get_object_array_elements(Obj, N, M, Rs) + ; jpl_get_primitive_array_elements(T, Obj, N, M, Rs) + ). + +%------------------------------------------------------------------------------ + +jpl_get_field(boolean, Obj, FieldID, R) :- + jGetBooleanField(Obj, FieldID, R). + +jpl_get_field(byte, Obj, FieldID, R) :- + jGetByteField(Obj, FieldID, R). + +jpl_get_field(char, Obj, FieldID, R) :- + jGetCharField(Obj, FieldID, R). + +jpl_get_field(short, Obj, FieldID, R) :- + jGetShortField(Obj, FieldID, R). + +jpl_get_field(int, Obj, FieldID, R) :- + jGetIntField(Obj, FieldID, R). + +jpl_get_field(long, Obj, FieldID, R) :- + jGetLongField(Obj, FieldID, R). + +jpl_get_field(float, Obj, FieldID, R) :- + jGetFloatField(Obj, FieldID, R). + +jpl_get_field(double, Obj, FieldID, R) :- + jGetDoubleField(Obj, FieldID, R). + +jpl_get_field(class(_,_), Obj, FieldID, R) :- + jGetObjectField(Obj, FieldID, R). + +jpl_get_field(array(_), Obj, FieldID, R) :- + jGetObjectField(Obj, FieldID, R). + +%------------------------------------------------------------------------------ + +% jpl_get_object_array_elements(+Type, +Object, +N, +M, -Vcs) :- +% Type is some object or array type; +% Object should be a (zero-based) array of element-type Type; +% N is an integer, 0 =< N < length(Object); +% M is an integer, N-1 =< M < length(Object); +% at call, Vcs will be unbound; +% at exit, Vcs will be a list of refs to the array's elements from index N to M inclusive + +jpl_get_object_array_elements(Obj, N, M, Vcs) :- + ( N =< M + -> Vcs = [Vc|Vcs2], + jGetObjectArrayElement(Obj, N, Vc), + Nx is N+1, + jpl_get_object_array_elements(Obj, Nx, M, Vcs2) + ; Vcs = [] + ). + +%------------------------------------------------------------------------------ + +% jpl_get_primitive_array_elements(+JspType, +Object, +N, +M, -Vcs) :- +% Object should be a (zero-based) Java array of (primitive) JspType; +% Vcs will be unbound on entry, +% and on exit will be a list of the elements from index N to M inclusive + +jpl_get_primitive_array_elements(T, Obj, N, M, Vcs) :- + Size is M-N+1, + ( Size == 0 + -> Vcs = [] + ; jni_type_to_xput_code(T, Xc), + jni_alloc_buffer(Xc, Size, Bp), + jpl_get_primitive_array_region(T, Obj, N, Size, Bp), + jpl_primitive_buffer_to_array(T, Xc, Bp, 0, Size, Vcs), + jni_free_buffer(Bp) + ). + +%------------------------------------------------------------------------------ + +jpl_get_primitive_array_region(boolean, Obj, N, S, I) :- + jGetBooleanArrayRegion(Obj, N, S, jbuf(I,boolean)). + +jpl_get_primitive_array_region(byte, Obj, N, S, I) :- + jGetByteArrayRegion(Obj, N, S, jbuf(I,byte)). + +jpl_get_primitive_array_region(char, Obj, N, S, I) :- + jGetCharArrayRegion(Obj, N, S, jbuf(I,char)). + +jpl_get_primitive_array_region(short, Obj, N, S, I) :- + jGetShortArrayRegion(Obj, N, S, jbuf(I,short)). + +jpl_get_primitive_array_region(int, Obj, N, S, I) :- + jGetIntArrayRegion(Obj, N, S, jbuf(I,int)). + +jpl_get_primitive_array_region(long, Obj, N, S, I) :- + jGetLongArrayRegion(Obj, N, S, jbuf(I,long)). + +jpl_get_primitive_array_region(float, Obj, N, S, I) :- + jGetFloatArrayRegion(Obj, N, S, jbuf(I,float)). + +jpl_get_primitive_array_region(double, Obj, N, S, I) :- + jGetDoubleArrayRegion(Obj, N, S, jbuf(I,double)). + +%------------------------------------------------------------------------------ + +jpl_get_static_field(boolean, Obj, FieldID, R) :- + jGetStaticBooleanField(Obj, FieldID, R). + +jpl_get_static_field(byte, Obj, FieldID, R) :- + jGetStaticByteField(Obj, FieldID, R). + +jpl_get_static_field(char, Obj, FieldID, R) :- + jGetStaticCharField(Obj, FieldID, R). + +jpl_get_static_field(short, Obj, FieldID, R) :- + jGetStaticShortField(Obj, FieldID, R). + +jpl_get_static_field(int, Obj, FieldID, R) :- + jGetStaticIntField(Obj, FieldID, R). + +jpl_get_static_field(long, Obj, FieldID, R) :- + jGetStaticLongField(Obj, FieldID, R). + +jpl_get_static_field(float, Obj, FieldID, R) :- + jGetStaticFloatField(Obj, FieldID, R). + +jpl_get_static_field(double, Obj, FieldID, R) :- + jGetStaticDoubleField(Obj, FieldID, R). + +jpl_get_static_field(class(_,_), Obj, FieldID, R) :- + jGetStaticObjectField(Obj, FieldID, R). + +jpl_get_static_field(array(_), Obj, FieldID, R) :- + jGetStaticObjectField(Obj, FieldID, R). + +%------------------------------------------------------------------------------ + +% jpl_new(+X, +Argz, -V) :- +% X can be: +% a suitable type +% i.e. any class(_,_), array(_) or primitive (i.e. not void) +% a class object +% i.e. whose type is class([java,lang],['Class']) +% an atomic classname +% e.g. 'java.lang.String' +% e.g. 'Ljava.lang.String;' +% an atomic descriptor +% e.g. '[I' +% +% if X denotes a primitive type and Argz is castable to a value of that type, +% then V is that value (a pointless mode of operation, but somehow complete...) +% +% if X denotes an array type and Argz is a non-negative integer, +% then V is a new array of that many elements, +% initialised to the appropriate default value; +% +% if X denotes an array type and Argz is a list of datums, +% each of which is (independently) castable to the array element type, +% then V is a new array of as many elements as Argz has members, +% initialised to the results of casting the respective members of Argz; +% +% if X denotes a non-array object type and Argz is a list of datums, +% then V is the result of an invocation of that type's most specifically-typed +% constructor to whose respective parameters the members of Argz are assignable + +jpl_new(X, Argz, V) :- + ground(Argz), + ( jpl_is_type(X) % NB only class(_,_) or array(_) + -> Tx = X + ; jpl_is_object(X), + jpl_object_to_type(X, class([java,lang],['Class'])) + -> jpl_class_to_type(X, Tx) % get the type this class denotes + ; atom(X) % eg 'java.lang.String', '[L' + -> jpl_classname_to_type(X, Tx) + ), + + % jpl_type_to_classname(Tx, Classname), writeq([jpl_new,Classname,Argz]), nl, + + jpl_new_1(Tx, Argz, Vx), + V = Vx. + +%------------------------------------------------------------------------------ + +% jpl_new_1(+Tx, +Argz, -Vx) :- +% (serves only jpl_new/3) +% +% Tx can be: +% a class(_,_) or array(_) type; +% +% Argz can be: +% a ground, proper list of constructor arguments +% a single argument +% (sloppy convenience, probably best ditched) +% +% at call, Vx is unbound; +% at exit, Vx is bound to a new, initialised ref (or a value) of type Tx + +jpl_new_1(class(Ps,Cs), Argz, Vx) :- + !, % green (see below) + jpl_type_to_class(class(Ps,Cs), Cx), % ensure class is findable + Tx = class(Ps,Cs), + ( is_list(Argz) % canonise sloppy Argz to Args + -> Args = Argz, + length(Args, A) + ; Args = [Argz], + A = 1 + ), + N = '', % JNI's constructor naming convention for GetMethodID() + Tr = void, % all constructors have this return "type" + findall( + z3(I,MID,Tps), + jpl_method_spec(Tx, I, N, A, _Mods, MID, Tr, Tps), % cached + Z3s + ), + ( Z3s == [] % no matches + -> write('Warning: no arity-matching constructors'), nl, fail + ; Z3s = [z3(I,MID,Tps)] % exactly one match + -> true + ; jpl_datums_to_types(Args, Tas), % most specific types + findall( + z3(I,MID,Tps), % select those to which Args is assignable + ( member(z3(I,MID,Tps), Z3s), + jpl_types_fit_types(Tas, Tps) + ), + Z3sA + ), + ( Z3sA == [] + -> write('Warning: no type-assignable constructors'), nl, fail + ; Z3sA = [z3(I,MID,Tps)] + -> true + ; jpl_z3s_to_most_specific_z3(Z3sA, z3(I,MID,Tps)) + -> true + ; write('Error: no single most-specific constructor'), nl, fail + ) + ), + jNewObject(Cx, MID, Tps, Args, Vx), + jpl_cache_type_of_ref(Tx, Vx). % since we know it + +jpl_new_1(array(T), Argz, Vx) :- + !, + ( integer(Argz), % integer I -> array[0..I-1] of default values + Argz >= 0 + -> Len is Argz + ; is_list(Argz) % [V1,..VN] -> array[0..N-1] of respective values + -> length(Argz, Len) + ), + jpl_new_array(T, Len, Vx), % NB may throw out-of-memory exception + ( nth0(I, Argz, Arg), % nmember fails silently when Argz is integer + jpl_set(Vx, I, Arg), + fail + ; true + ), + jpl_cache_type_of_ref(array(T), Vx). % since we know it + +jpl_new_1(T, Argz, Vx) :- % dubious completist generation of new primitive... + ( Argz == [] + -> jpl_primitive_type_default_value(T, Vx) + ; ( Argz = [Arg] + ; Argz = Arg % tolerate sloppiness... + ) + -> jpl_primitive_type_term_to_value(T, Argz, Vx) + ). + +%------------------------------------------------------------------------------ + +% jpl_new_array(+ElementType, +Length, -NewArray) :- + +jpl_new_array(boolean, Len, A) :- + jNewBooleanArray(Len, A). + +jpl_new_array(byte, Len, A) :- + jNewByteArray(Len, A). + +jpl_new_array(char, Len, A) :- + jNewCharArray(Len, A). + +jpl_new_array(short, Len, A) :- + jNewShortArray(Len, A). + +jpl_new_array(int, Len, A) :- + jNewIntArray(Len, A). + +jpl_new_array(long, Len, A) :- + jNewLongArray(Len, A). + +jpl_new_array(float, Len, A) :- + jNewFloatArray(Len, A). + +jpl_new_array(double, Len, A) :- + jNewDoubleArray(Len, A). + +jpl_new_array(array(T), Len, A) :- + jpl_type_to_class(array(T), C), + jNewObjectArray(Len, C, @(null), A). % initialise each element to null + +jpl_new_array(class(Ps,Cs), Len, A) :- + jpl_type_to_class(class(Ps,Cs), C), + jNewObjectArray(Len, C, @(null), A). + +%------------------------------------------------------------------------------ + +% jpl_set(+X, +Fspec, +V) :- +% basically, sets the Fspec-th field of object X to value V +% +% X can be: +% a class object, a classname, or an (object or array) type +% (for static fields, or java.lang.Class fields) +% a class instance +% (for non-static fields) +% an array +% (for indexed element or subrange assignment) +% but not: +% a String (no fields to retrieve) +% +% Fspec can be: +% an atomic field name +% (overloading will be resolved dynamically) +% an integral field index +% (static resolution: not tried yet) +% a fieldID/1 +% (static resolution: not tried yet) +% a variable +% (field names, or array indices, are generated) +% an array index I +% (X must be an array object: X[I] is assigned V) +% a pair I-J of integers (J can be a variable) +% (X must be an array object, V must be a list of values: X[I-J] will be assigned V) +% +% V must be ground (although one day we may pass variables to JPL?!) + +jpl_set(X, Fspec, V) :- + ground(V), % only defined for ground datums + ( jpl_is_object(X) % i.e. of class(_,_) or array(_) type + -> jpl_object_to_type(X, Type), + Obj = X + ; jpl_is_type(X) % e.g. class([java,lang],['String']), array(int) + -> jpl_type_to_class(X, Obj), + Type = class([java,lang],['Class']) + ; atom(X) % e.g. 'java.lang.String', '[L' + -> jpl_classname_to_type(X, Tx), + jpl_type_to_class(Tx, Obj), + Type = class([java,lang],['Class']) + ), + jpl_set_1(Type, Obj, Fspec, V). + +%------------------------------------------------------------------------------ + +% jpl_set_1(+Type, +Object, +FieldSpec, +Value) :- +% Object may be a class object, in which case Type is class([java,lang],['Class']) + +jpl_set_1(Tx, X, Fspec, V) :- % static field? + Tx = class([java,lang],['Class']), % a class object... + jpl_class_to_type(X, Tx2), + Tx2 \== Tx, % ...denoting other than java.lang.Class + !, + ( integer(Fspec) % assume it's a field index + -> I = Fspec + ; atom(Fspec) % assume it's a field name + -> N = Fspec + ; jpl_is_fieldID(Fspec) % assume it's a JNI field ID + -> FID = Fspec + ), + % consider static and instance fields of java.lang.Class + % and static fields of the denoted class + findall(z2(T,I,N,Mods,FID,Tf), + ( T = Tx, + jpl_field_spec(T, I, N, Mods, FID, Tf) + ; T = Tx2, + jpl_field_spec(T, I, N, Mods, FID, Tf), + member(static, Mods) + ), + Z2s + ), + ( Z2s = [] + -> write('Warning: no matching fields'), nl + ; Z2s = [z2(T,I,N,Mods,FID,Tf)] + -> ( T = Tx + -> jpl_type_to_class(Tx, Cc), + ( member(static, Mods) + -> jpl_set_static_field(Tf, Cc, FID, V) + ; jpl_set_field(Tf, Cc, FID, V) + ) + ; T = Tx2 + -> jpl_set_static_field(Tf, X, FID, V) + ) + ; write('Warning: many matching fields'), nl, fail + ). + +jpl_set_1(Tx, X, Fspec, V) :- % instance field? + Tx = class(_,_), % instance object, or the java.lang.Class object itself + !, + ( integer(Fspec) % assume it's a field or array index + -> I = Fspec + ; atom(Fspec) % assume it's a field name + -> N = Fspec + ; jpl_is_fieldID(Fspec) % assume it's a JNI field ID + -> FID = Fspec + ), + findall( + z(I,N,Mods,FID,Tf), + jpl_field_spec(Tx, I, N, Mods, FID, Tf), + Zs + ), + ( Zs = [] + -> write('Warning: no matching fields'), nl + ; Zs = [z(I,N,Mods,FID,Tf)] + -> ( member(static, Mods) + -> jpl_object_to_class(X, Cx), + jpl_set_static_field(Tf, Cx, FID, V) + ; jpl_set_field(Tf, X, FID, V) + ) + ; write('Warning: many matching fields'), nl, fail + ). + +jpl_set_1(array(T), X, Fspec, V) :- + ( is_list(V) + -> Vs = V + ; Vs = [V] % sloppy single-argument form + ), + length(Vs, Iv), + ( integer(Fspec), % single-element assignment + Fspec >= 0, + Iv is 1 + -> N is Fspec + ; Fspec = N-M, % element-sequence assignment + integer(N), + M is N+Iv-1 + -> true + ; Fspec == length + -> write('Error: cannot assign a value to final variable length'), nl, fail + ; write('Error: bad field spec for array set '(Fspec)), nl, fail + ), + jpl_set_2(T, X, N, Iv, Vs). + +%------------------------------------------------------------------------------ + +% jpl_set_2(+Type, +ArrayObject, +Offset, +DatumCount, +Datums) :- +% Datums, of which there are DatumCount, +% are stashed in successive elements of ArrayObject +% which is an array of Type +% starting at the Offset-th (numbered from 0) + +jpl_set_2(T, A, N, I, Ds) :- + ( jpl_datums_to_types(Ds, Tds), % most specialised types + jpl_types_fit_type(Tds, T) % all assignable? + -> true + ; write('Warning: not all datums can be assigned to array element type'), nl, fail + ), + ( ( T = class(_,_) + ; T = array(_) + ) + -> ( nth0(J, Ds, D), % for each datum + Nd is N+J, % compute array index + jSetObjectArrayElement(A, Nd, D), + fail % iterate + ; true + ) + ; jpl_primitive_type(T) + -> jni_type_to_xput_code(T, Xc), + jni_alloc_buffer(Xc, I, Bp), % I-element buf of required type + jpl_set_3(Ds, T, 0, Bp), + jpl_set_elements(T, A, N, I, Bp), + jni_free_buffer(Bp) + ; fail % bad type (exception?) + ). + +%------------------------------------------------------------------------------ + +% jpl_set_3(+Values, +Type, +BufferIndex, +BufferPointer) :- +% successive members of Values are stashed as (primitive) Type +% from the BufferIndex-th element (numbered from 0) onwards +% of the buffer indicated by BufferPointer + +jpl_set_3([], _, _, _). + +jpl_set_3([V|Vs], Tprim, Ib, Bp) :- + jni_convert_primitive_out(Tprim, V, Xhi, Xlo, Xc), + jni_stash_buffer_value(Bp, Ib, Xhi, Xlo, Xc), + Ibnext is Ib+1, + jpl_set_3(Vs, Tprim, Ibnext, Bp). + +%------------------------------------------------------------------------------ + +jpl_set_elements(boolean, Obj, N, I, Bp) :- + jSetBooleanArrayRegion(Obj, N, I, jbuf(Bp,boolean)). + +jpl_set_elements(char, Obj, N, I, Bp) :- + jSetCharArrayRegion(Obj, N, I, jbuf(Bp,char)). + +jpl_set_elements(byte, Obj, N, I, Bp) :- + jSetByteArrayRegion(Obj, N, I, jbuf(Bp,byte)). + +jpl_set_elements(short, Obj, N, I, Bp) :- + jSetShortArrayRegion(Obj, N, I, jbuf(Bp,short)). + +jpl_set_elements(int, Obj, N, I, Bp) :- + jSetIntArrayRegion(Obj, N, I, jbuf(Bp,int)). + +jpl_set_elements(long, Obj, N, I, Bp) :- + jSetLongArrayRegion(Obj, N, I, jbuf(Bp,long)). + +jpl_set_elements(float, Obj, N, I, Bp) :- + jSetFloatArrayRegion(Obj, N, I, jbuf(Bp,float)). + +jpl_set_elements(double, Obj, N, I, Bp) :- + jSetDoubleArrayRegion(Obj, N, I, jbuf(Bp,double)). + +%------------------------------------------------------------------------------ + +jpl_set_field(boolean, Obj, FieldID, R) :- + jSetBooleanField(Obj, FieldID, R). + +jpl_set_field(byte, Obj, FieldID, R) :- + jSetByteField(Obj, FieldID, R). + +jpl_set_field(char, Obj, FieldID, R) :- + jSetCharField(Obj, FieldID, R). + +jpl_set_field(short, Obj, FieldID, R) :- + jSetShortField(Obj, FieldID, R). + +jpl_set_field(int, Obj, FieldID, R) :- + jSetIntField(Obj, FieldID, R). + +jpl_set_field(long, Obj, FieldID, R) :- + jSetLongField(Obj, FieldID, R). + +jpl_set_field(float, Obj, FieldID, R) :- + jSetFloatField(Obj, FieldID, R). + +jpl_set_field(double, Obj, FieldID, R) :- + jSetDoubleField(Obj, FieldID, R). + +jpl_set_field(class(_,_), Obj, FieldID, R) :- + jSetObjectField(Obj, FieldID, R). + +jpl_set_field(array(_), Obj, FieldID, R) :- + jSetObjectField(Obj, FieldID, R). + +%------------------------------------------------------------------------------ + +jpl_set_static_field(boolean, Obj, FieldID, R) :- + jSetStaticBooleanField(Obj, FieldID, R). + +jpl_set_static_field(byte, Obj, FieldID, R) :- + jSetStaticByteField(Obj, FieldID, R). + +jpl_set_static_field(char, Obj, FieldID, R) :- + jSetStaticCharField(Obj, FieldID, R). + +jpl_set_static_field(short, Obj, FieldID, R) :- + jSetStaticShortField(Obj, FieldID, R). + +jpl_set_static_field(int, Obj, FieldID, R) :- + jSetStaticIntField(Obj, FieldID, R). + +jpl_set_static_field(long, Obj, FieldID, R) :- + jSetStaticLongField(Obj, FieldID, R). + +jpl_set_static_field(float, Obj, FieldID, R) :- + jSetStaticFloatField(Obj, FieldID, R). + +jpl_set_static_field(double, Obj, FieldID, R) :- + jSetStaticDoubleField(Obj, FieldID, R). + +jpl_set_static_field(class(_,_), Obj, FieldID, R) :- + jSetStaticObjectField(Obj, FieldID, R). + +jpl_set_static_field(array(_), Obj, FieldID, R) :- + jSetStaticObjectField(Obj, FieldID, R). + +%------------------------------------------------------------------------------ + +% jpl_z3s_to_most_specific_z3(+Zs, -Z) :- +% Zs is a list of arity-matching, type-suitable z3(I,MID,Tps) +% Z is the single most specific element of Zs, +% i.e. that than which no other z3/3 has a more specialised signature; +% fails if there is more than one such + +jpl_z3s_to_most_specific_z3(Zs, Z) :- + jpl_fergus_is_the_greatest(Zs, Z). + +%------------------------------------------------------------------------------ + +% jpl_z5s_to_most_specific_z5(+Zs, -Z) :- +% Zs is a list of arity-matching, type-suitable z5(I,Mods,MID,Tr,Tps) +% Z is the single most specific element of Zs, +% i.e. that than which no other z5/5 has a more specialised signature +% (this fails if there is more than one such) + +jpl_z5s_to_most_specific_z5(Zs, Z) :- + jpl_fergus_is_the_greatest(Zs, Z). + +%------------------------------------------------------------------------------ + +% jpl_pl_lib_version(-VersionString) :- +% jpl_pl_lib_version(-Major, -Minor, -Patch, -Status) :- + +jpl_pl_lib_version(VersionString) :- + jpl_pl_lib_version(Major, Minor, Patch, Status), + concat_atom([Major,'.',Minor,'.',Patch,'-',Status], VersionString). + + +jpl_pl_lib_version(3, 0, 3, alpha). + +%------------------------------------------------------------------------------ + +% jpl_type_alfa(0'$) --> % presumably not allowed +% "$". % given the "inner class" syntax? + +jpl_type_alfa(0'_) --> + "_", + !. + +jpl_type_alfa(C) --> + [C], { C>=0'a, C=<0'z }, + !. + +jpl_type_alfa(C) --> + [C], { C>=0'A, C=<0'Z }. + +%------------------------------------------------------------------------------ + +jpl_type_alfa_num(C) --> + jpl_type_alfa(C), + !. + +jpl_type_alfa_num(C) --> + [C], { C>=0'0, C=<0'9 }. + +%------------------------------------------------------------------------------ + +jpl_type_array_classname(array(T)) --> + "[", jpl_type_classname_2(T). + +%------------------------------------------------------------------------------ + +jpl_type_array_descriptor(array(T)) --> + "[", jpl_type_descriptor_1(T). + +%------------------------------------------------------------------------------ + +jpl_type_bare_class_descriptor(class(Ps,Cs)) --> + jpl_type_slashed_package_parts(Ps), jpl_type_class_parts(Cs). + +%------------------------------------------------------------------------------ + +jpl_type_bare_classname(class(Ps,Cs)) --> + jpl_type_dotted_package_parts(Ps), jpl_type_class_parts(Cs). + +%------------------------------------------------------------------------------ + +jpl_type_class_descriptor(class(Ps,Cs)) --> + "L", jpl_type_bare_class_descriptor(class(Ps,Cs)), ";". + +%------------------------------------------------------------------------------ + +jpl_type_class_part(N) --> + jpl_type_id(N). + +%------------------------------------------------------------------------------ + +jpl_type_class_parts([C|Cs]) --> + jpl_type_class_part(C), jpl_type_inner_class_parts(Cs). + +%------------------------------------------------------------------------------ + +jpl_type_classname_1(T) --> + jpl_type_bare_classname(T), + !. + +jpl_type_classname_1(T) --> + jpl_type_array_classname(T), + !. + +jpl_type_classname_1(T) --> + jpl_type_primitive(T). + +%------------------------------------------------------------------------------ + +jpl_type_classname_2(T) --> + jpl_type_delimited_classname(T). + +jpl_type_classname_2(T) --> + jpl_type_array_classname(T). + +jpl_type_classname_2(T) --> + jpl_type_primitive(T). + +%------------------------------------------------------------------------------ + +jpl_type_delimited_classname(Class) --> + "L", jpl_type_bare_classname(Class), ";". + +%------------------------------------------------------------------------------ + +jpl_type_descriptor_1(T) --> + jpl_type_primitive(T), + !. + +jpl_type_descriptor_1(T) --> + jpl_type_class_descriptor(T), + !. + +jpl_type_descriptor_1(T) --> + jpl_type_array_descriptor(T), + !. + +jpl_type_descriptor_1(T) --> + jpl_type_method_descriptor(T). + +%------------------------------------------------------------------------------ + +jpl_type_dotted_package_parts([P|Ps]) --> + jpl_type_package_part(P), ".", !, jpl_type_dotted_package_parts(Ps). + +jpl_type_dotted_package_parts([]) --> + []. + +%------------------------------------------------------------------------------ + +jpl_type_findclassname(T) --> + jpl_type_bare_class_descriptor(T). + +jpl_type_findclassname(T) --> + jpl_type_array_descriptor(T). + +%------------------------------------------------------------------------------ + +jpl_type_id(A) --> + { nonvar(A) -> atom_codes(A,[C|Cs]) ; true }, + jpl_type_alfa(C), jpl_type_id_rest(Cs), + { atom_codes(A, [C|Cs]) }. + +%------------------------------------------------------------------------------ + +jpl_type_id_rest([C|Cs]) --> + jpl_type_alfa_num(C), !, jpl_type_id_rest(Cs). + +jpl_type_id_rest([]) --> + []. + +%------------------------------------------------------------------------------ + +jpl_type_id_v2(A) --> % inner class name parts (empirically) + { nonvar(A) -> atom_codes(A,Cs) ; true }, + jpl_type_id_rest(Cs), + { atom_codes(A, Cs) }. + +%------------------------------------------------------------------------------ + +jpl_type_inner_class_part(N) --> + jpl_type_id_v2(N). + +%------------------------------------------------------------------------------ + +jpl_type_inner_class_parts([C|Cs]) --> + "$", jpl_type_inner_class_part(C), !, jpl_type_inner_class_parts(Cs). + +jpl_type_inner_class_parts([]) --> + []. + +%------------------------------------------------------------------------------ + +jpl_type_method_descriptor(method(Ts,T)) --> + "(", jpl_type_method_descriptor_args(Ts), ")", jpl_type_method_descriptor_return(T). + +%------------------------------------------------------------------------------ + +jpl_type_method_descriptor_args([T|Ts]) --> + jpl_type_descriptor_1(T), !, jpl_type_method_descriptor_args(Ts). + +jpl_type_method_descriptor_args([]) --> + []. + +%------------------------------------------------------------------------------ + +jpl_type_method_descriptor_return(T) --> + jpl_type_void(T). + +jpl_type_method_descriptor_return(T) --> + jpl_type_descriptor_1(T). + +%------------------------------------------------------------------------------ + +jpl_type_package_part(N) --> + jpl_type_id(N). + +%------------------------------------------------------------------------------ + +jpl_type_primitive(boolean) --> + "Z", + !. + +jpl_type_primitive(byte) --> + "B", + !. + +jpl_type_primitive(char) --> + "C", + !. + +jpl_type_primitive(short) --> + "S", + !. + +jpl_type_primitive(int) --> + "I", + !. + +jpl_type_primitive(long) --> + "J", + !. + +jpl_type_primitive(float) --> + "F", + !. + +jpl_type_primitive(double) --> + "D". + +%------------------------------------------------------------------------------ + +jpl_type_slashed_package_parts([P|Ps]) --> + jpl_type_package_part(P), "/", !, jpl_type_slashed_package_parts(Ps). + +jpl_type_slashed_package_parts([]) --> + []. + +%------------------------------------------------------------------------------ + +jpl_type_void(void) --> + "V". + +%------------------------------------------------------------------------------ + +%type jCallBooleanMethod(object, method_id, types, datums, boolean) + +% jCallBooleanMethod(+Obj, +MethodID, +Types, +Args, -Rbool) :- + +jCallBooleanMethod(Obj, MethodID, Types, Args, Rbool) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(39, Obj, MethodID, ArgBuf, Rbool). + +%------------------------------------------------------------------------------ + +%type jCallByteMethod(object, method_id, types, datums, byte) + +% jCallByteMethod(+Obj, +MethodID, +Types, +Args, -Rbyte) :- + +jCallByteMethod(Obj, MethodID, Types, Args, Rbyte) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(42, Obj, MethodID, ArgBuf, Rbyte). + +%------------------------------------------------------------------------------ + +%type jCallCharMethod(object, method_id, types, datums, char) + +% jCallCharMethod(+Obj, +MethodID, +Types, +Args, -Rchar) :- + +jCallCharMethod(Obj, MethodID, Types, Args, Rchar) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(45, Obj, MethodID, ArgBuf, Rchar). + +%------------------------------------------------------------------------------ + +%type jCallDoubleMethod(object, method_id, types, datums, double) + +% jCallDoubleMethod(+Obj, +MethodID, +Types, +Args, -Rdouble) :- + +jCallDoubleMethod(Obj, MethodID, Types, Args, Rdouble) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(60, Obj, MethodID, ArgBuf, Rdouble). + +%------------------------------------------------------------------------------ + +%type jCallFloatMethod(object, method_id, types, datums, float) + +% jCallFloatMethod(+Obj, +MethodID, +Types, +Args, -Rfloat) :- + +jCallFloatMethod(Obj, MethodID, Types, Args, Rfloat) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(57, Obj, MethodID, ArgBuf, Rfloat). + +%------------------------------------------------------------------------------ + +%type jCallIntMethod(object, method_id, types, datums, int) + +% jCallIntMethod(+Obj, +MethodID, +Types, +Args, -Rint) :- + +jCallIntMethod(Obj, MethodID, Types, Args, Rint) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(51, Obj, MethodID, ArgBuf, Rint). + +%------------------------------------------------------------------------------ + +%type jCallLongMethod(object, method_id, types, datums, long) + +% jCallLongMethod(+Obj, +MethodID, +Types, +Args, -Rlong) :- + +jCallLongMethod(Obj, MethodID, Types, Args, Rlong) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(54, Obj, MethodID, ArgBuf, Rlong). + +%------------------------------------------------------------------------------ + +%type jCallObjectMethod(object, method_id, types, datums, object) + +% jCallObjectMethod(+Obj, +MethodID, +Types, +Args, -Robj) :- + +jCallObjectMethod(Obj, MethodID, Types, Args, Robj) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(36, Obj, MethodID, ArgBuf, Robj). + +%------------------------------------------------------------------------------ + +%type jCallShortMethod(object, method_id, types, datums, short) + +% jCallShortMethod(+Obj, +MethodID, +Types, +Args, -Rshort) :- + +jCallShortMethod(Obj, MethodID, Types, Args, Rshort) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(48, Obj, MethodID, ArgBuf, Rshort). + +%------------------------------------------------------------------------------ + +%type jCallStaticBooleanMethod(class, types, datums, boolean) + +% jCallStaticBooleanMethod(+Class, +MethodID, +Types, +Args, -Rbool) :- + +jCallStaticBooleanMethod(Class, MethodID, Types, Args, Rbool) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(119, Class, MethodID, ArgBuf, Rbool). + +%------------------------------------------------------------------------------ + +%type jCallStaticByteMethod(class, method_id, types, datums, byte) + +% jCallStaticByteMethod(+Class, +MethodID, +Types, +Args, -Rbyte) :- + +jCallStaticByteMethod(Class, MethodID, Types, Args, Rbyte) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(122, Class, MethodID, ArgBuf, Rbyte). + +%------------------------------------------------------------------------------ + +%type jCallStaticCharMethod(class, method_id, types, datums, char) + +% jCallStaticCharMethod(+Class, +MethodID, +Types, +Args, -Rchar) :- + +jCallStaticCharMethod(Class, MethodID, Types, Args, Rchar) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(125, Class, MethodID, ArgBuf, Rchar). + +%------------------------------------------------------------------------------ + +%type jCallStaticDoubleMethod(class, method_id, types, datums, double) + +% jCallStaticDoubleMethod(+Class, +MethodID, +Types, +Args, -Rdouble) :- + +jCallStaticDoubleMethod(Class, MethodID, Types, Args, Rdouble) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(140, Class, MethodID, ArgBuf, Rdouble). + +%------------------------------------------------------------------------------ + +%type jCallStaticFloatMethod(class, method_id, types, datums, float) + +% jCallStaticFloatMethod(+Class, +MethodID, +Types, +Args, -Rfloat) :- + +jCallStaticFloatMethod(Class, MethodID, Types, Args, Rfloat) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(137, Class, MethodID, ArgBuf, Rfloat). + +%------------------------------------------------------------------------------ + +%type jCallStaticIntMethod(class, method_id, types, datums, int) + +% jCallStaticIntMethod(+Class, +MethodID, +Types, +Args, -Rint) :- + +jCallStaticIntMethod(Class, MethodID, Types, Args, Rint) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(131, Class, MethodID, ArgBuf, Rint). + +%------------------------------------------------------------------------------ + +%type jCallStaticLongMethod(class, method_id, types, datums, long) + +% jCallStaticLongMethod(+Class, +MethodID, +Types, +Args, -Rlong) :- + +jCallStaticLongMethod(Class, MethodID, Types, Args, Rlong) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(134, Class, MethodID, ArgBuf, Rlong). + +%------------------------------------------------------------------------------ + +%type jCallStaticObjectMethod(class, method_id, types, datums, object) + +% jCallStaticObjectMethod(+Class, +MethodID, +Types, +Args, -Robj) :- + +jCallStaticObjectMethod(Class, MethodID, Types, Args, Robj) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(116, Class, MethodID, ArgBuf, Robj). + +%------------------------------------------------------------------------------ + +%type jCallStaticShortMethod(class, method_id, types, datums, short) + +% jCallStaticShortMethod(+Class, +MethodID, +Types, +Args, -Rshort) :- + +jCallStaticShortMethod(Class, MethodID, Types, Args, Rshort) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(128, Class, MethodID, ArgBuf, Rshort). + +%------------------------------------------------------------------------------ + +%type jCallStaticVoidMethod(class, method_id, types, datums) + +% jCallStaticVoidMethod(+Class, +MethodID, +Types, +Args) :- + +jCallStaticVoidMethod(Class, MethodID, Types, Args) :- + jni_params_put(Args, Types, ArgBuf), + jni_void(143, Class, MethodID, ArgBuf). + +%------------------------------------------------------------------------------ + +%type jCallVoidMethod(object, method_id, types, datums) + +% jCallVoidMethod(+Obj, +MethodID, +Types, +Args) :- + +jCallVoidMethod(Obj, MethodID, Types, Args) :- + jni_params_put(Args, Types, ArgBuf), + jni_void(63, Obj, MethodID, ArgBuf). + +%------------------------------------------------------------------------------ + +%type jFindClass(findclassname, class) + +% jFindClass(+ClassName, -Class) :- + +jFindClass(ClassName, Class) :- + jni_func(6, ClassName, Class). + +%------------------------------------------------------------------------------ + +%type jGetArrayLength(array, int) + +% jGetArrayLength(+Array, -Size) :- + +jGetArrayLength(Array, Size) :- + jni_func(171, Array, Size). + +%------------------------------------------------------------------------------ + +%type jGetBooleanArrayRegion(boolean_array, int, int, boolean_buf) + +% jGetBooleanArrayRegion(+Array, +Start, +Len, +Buf) :- + +jGetBooleanArrayRegion(Array, Start, Len, Buf) :- + jni_void(199, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jGetBooleanField(object, field_id, boolean) + +% jGetBooleanField(+Obj, +FieldID, -Rbool) :- + +jGetBooleanField(Obj, FieldID, Rbool) :- + jni_func(96, Obj, FieldID, Rbool). + +%------------------------------------------------------------------------------ + +%type jGetByteArrayRegion(byte_array, int, int, byte_buf) + +% jGetByteArrayRegion(+Array, +Start, +Len, +Buf) :- + +jGetByteArrayRegion(Array, Start, Len, Buf) :- + jni_void(200, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jGetByteField(object, field_id, byte) + +% jGetByteField(+Obj, +FieldID, -Rbyte) :- + +jGetByteField(Obj, FieldID, Rbyte) :- + jni_func(97, Obj, FieldID, Rbyte). + +%------------------------------------------------------------------------------ + +%type jGetCharArrayRegion(char_array, int, int, char_buf) + +% jGetCharArrayRegion(+Array, +Start, +Len, +Buf) :- + +jGetCharArrayRegion(Array, Start, Len, Buf) :- + jni_void(201, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jGetCharField(object, field_id, char) + +% jGetCharField(+Obj, +FieldID, -Rchar) :- + +jGetCharField(Obj, FieldID, Rchar) :- + jni_func(98, Obj, FieldID, Rchar). + +%------------------------------------------------------------------------------ + +%type jGetDoubleArrayRegion(double_array, int, int, double_buf) + +% jGetDoubleArrayRegion(+Array, +Start, +Len, +Buf) :- + +jGetDoubleArrayRegion(Array, Start, Len, Buf) :- + jni_void(206, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jGetDoubleField(object, field_id, double) + +% jGetDoubleField(+Obj, +FieldID, -Rdouble) :- + +jGetDoubleField(Obj, FieldID, Rdouble) :- + jni_func(103, Obj, FieldID, Rdouble). + +%------------------------------------------------------------------------------ + +%type jGetFieldID(class, descriptor, field_id) + +% jGetFieldID(+Class, +Name, +Typedescriptor, -FieldID) :- + +jGetFieldID(Class, Name, Type, FieldID) :- + jpl_type_to_descriptor(Type, TD), + jni_func(94, Class, Name, TD, FieldID). + +%------------------------------------------------------------------------------ + +%type jGetFloatArrayRegion(float_array, int, int, float_buf) + +% jGetFloatArrayRegion(+Array, +Start, +Len, +Buf) :- + +jGetFloatArrayRegion(Array, Start, Len, Buf) :- + jni_void(205, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jGetFloatField(object, field_id, float) + +% jGetFloatField(+Obj, +FieldID, -Rfloat) :- + +jGetFloatField(Obj, FieldID, Rfloat) :- + jni_func(102, Obj, FieldID, Rfloat). + +%------------------------------------------------------------------------------ + +%type jGetIntArrayRegion(int_array, int, int, int_buf) + +% jGetIntArrayRegion(+Array, +Start, +Len, +Buf) :- + +jGetIntArrayRegion(Array, Start, Len, Buf) :- + jni_void(203, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jGetIntField(object, field_id, int) + +% jGetIntField(+Obj, +FieldID, -Rint) :- + +jGetIntField(Obj, FieldID, Rint) :- + jni_func(100, Obj, FieldID, Rint). + +%------------------------------------------------------------------------------ + +%type jGetLongArrayRegion(long_array, int, int, long_buf) + +% jGetLongArrayRegion(+Array, +Start, +Len, +Buf) :- + +jGetLongArrayRegion(Array, Start, Len, Buf) :- + jni_void(204, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jGetLongField(object, field_id, long) + +% jGetLongField(+Obj, +FieldID, -Rlong) :- + +jGetLongField(Obj, FieldID, Rlong) :- + jni_func(101, Obj, FieldID, Rlong). + +%------------------------------------------------------------------------------ + +%type jGetMethodID(class, name, descriptor, method_id) + +% jGetMethodID(+Class, +Name, +TypeDescriptor, -MethodID) :- + +jGetMethodID(Class, Name, Type, MethodID) :- + jpl_type_to_descriptor(Type, TD), + jni_func(33, Class, Name, TD, MethodID). + +%------------------------------------------------------------------------------ + +%type jGetObjectArrayElement(object_array, int, object) + +% jGetObjectArrayElement(+Array, +Index, -Obj) :- + +jGetObjectArrayElement(Array, Index, Obj) :- + jni_func(173, Array, Index, Obj). + +%------------------------------------------------------------------------------ + +%type jGetObjectClass(object, class) + +% jGetObjectClass(+Object, -Class) :- + +jGetObjectClass(Object, Class) :- + jni_func(31, Object, Class). + +%------------------------------------------------------------------------------ + +%type jGetObjectField(object, field_id, object) + +% jGetObjectField(+Obj, +FieldID, -RObj) :- + +jGetObjectField(Obj, FieldID, Robj) :- + jni_func(95, Obj, FieldID, Robj). + +%------------------------------------------------------------------------------ + +%type jGetShortArrayRegion(short_array, int, int, short_buf) + +% jGetShortArrayRegion(+Array, +Start, +Len, +Buf) :- + +jGetShortArrayRegion(Array, Start, Len, Buf) :- + jni_void(202, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jGetShortField(object, field_id, short) + +% jGetShortField(+Obj, +FieldID, -Rshort) :- + +jGetShortField(Obj, FieldID, Rshort) :- + jni_func(99, Obj, FieldID, Rshort). + +%------------------------------------------------------------------------------ + +%type jGetStaticBooleanField(class, field_id, boolean) + +% jGetStaticBooleanField(+Class, +FieldID, -Rbool) :- + +jGetStaticBooleanField(Class, FieldID, Rbool) :- + jni_func(146, Class, FieldID, Rbool). + +%------------------------------------------------------------------------------ + +%type jGetStaticByteField(class, field_id, byte) + +% jGetStaticByteField(+Class, +FieldID, -Rbyte) :- + +jGetStaticByteField(Class, FieldID, Rbyte) :- + jni_func(147, Class, FieldID, Rbyte). + +%------------------------------------------------------------------------------ + +%type jGetStaticCharField(class, field_id, char) + +% jGetStaticCharField(+Class, +FieldID, -Rchar) :- + +jGetStaticCharField(Class, FieldID, Rchar) :- + jni_func(148, Class, FieldID, Rchar). + +%------------------------------------------------------------------------------ + +%type jGetStaticDoubleField(class, field_id, double) + +% jGetStaticDoubleField(+Class, +FieldID, -Rdouble) :- + +jGetStaticDoubleField(Class, FieldID, Rdouble) :- + jni_func(153, Class, FieldID, Rdouble). + +%------------------------------------------------------------------------------ + +%type jGetStaticFieldID(class, name, field_id) + +% jGetStaticFieldID(+Class, +Name, +TypeDescriptor, -FieldID) :- + +jGetStaticFieldID(Class, Name, Type, FieldID) :- + jpl_type_to_descriptor(Type, TD), % cache this? + jni_func(144, Class, Name, TD, FieldID). + +%------------------------------------------------------------------------------ + +%type jGetStaticFloatField(class, field_id, float) + +% jGetStaticFloatField(+Class, +FieldID, -Rfloat) :- + +jGetStaticFloatField(Class, FieldID, Rfloat) :- + jni_func(152, Class, FieldID, Rfloat). + +%------------------------------------------------------------------------------ + +%type jGetStaticIntField(class, field_id, int) + +% jGetStaticIntField(+Class, +FieldID, -Rint) :- + +jGetStaticIntField(Class, FieldID, Rint) :- + jni_func(150, Class, FieldID, Rint). + +%------------------------------------------------------------------------------ + +%type jGetStaticLongField(class, field_id, long) + +% jGetStaticLongField(+Class, +FieldID, -Rlong) :- + +jGetStaticLongField(Class, FieldID, Rlong) :- + jni_func(151, Class, FieldID, Rlong). + +%------------------------------------------------------------------------------ + +%type jGetStaticMethodID(class, name, method_id) + +% jGetStaticMethodID(+Class, +Name, +TypeDescriptor, -MethodID) :- + +jGetStaticMethodID(Class, Name, Type, MethodID) :- + jpl_type_to_descriptor(Type, TD), + jni_func(113, Class, Name, TD, MethodID). + +%------------------------------------------------------------------------------ + +%type jGetStaticObjectField(class, field_id, object) + +% jGetStaticObjectField(+Class, +FieldID, -RObj) :- + +jGetStaticObjectField(Class, FieldID, Robj) :- + jni_func(145, Class, FieldID, Robj). + +%------------------------------------------------------------------------------ + +%type jGetStaticShortField(class, field_id, short) + +% jGetStaticShortField(+Class, +FieldID, -Rshort) :- + +jGetStaticShortField(Class, FieldID, Rshort) :- + jni_func(149, Class, FieldID, Rshort). + +%------------------------------------------------------------------------------ + +%type jGetSuperclass(object, object) + +% jGetSuperclass(+Class1, -Class2) :- + +jGetSuperclass(Class1, Class2) :- + jni_func(10, Class1, Class2). + +%------------------------------------------------------------------------------ + +%type jIsAssignableFrom(object, object) + +% jIsAssignableFrom(+Class1, +Class2) :- + +jIsAssignableFrom(Class1, Class2) :- + jni_func(11, Class1, Class2, @(true)). + +%------------------------------------------------------------------------------ + +%type jNewBooleanArray(int, boolean_array) + +% jNewBooleanArray(+Length, -Array) :- + +jNewBooleanArray(Length, Array) :- + jni_func(175, Length, Array). + +%------------------------------------------------------------------------------ + +%type jNewByteArray(int, byte_array) + +% jNewByteArray(+Length, -Array) :- + +jNewByteArray(Length, Array) :- + jni_func(176, Length, Array). + +%------------------------------------------------------------------------------ + +%type jNewCharArray(int, char_array) + +% jNewCharArray(+Length, -Array) :- + +jNewCharArray(Length, Array) :- + jni_func(177, Length, Array). + +%------------------------------------------------------------------------------ + +%type jNewDoubleArray(int, double_array) + +% jNewDoubleArray(+Length, -Array) :- + +jNewDoubleArray(Length, Array) :- + jni_func(182, Length, Array). + +%------------------------------------------------------------------------------ + +%type jNewFloatArray(int, float_array) + +% jNewFloatArray(+Length, -Array) :- + +jNewFloatArray(Length, Array) :- + jni_func(181, Length, Array). + +%------------------------------------------------------------------------------ + +%type jNewIntArray(int, int_array) + +% jNewIntArray(+Length, -Array) :- + +jNewIntArray(Length, Array) :- + jni_func(179, Length, Array). + +%------------------------------------------------------------------------------ + +%type jNewLongArray(int, long_array) + +% jNewLongArray(+Length, -Array) :- + +jNewLongArray(Length, Array) :- + jni_func(180, Length, Array). + +%------------------------------------------------------------------------------ + +%type jNewObject(class, method_id, types, datums, object) + +% jNewObject(+Class, +MethodID, +Types, +Args, -Obj) :- + +jNewObject(Class, MethodID, Types, Args, Obj) :- + jni_params_put(Args, Types, ArgBuf), + jni_func(30, Class, MethodID, ArgBuf, Obj). + +%------------------------------------------------------------------------------ + +%type jNewObjectArray(int, class, object, object_array) + +% jNewObjectArray(+Len, +Class, +InitVal, -Array) :- + +jNewObjectArray(Len, Class, InitVal, Array) :- + jni_func(172, Len, Class, InitVal, Array). + +%------------------------------------------------------------------------------ + +%type jNewShortArray(int, short_array) + +% jNewShortArray(+Length, -Array) :- + +jNewShortArray(Length, Array) :- + jni_func(178, Length, Array). + +%------------------------------------------------------------------------------ + +%type jSetBooleanArrayRegion(boolean_array, int, int, boolean_buf) + +% jSetBooleanArrayRegion(+Array, +Start, +Len, +Buf) :- + +jSetBooleanArrayRegion(Array, Start, Len, Buf) :- + jni_void(207, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jSetBooleanField(object, field_id, boolean) + +% jSetBooleanField(+Obj, +FieldID, +Rbool) :- + +jSetBooleanField(Obj, FieldID, Rbool) :- + jni_void(105, Obj, FieldID, Rbool). + +%------------------------------------------------------------------------------ + +%type jSetByteArrayRegion(byte_array, int, int, byte_buf) + +% jSetByteArrayRegion(+Array, +Start, +Len, +Buf) :- + +jSetByteArrayRegion(Array, Start, Len, Buf) :- + jni_void(208, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jSetByteField(object, field_id, byte) + +% jSetByteField(+Obj, +FieldID, +Rbyte) :- + +jSetByteField(Obj, FieldID, Rbyte) :- + jni_void(106, Obj, FieldID, Rbyte). + +%------------------------------------------------------------------------------ + +%type jSetCharArrayRegion(char_array, int, int, char_buf) + +% jSetCharArrayRegion(+Array, +Start, +Len, +Buf) :- + +jSetCharArrayRegion(Array, Start, Len, Buf) :- + jni_void(209, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jSetCharField(object, field_id, char) + +% jSetCharField(+Obj, +FieldID, +Rchar) :- + +jSetCharField(Obj, FieldID, Rchar) :- + jni_void(107, Obj, FieldID, Rchar). + +%------------------------------------------------------------------------------ + +%type jSetDoubleArrayRegion(double_array, int, int, double_buf) + +% jSetDoubleArrayRegion(+Array, +Start, +Len, +Buf) :- + +jSetDoubleArrayRegion(Array, Start, Len, Buf) :- + jni_void(214, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jSetDoubleField(object, field_id, double) + +% jSetDoubleField(+Obj, +FieldID, +Rdouble) :- + +jSetDoubleField(Obj, FieldID, Rdouble) :- + jni_void(112, Obj, FieldID, Rdouble). + +%------------------------------------------------------------------------------ + +%type jSetFloatArrayRegion(float_array, int, int, float_buf) + +% jSetFloatArrayRegion(+Array, +Start, +Len, +Buf) :- + +jSetFloatArrayRegion(Array, Start, Len, Buf) :- + jni_void(213, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jSetFloatField(object, field_id, float) + +% jSetFloatField(+Obj, +FieldID, +Rfloat) :- + +jSetFloatField(Obj, FieldID, Rfloat) :- + jni_void(111, Obj, FieldID, Rfloat). + +%------------------------------------------------------------------------------ + +%type jSetIntArrayRegion(int_array, int, int, int_buf) + +% jSetIntArrayRegion(+Array, +Start, +Len, +Buf) :- + +jSetIntArrayRegion(Array, Start, Len, Buf) :- + jni_void(211, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jSetIntField(object, field_id, int) + +% jSetIntField(+Obj, +FieldID, +Rint) :- + +jSetIntField(Obj, FieldID, Rint) :- + jni_void(109, Obj, FieldID, Rint). + +%------------------------------------------------------------------------------ + +%type jSetLongArrayRegion(long_array, int, int, long_buf) + +% jSetLongArrayRegion(+Array, +Start, +Len, +Buf) :- + +jSetLongArrayRegion(Array, Start, Len, Buf) :- + jni_void(212, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jSetLongField(object, field_id, long) + +% jSetLongField(+Obj, +FieldID, +Rlong) :- + +jSetLongField(Obj, FieldID, Rlong) :- + jni_void(110, Obj, FieldID, Rlong). + +%------------------------------------------------------------------------------ + +%type jSetObjectArrayElement(object_array, int, object) + +% jSetObjectArrayElement(+Array, +Index, +Obj) :- + +jSetObjectArrayElement(Array, Index, Obj) :- + jni_void(174, Array, Index, Obj). + +%------------------------------------------------------------------------------ + +%type jSetObjectField(object, field_id, object) + +% jSetObjectField(+Obj, +FieldID, +RObj) :- + +jSetObjectField(Obj, FieldID, Robj) :- + jni_void(104, Obj, FieldID, Robj). + +%------------------------------------------------------------------------------ + +%type jSetShortArrayRegion(short_array, int, int, short_buf) + +% jSetShortArrayRegion(+Array, +Start, +Len, +Buf) :- + +jSetShortArrayRegion(Array, Start, Len, Buf) :- + jni_void(210, Array, Start, Len, Buf). + +%------------------------------------------------------------------------------ + +%type jSetShortField(object, field_id, short) + +% jSetShortField(+Obj, +FieldID, +Rshort) :- + +jSetShortField(Obj, FieldID, Rshort) :- + jni_void(108, Obj, FieldID, Rshort). + +%------------------------------------------------------------------------------ + +%type jSetStaticBooleanField(class, field_id, boolean) + +% jSetStaticBooleanField(+Class, +FieldID, +Rbool) :- + +jSetStaticBooleanField(Class, FieldID, Rbool) :- + jni_void(155, Class, FieldID, Rbool). + +%------------------------------------------------------------------------------ + +%type jSetStaticByteField(class, field_id, byte) + +% jSetStaticByteField(+Class, +FieldID, +Rbyte) :- + +jSetStaticByteField(Class, FieldID, Rbyte) :- + jni_void(156, Class, FieldID, Rbyte). + +%------------------------------------------------------------------------------ + +%type jSetStaticCharField(class, field_id, char) + +% jSetStaticCharField(+Class, +FieldID, +Rchar) :- + +jSetStaticCharField(Class, FieldID, Rchar) :- + jni_void(157, Class, FieldID, Rchar). + +%------------------------------------------------------------------------------ + +%type jSetStaticDoubleField(class, field_id, double) + +% jSetStaticDoubleField(+Class, +FieldID, +Rdouble) :- + +jSetStaticDoubleField(Class, FieldID, Rdouble) :- + jni_void(162, Class, FieldID, Rdouble). + +%------------------------------------------------------------------------------ + +%type jSetStaticFloatField(class, field_id, float) + +% jSetStaticFloatField(+Class, +FieldID, +Rfloat) :- + +jSetStaticFloatField(Class, FieldID, Rfloat) :- + jni_void(161, Class, FieldID, Rfloat). + +%------------------------------------------------------------------------------ + +%type jSetStaticIntField(class, field_id, int) + +% jSetStaticIntField(+Class, +FieldID, +Rint) :- + +jSetStaticIntField(Class, FieldID, Rint) :- + jni_void(159, Class, FieldID, Rint). + +%------------------------------------------------------------------------------ + +%type jSetStaticLongField(class, field_id, long) + +% jSetStaticLongField(+Class, +FieldID, +Rlong) :- + +jSetStaticLongField(Class, FieldID, Rlong) :- + jni_void(160, Class, FieldID, Rlong). + +%------------------------------------------------------------------------------ + +%type jSetStaticObjectField(class, field_id, object) + +% jSetStaticObjectField(+Class, +FieldID, +Robj) :- + +jSetStaticObjectField(Class, FieldID, Robj) :- + jni_void(154, Class, FieldID, Robj). + +%------------------------------------------------------------------------------ + +%type jSetStaticShortField(class, field_id, short) + +% jSetStaticShortField(+Class, +FieldID, +Rshort) :- + +jSetStaticShortField(Class, FieldID, Rshort) :- + jni_void(158, Class, FieldID, Rshort). + +%------------------------------------------------------------------------------ + +% jni_convert_primitive_in(+JspType, -Term, +Xhi, +Xlo) :- +% a value of JspType returned +% (by jni_primitive_buffer_to_array or jni_get_array_element) +% as integers Xhi and Xlo +% is canonically (?) represented by Term; +% object types are bound in only where obvious (e.g. jstring, but not jthrowable) +% NB this oughta be done in foreign code... +% NB the following NBs are obsolete... +% NB this code assumes that null jbufs are never returned... +% NB XputMode is determined solely by JniType, but is needed earlier (for jni_call) +% NB this proc should be defined for all return types of supported JNI functions +% (see jni_proto/5) +% NB 'jsize' is synonymous with 'jint' + +jni_convert_primitive_in(boolean, T, 0, Xlo) :- + ( Xlo == 0 + -> T = @(false) + ; Xlo == 1 + -> T = @(true) + ). +jni_convert_primitive_in(byte, I, 0, I). +jni_convert_primitive_in(char, I, 0, I). +jni_convert_primitive_in(short, I, 0, I). +jni_convert_primitive_in(int, I, 0, I). +jni_convert_primitive_in(long, T, Xhi, Xlo) :- + ( ( Xhi == 0, + Xlo >= 0 % small non-negative + ; Xhi == -1, + Xlo < 0 % small negative + ) + -> T = Xlo + ; T = jlong(Xhi,Xlo) + ). +jni_convert_primitive_in(float, F, 0, F). +jni_convert_primitive_in(double, F, 0, F). + +%------------------------------------------------------------------------------ + +% jni_convert_primitive_out(+JspType, +Term, -Xhi, -Xlo, -JniXputCode) :- +% to pass Term to a JNI function as (primitive) JspType, +% send Xhi, Xlo with JniXputCode +% NB all this oughta be done in foreign code... +% NB JniXputCode is determined by both JspType and Term +% NB JniXputCode determines reassembly, widening and casting in foreign code + +jni_convert_primitive_out(boolean, @(false), 0, 0, 1). % JNI_XPUT_BOOLEAN + +jni_convert_primitive_out(boolean, @(true), 0, 1, 1). % JNI_XPUT_BOOLEAN + +jni_convert_primitive_out(char, I, 0, I, 3) :- % JNI_XPUT_CHAR + integer(I), + I >= 0, + I =< 65535. + +jni_convert_primitive_out(byte, I, 0, I, 2) :- % JNI_XPUT_BYTE + integer(I), + I >= -128, + I =< 127. + +jni_convert_primitive_out(short, I, 0, I, 4) :- % JNI_XPUT_SHORT + integer(I), + I >= -32768, + I =< 32767. + +jni_convert_primitive_out(int, I, 0, I, 5) :- % JNI_XPUT_INT + integer(I), + I >= -2147483648, + I =< 2147483647. + +jni_convert_primitive_out(long, I, V2, I, 6) :- % JNI_XPUT_LONG + integer(I), + ( I < 0 + -> V2 = -1 + ; V2 = 0 + ). + +jni_convert_primitive_out(long, jlong(V2,V1), V2, V1, 6) :- % JNI_XPUT_LONG + integer(V1), + integer(V2). + +jni_convert_primitive_out(float, F, 0, F, 7) :- % JNI_XPUT_FLOAT + float(F). + +jni_convert_primitive_out(float, I, 0, F, 7) :- % JNI_XPUT_FLOAT + integer(I), + F is float(I). + +jni_convert_primitive_out(float, jlong(V2,V1), V2, V1, 10) :- % JNI_XPUT_LONG_TO_FLOAT + integer(V1), + integer(V2). + +jni_convert_primitive_out(double, I, 0, F, 9) :- % JNI_XPUT_FLOAT_TO_DOUBLE + integer(I), + F is float(I). + +jni_convert_primitive_out(double, jlong(V2,V1), V2, V1, 11) :- % JNI_XPUT_LONG_TO_DOUBLE + integer(V1), + integer(V2). + +jni_convert_primitive_out(double, F, 0, F, 9) :- % JNI_XPUT_FLOAT_TO_DOUBLE + float(F). + +%------------------------------------------------------------------------------ + +% jni_params_put(+Args, +Types, -ArgBuf) :- +% the old form used a static buffer, hence was not re-entrant; +% the new form allocates a buffer of one jvalue per arg, +% puts the (converted) args into respective elements, then returns it +% (the caller is responsible for freeing it) + +%jni_params_put(As, Ts) :- +% jni_ensure_jvm, % in case e.g. NewStringUTF() is called +% jni_params_put_1(As, 0, Ts). + + +jni_params_put(As, Ts, ArgBuf) :- + jni_ensure_jvm, % in case e.g. NewStringUTF() is called + length(As, N), + jni_type_to_xput_code(jvalue, Xc), % Xc will be 15 + jni_alloc_buffer(Xc, N, ArgBuf), + jni_params_put_1(As, 0, Ts, ArgBuf). + +%------------------------------------------------------------------------------ + +% jni_params_put_1(+Args, +N, +JPLTypes, +ArgBuf) :- +% Args is a (full or partial) list of args-not-yet-stashed, +% and Types are their (JPL) types (e.g. 'boolean'); +% N is the arg and buffer index (0+) at which the head of Args is to be stashed; +% the old form used a static buffer and hence was non-reentrant; +% the new form uses a dynamically allocated buffer (which oughta be freed after use) +% +%NB if the (user-provided) actual params were to be unsuitable for conversion +%NB to the method-required types, this would fail silently (without freeing the buffer); +%NB it's not clear whether the overloaded-method-resolution ensures that all args +%NB are convertible + +%jni_params_put_1([], _, []). + +%jni_params_put_1([A|As], N, [Tjni|Ts]) :- % type checking? +% N2 is N+1, +% jni_params_put_1(As, N2, Ts), % stash last param first +% ( jni_type_to_xput_code(Tjni, Xc) +% -> jni_param_put(N, Xc, A) % foreign +% ; fail % oughta raise an exception? +% ). + + +jni_params_put_1([], _, [], _). + +jni_params_put_1([A|As], N, [Tjni|Ts], ArgBuf) :- % type checking? + ( jni_type_to_xput_code(Tjni, Xc) + -> jni_param_put(N, Xc, A, ArgBuf) % foreign + ; fail % oughta raise an exception? + ), + N2 is N+1, + jni_params_put_1(As, N2, Ts, ArgBuf). % stash remaining params (if any) + +%------------------------------------------------------------------------------ + +% jni_type_to_xput_code(+JspType, -JniXputCode) :- +% NB JniXputCode determines widening and casting in foreign code +% NB the codes could be compiled into jni_method_spec_cache etc. +% instead of, or as well as, types (for - small - efficiency gain) + +jni_type_to_xput_code(boolean, 1). % JNI_XPUT_BOOLEAN + +jni_type_to_xput_code(byte, 2). % JNI_XPUT_BYTE + +jni_type_to_xput_code(char, 3). % JNI_XPUT_CHAR + +jni_type_to_xput_code(short, 4). % JNI_XPUT_SHORT + +jni_type_to_xput_code(int, 5). % JNI_XPUT_INT + +jni_type_to_xput_code(long, 6). % JNI_XPUT_LONG + +jni_type_to_xput_code(float, 7). % JNI_XPUT_FLOAT + +jni_type_to_xput_code(double, 8). % JNI_XPUT_DOUBLE + +jni_type_to_xput_code(class(_,_), 12). % JNI_XPUT_REF + +jni_type_to_xput_code(array(_), 12). % JNI_XPUT_REF + +jni_type_to_xput_code(jvalue, 15). % JNI_XPUT_JVALUE + +%------------------------------------------------------------------------------ + +% jpl_class_to_constructor_array(+Class, -MethodArray) :- +% might this be done more efficiently in foreign code? + +jpl_class_to_constructor_array(Cx, Ma) :- + jpl_classname_to_class('java.lang.Class', CC), % cached? + jGetMethodID( + CC, + getConstructors, + method([],array(class([java,lang,reflect],['Constructor']))), + MID + ), + jCallObjectMethod(Cx, MID, [], [], Ma). + +%------------------------------------------------------------------------------ + +% jpl_class_to_constructors(+Class, -Methods) :- + +jpl_class_to_constructors(Cx, Ms) :- + jpl_class_to_constructor_array(Cx, Ma), + jpl_object_array_to_list(Ma, Ms). + +%------------------------------------------------------------------------------ + +% jpl_class_to_field_array(+Class, -FieldArray) :- + +jpl_class_to_field_array(Cx, Fa) :- + jpl_classname_to_class('java.lang.Class', CC), + jGetMethodID( + CC, + getFields, + method([],array(class([java,lang,reflect],['Field']))), + MID + ), + jCallObjectMethod(Cx, MID, [], [], Fa). + +%------------------------------------------------------------------------------ + +% jpl_class_to_fields(+Class, -Fields) :- + +jpl_class_to_fields(C, Fs) :- + jpl_class_to_field_array(C, Fa), + jpl_object_array_to_list(Fa, Fs). + +%------------------------------------------------------------------------------ + +% jpl_class_to_method_array(+Class, -MethodArray) :- +% migrate into foreign code for efficiency? + +jpl_class_to_method_array(Cx, Ma) :- + jpl_classname_to_class('java.lang.Class', CC), % cached? + jGetMethodID( + CC, + getMethods, + method([],array(class([java,lang,reflect],['Method']))), + MID + ), + jCallObjectMethod(Cx, MID, [], [], Ma). + +%------------------------------------------------------------------------------ + +% jpl_class_to_methods(+Class, -Methods) :- + +jpl_class_to_methods(Cx, Ms) :- + jpl_class_to_method_array(Cx, Ma), + jpl_object_array_to_list(Ma, Ms). + +%------------------------------------------------------------------------------ + +% jpl_constructor_to_modifiers(+Method, -Modifiers) :- +% migrate into foreign code for efficiency? + +jpl_constructor_to_modifiers(X, Ms) :- + jpl_classname_to_class('java.lang.reflect.Constructor', Cx), % cached? + jpl_method_to_modifiers_1(X, Cx, Ms). + +%------------------------------------------------------------------------------ + +% jpl_constructor_to_name(+Method, -Name) :- +% it is a JNI convention that each constructor behaves (at least, +% for reflection), as a method whose name is '' + +jpl_constructor_to_name(_X, ''). + +%------------------------------------------------------------------------------ + +% jpl_constructor_to_parameter_types(+Method, -ParameterTypes) :- +% migrate to foreign code for efficiency? + +jpl_constructor_to_parameter_types(X, Tps) :- + jpl_classname_to_class('java.lang.reflect.Constructor', Cx), % cached? + jpl_method_to_parameter_types_1(X, Cx, Tps). + +%------------------------------------------------------------------------------ + +% jpl_constructor_to_return_type(+Method, -Type) :- +% it is a JNI convention that, for the purposes of retrieving a MethodID, +% a constructor has a return type of 'void' + +jpl_constructor_to_return_type(_X, void). + +%------------------------------------------------------------------------------ + +% jpl_field_spec(+ClassType, -Index, -Name, -Modifiers, -MID, -Type) :- + +jpl_field_spec(Tc, I, N, Mods, MID, T) :- + ( jpl_field_spec_is_cached(Tc) + -> jpl_field_spec_cache(Tc, I, N, Mods, MID, T) + ; jpl_type_to_class(Tc, C), + jpl_class_to_fields(C, Fs), + jpl_field_spec_1(Fs, Tc), + assert(jpl_field_spec_is_cached(Tc)), + jpl_field_spec_cache(Tc, I, N, Mods, MID, T) + ). + +%------------------------------------------------------------------------------ + +jpl_field_spec_1(Fs, Tc) :- + ( jpl_type_to_class(Tc, C), + nth1(I, Fs, F), + jpl_field_to_name(F, N), + jpl_field_to_modifiers(F, Mods), + jpl_field_to_type(F, T), + ( member(static, Mods) + -> jGetStaticFieldID(C, N, T, MID) + ; jGetFieldID(C, N, T, MID) + ), + assert(jpl_field_spec_cache(Tc,I,N,Mods,MID,T)), + fail + ; true + ). + +%------------------------------------------------------------------------------ + +:- dynamic jpl_field_spec_cache/6. + +%------------------------------------------------------------------------------ + +:- dynamic jpl_field_spec_is_cached/1. + +%------------------------------------------------------------------------------ + +%type jpl_field_to_modifiers(object, ordset(modifier)) + +% jpl_field_to_modifiers(+Field, -Modifiers) :- + +jpl_field_to_modifiers(F, Ms) :- + jpl_classname_to_class('java.lang.reflect.Field', Cf), + jpl_method_to_modifiers_1(F, Cf, Ms). + +%------------------------------------------------------------------------------ + +% jpl_field_to_name(+Field, -Name) :- + +jpl_field_to_name(F, N) :- + jpl_classname_to_class('java.lang.reflect.Field', Cf), + jpl_method_to_name_1(F, Cf, N). + +%------------------------------------------------------------------------------ + +%type jpl_field_to_type(object, type) + +% jpl_field_to_type(+Field, -Type) :- + +jpl_field_to_type(F, Tf) :- + jpl_classname_to_class('java.lang.reflect.Field', Cf), + jGetMethodID(Cf, getType, method([],class([java,lang],['Class'])), MID), + jCallObjectMethod(F, MID, [], [], Cr), + jpl_class_to_type(Cr, Tf). + +%------------------------------------------------------------------------------ + +%type jpl_method_spec(type, integer, name, arity, ordset(modifier), method_id, type, list(type)) + +% jpl_method_spec(+ClassType, -Index, -Name, -Arity, -Modifiers, -MID, -ReturnType, -ParameterTypes) :- +% generates pertinent details of all accessible methods of ClassType, +% populating or using the cache as appropriate + +jpl_method_spec(Tc, I, N, A, Mods, MID, Tr, Tps) :- + ( jpl_method_spec_is_cached(Tc) + -> jpl_method_spec_cache(Tc, I, N, A, Mods, MID, Tr, Tps) + ; jpl_type_to_class(Tc, Cx), + jpl_class_to_constructors(Cx, Xs), + jpl_class_to_methods(Cx, Ms), + jpl_method_spec_1(Tc, Xs, Ms), + assert(jpl_method_spec_is_cached(Tc)), + jpl_method_spec_cache(Tc, I, N, A, Mods, MID, Tr, Tps) + ). + +%------------------------------------------------------------------------------ + +%type jpl_method_spec_1(type, list(method), list(method)) + +jpl_method_spec_1(Tc, Xs, Ms) :- + ( jpl_type_to_class(Tc, C), + ( nth1(I, Xs, X), % generate constructors, numbered from 1 + jpl_constructor_to_name(X, N), + jpl_constructor_to_modifiers(X, Mods), + jpl_constructor_to_return_type(X, Tr), + jpl_constructor_to_parameter_types(X, Tps) + ; length(Xs, J0), + nth1(J, Ms, M), % generate members, continuing numbering + I is J0+J, + jpl_method_to_name(M, N), + jpl_method_to_modifiers(M, Mods), + jpl_method_to_return_type(M, Tr), + jpl_method_to_parameter_types(M, Tps) + ), + length(Tps, A), % arity + ( member(static, Mods) + -> jGetStaticMethodID(C, N, method(Tps,Tr), MID) + ; jGetMethodID(C, N, method(Tps,Tr), MID) + ), + assert(jpl_method_spec_cache(Tc,I,N,A,Mods,MID,Tr,Tps)), + fail + ; true + ). + +%------------------------------------------------------------------------------ + +:- dynamic jpl_method_spec_cache/8. + +%------------------------------------------------------------------------------ + +:- dynamic jpl_method_spec_is_cached/1. + +%------------------------------------------------------------------------------ + +% jpl_method_to_modifiers(+Method, -ModifierSet) :- + +jpl_method_to_modifiers(M, Ms) :- + jpl_classname_to_class('java.lang.reflect.Method', Cm), + jpl_method_to_modifiers_1(M, Cm, Ms). + +%------------------------------------------------------------------------------ + +%type jpl_method_to_modifiers_1(object, object, ordset(modifier)) + +% jpl_method_to_modifiers_1(+Method, +ConstructorClass, -ModifierSet) :- + +jpl_method_to_modifiers_1(XM, Cxm, Ms) :- + jGetMethodID(Cxm, getModifiers, method([],int), MID), + jCallIntMethod(XM, MID, [], [], I), + jpl_modifier_int_to_modifiers(I, Ms). + +%------------------------------------------------------------------------------ + +% jpl_method_to_name(+Method, -Name) :- + +jpl_method_to_name(M, N) :- + jpl_classname_to_class('java.lang.reflect.Method', CM), + jpl_method_to_name_1(M, CM, N). + +%------------------------------------------------------------------------------ + +jpl_method_to_name_1(M, CM, N) :- + jGetMethodID(CM, getName, method([],class([java,lang],['String'])), MID), + jCallObjectMethod(M, MID, [], [], N). + +%------------------------------------------------------------------------------ + +% jpl_method_to_parameter_types(+Method, -Types) :- + +jpl_method_to_parameter_types(M, Tps) :- + jpl_classname_to_class('java.lang.reflect.Method', Cm), + jpl_method_to_parameter_types_1(M, Cm, Tps). + +%------------------------------------------------------------------------------ + +jpl_method_to_parameter_types_1(XM, Cxm, Tps) :- + jGetMethodID(Cxm, getParameterTypes, method([],array(class([java,lang],['Class']))), MID), + jCallObjectMethod(XM, MID, [], [], Atp), + jpl_object_array_to_list(Atp, Ctps), + jpl_classes_to_types(Ctps, Tps). + +%------------------------------------------------------------------------------ + +% jpl_method_to_return_type(+Method, -Type) :- + +jpl_method_to_return_type(M, Tr) :- + jpl_classname_to_class('java.lang.reflect.Method', Cm), + jGetMethodID(Cm, getReturnType, method([],class([java,lang],['Class'])), MID), + jCallObjectMethod(M, MID, [], [], Cr), + jpl_class_to_type(Cr, Tr). + +%------------------------------------------------------------------------------ + +jpl_modifier_bit(public, 0x001). +jpl_modifier_bit(private, 0x002). +jpl_modifier_bit(protected, 0x004). +jpl_modifier_bit(static, 0x008). +jpl_modifier_bit(final, 0x010). +jpl_modifier_bit(synchronized, 0x020). +jpl_modifier_bit(volatile, 0x040). +jpl_modifier_bit(transient, 0x080). +jpl_modifier_bit(native, 0x100). +jpl_modifier_bit(interface, 0x200). +jpl_modifier_bit(abstract, 0x400). + +%------------------------------------------------------------------------------ + +%type jpl_modifier_int_to_modifiers(integer, ordset(modifier)) + +% jpl_modifier_int_to_modifiers(+Int, -ModifierSet) :- +% ModifierSet is an ordered (hence canonical) list, +% possibly empty (although I suspect never in practice?), +% of modifier atoms, e.g. [public,static] + +jpl_modifier_int_to_modifiers(I, Ms) :- + setof( + M, % should use e.g. set_of_all/3 + B^(jpl_modifier_bit(M, B), + (B /\ I) =\= 0 + ), + Ms + ). + +%------------------------------------------------------------------------------ + +% jpl_servlet_byref(+Config, +Request, +Response) :- + +jpl_servlet_byref(Config, Request, Response) :- + jpl_call(Config, getServletContext, [], Context), + + jpl_call(Response, setStatus, [200], _), + jpl_call(Response, setContentType, ['text/html'], _), + jpl_call(Response, getWriter, [], W), + + jpl_call(W, println, ['

    jpl_servlet_byref/3 says:

    '], _),
    +
    +    jpl_call(W, println, ['\nservlet context stuff:'], _),
    +
    +    jpl_call(Context, getInitParameterNames, [], ContextInitParameterNameEnum),
    +    jpl_enumeration_to_list(ContextInitParameterNameEnum, ContextInitParameterNames),
    +    length(ContextInitParameterNames, NContextInitParameterNames),
    +    concat_atom(['\tContext.InitParameters = ',NContextInitParameterNames], NContextInitParameterNamesMsg),
    +    jpl_call(W, println, [NContextInitParameterNamesMsg], _),
    +    (	member(ContextInitParameterName, ContextInitParameterNames),
    +	jpl_call(Context, getInitParameter, [ContextInitParameterName], ContextInitParameter),
    +	concat_atom(['\t\tContext.InitParameter[',ContextInitParameterName,'] = ',ContextInitParameter], ContextInitParameterMsg),
    +	jpl_call(W, println, [ContextInitParameterMsg], _),
    +	fail
    +    ;	true
    +    ),
    +
    +    jpl_call(Context, getMajorVersion, [], MajorVersion),
    +    concat_atom(['\tContext.MajorVersion = ',MajorVersion], MajorVersionMsg),
    +    jpl_call(W, println, [MajorVersionMsg], _),
    +
    +    jpl_call(Context, getMinorVersion, [], MinorVersion),
    +    concat_atom(['\tContext.MinorVersion = ',MinorVersion], MinorVersionMsg),
    +    jpl_call(W, println, [MinorVersionMsg], _),
    +
    +    jpl_call(Context, getServerInfo, [], ServerInfo),
    +    concat_atom(['\tContext.ServerInfo = ',ServerInfo], ServerInfoMsg),
    +    jpl_call(W, println, [ServerInfoMsg], _),
    +
    +    jpl_call(W, println, ['\nservlet config stuff:'], _),
    +
    +    jpl_call(Config, getServletName, [], ServletName),
    +    (	ServletName == @(null)
    +    ->	ServletNameAtom = null
    +    ;	ServletNameAtom = ServletName
    +    ),
    +    concat_atom(['\tConfig.ServletName = ',ServletNameAtom], ServletNameMsg),
    +    jpl_call(W, println, [ServletNameMsg], _),
    +
    +    jpl_call(Config, getInitParameterNames, [], ConfigInitParameterNameEnum),
    +    jpl_enumeration_to_list(ConfigInitParameterNameEnum, ConfigInitParameterNames),
    +    length(ConfigInitParameterNames, NConfigInitParameterNames),
    +    concat_atom(['\tConfig.InitParameters = ',NConfigInitParameterNames], NConfigInitParameterNamesMsg),
    +    jpl_call(W, println, [NConfigInitParameterNamesMsg], _),
    +    (	member(ConfigInitParameterName, ConfigInitParameterNames),
    +	jpl_call(Config, getInitParameter, [ConfigInitParameterName], ConfigInitParameter),
    +	concat_atom(['\t\tConfig.InitParameter[',ConfigInitParameterName,'] = ',ConfigInitParameter], ConfigInitParameterMsg),
    +	jpl_call(W, println, [ConfigInitParameterMsg], _),
    +	fail
    +    ;	true
    +    ),
    +
    +    jpl_call(W, println, ['\nrequest stuff:'], _),
    +
    +    jpl_call(Request, getAttributeNames, [], AttributeNameEnum),
    +    jpl_enumeration_to_list(AttributeNameEnum, AttributeNames),
    +    length(AttributeNames, NAttributeNames),
    +    concat_atom(['\tRequest.Attributes = ',NAttributeNames], NAttributeNamesMsg),
    +    jpl_call(W, println, [NAttributeNamesMsg], _),
    +    (	member(AttributeName, AttributeNames),
    +	jpl_call(Request, getAttribute, [AttributeName], Attribute),
    +	jpl_call(Attribute, toString, [], AttributeString),
    +	concat_atom(['\t\tRequest.Attribute[',AttributeName,'] = ',AttributeString], AttributeMsg),
    +	jpl_call(W, println, [AttributeMsg], _),
    +	fail
    +    ;	true
    +    ),
    +
    +    jpl_call(Request, getCharacterEncoding, [], CharacterEncoding),
    +    (	CharacterEncoding == @(null)
    +    ->	CharacterEncodingAtom = ''
    +    ;	CharacterEncodingAtom = CharacterEncoding
    +    ),
    +    concat_atom(['\tRequest.CharacterEncoding',' = ',CharacterEncodingAtom], CharacterEncodingMsg),
    +    jpl_call(W, println, [CharacterEncodingMsg], _),
    +
    +    jpl_call(Request, getContentLength, [], ContentLength),
    +    concat_atom(['\tRequest.ContentLength',' = ',ContentLength], ContentLengthMsg),
    +    jpl_call(W, println, [ContentLengthMsg], _),
    +
    +    jpl_call(Request, getContentType, [], ContentType),
    +    (	ContentType == @(null)
    +    ->	ContentTypeAtom = ''
    +    ;	ContentTypeAtom = ContentType
    +    ),
    +    concat_atom(['\tRequest.ContentType',' = ',ContentTypeAtom], ContentTypeMsg),
    +    jpl_call(W, println, [ContentTypeMsg], _),
    +
    +    jpl_call(Request, getParameterNames, [], ParameterNameEnum),
    +    jpl_enumeration_to_list(ParameterNameEnum, ParameterNames),
    +    length(ParameterNames, NParameterNames),
    +    concat_atom(['\tRequest.Parameters = ',NParameterNames], NParameterNamesMsg),
    +    jpl_call(W, println, [NParameterNamesMsg], _),
    +    (	member(ParameterName, ParameterNames),
    +	jpl_call(Request, getParameter, [ParameterName], Parameter),
    +	concat_atom(['\t\tRequest.Parameter[',ParameterName,'] = ',Parameter], ParameterMsg),
    +	jpl_call(W, println, [ParameterMsg], _),
    +	fail
    +    ;	true
    +    ),
    +
    +    jpl_call(Request, getProtocol, [], Protocol),
    +    concat_atom(['\tRequest.Protocol',' = ',Protocol], ProtocolMsg),
    +    jpl_call(W, println, [ProtocolMsg], _),
    +
    +    jpl_call(Request, getRemoteAddr, [], RemoteAddr),
    +    concat_atom(['\tRequest.RemoteAddr',' = ',RemoteAddr], RemoteAddrMsg),
    +    jpl_call(W, println, [RemoteAddrMsg], _),
    +
    +    jpl_call(Request, getRemoteHost, [], RemoteHost),
    +    concat_atom(['\tRequest.RemoteHost',' = ',RemoteHost], RemoteHostMsg),
    +    jpl_call(W, println, [RemoteHostMsg], _),
    +
    +    jpl_call(Request, getScheme, [], Scheme),
    +    concat_atom(['\tRequest.Scheme',' = ',Scheme], SchemeMsg),
    +    jpl_call(W, println, [SchemeMsg], _),
    +
    +    jpl_call(Request, getServerName, [], ServerName),
    +    concat_atom(['\tRequest.ServerName',' = ',ServerName], ServerNameMsg),
    +    jpl_call(W, println, [ServerNameMsg], _),
    +
    +    jpl_call(Request, getServerPort, [], ServerPort),
    +    concat_atom(['\tRequest.ServerPort',' = ',ServerPort], ServerPortMsg),
    +    jpl_call(W, println, [ServerPortMsg], _),
    +
    +    jpl_call(Request, isSecure, [], @(Secure)),
    +    concat_atom(['\tRequest.Secure',' = ',Secure], SecureMsg),
    +    jpl_call(W, println, [SecureMsg], _),
    +
    +    jpl_call(W, println, ['\nHTTP request stuff:'], _),
    +
    +    jpl_call(Request, getAuthType, [], AuthType),
    +    (	AuthType == @(null)
    +    ->	AuthTypeAtom = ''
    +    ;	AuthTypeAtom = AuthType
    +    ),
    +    concat_atom(['\tRequest.AuthType',' = ',AuthTypeAtom], AuthTypeMsg),
    +    jpl_call(W, println, [AuthTypeMsg], _),
    +
    +    jpl_call(Request, getContextPath, [], ContextPath),
    +    (	ContextPath == @(null)
    +    ->	ContextPathAtom = ''
    +    ;	ContextPathAtom = ContextPath
    +    ),
    +    concat_atom(['\tRequest.ContextPath',' = ',ContextPathAtom], ContextPathMsg),
    +    jpl_call(W, println, [ContextPathMsg], _),
    +
    +    jpl_call(Request, getCookies, [], CookieArray),
    +    (	CookieArray == @(null)
    +    ->	Cookies = []
    +    ;	jpl_array_to_list(CookieArray, Cookies)
    +    ),
    +    length(Cookies, NCookies),
    +    concat_atom(['\tRequest.Cookies',' = ',NCookies], NCookiesMsg),
    +    jpl_call(W, println, [NCookiesMsg], _),
    +    (	nth0(NCookie, Cookies, Cookie),
    +	concat_atom(['\t\tRequest.Cookie[',NCookie,']'], CookieMsg),
    +	jpl_call(W, println, [CookieMsg], _),
    +
    +	jpl_call(Cookie, getName, [], CookieName),
    +	concat_atom(['\t\t\tRequest.Cookie.Name = ',CookieName], CookieNameMsg),
    +	jpl_call(W, println, [CookieNameMsg], _),
    +
    +	jpl_call(Cookie, getValue, [], CookieValue),
    +	concat_atom(['\t\t\tRequest.Cookie.Value = ',CookieValue], CookieValueMsg),
    +	jpl_call(W, println, [CookieValueMsg], _),
    +
    +	jpl_call(Cookie, getPath, [], CookiePath),
    +	(   CookiePath == @(null)
    +	->  CookiePathAtom = ''
    +	;   CookiePathAtom = CookiePath
    +	),
    +	concat_atom(['\t\t\tRequest.Cookie.Path = ',CookiePathAtom], CookiePathMsg),
    +	jpl_call(W, println, [CookiePathMsg], _),
    +
    +	jpl_call(Cookie, getComment, [], CookieComment),
    +	(   CookieComment == @(null)
    +	->  CookieCommentAtom = ''
    +	;   CookieCommentAtom = CookieComment
    +	),
    +	concat_atom(['\t\t\tRequest.Cookie.Comment = ',CookieCommentAtom], CookieCommentMsg),
    +	jpl_call(W, println, [CookieCommentMsg], _),
    +
    +	jpl_call(Cookie, getDomain, [], CookieDomain),
    +	(   CookieDomain == @(null)
    +	->  CookieDomainAtom = ''
    +	;   CookieDomainAtom = CookieDomain
    +	),
    +	concat_atom(['\t\t\tRequest.Cookie.Domain = ',CookieDomainAtom], CookieDomainMsg),
    +	jpl_call(W, println, [CookieDomainMsg], _),
    +
    +	jpl_call(Cookie, getMaxAge, [], CookieMaxAge),
    +	concat_atom(['\t\t\tRequest.Cookie.MaxAge = ',CookieMaxAge], CookieMaxAgeMsg),
    +	jpl_call(W, println, [CookieMaxAgeMsg], _),
    +
    +	jpl_call(Cookie, getVersion, [], CookieVersion),
    +	concat_atom(['\t\t\tRequest.Cookie.Version = ',CookieVersion], CookieVersionMsg),
    +	jpl_call(W, println, [CookieVersionMsg], _),
    +
    +	jpl_call(Cookie, getSecure, [], @(CookieSecure)),
    +	concat_atom(['\t\t\tRequest.Cookie.Secure',' = ',CookieSecure], CookieSecureMsg),
    +	jpl_call(W, println, [CookieSecureMsg], _),
    +
    +	fail
    +    ;	true
    +    ),
    +
    +    jpl_call(W, println, ['
    '], _), + + true. + +%------------------------------------------------------------------------------ + +jpl_servlet_byval(MM, CT, Ba) :- + CT = 'text/html', + multimap_to_atom(MM, MMa), + concat_atom(['', + '

    jpl_servlet_byval/3 says:

    ',
    +		     MMa,
    +		     '
    ' + ], Ba). + +%------------------------------------------------------------------------------ + +%type jpl_cache_type_of_ref(jpl_type, ref) + +% jpl_cache_type_of_ref(+Type, +Ref) :- +% Type must be a proper JPL type; +% Ref must be a proper JPL reference (not void); +% Type is memoed as the type of the referenced object (unless it's null) +% by iref (so as not to disable atom-based GC) +% NB obsolete lemmas must be watched-out-for and removed + +jpl_cache_type_of_ref(T, @(Tag)) :- + ( \+ ground(T) + -> write('[jpl_cache_type_of_ref/2: arg 1 is not ground]'), nl, + fail + ; \+ atom(Tag) + -> write('[jpl_cache_type_of_ref/2: arg 2 is not an atomic-tag ref]'), nl, + fail + ; Tag == null + -> true % silently ignore null refs + ; jni_tag_to_iref(Tag, Iref) + -> ( jpl_iref_type_cache(Iref, TC) % assume TC == T + -> ( T == TC + -> true + ; % write('[JPL: found obsolete tag-type lemma...]'), nl, % keep statistics? (why?) + retractall(jpl_iref_type_cache(Iref,_)), + assert(jpl_iref_type_cache(Iref,T)) + ) + ; assert(jpl_iref_type_cache(Iref,T)) + ) + ; write('[jpl_cache_type_of_ref/2: jni_tagatom_to_iref(Tag,_) failed]'), nl, + fail + ). + +%------------------------------------------------------------------------------ + +% jpl_class_tag_type_cache(-Tag, -ClassType) :- +% Tag is the tag part of an @Tag reference +% to a JVM instance of java.lang.Class +% which denotes ClassType; +% we index on Tag rather than on Iref so as to keep these objects around +% even after an atom garbage collection +% (if needed once, they are likely to be needed again) + +:- dynamic jpl_class_tag_type_cache/2. + +%------------------------------------------------------------------------------ + +% jpl_class_to_ancestor_classes(+Class, -AncestorClasses) :- + +jpl_class_to_ancestor_classes(C, Cas) :- + ( jpl_class_to_super_class(C, Ca) + -> Cas = [Ca|Cas2], + jpl_class_to_ancestor_classes(Ca, Cas2) + ; Cas = [] + ). + +%------------------------------------------------------------------------------ + +% jpl_class_to_classname(+Class, -ClassName) :- +% Class is a reference to a class object; +% ClassName is its canonical (?) source-syntax (dotted) name, +% e.g. 'java.util.Date' +% not used outside jni_junk and jpl_test; +% oughta use the available caches... + +jpl_class_to_classname(C, CN) :- + jpl_call(C, getName, [], CN). + +%------------------------------------------------------------------------------ + +% jpl_class_to_raw_classname(+Class, -ClassName) :- + +jpl_class_to_raw_classname(Cobj, CN) :- + jpl_classname_to_class('java.lang.Class', CC), % cached? + jGetMethodID(CC, getName, method([],class([java,lang],['String'])), MIDgetName), + jCallObjectMethod(Cobj, MIDgetName, [], [], S), + S = CN. + +%------------------------------------------------------------------------------ + +% jpl_class_to_raw_classname_chars(+Class, -ClassnameChars) :- +% Class is a reference to a class object; +% ClassnameChars is a chars representation of its dotted name, e.g. +% "java.util.Date" + +jpl_class_to_raw_classname_chars(Cobj, CsCN) :- + jpl_class_to_raw_classname(Cobj, CN), + atom_codes(CN, CsCN). + +%------------------------------------------------------------------------------ + +jpl_class_to_super_class(C, Cx) :- + jGetSuperclass(C, Cx), + Cx \== @(null), % as returned when C is java.lang.Object, i.e. no superclass + jpl_cache_type_of_ref(class([java,lang],['Class']), Cx). + +%------------------------------------------------------------------------------ + +% jpl_class_to_type(+ClassObject, -Type) :- +% ClassObject is a reference to a class object of Type +% NB should ensure that, if not found in cache, then cache is updated; +% intriguingly (?), getParameterTypes returns class objects with names +% 'boolean', 'byte' etc. and even 'void' (?!) + +jpl_class_to_type(@(Tag), Type) :- + ( jpl_class_tag_type_cache(Tag, Tx) + -> true + ; jpl_class_to_raw_classname_chars(@(Tag), Cs), % uncached + jpl_classname_chars_to_type(Cs, Tr), + jpl_type_to_canonical_type(Tr, Tx), + assert(jpl_class_tag_type_cache(Tag,Tx)) + -> true % the elseif goal should be determinate, but just in case... + ), + Type = Tx. + +%------------------------------------------------------------------------------ + +jpl_classes_to_types([], []). + +jpl_classes_to_types([C|Cs], [T|Ts]) :- + jpl_class_to_type(C, T), + jpl_classes_to_types(Cs, Ts). + +%------------------------------------------------------------------------------ + +jpl_classname_chars_to_type(Cs, Type) :- + ( phrase(jpl_type_classname_1(Type), Cs) + -> true + ). + +%------------------------------------------------------------------------------ + +% jpl_classname_to_class(+ClassName, -Class) :- +% ClassName unambiguously represents a class, +% e.g. 'java.lang.String' +% Class is a (canonical) reference to the corresponding class object + +jpl_classname_to_class(N, C) :- + jpl_classname_to_type(N, T), % cached + jpl_type_to_class(T, C). + +%------------------------------------------------------------------------------ + +% jpl_classname_to_type(+Classname, -Type) :- +% Classname is a source-syntax (dotted) class name, +% e.g. 'java.util.Date', '[java.util.Date' or '[L' +% Type is its corresponding JPL type structure, +% e.g. class([java,util],['Date']), array(class([java,util],['Date'])), ... + +jpl_classname_to_type(CN, T) :- + ( jpl_classname_type_cache(CN, Tx) + -> Tx = T + ; atom_codes(CN, CsCN), + phrase(jpl_type_classname_1(T), CsCN) + -> assert(jpl_classname_type_cache(CN,T)), + true + ). + +%------------------------------------------------------------------------------ + +:- dynamic jpl_classname_type_cache/2. + +%------------------------------------------------------------------------------ + +% jpl_datum_to_type(+Datum, -Type) :- +% Datum must be a proper JPL representation +% of an instance of one (or more) Java types; +% Type is the unique most specialised type of which Datum denotes an instance; +% N.B. 3 is an instance of byte, char, short, int and long, +% of which byte and char are the joint, overlapping most specialised types, +% so this relates 3 to the pseudo subtype 'char_byte' + +jpl_datum_to_type(D, T) :- + ( jpl_value_to_type(D, T) + -> true + ; jpl_ref_to_type(D, T) + ). + +%------------------------------------------------------------------------------ + +jpl_datums_to_most_specific_common_ancestor_type([D], T) :- + jpl_datum_to_type(D, T). + +jpl_datums_to_most_specific_common_ancestor_type([D1,D2|Ds], T0) :- + jpl_datum_to_type(D1, T1), + jpl_type_to_ancestor_types(T1, Ts1), + jpl_datums_to_most_specific_common_ancestor_type_1([D2|Ds], [T1|Ts1], [T0|_]). + +%------------------------------------------------------------------------------ + +jpl_datums_to_most_specific_common_ancestor_type_1([], Ts, Ts). + +jpl_datums_to_most_specific_common_ancestor_type_1([D|Ds], Ts1, Ts0) :- + jpl_datum_to_type(D, Tx), + jpl_lineage_types_type_to_common_lineage_types(Ts1, Tx, Ts2), + jpl_datums_to_most_specific_common_ancestor_type_1(Ds, Ts2, Ts0). + +%------------------------------------------------------------------------------ + +% jpl_datums_to_types(+Datums, -Types) :- +% each member of Datums is a JPL value or ref, +% denoting an instance of some Java type, +% and the corresponding member of Types denotes the most specialised type +% of which it is an instance (including some I invented for the overlaps +% between char and short, etc,) + +jpl_datums_to_types([], []). + +jpl_datums_to_types([D|Ds], [T|Ts]) :- + jpl_datum_to_type(D, T), + jpl_datums_to_types(Ds, Ts). + +%------------------------------------------------------------------------------ + +% jpl_false(-X) :- +% X is (by unification) the proper JPL datum which represents the Java value 'false' +% c.f. jpl_is_false/1 + +jpl_false(@(false)). + +%------------------------------------------------------------------------------ + +% jpl_ground_is_type(+X) :- +% X, known to be ground, is (or at least superficially resembles :-) a JPL type + +jpl_ground_is_type(X) :- + jpl_primitive_type(X), + !. + +jpl_ground_is_type(array(X)) :- + jpl_ground_is_type(X). + +jpl_ground_is_type(class(_,_)). + +jpl_ground_is_type(method(_,_)). + +%------------------------------------------------------------------------------ + +:- dynamic jpl_iref_type_cache/2. + +%------------------------------------------------------------------------------ + +% jpl_is_class(?X) :- +% X is a JPL ref to a java.lang.Class object + +jpl_is_class(X) :- + jpl_is_object(X), + jpl_object_to_type(X, class([java,lang],['Class'])). + +%------------------------------------------------------------------------------ + +% jpl_is_false(?X) :- +% X is the proper JPL datum which represents the Java value 'false'; +% whatever, no further instantiation of X occurs + +jpl_is_false(X) :- + X == @(false). + +%------------------------------------------------------------------------------ + +% jpl_is_fieldID(?X) :- +% X is a proper JPL field ID structure (jfieldID/1); +% applications should not be messing with these (?); +% whatever, no further instantiation of X occurs + +jpl_is_fieldID(jfieldID(X)) :- % NB a var arg may get bound... + integer(X). + +%------------------------------------------------------------------------------ + +% jpl_is_methodID(?X) :- +% X is a proper JPL method ID structure (jmethodID/1); +% applications should not be messing with these (?); +% whatever, no further instantiation of X occurs + +jpl_is_methodID(jmethodID(X)) :- % NB a var arg may get bound... + integer(X). + +%------------------------------------------------------------------------------ + +% jpl_is_null(?X) :- +% X is the proper JPL datum which represents Java's 'null' reference; +% whatever, no further instantiation of X occurs + +jpl_is_null(X) :- + X == @(null). + +%------------------------------------------------------------------------------ + +% jpl_is_object(?X) :- +% X is a proper, plausible JPL object reference; +% NB this checks only syntax, not whether the object exists; +% whatever, no further instantiation of X occurs + +jpl_is_object(X) :- + jpl_is_ref(X), % (syntactically, at least...) + X \== @(null). + +%------------------------------------------------------------------------------ + +% jpl_is_object_type(+T) :- +% T is an object (class or array) type, +% not e.g. a primitive, null or void + +jpl_is_object_type(T) :- + \+ var(T), + jpl_non_var_is_object_type(T). + +%------------------------------------------------------------------------------ + +% jpl_is_ref(?T) :- +% the arbitrary term T is a proper, syntactically plausible JPL reference, +% either to a Java object +% (which may not exist, although a jpl_is_current_ref/1 might be useful) +% or to Java's notional but important 'null' non-object; +% whatever, no further instantiation of X occurs; +% NB to distinguish tags from void/false/true, +% could check initial character(s) or length? or adopt strong/weak scheme... + +jpl_is_ref(@(Y)) :- + atom(Y), % presumably a (garbage-collectable) tag + Y \== void, % not a ref + Y \== false, % not a ref + Y \== true. % not a ref + +%------------------------------------------------------------------------------ + +% jpl_is_true(?X) :- +% X is a proper JPL datum, representing the Java value 'true'; +% whatever, no further instantiation of X occurs + +jpl_is_true(X) :- + X == @(true). + +%------------------------------------------------------------------------------ + +% jpl_is_type(+X) :- + +jpl_is_type(X) :- + ground(X), + jpl_ground_is_type(X). + +%------------------------------------------------------------------------------ + +% jpl_is_void(?X) :- +% X is the proper JPL datum which represents the pseudo Java value 'void' +% (which is returned by jpl_call/4 when invoked on void methods); +% NB you can try passing 'void' back to Java, but it won't ever be interested; +% whatever, no further instantiation of X occurs + +jpl_is_void(X) :- + X == @(void). + +%------------------------------------------------------------------------------ + +jpl_lineage_types_type_to_common_lineage_types(Ts, Tx, Ts0) :- + ( append(_, [Tx|Ts2], Ts) + -> [Tx|Ts2] = Ts0 + ; jpl_type_to_super_type(Tx, Tx2) + -> jpl_lineage_types_type_to_common_lineage_types(Ts, Tx2, Ts0) + ). + +%------------------------------------------------------------------------------ + +jpl_non_var_is_object_type(class(_,_)). + +jpl_non_var_is_object_type(array(_)). + +%------------------------------------------------------------------------------ + +% jpl_null(-X) :- +% X is (by unification) the proper JPL datum which represents the Java reference 'null'; +% c.f. jpl_is_null/1 + +jpl_null(@(null)). + +%------------------------------------------------------------------------------ + +% jpl_object_array_to_list(+ArrayObject, -Values) :- +% Values is a list of JPL values (primitive values or object references) +% representing the respective elements of ArrayObject + +jpl_object_array_to_list(A, Vs) :- + jpl_array_to_length(A, N), + jpl_object_array_to_list_1(A, 0, N, Vs). + +%------------------------------------------------------------------------------ + +% jpl_object_array_to_list_1(+A, +I, +N, -Xs) :- + +jpl_object_array_to_list_1(A, I, N, Xs) :- + ( I == N + -> Xs = [] + ; jGetObjectArrayElement(A, I, X), + Xs = [X|Xs2], + J is I+1, + jpl_object_array_to_list_1(A, J, N, Xs2) + ). + +%------------------------------------------------------------------------------ + +% jpl_object_to_class(+Object, -Class) :- +% Class is a (canonical) reference to the (canonical) class object +% which represents the (most specific) class of Object +% NB Object must be a valid object, else... +% NB wot's the point of caching the type if we don't look there first? + +jpl_object_to_class(Obj, C) :- + jGetObjectClass(Obj, C), + jpl_cache_type_of_ref(class([java,lang],['Class']), C). + +%------------------------------------------------------------------------------ + +% jpl_object_to_type(+Object, -Type) :- +% Object must be a proper JPL reference to a Java object +% (i.e. a class or array instance, but not null, void or String); +% Type is the JPL type of that object + +jpl_object_to_type(@(Tag), Type) :- + jpl_tag_to_type(Tag, Type). + +%------------------------------------------------------------------------------ + +jpl_object_type_to_super_type(T, Tx) :- + ( ( T = class(_,_) + ; T = array(_) + ) + -> jpl_type_to_class(T, C), + jpl_class_to_super_class(C, Cx), + Cx \== @(null), + jpl_class_to_type(Cx, Tx) + ). + +%------------------------------------------------------------------------------ + +% jpl_primitive_buffer_to_array(+Type, +Xc, +Bp, +I, +Size, -Vcs) :- +% Bp points to a buffer of (sufficient) Type values; +% Vcs will be unbound on entry, +% and on exit will be a list of Size of them, starting at index I +% (the buffer is indexed from zero) + +jpl_primitive_buffer_to_array(T, Xc, Bp, I, Size, [Vc|Vcs]) :- + jni_fetch_buffer_value(Bp, I, Xhi, Xlo, Xc), + jni_convert_primitive_in(T, Vc, Xhi, Xlo), + Ix is I+1, + ( Ix < Size + -> jpl_primitive_buffer_to_array(T, Xc, Bp, Ix, Size, Vcs) + ; Vcs = [] + ). + +%------------------------------------------------------------------------------ + +jpl_primitive_type(boolean). +jpl_primitive_type(char). +jpl_primitive_type(byte). +jpl_primitive_type(short). +jpl_primitive_type(int). +jpl_primitive_type(long). +jpl_primitive_type(float). +jpl_primitive_type(double). + +%------------------------------------------------------------------------------ + +% jpl_primitive_type_default_value(-Type, -Value) :- +% each element of any array of (primitive) Type created by jpl_new/3, +% or any instance of (primitive) Type created by jpl_new/3, +% should be initialised to Value (to mimic Java semantics) + +jpl_primitive_type_default_value(boolean, @(false)). +jpl_primitive_type_default_value(char, 0). +jpl_primitive_type_default_value(byte, 0). +jpl_primitive_type_default_value(short, 0). +jpl_primitive_type_default_value(int, 0). +jpl_primitive_type_default_value(long, 0). +jpl_primitive_type_default_value(float, 0.0). +jpl_primitive_type_default_value(double, 0.0). + +%------------------------------------------------------------------------------ + +jpl_primitive_type_super_type(T, Tx) :- + ( jpl_type_fits_type_direct_prim(T, Tx) + ; jpl_type_fits_type_direct_xtra(T, Tx) + ). + +%------------------------------------------------------------------------------ + +% jpl_primitive_type_term_to_value(+Type, +Term, -Val) :- +% Term, after widening iff appropriate, represents an instance of Type; +% Val is the instance of Type which it represents (often the same thing); +% currently used only by jpl_new_1 when creating an "instance" +% of a primitive type (which may be misguided completism - you can't +% do that in Java) + +jpl_primitive_type_term_to_value(Type, Term, Val) :- + ( jpl_primitive_type_term_to_value_1(Type, Term, Val) + -> true + ). + +%------------------------------------------------------------------------------ + +% jpl_primitive_type_term_to_value_1(+Type, +RawValue, -WidenedValue) :- +% I'm not worried about structure duplication here +% NB this oughta be done in foreign code... + +jpl_primitive_type_term_to_value_1(boolean, @(false), @(false)). + +jpl_primitive_type_term_to_value_1(boolean, @(true), @(true)). + +jpl_primitive_type_term_to_value_1(char, I, I) :- + integer(I), + I >= 0, + I =< 65535. + +jpl_primitive_type_term_to_value_1(byte, I, I) :- + integer(I), + I >= -128, + I =< 127. + +jpl_primitive_type_term_to_value_1(short, I, I) :- + integer(I), + I >= -32768, + I =< 32767. + +jpl_primitive_type_term_to_value_1(int, I, I) :- + integer(I). + +jpl_primitive_type_term_to_value_1(long, I, I) :- + integer(I). + +jpl_primitive_type_term_to_value_1(long, jlong(Xhi,Xlo), jlong(Xhi,Xlo)) :- + integer(Xhi), + integer(Xlo). + +jpl_primitive_type_term_to_value_1(float, I, F) :- + integer(I), + F is float(I). + +jpl_primitive_type_term_to_value_1(float, F, F) :- + float(F). + +jpl_primitive_type_term_to_value_1(double, I, F) :- + integer(I), + F is float(I). + +jpl_primitive_type_term_to_value_1(double, F, F) :- + float(F). + +%------------------------------------------------------------------------------ + +jpl_primitive_type_to_ancestor_types(T, Ts) :- + ( jpl_primitive_type_super_type(T, Ta) + -> Ts = [Ta|Tas], + jpl_primitive_type_to_ancestor_types(Ta, Tas) + ; Ts = [] + ). + +%------------------------------------------------------------------------------ + +jpl_primitive_type_to_super_type(T, Tx) :- + jpl_primitive_type_super_type(T, Tx). + +%------------------------------------------------------------------------------ + +% jpl_ref_to_type(+Ref, -Type) :- +% Ref must be a proper JPL reference (to an object, null or void); +% Type is its type + +jpl_ref_to_type(@(X), T) :- + ( X == null + -> T = null + ; X == void + -> T = void + ; jpl_tag_to_type(X, T) + ). + +%------------------------------------------------------------------------------ + +% jpl_tag_to_type(+Tag, -Type) :- +% Tag must be an (atomic) object tag; +% Type is its type (either from the cache or by reflection); + +jpl_tag_to_type(Tag, Type) :- + jni_tag_to_iref(Tag, Iref), + ( jpl_iref_type_cache(Iref, T) + -> true % T is Tag's type + ; jpl_object_to_class(@(Tag), Cobj), % else get ref to class obj + jpl_class_to_type(Cobj, T), % get type of class it denotes + assert(jpl_iref_type_cache(Iref,T)) + ), + Type = T. + +%------------------------------------------------------------------------------ + +% jpl_true(-X) :- +% X is (by unification) the proper JPL datum which represents the Java value 'true'; +% c.f. jpl_is_true/1 + +jpl_true(@(true)). + +%------------------------------------------------------------------------------ + +jpl_type_fits_type(Tx, Ty) :- + ( jpl_type_fits_type_1(Tx, Ty) + -> true + ). + +%------------------------------------------------------------------------------ + +% jpl_type_fits_type_1(+T1, +T2) :- +% it doesn't matter that this leaves choicepoints; it serves only jpl_type_fits_type/2 + +jpl_type_fits_type_1(T, T). + +jpl_type_fits_type_1(class(Ps1,Cs1), class(Ps2,Cs2)) :- + jpl_type_to_class(class(Ps1,Cs1), C1), + jpl_type_to_class(class(Ps2,Cs2), C2), + jIsAssignableFrom(C1, C2). + +jpl_type_fits_type_1(array(T1), class(Ps2,Cs2)) :- + jpl_type_to_class(array(T1), C1), + jpl_type_to_class(class(Ps2,Cs2), C2), + jIsAssignableFrom(C1, C2). + +jpl_type_fits_type_1(array(T1), array(T2)) :- + jpl_type_to_class(array(T1), C1), + jpl_type_to_class(array(T2), C2), + jIsAssignableFrom(C1, C2). + +jpl_type_fits_type_1(null, class(_,_)). + +jpl_type_fits_type_1(null, array(_)). + +jpl_type_fits_type_1(T1, T2) :- + jpl_type_fits_type_xprim(T1, T2). + +%------------------------------------------------------------------------------ + +jpl_type_fits_type_direct_prim(float, double). +jpl_type_fits_type_direct_prim(long, float). +jpl_type_fits_type_direct_prim(int, long). +jpl_type_fits_type_direct_prim(char, int). +jpl_type_fits_type_direct_prim(short, int). +jpl_type_fits_type_direct_prim(byte, short). + +%------------------------------------------------------------------------------ + +jpl_type_fits_type_direct_xprim(Tp, Tq) :- + jpl_type_fits_type_direct_prim(Tp, Tq). + +jpl_type_fits_type_direct_xprim(Tp, Tq) :- + jpl_type_fits_type_direct_xtra(Tp, Tq). + +%------------------------------------------------------------------------------ + +% jpl_type_fits_type_direct_xtra(pos_int, int). + jpl_type_fits_type_direct_xtra(char_int, int). + jpl_type_fits_type_direct_xtra(char_int, char). + jpl_type_fits_type_direct_xtra(char_short, short). + jpl_type_fits_type_direct_xtra(char_short, char). + jpl_type_fits_type_direct_xtra(char_byte, byte). + jpl_type_fits_type_direct_xtra(char_byte, char). +% jpl_type_fits_type_direct_xtra(neg_byte, byte). +% jpl_type_fits_type_direct_xtra(neg_short, short). +% jpl_type_fits_type_direct_xtra(neg_int, int). + +%------------------------------------------------------------------------------ + +% jpl_type_fits_type_xprim(-Tp, -T) :- +% indeterminate: serves only jpl_type_fits_type_1/2 + +jpl_type_fits_type_xprim(Tp, T) :- + jpl_type_fits_type_direct_xprim(Tp, Tq), + ( Tq = T + ; jpl_type_fits_type_xprim(Tq, T) + ). + +%------------------------------------------------------------------------------ + +% jpl_type_to_ancestor_types(+T, -Tas) :- +% this fails to accommodate the assignability of null... + +jpl_type_to_ancestor_types(T, Tas) :- + ( ( T = class(_,_) + ; T = array(_) + ) + -> jpl_type_to_class(T, C), + jpl_class_to_ancestor_classes(C, Cas), + jpl_classes_to_types(Cas, Tas) + ; jpl_primitive_type_to_ancestor_types(T, Tas) + -> true + ). + +%------------------------------------------------------------------------------ + +jpl_type_to_canonical_type(array(T), array(Tc)) :- + !, + jpl_type_to_canonical_type(T, Tc). + +jpl_type_to_canonical_type(class([],[void]), void) :- + !. + +jpl_type_to_canonical_type(class([],[N]), N) :- + jpl_primitive_type(N), + !. + +jpl_type_to_canonical_type(class(Ps,Cs), class(Ps,Cs)) :- + !. + +jpl_type_to_canonical_type(void, void) :- + !. + +jpl_type_to_canonical_type(P, P) :- + jpl_primitive_type(P). + +%------------------------------------------------------------------------------ + +% jpl_type_to_class(+Type, -ClassObject) :- +% incomplete types are now never cached (or otherwise passed around), +% but we check anyway (?) +% jFindClass throws an exception if FCN can't be found + +jpl_type_to_class(T, @(Tag)) :- + ground(T), + ( jpl_class_tag_type_cache(ClassTag,T) + -> Tag = ClassTag + ; ( jpl_type_to_findclassname(T, FCN) % peculiar syntax for FindClass() + -> jFindClass(FCN, @(ClassTag)), % which caches type of @ClassTag + jpl_cache_type_of_ref(T, @(ClassTag)) + ), + assert(jpl_class_tag_type_cache(ClassTag,T)) + ), + Tag = ClassTag. + +%------------------------------------------------------------------------------ + +%eg jpl_type_to_classname(class([java,util],['Date']), 'java.util.Date') + +% jpl_type_to_classname(+Type, -ClassName) :- +% Type, which is a class or array type (not sure about the others...), +% is denoted by ClassName in dotted syntax + +jpl_type_to_classname(T, CN) :- + ( phrase(jpl_type_classname_1(T), Cs) + -> atom_codes(CNx, Cs), % green commit to first solution + CN = CNx + ). + +%------------------------------------------------------------------------------ + +% jpl_type_to_descriptor(+Type, -Descriptor) :- +% Type (denoting any Java type, and can also be a JPL method/2 structure) +% is represented by Descriptor (JVM internal syntax) +% I'd cache this, but I'd prefer more efficient indexing on types (hashed?) + +jpl_type_to_descriptor(T, D) :- + ( phrase(jpl_type_descriptor_1(T), Cs) + -> atom_codes(Dx, Cs), + D = Dx + ). + +%------------------------------------------------------------------------------ + +% jpl_type_to_findclassname(+Type, -FindClassName) :- +% FindClassName denotes Type (class or array only) +% in the syntax required peculiarly by FindClass() + +jpl_type_to_findclassname(T, FCN) :- + ( phrase(jpl_type_findclassname(T), Cs) + -> atom_codes(FCNx, Cs), + FCN = FCNx + ). + +%------------------------------------------------------------------------------ + +jpl_type_to_super_type(T, Tx) :- + ( jpl_object_type_to_super_type(T, Tx) + -> true + ; jpl_primitive_type_to_super_type(T, Tx) + -> true + ). + +%------------------------------------------------------------------------------ + +% jpl_types_fit_type(+Types, +Type) :- +% each member of Types is (independently) (if that means anything) +% assignable to Type +% e.g. for dynamic type check when attempting to assign list of values to array + +jpl_types_fit_type([], _). + +jpl_types_fit_type([T1|T1s], T2) :- + jpl_type_fits_type(T1, T2), + jpl_types_fit_type(T1s, T2). + +%------------------------------------------------------------------------------ + +jpl_types_fit_types([], []). + +jpl_types_fit_types([T1|T1s], [T2|T2s]) :- + jpl_type_fits_type(T1, T2), + jpl_types_fit_types(T1s, T2s). + +%------------------------------------------------------------------------------ + +% jpl_value_to_type(+Value, -Type) :- +% Value must be a proper JPL datum other than a ref +% i.e. primitive, String or void; +% it is of (unique most specific) Type + +jpl_value_to_type(V, T) :- + ground(V), % critically assumed by jpl_value_to_type_1/2 + ( jpl_value_to_type_1(V, Tv) % 2nd arg must be unbound + -> T = Tv + ). + +%------------------------------------------------------------------------------ + +% jpl_value_to_type_1(+Value, -Type) :- +% Type is the unique most specific JPL type of which Value represents an instance; +% called solely by jpl_value_to_type/2, which commits to first solution; +% +% NB integer values are of JPL-peculiar uniquely most specific subtypes, +% i.e. char_byte, char_short, char_int, pos_int, neg_byte, neg_short, neg_int +% but all are understood by the JPL-internal utilities which call this proc +% +% NB could replace +% {pos_int,neg_int} -> proper_int (or int?) +% neg_byte -> proper_byte (or byte?) +% neg_short -> proper_short (or short?) +% +% NB we regard float as subtype of double +% +% NB objects and refs always have straightforward types + +jpl_value_to_type_1(@(false), boolean). + +jpl_value_to_type_1(@(true), boolean). + +jpl_value_to_type_1(jlong(_,_), long). % discrimination, not validation + +jpl_value_to_type_1(A, class([java,lang],['String'])) :- % yes it's a "value" + atom(A). + +jpl_value_to_type_1(I, T) :- + integer(I), + ( I >= 0 -> ( I < 128 -> T = char_byte + ; I < 32768 -> T = char_short + ; I < 65536 -> T = char_int + ; T = int % was pos_int + ) + ; I >= -128 -> T = byte % was neg_byte + ; I >= -32768 -> T = short % was neg_short + ; T = int % was neg_int + ). + +jpl_value_to_type_1(F, float) :- + float(F). + +%------------------------------------------------------------------------------ + +% jpl_void(-X) :- +% X is (by unification) the proper JPL datum which represents the pseudo Java value 'void'; +% c.f. jpl_is_void/1 + +jpl_void(@(void)). + +%------------------------------------------------------------------------------ + +%type jpl_array_to_length(array, integer) + +% jpl_array_to_length(+ArrayObject, -Length) :- +% must validate ArrayObject before making the JNI call... + +jpl_array_to_length(A, N) :- + ( jpl_ref_to_type(A, array(_)) % can this be done cheaper e.g. in foreign code? + -> jGetArrayLength(A, N) % *must* be array, else undefined (crash?) + ). + +%------------------------------------------------------------------------------ + +%type jpl_array_to_list(array, list(datum)) + +% jpl_array_to_list(+Array, -Elements) :- + +jpl_array_to_list(A, Es) :- + jpl_array_to_length(A, Len), + ( Len > 0 + -> LoBound is 0, + HiBound is Len-1, + jpl_get(A, LoBound-HiBound, Es) + ; Es = [] + ). + +%------------------------------------------------------------------------------ + +%type jpl_datums_to_array(list(datum), array) + +% jpl_datums_to_array(+Ds, -A) :- +% A will be a ref to a new JVM array, +% whose base type is the most specific Java type +% of which each member of Datums is (directly or indirectly) an instance; +% NB this fails (without warning, currently) if: +% Ds is an empty list (no base type can be inferred) +% Ds contains a primitive value and an object or array ref (no common supertype) + +jpl_datums_to_array(Ds, A) :- + ground(Ds), + jpl_datums_to_most_specific_common_ancestor_type(Ds, T), + jpl_new(array(T), Ds, A). + +%------------------------------------------------------------------------------ + +%type jpl_enumeration_element(object, datum) + +% jpl_enumeration_element(+Enumeration, -Element) :- +% generates each Element from the Enumeration + +jpl_enumeration_element(En, E) :- + ( jpl_call(En, hasMoreElements, [], @(true)) + -> jpl_call(En, nextElement, [], Ex), + ( E = Ex + ; jpl_enumeration_element(En, E) + ) + ). + +%------------------------------------------------------------------------------ + +%type jpl_enumeration_to_list(object, list(datum)) + +% jpl_enumeration_to_list(+Enumeration, -Elements) :- + +jpl_enumeration_to_list(EN, Es) :- + ( jpl_call(EN, hasMoreElements, [], @(true)) + -> jpl_call(EN, nextElement, [], E), + Es = [E|Es1], + jpl_enumeration_to_list(EN, Es1) + ; Es = [] + ). + +%------------------------------------------------------------------------------ + +%type jpl_hashtable_pair(object, pair(datum,datum)) + +% jpl_hashtable_pair(+HashTable, -KeyValuePair) :- +% generates Key-Value pairs from the given HashTable +% NB String is converted to atom but Integer is presumably returned as an object ref + +jpl_hashtable_pair(HT, K-V) :- + jpl_call(HT, keys, [], Ek), + jpl_enumeration_to_list(Ek, Ks), + member(K, Ks), + jpl_call(HT, get, [K], V). + +%------------------------------------------------------------------------------ + +%type jpl_iterator_element(object, datum) + +% jpl_iterator_element(+Iterator, -Element) :- + +jpl_iterator_element(I, E) :- + ( jpl_call(I, hasNext, [], @(true)) + -> ( jpl_call(I, next, [], E) % surely it's steadfast... + ; jpl_iterator_element(I, E) + ) + ). + +%------------------------------------------------------------------------------ + +%type jpl_list_to_array(list(datum), array) + +% jpl_list_to_array(+Datums, -Array) :- +% Datums is a proper list of JPL datums (values or refs); +% if they have a most specific common supertype, +% Array is an array, of that base type, +% whose respective elements are Datums + +jpl_list_to_array(Ds, A) :- + jpl_datums_to_array(Ds, A). + +%------------------------------------------------------------------------------ + +%type jpl_map_element(object, pair(datum,datum)) + +% jpl_map_element(+Map, -KeyValue) :- +% Map must be an instance of any implementation of the java.util.Map interface; +% this generates each Key-Value pair from the Map + +jpl_map_element(M, K-V) :- + jpl_call(M, entrySet, [], ES), + jpl_set_element(ES, E), + jpl_call(E, getKey, [], K), + jpl_call(E, getValue, [], V). + +%------------------------------------------------------------------------------ + +%type jpl_set_element(object, datum) + +% jpl_set_element(+Set, -Element) :- + +jpl_set_element(S, E) :- + jpl_call(S, iterator, [], I), + jpl_iterator_element(I, E). + + +%------------------------------------------------------------------------------ + +% is_pair(?T) :- +% I define a half-decent "pair" as having a ground key (any val) + +is_pair(0) :- !, fail. +is_pair(Key-_Val) :- + ground(Key). + +%------------------------------------------------------------------------------ + +is_pairs(0) :- !, fail. +is_pairs([]). +is_pairs([H|T]) :- + is_pair(H), + is_pairs(T). + +%------------------------------------------------------------------------------ + +qp_atom_to_chars(A, Cs) :- + atom_codes(A, Cs). + +%------------------------------------------------------------------------------ + +qp_chars_to_atom(Cs, A) :- + atom_codes(A, Cs). + +%------------------------------------------------------------------------------ + +multimap_to_atom(KVs, A) :- + multimap_to_atom_1(KVs, "", Cz, []), + flatten(Cz, Cs), + qp_chars_to_atom(Cs, A). + +%------------------------------------------------------------------------------ + +multimap_to_atom_1([], _, Cs, Cs). + +multimap_to_atom_1([K-V|KVs], T, Cs1, Cs0) :- + qp_atom_to_chars(K, CsK), + Cs1 = [T,CsK," = "|Cs2], + ( is_list(V) + -> ( is_pairs(V) + -> V = V2 + ; findall( + N-Ve, + nth1(N, V, Ve), + V2 + ) + ), + T2 = [" ",T], + Cs2 = [10|Cs2a], + multimap_to_atom_1(V2, T2, Cs2a, Cs3) + ; term_to_chars(V, CsV), + Cs2 = [CsV,10|Cs3] + ), + multimap_to_atom_1(KVs, T, Cs3, Cs0). + + + /******************************* + * MESSAGES * + *******************************/ + +:- multifile + prolog:error_message/3. + +prolog:error_message(java_exception(Ex)) --> + ( { jpl_call(Ex, toString, [], Msg) + } + -> [ 'Java exception: ~w'-[Msg] ] + ; [ 'Java exception: ~w'-[Ex] ] + ). + + + /******************************* + * PATHS * + *******************************/ + +:- multifile user:file_search_path/2. +:- dynamic user:file_search_path/2. + +user:file_search_path(jar, swi(lib)). + + + /******************************* + * LOAD THE JVM * + *******************************/ + +% check_java_environment +% +% Verify the Java environment. Preferably we would create, but +% most Unix systems do not allow putenv("LD_LIBRARY_PATH=..." in +% the current process. A suggesting found on the net is to modify +% LD_LIBRARY_PATH right at startup and next execv() yourself, but +% this doesn't work if we want to load Java on demand or if Prolog +% itself is embedded in another application. +% +% So, after reading lots of pages on the web, I decided checking +% the environment and producing a sensible error message is the +% best we can do. +% +% Please not that Java2 doesn't require $CLASSPATH to be set, so +% we do not check for that. + +check_java_environment :- + check_lib(java), + check_lib(jvm). + +check_lib(Name) :- + check_shared_object(Name, File, EnvVar, Absolute), + ( Absolute == (-) + -> ( current_prolog_flag(windows, true) + -> A = '%', Z = '%' + ; A = '$', Z = '' + ), + sformat(Msg, 'Please add directory holding ~w to ~w~w~w', + [ File, A, EnvVar, Z ]), + throw(error(existence_error(library, Name), + context(_, Msg))) + ; true + ). + +check_shared_object(Name, File, EnvVar, Absolute) :- + libfile(Name, File), + library_search_path(Path, EnvVar), + ( member(Dir, Path), + concat_atom([Dir, File], /, Absolute), + exists_file(Absolute) + -> true + ; Absolute = (-) + ). + +libfile(Base, File) :- + current_prolog_flag(unix, true), !, + atom_concat(lib, Base, F0), + current_prolog_flag(shared_object_extension, Ext), + file_name_extension(F0, Ext, File). +libfile(Base, File) :- + current_prolog_flag(windows, true), !, + current_prolog_flag(shared_object_extension, Ext), + file_name_extension(Base, Ext, File). + +library_search_path(Path, 'LD_LIBRARY_PATH') :- + current_prolog_flag(unix, true), !, + ( getenv('LD_LIBRARY_PATH', Env), + concat_atom(Path, ':', Env) + -> true + ; Path = [] + ). +library_search_path(Path, 'PATH') :- + current_prolog_flag(windows, true), !, + ( getenv('PATH', Env), + concat_atom(Path, ';', Env) + -> true + ; Path = [] + ). + +% add_jpl_to_classpath/0 +% +% Add jpl.jar to $CLASSPATH to facilitate callbacks + +add_jpl_to_classpath :- + absolute_file_name(jar('jpl.jar'), + [ access(read) + ], JplJAR), !, + ( getenv('CLASSPATH', Old) + -> true + ; Old = '.' + ), + concat_atom([JplJAR, Old], :, New), + setenv('CLASSPATH', New). + +% libjpl(-Spec) +% +% Return the spec for loading the JPL shared object. This shared +% object must be called libjpl.so as the Java System.loadLibrary() +% call used by jpl.jar adds the lib* prefix. + +libjpl(File) :- + ( current_prolog_flag(unix, true) + -> File = foreign(libjpl) + ; File = foreign(jpl) + ). + +% add_java_to_ldpath/0 +% +% Adds the directories holding jvm.dll and java.dll to the %PATH%. +% This appears to work on Windows. Unfortunately most Unix systems +% appear to inspect the content of LD_LIBRARY_PATH only once. + +add_java_to_ldpath :- + current_prolog_flag(windows, true), !, + add_java_dir(jvm, '\\jre\\bin\\client', Extra1), + add_java_dir(java, '\\jre\\bin', Extra2), + append(Extra1, Extra2, Extra), + ( Extra \== [] + -> print_message(informational, + format('Added ~w to %PATH%', [Extra])), + getenv('PATH', Path0), + concat_atom([Path0|Extra], ';', Path), + setenv('PATH', Path) + ; true + ). +add_java_to_ldpath. + +add_java_dir(DLL, SubPath, Dir) :- + ( check_shared_object(DLL, _, _Var, Abs), + Abs \== (-) + -> Dir = [] + ; java_home(JavaHome) + -> atom_concat(JavaHome, SubPath, ClientDir), + Dir = [ClientDir] + ; Dir = [] + ). + +java_home(Home) :- + getenv('JAVA_HOME', Home), + exists_directory(Home), !. +java_home(Home) :- + current_prolog_flag(windows, true), !, + Key0 = 'HKEY_LOCAL_MACHINE/Software/JavaSoft/Java Development Kit', + win_registry_get_value(Key0, 'CurrentVersion', Version), + concat_atom([Key0, Version], /, Key), + win_registry_get_value(Key, 'JavaHome', Home), + exists_directory(Home), !. +java_home(Home) :- + jpl_java_home(Home). +java_home(Home) :- + current_prolog_flag(unix, true), + member(Home, [ '/usr/lib/java', + '/usr/local/lib/java' + ]), + exists_directory(Home), !. + +:- dynamic + jvm_ready/0. +:- volatile + jvm_ready/0. + +setup_jvm :- + jvm_ready, !. +setup_jvm :- + add_jpl_to_classpath, + add_java_to_ldpath, + libjpl(JPL), +% catch(load_foreign_library(JPL), E, report_java_setup_problem(E)), + assert(jvm_ready). + +report_java_setup_problem(E) :- + print_message(error, E), + check_java_environment. + +:- initialization + setup_jvm. diff --git a/LGPL/JPL/src/Makefile.in b/LGPL/JPL/src/Makefile.in new file mode 100644 index 000000000..cfe1d31b0 --- /dev/null +++ b/LGPL/JPL/src/Makefile.in @@ -0,0 +1,63 @@ +# +# +JAVA_HOME=@JAVA_HOME@ +JVM_INC = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux +JVM_LIB = -L$(JAVA_HOME)/jre/lib/i386 -L$(JAVA_HOME)/jre/lib/i386/client -ljava -lverify -ljvm +# +# +# +# default base directory for YAP installation +# (EROOT for architecture-dependent files) +# +prefix = @prefix@ +ROOTDIR = $(prefix) +EROOTDIR = @exec_prefix@ +# +# where the binary should be +# +BINDIR = $(EROOTDIR)/bin +# +# where YAP should look for libraries +# +LIBDIR=$(EROOTDIR)/lib/Yap +# +# +CC=@CC@ +CFLAGS= @CFLAGS@ $(YAP_EXTRAS) $(DEFS) -I$(srcdir) -I../.. -I$(srcdir)/../../../include -I$(srcdir)/../../../library/yap2swi $(JVM_INC) -DIN_YAP=1 -DJAVA_HOME=\"$(JAVA_HOME)\" +# +# +# You shouldn't need to change what follows. +# +INSTALL=@INSTALL@ +INSTALL_DATA=@INSTALL_DATA@ +INSTALL_PROGRAM=@INSTALL_PROGRAM@ +SHELL=/bin/sh +RANLIB=@RANLIB@ +srcdir=@srcdir@ +SHLIB_CFLAGS=@SHLIB_CFLAGS@ +SHLIB_SUFFIX=@SHLIB_SUFFIX@ +#4.1VPATH=@srcdir@:@srcdir@/OPTYap +CWD=$(PWD) +# + +OBJS=jpl.o +SOBJS=jpl@SHLIB_SUFFIX@ + +all: $(SOBJS) + +jpl.o: $(srcdir)/jpl.c + $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/jpl.c -o jpl.o + + +@DO_SECOND_LD@%@SHLIB_SUFFIX@: %.o +@DO_SECOND_LD@ @SHLIB_LD@ -o $@ $< + +@DO_SECOND_LD@jpl_jni@SHLIB_SUFFIX@: jpl_jni.o jvm.o +@DO_SECOND_LD@ @SHLIB_LD@ -o jpl_jni@SHLIB_SUFFIX@ jpl.o $(JVM_LIB) + +install: all + $(INSTALL_PROGRAM) $(SOBJS) $(DESTDIR)$(LIBDIR) + +clean: + rm -f *.o *~ $(OBJS) $(SOBJS) *.BAK + diff --git a/LGPL/JPL/src/jpl.c b/LGPL/JPL/src/jpl.c new file mode 100644 index 000000000..7a78bd9b4 --- /dev/null +++ b/LGPL/JPL/src/jpl.c @@ -0,0 +1,6649 @@ +/* $Id: jpl.c,v 1.1 2004-08-27 20:27:32 vsc Exp $ + + Part of JPL -- SWI-Prolog/Java interface + + Author: Paul Singleton, Fred Dushin and Jan Wielemaker + E-mail: paul@jbgb.com + WWW: http://www.swi-prolog.org + Copyright (C): 1985-2004, Paul Singleton + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// this source file (jpl.c) combines my Prolog-calls-Java stuff (mostly prefixed 'JNI' or 'jni' here) +// with my adaptation of Fred Dushin's Java-calls-Prolog stuff (mostly prefixed 'JPL' or 'jpl' here) + +// recent fixes: +// * using PL_get_pointer(), PL_put_pointer() consistently (?) +// +// still to do: +// * make it completely thread-safe +// (both to multiple Prolog (engine-enabled) threads and to multiple Java threads) +// * suss JVM 'abort' and 'exit' handling, and 'vfprintf' redirection +// * figure out why Java native methods have "Class: jpl_fli_PL" (and not jpl_fli_Prolog) +// * rationalise initialisation; perhaps support startup from C? + +// update this to distinguish releases of this C library: +#define JPL_C_LIB_VERSION "3.0.4-alpha" +#define JPL_C_LIB_VERSION_MAJOR 3 +#define JPL_C_LIB_VERSION_MINOR 0 +#define JPL_C_LIB_VERSION_PATCH 4 +#define JPL_C_LIB_VERSION_STATUS "alpha" + +#define DEBUG(n, g) ((void)0) + +//=== includes ===================================================================================== + +#ifdef WIN32 +// OS-specific header (SWI-Prolog FLI and Java Invocation API both seem to need this): +#include +#endif + +// SWI-Prolog headers: +#if IN_YAP +#include +#else +#include +#include +#endif + +// Java Native Interface and Invocation Interface header: +#include + +// ANSI/ISO C library header (?): +#include +#include +#include +#include + +// POSIX 'pthreads' headers (initially for JPL's Prolog engine pool, useful for locking generally?): +#include +#include + +int jni_create_default_jvm(void); +install_t jpl_install(void); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_get_1default_1init_1args(JNIEnv *, jclass); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_set_1default_1init_1args(JNIEnv *, jclass, jobject); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_get_1actual_1init_1args(JNIEnv *,jclass); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_initialise(JNIEnv *,jclass); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_halt(JNIEnv *,jclass,jint); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_new_1term_1ref(JNIEnv *,jclass); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_new_1term_1refs(JNIEnv *,jclass,jint); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_copy_1term_1ref(JNIEnv *,jclass,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_reset_1term_1refs(JNIEnv *, jclass,jobject); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_new_1atom(JNIEnv *,jclass,jstring); +JNIEXPORT jstring JNICALL Java_jpl_fli_Prolog_atom_1chars(JNIEnv *,jclass,jobject); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_new_1functor(JNIEnv *,jclass,jobject,jint); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_functor_1name(JNIEnv *,jclass,jobject); +JNIEXPORT jint JNICALL Java_jpl_fli_Prolog_functor_1arity(JNIEnv *,jclass,jobject); +JNIEXPORT jint JNICALL Java_jpl_fli_Prolog_term_1type(JNIEnv *env,jclass,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_is_1variable(JNIEnv *,jclass,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_is_1atom(JNIEnv *,jclass,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_is_1integer(JNIEnv *,jclass,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_is_1float(JNIEnv *,jclass,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_is_1compound(JNIEnv *,jclass,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_is_1functor(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_is_1list(JNIEnv *,jclass,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_is_1atomic(JNIEnv *,jclass,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_is_1number(JNIEnv *,jclass,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_is_1atom(JNIEnv *,jclass,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1atom(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1atom_1chars(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1string_1chars(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1chars(JNIEnv *,jclass,jobject,jobject,jint); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1list_1chars(JNIEnv *,jclass,jobject,jobject,jint); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1integer(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1pointer(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1float(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1jref(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1jboolean(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1jpl_1term(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1functor(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1name_1arity(JNIEnv *,jclass,jobject,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1module(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1arg(JNIEnv *,jclass,jint,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1list(JNIEnv *,jclass,jobject,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1head(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1tail(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_get_1nil(JNIEnv *,jclass,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1variable(JNIEnv *,jclass,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1atom(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1atom_1chars(JNIEnv *,jclass,jobject,jstring); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1list_1chars(JNIEnv *,jclass,jobject,jstring); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1integer(JNIEnv *,jclass,jobject,jlong); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1pointer(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1float(JNIEnv *,jclass,jobject,jdouble); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1functor(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1list(JNIEnv *,jclass,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1nil(JNIEnv *,jclass,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1term(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1jref(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1jboolean(JNIEnv *,jclass,jobject,jboolean); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_put_1jvoid(JNIEnv *,jclass,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_cons_1functor_1v(JNIEnv *,jclass,jobject,jobject,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_cons_1list(JNIEnv *,jclass,jobject,jobject,jobject); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_open_1foreign_1frame(JNIEnv *,jclass); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_close_1foreign_1frame(JNIEnv *,jclass,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_discard_1foreign_1frame(JNIEnv *,jclass,jobject); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_pred(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_predicate(JNIEnv *,jclass,jstring,jint,jstring); +JNIEXPORT jint JNICALL Java_jpl_fli_Prolog_predicate_1info(JNIEnv *,jclass,jobject,jobject,jobject,jobject); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_open_1query(JNIEnv *,jclass,jobject,jint,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_next_1solution(JNIEnv *,jclass,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_cut_1query(JNIEnv *env,jclass,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_close_1query(JNIEnv *,jclass,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_call_1predicate(JNIEnv *,jclass,jobject,jint,jobject,jobject); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_call(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_exception(JNIEnv *,jclass,jobject); +JNIEXPORT jint JNICALL Java_jpl_fli_Prolog_compare(JNIEnv *,jclass,jobject,jobject); +JNIEXPORT void JNICALL Java_jpl_fli_Prolog_unregister_1atom(JNIEnv *,jclass,jobject); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_new_1module(JNIEnv *,jclass,jobject); +JNIEXPORT int JNICALL Java_jpl_fli_Prolog_action_1abort(JNIEnv *,jclass); +JNIEXPORT jint JNICALL Java_jpl_fli_Prolog_thread_1self(JNIEnv *,jclass); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_attach_1pool_1engine(JNIEnv *,jclass); +JNIEXPORT int JNICALL Java_jpl_fli_Prolog_attach_1engine(JNIEnv *,jclass,jobject); +JNIEXPORT int JNICALL Java_jpl_fli_Prolog_pool_1engine_1id(JNIEnv *env,jclass,jobject); +JNIEXPORT int JNICALL Java_jpl_fli_Prolog_release_1pool_1engine(JNIEnv *,jclass); +JNIEXPORT jboolean JNICALL Java_jpl_fli_Prolog_current_1engine_1is_1pool(JNIEnv *env,jclass); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_current_1engine(JNIEnv *env,jclass); +JNIEXPORT jobject JNICALL Java_jpl_fli_Prolog_get_1c_1lib_1version(JNIEnv *,jclass); + + +//=== JNI constants ================================================================================ + +#define JNI_MIN_JCHAR 0 +#define JNI_MAX_JCHAR 65535 + +#define JNI_MIN_JBYTE -128 +#define JNI_MAX_JBYTE 127 + +#define JNI_MIN_JSHORT -32768 +#define JNI_MAX_JSHORT 32767 + + +#define JNI_XPUT_VOID 0 +#define JNI_XPUT_BOOLEAN 1 +#define JNI_XPUT_BYTE 2 +#define JNI_XPUT_CHAR 3 +#define JNI_XPUT_SHORT 4 +#define JNI_XPUT_INT 5 +#define JNI_XPUT_LONG 6 +#define JNI_XPUT_FLOAT 7 +#define JNI_XPUT_DOUBLE 8 +#define JNI_XPUT_FLOAT_TO_DOUBLE 9 +#define JNI_XPUT_LONG_TO_FLOAT 10 +#define JNI_XPUT_LONG_TO_DOUBLE 11 +#define JNI_XPUT_REF 12 +#define JNI_XPUT_ATOM 13 +#define JNI_XPUT_JVALUEP 14 +#define JNI_XPUT_JVALUE 15 + + +// JNI "hashed refs" constants + +#define JNI_HR_LOAD_FACTOR 0.75 + +// jni_hr_add() return codes: +#define JNI_HR_ADD_FAIL -1 +#define JNI_HR_ADD_NEW 0 +#define JNI_HR_ADD_OLD 1 + + +//=== JPL constants ================================================================================ + +// legit values for jpl_status_jpl_ini and jpl_status_pvm_ini +#define JPL_INIT_RAW 101 +#define JPL_INIT_PVM_MAYBE 102 +#define JPL_INIT_OK 103 +#define JPL_INIT_JPL_FAILED 104 +#define JPL_INIT_PVM_FAILED 105 + +#define JPL_MAX_POOL_ENGINES 10 /* max pooled Prolog engines */ +#define JPL_INITIAL_POOL_ENGINES 1 /* initially created ones */ + + +//=== JNI Prolog<->Java conversion macros ========================================================== + +// JNI (Prolog-calls-Java) conversion macros; mainly used in jni_{func|void}_{0|1|2|3|4}_plc +// for re-entrancy, ensure that any variables which they use are declared dynamically +// (e.g. or i.e. are local to the host function) +// beware of evaluating *expressions* passed as actual parameters more than once + +#define JNI_term_to_jboolean(T,JB) \ + ( PL_get_functor((T),&fn) \ + && fn==JNI_functor_at_1 \ + ? ( ( a1=PL_new_term_ref(), \ + PL_get_arg(1,(T),a1) \ + ) \ + && PL_get_atom(a1,&a) \ + ? ( a==JNI_atom_false \ + ? ( (JB)=0, TRUE) \ + : ( a==JNI_atom_true \ + ? ( (JB)=1, TRUE) \ + : FALSE \ + ) \ + ) \ + : FALSE \ + ) \ + : FALSE \ + ) + +#define JNI_term_to_jchar(T,J) \ + ( PL_get_integer((T),&(J)) \ + && (J) >= JNI_MIN_JCHAR \ + && (J) <= JNI_MAX_JCHAR \ + ) + +#define JNI_term_to_jbyte(T,J) \ + ( PL_get_integer((T),&(J)) \ + && (J) >= JNI_MIN_JBYTE \ + && (J) <= JNI_MAX_JBYTE \ + ) + +#define JNI_term_to_jshort(T,J) \ + ( PL_get_integer((T),&(J)) \ + && (J) >= JNI_MIN_JSHORT \ + && (J) <= JNI_MAX_JSHORT \ + ) + +#define JNI_term_to_jint(T,J) \ + ( PL_get_integer((T),&(J)) \ + ) + +#define JNI_term_to_non_neg_jint(T,J) \ + ( PL_get_integer((T),&(J)) \ + && (J) >= 0 \ + ) + +#define JNI_term_to_jlong(T,J) \ + ( PL_get_integer((T),&i) \ + ? ( (J)=(jlong)i, TRUE) \ + : JNI_jlong2_to_jlong(T,(J)) \ + ) + +#define JNI_jlong2_to_jlong(T,J) \ + ( PL_get_functor((T),&fn) \ + && fn==JNI_functor_jlong_2 \ + ? ( ( a1=PL_new_term_ref(), \ + PL_get_arg(1,(T),a1) \ + ) \ + && ( a2=PL_new_term_ref(), \ + PL_get_arg(2,(T),a2) \ + ) \ + && PL_get_integer(a1,&xhi) \ + && PL_get_integer(a2,&xlo) \ + ? ( ((int*)&(J))[1]=xhi, \ + ((int*)&(J))[0]=xlo, \ + TRUE \ + ) \ + : FALSE \ + ) \ + : FALSE \ + ) + +#define JNI_term_to_jfloat(T,J) \ + ( PL_get_float((T),&(J)) \ + ? TRUE \ + : ( PL_get_integer((T),&i) \ + ? ( (J)=(jfloat)i, TRUE) \ + : ( JNI_jlong2_to_jlong((T),jl) \ + ? ( (J)=(jfloat)jl, TRUE) \ + : FALSE \ + ) \ + ) \ + ) + +#define JNI_term_to_jdouble(T,J) \ + ( PL_get_float((T),&(J)) \ + ? TRUE \ + : ( PL_get_integer((T),&i) \ + ? ( (J)=(jdouble)i, TRUE) \ + : ( JNI_jlong2_to_jlong((T),jl) \ + ? ( (J)=(jdouble)jl, TRUE) \ + : FALSE \ + ) \ + ) \ + ) + +#define JNI_term_to_jfieldID(T,J) \ + ( PL_get_functor((T),&fn) \ + && fn==JNI_functor_jfieldID_1 \ + && ( a1=PL_new_term_ref(), \ + PL_get_arg(1,(T),a1) \ + ) \ + && PL_get_pointer(a1,(void**)&(J)) \ + ) + +#define JNI_term_to_jmethodID(T,J) \ + ( PL_get_functor((T),&fn) \ + && fn==JNI_functor_jmethodID_1 \ + && ( a1=PL_new_term_ref(), \ + PL_get_arg(1,(T),a1) \ + ) \ + && PL_get_pointer(a1,(void**)&(J)) \ + ) + +// converts: +// atom -> String +// @(null) -> NULL +// @(tag) -> obj +// (else fails) +// +#define JNI_term_to_ref(T,J) \ + ( PL_get_atom_chars((T),&cp) \ + ? ((J)=(*env)->NewStringUTF(env,cp))!=NULL \ + : PL_get_functor((T),&fn) \ + && fn==JNI_functor_at_1 \ + && ( a1=PL_new_term_ref(), \ + PL_get_arg(1,(T),a1) \ + ) \ + && PL_get_atom(a1,&a) \ + && ( a==JNI_atom_null \ + ? ( (J)=0, TRUE) \ + : jni_tag_to_iref(a,(int*)&(J)) \ + ) \ + ) + +// converts: +// atom -> String +// @tag -> obj +// (else fails) +// stricter than JNI_term_to_ref(T,J) +// +#define JNI_term_to_jobject(T,J) \ + ( PL_get_atom_chars((T),&cp) \ + ? ((J)=(*env)->NewStringUTF(env,cp))!=NULL \ + : PL_get_functor((T),&fn) \ + && fn==JNI_functor_at_1 \ + && ( a1=PL_new_term_ref(), \ + PL_get_arg(1,(T),a1) \ + ) \ + && PL_get_atom(a1,&a) \ + && a!=JNI_atom_null \ + && jni_tag_to_iref(a,(int*)&(J)) \ + ) + + +// for now, these specific test-and-convert macros +// are merely mapped to their nearest ancestor... + +#define JNI_term_to_jclass(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_throwable_jclass(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_non_array_jclass(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_throwable_jobject(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_jstring(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_jarray(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_object_jarray(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_boolean_jarray(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_byte_jarray(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_char_jarray(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_short_jarray(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_int_jarray(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_long_jarray(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_float_jarray(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_double_jarray(T,J) JNI_term_to_jobject(T,J) + +#define JNI_term_to_jbuf(T,J,TP) \ + ( PL_get_functor((T),&fn) \ + && fn==JNI_functor_jbuf_2 \ + && ( a2=PL_new_term_ref(), \ + PL_get_arg(2,(T),a2) \ + ) \ + && PL_get_atom(a2,&a) \ + && a==(TP) \ + && ( a1=PL_new_term_ref(), \ + PL_get_arg(1,(T),a1) \ + ) \ + && PL_get_pointer(a1,(void**)&(J)) \ + ) + +#define JNI_term_to_charP(T,J) \ + PL_get_atom_chars((T),&(J)) + +#define JNI_term_to_pointer(T,J) \ + PL_get_pointer((T),(void**)&(J)) + + +// JNI Java-to-Prolog conversion macros: + +#define JNI_unify_void(T) \ + PL_unify_term((T), \ + PL_FUNCTOR, JNI_functor_at_1, \ + PL_ATOM, JNI_atom_void \ + ) + +#define JNI_unify_false(T) \ + PL_unify_term((T), \ + PL_FUNCTOR, JNI_functor_at_1, \ + PL_ATOM, JNI_atom_false \ + ) + +#define JNI_unify_true(T) \ + PL_unify_term((T), \ + PL_FUNCTOR, JNI_functor_at_1, \ + PL_ATOM, JNI_atom_true \ + ) + +#define JNI_jboolean_to_term(J,T) \ + ( (J)==0 \ + ? JNI_unify_false((T)) \ + : JNI_unify_true((T)) \ + ) + +#define JNI_jchar_to_term(J,T) \ + PL_unify_integer((T),(int)(J)) + +#define JNI_jbyte_to_term(J,T) \ + PL_unify_integer((T),(int)(J)) + +#define JNI_jshort_to_term(J,T) \ + PL_unify_integer((T),(int)(J)) + +#define JNI_jint_to_term(J,T) \ + PL_unify_integer((T),(int)(J)) + +#define JNI_jlong_to_term(J,T) \ + ( ( jl=(J), \ + xhi=((int*)&jl)[1], \ + xlo=((int*)&jl)[0], \ + TRUE \ + ) \ + && ( ( xhi== 0 && xlo>=0 ) \ + || ( xhi==-1 && xlo< 0 ) \ + ) \ + ? PL_unify_integer((T),xlo) \ + : PL_unify_term((T), \ + PL_FUNCTOR, JNI_functor_jlong_2, \ + PL_INTEGER, xhi, \ + PL_INTEGER, xlo \ + ) \ + ) + +#define JNI_jfloat_to_term(J,T) \ + PL_unify_float((T),(double)(J)) + +#define JNI_jdouble_to_term(J,T) \ + PL_unify_float((T),(double)(J)) + +// J can be an *expression* parameter to this macro; +// we must evaluate it exactly once; hence we save its value +// in the variable j, which must be dynamic (e.g. local) +// if this macro is to be re-entrant +#define JNI_jobject_to_term(J,T) \ + ( ( j=(J), j==NULL ) \ + ? PL_unify_term((T), \ + PL_FUNCTOR, JNI_functor_at_1, \ + PL_ATOM, JNI_atom_null \ + ) \ + : ( (*env)->IsInstanceOf(env,j,str_class) \ + ? jni_string_to_atom(j,&a) \ + && PL_unify_term((T), \ + PL_ATOM, a \ + ) \ + : jni_object_to_iref(j,&i) \ + && jni_iref_to_tag(i,&a) \ + && PL_unify_term((T), \ + PL_FUNCTOR, JNI_functor_at_1, \ + PL_ATOM, a \ + ) \ + ) \ + ) + +#define JNI_jfieldID_to_term(J,T) \ + PL_unify_term((T), \ + PL_FUNCTOR, JNI_functor_jfieldID_1, \ + PL_POINTER, (void*)(J) \ + ) + +#define JNI_jmethodID_to_term(J,T) \ + PL_unify_term((T), \ + PL_FUNCTOR, JNI_functor_jmethodID_1, \ + PL_POINTER, (void*)(J) \ + ) + +#define JNI_jbuf_to_term(J,T,TP) \ + PL_unify_term((T), \ + PL_FUNCTOR, JNI_functor_jbuf_2, \ + PL_POINTER, (void*)(J), \ + PL_ATOM, (TP) \ + ) + +#define JNI_pointer_to_term(J,T) \ + PL_unify_pointer((T),(void*)(J)) + +#define JNI_charP_to_term(J,T) \ + PL_unify_atom_chars((T),(J)) + + + +//=== JNI initialisation macro (typically succeeds cheaply) ======================================== + +#define jni_ensure_jvm() ( ( jvm != NULL \ + || jni_create_default_jvm() \ + ) \ + && jni_get_env() \ + ) + + +//=== JPL initialisation macros (typically succeed cheaply) ======================================== + +// outcomes: +// fail to find jpl.*, jpl.fli.* classes or to convert init args to String[]: exception, FALSE +// JPL is (newly or already) out of RAW state: TRUE +#define jpl_ensure_jpl_init(e) ( jpl_status != JPL_INIT_RAW \ + || jpl_do_jpl_init(e) \ + ) +// outcomes: +// JPL or PVM init has already failed: FALSE +// JPL or PVM init fails while being necessarily attempted: exception +// JPL is (newly or already) fully initialised: TRUE +#define jpl_ensure_pvm_init(e) ( jpl_status == JPL_INIT_OK \ + || ( jpl_ensure_jpl_init(e) , FALSE ) \ + || jpl_test_pvm_init(e) \ + || jpl_do_pvm_init(e) \ + ) + + +//=== types (structs and typedefs) ================================================================= + +// types for "hashed refs": + +typedef struct Hr_Entry HrEntry; // enables circular definition... + +struct Hr_Entry { // a single interned reference + jobject obj; // a JNI global ref + int hash; // identityHashCode(obj) + HrEntry *next; // next entry in this chain, or NULL + }; + +typedef struct Hr_Table HrTable; + +struct Hr_Table { + int count; // current # entries + int threshold; // rehash on add when count==threshold + int length; // # slots in slot array + HrEntry **slots; // pointer to slot array + }; + +typedef long pointer; // for JPL (I reckon 'int' is enough on 32-bit systems) +typedef int bool; // for JNI/JPL functions returning only TRUE or FALSE + + + +//=== JNI "constants" ============================================================================== + +// sizes of JNI primitive types: + +int size[16] = { // NB relies on sequence of JNI_XPUT_* defs + 0, + sizeof(jboolean), // size[JNI_XPUT_BOOLEAN] + sizeof(jbyte), // size[JNI_XPUT_BYTE] + sizeof(jchar), // size[JNI_XPUT_CHAR] + sizeof(jshort), // size[JNI_XPUT_SHORT] + sizeof(jint), // size[JNI_XPUT_INT] + sizeof(jlong), // size[JNI_XPUT_LONG] + sizeof(jfloat), // size[JNI_XPUT_FLOAT] + sizeof(jdouble), // size[JNI_XPUT_DOUBLE] + 0, // n/a - JNI_FLOAT_TO_DOUBLE + 0, // n/a - JNI_LONG_TO_FLOAT + 0, // n/a - JNI_LONG_TO_DOUBLE + 0, // n/a - JNI_REF + 0, // n/a - JNI_ATOM + 0, // n/a - JNI_JVALUEP + sizeof(jvalue) // size[JNI_XPUT_JVALUE] + }; + + + +//=== JNI "constants", lazily initialised by jni_init() ============================================ + +static atom_t JNI_atom_false; // false +static atom_t JNI_atom_true; // true + +static atom_t JNI_atom_boolean; // boolean +static atom_t JNI_atom_char; // char +static atom_t JNI_atom_byte; // byte +static atom_t JNI_atom_short; // short +static atom_t JNI_atom_int; // int +static atom_t JNI_atom_long; // long +static atom_t JNI_atom_float; // float +static atom_t JNI_atom_double; // double + +static atom_t JNI_atom_null; // null +static atom_t JNI_atom_void; // void + +static functor_t JNI_functor_at_1; // @(_) +static functor_t JNI_functor_jbuf_2; // jbuf(_,_) +static functor_t JNI_functor_jlong_2; // jlong(_,_) +static functor_t JNI_functor_jfieldID_1; // jfieldID(_) +static functor_t JNI_functor_jmethodID_1; // jmethodID(_) +static functor_t JNI_functor_error_2; // error(_, _) +static functor_t JNI_functor_java_exception_1; // java_exception(_) +static functor_t JNI_functor_jpl_error_1; // jpl_error(_) + + +//=== JNI's static JVM references, lazily initialised by jni_init() ================================ + +static jclass c_class; // java.lang.Class (rename to jClass_c ?) +static jmethodID c_getName; // java.lang.Class' getName() (rename to jClassGetName_m ?) +static jclass str_class; // java.lang.String (this duplicates jString_c below) + +static jclass sys_class; // java.lang.System (rename to jSystem_c ?) +static jmethodID sys_ihc; // java.lang.System's identityHashCode() (rename to jSystemIdentityHashCode_m ?) + + +//=== JPL's reusable global class object refs, initialised by jpl_ensure_jpl_init() ================ + +static jclass jString_c; +static jclass jJPLException_c; +static jclass jTermT_c; +static jclass jAtomT_c; +static jclass jFunctorT_c; +static jclass jFidT_c; +static jclass jPredicateT_c; +static jclass jQidT_c; +static jclass jModuleT_c; +static jclass jEngineT_c; + +static jclass jLongHolder_c; +static jclass jPointerHolder_c; +static jclass jIntHolder_c; +static jclass jDoubleHolder_c; +static jclass jStringHolder_c; +static jclass jObjectHolder_c; +static jclass jBooleanHolder_c; + +static jclass jJRef_c; +static jclass jJBoolean_c; + + +//=== JPL's reusable constant field IDs, set before first use by jpl_ensure_jpl_init() ============= + +static jfieldID jLongHolderValue_f; +static jfieldID jPointerHolderValue_f; +static jfieldID jIntHolderValue_f; +static jfieldID jDoubleHolderValue_f; +static jfieldID jStringHolderValue_f; +static jfieldID jObjectHolderValue_f; +static jfieldID jBooleanHolderValue_f; + +static jfieldID jJRefRef_f; +static jfieldID jJBooleanValue_f; + + + +//=== JPL's default args for PL_initialise() (NB these are not really good enough) ================= + +const char *default_args[] = { "pl", + "-g", "true", + NULL + }; // *must* have final NULL + + +//=== JNI global state (initialised by jni_create_jvm_c) =========================================== + +static JavaVM *jvm = NULL; // non-null -> JVM successfully loaded & initialised +static JNIEnv *env; // if jvm is defined, then so will this be + + + +//=== JNI global state (hashed global refs) ======================================================== + +static HrTable *hr_table = NULL; // static handle to allocated-on-demand table +static int hr_add_count = 0; // cumulative total of new refs interned +static int hr_old_count = 0; // cumulative total of old refs reused +static int hr_del_count = 0; // cumulative total of dead refs released + + +//=== JPL global state, initialised by jpl_ensure_jpl_init() or jpl_ensure_jvm_init() ============== + +static int jpl_status = JPL_INIT_RAW; // neither JPL nor PVM initialisation has occurred +static jobject dia = NULL; // default init args (after jpl init, until pvm init) +static jobject aia = NULL; // actual init args (after pvm init) +static PL_engine_t *engines = NULL; // handles of the pooled Prolog engines +static int engines_allocated = 0; /* size of engines array */ +static pthread_mutex_t engines_mutex = PTHREAD_MUTEX_INITIALIZER; // for controlling pool access +static pthread_cond_t engines_cond = PTHREAD_COND_INITIALIZER; // for controlling pool access + + +//=== common functions ============================================================================= + +static char * +jpl_c_lib_version(void) + { + static char v[100]; // version string + static char *vp = NULL; // set to v at first call + + if ( vp != NULL ) // already set? + { + return vp; + } + sprintf( v, "%d.%d.%d-%s", JPL_C_LIB_VERSION_MAJOR, JPL_C_LIB_VERSION_MINOR, JPL_C_LIB_VERSION_PATCH, JPL_C_LIB_VERSION_STATUS); + vp = v; + return vp; + } + + +/* +%T jpl_c_lib_version( -atom) + */ + +// ... +// +static foreign_t +jpl_c_java_home( + term_t ta + ) + { + + return PL_unify_atom_chars(ta,JAVA_HOME); + } + + +// ... +// +static foreign_t +jpl_c_lib_version_1_plc( + term_t ta + ) + { + + return PL_unify_atom_chars(ta,jpl_c_lib_version()); + } + + +/* +%T jpl_c_lib_version( -integer, -integer, -integer, -atom) + */ + +// ... +// +static foreign_t +jpl_c_lib_version_4_plc( + term_t tmajor, + term_t tminor, + term_t tpatch, + term_t tstatus + ) + { + + return PL_unify_integer(tmajor,JPL_C_LIB_VERSION_MAJOR) + && PL_unify_integer(tminor,JPL_C_LIB_VERSION_MINOR) + && PL_unify_integer(tpatch,JPL_C_LIB_VERSION_PATCH) + && PL_unify_atom_chars(tstatus,JPL_C_LIB_VERSION_STATUS); + } + + +//=== JNI function prototypes (to resolve unavoidable forward references) ========================== + +static int jni_hr_add(jobject,int*); +static int jni_hr_del(int); + + +//=== JNI functions (NB first 6 are cited in macros used subsequently) ============================= + +// this now checks that the atom's name resembles a tag (PS 18/Jun/2004) +static bool +jni_tag_to_iref( + atom_t a, + int *iref + ) + { + const char *s = PL_atom_chars(a); + + return strlen(s) == 12 + && s[0] == 'J' + && s[1] == '#' + && isdigit(s[2]) + && isdigit(s[3]) + && isdigit(s[4]) + && isdigit(s[5]) + && isdigit(s[6]) + && isdigit(s[7]) + && isdigit(s[8]) + && isdigit(s[9]) + && isdigit(s[10]) + && isdigit(s[11]) // s is like 'J#0123456789' + && (*iref=atoi(&s[2])) != 0; + } + + +static bool +jni_iref_to_tag( + int iref, + atom_t *a + ) + { + char abuf[13]; + + sprintf( abuf, "J#%010u", iref); // oughta encapsulate this mapping... + *a = PL_new_atom(abuf); + PL_unregister_atom(*a); // empirically decrement reference count... + return TRUE; // can't fail (?!) + } + + +static bool +jni_object_to_iref( + jobject obj, // a newly returned JNI local ref + int *iref // gets an integerised, canonical, global equivalent + ) + { + int r; // temp for result code + + if ( (r=jni_hr_add(obj,iref)) == JNI_HR_ADD_NEW ) + { + hr_add_count++; // obj was novel, has been added to dict + return TRUE; + } + else + if ( r == JNI_HR_ADD_OLD ) + { + hr_old_count++; // obj was already in dict + return TRUE; + } + else + { + return FALSE; // r == JNI_HR_ADD_FAIL, presumably + } + } + + +// retract all jpl_iref_type_cache(Iref,_) facts +static bool +jni_tidy_iref_type_cache( + int iref + ) + { + term_t goal = PL_new_term_ref(); + + PL_unify_term( goal, + PL_FUNCTOR, PL_new_functor(PL_new_atom("jpl_tidy_iref_type_cache"),1), + PL_INTEGER, iref + ); + return PL_call( + goal, + PL_new_module(PL_new_atom("user")) + ); + } + + +// could merge this into jni_hr_del() ? +static bool +jni_free_iref( // called indirectly from agc hook when a possible iref is unreachable + int iref + ) + { + + if ( jni_hr_del(iref) ) // iref matched a hashedref table entry? (in which case, was deleted) + { + if ( !jni_tidy_iref_type_cache(iref) ) + { + DEBUG(0, Sdprintf( "[JPL: jni_tidy_iref_type_cache(%u) failed]\n", iref)); + } + hr_del_count++; + return TRUE; + } + else + { + return FALSE; + } + } + + +static bool +jni_string_to_atom( // called from the JNI_jobject_to_term(J,T) macro + jobject obj, + atom_t *a + ) + { + const char *cp; + + return (cp=(*env)->GetStringUTFChars(env,obj,NULL)) != NULL + && ( *a=PL_new_atom(cp), TRUE) + && ( (*env)->ReleaseStringUTFChars(env,obj,cp), TRUE); + } + + +/* +%T jni_tag_to_iref( +atom, -integer) + */ + +// an FLI wrapper for jni_tag_to_iref() above +// with luck, this will be redundant when hybrid atom+int tag scheme is sorted +// is currently called by jpl_tag_to_type/2, jpl_cache_type_of_object/2 +// jpl_tag_to_type/2 is called by jpl_object_to_type/2, jpl_ref_to_type/2 +// +static foreign_t +jni_tag_to_iref_plc( + term_t tt, + term_t ti + ) + { + atom_t a; + int iref; + + return PL_get_atom(tt,&a) + && jni_tag_to_iref(a,&iref) + && PL_unify_integer(ti,iref); + } + + +// this will be hooked to SWI-Prolog's PL_agc_hook, +// and is called just before each redundant atom is expunged from the dict +// NB need to be able to switch this on and off from Prolog... +// +static bool +jni_atom_freed( + atom_t a + ) + { + const char *cp = PL_atom_chars(a); + int iref; + char cs[11]; + + if ( jni_tag_to_iref( a, &iref) ) // check format and convert digits to int if ok + { + sprintf( cs, "%010u", iref); // reconstruct digits part of tag in cs + if ( strcmp(&cp[2],cs) != 0 ) // original digits != reconstructed digits? + { + DEBUG(0, Sdprintf( "[JPL: garbage-collected tag '%s'=%u is bogus (not canonical)]\n", cp, iref)); + } + else + if ( !jni_free_iref(iref) ) // free it (iff it's in the hashedref table) + { + DEBUG(0, Sdprintf( "[JPL: garbage-collected tag '%s' is bogus (not in HashedRefs)]\n", cp)); + } + } + else + { + } + return TRUE; // means "go ahead and expunge the atom" (we do this regardless) + } + + +//=== "hashed ref" (canonical JNI global reference) support ======================================== + +/* +%T jni_hr_info( -term, -term, -term, -term) + */ + +static foreign_t +jni_hr_info_plc( // implements jni_hr_info/4 + term_t t1, // -integer: # object references currently in hash table + term_t t2, // -integer: total # object references so far added + term_t t3, // -integer: total # object references so far found to be already in table + term_t t4 // -integer: total # object references deleted from table (by atom GC) + ) + { + return PL_unify_integer(t1,(hr_table==NULL?0:hr_table->count)) // 0 was -1 (??) + && PL_unify_integer(t2,hr_add_count) + && PL_unify_integer(t3,hr_old_count) + && PL_unify_integer(t4,hr_del_count); + } + + +// unifies t2 with a Prolog term which represents the contents of the hashtable slot +// +static bool +jni_hr_table_slot( + term_t t2, + HrEntry *slot + ) + { + term_t tp = PL_new_term_ref(); + + if ( slot == NULL ) + { + return PL_unify_nil(t2); + } + else + { + return PL_unify_list(t2,tp,t2) + && PL_unify_term(tp, + PL_FUNCTOR, PL_new_functor(PL_new_atom("-"),2), + PL_INTEGER, slot->hash, + PL_INTEGER, (int)(slot->obj) + ) + && jni_hr_table_slot(t2,slot->next) + ; + } + } + + +/* +%T jni_hr_table( -term) + */ +// unifies t with a list of hash table slot representations +// +static foreign_t +jni_hr_table_plc( + term_t t + ) + { + term_t t1 = PL_copy_term_ref(t); + term_t t2 = PL_new_term_ref(); + int i; + + for ( i=0 ; ilength ; i++ ) + { + if ( !PL_unify_list(t1,t2,t1) || !jni_hr_table_slot(t2,hr_table->slots[i]) ) + { + return FALSE; + } + } + return PL_unify_nil(t1); + } + + +// an empty table of length is successfully created, where none was before +// +static bool +jni_hr_create( + int length // required # slots in table + ) + { + int i; // temp for iterative slot initialisation + + if ( hr_table != NULL ) + { + return FALSE; // table already exists (destroy before recreating) + } + if ( length <= 0 ) + { + return FALSE; // unsuitable length + } + if ( (hr_table=(HrTable*)malloc(sizeof(HrTable))) == NULL ) + { + return FALSE; // malloc failed (out of memory, presumably) + } + hr_table->length = length; + hr_table->threshold = (int)(hr_table->length*JNI_HR_LOAD_FACTOR); + if ( (hr_table->slots=(HrEntry**)malloc(length*sizeof(HrEntry*))) == NULL ) + { + return FALSE; // malloc failed: out of memory, presumably + } + for ( i=0 ; ilength ; i++ ) + { + hr_table->slots[i] = NULL; + } + hr_table->count = 0; + return TRUE; + } + + +// an empty table of some default length is successfully created, where none was before +// +static bool +jni_hr_create_default(void) + { + + return jni_hr_create( 101); + } + + +// ep must point to a chain of zero or more entries; they are freed +// +static void +jni_hr_free_chain_entries( + HrEntry *ep + ) + { + + if ( ep != NULL ) + { + jni_hr_free_chain_entries( ep->next); + free( ep); + } + } + + +// table t is emptied +// +static void +jni_hr_free_table_chains( + HrTable *t + ) + { + int index; + + for ( index=0 ; index<(t->length) ; index++ ) + { + jni_hr_free_chain_entries( t->slots[index]); + t->slots[index] = NULL; + } + t->count = 0; + } + + +// all dynamic space used by the pointed-to table is freed +// +static bool +jni_hr_free_table( + HrTable *t + ) + { + + if ( t == NULL ) + { + return FALSE; // table does not exist + } + else + { + jni_hr_free_table_chains( t); + free( t); + return TRUE; + } + } + + +// the current table is replaced by an equivalent one with more free space +// +static bool +jni_hr_rehash(void) + { + HrTable *t0; // old table while building new one from it + int i; // for iterating through slots in old table + HrEntry *ep1; // for iterating through all entries in old table + HrEntry *ep2; // an old table entry being relinked into new table + int index; // slot index in new table of entry being transferred + + t0 = hr_table; // temporarily hold onto former table + hr_table = NULL; // precondition for jni_hr_create + if ( !jni_hr_create(2*t0->length+1) ) // new bigger table in its place + { + hr_table = t0; // replace former table for tidiness + return FALSE; // failed to create replacement table during rehash + } + for ( i=0 ; ilength ; i++ ) // for each slot in *former* table + { + for ( ep1=t0->slots[i] ; ep1!=NULL ; ) + { // for each entry in that slot's chain + ep2 = ep1; // grab this entry + ep1 = ep1->next; // advance to next entry or NULL + index = (ep2->hash & 0x7fffffff) % hr_table->length; // new + ep2->next = hr_table->slots[index]; // relink into new array + hr_table->slots[index] = ep2; // " + } + t0->slots[i] = NULL; // tidy old array for generic freeing later + } + hr_table->count = t0->count; // new table's count is old table's count + jni_hr_free_table( t0); // free all space used by old table (NB no entries) + return TRUE; + } + + +static bool +jni_hr_hash( + jobject obj, // MUST BE a valid non-null reference to a Java object + int *hash // gets obj's System.identityHashCode() + ) + { + jobject e; // for possible (but unlikely?) exception + + *hash = (*env)->CallStaticIntMethod(env,sys_class,sys_ihc,obj,(int)obj); + return (e=(*env)->ExceptionOccurred(env))==NULL; + } + + +// returns +// JNI_HR_ADD_NEW -> referenced object is novel +// JNI_HR_ADD_OLD -> referenced object is already known +// JNI_HR_ADD_FAIL -> something went wrong +// and, in *iref, an integerised canonical global ref to the object +// +static int +jni_hr_add( + jobject lref, // new JNI local ref from a regular JNI call + int *iref // for integerised canonical global ref + ) + { + int hash; // System.identityHashCode of lref + int index; // lref's slot index, from hash + HrEntry *ep; // temp entry pointer for chain traversal + jobject gref; // iff lref is novel, will hold a global surrogate + + if ( hr_table==NULL && !jni_hr_create_default() ) + { + return JNI_HR_ADD_FAIL; // lazy table creation failed: oughta sort return codes + } + if ( !jni_hr_hash(lref,&hash) ) + { + return JNI_HR_ADD_FAIL; // System.identityHashCode() failed (?) + } + index = (hash & 0x7fffffff) % hr_table->length; // make this a macro? + for ( ep=hr_table->slots[index] ; ep!=NULL ; ep=ep->next ) + { + if ( ep->hash==hash ) + { + if ( (*env)->IsSameObject(env,ep->obj,lref) ) + { // newly referenced object is already interned + (*env)->DeleteLocalRef(env,lref); // free redundant new ref + *iref = (int)(ep->obj); // old, equivalent (global) ref + return JNI_HR_ADD_OLD; + } + } + } + if ( hr_table->count >= hr_table->threshold ) + { + (void)jni_hr_rehash(); // oughta check for failure, and return it... + return jni_hr_add(lref,iref); // try again with new, larger table + } + // referenced object is novel, and we can add it to table + if ( (gref=(*env)->NewGlobalRef(env,lref)) == NULL ) // derive a global ref + { + return JNI_HR_ADD_FAIL; + } + (*env)->DeleteLocalRef(env,lref); // free redundant (local) ref + ep = (HrEntry*)malloc(sizeof(HrEntry)); + ep->hash = hash; + ep->obj = gref; + ep->next = hr_table->slots[index]; // insert at front of chain + hr_table->slots[index] = ep; + hr_table->count++; + *iref = (int)gref; // pass back the (new) global ref + return JNI_HR_ADD_NEW; // obj was newly interned, under iref as supplied + } + + +// iref corresponded to an entry in the current HashedRef table; +// now that entry is gone, its space is recovered, counts are adjusted etc. +// +static bool +jni_hr_del( + int iref // a possibly spurious canonical global iref + ) + { + int index; // index to a HashedRef table slot + HrEntry *ep; // pointer to a HashedRef table entry + HrEntry **epp; // pointer to ep's handle, in case it needs updating + + DEBUG(1, Sdprintf( "[removing possible object reference %u]\n", obj)); + for ( index=0 ; indexlength ; index++ ) // for each slot + { + for ( epp=&(hr_table->slots[index]), ep=*epp ; ep!=NULL ; epp=&(ep->next), ep=*epp ) + { + if ( (int)(ep->obj) == iref ) // found the sought entry? + { + (*env)->DeleteGlobalRef( env, ep->obj); // free the global object reference + *epp = ep->next; // bypass the entry + free( ep); // free the now-redundant space + hr_table->count--; // adjust table's entry count + DEBUG(1, Sdprintf( "[found & removed hashtable entry for object reference %u]\n", iref)); + // should we do something with jni_iref_tidy_type_cache() here? + return TRUE; // entry found and removed + } + } + } + DEBUG(1, Sdprintf("[JPL: failed to find hashtable entry for (presumably bogus) object reference %u]\n", iref)); + return FALSE; + } + + +#if 0 /* These functions are not yet used */ + +static void +jni_hr_destroy() // tidily returns to consistent "table absent" state + { + + jni_hr_free_table( hr_table); + hr_table = NULL; + } + + +// this gets called OK, but I don't know the state of the JVM, +// or what happens to a pending JNI call +// +static void +jvm_exit( + jint code + ) + { + // term_t e = PL_new_term_ref(); + + // PL_unify_term( e, + // PL_FUNCTOR, JNI_functor_java_exception_2, + // PL_CHARS, "exited", + // PL_INTEGER, code + // ); + // return PL_raise_exception(e); + DEBUG(0, Sdprintf( "[JPL: JVM exits: code=%d]\n", code)); + } + + +// this gets called OK, but I don't know the state of the JVM, +// or what happens to a pending JNI call +// +static void +jvm_abort(void) + { + // term_t e = PL_new_term_ref(); + + // PL_unify_term( e, + // PL_FUNCTOR, JNI_functor_java_exception_2, + // PL_CHARS, "aborted", + // PL_INTEGER, 0 + // ); + // return PL_raise_exception(e); + DEBUG(0, Sdprintf( "[JPL: JVM aborts]\n")); + } + +#endif /*0*/ + + +// called once: after successful PVM & JVM creation/discovery, before any JNI calls +// +static int +jni_init(void) + { + jclass lref; // temporary local ref, replaced by global + + // these initialisations require an active PVM: + JNI_atom_false = PL_new_atom( "false"); + JNI_atom_true = PL_new_atom( "true"); + + JNI_atom_boolean = PL_new_atom( "boolean"); + JNI_atom_char = PL_new_atom( "char"); + JNI_atom_byte = PL_new_atom( "byte"); + JNI_atom_short = PL_new_atom( "short"); + JNI_atom_int = PL_new_atom( "int"); + JNI_atom_long = PL_new_atom( "long"); + JNI_atom_float = PL_new_atom( "float"); + JNI_atom_double = PL_new_atom( "double"); + + JNI_atom_null = PL_new_atom( "null"); + JNI_atom_void = PL_new_atom( "void"); // not yet used properly (?) + + JNI_functor_at_1 = PL_new_functor( PL_new_atom("@"), 1); + JNI_functor_jbuf_2 = PL_new_functor( PL_new_atom("jbuf"), 2); + JNI_functor_jlong_2 = PL_new_functor( PL_new_atom("jlong"), 2); + JNI_functor_jfieldID_1 = PL_new_functor( PL_new_atom("jfieldID"), 1); + JNI_functor_jmethodID_1 = PL_new_functor( PL_new_atom("jmethodID"), 1); + + JNI_functor_error_2 = PL_new_functor(PL_new_atom("error"), 2); + JNI_functor_java_exception_1 = PL_new_functor( PL_new_atom("java_exception"), 1); + JNI_functor_jpl_error_1 = PL_new_functor( PL_new_atom("jpl_error"), 1); + + (void)PL_agc_hook( jni_atom_freed); // link atom GC to object GC (cool:-) + + // these initialisations require an active JVM: + return ( (lref=(*env)->FindClass(env,"java/lang/Class")) != NULL + && (c_class=(*env)->NewGlobalRef(env,lref)) != NULL + && ( (*env)->DeleteLocalRef(env,lref), TRUE) + && (lref=(*env)->FindClass(env,"java/lang/String")) != NULL + && (str_class=(*env)->NewGlobalRef(env,lref)) != NULL + && ( (*env)->DeleteLocalRef(env,lref), TRUE) + && (c_getName=(*env)->GetMethodID(env,c_class,"getName","()Ljava/lang/String;")) != NULL + && (lref=(*env)->FindClass(env,"java/lang/System")) != NULL + && (sys_class=(*env)->NewGlobalRef(env,lref)) != NULL + && ( (*env)->DeleteLocalRef(env,lref), TRUE) + && (sys_ihc=(*env)->GetStaticMethodID(env,sys_class,"identityHashCode","(Ljava/lang/Object;)I")) != NULL + ? 0 + : -7 // NB #define this? + ) + ; + } + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +jni_new_java_exception(char *comment, atom_t ex) + +Throw a java exception as error(java_exception(@ex), comment) +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +static term_t +jni_new_java_exception( // construct a Prolog exception structure java_exception/2 + const char *m, // to represent a caught Java exception + atom_t a + ) + { + term_t e = PL_new_term_ref(); + + PL_unify_term(e, + PL_FUNCTOR, JNI_functor_error_2, + PL_FUNCTOR, JNI_functor_java_exception_1, + PL_FUNCTOR, JNI_functor_at_1, + PL_ATOM, a, + PL_CHARS, m); + return e; + } + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +jni_new_jpl_error(char *comment, atom_t ex) + +As above, but used for internal JPL errors +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +static term_t +jni_new_jpl_error( // construct a Prolog exception structure jpl_error/2 + const char *m, // to represent an exceptional condition within JSP + atom_t a + ) + { + term_t e = PL_new_term_ref(); + + PL_unify_term(e, + PL_FUNCTOR, JNI_functor_error_2, + PL_FUNCTOR, JNI_functor_jpl_error_1, + PL_FUNCTOR, JNI_functor_at_1, + PL_ATOM, a, + PL_CHARS, m); + return e; + } + + +// test for a raised exception; clear and report it if found +// +static bool +jni_check_exception(void) + { + jobject ej; // the pending Java exception, if any + jobject c; // its class + jobject s; // its class name as a JVM String, for the report + const char *cp; // its class name as a C string + term_t ep; // a newly created Prolog exception + int i; // temp for an iref denoting a Java exception + atom_t a; // temp for a tag denoting a Java exception + + if ( (ej=(*env)->ExceptionOccurred(env)) == NULL ) + { + return TRUE; + } + else + { + (*env)->ExceptionClear(env); // clear "exception-pending" state so we can do JNI calls + if ( (c=(*env)->GetObjectClass(env,ej)) != NULL ) + { // we've got its class + if ( (s=(*env)->CallObjectMethod(env,c,c_getName)) != NULL ) + { // we've got its name as a String + if ( jni_object_to_iref(ej,&i) ) + { + if ( jni_iref_to_tag(i,&a) ) + { + if ( (cp=(*env)->GetStringUTFChars(env,s,NULL)) != NULL ) + { + DEBUG(1, Sdprintf( "[#JNI exception occurred: %s]\n", cp)); + ep = jni_new_java_exception(cp,a); + (*env)->ReleaseStringUTFChars(env,s,cp); + } + else + { + ep = jni_new_jpl_error("FailedToGetUTFCharsOfNameOfClassOfException",a); + } + } + else + { + ep = jni_new_jpl_error("FailedToConvertExceptionIrefToTagatom",JNI_atom_null); + } + } + else + { + ep = jni_new_jpl_error("FailedToConvertExceptionObjectToIref",JNI_atom_null); + } + (*env)->DeleteLocalRef(env,s); + } + else + { + ep = jni_new_jpl_error("FailedToGetNameOfClassOfException",JNI_atom_null); + } + (*env)->DeleteLocalRef(env,c); + } + else + { + ep = jni_new_jpl_error("FailedToGetClassOfException",JNI_atom_null); + } + return PL_raise_exception(ep); + } + } + + +//=== buffer and method param transput ============================================================= + +/* +%T jni_byte_buf_length_to_codes( +integer, +integer, -term) + */ + +static foreign_t +jni_byte_buf_length_to_codes_plc( // carefully s/chars/codes/ :-( + term_t tbb, + term_t tlen, + term_t tcs + ) + { + functor_t fn; + term_t a1; + atom_t a; + term_t a2; + jbyte *bb; + int len; + int i; + term_t tl = PL_copy_term_ref( tcs); + term_t ta = PL_new_term_ref(); + void *ptr; + + if ( !( PL_get_functor(tbb,&fn) + && fn==JNI_functor_jbuf_2 + && ( a2=PL_new_term_ref(), + PL_get_arg(2,tbb,a2) + ) + && PL_get_atom(a2,&a) + && a==JNI_atom_byte + && ( a1=PL_new_term_ref(), + PL_get_arg(1,tbb,a1) + ) + && PL_get_pointer(a1,&ptr) + ) + || !PL_get_integer(tlen,&len) + ) + { + return FALSE; + } + bb = ptr; + + for ( i=0 ; i first) + term_t txc, // transput code, as Prolog integer, appropriate to this param + term_t tt, // param value as datum (value or ref) + term_t tjvp // param buffer (allocated just for this call) + ) + { + int n; // got from tn (see above) + int xc; // got from txc (see above) + jvalue *jvp; // got from tjvp (see above) + functor_t fn; // temp for conversion macros + term_t a1; // " + term_t a2; // " + atom_t a; // " + char *cp; // " + int i; // " + int xhi; // " + int xlo; // " + // jobject j; // " + jlong jl; // " + int ix; // temp for conversion + double dx; // " + long lx; // " + void *ptr; + + if ( !PL_get_integer(tn,&n) || + !PL_get_integer(txc,&xc) || + !PL_get_pointer(tjvp,&ptr) ) + { + return FALSE; + } + jvp = ptr; + + switch ( xc ) + { + case JNI_XPUT_BOOLEAN: + return JNI_term_to_jboolean(tt,jvp[n].z); + + case JNI_XPUT_BYTE: + return PL_get_integer(tt,&ix) + && ix >= JNI_MIN_JBYTE + && ix <= JNI_MAX_JBYTE + && ( (jvp[n].b=(jboolean)ix) , TRUE ); + + case JNI_XPUT_CHAR: + return PL_get_integer(tt,&ix) + && ix >= JNI_MIN_JCHAR + && ix <= JNI_MAX_JCHAR + && ( (jvp[n].c=(jchar)ix) , TRUE ); + + case JNI_XPUT_SHORT: + return PL_get_integer(tt,&ix) + && ix >= JNI_MIN_JSHORT + && ix <= JNI_MAX_JSHORT + && ( (jvp[n].s=(jshort)ix) , TRUE ); + + case JNI_XPUT_INT: + return JNI_term_to_jint(tt,jvp[n].i); + + case JNI_XPUT_LONG: + return JNI_term_to_jlong(tt,jvp[n].j); + + case JNI_XPUT_FLOAT: + return ( PL_get_float(tt,&dx) + ? ( jvp[n].f=(jfloat)dx, TRUE) + : ( PL_get_integer(tt,&ix) + ? ( jvp[n].f=(jfloat)ix, TRUE) + : ( JNI_jlong2_to_jlong(tt,lx) + ? ( jvp[n].f=(jfloat)lx, TRUE) + : FALSE + ) + ) + ); + + case JNI_XPUT_DOUBLE: + return JNI_term_to_jdouble(tt,jvp[n].d); + + case JNI_XPUT_REF: + return JNI_term_to_ref(tt,jvp[n].l); + + default: + return FALSE; // unknown or inappropriate JNI_XPUT_* code + } + } + + +/* +%T jni_alloc_buffer( +integer, +integer, -integer) + */ + +// for completeness, allocates zero-length buffers too, +// while avoiding malloc() problems +// +static foreign_t +jni_alloc_buffer_plc( + term_t txc, // +transput code + term_t tlen, // +required length (# items) + term_t tbp // -PL_POINTER to newly allocated buffer + ) + { + int xc; + int len; + void *bp; + + return PL_get_integer(txc,&xc) + && ( ( xc>=JNI_XPUT_BOOLEAN && xc<=JNI_XPUT_DOUBLE ) || xc==JNI_XPUT_JVALUE ) + && PL_get_integer(tlen,&len) + && len >= 0 + && (bp=malloc((len==0?1:len)*size[xc])) != NULL // avoid (unsafe) malloc(0) + && ( PL_unify_pointer(tbp,(void*)bp) + ? TRUE + : ( free(bp), FALSE) + ) + ; + } + + +/* +%T jni_free_buffer( +integer) + */ + +static foreign_t +jni_free_buffer_plc( + term_t tbp // +pointer: a redundant buffer + ) + { + void *bp; + + return PL_get_pointer(tbp,&bp) + && ( free(bp), TRUE); + } + + +/* +%T jni_fetch_buffer_value( +integer, +integer, +integer, -integer, -term) + */ + +// NB simplify this routine as done for jni_params_put +// +static foreign_t +jni_fetch_buffer_value_plc( + term_t tbp, // +pointer: an active buffer from jni_alloc_buffer/3 + term_t ti, // +integer: index into buffer; 0 <= i < length + term_t tv2, // -integer: hi int of value, or 0 + term_t tv1, // -integer|-float: lo int of value, or float + term_t txc // +integer: transput code (one of JNI_XPUT_*) + ) + { + void *bp; // buffer address (trusted to be valid) + int i; // buffer index (trusted to be valid) + int xc; // transput code (range-checked by switch statement) + + if ( !PL_get_pointer(tbp,&bp) || !PL_get_integer(ti,&i) || !PL_get_integer(txc,&xc) ) + { + return FALSE; + } + + switch ( xc ) + { + case JNI_XPUT_BOOLEAN: + return PL_unify_integer(tv2,0) + && PL_unify_integer(tv1,((jboolean*)bp)[i]); + + case JNI_XPUT_CHAR: + return PL_unify_integer(tv2,0) + && PL_unify_integer(tv1,((jchar*)bp)[i]); + + case JNI_XPUT_BYTE: + return PL_unify_integer(tv2,0) + && PL_unify_integer(tv1,((jbyte*)bp)[i]); + + case JNI_XPUT_SHORT: + return PL_unify_integer(tv2,0) + && PL_unify_integer(tv1,((jshort*)bp)[i]); + + case JNI_XPUT_INT: + return PL_unify_integer(tv2,0) + && PL_unify_integer(tv1,((jint*)bp)[i]); + + case JNI_XPUT_LONG: + return PL_unify_integer(tv2,((int*)&((jlong*)bp)[i])[1]) + && PL_unify_integer(tv1,((int*)&((jlong*)bp)[i])[0]); + + case JNI_XPUT_FLOAT: + return PL_unify_integer(tv2,0) + && PL_unify_float(tv1,((jfloat*)bp)[i]); + + case JNI_XPUT_DOUBLE: + return PL_unify_integer(tv2,((int*)&((jdouble*)bp)[i])[1]) + && PL_unify_integer(tv1,((int*)&((jdouble*)bp)[i])[0]); + default: + return FALSE; + } + } + + +/* +%T jni_stash_buffer_value( +integer, +integer, +integer, +term, +integer) + */ + +static foreign_t +jni_stash_buffer_value_plc( + term_t tbp, + term_t ti, + term_t tv2, + term_t tv1, + term_t txc + ) + { + void *bp; + int i; + int xc; + // int v1; + // int v2; + jlong vjl; + double vd; + + if ( !PL_get_pointer(tbp,&bp) + || !PL_get_integer(ti,&i) + || !PL_get_integer(txc,&xc) + ) + { + return FALSE; + } + + switch ( xc ) + { + case JNI_XPUT_BOOLEAN: + return PL_get_integer(tv1,(int*)&((jboolean*)bp)[i]); // NB not &(int) + + case JNI_XPUT_CHAR: + return PL_get_integer(tv1,(int*)&((jchar*)bp)[i]); // NB not &(int) + + case JNI_XPUT_BYTE: + return PL_get_integer(tv1,(int*)&((jbyte*)bp)[i]); // NB not &(int) + + case JNI_XPUT_SHORT: + return PL_get_integer(tv1,(int*)&((jshort*)bp)[i]); // NB not &(int) + + case JNI_XPUT_INT: + return PL_get_integer(tv1,(int*)&((jint*)bp)[i]); + + case JNI_XPUT_LONG: + return PL_get_integer(tv2,&((int*)&((jlong*)bp)[i])[1]) + && PL_get_integer(tv1,&((int*)&((jlong*)bp)[i])[0]); + + case JNI_XPUT_FLOAT: + return PL_get_float(tv1,&vd) + && ( ((jfloat*)bp)[i]=(jfloat)vd, TRUE); + + case JNI_XPUT_DOUBLE: + return PL_get_integer(tv2,&((int*)&((jdouble*)bp)[i])[1]) + && PL_get_integer(tv2,&((int*)&((jdouble*)bp)[i])[0]); + + case JNI_XPUT_FLOAT_TO_DOUBLE: + return PL_get_float(tv1,&((jdouble*)bp)[i]); + + case JNI_XPUT_LONG_TO_FLOAT: + return PL_get_integer(tv2,&((int*)&vjl)[1]) + && PL_get_integer(tv1,&((int*)&vjl)[0]) + && ( ((jfloat*)bp)[i]=(jfloat)vjl, TRUE); + + case JNI_XPUT_LONG_TO_DOUBLE: + return PL_get_integer(tv2,&((int*)&vjl)[1]) + && PL_get_integer(tv1,&((int*)&vjl)[0]) + && ( ((jdouble*)bp)[i]=(jdouble)vjl, TRUE); + + default: + return FALSE; + } + } + + +//=== JVM initialisation, startup etc. ============================================================= + +// this isn't much use; it can't discover JDK 1.2 support... +static int +jni_supported_jvm_version( + int major, + int minor + ) + { + JDK1_1InitArgs vm_args; + int mhi; + int mlo; + + vm_args.version = ((major&0xFFFF)<<16) + (minor&0xFFFF); + JNI_GetDefaultJavaVMInitArgs( &vm_args); + mhi = (vm_args.version>>16)&0xFFFF; + mlo = (vm_args.version)&0xFFFF; + DEBUG(1, Sdprintf( "JNI_GetDefaultJavaVMInitArgs() returns %d,%d\n", mhi, mlo)); + return major == mhi + && minor == mlo + ; + } + + +static int +jni_get_created_jvm_count(void) + { + int n; + + return ( JNI_GetCreatedJavaVMs(NULL,0,&n) == 0 // what does the '0' arg mean? + ? n + : -1 + ) + ; + } + + +// this could be inlined, or made into a macro? +static int +jni_get_env(void) + { + JNIEnv *env0 = env; + int r; + + r = (*jvm)->GetEnv(jvm,(void**)&env,JNI_VERSION_1_2) == JNI_OK; + if ( env != env0 ) + { + DEBUG(1, Sdprintf( "[new env=%u]\n", (void*)env)); + } + return r; + } + + +#define MAX_JVM_OPTIONS 10 + +static int +jni_create_jvm_c( + char *classpath + ) + { + JavaVMInitArgs vm_args; + char cpopt[1000]; + JavaVMOption opt[MAX_JVM_OPTIONS]; + int r; + int n; + int optn = 0; + + DEBUG(1, Sdprintf( "[creating JVM with 'java.class.path=%s']\n", classpath)); + vm_args.version = JNI_VERSION_1_2; // "Java 1.2 please" + if ( classpath ) + { strcpy( cpopt, "-Djava.class.path="); + strcat( cpopt, classpath); // oughta check length... + vm_args.options = opt; + opt[optn].optionString = cpopt; + optn++; + } + // opt[optn++].optionString = "-Djava.compiler=NONE"; + // opt[optn].optionString = "exit"; // I don't understand this yet... + // opt[optn++].extraInfo = jvm_exit; + // opt[optn].optionString = "abort"; // I don't understand this yet... + // opt[optn++].extraInfo = jvm_abort; + // opt[optn++].optionString = "-Xcheck:jni"; // extra checking of JNI calls + // opt[optn++].optionString = "-Xnoclassgc"; // so method/field IDs remain valid (?) + // opt[optn].optionString = "vfprintf"; + // opt[optn++].extraInfo = fprintf; // no O/P, then SEGV + // opt[optn++].extraInfo = xprintf; // one message, then SEGV + // opt[optn++].optionString = "-verbose:jni"; + vm_args.nOptions = optn; + // vm_args.ignoreUnrecognized = TRUE; + + return + ( JNI_GetCreatedJavaVMs(&jvm,1,&n) == 0 // what does the '1' arg mean? + && n == 1 + // && (r=(*jvm)->GetEnv(jvm,(void**)&env,JNI_VERSION_1_2)) == JNI_OK + && jni_get_env() + ? 2 // success (JVM already available) + : ( (r=JNI_CreateJavaVM(&jvm,(void**)&env,&vm_args)) == 0 + ? 0 // success (JVM created OK) + : ( jvm=NULL, r) // -ve, i.e. some create error + ) + ); + } + + +static foreign_t +jni_supported_jvm_version_plc( // not as useful as I'd hoped... + term_t t1, + term_t t2 + ) + { + int major; + int minor; + + return PL_get_integer(t1,&major) + && PL_get_integer(t2,&minor) + && jni_supported_jvm_version(major,minor) + ; + } + + +static foreign_t +jni_get_created_jvm_count_plc( + term_t t1 + ) + { + + return PL_unify_integer(t1,jni_get_created_jvm_count()); + } + + +static int +jni_create_jvm( + char *cp + ) + { + int r1; + int r2; + + DEBUG(1, Sdprintf("[JPL: checking for Java VM...]\n")); + return + ( jvm != NULL + ? 1 // already initialised + : ( (r1=jni_create_jvm_c(cp)) < 0 + ? r1 // err code from JVM-specific routine + : ( (r2=jni_init()) < 0 + ? r2 // err code from jni_init() + : ( r1 == 0 // success code from JVM-specific routine + ? ( DEBUG(0, Sdprintf("[JPL: Java VM created]\n")), r1) + : ( DEBUG(0, Sdprintf("[JPL: Java VM found]\n")), r1) + ) + ) + ) + ); + } + + +/* +%T jni_create_jvm( +string, -integer) + */ +// is this useful? dangerous? redundant? +// +static foreign_t +jni_create_jvm_plc( // maps jni_create_jvm() into Prolog + term_t a1, + term_t a2 + ) + { + char *classpath; + + return PL_get_atom_chars( a1, &classpath) + && PL_unify_integer(a2,jni_create_jvm(classpath)); + } + + + + +int +jni_create_default_jvm(void) + { + char *cp; + + cp = getenv("CLASSPATH"); + return jni_create_jvm(cp) >= 0; // e.g. 2 -> "JVM already available" + } + + +/* +%T jni_ensure_jvm + */ +static foreign_t +jni_ensure_jvm_plc(void) + { + + return jni_ensure_jvm(); + } + + +// NB after any JNI call which clearly indicates success, +// it is unnecessary to check for an exception +// (potential for slight economy here...) + +/* +%T jni_void( +integer) + */ +static foreign_t +jni_void_0_plc( // C identifiers distinguished _0_ etc, Prolog name is overloaded + term_t tn + ) + { + int n; // JNI function index + jboolean r; // Prolog exit/fail outcome + + if ( !jni_ensure_jvm() // ought this either succeed or throw a JPL error? + || !PL_get_integer(tn,&n) // ought this either succeed or throw a Prolog type error? + ) + { + return FALSE; + } + + switch ( n ) + { + case 17: + r = ( (*env)->ExceptionClear(env) , TRUE ); // could just return... + break; + default: + return FALSE; // oughta throw exception (design-time error :-) + break; + } + + return jni_check_exception() && r; + } + + +/* +%T jni_void( +integer, +term) + */ +static foreign_t +jni_void_1_plc( + term_t tn, // +FuncIndex + term_t ta1 // +Arg1 + ) + { + int n; // JNI function index + // functor_t fn; // temp for conversion macros + // term_t a1; // " + // term_t a2; // " + // atom_t a; // " + // char *cp; // " + // int i; // " + // int xhi; // " + // int xlo; // " + // jobject j; // " + // jlong jl; // " + // void *p1; // temp for converted (JVM) arg + char *c1; // " + // int i1; // " + // jlong l1; // " + // double d1; // " + jboolean r; // Prolog exit/fail outcome + + if ( !jni_ensure_jvm() + || !PL_get_integer(tn,&n) + ) + { + return FALSE; + } + + switch ( n ) + { + case 18: + r = JNI_term_to_charP(ta1,c1) + && ( (*env)->FatalError(env,(char*)c1) , TRUE ); + break; + default: + return FALSE; // oughta throw exception (design-time error :-) + break; + } + + return jni_check_exception() && r; + } + + +/* +%T jni_void( +integer, +term, +term) + */ +static foreign_t +jni_void_2_plc( + term_t tn, // +FuncIndex + term_t ta1, // +Arg1 + term_t ta2 // +Arg2 + ) + { + int n; // JNI function index + functor_t fn; // temp for conversion macros + term_t a1; // " + term_t a2; // " + atom_t a; // " + char *cp; // " + // int i; // " + // int xhi; // " + // int xlo; // " + // jobject j; // " + // jlong jl; // " + void *p1; // temp for converted (JVM) arg + void *p2; // " + // char *c1; // " + char *c2; // " + // int i1; // " + // int i2; // " + // jlong l1; // " + // jlong l2; // " + // double d1; // " + // double d2; // " + jboolean r; // Prolog exit/fail outcome + + if ( !jni_ensure_jvm() + || !PL_get_integer(tn,&n) + ) + { + return FALSE; + } + + switch ( n ) + { + case 166: + r = JNI_term_to_jstring(ta1,p1) + && JNI_term_to_jbuf(ta2,p2,JNI_atom_char) + && ( (*env)->ReleaseStringChars(env,(jstring)p1,(jchar*)p2) , TRUE ); + break; + case 170: + r = JNI_term_to_jstring(ta1,p1) + && JNI_term_to_jbuf(ta2,c2,JNI_atom_byte) + && ( (*env)->ReleaseStringUTFChars(env,(jstring)p1,(char*)c2) , TRUE ); + break; + default: + return FALSE; // oughta throw exception (design-time error :-) + break; + } + + return jni_check_exception() && r; + } + + +/* +%T jni_void( +integer, +term, +term, +term) + */ +static foreign_t +jni_void_3_plc( + term_t tn, // +FuncIndex + term_t ta1, // +Arg1 + term_t ta2, // +Arg2 + term_t ta3 // +Arg3 + ) + { + int n; // JNI function index + functor_t fn; // temp for conversion macros + term_t a1; // " + term_t a2; // " + atom_t a; // " + char *cp; // " + int i; // " + int xhi; // " + int xlo; // " + // jobject j; // " + jlong jl; // " + void *p1; // temp for converted (JVM) arg + void *p2; // " + void *p3; // " + // char *c1; // " + // char *c2; // " + // char *c3; // " + // int i1; // " + int i2; // " + int i3; // " + // jlong l1; // " + // jlong l2; // " + jlong l3; // " + // double d1; // " + // double d2; // " + double d3; // " + jvalue *jvp = NULL; // if this is given a buffer, it will be freed after the call + jboolean r; // Prolog exit/fail outcome + + if ( !jni_ensure_jvm() + || !PL_get_integer(tn,&n) + ) + { + return FALSE; + } + + switch ( n ) + { + case 63: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && ( (*env)->CallVoidMethodA(env,(jobject)p1,(jmethodID)p2,jvp) , TRUE ); + break; + case 143: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && ( (*env)->CallStaticVoidMethodA(env,(jclass)p1,(jmethodID)p2,jvp) , TRUE ); + break; + case 104: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_ref(ta3,p3) + && ( (*env)->SetObjectField(env,(jobject)p1,(jfieldID)p2,(jobject)p3) , TRUE ); + break; + case 105: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jboolean(ta3,i3) + && ( (*env)->SetBooleanField(env,(jobject)p1,(jfieldID)p2,(jboolean)i3) , TRUE ); + break; + case 106: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jbyte(ta3,i3) + && ( (*env)->SetByteField(env,(jobject)p1,(jfieldID)p2,(jbyte)i3) , TRUE ); + break; + case 107: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jchar(ta3,i3) + && ( (*env)->SetCharField(env,(jobject)p1,(jfieldID)p2,(jchar)i3) , TRUE ); + break; + case 108: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jshort(ta3,i3) + && ( (*env)->SetShortField(env,(jobject)p1,(jfieldID)p2,(jshort)i3) , TRUE ); + break; + case 109: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jint(ta3,i3) + && ( (*env)->SetIntField(env,(jobject)p1,(jfieldID)p2,(jint)i3) , TRUE ); + break; + case 110: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jlong(ta3,l3) + && ( (*env)->SetLongField(env,(jobject)p1,(jfieldID)p2,(jlong)l3) , TRUE ); + break; + case 111: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jfloat(ta3,d3) + && ( (*env)->SetFloatField(env,(jobject)p1,(jfieldID)p2,(jfloat)d3) , TRUE ); + break; + case 112: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jdouble(ta3,d3) + && ( (*env)->SetDoubleField(env,(jobject)p1,(jfieldID)p2,(jdouble)d3) , TRUE ); + break; + case 154: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_ref(ta3,p3) + && ( (*env)->SetStaticObjectField(env,(jclass)p1,(jfieldID)p2,(jobject)p3) , TRUE ); + break; + case 155: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jboolean(ta3,i3) + && ( (*env)->SetStaticBooleanField(env,(jclass)p1,(jfieldID)p2,(jboolean)i3) , TRUE ); + break; + case 156: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jbyte(ta3,i3) + && ( (*env)->SetStaticByteField(env,(jclass)p1,(jfieldID)p2,(jbyte)i3) , TRUE ); + break; + case 157: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jchar(ta3,i3) + && ( (*env)->SetStaticCharField(env,(jclass)p1,(jfieldID)p2,(jchar)i3) , TRUE ); + break; + case 158: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jshort(ta3,i3) + && ( (*env)->SetStaticShortField(env,(jclass)p1,(jfieldID)p2,(jshort)i3) , TRUE ); + break; + case 159: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jint(ta3,i3) + && ( (*env)->SetStaticIntField(env,(jclass)p1,(jfieldID)p2,(jint)i3) , TRUE ); + break; + case 160: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jlong(ta3,l3) + && ( (*env)->SetStaticLongField(env,(jclass)p1,(jfieldID)p2,(jlong)l3) , TRUE ); + break; + case 161: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jfloat(ta3,d3) + && ( (*env)->SetStaticFloatField(env,(jclass)p1,(jfieldID)p2,(jfloat)d3) , TRUE ); + break; + case 162: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_term_to_jdouble(ta3,d3) + && ( (*env)->SetStaticDoubleField(env,(jclass)p1,(jfieldID)p2,(jdouble)d3) , TRUE ); + break; + case 174: + r = JNI_term_to_object_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_ref(ta3,p3) + && ( (*env)->SetObjectArrayElement(env,(jobjectArray)p1,(jsize)i2,(jobject)p3) , TRUE ); + break; + case 191: + r = JNI_term_to_boolean_jarray(ta1,p1) + && JNI_term_to_jbuf(ta2,p2,JNI_atom_boolean) + && JNI_term_to_jint(ta3,i3) + && ( (*env)->ReleaseBooleanArrayElements(env,(jbooleanArray)p1,(jboolean*)p2,(jint)i3) , TRUE ); + break; + case 192: + r = JNI_term_to_byte_jarray(ta1,p1) + && JNI_term_to_jbuf(ta2,p2,JNI_atom_byte) + && JNI_term_to_jint(ta3,i3) + && ( (*env)->ReleaseByteArrayElements(env,(jbyteArray)p1,(jbyte*)p2,(jint)i3) , TRUE ); + break; + case 193: + r = JNI_term_to_char_jarray(ta1,p1) + && JNI_term_to_jbuf(ta2,p2,JNI_atom_char) + && JNI_term_to_jint(ta3,i3) + && ( (*env)->ReleaseCharArrayElements(env,(jcharArray)p1,(jchar*)p2,(jint)i3) , TRUE ); + break; + case 194: + r = JNI_term_to_short_jarray(ta1,p1) + && JNI_term_to_jbuf(ta2,p2,JNI_atom_short) + && JNI_term_to_jint(ta3,i3) + && ( (*env)->ReleaseShortArrayElements(env,(jshortArray)p1,(jshort*)p2,(jint)i3) , TRUE ); + break; + case 195: + r = JNI_term_to_int_jarray(ta1,p1) + && JNI_term_to_jbuf(ta2,p2,JNI_atom_int) + && JNI_term_to_jint(ta3,i3) + && ( (*env)->ReleaseIntArrayElements(env,(jintArray)p1,(jint*)p2,(jint)i3) , TRUE ); + break; + case 196: + r = JNI_term_to_long_jarray(ta1,p1) + && JNI_term_to_jbuf(ta2,p2,JNI_atom_long) + && JNI_term_to_jint(ta3,i3) + && ( (*env)->ReleaseLongArrayElements(env,(jlongArray)p1,(jlong*)p2,(jint)i3) , TRUE ); + break; + case 197: + r = JNI_term_to_float_jarray(ta1,p1) + && JNI_term_to_jbuf(ta2,p2,JNI_atom_float) + && JNI_term_to_jint(ta3,i3) + && ( (*env)->ReleaseFloatArrayElements(env,(jfloatArray)p1,(jfloat*)p2,(jint)i3) , TRUE ); + break; + case 198: + r = JNI_term_to_double_jarray(ta1,p1) + && JNI_term_to_jbuf(ta2,p2,JNI_atom_double) + && JNI_term_to_jint(ta3,i3) + && ( (*env)->ReleaseDoubleArrayElements(env,(jdoubleArray)p1,(jdouble*)p2,(jint)i3) , TRUE ); + break; + default: + return FALSE; // oughta throw exception (design-time error :-) + break; + } + + if ( jvp != NULL ) + { + free( jvp); + } + + return jni_check_exception() && r; + } + + +/* +%T jni_void( +integer, +term, +term, +term, +term) + */ +static foreign_t +jni_void_4_plc( + term_t tn, // +FuncIndex + term_t ta1, // +Arg1 + term_t ta2, // +Arg2 + term_t ta3, // +Arg3 + term_t ta4 // +Arg4 + ) + { + int n; // JNI function index + functor_t fn; // temp for conversion macros + term_t a1; // " + term_t a2; // " + atom_t a; // " + char *cp; // " + // int i; // " + // int xhi; // " + // int xlo; // " + // jobject j; // " + // jlong jl; // " + void *p1; // temp for converted (JVM) arg + void *p2; // " + void *p3; // " + void *p4; // " + // char *c1; // " + // char *c2; // " + // char *c3; // " + // char *c4; // " + // int i1; // " + int i2; // " + int i3; // " + // int i4; // " + // jlong l1; // " + // jlong l2; // " + // jlong l3; // " + // jlong l4; // " + // double d1; // " + // double d2; // " + // double d3; // " + // double d4; // " + jvalue *jvp = NULL; // if this is given a buffer, it will be freed after the call + jboolean r; // Prolog exit/fail outcome + + if ( !jni_ensure_jvm() + || !PL_get_integer(tn,&n) + ) + { + return FALSE; + } + + switch ( n ) + { + case 93: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jclass(ta2,p2) + && JNI_term_to_jmethodID(ta3,p3) + && JNI_term_to_pointer(ta4,jvp) + && ( (*env)->CallNonvirtualVoidMethodA(env,(jobject)p1,(jclass)p2,(jmethodID)p3,jvp) , TRUE ); + break; + case 199: + r = JNI_term_to_boolean_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_boolean) + && ( (*env)->GetBooleanArrayRegion(env,(jbooleanArray)p1,(jsize)i2,(jsize)i3,(jboolean*)p4) , TRUE ); + break; + case 200: + r = JNI_term_to_byte_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_byte) + && ( (*env)->GetByteArrayRegion(env,(jbyteArray)p1,(jsize)i2,(jsize)i3,(jbyte*)p4) , TRUE ); + break; + case 201: + r = JNI_term_to_char_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_char) + && ( (*env)->GetCharArrayRegion(env,(jcharArray)p1,(jsize)i2,(jsize)i3,(jchar*)p4) , TRUE ); + break; + case 202: + r = JNI_term_to_short_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_short) + && ( (*env)->GetShortArrayRegion(env,(jshortArray)p1,(jsize)i2,(jsize)i3,(jshort*)p4) , TRUE ); + break; + case 203: + r = JNI_term_to_int_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_int) + && ( (*env)->GetIntArrayRegion(env,(jintArray)p1,(jsize)i2,(jsize)i3,(jint*)p4) , TRUE ); + break; + case 204: + r = JNI_term_to_long_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_long) + && ( (*env)->GetLongArrayRegion(env,(jlongArray)p1,(jsize)i2,(jsize)i3,(jlong*)p4) , TRUE ); + break; + case 205: + r = JNI_term_to_float_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_float) + && ( (*env)->GetFloatArrayRegion(env,(jfloatArray)p1,(jsize)i2,(jsize)i3,(jfloat*)p4) , TRUE ); + break; + case 206: + r = JNI_term_to_double_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_double) + && ( (*env)->GetDoubleArrayRegion(env,(jdoubleArray)p1,(jsize)i2,(jsize)i3,(jdouble*)p4) , TRUE ); + break; + case 207: + r = JNI_term_to_boolean_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_boolean) + && ( (*env)->SetBooleanArrayRegion(env,(jbooleanArray)p1,(jsize)i2,(jsize)i3,(jboolean*)p4) , TRUE ); + break; + case 208: + r = JNI_term_to_byte_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_byte) + && ( (*env)->SetByteArrayRegion(env,(jbyteArray)p1,(jsize)i2,(jsize)i3,(jbyte*)p4) , TRUE ); + break; + case 209: + r = JNI_term_to_char_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_char) + && ( (*env)->SetCharArrayRegion(env,(jcharArray)p1,(jsize)i2,(jsize)i3,(jchar*)p4) , TRUE ); + break; + case 210: + r = JNI_term_to_short_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_short) + && ( (*env)->SetShortArrayRegion(env,(jshortArray)p1,(jsize)i2,(jsize)i3,(jshort*)p4) , TRUE ); + break; + case 211: + r = JNI_term_to_int_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_int) + && ( (*env)->SetIntArrayRegion(env,(jintArray)p1,(jsize)i2,(jsize)i3,(jint*)p4) , TRUE ); + break; + case 212: + r = JNI_term_to_long_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_long) + && ( (*env)->SetLongArrayRegion(env,(jlongArray)p1,(jsize)i2,(jsize)i3,(jlong*)p4) , TRUE ); + break; + case 213: + r = JNI_term_to_float_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_float) + && ( (*env)->SetFloatArrayRegion(env,(jfloatArray)p1,(jsize)i2,(jsize)i3,(jfloat*)p4) , TRUE ); + break; + case 214: + r = JNI_term_to_double_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_term_to_jint(ta3,i3) + && JNI_term_to_jbuf(ta4,p4,JNI_atom_double) + && ( (*env)->SetDoubleArrayRegion(env,(jdoubleArray)p1,(jsize)i2,(jsize)i3,(jdouble*)p4) , TRUE ); + break; + default: + return FALSE; // oughta throw exception (design-time error :-) + break; + } + + if ( jvp != NULL ) + { + free( jvp); + } + + return jni_check_exception() && r; + } + + +/* +%T jni_func( +integer, -term) + */ +static foreign_t +jni_func_0_plc( + term_t tn, // +FuncIndex + term_t tr // -Result + ) + { + int n; // JNI function index + // functor_t fn; // temp for conversion macros + // term_t a1; // " + // term_t a2; // " + atom_t a; // " + // char *cp; // " + int i; // " + // int xhi; // " + // int xlo; // " + jobject j; // " + // jlong jl; // " + jboolean r; // Prolog exit/fail outcome + + if ( !jni_ensure_jvm() + || !PL_get_integer(tn,&n) + ) + { + return FALSE; + } + + switch ( n ) + { + case 4: + r = JNI_jint_to_term((*env)->GetVersion(env),tr); + break; + case 15: + r = JNI_jobject_to_term((*env)->ExceptionOccurred(env),tr); + break; + default: + return FALSE; // oughta throw exception (design-time error :-) + break; + } + + return jni_check_exception() && r; // surely NEITHER of these throws an exception! + } + + +/* +%T jni_func( +integer, +term, -term) + */ +static foreign_t +jni_func_1_plc( + term_t tn, // +FuncIndex + term_t ta1, // +Arg1 + term_t tr // -Result + ) + { + int n; // JNI function index + functor_t fn; // temp for conversion macros + term_t a1; // " + // term_t a2; // " + atom_t a; // " + char *cp; // " + int i; // " + // int xhi; // " + // int xlo; // " + jobject j; // " + // jlong jl; // " + void *p1; // temp for converted (JVM) arg + char *c1; // " + int i1; // " + // jlong l1; // " + // double d1; // " + jboolean r; // Prolog exit/fail outcome + + if ( !jni_ensure_jvm() + || !PL_get_integer(tn,&n) + ) + { + return FALSE; + } + + + + switch ( n ) + { + case 6: + r = JNI_term_to_charP(ta1,c1) + && JNI_jobject_to_term((*env)->FindClass(env,(char*)c1),tr); + break; + case 10: + r = JNI_term_to_jclass(ta1,p1) + && JNI_jobject_to_term((*env)->GetSuperclass(env,(jclass)p1),tr); + break; + case 13: + r = JNI_term_to_throwable_jobject(ta1,p1) + && JNI_jint_to_term((*env)->Throw(env,(jthrowable)p1),tr); + break; + case 27: + r = JNI_term_to_non_array_jclass(ta1,p1) + && JNI_jobject_to_term((*env)->AllocObject(env,(jclass)p1),tr); + break; + case 31: + r = JNI_term_to_jobject(ta1,p1) + && JNI_jobject_to_term((*env)->GetObjectClass(env,(jobject)p1),tr); + break; + case 164: + r = JNI_term_to_jstring(ta1,p1) + && JNI_jint_to_term((*env)->GetStringLength(env,(jstring)p1),tr); + break; + case 167: + r = JNI_term_to_charP(ta1,c1) + && JNI_jobject_to_term((*env)->NewStringUTF(env,(char*)c1),tr); + break; + case 168: + r = JNI_term_to_jstring(ta1,p1) + && JNI_jint_to_term((*env)->GetStringUTFLength(env,(jstring)p1),tr); + break; + case 171: + r = JNI_term_to_jarray(ta1,p1) + && JNI_jint_to_term((*env)->GetArrayLength(env,(jarray)p1),tr); + break; + case 175: + r = JNI_term_to_non_neg_jint(ta1,i1) + && JNI_jobject_to_term((*env)->NewBooleanArray(env,(jsize)i1),tr); + break; + case 176: + r = JNI_term_to_non_neg_jint(ta1,i1) + && JNI_jobject_to_term((*env)->NewByteArray(env,(jsize)i1),tr); + break; + case 177: + r = JNI_term_to_non_neg_jint(ta1,i1) + && JNI_jobject_to_term((*env)->NewCharArray(env,(jsize)i1),tr); + break; + case 178: + r = JNI_term_to_non_neg_jint(ta1,i1) + && JNI_jobject_to_term((*env)->NewShortArray(env,(jsize)i1),tr); + break; + case 179: + r = JNI_term_to_non_neg_jint(ta1,i1) + && JNI_jobject_to_term((*env)->NewIntArray(env,(jsize)i1),tr); + break; + case 180: + r = JNI_term_to_non_neg_jint(ta1,i1) + && JNI_jobject_to_term((*env)->NewLongArray(env,(jsize)i1),tr); + break; + case 181: + r = JNI_term_to_non_neg_jint(ta1,i1) + && JNI_jobject_to_term((*env)->NewFloatArray(env,(jsize)i1),tr); + break; + case 182: + r = JNI_term_to_non_neg_jint(ta1,i1) + && JNI_jobject_to_term((*env)->NewDoubleArray(env,(jsize)i1),tr); + break; + case 217: + r = JNI_term_to_jobject(ta1,p1) + && JNI_jint_to_term((*env)->MonitorEnter(env,(jobject)p1),tr); + break; + case 218: + r = JNI_term_to_jobject(ta1,p1) + && JNI_jint_to_term((*env)->MonitorExit(env,(jobject)p1),tr); + break; + default: + return FALSE; // oughta throw exception (design-time error :-) + break; + } + + return jni_check_exception() && r; + } + + +/* +%T jni_func( +integer, +term, +term, -term) + */ +static foreign_t +jni_func_2_plc( + term_t tn, // +FuncIndex + term_t ta1, // +Arg1 + term_t ta2, // +Arg2 + term_t tr // -Result + ) + { + int n; // JNI function index + functor_t fn; // temp for conversion macros + term_t a1; // " + // term_t a2; // " + atom_t a; // " + char *cp; // " + int i; // " + int xhi; // " + int xlo; // " + jobject j; // " + jlong jl; // " + void *p1; // temp for converted (JVM) arg + void *p2; // " + char *c1; // " + char *c2; // " + // int i1; // " + int i2; // " + // jlong l1; // " + // jlong l2; // " + // double d1; // " + // double d2; // " + jboolean r; // Prolog exit/fail outcome + + if ( !jni_ensure_jvm() + || !PL_get_integer(tn,&n) + ) + { + return FALSE; + } + + switch ( n ) + { + case 11: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jclass(ta2,p2) + && JNI_jboolean_to_term((*env)->IsAssignableFrom(env,(jclass)p1,(jclass)p2),tr); + break; + case 14: + r = JNI_term_to_throwable_jclass(ta1,p1) + && JNI_term_to_charP(ta2,c2) + && JNI_jint_to_term((*env)->ThrowNew(env,(jclass)p1,(char*)c2),tr); + break; + case 24: + r = JNI_term_to_ref(ta1,p1) + && JNI_term_to_ref(ta2,p2) + && JNI_jboolean_to_term((*env)->IsSameObject(env,(jobject)p1,(jobject)p2),tr); + break; + case 32: + r = JNI_term_to_ref(ta1,p1) + && JNI_term_to_jclass(ta2,p2) + && JNI_jboolean_to_term((*env)->IsInstanceOf(env,(jobject)p1,(jclass)p2),tr); + break; + case 95: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jobject_to_term((*env)->GetObjectField(env,(jobject)p1,(jfieldID)p2),tr); + break; + case 96: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jboolean_to_term((*env)->GetBooleanField(env,(jobject)p1,(jfieldID)p2),tr); + break; + case 97: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jbyte_to_term((*env)->GetByteField(env,(jobject)p1,(jfieldID)p2),tr); + break; + case 98: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jchar_to_term((*env)->GetCharField(env,(jobject)p1,(jfieldID)p2),tr); + break; + case 99: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jshort_to_term((*env)->GetShortField(env,(jobject)p1,(jfieldID)p2),tr); + break; + case 100: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jint_to_term((*env)->GetIntField(env,(jobject)p1,(jfieldID)p2),tr); + break; + case 101: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jlong_to_term((*env)->GetLongField(env,(jobject)p1,(jfieldID)p2),tr); + break; + case 102: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jfloat_to_term((*env)->GetFloatField(env,(jobject)p1,(jfieldID)p2),tr); + break; + case 103: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jdouble_to_term((*env)->GetDoubleField(env,(jobject)p1,(jfieldID)p2),tr); + break; + case 145: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jobject_to_term((*env)->GetStaticObjectField(env,(jclass)p1,(jfieldID)p2),tr); + break; + case 146: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jboolean_to_term((*env)->GetStaticBooleanField(env,(jclass)p1,(jfieldID)p2),tr); + break; + case 147: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jbyte_to_term((*env)->GetStaticByteField(env,(jclass)p1,(jfieldID)p2),tr); + break; + case 148: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jchar_to_term((*env)->GetStaticCharField(env,(jclass)p1,(jfieldID)p2),tr); + break; + case 149: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jshort_to_term((*env)->GetStaticShortField(env,(jclass)p1,(jfieldID)p2),tr); + break; + case 150: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jint_to_term((*env)->GetStaticIntField(env,(jclass)p1,(jfieldID)p2),tr); + break; + case 151: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jlong_to_term((*env)->GetStaticLongField(env,(jclass)p1,(jfieldID)p2),tr); + break; + case 152: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jfloat_to_term((*env)->GetStaticFloatField(env,(jclass)p1,(jfieldID)p2),tr); + break; + case 153: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jfieldID(ta2,p2) + && JNI_jdouble_to_term((*env)->GetStaticDoubleField(env,(jclass)p1,(jfieldID)p2),tr); + break; + case 163: + r = JNI_term_to_charP(ta1,c1) // oughta be _jcharP, i.e. Unicode + && JNI_term_to_non_neg_jint(ta2,i2) + && JNI_jobject_to_term((*env)->NewString(env,(jchar*)c1,(jsize)i2),tr); + break; + case 165: + r = JNI_term_to_jstring(ta1,p1) + && JNI_jbuf_to_term((*env)->GetStringChars(env,(jstring)p1,(jboolean*)&i2),tr,JNI_atom_boolean) + && JNI_jboolean_to_term(i2,ta2); + break; + case 169: + r = JNI_term_to_jstring(ta1,p1) + && JNI_jbuf_to_term((*env)->GetStringUTFChars(env,(jstring)p1,(jboolean*)&i2),tr,JNI_atom_byte) + && JNI_jboolean_to_term(i2,ta2); + break; + case 173: + r = JNI_term_to_object_jarray(ta1,p1) + && JNI_term_to_jint(ta2,i2) + && JNI_jobject_to_term((*env)->GetObjectArrayElement(env,(jobjectArray)p1,(jsize)i2),tr); + break; + case 183: + r = JNI_term_to_boolean_jarray(ta1,p1) + && JNI_jbuf_to_term((*env)->GetBooleanArrayElements(env,(jbooleanArray)p1,(jboolean*)&i2),tr,JNI_atom_boolean) + && JNI_jboolean_to_term(i2,ta2); + break; + case 184: + r = JNI_term_to_byte_jarray(ta1,p1) + && JNI_jbuf_to_term((*env)->GetByteArrayElements(env,(jbyteArray)p1,(jboolean*)&i2),tr,JNI_atom_byte) + && JNI_jboolean_to_term(i2,ta2); + break; + case 185: + r = JNI_term_to_char_jarray(ta1,p1) + && JNI_jbuf_to_term((*env)->GetCharArrayElements(env,(jcharArray)p1,(jboolean*)&i2),tr,JNI_atom_char) + && JNI_jboolean_to_term(i2,ta2); + break; + case 186: + r = JNI_term_to_short_jarray(ta1,p1) + && JNI_jbuf_to_term((*env)->GetShortArrayElements(env,(jshortArray)p1,(jboolean*)&i2),tr,JNI_atom_short) + && JNI_jboolean_to_term(i2,ta2); + break; + case 187: + r = JNI_term_to_int_jarray(ta1,p1) + && JNI_jbuf_to_term((*env)->GetIntArrayElements(env,(jintArray)p1,(jboolean*)&i2),tr,JNI_atom_int) + && JNI_jboolean_to_term(i2,ta2); + break; + case 188: + r = JNI_term_to_long_jarray(ta1,p1) + && JNI_jbuf_to_term((*env)->GetLongArrayElements(env,(jlongArray)p1,(jboolean*)&i2),tr,JNI_atom_long) + && JNI_jboolean_to_term(i2,ta2); + break; + case 189: + r = JNI_term_to_float_jarray(ta1,p1) + && JNI_jbuf_to_term((*env)->GetFloatArrayElements(env,(jfloatArray)p1,(jboolean*)&i2),tr,JNI_atom_float) + && JNI_jboolean_to_term(i2,ta2); + break; + case 190: + r = JNI_term_to_double_jarray(ta1,p1) + && JNI_jbuf_to_term((*env)->GetDoubleArrayElements(env,(jdoubleArray)p1,(jboolean*)&i2),tr,JNI_atom_double) + && JNI_jboolean_to_term(i2,ta2); + break; + default: + return FALSE; // oughta throw exception (design-time error :-) + break; + } + + return jni_check_exception() && r; + } + + +/* +%T jni_func( +integer, +term, +term, +term, -term) + */ +static foreign_t +jni_func_3_plc( + term_t tn, // +FuncIndex + term_t ta1, // +Arg1 + term_t ta2, // +Arg2 + term_t ta3, // +Arg3 + term_t tr // -Result + ) + { + int n; // JNI function index + functor_t fn; // temp for conversion macros + term_t a1; // " + // term_t a2; // " + atom_t a; // " + char *cp; // " + int i; // " + int xhi; // " + int xlo; // " + jobject j; // " + jlong jl; // " + void *p1; // temp for converted (JVM) arg + void *p2; // " + void *p3; // " + // char *c1; // " + char *c2; // " + char *c3; // " + int i1; // " + // int i2; // " + // int i3; // " + // jlong l1; // " + // jlong l2; // " + // jlong l3; // " + // double d1; // " + // double d2; // " + // double d3; // " + jvalue *jvp = NULL; // if this is given a buffer, it will be freed after the call + jboolean r; // Prolog exit/fail outcome + + if ( !jni_ensure_jvm() + || !PL_get_integer(tn,&n) + ) + { + return FALSE; + } + + switch ( n ) + { + case 30: + r = JNI_term_to_non_array_jclass(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jobject_to_term((*env)->NewObjectA(env,(jclass)p1,(jmethodID)p2,jvp),tr); + break; + case 36: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jobject_to_term((*env)->CallObjectMethodA(env,(jobject)p1,(jmethodID)p2,jvp),tr); + break; + case 39: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jboolean_to_term((*env)->CallBooleanMethodA(env,(jobject)p1,(jmethodID)p2,jvp),tr); + break; + case 42: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jbyte_to_term((*env)->CallByteMethodA(env,(jobject)p1,(jmethodID)p2,jvp),tr); + break; + case 45: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jchar_to_term((*env)->CallCharMethodA(env,(jobject)p1,(jmethodID)p2,jvp),tr); + break; + case 48: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jshort_to_term((*env)->CallShortMethodA(env,(jobject)p1,(jmethodID)p2,jvp),tr); + break; + case 51: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jint_to_term((*env)->CallIntMethodA(env,(jobject)p1,(jmethodID)p2,jvp),tr); + break; + case 54: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jlong_to_term((*env)->CallLongMethodA(env,(jobject)p1,(jmethodID)p2,jvp),tr); + break; + case 57: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jfloat_to_term((*env)->CallFloatMethodA(env,(jobject)p1,(jmethodID)p2,jvp),tr); + break; + case 60: + r = JNI_term_to_jobject(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jdouble_to_term((*env)->CallDoubleMethodA(env,(jobject)p1,(jmethodID)p2,jvp),tr); + break; + case 116: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jobject_to_term((*env)->CallStaticObjectMethodA(env,(jclass)p1,(jmethodID)p2,jvp),tr); + break; + case 119: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jboolean_to_term((*env)->CallStaticBooleanMethodA(env,(jclass)p1,(jmethodID)p2,jvp),tr); + break; + case 122: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jbyte_to_term((*env)->CallStaticByteMethodA(env,(jclass)p1,(jmethodID)p2,jvp),tr); + break; + case 125: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jchar_to_term((*env)->CallStaticCharMethodA(env,(jclass)p1,(jmethodID)p2,jvp),tr); + break; + case 128: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jshort_to_term((*env)->CallStaticShortMethodA(env,(jclass)p1,(jmethodID)p2,jvp),tr); + break; + case 131: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jint_to_term((*env)->CallStaticIntMethodA(env,(jclass)p1,(jmethodID)p2,jvp),tr); + break; + case 134: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jlong_to_term((*env)->CallStaticLongMethodA(env,(jclass)p1,(jmethodID)p2,jvp),tr); + break; + case 137: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jfloat_to_term((*env)->CallStaticFloatMethodA(env,(jclass)p1,(jmethodID)p2,jvp),tr); + break; + case 140: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jmethodID(ta2,p2) + && JNI_term_to_pointer(ta3,jvp) + && JNI_jdouble_to_term((*env)->CallStaticDoubleMethodA(env,(jclass)p1,(jmethodID)p2,jvp),tr); + break; + case 33: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_charP(ta2,c2) + && JNI_term_to_charP(ta3,c3) + && JNI_jmethodID_to_term((*env)->GetMethodID(env,(jclass)p1,(char*)c2,(char*)c3),tr); + break; + case 94: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_charP(ta2,c2) + && JNI_term_to_charP(ta3,c3) + && JNI_jfieldID_to_term((*env)->GetFieldID(env,(jclass)p1,(char*)c2,(char*)c3),tr); + break; + case 113: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_charP(ta2,c2) + && JNI_term_to_charP(ta3,c3) + && JNI_jmethodID_to_term((*env)->GetStaticMethodID(env,(jclass)p1,(char*)c2,(char*)c3),tr); + break; + case 144: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_charP(ta2,c2) + && JNI_term_to_charP(ta3,c3) + && JNI_jfieldID_to_term((*env)->GetStaticFieldID(env,(jclass)p1,(char*)c2,(char*)c3),tr); + break; + case 172: + r = JNI_term_to_non_neg_jint(ta1,i1) + && JNI_term_to_jclass(ta2,p2) + && JNI_term_to_ref(ta3,p3) + && JNI_jobject_to_term((*env)->NewObjectArray(env,(jsize)i1,(jclass)p2,(jobject)p3),tr); + break; + default: + return FALSE; // oughta throw exception (design-time error :-) + break; + } + + if ( jvp != NULL ) + { + free( jvp); + } + + return jni_check_exception() && r; + } + + +/* +%T jni_func( +integer, +term, +term, +term, +term, -term) + */ +static foreign_t +jni_func_4_plc( + term_t tn, // +FuncIndex + term_t ta1, // +Arg1 + term_t ta2, // +Arg2 + term_t ta3, // +Arg3 + term_t ta4, // +Arg4 + term_t tr // -Result + ) + { + int n; // JNI function index + functor_t fn; // temp for conversion macros + term_t a1; // " + term_t a2; // " + atom_t a; // " + char *cp; // " + int i; // " + int xhi; // " + int xlo; // " + jobject j; // " + jlong jl; // " + void *p1; // temp for converted (JVM) arg + void *p2; // " + void *p3; // " + // void *p4; // " + char *c1; // " + // char *c2; // " + // char *c3; // " + // char *c4; // " + // int i1; // " + // int i2; // " + // int i3; // " + int i4; // " + // jlong l1; // " + // jlong l2; // " + // jlong l3; // " + // jlong l4; // " + // double d1; // " + // double d2; // " + // double d3; // " + // double d4; // " + jvalue *jvp = NULL; // if this is given a buffer, it will be freed after the call + jboolean r; // Prolog exit/fail outcome + + if ( !jni_ensure_jvm() + || !PL_get_integer(tn,&n) + ) + { + return FALSE; + } + + switch ( n ) + { + case 66: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jobject(ta2,p2) + && JNI_term_to_jmethodID(ta3,p3) + && JNI_term_to_pointer(ta4,jvp) + && JNI_jobject_to_term((*env)->CallNonvirtualObjectMethodA(env,(jobject)p1,(jclass)p2,(jmethodID)p3,jvp),tr); + break; + case 69: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jobject(ta2,p2) + && JNI_term_to_jmethodID(ta3,p3) + && JNI_term_to_pointer(ta4,jvp) + && JNI_jboolean_to_term((*env)->CallNonvirtualBooleanMethodA(env,(jobject)p1,(jclass)p2,(jmethodID)p3,jvp),tr); + break; + case 72: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jobject(ta2,p2) + && JNI_term_to_jmethodID(ta3,p3) + && JNI_term_to_pointer(ta4,jvp) + && JNI_jbyte_to_term((*env)->CallNonvirtualByteMethodA(env,(jobject)p1,(jclass)p2,(jmethodID)p3,jvp),tr); + break; + case 75: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jobject(ta2,p2) + && JNI_term_to_jmethodID(ta3,p3) + && JNI_term_to_pointer(ta4,jvp) + && JNI_jchar_to_term((*env)->CallNonvirtualCharMethodA(env,(jobject)p1,(jclass)p2,(jmethodID)p3,jvp),tr); + break; + case 78: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jobject(ta2,p2) + && JNI_term_to_jmethodID(ta3,p3) + && JNI_term_to_pointer(ta4,jvp) + && JNI_jshort_to_term((*env)->CallNonvirtualShortMethodA(env,(jobject)p1,(jclass)p2,(jmethodID)p3,jvp),tr); + break; + case 81: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jobject(ta2,p2) + && JNI_term_to_jmethodID(ta3,p3) + && JNI_term_to_pointer(ta4,jvp) + && JNI_jint_to_term((*env)->CallNonvirtualIntMethodA(env,(jobject)p1,(jclass)p2,(jmethodID)p3,jvp),tr); + break; + case 84: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jobject(ta2,p2) + && JNI_term_to_jmethodID(ta3,p3) + && JNI_term_to_pointer(ta4,jvp) + && JNI_jlong_to_term((*env)->CallNonvirtualLongMethodA(env,(jobject)p1,(jclass)p2,(jmethodID)p3,jvp),tr); + break; + case 87: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jobject(ta2,p2) + && JNI_term_to_jmethodID(ta3,p3) + && JNI_term_to_pointer(ta4,jvp) + && JNI_jfloat_to_term((*env)->CallNonvirtualFloatMethodA(env,(jobject)p1,(jclass)p2,(jmethodID)p3,jvp),tr); + break; + case 90: + r = JNI_term_to_jclass(ta1,p1) + && JNI_term_to_jobject(ta2,p2) + && JNI_term_to_jmethodID(ta3,p3) + && JNI_term_to_pointer(ta4,jvp) + && JNI_jdouble_to_term((*env)->CallNonvirtualDoubleMethodA(env,(jobject)p1,(jclass)p2,(jmethodID)p3,jvp),tr); + break; + case 5: + r = JNI_term_to_charP(ta1,c1) + && JNI_term_to_jobject(ta2,p2) + && JNI_term_to_jbuf(ta3,p3,JNI_atom_byte) + && JNI_term_to_jint(ta4,i4) + && JNI_jobject_to_term((*env)->DefineClass(env,(char*)c1,(jobject)p2,(jbyte*)p3,(jsize)i4),tr); + break; + default: + return FALSE; // oughta throw exception (design-time error :-) + break; + } + + if ( jvp != NULL ) + { + free( jvp); + } + + return jni_check_exception() && r; + } + + +// would it be better style to have this at the end of the file? +static +PL_extension predspecs[] = + { { "jni_create_jvm", 2, jni_create_jvm_plc, 0 }, + { "jni_supported_jvm_version", 2, jni_supported_jvm_version_plc, 0 }, + { "jni_get_created_jvm_count", 1, jni_get_created_jvm_count_plc, 0 }, + { "jni_ensure_jvm", 0, jni_ensure_jvm_plc, 0 }, + { "jni_tag_to_iref", 2, jni_tag_to_iref_plc, 0 }, + { "jni_hr_info", 4, jni_hr_info_plc, 0 }, + { "jni_hr_table", 1, jni_hr_table_plc, 0 }, + { "jni_byte_buf_length_to_codes", 3, jni_byte_buf_length_to_codes_plc, 0 }, + { "jni_param_put", 4, jni_param_put_plc, 0 }, + { "jni_alloc_buffer", 3, jni_alloc_buffer_plc, 0 }, + { "jni_free_buffer", 1, jni_free_buffer_plc, 0 }, + { "jni_fetch_buffer_value", 5, jni_fetch_buffer_value_plc, 0 }, + { "jni_stash_buffer_value", 5, jni_stash_buffer_value_plc, 0 }, + { "jni_void", 1, jni_void_0_plc, 0 }, + { "jni_void", 2, jni_void_1_plc, 0 }, + { "jni_void", 3, jni_void_2_plc, 0 }, + { "jni_void", 4, jni_void_3_plc, 0 }, + { "jni_void", 5, jni_void_4_plc, 0 }, + { "jni_func", 2, jni_func_0_plc, 0 }, + { "jni_func", 3, jni_func_1_plc, 0 }, + { "jni_func", 4, jni_func_2_plc, 0 }, + { "jni_func", 5, jni_func_3_plc, 0 }, + { "jni_func", 6, jni_func_4_plc, 0 }, + { "jpl_c_lib_version", 1, jpl_c_lib_version_1_plc, 0 }, + { "jpl_c_lib_version", 4, jpl_c_lib_version_4_plc, 0 }, + { "jpl_java_home", 1, jpl_c_java_home, 0 }, + { NULL, 0, NULL, 0 } + }; + + +install_t +jpl_install(void) + { + + // PL_register_extensions( predspecs); + PL_load_extensions( predspecs); + } + + +//=== JPL functions ================================================================================ + +static int create_pool_engines(void); + +static int +jpl_num_initial_default_args(void) // used only once, by jpl_do_jpl_init() + { + int i; + + for ( i=0 ; default_args[i]!=NULL ; i++ ) + { + } + return i; + } + + +// outcomes: +// fail to find jpl.*, jpl.fli.* classes or to convert init args to String[]: exception, FALSE +// all OK: TRUE +// +static bool +jpl_do_jpl_init( // to be called once only, after PL init, before any JPL calls + JNIEnv *env + ) + { + jclass tc; // temporary class ref + jobject ta; // temporary array ref + char *msg; // error message for exceptions thrown here + int i; // loop counter + jobject to; // temporary (String) object ref + + if ( jpl_status != JPL_INIT_RAW ) // jpl init already attempted? (shouldn't happen) + { + DEBUG(1, Sdprintf( "[JPL: jpl_do_jpl_init() called AGAIN (skipping...)]\n")); + return TRUE; + } + + // prerequisites for setting initial default args into String[] dia: + if ( (tc=(*env)->FindClass(env,"java/lang/String")) == NULL + || (jString_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (ta=(*env)->NewObjectArray(env,jpl_num_initial_default_args(),jString_c,NULL)) == NULL + || (dia=(*env)->NewGlobalRef(env,ta)) == NULL + || ( (*env)->DeleteLocalRef(env,ta), FALSE) + ) + { + msg = "jpl_do_jpl_init(): failed to find java.lang.String or create String[] dia"; + goto err; + } + + // copy the initial default args into String[] dia: + for ( i=0 ; default_args[i]!=NULL ; i++ ) + { + if ( (to=(*env)->NewStringUTF(env,default_args[i])) == NULL ) + { + msg = "jpl_do_jpl_init(): failed to convert an initial default arg to a String"; + goto err; + } + (*env)->SetObjectArrayElement(env,dia,i,to); // any errors/exceptions to be handled here? + } + + if ( (tc=(*env)->FindClass(env,"jpl/JPLException")) == NULL + || (jJPLException_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/term_t")) == NULL + || (jTermT_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/atom_t")) == NULL + || (jAtomT_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/functor_t")) == NULL + || (jFunctorT_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/fid_t")) == NULL + || (jFidT_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/predicate_t")) == NULL + || (jPredicateT_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/qid_t")) == NULL + || (jQidT_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/module_t")) == NULL + || (jModuleT_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/engine_t")) == NULL + || (jEngineT_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/LongHolder")) == NULL + || (jLongHolder_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/PointerHolder")) == NULL + || (jPointerHolder_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/IntHolder")) == NULL + || (jIntHolder_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/DoubleHolder")) == NULL + || (jDoubleHolder_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/StringHolder")) == NULL + || (jStringHolder_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/ObjectHolder")) == NULL + || (jObjectHolder_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/fli/BooleanHolder")) == NULL + || (jBooleanHolder_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/JRef")) == NULL + || (jJRef_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (tc=(*env)->FindClass(env,"jpl/JBoolean")) == NULL + || (jJBoolean_c=(*env)->NewGlobalRef(env,tc)) == NULL + || ( (*env)->DeleteLocalRef(env,tc), FALSE) + + || (jLongHolderValue_f=(*env)->GetFieldID(env,jLongHolder_c,"value","J")) == NULL + + || (jPointerHolderValue_f=(*env)->GetFieldID(env,jPointerHolder_c,"value","J")) == NULL + + || (jIntHolderValue_f=(*env)->GetFieldID(env,jIntHolder_c,"value","I")) == NULL + + || (jDoubleHolderValue_f=(*env)->GetFieldID(env,jDoubleHolder_c,"value","D")) == NULL + + || (jStringHolderValue_f=(*env)->GetFieldID(env,jStringHolder_c,"value","Ljava/lang/String;")) == NULL + + || (jObjectHolderValue_f=(*env)->GetFieldID(env,jObjectHolder_c,"value","Ljava/lang/Object;")) == NULL + + || (jBooleanHolderValue_f=(*env)->GetFieldID(env,jBooleanHolder_c,"value","Z")) == NULL + + || (jJRefRef_f=(*env)->GetFieldID(env,jJRef_c,"ref","Ljava/lang/Object;")) == NULL + + || (jJBooleanValue_f=(*env)->GetFieldID(env,jJBoolean_c,"value","Z")) == NULL + ) + { + msg = "jpl_do_jpl_init(): failed to find jpl.* or jpl.fli.* classes"; + goto err; + } + + DEBUG(1, Sdprintf( "[jpl_do_jpl_init() sets jpl_status = JPL_INIT_PVM_MAYBE, returns TRUE]\n")); + jpl_status = JPL_INIT_PVM_MAYBE; + return TRUE; + +err: + jpl_status = JPL_INIT_JPL_FAILED; + (*env)->ThrowNew(env,jJPLException_c,msg); + return FALSE; + } + + +// prerequisite: +// called only from jpl_test_pvm_init() and jpl_do_pvm_init() +// outcomes: +// error setting up post-PVM-init JPL state: throws exception, sets status = PVM_FAILED, returns FALSE +// OK: sets status = OK, returns TRUE +// +static bool +jpl_post_pvm_init( + JNIEnv *env, + int argc, + char **argv + ) + { + char *msg; + jobject ta; + int i; + + // Prolog VM is already initialised (by us or by other party) + // retire default init args and set up actual init args: + dia = NULL; // probably oughta delete (global) ref to former args... + if ( (ta=(*env)->NewObjectArray(env,argc,jString_c,NULL)) == NULL + || (aia=(*env)->NewGlobalRef(env,ta)) == NULL + || ( (*env)->DeleteLocalRef(env,ta), FALSE) + ) + { + msg = "jpl_post_pvm_init(): failed to copy actual init args"; + goto err; + } + for ( i=0 ; iNewStringUTF(env,argv[i]); + if ( to == NULL ) + { + msg = "jpl_post_pvm_init(): failed to convert actual PL init arg to String"; + goto err; + } + (*env)->SetObjectArrayElement(env,aia,i,to); + } + + if ( create_pool_engines() != 0 ) + { + msg = "jpl_post_pvm_init(): failed to create Prolog engine pool"; + goto err; + } + + jpl_status = JPL_INIT_OK; + return TRUE; + +err: + (*env)->ThrowNew( env, jJPLException_c, msg); + jpl_status = JPL_INIT_PVM_FAILED; + return FALSE; + } + + +// prerequisite: jpl_status != JPL_INIT_RAW +// outcomes: +// PVM is not (already) initialised -> FALSE +// PVM is (already) initialised -> TRUE +// error setting up post-PVM-init JPL state -> exception +// +static bool +jpl_test_pvm_init( + JNIEnv *env + ) + { + char *msg; + int argc; + char **argv; + // jobject ta; + // int i; + + if ( jpl_status == JPL_INIT_RAW ) + { + msg = "jpl_test_pvm_init(): called while jpl_status == JPL_INIT_RAW"; + goto err; + } + + if ( jpl_status==JPL_INIT_JPL_FAILED || jpl_status==JPL_INIT_PVM_FAILED ) + { + msg = "jpl_test_pvm_init(): initialisation has already failed"; + goto err; + } + + if ( jpl_status == JPL_INIT_OK ) + { + return TRUE; + } + + if ( jpl_status == JPL_INIT_PVM_MAYBE ) + { + // we test this each time (if not already initialised) in case other foreign code inits the PVM: + if ( !PL_is_initialised(&argc,&argv) ) // PVM not ready? + { + // jpl_status remains = JPL_INIT_PVM_MAYBE + DEBUG(1, Sdprintf( "[pl_test_pvm_init(): PL is not yet initialised: returning FALSE]\n")); + return FALSE; // already-active Prolog VM not found (NB not an exceptional condition) + } + else + { + DEBUG(1, Sdprintf( "[pl_test_pvm_init(): PL is already initialised: proceeding to jpl_post_pvm_init()]\n")); + return jpl_post_pvm_init(env,argc,argv); // TRUE, FALSE or exception + } + } + + msg = "jpl_test_pvm_init(): unknown jpl_status value"; + goto err; + +err: + (*env)->ThrowNew( env, jJPLException_c, msg); + jpl_status = JPL_INIT_PVM_FAILED; + return FALSE; + } + + +// prerequisite: +// jpl_status == JPL_INIT_PVM_MAYBE +// outcomes: +// successful PVM initialisation and subsequent JPL state setup -> TRUE +// any error -> exception +// +static bool +jpl_do_pvm_init( + JNIEnv *env + ) + { + char *msg; + int argc; + char **argv; + int i; + jstring arg; + char *cp; + + // redundant prerequisites check: + if ( jpl_status != JPL_INIT_PVM_MAYBE ) + { + msg = "jpl_do_pvm_init(): called while jpl_status != JPL_INIT_PVM_MAYBE"; + goto err; + } + + // copy current default init args into suitable form for PL_initialise(): + if ( dia == NULL ) + { + msg = "jpl_do_pvm_init(): dia == NULL"; + goto err; + } + argc = (*env)->GetArrayLength(env,dia); + if ( argc <= 0 ) + { + msg = "jpl_do_pvm_init(): there are fewer than 1 default init args"; + goto err; + } + if ( (argv=(char**)malloc((argc+1)*sizeof(char*))) == NULL ) + { + msg = "jpl_do_pvm_init(): malloc() failed for argv"; + goto err; + } + for ( i=0 ; iGetObjectArrayElement(env,dia,i); + cp = (char*)(*env)->GetStringUTFChars(env,arg,0); + argv[i] = (char*)malloc(strlen(cp)+1); + strcpy( argv[i], cp); + DEBUG(1, Sdprintf( " argv[%d] = %s\n", i, argv[i])); + (*env)->ReleaseStringUTFChars( env, arg, cp); + } + DEBUG(1, Sdprintf( " argv[%d] = NULL\n", argc)); + argv[argc] = NULL; + if ( !PL_initialise(argc,(char**)argv) ) // NB not (const char**) + { + msg = "jpl_do_pvm_init(): PL_initialise() failed"; + goto err; + } + // *don't* free argv (must exist for lifetime of Prolog VM) + + return jpl_post_pvm_init(env,argc,argv); // TRUE, FALSE or exception + +err: + jpl_status = JPL_INIT_PVM_FAILED; + (*env)->ThrowNew( env, jJPLException_c, msg); + return FALSE; + } + + +//=== initialisation-related native Java methods of jpl.fli.Prolog ================================= + +/* + * Class: jpl_fli_PL + * Method: get_default_init_args + * Signature: ()[Ljava/lang/String; + */ +// +// if not yet init then return default init args as String[] +// if already init then return NULL +// if already failed to init then throw an exception +// +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_get_1default_1init_1args( + JNIEnv *env, + jclass jProlog + ) + { + char *msg; + + jpl_ensure_jpl_init( env); // lazily do "local" initialisations iff necessary + + if ( jpl_status==JPL_INIT_JPL_FAILED || jpl_status==JPL_INIT_PVM_FAILED ) + { + msg = "jpl.fli.Prolog.set_default_init_args(): initialisation has already failed"; + goto err; + } + + return ( jpl_test_pvm_init(env) // if Prolog VM is initialised + ? NULL // then default init args are no longer defined + : dia // else here they are + ) + ; +err: + (*env)->ThrowNew( env, jJPLException_c, msg); + return FALSE; + } + + +/* + * Class: jpl_fli_PL + * Method: set_default_init_args + * Signature: ([Ljava/lang/String;)Z + */ +// +// if the given jargs are null then throw an exception +// if already failed to init then throw an exception +// if not yet init then set default init args from jargs and return TRUE +// if already init then return FALSE +// +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_set_1default_1init_1args( + JNIEnv *env, + jclass jProlog, + jobject jargs // oughta be proper array, perhaps zero-length + ) + { + char *msg; + + jpl_ensure_jpl_init( env); // lazily do "local" initialisations iff necessary + + if ( jargs == NULL ) // improper call + { + msg = "jpl.fli.Prolog.set_default_init_args() called with NULL arg"; + goto err; + } + + if ( jpl_status==JPL_INIT_JPL_FAILED || jpl_status==JPL_INIT_PVM_FAILED ) + { + msg = "jpl.fli.Prolog.set_default_init_args(): initialisation has already failed"; + goto err; + } + + if ( jpl_test_pvm_init(env) ) // if Prolog VM is initialised + { + return FALSE; // unable to set default init args (too late: PVM is already initialised) + } + else + { + dia = NULL; // probably oughta delete (global) (?) ref of former args... + dia = (*env)->NewGlobalRef(env,jargs); + return TRUE; // OK: default init args set to those provided + } + +err: + (*env)->ThrowNew( env, jJPLException_c, msg); + return FALSE; + } + + +/* + * Class: jpl_fli_PL + * Method: get_actual_init_args + * Signature: ()[Ljava/lang/String; + */ +// +// if not yet init then return null +// if already init then return actual init args as String[] +// if already failed to init then throw an exception +// +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_get_1actual_1init_1args( + JNIEnv *env, + jclass jProlog + ) + { + char *msg; + + jpl_ensure_jpl_init( env); // lazily do "local" initialisations iff necessary + + if ( jpl_status==JPL_INIT_JPL_FAILED || jpl_status==JPL_INIT_PVM_FAILED ) + { + msg = "jpl.fli.Prolog.get_actual_init_args(): initialisation has already failed"; + goto err; + } + + return ( jpl_test_pvm_init(env) // check PL_initialise() and update local state as appropriate + ? aia // here they are + : NULL // PVM not (yet) initialised + ); + +err: + (*env)->ThrowNew( env, jJPLException_c, msg); + return NULL; + } + + +/* + * Class: jpl_fli_PL + * Method: initialise + * Signature: ()Z + */ +// +// if already init then return FALSE +// if already failed to init then throw an exception +// else attempt to init and if success then return TRUE else throw an exception +// +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_initialise( + JNIEnv *env, + jclass jProlog + ) + { + char *msg; + + jpl_ensure_jpl_init( env); // lazily do "local" initialisations iff necessary + + if ( jpl_status==JPL_INIT_JPL_FAILED || jpl_status==JPL_INIT_PVM_FAILED ) + { + msg = "jpl.fli.Prolog.initialise(): initialisation has already failed"; + goto err; + } + + if ( jpl_test_pvm_init(env) ) + { + return FALSE; // PVM is already initialised + } + else + { + jpl_do_pvm_init( env); + return jpl_test_pvm_init(env); + } + +err: + (*env)->ThrowNew( env, jJPLException_c, msg); + return FALSE; + } + + +/* + * Class: jpl_fli_PL + * Method: halt + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_halt( + JNIEnv *env, + jclass jProlog, + jint jstatus + ) + { + + jpl_ensure_pvm_init(env); + PL_halt( (int)jstatus); + } + + +//=== JPL utility functions ======================================================================== + +/*----------------------------------------------------------------------- + * getLongValue + * + * Retrieves the value in a jpl.fli.LongHolder (or subclass) instance + * + * @param env Java environment + * @param jlong_holder the LongHolder class instance, or null + * @param lv address to write the retrieved (long) value + * @return success? (the LongHolder was not null) + *---------------------------------------------------------------------*/ +static +bool +getLongValue( + JNIEnv *env, + jobject jlong_holder, + long *lv + ) + { + + if ( jlong_holder == NULL ) + { + *lv = 0L; + return FALSE; + } + else // Java compilation ensures it's a jpl.fli.LongHolder instance + { + *lv = (long)(*env)->GetLongField(env,jlong_holder,jLongHolderValue_f); + return TRUE; + } + } + + +/*----------------------------------------------------------------------- + * getPointerValue + * + * Retrieves the value in a jpl.fli.PointerHolder instance + * + * @param env Java environment + * @param jpointer_holder the PointerHolder class instance, or null + * @param pv address to write the retrieved (pointer) value + * @return success? (the PointerHolder was not null) + *---------------------------------------------------------------------*/ +static +bool +getPointerValue( // sets pv to jpointer_holder's .value_ (and succeeds), else sets it to NULL (and fails) + JNIEnv *env, + jobject jpointer_holder, + pointer *pv + ) + { + + if ( jpointer_holder == NULL ) + { + *pv = (pointer)NULL; + return FALSE; + } + else // Java compilation ensures it's a jpl.fli.PointerHolder instance + { + *pv = (pointer)(*env)->GetLongField(env,jpointer_holder,jPointerHolderValue_f); + return TRUE; + } + } + + +/*----------------------------------------------------------------------- + * setPointerValue + * + * Sets the value in a jpl.fli.Pointer class instance (unless it's null) + * to the supplied value (maybe 0L) + * + * @param env Java environment + * @param jpointer_holder the PointerHolder class instance, or null + * @param pv the new (pointer) value + *---------------------------------------------------------------------*/ +static +bool +setPointerValue( + JNIEnv *env, + jobject jpointer_holder, + pointer pv + ) + { + + return jpointer_holder != NULL + && ( (*env)->SetLongField(env,jpointer_holder,jPointerHolderValue_f,(long)pv), + TRUE + ) + ; + } + + +/*----------------------------------------------------------------------- + * setIntValue + * + * Sets the value in a Java IntHolder class instance (unless it's null) + * to the supplied value + * + * @param env Java environment + * @param jint_holder the IntHolder class instance, or null + * @param iv the new (int) value + *---------------------------------------------------------------------*/ +static +bool +setIntValue( + JNIEnv *env, + jobject jint_holder, + int iv + ) + { + + return jint_holder != NULL + && ( (*env)->SetIntField(env,jint_holder,jIntHolderValue_f,iv), + TRUE + ) + ; + } + + +/*----------------------------------------------------------------------- + * setLongValue + * + * Sets the value in a Java LongHolder class instance (unless it's null) + * to the supplied value (maybe 0L) + * + * @param env Java environment + * @param jlong_holder the LongHolder class instance, or null + * @param lv the new (long) value + *---------------------------------------------------------------------*/ +static +bool +setLongValue( + JNIEnv *env, + jobject jlong_holder, + long lv + ) + { + + return jlong_holder != NULL + && ( (*env)->SetLongField(env,jlong_holder,jLongHolderValue_f,lv), + TRUE + ) + ; + } + + +/*----------------------------------------------------------------------- + * setDoubleValue + * + * Sets the value in a Java DoubleHolder class instance (unless it's null) + * to the supplied value + * + * @param env Java environment + * @param jdouble_holder the DoubleHolder class instance, or null + * @param dv the new (double) value + *---------------------------------------------------------------------*/ +static +bool +setDoubleValue( + JNIEnv *env, + jobject jdouble_holder, + double dv + ) + { + + return jdouble_holder != NULL + && ( (*env)->SetDoubleField(env,jdouble_holder,jDoubleHolderValue_f,dv), + TRUE + ) + ; + } + + +/*----------------------------------------------------------------------- + * setStringValue + * + * Sets the value in a Java StringHolder class instance (unless it's null) + * to the supplied value (maybe null) + * + * @param env Java environment + * @param jstring_holder the StringHolder class instance, or null + * @param sv the new (jstring) value + *---------------------------------------------------------------------*/ +static +bool +setStringValue( + JNIEnv *env, + jobject jstring_holder, + jstring sv + ) + { + + return jstring_holder != NULL + && ( (*env)->SetObjectField(env,jstring_holder,jStringHolderValue_f,sv), + TRUE + ) + ; + } + + +/*----------------------------------------------------------------------- + * setObjectValue + * + * Sets the value in a Java ObjectHolder class instance (unless it's null) + * to the supplied value (maybe null) + * + * @param env Java environment + * @param jobject_holder the ObjectHolder class instance, or null + * @param ref the new (jobject) value + *---------------------------------------------------------------------*/ +static +bool +setObjectValue( + JNIEnv *env, + jobject jobject_holder, + jobject ref + ) + { + + return jobject_holder != NULL + && ( (*env)->SetObjectField(env,jobject_holder,jObjectHolderValue_f,ref), + TRUE + ) + ; + } + + +/*----------------------------------------------------------------------- + * setBooleanValue + * + * Sets the .value field of a Java BooleanHolder class instance (unless it's null) + * to the supplied jboolean value + * + * @param env Java environment + * @param jboolean_holder the BooleanHolder class instance, or null + * @param jb the new (jboolean) value + *---------------------------------------------------------------------*/ +static +bool +setBooleanValue( + JNIEnv *env, + jobject jboolean_holder, + jboolean jb + ) + { + + return jboolean_holder != NULL + && ( (*env)->SetBooleanField(env,jboolean_holder,jBooleanHolderValue_f,jb), + TRUE + ) + ; + } + + +/*----------------------------------------------------------------------- + * updateAtomValue + * + * Updates the value in a Java atom_t class instance (unless it's null) + * to the supplied value (maybe 0L); unregisters and registers old and new + * atom references as appropriate. NB atom_t extends LongHolder. + * + * @param env Java environment + * @param jatom_holder the atom_t class instance, or null + * @param atom2 the new atom reference + *---------------------------------------------------------------------*/ +static +bool +updateAtomValue( + JNIEnv *env, + jobject jatom_holder, + atom_t atom2 // new value (perhaps 0L (?)) + ) + { + atom_t atom1; // old value (perhaps 0L (?)) + + if ( jatom_holder == NULL ) + { + return FALSE; + } + else + { + atom1 = (atom_t)(*env)->GetLongField(env,jatom_holder,jLongHolderValue_f); + if ( atom1 != 0L ) + { + PL_unregister_atom( atom1); + } + (*env)->SetLongField(env,jatom_holder,jLongHolderValue_f,(long)atom2); + if ( atom2 != 0L ) + { + PL_register_atom( atom2); + } + return TRUE; + } + } + + + +//=== Java-wrapped SWI-Prolog FLI functions ======================================================== + +/* + * Class: jpl_fli_PL + * Method: new_term_ref + * Signature: ()Ljpl/fli/term_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_new_1term_1ref( + JNIEnv *env, + jclass jProlog + ) + { + jobject rval; + + return ( jpl_ensure_pvm_init(env) + && (rval=(*env)->AllocObject(env,jTermT_c)) != NULL + && setLongValue(env,rval,(long)PL_new_term_ref()) + ? rval + : NULL + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: new_term_refs + * Signature: (I)Ljpl/fli/term_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_new_1term_1refs( + JNIEnv *env, + jclass jProlog, + jint jn + ) + { + jobject rval; + term_t trefs; + + DEBUG(1, Sdprintf( ">new_term_refs(env=%lu,jProlog=%lu,jn=%lu)...\n", (long)env, (long)jProlog, (long)jn)); + + return ( jpl_ensure_pvm_init(env) + && jn >= 0 // I hope PL_new_term_refs(0) is defined [ISSUE] + && (rval=(*env)->AllocObject(env,jTermT_c)) != NULL + && ( trefs=PL_new_term_refs((int)jn), TRUE ) + && setLongValue(env,rval,(long)trefs) + && ( DEBUG(1, Sdprintf(" ok: stashed trefs=%ld into new term_t object\n",(long)trefs)), TRUE ) + ? rval + : NULL + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: copy_term_ref + * Signature: (Ljpl/fli/term_t;)Ljpl/fli/term_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_copy_1term_1ref( + JNIEnv *env, + jclass jProlog, + jobject jfrom + ) + { + jobject rval; + term_t term; + term_t term2; + + return ( jpl_ensure_pvm_init(env) + // && jfrom != NULL // redundant: getLongValue checks this + && getLongValue(env,jfrom,(long*)&term) // SWI RM implies must be non-null + && (rval=(*env)->AllocObject(env,jTermT_c)) != NULL + && ( (term2=PL_copy_term_ref(term)) , TRUE ) // SWI RM -> always succeeds + && setLongValue(env,rval,(long)term2) + ? rval + : NULL // oughta warn of failure? + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: reset_term_refs + * Signature: (Ljpl/fli/term_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_reset_1term_1refs( + JNIEnv *env, + jclass jProlog, + jobject jafter + ) + { + term_t term; + + if ( jpl_ensure_pvm_init(env) + // && jafter != NULL // redundant: getLongValue checks this + && getLongValue(env,jafter,&term) // SWI RM -> oughta be non-null + ) + { + PL_reset_term_refs( term); // void; SWI RM -> "always succeeds" + } + } + + +/* + * Class: jpl_fli_PL + * Method: new_atom + * Signature: (Ljava/lang/String;)Ljpl/fli/atom_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_new_1atom( + JNIEnv *env, + jclass jProlog, + jstring jname + ) + { + const char *name; + atom_t atom; + jobject rval; + + return ( jpl_ensure_pvm_init(env) + && jname != NULL + && (name=(*env)->GetStringUTFChars(env,jname,NULL)) != NULL // no exceptions + && ( (atom=PL_new_atom(name)) , TRUE ) // SWI RM p138 -> "always succeeds"; incs ref count + && ( (*env)->ReleaseStringUTFChars(env,jname,name) , TRUE ) // void; no exceptions + && (rval=(*env)->AllocObject(env,jAtomT_c)) != NULL // doesn't call any constructor + && setLongValue(env,rval,(long)atom) + ? rval + : NULL // oughta warn of failure? + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: atom_chars + * Signature: (Ljpl/fli/atom_t;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL // the local ref goes out of scope, +Java_jpl_fli_Prolog_atom_1chars( // but the string itself doesn't + JNIEnv *env, + jclass jProlog, + jobject jatom + ) + { + atom_t atom; + jstring lref; + // jstring gref; + const char *s; + + return ( jpl_ensure_pvm_init(env) + && getLongValue(env,jatom,(long*)&atom) // checks jatom != null + && (s=PL_atom_chars(atom)) != NULL // SWI RM -> "always succeeds" + && (lref=(*env)->NewStringUTF(env,s)) != NULL // out-of-memory -> NULL, exception + ? lref + : NULL + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: new_functor + * Signature: (Ljpl/fli/atom_t;I)Ljpl/fli/functor_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_new_1functor( + JNIEnv *env, + jclass jProlog, + jobject jatom, // read-only + jint jarity + ) + { + term_t atom; + functor_t functor; + jobject rval; + + return ( jpl_ensure_pvm_init(env) + && jarity >= 0 + && getLongValue(env,jatom,(long*)&atom) // checks jatom isn't null + && (rval=(*env)->AllocObject(env,jFunctorT_c)) != NULL + && (functor=PL_new_functor(atom,(int)jarity)) != 0L + && setLongValue(env,rval,(long)functor) + ? rval + : NULL // oughta warn of failure? + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: functor_name + * Signature: (Ljpl/fli/functor_t;)Ljpl/fli/atom_t; + */ +JNIEXPORT jobject JNICALL // returns a new atom_t, containing a newly-registered atom ref +Java_jpl_fli_Prolog_functor_1name( + JNIEnv *env, + jclass jProlog, + jobject jfunctor + ) + { + functor_t functor; + atom_t atom; + jobject rval; + + return ( jpl_ensure_pvm_init(env) + && getLongValue(env,jfunctor,(long*)&functor) // SWI RM -> must be a real functor + && (atom=PL_functor_name(functor)) != 0L // unlike PL_new_atom, doesn't register the ref + && (rval=(*env)->AllocObject(env,jAtomT_c)) != NULL // doesn't call any constructor + && setLongValue(env,rval,(long)atom) + && ( PL_register_atom(atom), TRUE ) // register this reference + ? rval + : NULL // oughta warn of failure? + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: functor_arity + * Signature: (Ljpl/fli/functor_t;)I + */ +JNIEXPORT jint JNICALL +Java_jpl_fli_Prolog_functor_1arity( + JNIEnv *env, + jclass jProlog, + jobject jfunctor + ) + { + functor_t functor; + + return ( jpl_ensure_pvm_init(env) + && getLongValue(env,jfunctor,(long*)&functor) // checks jfunctor isn't null + ? PL_functor_arity(functor) + : -1 // oughta warn of failure? + ) + ; + } + + +//=== from "5.6.3 Analysing terms via the foreign interface", "Testing the Type of a term" ======== + +// not needed: +// PL_register_atom() + +/* + * Class: jpl_fli_PL + * Method: term_type + * Signature: (Ljpl/fli/term_t;)I + */ +JNIEXPORT jint JNICALL +Java_jpl_fli_Prolog_term_1type( + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; + + return ( jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks jterm isn't null + ? PL_term_type(term) + : -1 // i.e. when jterm is null + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: is_variable + * Signature: (Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_is_1variable( + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; + + return jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks jterm isn't null + && PL_is_variable(term) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: is_atom + * Signature: (Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_is_1atom( + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; + + return jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks jterm isn't null + && PL_is_atom(term) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: is_integer + * Signature: (Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_is_1integer( + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; + + return jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks jterm isn't null + && PL_is_integer(term) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: is_float + * Signature: (Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_is_1float( + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; + + return jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks jterm isn't null + && PL_is_float(term) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: is_compound + * Signature: (Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_is_1compound( + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; + + return jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks jterm isn't null + && PL_is_compound(term) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: is_functor + * Signature: (Ljpl/fli/term_t;Ljpl/fli/functor_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_is_1functor( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jfunctor + ) + { + term_t term; + functor_t functor; + + return jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks jterm isn't null + && getLongValue(env,jfunctor,(long*)&functor) // checks jfunctor isn't null + && PL_is_functor(term,functor) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: is_list + * Signature: (Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_is_1list( + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; + + return jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks jterm isn't null + && PL_is_list(term) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: is_atomic + * Signature: (Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_is_1atomic( + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; + + return jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks jterm isn't null + && PL_is_atomic(term) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: is_number + * Signature: (Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_is_1number( + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; + + return jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks jterm isn't null + && PL_is_number(term) + ; + } + + + +//=== from "5.6.3 Analysing Terms via the Foreign Interface: Reading data from a term" ============ + +// not yet mapped: register_atom() +// unregister_atom() + +/* + * Class: jpl_fli_PL + * Method: get_atom + * Signature: (Ljpl/fli/term_t;Ljpl/fli/atom_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1atom( + JNIEnv *env, + jclass jProlog, + jobject jterm, // read + jobject jatom // update + ) + { + term_t term; + atom_t atom; + + return jpl_ensure_pvm_init(env) + && jatom != NULL // don't call PL_get_atom if jatom is null + && getLongValue(env,jterm,(long*)&term) // checks that jterm != NULL + && PL_get_atom(term,&atom) // iff term is an atom; doesn't register the ref + && updateAtomValue(env,jatom,atom) // unreg old ref (if any); reg new ref (if any) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_atom_chars + * Signature: (Ljpl/fli/term_t;Ljpl/fli/StringHolder;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1atom_1chars( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jstring_holder + ) + { + term_t term; + char *s; + jstring string; + + return jpl_ensure_pvm_init(env) + && jstring_holder != NULL // don't call PL_get_atom_chars if this is null + && getLongValue(env,jterm,(long*)&term) // checks that jterm != NULL + && PL_get_atom_chars(term,&s) // fails (usefully) if term is not an atom + && (string=(*env)->NewStringUTF(env,s)) != NULL // OK as local ref... + && setStringValue(env,jstring_holder,string) // ...when sent straight back to JVM + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_string_chars + * Signature: (Ljpl/fli/term_t;Ljpl/fli/StringHolder;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1string_1chars( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jstring_holder + ) + { + term_t term; + char *s; + int n; + jstring string; + + return jpl_ensure_pvm_init(env) + && jstring_holder != NULL // don't call PL_get_atom_chars if this is null + && getLongValue(env,jterm,(long*)&term) // checks that jterm != NULL + && PL_get_string_chars(term,&s,&n) // fails (usefully) if term is not a string + && (string=(*env)->NewStringUTF(env,s)) != NULL // OK as local ref... + && setStringValue(env,jstring_holder,string) // ...when sent straight back to JVM + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_chars + * Signature: (Ljpl/fli/term_t;Ljpl/fli/StringHolder;I)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1chars( // withdraw this? + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jstring_holder, + jint jflags + ) + { + term_t term; + char *s; + jstring string; + + return jpl_ensure_pvm_init(env) + && jstring_holder != NULL + && getLongValue(env,jterm,(long*)&term) // checks that jterm != NULL + && PL_get_chars(term,&s,(unsigned)jflags) + && (string=(*env)->NewStringUTF(env,s)) != NULL + && setStringValue(env,jstring_holder,string) // OK as local ref? + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_list_chars + * Signature: (Ljpl/fli/term_t;Ljpl/fli/StringHolder;I)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1list_1chars( // withdraw this? + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jstring_holder, + jint jflags + ) + { + term_t term; + char *s; + jstring string; + + return jpl_ensure_pvm_init(env) + && jstring_holder != NULL // don't call PL_get_list_chars if this is null + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && PL_get_list_chars(term,&s,(unsigned)jflags) + && (string=(*env)->NewStringUTF(env,s)) != NULL + && setStringValue(env,jstring_holder,string) // OK as local ref? + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_integer + * Signature: (Ljpl/fli/term_t;Ljpl/fli/IntHolder;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1integer( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jint_holder + ) + { + term_t term; + int i; + + return jpl_ensure_pvm_init(env) + && jint_holder != NULL // don't call PL_get_integer if this is null + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && PL_get_integer(term,&i) + && setIntValue(env,jint_holder,i) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_pointer + * Signature: (Ljpl/fli/term_t;Ljpl/fli/Pointer;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1pointer( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jpointer + ) + { + term_t term; + pointer ptr; + + return jpl_ensure_pvm_init(env) + && jpointer != NULL + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && PL_get_pointer(term,(void**)&ptr) + && setPointerValue(env,jpointer,ptr) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_float + * Signature: (Ljpl/fli/term_t;Ljpl/fli/DoubleHolder;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1float( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jdouble_holder + ) + { + term_t term; + double d; + + return jpl_ensure_pvm_init(env) + && jdouble_holder != NULL + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && PL_get_float(term,&d) + && setDoubleValue(env,jdouble_holder,d) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_jref + * Signature: (Ljpl/fli/term_t;Ljpl/fli/ObjectHolder;)Z + */ +// added 26/Jan/2004 untested... +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1jref( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jobject_holder + ) + { + term_t term; + jobject ref; + char *cp; + functor_t fn; + term_t a1; + atom_t a; + + return jpl_ensure_pvm_init(env) + && jobject_holder != NULL + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && JNI_term_to_ref(term,ref) + && setObjectValue(env,jobject_holder,ref) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_jboolean + * Signature: (Ljpl/fli/term_t;Ljpl/fli/BooleanHolder;)Z + */ +// called with a term_t holder and a boolean holder; +// if the term_t is @(false) or @(true), sets the boolean value accordingly and succeeds, +// else fails +// added 26/Jan/2004 untested... +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1jboolean( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jboolean_holder + ) + { + term_t term; // temp for term ref extracted from the passed-in "term_t holder" + jboolean b; // temp for boolean by-ref result from JNI_term_to_jboolean(+,-) + functor_t fn; // temp for JNI_term_to_jboolean(+,-) + term_t a1; // " + atom_t a; // " + + return jpl_ensure_pvm_init(env) // merge these please + && jni_ensure_jvm() // " + && jboolean_holder != NULL // fail if no boolean holder is passed + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && JNI_term_to_jboolean(term,b) + && setBooleanValue(env,jboolean_holder,b) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_jpl_term + * Signature: (Ljpl/fli/term_t;Ljpl/fli/ObjectHolder;)Z + */ +// +// added 18/Jun/2004 PS untested... +// succeeds iff jterm is one of the special JPL terms, +// i.e. @(false), @(true), @(null) or @(Tag) e.g. @('J#0123456789'), +// stashing a corresponding jpl.JBoolean or jpl.JRef into the object holder +// +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1jpl_1term( + JNIEnv *env, + jclass jProlog, + jobject jterm, // a jpl.fli.term_t instance + jobject jobject_holder // a jpl.fli.ObjectHolder instance + ) + { + term_t term; // the Prolog term referred to by jterm + functor_t fn; // the term's functor + term_t a1; // the term's first & only arg, if it has one + atom_t a; // the atom which is the term's only arg + jobject obj; // a JBoolean or JRef to be returned + jobject ref; // the object referred to by Tag + + return jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) + && PL_get_functor(term,&fn) // succeeds iff jterm is atom or compound + && fn == JNI_functor_at_1 // jterm is @(Something) + && ( a1 = PL_new_term_ref(), + PL_get_arg(1,term,a1) // a1 is that Something + ) + && PL_get_atom(a1,&a) // succeeds iff a1 is an atom + && ( a == JNI_atom_null // Something == null + ? (obj=(*env)->AllocObject(env,jJRef_c)) != NULL + && ((*env)->SetObjectField(env,obj,jJRefRef_f,NULL), TRUE) + && setObjectValue(env,jobject_holder,obj) + : a == JNI_atom_true // Something == true + ? (obj=(*env)->AllocObject(env,jJBoolean_c)) != NULL + && ((*env)->SetBooleanField(env,obj,jJBooleanValue_f,TRUE), TRUE) + && setObjectValue(env,jobject_holder,obj) + : a == JNI_atom_false // Something == false + ? (obj=(*env)->AllocObject(env,jJBoolean_c)) != NULL + && ((*env)->SetBooleanField(env,obj,jJBooleanValue_f,FALSE), TRUE) + && setObjectValue(env,jobject_holder,obj) + : jni_tag_to_iref(a,(int*)&ref) // convert digits to int + ? (obj=(*env)->AllocObject(env,jJRef_c)) != NULL + && ((*env)->SetObjectField(env,obj,jJRefRef_f,ref), TRUE) + && setObjectValue(env,jobject_holder,obj) + : FALSE // jterm is not a special JPL structure + ); + } + + +/* + * Class: jpl_fli_PL + * Method: get_functor + * Signature: (Ljpl/fli/term_t;Ljpl/fli/functor_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1functor( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jfunctor + ) + { + term_t term; + functor_t functor; + + return jpl_ensure_pvm_init(env) + && jfunctor != NULL + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && PL_get_functor(term,&functor) + && setLongValue(env,jfunctor,(long)functor) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_name_arity + * Signature: (Ljpl/fli/term_t;Ljpl/fli/StringHolder;Ljpl/fli/IntHolder;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1name_1arity( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jname_holder, // was atom_t, now StringHolder + jobject jarity_holder + ) + { + term_t term; + atom_t atom; + int arity; + char *name; + jstring jname; + + return jpl_ensure_pvm_init(env) + && jname_holder != NULL // don't proceed if this holder is null + && jarity_holder != NULL // don't proceed if this holder is null + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && PL_get_name_arity(term,&atom,&arity) // no need to register transient atom ref + && ( name=(char*)PL_atom_chars(atom) , TRUE ) // from const char* + && (jname=(*env)->NewStringUTF(env,name)) != NULL + && setStringValue(env,jname_holder,jname) // stash String ref in holder + && setIntValue(env,jarity_holder,arity) // stash arity value in holder + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_module + * Signature: (Ljpl/fli/term_t;Ljpl/fli/Pointer;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1module( + JNIEnv *env, + jclass jProlog, + jobject jterm, // read + jobject jmodule // update + ) + { + term_t term; + module_t module; + + return jpl_ensure_pvm_init(env) + && jmodule != NULL // don't proceed if this holder is null + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && PL_get_module(term,&module) + && setPointerValue(env,jmodule,(pointer)module) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_arg + * Signature: (ILjpl/fli/term_t;Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1arg( + JNIEnv *env, + jclass jProlog, + jint jindex, + jobject jterm, + jobject jarg + ) + { + term_t term; + term_t arg; + + return jpl_ensure_pvm_init(env) + && jarg != NULL // don't proceed if this holder is null + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && ( arg=PL_new_term_ref() , TRUE ) // Fred used jarg's original term ref (?) + && PL_get_arg(jindex,term,arg) + && setLongValue(env,jarg,(long)arg) + ; + } + + +//=== from "5.6.3 Analysing Terms via the Foreign Interface: Reading a list" ====================== + +// not yet mapped: +// get_atom_nchars() +// get_atom_nchars() +// get_list_nchars() +// get_nchars() +// put_atom_nchars() +// put_list_ncodes() +// put_list_nchars() +// unify_atom_nchars() +// unify_list_ncodes() +// unify_list_nchars() + +/* + * Class: jpl_fli_PL + * Method: get_list + * Signature: (Ljpl/fli/term_t;Ljpl/fli/term_t;Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1list( + JNIEnv *env, + jclass jProlog, + jobject jlist, + jobject jhead, + jobject jtail + ) + { + term_t list; + term_t head = PL_new_term_ref(); + term_t tail = PL_new_term_ref(); + + return jpl_ensure_pvm_init(env) + && jhead != NULL + && jtail != NULL + && getLongValue(env,jlist,(long*)&list) // checks that jlist isn't null + && PL_get_list(list,head,tail) + && setLongValue(env,jhead,(long)head) + && setLongValue(env,jtail,(long)tail) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_head + * Signature: (Ljpl/fli/term_t;Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1head( + JNIEnv *env, + jclass jProlog, + jobject jlist, + jobject jhead + ) + { + term_t list; + term_t head = PL_new_term_ref(); + + return jpl_ensure_pvm_init(env) + && jhead != NULL + && getLongValue(env,jlist,(long*)&list) // checks that jlist isn't null + && PL_get_head(list,head) + && setLongValue(env,jhead,(long)head) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_tail + * Signature: (Ljpl/fli/term_t;Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1tail( + JNIEnv *env, + jclass jProlog, + jobject jlist, + jobject jtail + ) + { + term_t list; + term_t tail = PL_new_term_ref(); + + return jpl_ensure_pvm_init(env) + && jtail != NULL + && getLongValue(env,jlist,(long*)&list) // checks that jlist isn't null + && PL_get_tail(list,tail) + && setLongValue(env,jtail,(long)tail) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_nil + * Signature: (Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_get_1nil( // redundant: tests term == '[]' + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; + + return jpl_ensure_pvm_init(env) + && jterm != NULL + && getLongValue(env,jterm,(long*)&term) + && PL_get_nil(term) + ; + } + + +//=== from "5.6.4 Constructing terms" ============================================================== +// these methods perhaps oughta return jboolean, false iff given object is null... + +/* + * Class: jpl_fli_PL + * Method: put_variable + * Signature: (Ljpl/fli/term_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1variable( + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; + + if ( jpl_ensure_pvm_init(env) // may throw exception but cannot fail + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + ) + { + PL_put_variable(term); + } + } + + +/* + * Class: jpl_fli_PL + * Method: put_atom + * Signature: (Ljpl/fli/term_t;Ljpl/fli/atom_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1atom( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jatom + ) + { + term_t term; + atom_t atom; + + if ( jpl_ensure_pvm_init(env) + && jatom != NULL // don't proceed if this holder is null + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + ) + { + getLongValue( env, jterm, (long*)&term); + getLongValue( env, jatom, (long*)&atom); // no need to register this transient atom ref + PL_put_atom( term, atom); + } + } + + +/* + * Class: jpl_fli_PL + * Method: put_atom_chars + * Signature: (Ljpl/fli/term_t;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1atom_1chars( // no atom refs involved here + JNIEnv *env, + jclass jProlog, + jobject jterm, + jstring jchars + ) + { + term_t term; + const char *chars; + + if ( jpl_ensure_pvm_init(env) + && jchars != NULL + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && (chars=(*env)->GetStringUTFChars(env,jchars,NULL)) != NULL // is this return idiom OK? [ISSUE] + ) + { + PL_put_atom_chars( term, chars); + (*env)->ReleaseStringUTFChars( env, jchars, chars); + } + } + + +/* + * Class: jpl_fli_PL + * Method: put_list_chars + * Signature: (Ljpl/fli/term_t;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1list_1chars( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jstring jchars + ) + { + term_t term; + const char *chars; + + if ( jpl_ensure_pvm_init(env) + && jchars != NULL + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && (chars=(*env)->GetStringUTFChars(env,jchars,NULL)) != NULL // is this return idiom OK? [ISSUE] + ) + { + PL_put_list_chars( term, chars); + (*env)->ReleaseStringUTFChars( env, jchars, chars); + } + } + + +/* + * Class: jpl_fli_PL + * Method: put_integer + * Signature: (Ljpl/fli/term_t;J)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1integer( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jlong ji // why jlong? + ) + { + term_t term; + + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + ) + { + PL_put_integer( term, (int)ji); // ??? + } + } + + +/* + * Class: jpl_fli_PL + * Method: put_pointer + * Signature: (Ljpl/fli/term_t;Ljpl/fli/Pointer;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1pointer( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jpointer + ) + { + term_t term; + pointer ptr; + + if ( jpl_ensure_pvm_init(env) + && jpointer != NULL + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && getPointerValue(env,jpointer,&ptr) + ) + { + PL_put_pointer( term, (void*)ptr); + } + } + + +/* + * Class: jpl_fli_PL + * Method: put_float + * Signature: (Ljpl/fli/term_t;D)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1float( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jdouble jf + ) + { + term_t term; + + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + ) + { + PL_put_float( term, jf); + } + } + + +/* + * Class: jpl_fli_PL + * Method: put_functor + * Signature: (Ljpl/fli/term_t;Ljpl/fli/functor_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1functor( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jfunctor + ) + { + term_t term; + functor_t functor; + + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && getLongValue(env,jfunctor,(long*)&functor) // checks that jfunctor isn't null + ) + { + PL_put_functor( term, functor); + } + } + + +/* + * Class: jpl_fli_PL + * Method: put_list + * Signature: (Ljpl/fli/term_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1list( + JNIEnv *env, + jclass jProlog, + jobject jlist + ) + { + term_t term; + + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jlist,(long*)&term) // checks that jlist isn't null + ) + { + PL_put_list( term); + } + } + + +/* + * Class: jpl_fli_PL + * Method: put_nil + * Signature: (Ljpl/fli/term_t;)V + */ +JNIEXPORT void +JNICALL Java_jpl_fli_Prolog_put_1nil( + JNIEnv *env, + jclass jProlog, + jobject jlist + ) + { + term_t term; + + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jlist,(long*)&term) // checks that jlist isn't null + ) + { + PL_put_nil( term); + } + } + + +/* + * Class: jpl_fli_PL + * Method: put_term + * Signature: (Ljpl/fli/term_t;Ljpl/fli/term_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1term( + JNIEnv *env, + jclass jProlog, + jobject jterm1, + jobject jterm2 + ) + { + term_t term1; + term_t term2; + + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jterm1,(long*)&term1) // checks that jterm1 isn't null + && getLongValue(env,jterm2,(long*)&term2) // checks that jterm2 isn't null + ) + { + PL_put_term( term1, term2); + } + } + + +/* + * Class: jpl_fli_PL + * Method: put_jref + * Signature: (Ljpl/fli/term_t;Ljava/lang/Object;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1jref( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jref + ) + { + term_t term; + jobject j; // temp for JNI_jobject_to_term(+,-) + atom_t a; // " + int i; // " + + DEBUG(1, Sdprintf( ">put_ref(env=%lu,jProlog=%lu,jterm=%lu,jref=%lu)...\n", env, jProlog, jterm, jref)); + + ( jpl_ensure_pvm_init(env) // combine these two please + && jni_ensure_jvm() // " + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && JNI_jobject_to_term(jref,term) // assumes term is var; OK if jref == null + ); + } + + +/* + * Class: jpl_fli_PL + * Method: put_jboolean + * Signature: (Ljpl/fli/term_t;Z)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1jboolean( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jboolean jbool + ) + { + term_t term; // temp for term ref from within the passed "term holder" + + DEBUG(1, Sdprintf( ">put_jboolean(env=%lu,jProlog=%lu,jterm=%lu,jbool=%u)...\n", env, jProlog, jterm, jbool)); + + ( jpl_ensure_pvm_init(env) // combine these two please + && jni_ensure_jvm() // " + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && JNI_jboolean_to_term(jbool,term) // assumes term is var + ); + } + + +/* + * Class: jpl_fli_PL + * Method: put_jvoid + * Signature: (Ljpl/fli/term_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_put_1jvoid( + JNIEnv *env, + jclass jProlog, + jobject jterm + ) + { + term_t term; // temp for term ref from within the passed "term holder" + + DEBUG(1, Sdprintf( ">put_jvoid(env=%lu,jProlog=%lu,jterm=%lu)...\n", env, jProlog, jterm)); + + ( jpl_ensure_pvm_init(env) // combine these two please + && jni_ensure_jvm() // " + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && JNI_unify_void(term) // assumes term is var + ); + } + + +/* + * Class: jpl_fli_PL + * Method: cons_functor_v + * Signature: (Ljpl/fli/term_t;Ljpl/fli/functor_t;Ljpl/fli/term_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_cons_1functor_1v( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jfunctor, + jobject jterm0 + ) + { + term_t term; + functor_t functor; + term_t term0; + + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks that jterm isn't null + && getLongValue(env,jfunctor,(long*)&functor) // checks that jfunctor isn't null + && getLongValue(env,jterm0,(long*)&term0) // checks that jterm0 isn't null + ) + { + PL_cons_functor_v( term, functor, term0); + } + } + + +/* + * Class: jpl_fli_PL + * Method: cons_list + * Signature: (Ljpl/fli/term_t;Ljpl/fli/term_t;Ljpl/fli/term_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_cons_1list( + JNIEnv *env, + jclass jProlog, + jobject jlist, + jobject jhead, + jobject jtail ) + { + term_t list; + term_t head; + term_t tail; + + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jlist,(long*)&list) // checks that jlist isn't null + && getLongValue(env,jhead,(long*)&head) // checks that jhead isn't null + && getLongValue(env,jtail,(long*)&tail) // checks that jtail isn't null + ) + { + PL_cons_list( list, head, tail); + } + } + + +//=== from "5.6.5 Unifying data" ================================================================== + +// not yet mapped: +// unify_atom() +// unify_atom_chars() +// unify_list_chars() +// unify_integer() +// unify_float() +// unify_pointer() +// unify_functor() +// unify_list() +// unify_nil() +// unify_arg() +// unify_term() +// chars_to_term() +// quote() + +// /* +// * Class: jpl_fli_PL +// * Method: unify +// * Signature: (Ljpl/fli/term_t;Ljpl/fli/term_t;)I +// */ +// JNIEXPORT jint JNICALL +// Java_jpl_fli_Prolog_unify( +// JNIEnv *env, +// jclass jProlog, +// jobject jterm1, +// jobject jterm2 +// ) +// { +// term_t term1; +// term_t term2; +// +// if ( jpl_ensure_pvm_init(env) +// && getLongValue(env,jterm1,(long*)&term1) // checks that jterm1 isn't null +// && getLongValue(env,jterm2,(long*)&term2) // checks that jterm2 isn't null +// ) +// { +// PL_unify( term1, term2); +// } +// } + + +//=== from "5.6.7 Discarding data" (none of these are (yet) used in LLI or HLI) =================== + +/* + * Class: jpl_fli_PL + * Method: open_foreign_frame + * Signature: ()Ljpl/fli/fid_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_open_1foreign_1frame( + JNIEnv *env, + jclass jProlog + ) + { + jobject rval; + + if ( jpl_ensure_pvm_init(env) + && (rval=(*env)->AllocObject(env,jFidT_c)) != NULL // get a new fid_t object + && setLongValue(env,rval,(long)PL_open_foreign_frame()) // open a frame only if alloc succeeds + ) + { + return rval; + } + else + { + return NULL; + } + } + + +/* + * Class: jpl_fli_PL + * Method: close_foreign_frame + * Signature: (Ljpl/fli/fid_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_close_1foreign_1frame( + JNIEnv *env, + jclass jProlog, + jobject jfid + ) + { + fid_t fid; + + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jfid,(long*)&fid) // checks that jfid isn't null + ) + { + PL_close_foreign_frame(fid); + } + } + + +/* + * Class: jpl_fli_PL + * Method: discard_foreign_frame + * Signature: (Ljpl/fli/fid_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_discard_1foreign_1frame( + JNIEnv *env, + jclass jProlog, + jobject jfid + ) + { + fid_t fid; + + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jfid,(long*)&fid) // checks that jfid isn't null + ) + { + PL_discard_foreign_frame(fid); + } + } + + +//=== from "5.6.6 Calling Prolog from C: Predicate references" ==================================== + +/* + * Class: jpl_fli_PL + * Method: pred + * Signature: (Ljpl/fli/functor_t;Ljpl/fli/module_t;)Ljpl/fli/predicate_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_pred( + JNIEnv *env, + jclass jProlog, + jobject jfunctor, + jobject jmodule + ) + { + functor_t functor; + module_t module; + predicate_t predicate; + jobject rval; + + return ( jpl_ensure_pvm_init(env) + && getLongValue(env,jfunctor,(long*)&functor) // checks that jfunctor isn't null + && ( getPointerValue(env,jmodule,(pointer*)&module) , TRUE ) // if jmodule is null then module = NULL + && ( (predicate=PL_pred(functor,module)) , TRUE ) // module==NULL is OK (?) [ISSUE] + && (rval=(*env)->AllocObject(env,jPredicateT_c)) != NULL + && setPointerValue(env,rval,(pointer)predicate) + && ( DEBUG(1, Sdprintf("[pred module = %s]\n",(module==NULL?"(null)":PL_atom_chars(PL_module_name(module))))), TRUE ) + ? rval + : NULL // oughta warn of failure? + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: predicate + * Signature: (Ljava/lang/String;ILjava/lang/String;)Ljpl/fli/predicate_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_predicate( + JNIEnv *env, + jclass jProlog, + jstring jname, + jint jarity, + jstring jmodule + ) + { + const char *name; + const char *module; // NOT module_t as in JPL 1.0.1 + predicate_t predicate; + jobject rval; + + DEBUG(1, Sdprintf(">predicate(env=%lu,jProlog=%lu,jname=%lu,jarity=%lu,jmodule=%lu)...\n", + (long)env, (long)jProlog, (long)jname, (long)jarity, (long)jmodule)); + return ( jpl_ensure_pvm_init(env) + && jname != NULL + && jarity >= 0 + && (name=(*env)->GetStringUTFChars(env,jname,0)) != NULL + && ( jmodule != NULL + ? (module=(*env)->GetStringUTFChars(env,jmodule,0)) != NULL + : ( module=NULL, TRUE ) + ) + && ( (predicate=PL_predicate(name,jarity,module)) , TRUE ) + && ( (*env)->ReleaseStringUTFChars(env,jname,name) , TRUE ) + && ( jmodule != NULL + ? ( (*env)->ReleaseStringUTFChars(env,jmodule,module), TRUE ) + : TRUE + ) + && (rval=(*env)->AllocObject(env,jPredicateT_c)) != NULL + && setPointerValue(env,rval,(pointer)predicate) + ? ( + DEBUG(1, Sdprintf("[predicate() module=%s\n",(module==NULL?"(null)":module))), + rval + ) + : NULL // oughta warn of failure? + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: predicate_info + * Signature: (Ljpl/fli/predicate_t;Ljpl/fli/atom_t;ILjpl/fli/module_t;)I + */ +// +// perhaps this oughta return a jboolean instead? +// +JNIEXPORT jint JNICALL +Java_jpl_fli_Prolog_predicate_1info( + JNIEnv *env, + jclass jProlog, + jobject jpredicate, + jobject jatom, // this Atom instance will have its value field destructively updated + jobject jarity_holder, + jobject jmodule + ) + { + predicate_t predicate; + atom_t atom; // update + int arity; // update + module_t module; // update + + return jpl_ensure_pvm_init(env) + && jatom != NULL // must have an atom holder object + && jarity_holder != NULL // must have an arity holder object + && jmodule != NULL // must have a module holder object + && getPointerValue(env,jpredicate,(pointer*)&predicate) // checks that jpredicate isn't null + && ( PL_predicate_info(predicate,&atom,&arity,&module) , TRUE ) // "always succeeds"; returns void + && updateAtomValue(env,jatom,atom) // unreg old ref, if any; reg new ref + && setIntValue(env,jarity_holder,arity) // stash arity in holder + && setPointerValue(env,jmodule,(pointer)module) // stash module ref in holder + ; + } + + +//=== from "5.6.6 Calling Prolog from C: Initiating a query from C" =============================== + +/* + * Class: jpl_fli_PL + * Method: open_query + * Signature: (Ljpl/fli/module_t;ILjpl/fli/predicate_t;Ljpl/fli/term_t;)Ljpl/fli/qid_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_open_1query( + JNIEnv *env, + jclass jProlog, + jobject jmodule, // read + jint jflags, // read + jobject jpredicate, // read + jobject jterm0 // read + ) + { + module_t module; + predicate_t predicate; + term_t term0; + qid_t qid; + jobject jqid; // for returned new QidT object + + DEBUG(1, Sdprintf( ">open_query(env=%lu,jProlog=%lu,jmodule=%lu,jflags=%lu,jpredicate=%lu,jterm0=%lu)...\n", + (long)env, (long)jProlog, (long)jmodule, (long)jflags, (long)jpredicate, (long)jterm0)); + return ( jpl_ensure_pvm_init(env) + && ( getPointerValue(env,jmodule,(pointer*)&module) , TRUE ) // NULL module is OK below... + && ( DEBUG(1, Sdprintf(" ok: getPointerValue(env,jmodule=%lu,&(pointer)module=%lu)\n",(long)jmodule,(long)module)), TRUE ) + && getPointerValue(env,jpredicate,(pointer*)&predicate) // checks that jpredicate != NULL + && ( DEBUG(1, Sdprintf(" ok: getPointerValue(env,jpredicate=%lu,&(pointer)predicate=%lu)\n",(long)jpredicate,(long)predicate)), TRUE ) + && getLongValue(env,jterm0,(long*)&term0) // jterm0!=NULL + && ( (qid=PL_open_query(module,jflags,predicate,term0)) , TRUE ) // NULL module is OK (?) [ISSUE] + && ( DEBUG(1, Sdprintf(" ok: PL_open_query(module=%lu,jflags=%u,predicate=%lu,term0=%lu)=%lu\n",(long)module,jflags,(long)predicate,(long)term0,(long)qid)), TRUE ) + && (jqid=(*env)->AllocObject(env,jQidT_c)) != NULL + && ( DEBUG(1, Sdprintf(" ok: AllocObject(env,jQidT_c)=%lu\n",(long)jqid)), TRUE ) + && setLongValue(env,jqid,(long)qid) + && ( DEBUG(1, Sdprintf(" ok: setLongValue(env,%lu,%lu)\n",(long)jqid,(long)qid)), TRUE ) + && ( DEBUG(1, Sdprintf("[open_query module = %s]\n", (module==NULL?"(null)":PL_atom_chars(PL_module_name(module))))), TRUE ) + ? ( + DEBUG(1, Sdprintf(" =%lu\n",(long)jqid)), + jqid + ) + : NULL // oughta diagnose failure? raise JPL exception? + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: next_solution + * Signature: (Ljpl/fli/qid_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_next_1solution( + JNIEnv *env, + jclass jProlog, + jobject jqid // read + ) + { + qid_t qid; + int rval; // for boolean return value + + DEBUG(1, Sdprintf( ">next_solution(env=%lu,jProlog=%lu,jqid=%lu)...\n", (long)env, (long)jProlog, (long)jqid)); + return jpl_ensure_pvm_init(env) + && getLongValue(env,jqid,(long*)&qid) // checks that jqid isn't null + && ( DEBUG(1, Sdprintf( " ok: getLongValue(env,jqid,(long*)&qid(%lu))\n",(long)qid)), TRUE ) + && ( rval=PL_next_solution(qid), TRUE ) // can call this until it returns FALSE + && ( DEBUG(1, Sdprintf( " ok: PL_next_solution(qid=%lu)=%u\n",(long)qid,rval)), TRUE ) + && ( + DEBUG(1, Sdprintf(" =%lu\n",(long)rval)), + rval + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: cut_query + * Signature: (Ljpl/fli/qid_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_cut_1query( + JNIEnv *env, + jclass jProlog, + jobject jqid + ) + { + qid_t qid; + + DEBUG(1, Sdprintf( ">cut_query(env=%lu,jProlog=%lu,jquid=%u)...\n", (long)env, (long)jProlog, (long)jqid)); + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jqid,(long*)&qid) // checks that jqid != NULL + ) + { + PL_cut_query( qid); // void + DEBUG(1, Sdprintf( " ok: PL_cut_query(%lu)\n", (long)qid)); + } + } + + +/* + * Class: jpl_fli_PL + * Method: close_query + * Signature: (Ljpl/fli/qid_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_close_1query( + JNIEnv *env, + jclass jProlog, + jobject jqid + ) + { + qid_t qid; + + DEBUG(1, Sdprintf( ">close_query(env=%lu,jProlog=%lu,jquid=%u)...\n", (long)env, (long)jProlog, (long)jqid)); + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jqid,(long*)&qid) // checks that jqid != NULL + ) + { + PL_close_query( qid); // void + DEBUG(1, Sdprintf( " ok: PL_close_query(%lu)\n", (long)qid)); + } + } + + +/* + * Class: jpl_fli_PL + * Method: call_predicate + * Signature: (Ljpl/fli/module_t;ILjpl/fli/predicate_t;Ljpl/fli/term_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_call_1predicate( + JNIEnv *env, + jclass jProlog, + jobject jmodule, // null is OK + jint jflags, + jobject jpredicate, + jobject jterm0 + ) + { + module_t module; + predicate_t predicate; + term_t term0; + + return jpl_ensure_pvm_init(env) + && ( getPointerValue(env,jmodule,(pointer*)&module) , TRUE ) // if jmodule is null then module = NULL + && getPointerValue(env,jpredicate,(pointer*)&predicate) // checks that jpredicate isn't null + && getLongValue(env,jterm0,(long*)&term0) // checks that jterm0 isn't null + && PL_call_predicate(module,jflags,predicate,term0) // assumes module == NULL is OK [ISSUE] + ; + } + + +/* + * Class: jpl_fli_PL + * Method: call + * Signature: (Ljpl/fli/term_t;Ljpl/fli/module_t;)Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_call( + JNIEnv *env, + jclass jProlog, + jobject jterm, + jobject jmodule // null is OK + ) + { + term_t term; + module_t module; + + return jpl_ensure_pvm_init(env) + && getLongValue(env,jterm,(long*)&term) // checks that jterm != NULL + && ( getPointerValue(env,jmodule,(pointer*)&module) , TRUE ) // if jmodule is null then module = NULL + && PL_call(term,module) // assumes module == NULL is OK [ISSUE] + ; + } + + +//=== from "5.6.9 Prolog exceptions in foreign code" ============================================== + +// not yet mapped: +// raise_exception() +// throw() + +/* + * Class: jpl_fli_PL + * Method: exception + * Signature: (Ljpl/fli/qid_t;)Ljpl/fli/term_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_exception( + JNIEnv *env, + jclass jProlog, + jobject jqid + ) + { + qid_t qid; + term_t term; + jobject term_t; // return value + + DEBUG(1, Sdprintf( ">exception(jqid=%lu)\n", (long)jqid)); + return ( jpl_ensure_pvm_init(env) + && ( DEBUG(1, Sdprintf( " ok: jpl_ensure_pvm_init(env)\n")), TRUE ) + // && jqid != NULL // redundant + && ( DEBUG(1, Sdprintf( " ok: jqid != NULL\n")), TRUE ) + && getLongValue(env,jqid,(long*)&qid) // checks that jqid isn't null + && ( DEBUG(1, Sdprintf( " ok: getLongValue(env,jqid,(long*)&qid)\n")), TRUE ) + && ( (term=PL_exception(qid)) , TRUE ) // we'll build a term_t object regardless + && ( DEBUG(1, Spdrintf(" ok: ( (term=PL_exception(qid)), TRUE)\n")), TRUE ) + && (term_t=(*env)->AllocObject(env,jTermT_c)) != NULL + && ( DEBUG(1, Sdprintf( " ok: (term_t=(*env)->AllocObject(env,jTermT_c)) != NULL\n")), TRUE ) + && setLongValue(env,term_t,(long)term) + && ( DEBUG(1, Sdprintf( " ok: setLongValue(env,term_t,(long)term)\n")), TRUE ) + ? ( + DEBUG(1, Sdprintf(" =%lu\n",(long)term_t)), + term_t + ) + : NULL // oughta diagnose failure? + ) + ; + } + + +//=== from "5.6.1 Miscellaneous" ================================================================== + +// not yet mapped (these might actually be useful as native methods, although they can be called via Prolog): +// record() +// reorded() +// erase() + +/* + * Class: jpl_fli_PL + * Method: compare + * Signature: (Ljpl/fli/term_t;Ljpl/fli/term_t;)I + */ +JNIEXPORT jint JNICALL // returns -1, 0 or 1 (or -2 for error) +Java_jpl_fli_Prolog_compare( + JNIEnv *env, + jclass jProlog, + jobject jterm1, + jobject jterm2 + ) + { + term_t term1; + term_t term2; + + DEBUG(1, Sdprintf( ">compare(term1=%lu,term2=%lu)\n", (long)jterm1, (long)jterm2)); + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jterm1,(long*)&term1) // checks jterm1 isn't null + && getLongValue(env,jterm2,(long*)&term2) // checks jterm2 isn't null + ) + { + DEBUG(1, Sdprintf( "> PL_compare( %u, %u)", term1, term2)); + return PL_compare(term1,term2); // returns -1, 0 or 1 + } + else + { + return -2; // oughta throw an exception... + } + } + + +/* + * Class: jpl_fli_PL + * Method: unregister_atom + * Signature: (Ljpl/fli/atom_t;)V + */ +JNIEXPORT void JNICALL +Java_jpl_fli_Prolog_unregister_1atom( + JNIEnv *env, + jclass jProlog, + jobject jatom + ) + { + atom_t atom; + + DEBUG(1, Sdprintf( ">unregister_atom(env=%lu,jProlog=%lu,jatom=%u)...\n", (long)env, (long)jProlog, (long)jatom)); + + if ( jpl_ensure_pvm_init(env) + && getLongValue(env,jatom,(long*)&atom) // checks that jatom isn't null + ) + { + PL_unregister_atom( atom); // void + DEBUG(1, Sdprintf( " ok: PL_unregister_atom(%lu)\n", (long)atom)); + } + } + + +/* + * Class: jpl_fli_PL + * Method: new_module + * Signature: (Ljpl/fli/atom_t;)Ljpl/fli/module_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_new_1module( + JNIEnv *env, + jclass jProlog, + jobject jatom + ) + { + atom_t atom; + module_t module; + jobject rval; + + return ( jpl_ensure_pvm_init(env) + && getLongValue(env,jatom,(long*)&atom) // checks that jatom isn't null + && ( (module=PL_new_module(atom)) , TRUE ) + && (rval=(*env)->AllocObject(env,jModuleT_c)) != NULL + && setPointerValue(env,rval,(pointer)module) + ? rval + : NULL // oughta warn of failure? + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: action_abort + * Signature: ()I + */ +JNIEXPORT int JNICALL +Java_jpl_fli_Prolog_action_1abort( + JNIEnv *env, + jclass jProlog + ) + { + + if ( jpl_ensure_pvm_init(env) ) + { + return PL_action(PL_ACTION_ABORT); + } + else + { + return -2; // oughta throw exception? + } + } + + +//=== JPL's Prolog engine pool and thread management =============================================== + +/* + * Class: jpl_fli_PL + * Method: thread_self + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_jpl_fli_Prolog_thread_1self( + JNIEnv *env, + jclass jProlog + ) + { + + if ( jpl_ensure_pvm_init(env) ) + { + return PL_thread_self(); + } + else + { + return -2; + } + } + + +static int +create_pool_engines() + { + int i; + + DEBUG(1, Sdprintf( "JPL creating engine pool:\n")); + if ( (engines=malloc(sizeof(PL_engine_t)*JPL_MAX_POOL_ENGINES)) == NULL ) + { + return -1; /* malloc failed */ + } + engines_allocated = JPL_MAX_POOL_ENGINES; + memset(engines, 0, sizeof(PL_engine_t)*engines_allocated); + + DEBUG(1, Sdprintf( "JPL stashing default engine as [0]\n")); + PL_set_engine( PL_ENGINE_CURRENT, &engines[0]); + + DEBUG(1, Sdprintf( "JPL detaching default engine\n")); + // PL_set_engine( NULL, NULL); + + for ( i=1 ; iAllocObject(env,jEngineT_c)) != NULL + && setPointerValue(env,rval,(pointer)engines[i]) + ? rval + : NULL + ); + } + if ( rc != PL_ENGINE_INUSE ) + { + DEBUG(1, Sdprintf( "JPL PL_set_engine fails with %d\n", rc)); + pthread_mutex_unlock( &engines_mutex); + return NULL; // bad engine status: oughta throw exception + } + } + + for ( i=0 ; i 0 ) + { DEBUG(1, Sdprintf("JPL releasing engine[%d]=%p\n", i, e)); + PL_set_engine(NULL, NULL); + pthread_cond_signal(&engines_cond); // alert waiters + } + return i; + } + else + { + return -2; + } + } + + +/* + * Class: jpl_fli_PL + * Method: current_engine_is_pool + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL +Java_jpl_fli_Prolog_current_1engine_1is_1pool( + JNIEnv *env, + jclass jProlog + ) + { + + if ( jpl_ensure_pvm_init(env) ) + { + return current_pool_engine() >= 0; + } + else + { + return FALSE; // libpl could not be initialised: oughta throw exception + } + } + + +/* + * Class: jpl_fli_PL + * Method: current_engine + * Signature: ()Ljpl/fli/engine_t; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_current_1engine( + JNIEnv *env, + jclass jProlog + ) + { + PL_engine_t engine; + jobject rval; + + return ( jpl_ensure_pvm_init(env) + && PL_thread_self() != -1 + && ( current_pool_engine_handle(&engine) , TRUE ) + && (rval=(*env)->AllocObject(env,jEngineT_c)) != NULL + && setPointerValue(env,rval,(pointer)engine) + ? rval + : NULL + ) + ; + } + + +/* + * Class: jpl_fli_PL + * Method: get_c_lib_version + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jobject JNICALL +Java_jpl_fli_Prolog_get_1c_1lib_1version( + JNIEnv *env, + jclass jProlog + ) + { + + return (*env)->NewStringUTF(env,JPL_C_LIB_VERSION); + } + + +#ifdef _WIN32 + +#include + +int WINAPI PROTO(win_yap2swi, (HANDLE, DWORD, LPVOID)); + +int WINAPI win_yap2swi(HANDLE hinst, DWORD reason, LPVOID reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + break; + case DLL_PROCESS_DETACH: + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + return 1; +} +#endif + +//=== end of jpl.c ================================================================================= +