Java "Machine"

Admin User, erstellt 02. Mai 2024
         
package nova;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
/**
* 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 Machine {
public final static Object[] VOID_ARGS = new Object[0];
public static Store.Variable trail = null;
public static Choice redo = null;
public static Object call = "[]";
public static int count = 0;
private static Timer timer = null;
private static Timer getTimer() {
if (timer == null)
timer = new Timer(true);
return timer;
}
/**
* Create an error term from a message.
*
* @param beta The message.
* @return Compound The error term.
*/
public static Handler.Problem make_error(Object beta) {
return new Handler.Problem(new Store.Compound("error",
new Object[]{beta, fetch_stack()}));
}
/**
* Retrieve the current stack.
*
* @return {string | Compound} The current stack.
*/
public static Object fetch_stack() {
Store.Provable temp = Store.pred_link("sys_including", 3);
if (temp == null || !Store.is_logical(temp.rope))
return "[]";
Store.Clause[] data = Store.snapshot_data(temp.rope);
Store.Compound back = null;
Object res = null;
for (int i = 0; i < data.length; i++) {
Store.Compound elem = fetch_frame(data[i]);
if (!elem.args[1].equals(ctx))
continue;
elem = new Store.Compound("sys_including", new Object[]{elem.args[0], elem.args[2]});
elem = new Store.Compound(".", new Object[]{elem, 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;
}
public static Store.Compound fetch_frame(Store.Clause clause) {
Object[] display;
if (clause.size != 0) {
display = new Object[clause.size];
} else {
display = null;
}
temp_display = display;
Object[] args = new Object[clause.head.length];
for (int i = 0; i < args.length; i++)
args[i] = exec_build(clause.head[i]);
temp_display = null;
return new Store.Compound("sys_including", args);
}
/**
* Create an indicator from a functor and an arity.
*
* @param functor The functor.
* @param arity The arity.
* @return Compound The indicator.
*/
public static Object make_indicator(Object functor, int arity) {
return new Store.Compound("/", new Object[]{functor, Integer.valueOf(arity)});
}
/**************************************************************/
/* Garbage Collection */
/**************************************************************/
public static final int VAR_MASK_EVEN = 0x40000000;
public static final int VAR_MASK_ODD = 0x20000000;
public static final int VAR_MASK_STATE = VAR_MASK_EVEN | VAR_MASK_ODD;
public static final int GC_MASK_ASYNC_MODE = 0x00000001;
public static final int GC_MASK_ALLOW_YIELD = 0x00000008;
public static final int GC_MASK_IMPORT_ASYNC = 0x00000010;
public static final int GC_MASK_PROP_ASYNC = 0x00000020;
public static final int GC_MASK_READ_ASYNC = 0x00000040;
public static final int GC_MASK_FULL_ASYNC =
GC_MASK_ASYNC_MODE | GC_MASK_ALLOW_YIELD;
public static final int GC_MAX_TRAIL = 3000000;
/* LIPS / 60 */
public static final int GC_MAX_INFERS = 200000;
/* LIPS * 60 */
public static final int GC_MAX_DIRTY = 720000000;
public static int gc_flags = VAR_MASK_ODD |
GC_MASK_IMPORT_ASYNC | GC_MASK_PROP_ASYNC | GC_MASK_READ_ASYNC;
public static long gc_time = 0;
public static long gc_enter = 0;
public static long gc_tick = GC_MAX_INFERS;
public static long gc_tock = GC_MAX_DIRTY;
/**
* Set the garbage collector flags.
*
* @param flags The garbage collector flags.
*/
public static void set_gc_flags(int flags) {
gc_flags = flags;
}
/**
* Retrieve the real time.
*
* @return The real time.
*/
public static long real_time() {
return (System.nanoTime() + 500000) / 1000000;
}
/**************************************************************/
/* Major Marking */
/**************************************************************/
/**
* Perform major garbage collection.
*/
private static void gc_major() {
gc_time -= real_time();
gc_flags ^= VAR_MASK_STATE;
/* mark phase */
Store.engine.low = 0;
Store.engine.high = Store.engine.serno;
Store.engine.serno = 0;
mark_call(call);
Choice last = redo;
while (last != null) {
mark_call(last.cont);
last = last.tail;
}
/* sweep phase */
last = redo;
while (last != null) {
last.mark = adjust_mark(last.mark);
last = last.tail;
}
sweep_trail(null);
gc_time += real_time();
}
/**
* Major mark a term.
*
* @param term The term.
*/
private static void mark_term(Object term) {
for (; ; ) {
if (Store.is_variable(term)) {
Store.Variable var = (Store.Variable) term;
int val = var.flags;
if ((val & VAR_MASK_STATE) == (gc_flags & VAR_MASK_STATE))
break;
val = val & ~VAR_MASK_STATE;
if (val > Store.engine.serno)
Store.engine.serno = val + 1;
if (Store.engine.low <= val && val < Store.engine.high) {
if (val - Store.engine.low > Store.engine.high - val) {
Store.engine.high = val;
} else {
Store.engine.low = val + 1;
}
}
var.flags = val | (gc_flags & VAR_MASK_STATE);
if (var.instantiated != Store.UNDEF_OBJ) {
term = var.instantiated;
} else {
break;
}
} else if (Store.is_compound(term)) {
Object[] args = ((Store.Compound) term).args;
int i = 0;
for (; i < args.length - 1; i++)
mark_term(args[i]);
term = args[i];
} else {
break;
}
}
}
/**
* Major mark a continuation.
*
* @param term The continuation.
*/
private static void mark_call(Object term) {
String gc_color = ((gc_flags & VAR_MASK_EVEN) != 0) ? "E" : "O";
while (Store.is_compound(term) && (!gc_color.equals(((Store.Compound) term).functor))) {
Store.Compound cmp = (Store.Compound) term;
cmp.functor = gc_color;
mark_term(cmp.args[0]);
term = cmp.args[1];
}
}
/**************************************************************/
/* Minor Marking */
/**************************************************************/
/**
* Perform minor garbage collection.
*/
private static void gc_minor() {
gc_time -= real_time();
/* mark phase */
mark2_call(call);
Choice last = redo;
while (last != null) {
mark2_call(last.cont);
last = last.tail;
}
mark2_trail(Store.engine.backtrail);
/* sweep phase */
last = redo;
while (last != null) {
last.mark = adjust_mark(last.mark);
last = last.tail;
}
sweep_trail(Store.engine.backtrail);
gc_time += real_time();
}
/**
* Minor mark a term.
*
* @param term The term.
*/
public static void mark2_term(Object term) {
for (; ; ) {
if (Store.is_variable(term)) {
Store.Variable var = (Store.Variable) term;
int val = var.flags;
if ((val & VAR_MASK_STATE) == (gc_flags & VAR_MASK_STATE))
break;
val = val & ~VAR_MASK_STATE;
var.flags = val | (gc_flags & VAR_MASK_STATE);
if (var.instantiated != Store.UNDEF_OBJ) {
term = var.instantiated;
} else {
break;
}
} else if (Store.is_compound(term)) {
Object[] args = ((Store.Compound) term).args;
int i = 0;
for (; i < args.length - 1; i++)
mark2_term(args[i]);
term = args[i];
} else {
break;
}
}
}
/**
* Minor mark a continuation.
*
* @param term The continuation.
*/
private static void mark2_call(Object term) {
String gc_color = ((gc_flags & VAR_MASK_EVEN) != 0) ? "E" : "O";
while (Store.is_compound(term) && (!gc_color.equals(((Store.Compound) term).functor))) {
Store.Compound cmp = (Store.Compound) term;
cmp.functor = gc_color;
mark2_term(cmp.args[0]);
term = cmp.args[1];
}
}
/**
* Minor mark the trail
*
* @param stop The stop.
*/
private static void mark2_trail(Store.Variable stop) {
Store.Variable temp = trail;
while (temp != stop) {
if ((temp.flags & VAR_MASK_STATE) == VAR_MASK_STATE)
mark2_term(temp);
temp = temp.tail;
}
}
/**************************************************************/
/* Variable Sweep */
/**************************************************************/
/**
* Adjust a marker into the trail.
*
* @param temp The trail.
* @return Variable The adjusted trail.
*/
private static Store.Variable adjust_mark(Store.Variable temp) {
while (temp != null) {
if ((temp.flags & VAR_MASK_STATE) == (gc_flags & VAR_MASK_STATE)) {
return temp;
} else {
temp = temp.tail;
}
}
return null;
}
/**
* Sweep the trail.
*
* @param stop The stop.
*/
private static void sweep_trail(Store.Variable stop) {
Store.Variable temp = trail;
Store.Variable back = null;
while (temp != stop) {
Store.Variable term = temp;
temp = term.tail;
if ((term.flags & VAR_MASK_STATE) == (gc_flags & VAR_MASK_STATE)) {
if (back != null) {
back.tail = term;
} else {
trail = term;
}
back = term;
} else {
count--;
term.instantiated = Store.UNDEF_OBJ;
term.tail = null;
}
}
if (back != null) {
back.tail = stop;
} else {
trail = stop;
}
Store.engine.backtrail = trail;
Store.engine.backcount = count;
}
/**************************************************************/
/* Signal Handling */
/**************************************************************/
/**
* Check the signal message.
*/
public static boolean solve_signal(Object rope, int at, Choice choice) {
if (Store.engine.signal != Store.UNDEF_OBJ) {
Object message = Store.engine.signal;
Store.engine.signal = Store.UNDEF_OBJ;
throw make_error(message);
}
return Boolean.TRUE;
}
private static HashMap<Store.Variable, Store.Variable> temp_assoc;
/**
* Copy a term.
*
* @param alpha The term.
* @return any The copy.
*/
public static Object copy_term(Object alpha) {
temp_assoc = null;
Object res = copy_term2(alpha);
temp_assoc = null;
return res;
}
private static Object copy_term2(Object alpha2) {
Store.Compound back = null;
for (; ; ) {
alpha2 = deref(alpha2);
if (Store.is_variable(alpha2)) {
Store.Variable peek;
if (temp_assoc == null) {
temp_assoc = new HashMap<>();
peek = null;
} else {
peek = temp_assoc.get((Store.Variable) alpha2);
}
if (peek == null) {
peek = new Store.Variable();
temp_assoc.put((Store.Variable) alpha2, peek);
}
alpha2 = peek;
break;
} else if (Store.is_compound(alpha2)) {
Object[] t1 = ((Store.Compound) alpha2).args;
Object[] args = new Object[t1.length];
alpha2 = new Store.Compound(((Store.Compound) alpha2).functor, args);
int i = 0;
for (; i < args.length - 1; i++)
args[i] = copy_term2(t1[i]);
args[i] = back;
back = (Store.Compound) alpha2;
alpha2 = t1[i];
} else {
break;
}
}
while (back != null) {
Object peek = back.args[back.args.length - 1];
back.args[back.args.length - 1] = alpha2;
alpha2 = back;
back = (Store.Compound) peek;
}
return alpha2;
}
/**************************************************************/
/* Clause Loops */
/**************************************************************/
/**
* Set the continuation.
*
* @param term The continuation.
*/
public static void cont(Object term) {
call = term;
}
/**
* Solve Prolog goals.
*
* @param snap The choice point boundary.
* @param found True for call, and false for redo.
* @return True if execution succeeds, otherwise false.
*/
public static Object solve(Choice snap, Object found) {
for (; ; ) {
if (found == Boolean.TRUE) {
if (gc_enter >= gc_tick) {
gc_tick += GC_MAX_INFERS;
if (count > GC_MAX_TRAIL) {
gc_major();
if (count > GC_MAX_TRAIL)
throw make_error(new Store.Compound("system_error",
new Object[]{"stack_overflow"}));
} else if (gc_enter >= gc_tock) {
gc_tock += GC_MAX_DIRTY;
gc_major();
} else if (3 * (count - Store.engine.backcount) > GC_MAX_TRAIL &&
3 * Store.engine.backcount > GC_MAX_TRAIL) {
gc_minor();
}
if ((gc_flags & GC_MASK_ASYNC_MODE) != 0) {
more(new Choice(Machine::solve_signal, null, 0, trail));
return immediate_promise();
}
}
Object goal = call;
if (Store.is_compound(goal)) {
gc_enter++;
goal = deref(((Store.Compound) goal).args[0]);
Store.Provable peek = lookup_pred(goal);
if (peek == null || (peek.flags & Store.MASK_PRED_ARITHMETIC) != 0)
throw make_error(new Store.Compound("existence_error",
new Object[]{"procedure", make_indicator_term(goal)}));
Object[] args;
if (Store.is_compound(goal)) {
args = ((Store.Compound) goal).args;
} else {
args = VOID_ARGS;
}
if ((peek.flags & Store.MASK_PRED_CHECK) != 0) {
if (!((Handler.Check) peek.func).run(args)) {
found = Boolean.FALSE;
} else {
Machine.cont(((Store.Compound) Machine.call).args[1]);
found = Boolean.TRUE;
}
} else if ((peek.flags & Store.MASK_PRED_SPECIAL) != 0) {
found = ((Handler.Builtin) peek.func).run(args);
} else {
Store.Logical def = defined_clauses(peek, args);
found = solve2_rope(args, Store.snapshot_data(def), 0, null);
}
} else {
break;
}
} else if (found == Boolean.FALSE) {
if (redo != snap) {
Choice choice = redo;
redo = choice.tail;
unbind(choice.mark);
call = choice.cont;
found = choice.func.run(choice.data, choice.at, choice);
} else {
break;
}
} else {
break;
}
}
return found;
}
private static Handler.Promise immediate_promise() {
return new Handler.Promise(() -> {
try {
Thread.sleep(0);
} catch (InterruptedException x) {
throw Machine.make_error(new Store.Compound("resource_error",
new Object[]{"interrupted_exception"}));
}
});
}
/**
* Lookup a predicate.
*
* @param goal The goal.
* @return Provable The predicate or null.
*/
public static Store.Provable lookup_pred(Object goal) {
Object functor;
int arity;
if (Store.is_compound(goal)) {
Store.Compound cmp = (Store.Compound) goal;
functor = cmp.functor;
arity = cmp.args.length;
} else {
functor = goal;
arity = 0;
}
return resolve_functor(functor, arity);
}
private static Store.Provable resolve_functor(Object functor, int arity) {
if (Store.is_cache(functor)) {
return Store.ensure_link((Store.Cache) functor, arity);
} else if (is_atom(functor)) {
return Store.pred_link((String) functor, arity);
} else if (Store.is_provable(functor)) {
return (Store.Provable) functor;
} else {
check_callable(functor);
return null;
}
}
public static Object make_indicator_term(Object goal) {
Object functor;
int arity;
if (Store.is_compound(goal)) {
Store.Compound cmp = (Store.Compound) goal;
functor = cmp.functor;
arity = cmp.args.length;
} else {
functor = goal;
arity = 0;
}
if (Store.is_cache(functor))
functor = ((Store.Cache) functor).name;
return make_indicator(functor, arity);
}
private static Object solve_rope(Object rope, int at, Choice choice) {
Object[] args;
Object goal = deref(((Store.Compound) Machine.call).args[0]);
if (Store.is_compound(goal)) {
args = ((Store.Compound) goal).args;
} else {
args = VOID_ARGS;
}
return solve2_rope(args, rope, at, choice);
}
/**
* Search a Prolog clause and add it to the continuation.
*
* @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.
*/
static Object solve2_rope(Object[] args, Object data, int at, Choice choice) {
Store.Variable mark = trail;
Store.Clause[] rope = (Store.Clause[]) data;
while (at < rope.length) {
Store.Clause clause = rope[at++];
Object[] display;
if (clause.size != 0) {
display = new Object[clause.size];
} else {
display = null;
}
if (exec_head(clause.head, display, args)) {
int peek = clause.cutvar;
if (peek != -1)
display[peek] = redo;
if (at < rope.length) {
if (choice == null) {
choice = new Choice(Machine::solve_rope, rope, at, mark);
} else {
choice.at = at;
}
more(choice);
if (exec_check(clause.body, display))
return Boolean.TRUE;
if (redo != choice)
return Boolean.FALSE;
more(choice.tail);
} else {
return (exec_check(clause.body, display) ? Boolean.TRUE : Boolean.FALSE);
}
}
unbind(mark);
}
return Boolean.FALSE;
}
/**
* Remove choice points.
*
* @param last The last choice point.
*/
public static void cut(Choice last) {
redo = last;
}
/**
* Advance the choice points.
*
* @param choice The new choice point.
*/
public static void more(Choice choice) {
redo = choice;
}
public static final class Choice {
public Handler.Callback func;
public Object data;
public int at;
public Store.Variable mark;
public Object cont;
public Choice tail;
/**
* Create a choice point.
*
* @param func The choice point handler.
* @param data The choice point data.
* @param at The choice point index.
* @param mark The trail mark.
*/
Choice(Handler.Callback func, Object data, int at, Store.Variable mark) {
this.func = func;
this.data = data;
this.at = at;
this.mark = mark;
this.cont = call;
this.tail = redo;
}
}
public static final class Goal {
public int size;
public Object[] body;
/**
* Create a goal.
*
* @param size The number of variables.
* @param body The build Albufeira code.
*/
public Goal(int size, Object[] body) {
this.size = size;
this.body = body;
}
}
/**************************************************************/
/* Clauses Retrieval */
/**************************************************************/
/**
* Find the logical for a call.
*
* @param pred The predicate.
* @param args The arguments.
* @return Logical The logical.
*/
public static Store.Logical defined_clauses(Store.Provable pred, Object[] args) {
Store.Logical peek = pred.rope;
if (peek.count < 2)
return peek;
if (args.length > 0 && pred.idxmap.size() > 0) {
Object key = key_value(args[0]);
if (key == Store.UNDEF_OBJ) {
return peek;
} else {
peek = pred.idxmap.get(key);
if (peek == null) {
return pred.nonguard;
} else {
return peek;
}
}
} else {
return peek;
}
}
static Object key_value(Object term) {
term = deref(term);
if (Store.is_variable(term)) {
return Store.UNDEF_OBJ;
} else if (Store.is_compound(term)) {
return ((Store.Compound) term).functor;
} else {
return term;
}
}
/**************************************************************/
/* Directives */
/**************************************************************/
/**
* Run a compiled goal once. The goal is run with auto-yield
* disabled and promises are not accepted.
*
* @param goal The compiled goal.
*/
public static void run(Goal goal) {
if (!launch(goal, "main", Machine.VOID_ARGS))
throw make_error(new Store.Compound("syntax_error",
new Object[]{"directive_failed"}));
}
static Choice snap_setup() {
redo = new Choice(Machine::solve_setup, null, 0, trail);
return redo;
}
static Object solve_setup(Object rope, int at, Choice choice) {
return Boolean.FALSE;
}
static void snap_cleanup(Choice snap) {
cut(snap.tail);
unbind(snap.mark);
call = snap.cont;
}
/**************************************************************/
/* Terms */
/**************************************************************/
/**
* Check whether an object is an atom.
*
* @param obj The object.
* @return boolean True if the object is an atom, otherwise false.
*/
public static boolean is_atom(Object obj) {
return obj instanceof String;
}
/**
* Check whether an object is a number.
*
* @param obj The object.
* @return boolean True if the object is a number, otherwise false.
*/
public static boolean is_number(Object obj) {
return obj instanceof Number;
}
/**
* Check whether an object is an integer.
*
* @param obj The object.
* @return boolean True if the object is an integer, otherwise false.
*/
public static boolean is_integer(Object obj) {
return (obj instanceof Integer) || (obj instanceof BigInteger);
}
/**
* Check whether an object is a float.
*
* @param obj The object.
* @return boolean True if the object is a float, otherwise false.
*/
public static boolean is_float(Object obj) {
return obj instanceof Double;
}
/**************************************************************/
/* Albufeira Code */
/**************************************************************/
private static Object[] temp_display;
public static Object exec_build(Object template) {
Store.Compound back = null;
for (; ; ) {
if (Store.is_place(template)) {
int index = ((Store.Place) template).index;
if (index == -1) {
template = new Store.Variable();
} else if (index < -1) {
template = new Store.Variable();
temp_display[(-index) - 2] = template;
} else {
template = temp_display[index];
}
break;
} else if (Store.is_skeleton(template)) {
Object[] t1 = ((Store.Skeleton) template).args;
Object[] args = new Object[t1.length];
template = new Store.Compound(((Store.Skeleton) template).functor, args);
int i = 0;
for (; i < args.length - 1; i++)
args[i] = exec_build(t1[i]);
args[i] = back;
back = (Store.Compound) template;
template = t1[i];
} else {
break;
}
}
while (back != null) {
Object peek = back.args[back.args.length - 1];
back.args[back.args.length - 1] = template;
template = back;
back = (Store.Compound) peek;
}
return template;
}
public static boolean exec_unify(Object template, Object alpha) {
for (; ; ) {
if (Store.is_place(template)) {
int index = ((Store.Place) template).index;
if (index == -1) {
return true;
} else if (index < -1) {
temp_display[(-index) - 2] = deref(alpha);
return true;
} else {
return unify(temp_display[index], alpha);
}
} else if (Store.is_skeleton(template)) {
alpha = deref(alpha);
if (Store.is_variable(alpha)) {
Object[] t1 = ((Store.Skeleton) template).args;
Object[] args = new Object[t1.length];
template = new Store.Compound(((Store.Skeleton) template).functor, args);
for (int i = 0; i < args.length; i++)
args[i] = exec_build(t1[i]);
bind(template, (Store.Variable) alpha);
return true;
} else if (Store.is_compound(alpha)) {
Object[] t1 = ((Store.Skeleton) template).args;
Object[] t2 = ((Store.Compound) alpha).args;
if (t1.length != t2.length)
return false;
if (!((Store.Skeleton) template).functor.equals(
((Store.Compound) alpha).functor))
return false;
int i = 0;
for (; i < t1.length - 1; i++)
if (!exec_unify(t1[i], t2[i]))
return false;
template = t1[i];
alpha = t2[i];
} else {
return false;
}
} else {
return unify(template, alpha);
}
}
}
static Object exec_body(Object[] code, Object[] display) {
temp_display = display;
Store.Compound back = null;
Object res = null;
for (int i = 0; i < code.length; i++) {
Object goal = exec_build(code[i]);
Store.Compound temp = new Store.Compound(".", new Object[]{goal, Store.UNDEF_OBJ});
if (back == null) {
res = temp;
} else {
back.args[1] = temp;
}
back = temp;
}
if (back == null) {
res = "[]";
} else {
back.args[1] = "[]";
}
temp_display = null;
return res;
}
static boolean exec_head(Object[] code, Object[] display,
Object[] aux) {
temp_display = display;
for (int i = 0; i < code.length; i++) {
if (!exec_unify(code[i], aux[i])) {
temp_display = null;
return false;
}
}
temp_display = null;
return true;
}
/**************************************************************/
/* Head Check */
/**************************************************************/
public static Number exec_eval(Object template) {
if (Store.is_skeleton(template)) {
Store.Skeleton skel = (Store.Skeleton) template;
Store.Provable peek = resolve_functor(skel.functor, skel.args.length + 1);
if (peek == null || (peek.flags & Store.MASK_PRED_ARITHMETIC) == 0)
throw make_error(new Store.Compound("type_error",
new Object[]{"evaluable", make_indicator(skel.functor, skel.args.length)}));
return ((Handler.Funktion) peek.func).eval(skel.args);
} else {
if (Store.is_place(template)) {
int index = ((Store.Place) template).index;
if (index < 0) {
throw make_error("instantiation_error");
} else {
template = temp_display[index];
}
}
template = deref(template);
if (is_number(template))
return (Number) template;
Store.Provable peek = lookup_eval(template);
if (peek == null || (peek.flags & Store.MASK_PRED_ARITHMETIC) == 0)
throw make_error(new Store.Compound("type_error",
new Object[]{"evaluable", make_indicator_term(template)}));
Object[] args;
if (Store.is_compound(template)) {
args = ((Store.Compound) template).args;
} else {
args = VOID_ARGS;
}
return ((Handler.Funktion) peek.func).eval(args);
}
}
private static Object exec_test(Object template) {
if (Store.is_skeleton(template)) {
Store.Skeleton skel = (Store.Skeleton) template;
Store.Provable peek = resolve_functor(skel.functor, skel.args.length);
if (peek == null || (peek.flags & Store.MASK_PRED_CHECK) == 0) {
Object[] args = new Object[skel.args.length];
for (int i = 0; i < args.length; i++)
args[i] = exec_build(skel.args[i]);
if (peek == null || (peek.flags & Store.MASK_PRED_ARITHMETIC) != 0) {
return new Store.Compound(skel.functor, args);
} else {
return new Store.Compound(peek, args);
}
} else {
gc_enter++;
return (((Handler.Check) peek.func).run(skel.args) ? Boolean.TRUE : Boolean.FALSE);
}
} else {
if (Store.is_place(template)) {
int index = ((Store.Place) template).index;
if (index < 0) {
throw make_error("instantiation_error");
} else {
template = temp_display[index];
}
}
template = deref(template);
Store.Provable peek = lookup_pred(template);
if (peek == null || (peek.flags & Store.MASK_PRED_CHECK) == 0) {
return template;
} else {
gc_enter++;
Object[] args;
if (Store.is_compound(template)) {
args = ((Store.Compound) template).args;
} else {
args = VOID_ARGS;
}
return (((Handler.Check) peek.func).run(args) ? Boolean.TRUE : Boolean.FALSE);
}
}
}
private static boolean exec_check(Object[] code, Object[] display) {
temp_display = display;
boolean check = true;
Store.Compound back = null;
Object res = null;
for (int i = 0; i < code.length; i++) {
Object goal = (check ? exec_test(code[i]) : exec_build(code[i]));
if (Boolean.TRUE.equals(goal))
continue;
if (Boolean.FALSE.equals(goal)) {
temp_display = null;
return false;
}
Store.Compound temp = new Store.Compound(".", new Object[]{goal, Store.UNDEF_OBJ});
if (back == null) {
res = temp;
} else {
back.args[1] = temp;
}
back = temp;
check = false;
}
if (back == null) {
res = ((Store.Compound) call).args[1];
} else {
back.args[1] = ((Store.Compound) call).args[1];
}
temp_display = null;
cont(res);
return true;
}
/**************************************************************/
/* Unification */
/**************************************************************/
/**
* Determine whether two terms unify.
* As a side effect the trail is extended, even if unification fails.
* Tail recursive solution.
*
* @param first The first term.
* @param second The second term.
* @return boolean True if the two terms unify, otherwise false.
*/
public static boolean unify(Object first, Object second) {
for (; ; ) {
first = deref(first);
second = deref(second);
if (Store.is_variable(first)) {
if (Store.is_variable(second) && first == second)
return true;
bind(second, (Store.Variable) first);
return true;
}
if (Store.is_variable(second)) {
bind(first, (Store.Variable) second);
return true;
}
if (!Store.is_compound(first))
return Objects.equals(first, second);
if (!Store.is_compound(second))
return false;
Object[] t1 = ((Store.Compound) first).args;
Object[] t2 = ((Store.Compound) second).args;
if (t1.length != t2.length)
return false;
if (!((Store.Compound) first).functor.equals(
((Store.Compound) second).functor))
return false;
int i = 0;
for (; i < t1.length - 1; i++) {
if (!unify(t1[i], t2[i]))
return false;
}
first = t1[i];
second = t2[i];
}
}
/**
* Dereference a Prolog term.
*
* @param term The Prolog term.
* @return any The dereferenced Prolog term.
*/
public static Object deref(Object term) {
while (Store.is_variable(term) &&
((Store.Variable) term).instantiated != Store.UNDEF_OBJ)
term = ((Store.Variable) term).instantiated;
return term;
}
/**
* Bind a variable to a term.
*
* @param source The Prolog term.
* @param term The variable.
*/
public static void bind(Object source, Store.Variable term) {
term.instantiated = source;
term.tail = trail;
if ((term.flags & VAR_MASK_STATE) == (gc_flags & VAR_MASK_STATE))
term.flags |= VAR_MASK_STATE;
trail = term;
count++;
}
/**
* Unbind variable binds.
*
* @param mark The trail mark.
*/
public static void unbind(Store.Variable mark) {
while (mark != trail) {
Store.Variable term = trail;
if (Store.engine.backtrail == term) {
Store.engine.backtrail = term.tail;
Store.engine.backcount--;
}
trail = term.tail;
count--;
term.instantiated = Store.UNDEF_OBJ;
term.tail = null;
}
}
/**************************************************************/
/* Eval Service */
/**************************************************************/
/**
* Assure that the object is a nonvar.
*
* @param beta The object.
*/
public static void check_nonvar(Object beta) {
if (Store.is_variable(beta))
throw make_error("instantiation_error");
}
/**
* Assure that the object is a callable.
*
* @param beta The object.
*/
public static void check_callable(Object beta) {
if (Store.is_variable(beta) || is_number(beta)) {
check_nonvar(beta);
beta = copy_term(beta);
throw make_error(new Store.Compound("type_error",
new Object[]{"callable", beta}));
}
}
/**
* Lookup an evaluable function.
*
* @param expr The arithmetic expression.
* @return Provable The evaluable function or null.
*/
private static Store.Provable lookup_eval(Object expr) {
Object functor;
int arity;
if (Store.is_compound(expr)) {
Store.Compound cmp = (Store.Compound) expr;
functor = cmp.functor;
arity = cmp.args.length;
} else {
functor = expr;
arity = 0;
}
return resolve_functor(functor, arity + 1);
}
/**************************************************************/
/* Context */
/**************************************************************/
public static final class Context {
public Store.Variable trail;
public Choice redo;
public Object call;
public int count;
public int gc_flags;
public Store.Engine engine;
/**
* Create a task context.
*/
public Context() {
this.trail = null;
this.redo = null;
this.call = "[]";
this.count = 0;
this.gc_flags = VAR_MASK_ODD |
GC_MASK_IMPORT_ASYNC | GC_MASK_PROP_ASYNC | GC_MASK_READ_ASYNC;
this.engine = new Store.Engine();
}
}
public static Object ctx = "main";
/**
* Set the task context.
*
* @param buf The context.
*/
public static void ctx_set(Object buf) {
ctx = buf;
}
/**
* Switch the task context.
*
* @param buf The context.
*/
public static void ctx_switch(Context buf) {
Store.Variable vtemp = trail;
trail = buf.trail;
buf.trail = vtemp;
Choice ctemp = redo;
redo = buf.redo;
buf.redo = ctemp;
Object otemp = call;
call = buf.call;
buf.call = otemp;
int itemp = count;
count = buf.count;
buf.count = itemp;
itemp = gc_flags;
gc_flags = buf.gc_flags;
buf.gc_flags = itemp;
Store.Engine etemp = Store.engine;
Store.set_engine(buf.engine);
buf.engine = etemp;
}
/**************************************************************/
/* Callback */
/**************************************************************/
/**
* Run a callback once, i.e. no choice point or trailing left
* behind. Callbacks are run with auto-yield disabled and
* promises are not accepted, i.e. run "stackless" on top of the
* given main stack or side stack. "stackless" because completion,
* i.e. return or exception by the callback, is the only context switch.
*
* @param form The goal or closure.
* @param buf The context or "main".
* @param params The actual parameters.
* @return True or false.
*/
public static boolean launch(Object form, Object buf, Object[] params) {
if (!buf.equals("main")) {
ctx_set(buf);
ctx_switch((Context) buf);
}
int back = gc_flags & GC_MASK_FULL_ASYNC;
set_gc_flags(gc_flags & ~GC_MASK_FULL_ASYNC);
Choice snap = snap_setup();
if (form instanceof Store.Clause) {
call = melt_clause((Store.Clause) form, params);
} else if (form instanceof Goal) {
call = melt_directive((Goal) form);
} else {
call = form;
}
Object found;
try {
found = solve(snap, Boolean.TRUE);
} finally {
snap_cleanup(snap);
set_gc_flags((gc_flags & ~GC_MASK_FULL_ASYNC) | back);
if (!buf.equals("main")) {
ctx_switch((Context) buf);
ctx_set("main");
}
}
return ((Boolean)found).booleanValue();
}
public static Object melt_directive(Goal goal) {
Object[] display;
if (goal.size != 0) {
display = new Object[goal.size];
} else {
display = null;
}
return exec_body(goal.body, display);
}
public static Object melt_clause(Store.Clause clause, Object[] params) {
Object[] display;
if (clause.size != 0) {
display = new Object[clause.size];
} else {
display = null;
}
if (exec_head(clause.head, display, params)) {
int peek = clause.cutvar;
if (peek != -1)
display[peek] = redo;
return exec_body(clause.body, display);
} else {
return "[]";
}
}
/**************************************************************/
/* Task */
/**************************************************************/
/**
* Run a task once, i.e. no choice point or trailing left
* behind. Tasks are run with auto-yield enabled and promises are
* accepted, i.e. run "stackfull" on top of the given main stack
* or side stack. "stackfull" because not only completion, i.e.
* return or exception by the task, cause a context switch, but
* also await of an auto-yield or promise.
*
* @param form The goal or closure.
* @param buf The context or "main".
* @param params The actual parameters.
* @return True or false.
*/
public static boolean launch_async(Object form, Object buf, Object[] params) {
if (!buf.equals("main")) {
ctx_set(buf);
ctx_switch((Context) buf);
}
int back = gc_flags & GC_MASK_FULL_ASYNC;
set_gc_flags(gc_flags | GC_MASK_FULL_ASYNC);
Object found = Boolean.TRUE;
Choice snap = snap_setup();
if (form instanceof Store.Clause) {
call = melt_clause((Store.Clause) form, params);
} else if (form instanceof Goal) {
call = melt_directive((Goal) form);
} else {
call = form;
}
try {
for (; ; ) {
found = solve(snap, found);
if (found == Boolean.FALSE) {
break;
} else if (found != Boolean.TRUE) {
if (!buf.equals("main")) {
ctx_switch((Context) buf);
ctx_set("main");
}
((Handler.Promise) found).await();
if (!buf.equals("main")) {
ctx_set(buf);
ctx_switch((Context) buf);
}
found = Boolean.FALSE;
} else {
break;
}
}
} finally {
snap_cleanup(snap);
set_gc_flags((gc_flags & ~GC_MASK_FULL_ASYNC) | back);
if (!buf.equals("main")) {
ctx_switch((Context) buf);
ctx_set("main");
}
}
return ((Boolean)found).booleanValue();
}
/**
* Delay a coroutine by some milliseconds.
*
* @param proc The coroutine.
* @param delay The milliseconds.
* @return The timer.
*/
public static TimerTask setDelay(Runnable proc, long delay) {
TimerTask tid = new Later(proc);
Timer timer = getTimer();
timer.schedule(tid, delay);
return tid;
}
private static class Later extends TimerTask {
Runnable proc;
public Later(Runnable proc) {
this.proc = proc;
}
public void run() {
new Handler.Coroutine(() -> proc.run()).async();
}
}
/**
* Register an interrupt function in a context.
*
* @param buf The context.
* @param func The function.
*/
public static void register_interrupt(Object buf, Runnable func) {
Store.Engine en = determine_engine(buf);
en.interrupt = func;
}
/**
* Register a signal in a context.
*
* @param buf The context.
* @param msg The signal.
*/
public static void register_signal(Object buf, Object msg) {
Store.Engine en = determine_engine(buf);
en.signal = msg;
}
/**
* Invoke the interrupt handler of a context.
*
* @param buf The context.
*/
public static void invoke_interrupt(Object buf) {
Store.Engine en = determine_engine(buf);
en.interrupt.run();
}
private static Store.Engine determine_engine(Object buf) {
if (!buf.equals("main")) {
if (!buf.equals(ctx)) {
Context temp = (Context) buf;
return temp.engine;
} else {
return Store.engine;
}
} else {
if (!ctx.equals("main")) {
Context temp = (Context) ctx;
return temp.engine;
} else {
return Store.engine;
}
}
}
}