Java "Runtime"

Admin User, erstellt 27. Apr. 2024
         
package nova;
import nova.envir.ComputeCompare;
import nova.envir.ComputeElem;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.SocketException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpTimeoutException;
import java.nio.charset.StandardCharsets;
import java.nio.file.NoSuchFileException;
import java.util.*;
/**
* Warranty & Liability
* To the extent permitted by applicable law and unless explicitly
* otherwise agreed upon, XLOG Technologies AG makes no warranties
* regarding the provided information. XLOG Technologies AG assumes
* no liability that any problems might be solved with the information
* provided by XLOG Technologies AG.
* <p/>
* Rights & License
* All industrial property rights regarding the information - copyright
* and patent rights in particular - are the sole property of XLOG
* Technologies AG. If the company was not the originator of some
* excerpts, XLOG Technologies AG has at least obtained the right to
* reproduce, change and translate the information.
* <p/>
* Reproduction is restricted to the whole unaltered document. Reproduction
* of the information is only allowed for non-commercial uses. Selling,
* giving away or letting of the execution of the library is prohibited.
* The library can be distributed as part of your applications and libraries
* for execution provided this comment remains unchanged.
* <p/>
* Restrictions
* Only to be distributed with programs that add significant and primary
* functionality to the library. Not to be distributed with additional
* software intended to replace any components of the library.
* <p/>
* Trademarks
* Jekejeke is a registered trademark of XLOG Technologies AG.
*/
public final class Runtime {
public static final int MAX_BUF = 4096;
private static String bootbase = "";
public static String codebase = "";
private static HttpClient client = null;
public static HttpClient getHttpClient() {
if (client == null)
client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
return client;
}
/**
* Set the boot base.
*
* @param url The boot base.
*/
public static void set_bootbase(String url) {
bootbase = url;
}
/**
* Set the code base.
*
* @param url The code base.
*/
public static void set_codebase(String url) {
codebase = url;
}
/**
* <p>Resolve a child path against a parent.</p>
*
* @param parent The parent path.
* @param child The child path.
* @return The result.
*/
public static File file(String parent, String child) {
File res = new File(child);
if (!res.isAbsolute())
res = new File(parent, child);
return res;
}
/******************************************************************/
/* current_output/1, current_error/1, set_output/1 and set_error/1*/
/******************************************************************/
public static final class Sink {
public StringBuilder buf;
public Handler.Sender send;
public int last;
public Handler.Notifier notify;
public Handler.Releaser release;
public Object data;
public int indent;
/**
* Create a text output.
*/
public Sink() {
this.buf = new StringBuilder();
this.send = (fd, buf) -> {
};
this.last = -1;
this.notify = (fd) -> {
};
this.release = (fd) -> {
};
this.data = Store.UNDEF_OBJ;
this.indent = 0;
}
}
/**
* current_output(S): [ISO 8.11.2]
* The built-in succeeds in S with the current output.
*/
private static boolean test_current_output(Object[] args) {
Object alpha = Store.engine.text_output;
return Machine.exec_unify(args[0], alpha);
}
/**
* current_error(S):
* The built-in succeeds in S with the current error.
*/
private static boolean test_current_error(Object[] args) {
Object alpha = Store.engine.text_error;
return Machine.exec_unify(args[0], alpha);
}
/**
* set_output(S): [ISO 8.11.4]
* The built-in succeeds. As a side effect the current output is set to S.
*/
private static boolean test_set_output(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
check_sink(obj);
Store.engine.text_output = (Sink) obj;
return true;
}
/**
* set_error(S):
* The built-in succeeds. As a side effect the current error is set to S.
*/
private static boolean test_set_error(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
check_sink(obj);
Store.engine.text_error = (Sink) obj;
return true;
}
/**
* Assure that the object is a sink.
*
* @param beta The object.
*/
public static void check_sink(Object beta) {
if (!(beta instanceof Sink)) {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"writer", beta}));
}
}
/******************************************************************/
/* put_code/2, current_lastcode/2 and set_lastcode/2 */
/******************************************************************/
/**
* put_code(S, C): [ISO 8.12.3]
* The built-in succeeds. As a side effect, it adds
* the code point C to the stream S.
*/
private static boolean test_put_code(Object[] args) {
Object stream = Machine.deref(Machine.exec_build(args[0]));
check_sink(stream);
Object alpha = Machine.deref(Machine.exec_build(args[1]));
Special.check_integer(alpha);
int ch = (!Special.is_bigint(alpha) ? ((Integer) alpha).intValue() : -1);
if (ch < 0 || ch > 0x10FFFF)
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"code_point", alpha}));
put_code((Sink) stream, ch);
return true;
}
private static void put_code(Sink stream, int ch) {
stream.buf.appendCodePoint(ch);
stream.last = ch;
if (stream.buf.length() >= MAX_BUF)
flush_buffer(stream);
}
public static void flush_buffer(Sink stream) {
if (stream.buf.length() > 0) {
stream.send.perform(stream.data, stream.buf);
stream.buf = new StringBuilder();
}
}
/**
* current_lastcode(S, C):
* The built-in succeeds in C with the
* last code point of the output stream S.
*/
private static boolean test_current_lastcode(Object[] args) {
Object stream = Machine.deref(Machine.exec_build(args[0]));
check_sink(stream);
return Machine.exec_unify(args[1], Integer.valueOf(((Sink) stream).last));
}
/**
* set_lastcode(S, C):
* The built-in succeeds. As a side effect, the last
* code point of the stream S is set to C.
*/
private static boolean test_set_lastcode(Object[] args) {
Object stream = Machine.deref(Machine.exec_build(args[0]));
check_sink(stream);
Object alpha = Machine.deref(Machine.exec_build(args[1]));
Special.check_integer(alpha);
int ch = (!Special.is_bigint(alpha) ? ((Integer) alpha).intValue() : -2);
((Sink) stream).last = ch;
return true;
}
/******************************************************************/
/* put_atom/2 */
/******************************************************************/
/**
* put_atom(S, A):
* The built-in succeeds. As a side effect, it adds
* the atom to the stream S.
*/
private static boolean test_put_atom(Object[] args) {
Object stream = Machine.deref(Machine.exec_build(args[0]));
check_sink(stream);
Object text = Machine.deref(Machine.exec_build(args[1]));
Special.check_atom(text);
put_atom((Sink) stream, (String) text);
return true;
}
public static void put_atom(Sink stream, String text) {
if (text.length() > 0) {
stream.buf.append(text);
stream.last = text.codePointBefore(text.length());
if (stream.buf.length() >= MAX_BUF)
flush_buffer(stream);
}
}
/******************************************************************/
/* current_input/1 and set_input/1 */
/******************************************************************/
public static final int MASK_SRC_SKIP = 0x00000001;
public static final int MASK_SRC_AREAD = 0x00000002;
public static final class Source {
public String buf;
public int pos;
public Object receive;
public int flags;
public int lineno;
public Object release;
public Object data;
/**
* Create a text input.
*/
public Source() {
this.buf = "";
this.pos = 0;
this.receive = (Handler.Receiver) (fd) -> "";
this.flags = 0;
this.lineno = 0;
this.release = (Handler.Releaser) (fd) -> {};
this.data = Store.UNDEF_OBJ;
}
}
/**
* current_input(S): [ISO 8.11.1]
* The built-in succeeds in S with the current input.
*/
private static boolean test_current_input(Object[] args) {
Object alpha = Store.engine.text_input;
return Machine.exec_unify(args[0], alpha);
}
/**
* set_input(S): [ISO 8.11.3]
* The built-in succeeds. As a side effect it sets the current input to S.
*/
private static boolean test_set_input(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
check_source(obj);
Store.engine.text_input = (Source) obj;
return true;
}
/**
* Assure that the object is a source.
*
* @param beta The object.
*/
private static void check_source(Object beta) {
if (!(beta instanceof Source)) {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"reader", beta}));
}
}
/*******************************************************************/
/* os_read_sync/1, os_get_code/2 and os_peek_code/2 */
/*******************************************************************/
/**
* os_read_sync(S):
* The predicate succeeds. As a side effect the stream buffer is read.
*/
private static boolean test_os_read_sync(Object[] args) {
Source stream = (Source) Machine.deref(Machine.exec_build(args[0]));
stream.buf = ((Handler.Receiver) stream.receive).perform(stream.data);
stream.pos = 0;
return true;
}
/**
* os_get_code(S, C):
* The predicate succeeds in C with the Unicode point from the stream buffer S.
* As a side effect the stream position is advanced.
*/
private static boolean test_os_get_code(Object[] args) {
Source stream = (Source) Machine.deref(Machine.exec_build(args[0]));
int pos = stream.pos;
String buf = stream.buf;
if (pos < buf.length()) {
int ch = buf.codePointAt(pos);
pos += Character.charCount(ch);
if (ch == 13 || (ch == 10 && (stream.flags & MASK_SRC_SKIP) == 0))
stream.lineno++;
if (ch == 13) {
stream.flags |= MASK_SRC_SKIP;
} else {
stream.flags &= ~MASK_SRC_SKIP;
}
stream.pos = pos;
return Machine.exec_unify(args[1], Integer.valueOf(ch));
} else {
return false;
}
}
/**
* os_peek_code(S, C):
* The built-in succeeds in C with the Unicode point from the stream buffer S.
*/
private static boolean test_os_peek_code(Object[] args) {
Source stream = (Source) Machine.deref(Machine.exec_build(args[0]));
int pos = stream.pos;
String buf = stream.buf;
if (pos < buf.length()) {
int ch = buf.codePointAt(pos);
return Machine.exec_unify(args[1], Integer.valueOf(ch));
} else {
return false;
}
}
/*******************************************************************/
/* os_open_promise/2 */
/*******************************************************************/
/**
* os_open_promise(P, S, Q):
* The predicate succeeds in Q with a promise for open input S
* on path P.
*/
private static boolean test_os_open_promise(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(obj);
String url = (String) obj;
Source stream = new Source();
if (!Machine.exec_unify(args[1], stream))
return false;
Object buf = Machine.ctx;
Handler.Promise prom;
if (url.startsWith("http:") || url.startsWith("https:")) {
prom = open_http_promise(buf, stream, url);
} else {
prom = open_file_promise(buf, stream, url);
}
return Machine.exec_unify(args[2], prom);
}
public static Handler.Promise open_http_promise(Object buf, Source src, String url) {
return new Handler.Promise(() -> {
Thread self = Thread.currentThread();
Machine.register_interrupt(buf, () -> self.interrupt());
try {
HttpRequest.Builder builder = HttpRequest.newBuilder().GET();
HttpClient client = getHttpClient();
HttpResponse<InputStream> response;
try {
response = client.send(builder.uri(URI.create(url)).build(),
HttpResponse.BodyHandlers.ofInputStream());
} catch (IOException err) {
Machine.register_signal(buf, map_file_error(err, url));
return;
}
if (response.statusCode() != 200) {
Machine.register_signal(buf, map_http_result(response.statusCode(), url));
} else {
src.data = new InputStreamReader(response.body(), StandardCharsets.UTF_8);
src.receive = (Handler.Factory) Runtime::file_read_promise;
src.release = (Handler.Factory) Runtime::file_close_promise;
src.flags |= MASK_SRC_AREAD;
}
} catch (InterruptedException x) {
/* */
} finally {
Machine.register_interrupt(buf, () -> {});
}
});
}
public static Handler.Promise open_file_promise(Object buf, Source stream, String url) {
return new Handler.Promise(() -> {
try {
File file = file(codebase, url);
FileInputStream in = new FileInputStream(file);
stream.data = new InputStreamReader(in, StandardCharsets.UTF_8);
stream.receive = (Handler.Factory) Runtime::file_read_promise;
stream.release = (Handler.Factory) Runtime::file_close_promise;
stream.flags |= MASK_SRC_AREAD;
} catch (IOException err) {
Machine.register_signal(buf, map_file_error(err, url));
}
});
}
public static Object map_file_error(Exception err, String url) {
if (err instanceof InterruptedException) {
return new Store.Compound("resource_error",
new Object[]{"interrupted_exception"});
} else if (err instanceof FileNotFoundException) {
return new Store.Compound("existence_error",
new Object[]{"source_sink", url});
} else {
return new Store.Compound("existence_error",
new Object[]{"source_sink", url});
}
}
/*******************************************************************/
/* os_stream_flags/2, os_read_promise/2 and os_close_promise/2 */
/*******************************************************************/
/**
* os_stream_flags(S, F):
* The predicate succeeds in F with the flags of the stream S.
*/
private static boolean test_os_stream_flags(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
int flags;
if (obj instanceof Source) {
flags = ((Source) obj).flags;
} else {
check_sink(obj);
flags = 0;
}
return Machine.exec_unify(args[1], Integer.valueOf(flags));
}
/**
* os_read_promise(S, P):
* The predicate suceeds in P with a read promise for a input S.
*/
private static boolean test_os_read_promise(Object[] args) {
Source stream = (Source) Machine.deref(Machine.exec_build(args[0]));
Object buf = Machine.ctx;
return Machine.exec_unify(args[1], ((Handler.Factory) stream.receive).perform(buf, stream));
}
public static Handler.Promise file_read_promise(Object buf, Source stream) {
return new Handler.Promise(() -> {
try {
StringBuilder res = new StringBuilder();
char[] cbuf = new char[8192];
int len = ((Reader)stream.data).read(cbuf);
while (len >= 0) {
res.append(cbuf, 0, len);
len = ((Reader)stream.data).read(cbuf);
}
stream.buf = res.toString();
stream.pos = 0;
} catch (IOException err) {
Machine.register_signal(buf, map_stream_error(err));
}
});
}
/**
* Map a stream error when in transit.
*
* @param err The offending error.
* @return The Prolog error term.
*/
public static Object map_stream_error(IOException err) {
if (err instanceof InterruptedIOException ||
err instanceof HttpTimeoutException) {
return new Store.Compound("resource_error",
new Object[]{"socket_timeout"});
} else if (err instanceof SocketException) {
return new Store.Compound("resource_error",
new Object[]{"remote_error"});
} else {
return new Store.Compound("resource_error",
new Object[]{"io_error"});
}
}
/**
* os_close_promise(S, P):
* The predicate suceeds in P with a read promise for a input S.
*/
private static boolean test_os_close_promise(Object[] args) {
Source stream = (Source) Machine.deref(Machine.exec_build(args[0]));
Object buf = Machine.ctx;
return Machine.exec_unify(args[1], ((Handler.Factory) stream.release).perform(buf, stream));
}
public static Handler.Promise file_close_promise(Object buf, Source stream) {
return new Handler.Promise(() -> {
try {
((Closeable) stream.data).close();
} catch (IOException err) {
Machine.register_signal(buf, map_stream_error(err));
}
});
}
/******************************************************************/
/* os_open_sync/3 */
/******************************************************************/
/**
* os_open_sync(P, M, S):
* The predicate succeeds. As a side effect the stream S is
* opened on the path P with the mode M.
*/
private static boolean test_os_open_sync(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(obj);
String url = (String) obj;
Object mode = Machine.deref(Machine.exec_build(args[1]));
Special.check_atom(mode);
Object stream;
if ("read".equals(mode)) {
throw Machine.make_error(new Store.Compound("resource_error",
new Object[]{"not_implemented"}));
} else if ("write".equals(mode)) {
stream = open_write(url, false);
} else if ("append".equals(mode)) {
stream = open_write(url, true);
} else {
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"io_mode", mode}));
}
return Machine.exec_unify(args[2], stream);
}
public static Object open_write(String url, boolean append) {
try {
File file = file(codebase, url);
FileOutputStream out = new FileOutputStream(file, append);
Sink dst = new Sink();
dst.data = new OutputStreamWriter(out, StandardCharsets.UTF_8);
dst.send = Runtime::file_write;
dst.release = Runtime::file_close;
dst.notify = Runtime::file_flush;
return dst;
} catch (IOException err) {
throw Machine.make_error(map_file_error(err, url));
}
}
public static void file_write(Object data, StringBuilder buf) {
try {
int len = buf.length();
int pos = 0;
char[] cbuf = null;
while (len > 0) {
int span = Math.min(len, 8192);
if (cbuf == null)
cbuf = new char[span];
buf.getChars(pos, span, cbuf, 0);
((Writer) data).write(cbuf, 0, span);
pos += span;
len -= span;
}
} catch (IOException err) {
throw Machine.make_error(map_stream_error(err));
}
}
public static void file_flush(Object data) {
try {
((Flushable) data).flush();
} catch (IOException err) {
throw Machine.make_error(map_stream_error(err));
}
}
public static void file_close(Object data) {
try {
((Closeable) data).close();
} catch (IOException err) {
throw Machine.make_error(map_stream_error(err));
}
}
/******************************************************************/
/* flush_output/1 and os_close_sync/1 */
/******************************************************************/
/**
* flush_output(S): [ISO 8.11.7]
* The built-in succeeds. As a side effect, it flushes the stream S buffer.
*/
private static boolean test_flush_output(Object[] args) {
Object stream = Machine.deref(Machine.exec_build(args[0]));
check_sink(stream);
flush((Sink) stream);
return true;
}
public static void flush(Sink stream) {
flush_buffer(stream);
stream.notify.perform(stream.data);
}
/**
* close(S): [ISO 8.11.6]
* The built-in succeeds. As a side effect, the stream S is closed.
*/
private static boolean test_os_close_sync(Object[] args) {
Object stream = Machine.deref(Machine.exec_build(args[0]));
if (stream instanceof Sink) {
/* */
} else {
check_source(stream);
}
close(stream);
return true;
}
public static void close(Object stream) {
if (stream instanceof Sink) {
flush_buffer((Sink) stream);
((Sink) stream).release.perform(((Sink) stream).data);
} else {
((Handler.Releaser)((Source) stream).release).perform(((Source) stream).data);
}
}
/*******************************************************************/
/* os_prop_promise/3 and set_file_property/2 */
/*******************************************************************/
/**
* os_prop_promise(F, M, Q):
* The predicate succeeds in Q with with a promise for the
* properties M of the file F. Barks if path F doesn't exist
* or io exception while resolving.
*/
private static boolean test_os_prop_promise(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(obj);
String url = (String) obj;
HashMap<String, Object> res = new HashMap<String, Object>();
if (!Machine.exec_unify(args[1], res))
return false;
Object buf = Machine.ctx;
Handler.Promise prom;
if (url.startsWith("http:") || url.startsWith("https:")) {
prom = prop_http_promise(buf, url, res);
} else {
prom = prop_file_promise(buf, url, res);
}
return Machine.exec_unify(args[2], prom);
}
private static Handler.Promise prop_http_promise(Object buf, String url, HashMap<String, Object> res) {
return new Handler.Promise(() -> {
Thread self = Thread.currentThread();
Machine.register_interrupt(buf, () -> self.interrupt());
try {
HttpRequest.Builder builder = HttpRequest.newBuilder().HEAD();
HttpClient client = getHttpClient();
HttpResponse<Void> response;
try {
response = client.send(builder.uri(URI.create(url)).build(),
HttpResponse.BodyHandlers.discarding());
} catch (IOException err) {
Machine.register_signal(buf, map_file_error(err, url));
return;
}
if (response.statusCode() != 200) {
Machine.register_signal(buf, map_http_result(response.statusCode(), url));
} else {
Optional<String> val = response.headers().firstValue("last-modified");
String rpath = response.uri().toString();
long mtime;
try {
mtime = (val.isPresent() ? Date.parse(val.get()) : -1);
} catch (IllegalArgumentException x) {
mtime = -1;
}
String ftype = "regular";
res.put("last_modified", ComputeElem.norm_smallint(mtime));
res.put("real_path", rpath);
res.put("type", ftype);
}
} catch (InterruptedException x) {
/* */
} finally {
Machine.register_interrupt(buf, () -> {});
}
});
}
public static Object map_http_result(int res, String url) {
switch (res) {
case 403: // Forbidden
return new Store.Compound("permission_error",
new Object[]{"open", "source_sink", url});
case 404: // Not Found
return new Store.Compound("existence_error",
new Object[]{"source_sink", url});
case 405: // Method Not Allowed
return new Store.Compound("resource_error",
new Object[]{"illegal_method"});
default:
return new Store.Compound("resource_error",
new Object[]{"io_exception"});
}
}
private static Handler.Promise prop_file_promise(Object buf, String url, HashMap<String, Object> res) {
return new Handler.Promise(() -> {
try {
File file = file(codebase, url);
file = file.toPath().toRealPath().toFile();
String rpath = file.getPath();
long mtime = file.lastModified();
String ftype = (file.isFile() ? "regular" : (file.isDirectory() ? "directory" : "other"));
res.put("last_modified", ComputeElem.norm_smallint(mtime));
res.put("real_path", rpath);
res.put("type", ftype);
} catch (IOException err) {
Machine.register_signal(buf, map_file_error(err, url));
}
});
}
/**
* set_file_property(F, P):
* The predicate assigns the property P to the file F.
*/
private static boolean test_set_file_property(Object[] args) {
Object url = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(url);
Object prop = Machine.deref(Machine.exec_build(args[1]));
if (Store.is_compound(prop) &&
((Store.Compound) prop).functor.equals("last_modified") &&
((Store.Compound) prop).args.length == 1) {
Object val2 = Machine.deref(((Store.Compound) prop).args[0]);
Special.check_integer(val2);
if (ComputeCompare.integer_signum((Number) val2) < 0)
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"not_less_than_zero", val2}));
if (!ComputeCompare.is_long((Number) val2))
throw Machine.make_error(new Store.Compound("representation_error",
new Object[]{"long", val2}));
File file = file(codebase, (String) url);
if (!file.setLastModified(((Number) val2).longValue())) {
if (!file.exists()) {
throw Machine.make_error(new Store.Compound("existence_error",
new Object[]{"source_sink", url}));
} else {
throw Machine.make_error(new Store.Compound("resource_error",
new Object[]{"io_exception"}));
}
}
} else {
Machine.check_nonvar(prop);
prop = Machine.copy_term(prop);
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"prolog_property", prop}));
}
return true;
}
/******************************************************************/
/* ir_place_new/2 and ir_skeleton_new/3 */
/******************************************************************/
/**
* ir_place_new(I, S):
* The predicate succeeds in S with a new place for index I.
*/
private static boolean test_ir_place_new(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
Special.check_integer(alpha);
alpha = new Store.Place(((Integer) alpha).intValue());
return Machine.exec_unify(args[1], new Store.Quote(alpha));
}
/**
* ir_skeleton_new(F, L, S):
* The predicate succeeds in S with a new skeleton for functor F and list L.
*/
private static boolean test_ir_skeleton_new(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
Object beta = Machine.deref(Machine.exec_build(args[1]));
Object[] temp = Special.list_objects(beta);
Store.unquote_objects(temp);
alpha = new Store.Skeleton(alpha, temp);
return Machine.exec_unify(args[2], new Store.Quote(alpha));
}
/******************************************************************/
/* ir_is_site/1, ir_pred_site/2 and ir_site_name/2 */
/******************************************************************/
/**
* ir_is_site(Q): internal only
* The built-in succeeds if Q is a cache.
*/
private static boolean test_ir_is_site(Object[] args) {
Object cache = Machine.deref(Machine.exec_build(args[0]));
return Store.is_cache(cache);
}
/**
* ir_pred_site(F, Q): internal only
* The built-in succeeds in Q with the cache for the functor F.
*/
private static boolean test_ir_pred_site(Object[] args) {
Object name = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(name);
return Machine.exec_unify(args[1], new Store.Cache((String) name));
}
/**
* ir_site_name(Q, F): internal only
* The built-in succeeds in F with the functor of the cache Q.
*/
private static boolean test_ir_site_name(Object[] args) {
Object cache = Machine.deref(Machine.exec_build(args[0]));
check_cache(cache);
return Machine.exec_unify(args[1], ((Store.Cache) cache).name);
}
/**
* Assure that the object is a cache.
*
* @param beta The object.
*/
public static void check_cache(Object beta) {
if (!Store.is_cache(beta)) {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"cache", beta}));
}
}
/*********************************************************************/
/* ir_clause_new/6 and ir_clause_add/4 */
/*********************************************************************/
/**
* ir_clause_new(S, H, B, R, D, C):
* The built-in succeeds in C with a Java object representing
* a clause with variable count S, head instructions H, body instructions B,
* cut variable index R and head index option D.
*/
private static boolean test_ir_clause_new(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
Special.check_integer(alpha);
Object beta = Machine.deref(Machine.exec_build(args[1]));
Object[] head = Special.list_objects(beta);
Object gamma = Machine.deref(Machine.exec_build(args[2]));
Object[] body = Special.list_objects(gamma);
Object delta = Machine.deref(Machine.exec_build(args[3]));
Special.check_integer(delta);
Object mue = Machine.deref(Machine.exec_build(args[4]));
if (Store.is_compound(mue) &&
"just".equals(((Store.Compound) mue).functor) &&
((Store.Compound) mue).args.length == 1) {
mue = Machine.deref(((Store.Compound) mue).args[0]);
} else {
mue = Store.UNDEF_OBJ;
}
int size = ((Integer) alpha).intValue();
Store.unquote_objects(head);
Store.unquote_objects(body);
int cutvar = ((Integer) delta).intValue();
return Machine.exec_unify(args[5], new Store.Clause(size, head, body, cutvar, mue));
}
/**
* ir_clause_add(F, A, C, O):
* The built-in succeeds. As a side effect the Java object clause C
* is added according to options O to the knowledge base for the predicate
* indicator F/A. If C is not a clause, but directly a Java function
* of a special, the built-in definition of the indicator F/A is updated.
*/
private static boolean test_ir_clause_add(Object[] args) {
Object functor = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(functor);
Object beta = Machine.deref(Machine.exec_build(args[1]));
Special.check_integer(beta);
Object gamma = Machine.deref(Machine.exec_build(args[2]));
Object delta = Machine.deref(Machine.exec_build(args[3]));
Special.check_integer(delta);
int arity = ((Integer) beta).intValue();
int flags = ((Integer) delta).intValue();
Store.add_clause((String) functor, arity, gamma, flags);
return true;
}
/*********************************************************************/
/* ir_goal_new/4 and ir_goal_run/1 */
/*********************************************************************/
/**
* ir_goal_new(S, B, G):
* The built-in succeeds in G with a Java object representing
* a goal with variable count S, body instructions B.
*/
private static boolean test_ir_goal_new(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
Special.check_integer(alpha);
Object beta = Machine.deref(Machine.exec_build(args[1]));
Object[] body = Special.list_objects(beta);
int size = ((Integer) alpha).intValue();
Store.unquote_objects(body);
return Machine.exec_unify(args[2], new Machine.Goal(size, body));
}
/**
* ir_goal_run(G):
* As a side effect, the built-in executes the Java object goal G,
* cuts away its choice points and undoes its bindings. If the goal fails,
* it throws a new error. If the goal throws an error, it re-throws this error.
* If the goal succeeds, the built-in succeeds.
*/
private static Object special_ir_goal_run(Object[] args) {
Object goal = Machine.deref(args[0]);
check_goal(goal);
Machine.Choice snap = Machine.snap_setup();
Machine.cont(Machine.melt_directive((Machine.Goal) goal));
return solve_run(snap, 1, null);
}
/**
* Call or resume a goal.
* Failure results in error, success results in cut.
*
* @param data The surrounding choice point.
* @param at The call or redo flag.
* @param choice The choice point for reuse or null.
* @return any True if goal succeeded, otherwise false.
*/
private static Object solve_run(Object data, int at, Machine.Choice choice) {
Machine.Choice snap = (Machine.Choice) data;
Object found = (at != 0 ? Boolean.TRUE : Boolean.FALSE);
try {
found = Machine.solve(snap, found);
} catch (Throwable x) {
Machine.snap_cleanup(snap);
throw x;
}
if (found == Boolean.FALSE)
throw Machine.make_error(new Store.Compound("syntax_error",
new Object[]{"directive_failed"}));
if (found != Boolean.TRUE) {
if (Machine.redo != snap) {
if (choice == null) {
choice = new Machine.Choice(Runtime::solve_run, snap, 0, Machine.trail);
} else {
choice.mark = Machine.trail;
choice.cont = Machine.call;
choice.tail = Machine.redo;
}
Machine.more(choice);
} else {
Machine.cut(snap.tail);
}
return found;
}
Machine.snap_cleanup(snap);
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
/******************************************************************/
/* Dynamic Database */
/******************************************************************/
private static final int MASK_FIND_MODIFY = 0x00000001;
private static final int MASK_FIND_DYNAMIC = 0x00000002;
private static final int MASK_FIND_REVERSE = 0x00000004;
/**
* kb_clause_ref(H, F, C): internal only
* The built-in succeeds in C with the clause references
* for the head H and the flags F.
*/
private static Object special_kb_clause_ref(Object[] args) {
Object head = Machine.deref(args[0]);
Object beta = Machine.deref(args[1]);
Special.check_integer(beta);
int flags = ((Number) beta).intValue();
Store.Provable peek = Machine.lookup_pred(head);
if (peek == null)
return false;
if ((flags & MASK_FIND_DYNAMIC) != 0)
if ((peek.flags & Store.MASK_PRED_DYNAMIC) == 0)
make_error_find(head, flags);
if (!Store.is_logical(peek.rope))
return false;
Object[] temp;
if (Store.is_compound(head)) {
temp = ((Store.Compound) head).args;
} else {
temp = Machine.VOID_ARGS;
}
Store.Logical rope = Machine.defined_clauses(peek, temp);
Store.Clause[] data = Store.snapshot_data(rope);
if ((flags & MASK_FIND_REVERSE) == 0) {
return solve2_ref(args, data, 0, null);
} else {
return solve2_ref_reverse(args, data, data.length, null);
}
}
private static void make_error_find(Object head, int flags) {
if ((flags & MASK_FIND_MODIFY) != 0) {
throw Machine.make_error(new Store.Compound("permission_error",
new Object[]{"modify", "static_procedure", Machine.make_indicator_term(head)}));
} else {
throw Machine.make_error(new Store.Compound("permission_error",
new Object[]{"access", "private_procedure", Machine.make_indicator_term(head)}));
}
}
private static Object solve_ref(Object rope, int at, Machine.Choice choice) {
Object goal = Machine.deref(((Store.Compound) Machine.call).args[0]);
return solve2_ref(((Store.Compound) goal).args, rope, at, choice);
}
private static Object solve_ref_reverse(Object rope, int at, Machine.Choice choice) {
Object goal = Machine.deref(((Store.Compound) Machine.call).args[0]);
return solve2_ref_reverse(((Store.Compound) goal).args, rope, at, choice);
}
/**
* Search a Prolog clause and return it.
*
* @param args The current arguments.
* @param data The clause list.
* @param at The clause index.
* @param choice The choice point for reuse or null.
* @return boolean True if search succeeds, otherwise false.
*/
private static Object solve2_ref(Object[] args, Object data, int at, Machine.Choice choice) {
Store.Clause[] rope = (Store.Clause[]) data;
Store.Variable mark = Machine.trail;
while (at < rope.length) {
Store.Clause clause = rope[at++];
if (Machine.unify(args[2], clause)) {
if (at < rope.length) {
if (choice == null) {
choice = new Machine.Choice(Runtime::solve_ref, rope, at, mark);
} else {
choice.at = at;
}
Machine.more(choice);
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
Machine.unbind(mark);
}
return Boolean.FALSE;
}
/**
* Search a Prolog clause backwards and return it.
*
* @param args The current arguments.
* @param data The clause list.
* @param at The clause index.
* @param choice The choice point for reuse or null.
* @return boolean True if search succeeds, otherwise false.
*/
private static Object solve2_ref_reverse(Object[] args, Object data, int at, Machine.Choice choice) {
Store.Clause[] rope = (Store.Clause[]) data;
Store.Variable mark = Machine.trail;
while (at > 0) {
Store.Clause clause = rope[--at];
if (Machine.unify(args[2], clause)) {
if (at > 0) {
if (choice == null) {
choice = new Machine.Choice(Runtime::solve_ref_reverse, rope, at, mark);
} else {
choice.at = at;
}
Machine.more(choice);
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
Machine.unbind(mark);
}
return Boolean.FALSE;
}
/**
* kb_pred_touch(F, N, O): internal only
* The built-in succeeds. As a side effect the predicate
* indicator F/N with options O is touched.
*/
private static boolean test_kb_pred_touch(Object[] args) {
Object functor = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(functor);
Object beta = Machine.deref(Machine.exec_build(args[1]));
Special.check_integer(beta);
Object gamma = Machine.deref(Machine.exec_build(args[2]));
Special.check_integer(gamma);
Store.pred_touch((String) functor, ((Number) beta).intValue(),
((Number) gamma).intValue());
return true;
}
/**
* kb_clause_remove(F, N, G, R): internal only
* The built-in succeeds if the clause or predicate R could
* be removed from the predicate indicator F/N and the flags G.
*/
private static boolean test_kb_clause_remove(Object[] args) {
Object functor = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(functor);
Object beta = Machine.deref(Machine.exec_build(args[1]));
Special.check_integer(beta);
int arity = ((Number) beta).intValue();
Object gamma = Machine.deref(Machine.exec_build(args[2]));
Special.check_integer(gamma);
int flags = ((Number) gamma).intValue();
Object clause = Machine.deref(Machine.exec_build(args[3]));
check_clause(clause);
return Store.remove_clause((String) functor, arity, clause, flags);
}
public static void check_clause(Object beta) {
if (!(beta instanceof Store.Clause)) {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"clause", beta}));
}
}
/**
* kb_pred_destroy(F, N): internal only
* The built-in succeeds. As a side effect the
* predicate indicator F/N is destroyed.
*/
private static boolean test_kb_pred_destroy(Object[] args) {
Object functor = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(functor);
Object beta = Machine.deref(Machine.exec_build(args[1]));
Special.check_integer(beta);
int arity = ((Number) beta).intValue();
Store.pred_destroy((String) functor, arity);
return true;
}
/******************************************************************/
/* Linked Provables */
/******************************************************************/
/**
* kb_make_defined(L, P): internal only
* The built-in succeeds in P with an anonymous predicate for the clauses L.
*/
private static boolean test_kb_make_defined(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
Object[] rope = Special.list_objects(alpha);
return Machine.exec_unify(args[1], Store.make_defined(rope));
}
/**
* kb_is_link(Q): internal only
* The built-in succeeds if Q is a provable.
*/
private static boolean test_kb_is_link(Object[] args) {
Object peek = Machine.deref(Machine.exec_build(args[0]));
return Store.is_provable(peek);
}
/**
* kb_pred_link(F, A, Q): internal only
* The built-in succeeds in Q with the provable of the
* predicate indicator F/A. Otherwise if no such provable
* exists the built-in fails.
*/
private static boolean test_kb_pred_link(Object[] args) {
Object functor = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(functor);
Object beta = Machine.deref(Machine.exec_build(args[1]));
Special.check_integer(beta);
int arity = ((Number) beta).intValue();
Store.Provable peek = Store.pred_link((String) functor, arity);
if (peek == null)
return false;
return Machine.exec_unify(args[2], peek);
}
/**
* kb_link_flags(Q, F): internal only
* The built-in succeeds in F with the flags of the provable Q.
*/
private static boolean test_kb_link_flags(Object[] args) {
Object peek = Machine.deref(Machine.exec_build(args[0]));
check_provable(peek);
return Machine.exec_unify(args[1], Integer.valueOf(((Store.Provable) peek).flags));
}
/**
* Assure that the object is a provable.
*
* @param beta The object.
*/
public static void check_provable(Object beta) {
if (!Store.is_provable(beta)) {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"provable", beta}));
}
}
/*********************************************************************/
/* Meta Data */
/*********************************************************************/
/**
* kb_pred_list(L): internal only
* The built-in succeeds in L with the current predicate indicators.
*/
private static boolean test_kb_pred_list(Object[] args) {
Object res = kb_pred_list();
return Machine.exec_unify(args[0], res);
}
private static Object kb_pred_list() {
Store.Compound back = null;
Object res = null;
Iterator<Map.Entry<String, Handler.Rope<Store.Provable>>> it = Store.kb.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Handler.Rope<Store.Provable>> entry = it.next();
Handler.Rope<Store.Provable> temp = entry.getValue();
for (int i = 0; i < temp.size(); i++) {
Store.Provable peek = temp.get(i);
if (peek == null || peek.remover != Store.UNDEF_INT)
continue;
Store.Compound elem = new Store.Compound(".",
new Object[]{Machine.make_indicator(entry.getKey(), i),
Store.UNDEF_OBJ});
if (back == null) {
res = elem;
} else {
back.args[1] = elem;
}
back = elem;
}
}
if (back == null) {
res = "[]";
} else {
back.args[1] = "[]";
}
return res;
}
/**
* kb_clause_creator(C, S):
* The built-in succeeds in S with the creator of the clause C.
*/
private static boolean test_kb_clause_creator(Object[] args) {
Object clause = Machine.deref(Machine.exec_build(args[0]));
check_clause(clause);
return Machine.exec_unify(args[1], Integer.valueOf(((Store.Clause) clause).creator));
}
/**
* kb_clause_shard(C, S):
* The built-in succeeds in S with the shard of the clause C.
*/
private static boolean test_kb_clause_shard(Object[] args) {
Object clause = Machine.deref(Machine.exec_build(args[0]));
check_clause(clause);
return Machine.exec_unify(args[1], ((Store.Clause) clause).shard);
}
/**
* kb_clause_head(C, H): internal only
* The built-in succeeds in H with the head of the clause C.
*/
private static Object special_kb_clause_head(Object[] args) {
Object beta = Machine.deref(args[0]);
check_clause(beta);
Store.Clause clause = (Store.Clause) beta;
Object head = Machine.deref(args[1]);
Object[] display;
if (clause.size != 0) {
display = new Object[clause.size];
} else {
display = null;
}
if (Store.is_compound(head) &&
!Machine.exec_head(clause.head, display,
((Store.Compound) head).args))
return Boolean.FALSE;
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
/**
* kb_clause_data(C, H, O, L): internal only
* The built-in succeeds in H, O and L with the head,
* cut var and the body of the clause C.
*/
private static Object special_kb_clause_data(Object[] args) {
Object beta = Machine.deref(args[0]);
check_clause(beta);
Store.Clause clause = (Store.Clause) beta;
Object head = Machine.deref(args[1]);
Object[] display;
if (clause.size != 0) {
display = new Object[clause.size];
} else {
display = null;
}
if (Store.is_compound(head) &&
!Machine.exec_head(clause.head, display,
((Store.Compound) head).args))
return Boolean.FALSE;
Object temp;
int peek = clause.cutvar;
if (peek != -1) {
temp = new Store.Variable();
display[peek] = temp;
temp = new Store.Compound("just", new Object[]{temp});
} else {
temp = "nothing";
}
if (!Machine.unify(args[2], temp))
return Boolean.FALSE;
temp = Machine.exec_body(clause.body, display);
if (!Machine.unify(args[3], temp))
return Boolean.FALSE;
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
/******************************************************************/
/* dg_date_now/1 and dg_real_time/1 */
/******************************************************************/
/**
* dg_date_now(W): internal only
* The built-in succeeds in W with the wall clock time.
*/
private static boolean test_dg_date_now(Object[] args) {
return Machine.exec_unify(args[0],
ComputeElem.norm_smallint(System.currentTimeMillis()));
}
/**
* dg_real_time(W): internal only
* The built-in succeeds in W with the real time.
*/
private static boolean test_dg_real_time(Object[] args) {
return Machine.exec_unify(args[0],
ComputeElem.norm_smallint(Machine.real_time()));
}
/******************************************************************/
/* dg_gc_time/1, dg_call_count/1 and dg_gc_flags/1 */
/******************************************************************/
/**
* dg_gc_time(W): internal only
* The built-in succeeds in W with the garbage collection time.
*/
private static boolean test_dg_gc_time(Object[] args) {
return Machine.exec_unify(args[0],
ComputeElem.norm_smallint(Machine.gc_time));
}
/**
* dg_call_count(W): internal only
* The built-in succeeds in W with the call count.
*/
private static boolean test_dg_call_count(Object[] args) {
return Machine.exec_unify(args[0],
ComputeElem.norm_smallint(Machine.gc_enter));
}
/**
* dg_gc_flags(W): internal only
* The built-in succeeds in W with the garbage collector flags.
*/
private static boolean test_dg_gc_flags(Object[] args) {
return Machine.exec_unify(args[0], Integer.valueOf(Machine.gc_flags));
}
/******************************************************************/
/* dg_var_serno/2 */
/******************************************************************/
/**
* dg_var_serno(V, S): internal only
* The built-in succeeds in S with the serno of the variable V.
*/
private static boolean test_dg_var_serno(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
Special.check_var(obj);
return Machine.exec_unify(args[1], Integer.valueOf(
(((Store.Variable) obj).flags & ~Machine.VAR_MASK_STATE)));
}
/**************************************************************/
/* dg_clear_stage/0, dg_get_stage/1 and dg_set_stage/1 */
/**************************************************************/
/**
* dg_clear_stage: internal only
* The built-in succeeds. As a side effect it clears the current stage.
*/
private static boolean test_dg_clear_stage(Object[] args) {
Store.clear();
return true;
}
/**
* dg_get_stage(D): internal only
* The built-in succeeds in D with the current stage.
*/
private static boolean test_dg_get_stage(Object[] args) {
return Machine.exec_unify(args[0], Integer.valueOf(Store.stage));
}
/**
* dg_set_stage(D): internal only
* The built-in succeeds. As a side effect it changes the current stage.
*/
private static boolean test_dg_set_stage(Object[] args) {
Object value = Machine.deref(Machine.exec_build(args[0]));
Special.check_integer(value);
Store.set_stage(((Number) value).intValue());
return true;
}
/**************************************************************/
/* dg_get_partition/1 and dg_set_partition/1 */
/**************************************************************/
/**
* dg_get_partition(D): internal only
* The built-in succeeds in D with the current stage.
*/
private static boolean test_dg_get_partition(Object[] args) {
return Machine.exec_unify(args[0], Store.engine.partition);
}
/**
* dg_set_partition(D): internal only
* The built-in succeeds. As a side effect it changes the current partition.
*/
private static boolean test_dg_set_partition(Object[] args) {
Object value = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(value);
Store.set_partition((String) value);
return true;
}
/**************************************************************/
/* os_stream_list/2, os_get_workdir/1 and os_set_workdir/1 */
/**************************************************************/
/**
* os_stream_list(S, L): internal only
* The built-in succeeds in L with the properties of the stream S.
*/
private static boolean test_os_stream_list(Object[] args) {
Object stream = Machine.deref(Machine.exec_build(args[0]));
stream = os_stream_list(stream);
return Machine.exec_unify(args[1], stream);
}
private static Object os_stream_list(Object stream) {
Object res;
if (stream instanceof Sink) {
res = "[]";
} else {
check_source(stream);
res = "[]";
Object value = new Store.Compound("line_no",
new Object[]{Integer.valueOf(((Source) stream).lineno)});
res = new Store.Compound(".",
new Object[]{value, res});
}
return res;
}
/**
* os_get_workdir(D): internal only
* The built-in succeeds in D with the working directory.
*/
private static boolean test_os_get_workdir(Object[] args) {
Object url = codebase + File.separatorChar;
return Machine.exec_unify(args[0], url);
}
/**
* os_set_workdir(D): internal only
* The built-in succeeds. As a side effect it changes the working directory to D.
*/
private static boolean test_os_set_workdir(Object[] args) {
Object url = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(url);
File file = file(codebase, (String) url);
try {
file = file.toPath().toRealPath().toFile();
} catch (NoSuchFileException x) {
throw Machine.make_error(new Store.Compound("existence_error",
new Object[]{"source_sink", url}));
} catch (IOException x) {
throw Machine.make_error(new Store.Compound("resource_error",
new Object[]{"io_exception"}));
}
if (!file.isDirectory())
throw Machine.make_error(new Store.Compound("resource_error",
new Object[]{"io_exception"}));
codebase = file.getPath();
return true;
}
/*********************************************************************/
/* os_get_libpath/1 and os_get_natext/1 */
/*********************************************************************/
/**
* os_get_libpath(D): internal only
* The built-in succeeds in D with the library path.
*/
private static boolean test_os_get_libpath(Object[] args) {
Object url = bootbase + File.separatorChar;
return Machine.exec_unify(args[0], url);
}
/**
* os_get_natext(D): internal only
* The built-in succeeds in D with the native extension.
*/
private static boolean test_os_get_natext(Object[] args) {
return Machine.exec_unify(args[0], Special.NAT_EXT);
}
/*********************************************************************/
/* os_call_later/3 and os_call_cancel/1 */
/*********************************************************************/
/**
* os_call_later(N, D, T): internal only
* The predicate succeeds in T with a new timer. As a side
* effect it schedules the compiled goal N to be executed
* after D milliseconds.
*/
private static boolean test_os_call_later(Object[] args) {
Object goal = Machine.deref(Machine.exec_build(args[0]));
check_goal(goal);
Object alpha = Machine.deref(Machine.exec_build(args[1]));
Special.check_integer(alpha);
long delay = ((Number) alpha).longValue();
Object buf = Machine.ctx;
TimerTask tid = Machine.setDelay(() -> Machine.launch(goal, buf, Machine.VOID_ARGS), delay);
return Machine.exec_unify(args[2], tid);
}
private static void check_goal(Object beta) {
if (!(beta instanceof Machine.Goal)) {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"goal", beta}));
}
}
/**
* os_call_cancel(T): internal only
* The predicate succeeds. As a side effect it cancels the timer T.
*/
private static boolean test_os_call_cancel(Object[] args) {
TimerTask tid = (TimerTask) Machine.deref(Machine.exec_build(args[0]));
tid.cancel();
return true;
}
/******************************************************************/
/* os_task_current/1, os_task_abort/2 and os_task_create/2 */
/******************************************************************/
/**
* os_task_current(E): internal only
* The predicate succeeds in E with the current task.
*/
private static boolean test_os_task_current(Object[] args) {
return Machine.exec_unify(args[0], Machine.ctx);
}
/**
* os_task_abort(E, M): internal only
* The predicate succeeds. As a side effect the task E gets
* the message M signalled.
*/
private static boolean test_os_task_abort(Object[] args) {
Object buf = Machine.deref(Machine.exec_build(args[0]));
Object msg = Machine.exec_build(args[1]);
msg = Machine.copy_term(msg);
Machine.register_signal(buf, msg);
Machine.invoke_interrupt(buf);
return true;
}
/**
* os_task_create(N, E): internal only
* The predicate succeeds in E with a new task for the compiled
* goal N. The task is scheduled to execute immediately.
*/
private static boolean test_os_task_create(Object[] args) {
Object goal = Machine.deref(Machine.exec_build(args[0]));
check_goal(goal);
Machine.Context buf = new Machine.Context();
buf.engine.text_output = Store.engine.text_output;
buf.engine.text_error = Store.engine.text_error;
buf.engine.text_input = Store.engine.text_input;
Machine.setDelay(() -> Machine.launch_async(goal, buf, Machine.VOID_ARGS), 0);
return Machine.exec_unify(args[1], buf);
}
/******************************************************************/
/* os_host_info/1 */
/******************************************************************/
/**
* os_host_info(I): internal only
* The predicate succeeds in I with the host programming language info.
*/
private static boolean test_os_host_info(Object[] args) {
String version = System.getProperty("java.version");
int k = version.indexOf('_');
if (k != -1)
version = version.substring(0, k);
StringTokenizer st = new StringTokenizer(version, ".");
Object[] res = new Object[3];
for (int i = 0; i < res.length; i++)
res[i] = Integer.valueOf(Integer.parseInt(st.nextToken()));
Object value = new Store.Compound("java", res);
return Machine.exec_unify(args[0], value);
}
/******************************************************************/
/* Runtime Init */
/******************************************************************/
public static void boot() {
// stream specials, output
Store.add("current_output", 1, Special.make_check(Runtime::test_current_output));
Store.add("current_error", 1, Special.make_check(Runtime::test_current_error));
Store.add("set_output", 1, Special.make_check(Runtime::test_set_output));
Store.add("set_error", 1, Special.make_check(Runtime::test_set_error));
Store.add("put_code", 2, Special.make_check(Runtime::test_put_code));
Store.add("current_lastcode", 2, Special.make_check(Runtime::test_current_lastcode));
Store.add("set_lastcode", 2, Special.make_check(Runtime::test_set_lastcode));
Store.add("put_atom", 2, Special.make_check(Runtime::test_put_atom));
// stream specials, input
Store.add("current_input", 1, Special.make_check(Runtime::test_current_input));
Store.add("set_input", 1, Special.make_check(Runtime::test_set_input));
Store.add("os_read_sync", 1, Special.make_check(Runtime::test_os_read_sync));
Store.add("os_get_code", 2, Special.make_check(Runtime::test_os_get_code));
Store.add("os_peek_code", 2, Special.make_check(Runtime::test_os_peek_code));
Store.add("os_open_promise", 3, Special.make_check(Runtime::test_os_open_promise));
Store.add("os_stream_flags", 2, Special.make_check(Runtime::test_os_stream_flags));
Store.add("os_read_promise", 2, Special.make_check(Runtime::test_os_read_promise));
Store.add("os_close_promise", 2, Special.make_check(Runtime::test_os_close_promise));
// stream specials, files
Store.add("os_open_sync", 3, Special.make_check(Runtime::test_os_open_sync));
Store.add("flush_output", 1, Special.make_check(Runtime::test_flush_output));
Store.add("os_close_sync", 1, Special.make_check(Runtime::test_os_close_sync));
Store.add("os_prop_promise", 3, Special.make_check(Runtime::test_os_prop_promise));
Store.add("set_file_property", 2, Special.make_check(Runtime::test_set_file_property));
// intermediate representation, Albufeira code
Store.add("ir_place_new", 2, Special.make_check(Runtime::test_ir_place_new));
Store.add("ir_skeleton_new", 3, Special.make_check(Runtime::test_ir_skeleton_new));
Store.add("ir_is_site", 1, Special.make_check(Runtime::test_ir_is_site));
Store.add("ir_pred_site", 2, Special.make_check(Runtime::test_ir_pred_site));
Store.add("ir_site_name", 2, Special.make_check(Runtime::test_ir_site_name));
// intermediate representation specials, consult text, internal only
Store.add("ir_clause_new", 6, Special.make_check(Runtime::test_ir_clause_new));
Store.add("ir_clause_add", 4, Special.make_check(Runtime::test_ir_clause_add));
Store.add("ir_goal_new", 3, Special.make_check(Runtime::test_ir_goal_new));
Store.add("ir_goal_run", 1, Special.make_special(Runtime::special_ir_goal_run));
// knowledge base specials, dynamic database, internal only
Store.add("kb_clause_ref", 3, Special.make_special(Runtime::special_kb_clause_ref));
Store.add("kb_pred_touch", 3, Special.make_check(Runtime::test_kb_pred_touch));
Store.add("kb_clause_remove", 4, Special.make_check(Runtime::test_kb_clause_remove));
Store.add("kb_pred_destroy", 2, Special.make_check(Runtime::test_kb_pred_destroy));
// knowledge base specials, linked provables, internal only
Store.add("kb_make_defined", 2, Special.make_check(Runtime::test_kb_make_defined));
Store.add("kb_is_link", 1, Special.make_check(Runtime::test_kb_is_link));
Store.add("kb_pred_link", 3, Special.make_check(Runtime::test_kb_pred_link));
Store.add("kb_link_flags", 2, Special.make_check(Runtime::test_kb_link_flags));
// knowledge base specials, meta data, internal only
Store.add("kb_pred_list", 1, Special.make_check(Runtime::test_kb_pred_list));
Store.add("kb_clause_creator", 2, Special.make_check(Runtime::test_kb_clause_creator));
Store.add("kb_clause_shard", 2, Special.make_check(Runtime::test_kb_clause_shard));
Store.add("kb_clause_head", 2, Special.make_special(Runtime::special_kb_clause_head));
Store.add("kb_clause_data", 4, Special.make_special(Runtime::special_kb_clause_data));
// system specials, statistics, internal only
Store.add("dg_date_now", 1, Special.make_check(Runtime::test_dg_date_now));
Store.add("dg_real_time", 1, Special.make_check(Runtime::test_dg_real_time));
Store.add("dg_gc_time", 1, Special.make_check(Runtime::test_dg_gc_time));
Store.add("dg_call_count", 1, Special.make_check(Runtime::test_dg_call_count));
Store.add("dg_gc_flags", 1, Special.make_check(Runtime::test_dg_gc_flags));
Store.add("dg_var_serno", 2, Special.make_check(Runtime::test_dg_var_serno));
// system specials, staging, internal only
Store.add("dg_clear_stage", 0, Special.make_check(Runtime::test_dg_clear_stage));
Store.add("dg_get_stage", 1, Special.make_check(Runtime::test_dg_get_stage));
Store.add("dg_set_stage", 1, Special.make_check(Runtime::test_dg_set_stage));
Store.add("dg_get_partition", 1, Special.make_check(Runtime::test_dg_get_partition));
Store.add("dg_set_partition", 1, Special.make_check(Runtime::test_dg_set_partition));
// system specials, operating, internal only
Store.add("os_stream_list", 2, Special.make_check(Runtime::test_os_stream_list));
Store.add("os_get_workdir", 1, Special.make_check(Runtime::test_os_get_workdir));
Store.add("os_set_workdir", 1, Special.make_check(Runtime::test_os_set_workdir));
Store.add("os_get_libpath", 1, Special.make_check(Runtime::test_os_get_libpath));
Store.add("os_get_natext", 1, Special.make_check(Runtime::test_os_get_natext));
// system specials, coroutines, internal only
Store.add("os_call_later", 3, Special.make_check(Runtime::test_os_call_later));
Store.add("os_call_cancel", 1, Special.make_check(Runtime::test_os_call_cancel));
Store.add("os_task_current", 1, Special.make_check(Runtime::test_os_task_current));
Store.add("os_task_abort", 2, Special.make_check(Runtime::test_os_task_abort));
Store.add("os_task_create", 2, Special.make_check(Runtime::test_os_task_create));
// system specials, natlib, internal only
Store.add("os_host_info", 1, Special.make_check(Runtime::test_os_host_info));
}
}