Admin User, created Apr 17. 2025
package nova;
import nova.envir.ComputeCompare;
import nova.envir.ComputeElem;
import java.io.*;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.channels.UnresolvedAddressException;
import java.nio.charset.Charset;
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 {
private static final String HTTP_TIME = "%a, %d %b %Y %H:%M:%S GMT";
private static final int MAX_BUF = 4096;
public static String codebase = System.getProperty("user.dir");
private static String bootbase = "";
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;
}
/**
* <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 and current_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) -> fd;
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/1 and set_error/1 */
/**************************************************************/
/**
* 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 = new Machine.copy_term().copy_term2(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"writer", beta}));
}
}
/**************************************************************/
/* put_atom/2 and dg_var_serno/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.last = text.codePointBefore(text.length());
if (stream.buf != null) {
stream.buf.append(text);
if (stream.buf.length() >= MAX_BUF)
flush_buffer(stream);
} else {
stream.data = stream.send.perform(stream.data, text);
}
}
}
private static void flush_buffer(Sink stream) {
if (stream.buf != null && stream.buf.length() > 0) {
String text = stream.buf.toString();
stream.buf = new StringBuilder();
stream.data = stream.send.perform(stream.data, text);
}
}
/**
* 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)));
}
/**************************************************************/
/* 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 = new Machine.copy_term().copy_term2(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_opts/4 */
/****************************************************************/
/**
* os_open_promise_opts(P, L, S, Q):
* The predicate succeeds in Q with a promise for open input S
* on path P and option list L.
*/
private static boolean test_os_open_promise_opts(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
special.check_atom(obj);
String url = (String) obj;
HashMap<String, Object> opts = (HashMap<String, Object>) Machine.deref(Machine.exec_build(args[1]));
Source stream = new Source();
if (!Machine.exec_unify(args[2], stream))
return false;
Object buf = Machine.ctx;
Handler.Promise prom;
if (url.startsWith("http:") || url.startsWith("https:")) {
prom = open_http_promise_opts(buf, stream, url, opts);
} else {
prom = open_file_promise_opts(buf, stream, url, opts);
}
return Machine.exec_unify(args[3], prom);
}
private static Handler.Promise open_http_promise_opts(Object buf,
Source stream, String url, HashMap<String, Object> opts) {
return new Handler.Promise(() -> {
Thread self = Thread.currentThread();
Machine.register_interrupt(buf, () -> self.interrupt());
try {
String method;
HttpRequest.BodyPublisher body;
if (opts != null && opts.get("method") != null) {
method = opts.get("method").toString();
} else if (opts != null && opts.get("body") != null) {
method = "POST";
} else {
method = "GET";
}
if (opts != null && opts.get("body") != null) {
HashMap<String, Object> opts2 = (HashMap<String, Object>) opts.get("body");
body = HttpRequest.BodyPublishers.ofString(
opts2.get("text").toString(),
get_encoding(opts2));
} else {
body = HttpRequest.BodyPublishers.noBody();
}
HttpRequest.Builder builder = HttpRequest.newBuilder().method(method, body);
if (opts != null && opts.get("headers") != null) {
HashMap<String, Object> headers = (HashMap<String, Object>) opts.get("headers");
Iterator<Map.Entry<String, Object>> it = headers.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Object> entry = it.next();
builder = builder.header(entry.getKey(), entry.getValue().toString());
}
}
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 || 399 < response.statusCode()) {
Machine.register_signal(buf, map_http_result(response.statusCode(), url));
} else {
if (opts != null) {
opts.put("uri", response.uri().toString());
opts.put("status", Integer.valueOf(response.statusCode()));
HashMap<String, Object> res = new HashMap<>();
Map<String,List<String>> map = response.headers().map();
Iterator<Map.Entry<String,List<String>>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String,List<String>> entry = it.next();
res.put(entry.getKey(), entry.getValue().get(0));
}
opts.put("fields", res);
}
InputStream in = response.body();
stream.data = new InputStreamReader(in, get_encoding(opts));
stream.receive = (Handler.Factory) runtime::file_read_promise;
stream.release = (Handler.Factory) runtime::file_close_promise;
stream.flags |= MASK_SRC_AREAD;
}
} catch (InterruptedException x) {
/* */
} finally {
Machine.register_interrupt(buf, () -> {
});
}
});
}
public static Charset get_encoding(HashMap<String, Object> opts) {
if (opts != null && opts.get("encoding") != null) {
String encoding = opts.get("encoding").toString();
return Charset.forName(encoding);
} else {
return StandardCharsets.UTF_8;
}
}
private static Handler.Promise open_file_promise_opts(Object buf,
Source stream, String url, HashMap<String, Object> opts) {
return new Handler.Promise(() -> {
File file = file(codebase, url);
try {
InputStream in = new FileInputStream(file);
stream.data = new InputStreamReader(in, get_encoding(opts));
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 ||
err instanceof NoSuchFileException) {
return new Store.Compound("existence_error",
new Object[]{"source_sink", url});
} else if (err instanceof ConnectException) {
Throwable cause = err.getCause();
if (cause != null && cause.getCause() instanceof UnresolvedAddressException) {
return new Store.Compound("resource_error", new Object[]{"unknown_host"});
} else {
return new Store.Compound("resource_error", new Object[]{"connect_failed"});
}
} else {
return new Store.Compound("resource_error", new Object[]{"remote_error"});
}
}
/*******************************************************************/
/* 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 {
char[] cbuf = new char[8192];
int len = ((Reader)stream.data).read(cbuf);
stream.buf = (len > 0 ? new String(cbuf, 0, len) : "");
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 SocketTimeoutException) {
return new Store.Compound("resource_error",
new Object[]{"socket_timeout"});
} else if (err instanceof BindException) {
return new Store.Compound("resource_error",
new Object[]{"port_error"});
} 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_exception"});
}
}
/**
* 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_opts/4 */
/**************************************************************/
/**
* os_open_sync_opts(P, M, L, S):
* The predicate succeeds. As a side effect the stream S is
* opened on the path P with the mode M and the option list L.
*/
private static boolean test_os_open_sync_opts(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);
HashMap<String, Object> opts = (HashMap<String, Object>) Machine.deref(Machine.exec_build(args[2]));
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, opts);
} else if ("append".equals(mode)) {
stream = open_write(url, true, opts);
} else {
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"io_mode", mode}));
}
return Machine.exec_unify(args[3], stream);
}
private static Object open_write(String url, boolean append, HashMap<String, Object> opts) {
try {
File file = file(codebase, url);
FileOutputStream out = new FileOutputStream(file, append);
Sink dst = new Sink();
dst.data = new OutputStreamWriter(out, get_encoding(opts));
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 Object file_write(Object data, String 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;
}
return data;
} 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(stream);
return true;
}
public static void flush(Object obj) {
Sink stream = (Sink)obj;
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.BodyPublisher body = HttpRequest.BodyPublishers.noBody();
String method = "HEAD";
HttpRequest.Builder builder = HttpRequest.newBuilder().method(method, body);
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");
long mtime = (val.isPresent() ? special.sys_time_parse(
val.get(), HTTP_TIME, 1) : -1);
res.put("last_modified", ComputeElem.norm_smallint(mtime));
res.put("absolute_path", response.uri().toString());
res.put("type", "regular");
}
} 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"});
case 500: // Internal Server Error
return new Store.Compound("resource_error",
new Object[]{"internal_error"});
case 503: // Service Unavailable
return new Store.Compound("resource_error",
new Object[]{"service_unavailable"});
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(() -> {
File file = file(codebase, url);
try {
if (!file.exists())
throw new NoSuchFileException("");
String ftype = (file.isFile() ? "regular" : (file.isDirectory() ? "directory" : "other"));
res.put("last_modified", ComputeElem.norm_smallint(file.lastModified()));
res.put("absolute_path", file.getCanonicalPath());
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 obj = Machine.deref(Machine.exec_build(args[0]));
special.check_atom(obj);
String url = (String)obj;
if (url.startsWith("http:") || url.startsWith("https:"))
throw Machine.make_error(new Store.Compound("permission_error",
new Object[]{"access", "source_sink", 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, 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 = new Machine.copy_term().copy_term2(prop);
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"prolog_property", prop}));
}
return true;
}
/**************************************************************/
/* ir_place_new/2, ir_skeleton_new/3 and ir_pred_site/2 */
/**************************************************************/
/**
* 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_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_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, R, G):
* The built-in succeeds in G with a Java object representing
* a goal with variable count S, body instructions B and the
* cut variable index R.
*/
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);
Object gamma = Machine.deref(Machine.exec_build(args[2]));
special.check_integer(gamma);
int size = ((Integer) alpha).intValue();
Store.unquote_objects(body);
int cutvar = ((Integer) gamma).intValue();
return Machine.exec_unify(args[3], new Machine.Goal(size, body, cutvar));
}
/**
* 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);
}
public static void check_goal(Object beta) {
if (!(beta instanceof Machine.Goal)) {
Machine.check_nonvar(beta);
beta = new Machine.copy_term().copy_term2(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"goal", beta}));
}
}
/**
* 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.more(snap.tail);
}
return found;
}
Machine.snap_cleanup(snap);
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
/**************************************************************/
/* kb_clause_ref/3 and kb_pred_touch/3 */
/**************************************************************/
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/4 and kb_pred_destroy/2 */
/**************************************************************/
/**
* 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 = new Machine.copy_term().copy_term2(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;
}
/**************************************************************/
/* kb_make_defined/2, kb_pred_link/3 and kb_link_flags/2 */
/**************************************************************/
/**
* 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_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 = new Machine.copy_term().copy_term2(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"provable", beta}));
}
}
/**************************************************************/
/* kb_pred_list/1, kb_clause_creator/2 and kb_clause_shard/2 */
/**************************************************************/
/**
* 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/2 and kb_clause_data/4 */
/**************************************************************/
/**
* 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;
}
/**************************************************************/
/* sys_stat_map/1, dg_gc_flags/1 and garbage_collect/0 */
/**************************************************************/
/**
* sys_stat_map(M): internal only
* The built-in succeeds in W with the statistics map.
*/
private static boolean test_sys_stat_map(Object[] args) {
HashMap<String, Object> res = new HashMap<>();
res.put("wall", ComputeElem.norm_smallint(System.currentTimeMillis()));
res.put("time", ComputeElem.norm_smallint(Machine.real_time()));
res.put("calls", ComputeElem.norm_smallint(Machine.gc_enter));
res.put("gctime", ComputeElem.norm_smallint(Machine.gc_time));
res.put("used", ComputeElem.norm_smallint( Runtime.getRuntime().totalMemory() -
Runtime.getRuntime().freeMemory()));
return Machine.exec_unify(args[0], res);
}
/**
* 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));
}
/**
* garbage_collect: internal only
* The built-in succeeds in attempting a garbage colection.
*/
private static boolean test_garbage_collect(Object[] args) {
Machine.gc_major();
Runtime.getRuntime().gc();
return true;
}
/**************************************************************/
/* sys_flag_map/1 */
/**************************************************************/
/**
* sys_flag_map(M): internal only
* The built-in succeeds in W with a Prolog flag map.
*/
private static boolean test_sys_flag_map(Object[] args) {
HashMap<String, Object> res = new HashMap<>();
res.put("host_info", System.getProperty("java.vendor")+", Java "+System.getProperty("java.version"));
res.put("mach_info", System.getProperty("os.arch")+", "+System.getProperty("os.name"));
return Machine.exec_unify(args[0], res);
}
/**************************************************************/
/* 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) {
Machine.teardown();
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_get_workdir/1 and os_set_workdir/1 */
/**************************************************************/
/**
* 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 obj = Machine.deref(Machine.exec_build(args[0]));
special.check_atom(obj);
String url = (String)obj;
File file = file(codebase, url);
String rpath;
try {
if (!file.exists())
throw new NoSuchFileException("");
if (!file.isDirectory())
throw new IOException("");
rpath = file.getCanonicalPath();
} catch (IOException err) {
throw Machine.make_error(map_file_error(err, url));
}
codebase = rpath;
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);
}
/**************************************************************/
/* 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_atom", 2, special.make_check(runtime::test_put_atom));
Store.add("dg_var_serno", 2, special.make_check(runtime::test_dg_var_serno));
// 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_opts", 4, special.make_check(runtime::test_os_open_promise_opts));
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_opts", 4, special.make_check(runtime::test_os_open_sync_opts));
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_pred_site", 2, special.make_check(runtime::test_ir_pred_site));
// 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", 4, 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_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("sys_stat_map", 1, special.make_check(runtime::test_sys_stat_map));
Store.add("dg_gc_flags", 1, special.make_check(runtime::test_dg_gc_flags));
Store.add("garbage_collect", 0, special.make_check(runtime::test_garbage_collect));
Store.add("sys_flag_map", 1, special.make_check(runtime::test_sys_flag_map));
// 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_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));
}
}