Java "Special"

Admin User, erstellt 03. Mai 2024
         
package nova;
import nova.envir.ComputeCompare;
import nova.envir.ComputeElem;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
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 Special {
public static int MAX_ARITY = 2147483647;
public static final String NAT_EXT = ".java";
public static String[] main_args = new String[0];
private static String[] classpath = null;
/**
* Set the program arguments.
*
* @param a The program arguments.
*/
public static void set_args(String[] a) {
main_args = a;
}
/**
* <p>Set the class path.</p>
*
* @param cp The class path.
*/
public static void set_classpath(String[] cp) {
classpath = cp;
}
/******************************************************************/
/* Special Predicate */
/******************************************************************/
/**
* Return a built-in for a special.
*
* @param func The special.
* @return Provable The built-in.
*/
public static Store.Provable make_special(Handler.Builtin func) {
Store.Provable peek = new Store.Provable(Store.MASK_PRED_SPECIAL);
peek.func = func;
return peek;
}
/**
* Return a built-in for a check.
*
* @param func The check.
* @return Provable The built-in.
*/
public static Store.Provable make_check(Handler.Check func) {
Store.Provable peek = new Store.Provable(Store.MASK_PRED_CHECK);
peek.func = func;
return peek;
}
/**
* Return a built-in for an arithmetic.
*
* @param func The arithmetic.
* @return Provable The built-in.
*/
public static Store.Provable make_arithmetic(Handler.Funktion func) {
Store.Provable peek = new Store.Provable(Store.MASK_PRED_ARITHMETIC);
peek.func = func;
return peek;
}
/******************************************************************/
/* fail/0, '$CUT'/1 and '$MARK'/1 */
/******************************************************************/
/**
* fail: [ISO 7.8.2]
* The built-in fails.
*/
private static boolean test_fail(Object[] args) {
return false;
}
/**
* '$CUT'(R): internal only
* The built-in removes the choice points up to R and succeeds.
*/
private static boolean test_cut(Object[] args) {
Object choice = Machine.deref(Machine.exec_build(args[0]));
Machine.cut((Machine.Choice) choice);
return true;
}
/**
* '$MARK'(R): Internal only
* The built-in binds R to the top choice point.
*/
private static boolean test_mark(Object[] args) {
Object choice = Machine.redo;
return Machine.exec_unify(args[0], choice);
}
/******************************************************************/
/* '$SEQ'/2 and '$ALT'/1 */
/******************************************************************/
/**
* '$SEQ'(O, L): internal only
* If the Prolog term O has the form just(R) bind R the top choice point.
* Otherwise, do nothing. The built-in then sequentially adds the goals L
* to the continuation.
*/
private static Object special_seq(Object[] args) {
Object temp = Machine.deref(args[0]);
solve_mark(temp);
temp = Machine.deref(args[1]);
solve_seq(temp);
return Boolean.TRUE;
}
/**
* If the Prolog term has the form just(R) bind R the top choice point.
* Otherwise do nothing.
*
* @param temp The Prolog term.
*/
private static void solve_mark(Object temp) {
if (Store.is_compound(temp) &&
"just".equals(((Store.Compound) temp).functor) &&
((Store.Compound) temp).args.length == 1) {
temp = Machine.deref(((Store.Compound) temp).args[0]);
Machine.bind(Machine.redo, (Store.Variable) temp);
}
}
/**
* Sequentially adds the literals L to the continuation. The list
* is unchecked, no validation that it ends on [].
*
* @param goal The literals.
*/
private static void solve_seq(Object goal) {
Store.Compound back = null;
Object res = null;
while (Store.is_compound(goal) &&
".".equals(((Store.Compound) goal).functor) &&
((Store.Compound) goal).args.length == 2) {
Object peek = ((Store.Compound) goal).args[0];
Store.Compound temp = new Store.Compound(".",
new Object[]{peek, Store.UNDEF_OBJ});
if (back == null) {
res = temp;
} else {
back.args[1] = temp;
}
back = temp;
goal = Machine.deref(((Store.Compound) goal).args[1]);
}
if (back == null) {
res = ((Store.Compound) Machine.call).args[1];
} else {
back.args[1] = ((Store.Compound) Machine.call).args[1];
}
Machine.cont(res);
}
/**
* '$ALT'(L): internal only
* The built-in alternatively adds the variants L to the
* continuation and succeeds.
*/
private static Object special_alt(Object[] args) {
Object goal = Machine.deref(args[0]);
return solve_alt(goal, -1, null);
}
/**
* Alternatively adds the variants to the continuation.
*
* @param goal The variants.
* @param at This argument is ignored.
* @param choice The choice point for reuse or null.
* @return boolean True if a variant could be added, otherwise false.
*/
private static Object solve_alt(Object goal, int at, Machine.Choice choice) {
if (Store.is_compound(goal) &&
".".equals(((Store.Compound) goal).functor) &&
((Store.Compound) goal).args.length == 2) {
Store.Variable mark = Machine.trail;
Object peek = Machine.deref(((Store.Compound) goal).args[0]);
Object temp = Machine.deref(((Store.Compound) peek).args[0]);
solve_mark(temp);
peek = Machine.deref(((Store.Compound) peek).args[1]);
goal = Machine.deref(((Store.Compound) goal).args[1]);
if (Store.is_compound(goal) &&
".".equals(((Store.Compound) goal).functor) &&
((Store.Compound) goal).args.length == 2) {
if (choice == null) {
choice = new Machine.Choice(Special::solve_alt, goal, -1, mark);
} else {
choice.data = goal;
}
Machine.more(choice);
}
solve_seq(peek);
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
/*****************************************************************/
/* sys_raise/1 and sys_trap/3 */
/*****************************************************************/
/**
* sys_raise(E): internal only
* The predicate raises the exception E.
*/
private static boolean test_sys_raise(Object[] args) {
Object problem = Machine.exec_build(args[0]);
throw new Handler.Problem(Machine.copy_term(problem));
}
/**
* sys_trap(G, E, F): internal only
* The built-in succeeds whenever G succeeds. If
* there was an exception that unifies with E, the
* built-in further succeeds whenever F succeeds.
*/
private static Object special_sys_trap(Object[] args) {
Object goal = Machine.deref(args[0]);
Machine.Choice snap = Machine.snap_setup();
goal = new Store.Compound(".", new Object[]{goal, "[]"});
Machine.cont(goal);
return solve_catch(snap, 1, null);
}
/**
* Call, redo or resume a goal.
* If there is an exception put the handler on the continuation.
*
* @param data The surrounding choice point.
* @param at The call or redo flag.
* @param choice The choice point for reuse or null.
* @return boolean True if goal succeeded, otherwise false.
*/
private static Object solve_catch(Object data, int at, Machine.Choice choice) {
if (choice != null) {
choice.mark = null;
choice.cont = "[]";
choice.tail = null;
}
Machine.Choice snap = (Machine.Choice) data;
Object found = (at != 0 ? Boolean.TRUE : Boolean.FALSE);
try {
found = Machine.solve(snap, found);
} catch (Throwable err) {
Machine.snap_cleanup(snap);
Object goal = Machine.deref(((Store.Compound) Machine.call).args[0]);
err = map_throwable(err);
if (!Machine.unify(((Store.Compound) goal).args[1],
(err instanceof Handler.Problem ? ((Handler.Problem) err).term : err)))
Special.sneaky(err);
goal = Machine.deref(((Store.Compound) goal).args[2]);
goal = new Store.Compound(".",
new Object[]{goal, ((Store.Compound) Machine.call).args[1]});
Machine.cont(goal);
return Boolean.TRUE;
}
if (found == Boolean.FALSE)
return Boolean.FALSE;
if (Machine.redo != snap) {
if (choice == null) {
choice = new Machine.Choice(Special::solve_catch, 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);
}
if (found == Boolean.TRUE)
Machine.cont(((Store.Compound) snap.cont).args[1]);
return found;
}
private static Throwable map_throwable(Throwable err) {
if (err instanceof StackOverflowError)
err = Machine.make_error(new Store.Compound("system_error",
new Object[]{"stack_overflow"}));
return err;
}
/**
* https://www.baeldung.com/java-sneaky-throws
*/
private static <E extends Throwable> void sneaky(Throwable x) throws E {
throw (E) x;
}
/*******************************************************************/
/* os_sleep_promise/2 and os_import_promise/3 */
/*******************************************************************/
/**
* os_sleep_promise(D, P):
* The predicate succeeds in P with a promise for a delay D.
*/
private static boolean test_os_sleep_promise(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
check_integer(obj);
if (ComputeCompare.integer_signum((Number) obj) < 0)
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"not_less_than_zero", obj}));
long delay = ((Number) obj).longValue();
Object buf = Machine.ctx;
return Machine.exec_unify(args[1], sleep_promise(buf, delay));
}
private static Handler.Promise sleep_promise(Object buf, long delay) {
return new Handler.Promise(() -> {
Thread self = Thread.currentThread();
Machine.register_interrupt(buf, () -> self.interrupt());
try {
Thread.sleep(delay);
} catch (InterruptedException x) {
/* */
} finally {
Machine.register_interrupt(buf, () -> {});
}
});
}
/**
* os_import_promise(F, M, Q):
* The predicate succeeds in Q with with a promise for the
* import M of the file F.
*/
private static boolean test_os_import_promise(Object[] args) {
Object url = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(url);
HashMap<String, Object> res = new HashMap<String, Object>();
if (!Machine.exec_unify(args[1], res))
return false;
Object buf = Machine.ctx;
return Machine.exec_unify(args[2], import_promise(buf, (String) url, res));
}
private static Handler.Promise import_promise(Object buf, String url, HashMap<String, Object> res) {
return new Handler.Promise(() -> {
String name = Special.find_name(url);
try {
Class<?> clazz = Class.forName(name);
res.put("module", clazz);
} catch (ClassNotFoundException x) {
Machine.register_signal(buf, new Store.Compound("existence_error",
new Object[]{"class", url}));
} catch (ExceptionInInitializerError x) {
Machine.register_signal(buf, x.getCause());
}
});
}
/**
* Find a Java class name from an url
*
* @param url The url
* @return The Java class name or null
*/
public static String find_name(String url) {
if (!url.endsWith(Special.NAT_EXT))
return null;
url = new File(url).toURI().toString();
String path = find_path(url);
if (path == null)
return null;
url = url.substring(path.length(), url.length() - Special.NAT_EXT.length());
url = url.replace("/", ".");
url = url.replace("\\", ".");
return url;
}
/**
* Find a classpath entry for an url
*
* @param url The url
* @return The classpath entry or null
*/
private static String find_path(String url) {
for (int i = 0; i < Special.classpath.length; i++) {
String path = Special.classpath[i];
if (url.startsWith(path))
return path;
}
return null;
}
/**
* os_invoke_main(M):
* Invoke the main method of the module M.
*/
private static boolean test_os_invoke_main(Object[] args) {
Class<?> clazz = (Class<?>)Machine.deref(Machine.exec_build(args[0]));
try {
Method method = clazz.getDeclaredMethod("main");
method.invoke(null);
} catch (NoSuchMethodException x) {
throw Machine.make_error(new Store.Compound("existence_error",
new Object[]{"method", "main"}));
} catch (IllegalAccessException x) {
throw Machine.make_error(new Store.Compound("permission_error",
new Object[]{"invoke", "method", "main"}));
} catch (InvocationTargetException x) {
Special.sneaky(x.getCause());
}
return true;
}
/*******************************************************************/
/* '$YIELD'/1, shield/1 and unshield/1 */
/*******************************************************************/
/**
* '$YIELD'(R): Internal only
* The built-in stops the interpreter loop with return value R.
*/
private static Object special_yield(Object[] args) {
if ((Machine.gc_flags & Machine.GC_MASK_ALLOW_YIELD) == 0)
throw Machine.make_error(new Store.Compound("system_error",
new Object[]{"illegal_yield"}));
Machine.cont(((Store.Compound) Machine.call).args[1]);
Machine.more(new Machine.Choice(Machine::solve_signal, null, 0, Machine.trail));
return Machine.deref(args[0]);
}
/**
* shield(G):
* The predicate succeeds whenever the goal G succeeds.
* The goal is executed without auto-yield.
*/
private static Object special_shield(Object[] args) {
Object goal = Machine.deref(args[0]);
Machine.Choice snap = Machine.snap_setup();
goal = new Store.Compound(".", new Object[]{goal, "[]"});
Machine.cont(goal);
return solve_shield(snap, 1, null);
}
/**
* Call, redo or resume a goal.
* The goal is executed without auto-yield.
*
* @param data The surrounding choice point.
* @param at The call or redo flag.
* @param choice The choice point for reuse or null.
* @return boolean True if goal succeeded, otherwise false.
*/
private static Object solve_shield(Object data, int at, Machine.Choice choice) {
if (choice != null) {
choice.mark = null;
choice.cont = "[]";
choice.tail = null;
}
Machine.Choice snap = (Machine.Choice) data;
Object found = (at != 0 ? Boolean.TRUE : Boolean.FALSE);
int back = Machine.gc_flags & Machine.GC_MASK_ASYNC_MODE;
Machine.set_gc_flags(Machine.gc_flags & ~Machine.GC_MASK_ASYNC_MODE);
try {
found = Machine.solve(snap, found);
} catch (Throwable x) {
Machine.set_gc_flags((Machine.gc_flags & ~Machine.GC_MASK_ASYNC_MODE) | back);
Machine.snap_cleanup(snap);
throw x;
}
Machine.set_gc_flags((Machine.gc_flags & ~Machine.GC_MASK_ASYNC_MODE) | back);
if (found == Boolean.FALSE)
return Boolean.FALSE;
if (Machine.redo != snap) {
if (choice == null) {
choice = new Machine.Choice(Special::solve_shield, 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);
}
if (found == Boolean.TRUE)
Machine.cont(((Store.Compound) snap.cont).args[1]);
return found;
}
/**
* unshield(G):
* The predicate succeeds whenever the goal G succeeds.
* The goal is executed with auto-yield.
*/
private static Object special_unshield(Object[] args) {
Object goal = Machine.deref(args[0]);
Machine.Choice snap = Machine.snap_setup();
goal = new Store.Compound(".", new Object[]{goal, "[]"});
Machine.cont(goal);
return solve_unshield(snap, 1, null);
}
/**
* Call, redo or resume a goal.
* The goal is executed without auto-yield.
*
* @param data The surrounding choice point.
* @param at The call or redo flag.
* @param choice The choice point for reuse or null.
* @return boolean True if goal succeeded, otherwise false.
*/
private static Object solve_unshield(Object data, int at, Machine.Choice choice) {
if (choice != null) {
choice.mark = null;
choice.cont = "[]";
choice.tail = null;
}
Machine.Choice snap = (Machine.Choice) data;
Object found = (at != 0 ? Boolean.TRUE : Boolean.FALSE);
int back = Machine.gc_flags & Machine.GC_MASK_ASYNC_MODE;
Machine.set_gc_flags(Machine.gc_flags | Machine.GC_MASK_ASYNC_MODE);
try {
found = Machine.solve(snap, found);
} catch (Throwable x) {
Machine.set_gc_flags((Machine.gc_flags & ~Machine.GC_MASK_ASYNC_MODE) | back);
Machine.snap_cleanup(snap);
throw x;
}
Machine.set_gc_flags((Machine.gc_flags & ~Machine.GC_MASK_ASYNC_MODE) | back);
if (found == Boolean.FALSE)
return Boolean.FALSE;
if (Machine.redo != snap) {
if (choice == null) {
choice = new Machine.Choice(Special::solve_unshield, 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);
}
if (found == Boolean.TRUE)
Machine.cont(((Store.Compound) snap.cont).args[1]);
return found;
}
/*********************************************************************/
/* Type Assertions */
/*********************************************************************/
/**
* Assure that the object is an atom.
*
* @param beta The object.
*/
public static void check_atom(Object beta) {
if (!Machine.is_atom(beta)) {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"atom", beta}));
}
}
/**
* Assure that the object is a number.
*
* @param beta The object.
*/
public static void check_number(Object beta) {
if (!Machine.is_number(beta)) {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"number", beta}));
}
}
/**
* Assure that the object is an integer.
*
* @param beta The object.
*/
public static void check_integer(Object beta) {
if (!Machine.is_integer(beta)) {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"integer", beta}));
}
}
/**
* Assure that the object is atomic.
*
* @param beta The object.
*/
public static void check_atomic(Object beta) {
if (Store.is_variable(beta) || Store.is_compound(beta)) {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"atomic", beta}));
}
}
/**
* Assure that the Prolog term is nil.
*
* @param beta The Prolog term.
*/
public static void check_nil(Object beta) {
if (!"[]".equals(beta)) {
if (Store.is_compound(beta)
&& ".".equals(((Store.Compound) beta).functor)
&& ((Store.Compound) beta).args.length == 2) {
throw Machine.make_error(new Store.Compound("representation_error",
new Object[]{"int"}));
} else {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"list", beta}));
}
}
}
/**
* Assure that the object is a symbol.
*
* @param beta The object.
*/
public static void check_symbol(Object beta) {
if (Store.is_variable(beta) || Store.is_compound(beta) || Machine.is_number(beta)) {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"symbol", beta}));
}
}
/*********************************************************************/
/* =/2 and copy_term/2 */
/*********************************************************************/
/**
* S = T: [ISO 8.2.1]
* The built-in succeeds when the Prolog terms S and T unify,
* otherwise the built-in fails.
*/
private static boolean test_unify(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
return Machine.exec_unify(args[1], alpha);
}
/**
* copy_term(S, T): [ISO 8.5.4]
* The built-in succeeds in T with a copy of S.
*/
private static boolean test_copy_term(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
alpha = Machine.copy_term(alpha);
return Machine.exec_unify(args[1], alpha);
}
/******************************************************************/
/* =../2 and functor/3 */
/******************************************************************/
/**
* T =.. [F|L]: [ISO 8.5.3]
* If T is a variable, the built-in succeeds in T with the Prolog term
* from the functor F and arguments L. Otherwise the built-in succeeds in
* F and L with the functor and arguments of the Prolog term T.
*/
private static boolean test_univ(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
if (Store.is_variable(alpha)) {
Object beta = Machine.deref(Machine.exec_build(args[1]));
beta = special_univ_pack(beta);
return Machine.unify(alpha, beta);
} else {
alpha = special_univ_unpack(alpha);
return Machine.exec_unify(args[1], alpha);
}
}
private static Object special_univ_pack(Object beta) {
if (Store.is_compound(beta) &&
".".equals(((Store.Compound) beta).functor) &&
((Store.Compound) beta).args.length == 2) {
Object peek = Machine.deref(((Store.Compound) beta).args[1]);
Object[] args = list_objects(peek);
peek = Machine.deref(((Store.Compound) beta).args[0]);
if (args.length == 0) {
check_atomic(peek);
} else {
check_symbol(peek);
peek = new Store.Compound(peek, args);
}
return peek;
} else {
Machine.check_nonvar(beta);
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"list", beta}));
}
}
public static Object[] list_objects(Object obj) {
Object peek = obj;
int arity = 0;
while (Store.is_compound(peek) &&
".".equals(((Store.Compound) peek).functor) &&
((Store.Compound) peek).args.length == 2 &&
arity < Special.MAX_ARITY) {
arity++;
peek = Machine.deref(((Store.Compound) peek).args[1]);
}
Special.check_nil(peek);
if (arity == 0) {
return Machine.VOID_ARGS;
} else {
Object[] args = new Object[arity];
peek = obj;
arity = 0;
while (Store.is_compound(peek) &&
".".equals(((Store.Compound) peek).functor) &&
((Store.Compound) peek).args.length == 2) {
args[arity++] = Machine.deref(((Store.Compound) peek).args[0]);
peek = Machine.deref(((Store.Compound) peek).args[1]);
}
return args;
}
}
private static Object special_univ_unpack(Object alpha) {
Store.Compound res;
if (Store.is_compound(alpha)) {
res = new Store.Compound(".",
new Object[]{((Store.Compound) alpha).functor, Store.UNDEF_OBJ});
Store.Compound back = res;
Object[] args = ((Store.Compound) alpha).args;
for (int i = 0; i < args.length; i++) {
Store.Compound peek = new Store.Compound(".",
new Object[]{args[i], Store.UNDEF_OBJ});
back.args[1] = peek;
back = peek;
}
back.args[1] = "[]";
} else {
res = new Store.Compound(".",
new Object[]{alpha, "[]"});
}
return res;
}
/**
* functor(T, F, A): [ISO 8.5.1]
* If T is a variable, the built-in succeeds in T with a new Prolog term
* from the functor F and the arity A. Otherwise the built-in succeeds in
* F and L with the functor and arguments of the Prolog term T.
*/
private static boolean test_functor(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
if (Store.is_variable(alpha)) {
Object functor = Machine.deref(Machine.exec_build(args[1]));
Object beta = Machine.deref(Machine.exec_build(args[2]));
check_integer(beta);
if (ComputeCompare.integer_signum((Number) beta) < 0)
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"not_less_than_zero", beta}));
int arity = (!is_bigint(beta) ? ((Integer) beta).intValue() : -1);
if (arity == -1)
throw Machine.make_error(new Store.Compound("representation_error",
new Object[]{"max_arity"}));
Object res;
if (arity == 0) {
check_atomic(functor);
res = functor;
} else {
check_symbol(functor);
Object[] temp = new Object[arity];
for (int i = 0; i < arity; i++)
temp[i] = new Store.Variable();
res = new Store.Compound(functor, temp);
}
return Machine.unify(alpha, res);
} else {
Object functor;
Object arity;
if (Store.is_compound(alpha)) {
Store.Compound cmp = (Store.Compound) alpha;
functor = cmp.functor;
arity = Integer.valueOf(cmp.args.length);
} else {
functor = alpha;
arity = Integer.valueOf(0);
}
if (!Machine.exec_unify(args[1], functor))
return false;
return Machine.exec_unify(args[2], arity);
}
}
/******************************************************************/
/* arg/3 and change_arg/3 */
/******************************************************************/
/**
* arg(K, X, Y): [ISO 8.5.2]
* The predicate succeeds in Y with the K-th argument of X.
*/
private static boolean test_arg(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
check_integer(alpha);
Object beta = Machine.deref(Machine.exec_build(args[1]));
Machine.check_callable(beta);
int arity;
if (Store.is_compound(beta)) {
arity = ((Store.Compound) beta).args.length;
} else {
arity = 0;
}
int pos = (!is_bigint(beta) ? ((Integer) alpha).intValue() : 0);
if (pos < 1 || arity < pos)
return false;
beta = ((Store.Compound) beta).args[pos - 1];
return Machine.exec_unify(args[2], beta);
}
/**
* change_arg(K, X, Y):
* The predicate succeeds. As a side-effect the K-th argument of X is set to Y.
*/
private static boolean test_change_arg(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
check_integer(alpha);
Object beta = Machine.deref(Machine.exec_build(args[1]));
Machine.check_callable(beta);
Object gamma = Machine.deref(Machine.exec_build(args[2]));
int arity;
if (Store.is_compound(beta)) {
arity = ((Store.Compound) beta).args.length;
} else {
arity = 0;
}
int pos = (!is_bigint(beta) ? ((Integer) alpha).intValue() : 0);
if (pos < 1 || arity < pos)
return false;
beta = ((Store.Compound) beta).args[pos - 1];
check_var(beta);
link(gamma, (Store.Variable) beta);
return true;
}
/**
* Assure that the object is a var.
*
* @param beta The object.
*/
public static void check_var(Object beta) {
if (!Store.is_variable(beta)) {
beta = Machine.copy_term(beta);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"var", beta}));
}
}
private static void link(Object source, Store.Variable term) {
if (term.tail == null) {
term.instantiated = source;
if ((term.flags & Machine.VAR_MASK_STATE) ==
(Machine.gc_flags & Machine.VAR_MASK_STATE))
Machine.mark2_term(source);
} else {
Object beta = Machine.copy_term(term);
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"conductor", beta}));
}
}
/*****************************************************************/
/* ir_object_new/1, ir_object_current/3 and ir_object_set/3 */
/*****************************************************************/
/**
* ir_object_new(O):
* The predicate succeeds in O with a new Java object.
*/
private static boolean test_ir_object_new(Object[] args) {
HashMap<String, Object> res = new HashMap<>();
return Machine.exec_unify(args[0], res);
}
/**
* ir_object_current(O, K, V):
* The predicate succeeds in V with the value of the key K
* in the Java object O.
*/
private static boolean test_ir_object_current(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
Object key = Machine.deref(Machine.exec_build(args[1]));
Special.check_atom(key);
Object res = ((HashMap<String, Object>) obj).getOrDefault((String) key, Store.UNDEF_OBJ);
if (res == Store.UNDEF_OBJ)
return false;
return Machine.exec_unify(args[2], res);
}
/**
* ir_object_set(O, K, V):
* The predicate sets the value of the key K in the
* Java object O to V.
*/
private static boolean test_ir_object_set(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
Object key = Machine.deref(Machine.exec_build(args[1]));
Special.check_atom(key);
Object value = Machine.deref(Machine.exec_build(args[2]));
((HashMap<String, Object>) obj).put((String) key, value);
return true;
}
/**
* ir_object_keys(O, L):
* The predicate succeeds in L with the keys of
* the Java object O
*/
private static boolean test_ir_object_keys(Object[] args) {
Object obj = Machine.deref(Machine.exec_build(args[0]));
Object res = set_to_list(((HashMap<String, Object>) obj).keySet(), "[]");
return Machine.exec_unify(args[1], res);
}
/******************************************************************/
/* ground/1 and nonground/2 */
/******************************************************************/
/**
* ground(T): [TC2 8.3.10]
* The built-in succceeds if T is ground.
*/
private static boolean test_ground(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
alpha = first_variable(alpha);
return (alpha == null);
}
/**
* nonground(T, V):
* The built-in succeeds if T is non-ground and V is the first variable.
*/
private static boolean test_nonground(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
alpha = first_variable(alpha);
if (alpha == null)
return false;
return Machine.exec_unify(args[1], alpha);
}
/**
* Find the first variable of a Prolog term.
*
* @param alpha The Prolog term.
* @return The first variable or undefined.
*/
static Store.Variable first_variable(Object alpha) {
for (; ; ) {
alpha = Machine.deref(alpha);
if (Store.is_variable(alpha)) {
return (Store.Variable) alpha;
} else if (Store.is_compound(alpha)) {
Object[] peek = ((Store.Compound) alpha).args;
int i = 0;
for (; i < peek.length - 1; i++) {
Store.Variable res = first_variable(peek[i]);
if (res != null)
return res;
}
alpha = peek[i];
} else {
return null;
}
}
}
/******************************************************************/
/* term_variables/3 and term_singletons/2 */
/******************************************************************/
private static LinkedHashSet<Store.Variable> temp_set;
/**
* term_variables(T, L, E): [TC2 8.5.5]
* The built-in succeeds in L with a list with end E and
* with the variables of T as its list elements.
*/
private static boolean test_term_variables(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
Object beta = Machine.exec_build(args[1]);
Object gamma = Machine.deref(Machine.exec_build(args[2]));
temp_set = null;
term_variables2(alpha);
LinkedHashSet<Store.Variable> temp = temp_set;
temp_set = null;
alpha = set_to_list(temp, gamma);
return Machine.unify(beta, alpha);
}
private static void term_variables2(Object alpha2) {
for (; ; ) {
alpha2 = Machine.deref(alpha2);
if (Store.is_variable(alpha2)) {
Store.Variable peek = (Store.Variable) alpha2;
if (temp_set == null)
temp_set = new LinkedHashSet<>();
temp_set.add(peek);
break;
} else if (Store.is_compound(alpha2)) {
Object[] peek = ((Store.Compound) alpha2).args;
int i = 0;
for (; i < peek.length - 1; i++)
term_variables2(peek[i]);
alpha2 = peek[i];
} else {
break;
}
}
}
private static LinkedHashSet<Store.Variable> temp_anon;
/**
* term_singletons(T, L):
* The built-in succeeds in L with the singleton variables of T.
*/
private static boolean test_term_singletons(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
temp_set = null;
temp_anon = null;
term_singletons2(alpha);
LinkedHashSet<Store.Variable> temp = temp_anon;
temp_set = null;
temp_anon = null;
alpha = set_to_list(temp, "[]");
return Machine.exec_unify(args[1], alpha);
}
private static void term_singletons2(Object alpha2) {
for (; ; ) {
alpha2 = Machine.deref(alpha2);
if (Store.is_variable(alpha2)) {
Store.Variable peek = (Store.Variable) alpha2;
if (temp_set == null) {
temp_set = new LinkedHashSet<>();
temp_anon = new LinkedHashSet<>();
}
if (!temp_set.contains(peek)) {
temp_set.add(peek);
temp_anon.add(peek);
} else {
temp_anon.remove(peek);
}
break;
} else if (Store.is_compound(alpha2)) {
Object[] peek = ((Store.Compound) alpha2).args;
int i = 0;
for (; i < peek.length - 1; i++)
term_singletons2(peek[i]);
alpha2 = peek[i];
} else {
break;
}
}
}
/**
* Convert a native set into a Prolog list.
*
* @param temp The native set.
* @param end The list end.
*/
private static Object set_to_list(Collection<?> temp, Object end) {
Store.Compound back = null;
Object res = null;
if (temp != null) {
Iterator<?> it = temp.iterator();
while (it.hasNext()) {
Object value = it.next();
Store.Compound peek = new Store.Compound(".",
new Object[]{value, Store.UNDEF_OBJ});
if (back == null) {
res = peek;
} else {
back.args[1] = peek;
}
back = peek;
}
}
if (back == null) {
res = end;
} else {
back.args[1] = end;
}
return res;
}
/******************************************************************/
/* reference/1, \=/2 and acyclic_term/1 */
/******************************************************************/
/**
* reference(A):
* The built-in succeeds if A is a Prolog reference. Otherwise, it fails.
*/
private static boolean test_reference(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
if (Store.is_variable(alpha) || Store.is_compound(alpha))
return false;
if (Machine.is_atom(alpha) || Machine.is_number(alpha))
return false;
return true;
}
private static Handler.Rope<Store.Variable> temp_array;
/**
* acyclic_term(T): [TC2 8.3.11]
* The predicate succeeds when the Prolog term T is an acyclic term,
* i.e. contains no cycles.
*/
private static boolean test_acyclic(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
temp_array = null;
boolean res = is_acyclic2(alpha);
temp_array = null;
return res;
}
private static boolean is_acyclic2(Object alpha2) {
int undo = 0;
for (; ; ) {
if (Store.is_variable(alpha2)) {
Store.Variable peek = (Store.Variable) alpha2;
if (peek.instantiated != Store.UNDEF_OBJ) {
if (temp_array == null)
temp_array = new Handler.Rope<>();
if (temp_array.contains(peek))
return false;
temp_array.add(peek);
undo++;
alpha2 = peek.instantiated;
} else {
break;
}
} else if (Store.is_compound(alpha2)) {
Object[] peek = ((Store.Compound) alpha2).args;
int i = 0;
for (; i < peek.length - 1; i++)
if (!is_acyclic2(peek[i]))
return false;
alpha2 = peek[i];
} else {
break;
}
}
if (undo > 0)
temp_array.removeRange(temp_array.size() - undo, temp_array.size());
return true;
}
/******************************************************************/
/* callable/1, var/1, nonvar/1, compound/1, atomic/1 and atom/1 */
/******************************************************************/
/**
* callable(C): [TC2 8.3.9]
* The built-in succeeds if C is a Prolog compound or symbol. Otherwise, it fails.
*/
private static boolean test_callable(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
if (Store.is_variable(alpha) || Machine.is_number(alpha))
return false;
return true;
}
/**
* var(V): [ISO 8.3.1]
* The built-in succeeds if V is a Prolog variable. Otherwise, it fails.
*/
private static boolean test_var(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
return Store.is_variable(alpha);
}
/**
* nonvar(V): [ISO 8.3.7]
* The built-in succeeds if V is not a Prolog variable. Otherwise, it fails.
*/
private static boolean test_nonvar(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
return !Store.is_variable(alpha);
}
/**
* compound(C): [ISO 8.3.6]
* The built-in succeeds if V is a Prolog compound. Otherwise, it fails.
*/
private static boolean test_compound(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
return Store.is_compound(alpha);
}
/**
* atomic(A): [ISO 8.3.5]
* The built-in succeeds if A is a Prolog symbol or number. Otherwise, it fails.
*/
private static boolean test_atomic(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
if (Store.is_compound(alpha) || Store.is_variable(alpha))
return false;
return true;
}
/**
* atom(A): [ISO 8.3.2]
* The built-in succeeds if A is a Prolog atom. Otherwise, it fails.
*/
private static boolean test_atom(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
return Machine.is_atom(alpha);
}
/******************************************************************/
/* number/1, integer/1 and float/1 */
/******************************************************************/
/**
* number(A): [ISO 8.3.8]
* The built-in succeeds if A is a Prolog number. Otherwise, it fails.
*/
private static boolean test_number(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
return Machine.is_number(alpha);
}
/**
* integer(A): [ISO 8.3.3]
* The built-in succeeds if A is a Prolog integer. Otherwise, it fails.
*/
private static boolean test_integer(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
return Machine.is_integer(alpha);
}
/**
* float(A): [ISO 8.3.4]
* The built-in succeeds if A is a Prolog float. Otherwise, it fails.
*/
private static boolean test_float(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
return Machine.is_float(alpha);
}
/******************************************************************/
/* Number Utilities */
/******************************************************************/
/**
* Check whether an object is a bigint.
*
* @param alpha The object.
* @return boolean True if the object is a bignum, otherwise false.
*/
public static boolean is_bigint(Object alpha) {
return alpha instanceof BigInteger;
}
/******************************************************************/
/* code_type/2 and code_numeric/2 */
/******************************************************************/
/**
* code_type(C, T):
* The predicate succeeds in T with the Unicode general category of C.
* Otherwise, the predicate succeeds in T with 0.
*/
private static boolean test_code_type(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
check_integer(alpha);
int ch = (!is_bigint(alpha) ? ((Integer) alpha).intValue() : -1);
if (ch < 0 || ch > 0x10FFFF) {
ch = 0; // UNASSIGNED
} else {
ch = Character.getType(ch);
}
alpha = Integer.valueOf(ch);
return Machine.exec_unify(args[1], alpha);
}
/**
* code_numeric(C, V):
* The predicate succeeds in V with the Unicode numeric value of C,
* in case it is integer and between 0 and 35. Otherwise, the predicate
* succeeds in V with -1.
*/
private static boolean test_code_numeric(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
check_integer(alpha);
int ch = (!is_bigint(alpha) ? ((Integer) alpha).intValue() : -1);
if (ch < 0 || ch > 0x10FFFF) {
ch = -1; // UNASSIGNED
} else {
ch = Character.digit(ch, 36);
}
alpha = Integer.valueOf(ch);
return Machine.exec_unify(args[1], alpha);
}
/*********************************************************************/
/* atom_integer/3 */
/*********************************************************************/
/**
* atom_integer(A, R, N):
* If A is a variable, then the built-in succeeds in A with the
* atom for the Prolog integer N in radix R. Otherwise the
* built-in succeeds in N with the Prolog number from the
* atom A in radix R.
*/
private static boolean test_atom_integer(Object[] args) {
Object text = Machine.deref(Machine.exec_build(args[0]));
Object alpha = Machine.deref(Machine.exec_build(args[1]));
check_integer(alpha);
int radix = (!is_bigint(alpha) ? ((Integer) alpha).intValue() : 1);
if (radix < 2 || radix > 36)
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"radix", alpha}));
if (Store.is_variable(text)) {
Object beta = Machine.deref(Machine.exec_build(args[2]));
check_integer(beta);
beta = atom_integer_encode(beta, radix);
return Machine.unify(text, beta);
} else {
check_atom(text);
text = atom_integer_decode((String) text, radix);
return Machine.exec_unify(args[2], text);
}
}
/**
* Encode a Prolog integer to a string.
*
* @param num The Prolog integer.
* @param radix The radix.
* @return The string.
*/
private static String atom_integer_encode(Object num, int radix) {
String res;
if (is_bigint(num)) {
res = ((BigInteger) num).toString(radix);
} else {
res = Integer.toString(((Integer) num).intValue(), radix);
}
return res;
}
/**
* Decode a Prolog integer from a string.
*
* @param text The string
* @param radix The radix.
* @return The Prolog integer.
*/
private static Number atom_integer_decode(String text, int radix) {
try {
int step = 63 / (32 - Integer.numberOfLeadingZeros(radix - 1));
Number res;
if (text.length() <= step) {
long val = Long.parseLong(text, radix);
res = ComputeElem.norm_smallint(val);
} else {
BigInteger val = new BigInteger(text, radix);
res = ComputeElem.norm_bigint(val);
}
return res;
} catch (NumberFormatException x) {
throw Machine.make_error(new Store.Compound("syntax_error",
new Object[]{"illegal_number"}));
}
}
/******************************************************************/
/* atom_number/2 */
/******************************************************************/
/**
* atom_number(A, N):
* If A is a variable, then the built-in succeeds in A with the
* atom for the Prolog number N. Otherwise the built-in succeeds in N
* with the Prolog number from the atom A.
*/
private static boolean test_atom_number(Object[] args) {
Object text = Machine.deref(Machine.exec_build(args[0]));
if (Store.is_variable(text)) {
Object beta = Machine.deref(Machine.exec_build(args[1]));
check_number(beta);
beta = atom_number_encode(beta);
return Machine.unify(text, beta);
} else {
check_atom(text);
text = atom_number_decode((String) text);
return Machine.exec_unify(args[1], text);
}
}
/**
* Encode a Prolog number to a string.
*
* @param num The Prolog number.
* @return The string.
*/
private static String atom_number_encode(Object num) {
if (Machine.is_integer(num)) {
return num.toString();
} else {
String res = String.format(Locale.UK, "%.17g", (Double) num);
return shape_number(res);
}
}
/**
* Shape the number string so that it has always a period,
* no exponent positive sign and upper case exponent.
*
* @param res The ascii number string
* @return The shaped number string.
*/
public static String shape_number(String res) {
int peek = res.indexOf('e');
if (peek != -1) {
res = shape_number_mantissa(res.substring(0, peek)) +
"e" + shape_number_exponent(res.substring(peek + 1));
} else {
res = shape_number_mantissa(res);
}
return res;
}
private static String shape_number_mantissa(String res) {
if (res.indexOf('.') != -1) {
int pos = res.length();
while (res.charAt(pos - 1) == '0')
pos--;
if (res.charAt(pos - 1) == '.')
pos++;
if (pos != res.length())
res = res.substring(0, pos);
}
return res;
}
private static String shape_number_exponent(String res) {
if (0 < res.length() && res.charAt(0) == '+')
res = res.substring(1);
return res;
}
/**
* Decode a Prolog number from a string. Unlike the ISO
* core standard and numbers without a period but with
* an exponent are accepted as float.
*
* @param text The string
* @return The Prolog number.
*/
private static Number atom_number_decode(String text) {
try {
Number res;
if ((text.indexOf('.') != -1) ||
(text.indexOf('e') != -1) ||
(text.indexOf('E') != -1)) {
double val = Double.parseDouble(text);
res = ComputeElem.norm_float(val);
} else {
if (text.length() <= 18) {
long val = Long.parseLong(text);
res = ComputeElem.norm_smallint(val);
} else {
BigInteger val = new BigInteger(text);
res = ComputeElem.norm_bigint(val);
}
}
return res;
} catch (NumberFormatException x) {
throw Machine.make_error(new Store.Compound("syntax_error",
new Object[]{"illegal_number"}));
}
}
/******************************************************************/
/* atom_reference/2 */
/******************************************************************/
/**
* atom_reference(A, R):
* The built-in succeeds in A with the atom for the Prolog reference R.
*/
private static boolean test_atom_reference(Object[] args) {
Object text = Machine.deref(Machine.exec_build(args[0]));
if (Store.is_variable(text)) {
Object obj = Machine.deref(Machine.exec_build(args[1]));
if (obj == Boolean.TRUE) {
obj = "True";
} else if (obj == Boolean.FALSE) {
obj = "False";
} else if (obj == null) {
obj = "None";
} else {
obj = "Reference";
}
return Machine.unify(text, obj);
} else {
check_atom(text);
Object obj;
if ("True".equals(text)) {
obj = true;
} else if ("False".equals(text)) {
obj = false;
} else if ("None".equals(text)) {
obj = null;
} else {
obj = Store.UNDEF_OBJ;
}
if (obj == Store.UNDEF_OBJ)
throw Machine.make_error(new Store.Compound("syntax_error",
new Object[]{"illegal_reference"}));
return Machine.exec_unify(args[1], obj);
}
}
/******************************************************************/
/* Time Formatting */
/******************************************************************/
/**
* sys_get_locale(L):
* The built-in succeeds in L with the current locale
* of the JavaScript environment.
*/
private static boolean test_sys_get_locale(Object[] args) {
Locale loc = Locale.getDefault();
return Machine.exec_unify(args[0], loc.toString());
}
/**
* sys_time_atom(F, T, S): internal only
* If A is a variable, the built-in succeeds in A with the millisecond
* time T formatted by the pattern F. Otherwise the built-in succeeds
* in T with the millisecond time parsed from A by the pattern F.
*/
private static boolean test_sys_time_atom(Object[] args) {
Object text = Machine.deref(Machine.exec_build(args[0]));
check_atom(text);
Object tms = Machine.deref(Machine.exec_build(args[1]));
if (Store.is_variable(tms)) {
Object res = Machine.deref(Machine.exec_build(args[2]));
check_atom(res);
Date date = sys_time_parse((String) res, (String) text);
return Machine.unify(tms, ComputeElem.norm_smallint(date.getTime()));
} else {
check_integer(tms);
if (!ComputeCompare.is_long((Number) tms))
throw Machine.make_error(new Store.Compound("representation_error",
new Object[]{"long", tms}));
Date date = new Date(((Number) tms).longValue());
return Machine.exec_unify(args[2], sys_time_format((String) text, date));
}
}
/**
* <p>Parse a date time string.</p>
*
* @param res The date time as a string.
* @param pat The pattern.
* @return The date time.
*/
public static Date sys_time_parse(String res, String pat) {
int year = 1970; int month = 1; int day = 1;
int hour = 0; int minute = 0; int second = 0;
int j = 0;
for (int i = 0; i < pat.length(); i++) {
char ch = pat.charAt(i);
if (ch == '%') {
i++;
int k;
switch (pat.charAt(i)) {
case 'd':
k = scan_integer(res, j);
day = Integer.parseInt(res.substring(j, k));
j = k;
break;
case 'm':
k = scan_integer(res, j);
month = Integer.parseInt(res.substring(j, k));
j = k;
break;
case 'Y':
k = scan_integer(res, j);
year = Integer.parseInt(res.substring(j, k));
j = k;
break;
case 'H':
k = scan_integer(res, j);
hour = Integer.parseInt(res.substring(j, k));
j = k;
break;
case 'M':
k = scan_integer(res, j);
minute = Integer.parseInt(res.substring(j, k));
j = k;
break;
case 'S':
k = scan_integer(res, j);
second = Integer.parseInt(res.substring(j, k));
j = k;
break;
}
} else {
if (j < res.length() && res.charAt(j) == ch)
j++;
}
}
return new Date(year - 1900, month - 1, day, hour, minute, second);
}
/**
* <p>Scan integer.</p>
*
* @param res The text.
* @param j The old position.
* @return The new position.
*/
private static int scan_integer(String res, int j) {
while (j < res.length() && Character.isDigit(res.charAt(j)))
j++;
return j;
}
/**
* <p>Format a date time string.</p>
*
* @param pat The format pattern.
* @param date The date time.
* @return The date time as a string.
*/
public static String sys_time_format(String pat, Date date) {
StringBuilder buf = new StringBuilder();
int k = 0;
for (int i = 0; i < pat.length(); i++) {
char ch = pat.charAt(i);
if (ch == '%') {
buf.append(pat, k, i);
i++;
if (i < pat.length()) {
switch (pat.charAt(i)) {
case 'd':
append_padded(buf, date.getDate());
break;
case 'm':
append_padded(buf, date.getMonth() + 1);
break;
case 'Y':
buf.append(date.getYear() + 1900);
break;
case 'H':
append_padded(buf, date.getHours());
break;
case 'M':
append_padded(buf, date.getMinutes());
break;
case 'S':
append_padded(buf, date.getSeconds());
break;
}
k = i + 1;
} else {
k = i;
}
}
}
buf.append(pat, k, pat.length());
return buf.toString();
}
/**
* <p>Append an integer value zero padded.</p>
*
* @param buf The string builder.
* @param value The integer value.
*/
private static void append_padded(StringBuilder buf, int value) {
if (value < 10)
buf.append('0');
buf.append(value);
}
/**
* sys_get_args(L):
* The built-in succeeds in L with the current command
* line arguments of the JavaScript environment.
*/
private static boolean test_sys_get_args(Object[] args) {
Object res = "[]";
for (int i = main_args.length - 1; i >= 0; i--)
res = new Store.Compound(".", new Object[]{main_args[i], res});
return Machine.exec_unify(args[0], res);
}
/******************************************************************/
/* Special Init */
/******************************************************************/
public static void boot() {
// Albufeira compiler, control flow
Store.add("fail", 0, make_check(Special::test_fail));
Store.add("$CUT", 1, make_check(Special::test_cut));
Store.add("$MARK", 1, make_check(Special::test_mark));
Store.add("$SEQ", 2, make_special(Special::special_seq));
Store.add("$ALT", 1, make_special(Special::special_alt));
Store.add("sys_raise", 1, make_check(Special::test_sys_raise));
Store.add("sys_trap", 3, make_special(Special::special_sys_trap));
// Albufeira compiler, async flow
Store.add("os_sleep_promise", 2, make_check(Special::test_os_sleep_promise));
Store.add("os_import_promise", 3, make_check(Special::test_os_import_promise));
Store.add("os_invoke_main", 1, make_check(Special::test_os_invoke_main));
Store.add("$YIELD", 1, make_special(Special::special_yield));
Store.add("shield", 1, make_special(Special::special_shield));
Store.add("unshield", 1, make_special(Special::special_unshield));
// term specials
Store.add("=", 2, make_check(Special::test_unify));
Store.add("copy_term", 2, make_check(Special::test_copy_term));
Store.add("=..", 2, make_check(Special::test_univ));
Store.add("functor", 3, make_check(Special::test_functor));
Store.add("arg", 3, make_check(Special::test_arg));
Store.add("change_arg", 3, make_check(Special::test_change_arg));
// object specials
Store.add("ir_object_new", 1, Special.make_check(Special::test_ir_object_new));
Store.add("ir_object_current", 3, Special.make_check(Special::test_ir_object_current));
Store.add("ir_object_set", 3, Special.make_check(Special::test_ir_object_set));
Store.add("ir_object_keys", 2, Special.make_check(Special::test_ir_object_keys));
// variable specials
Store.add("ground", 1, make_check(Special::test_ground));
Store.add("nonground", 2, make_check(Special::test_nonground));
Store.add("term_variables", 3, make_check(Special::test_term_variables));
Store.add("term_singletons", 2, make_check(Special::test_term_singletons));
Store.add("reference", 1, make_check(Special::test_reference));
Store.add("acyclic_term", 1, make_check(Special::test_acyclic));
// type specials
Store.add("callable", 1, make_check(Special::test_callable));
Store.add("var", 1, make_check(Special::test_var));
Store.add("nonvar", 1, make_check(Special::test_nonvar));
Store.add("compound", 1, make_check(Special::test_compound));
Store.add("atomic", 1, make_check(Special::test_atomic));
Store.add("atom", 1, make_check(Special::test_atom));
Store.add("number", 1, make_check(Special::test_number));
Store.add("integer", 1, make_check(Special::test_integer));
Store.add("float", 1, make_check(Special::test_float));
// atom specials
Store.add("code_type", 2, make_check(Special::test_code_type));
Store.add("code_numeric", 2, make_check(Special::test_code_numeric));
Store.add("atom_integer", 3, make_check(Special::test_atom_integer));
Store.add("atom_number", 2, make_check(Special::test_atom_number));
Store.add("atom_reference", 2, make_check(Special::test_atom_reference));
// locale specials
Store.add("sys_get_locale", 1, make_check(Special::test_sys_get_locale));
Store.add("sys_time_atom", 3, make_check(Special::test_sys_time_atom));
Store.add("sys_get_args", 1, make_check(Special::test_sys_get_args));
}
}