Java "Eval"

Admin User, created Apr 16. 2024
         
package nova;
import nova.envir.ComputeBits;
import nova.envir.ComputeCompare;
import nova.envir.ComputeElem;
import nova.envir.RangeException;
import java.util.Objects;
/**
* 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 Eval {
private static final Double DOUBLE_PI = Double.valueOf(Math.PI);
private static final Double DOUBLE_E = Double.valueOf(Math.E);
private static final Double DOUBLE_EPSILON = Double.valueOf(Math.ulp(1.0));
/******************************************************************/
/* Evaluable Predicates */
/******************************************************************/
private static boolean test_eval(Object[] args) {
try {
Number res = Machine.exec_eval(args[0]);
return Machine.exec_unify(args[1], res);
} catch (RuntimeException x) {
throw mapRuntime(x);
}
}
/**
* <p>Attempt to map a runtime exception to Prolog exception</p>
*
* @param x The runtime exception.
* @return The Prolog exception or the original runtime exeption.
*/
public static RuntimeException mapRuntime(RuntimeException x) {
if (x instanceof ArithmeticException) {
return Machine.make_error(new Store.Compound("evaluation_error",
new Object[]{x.getMessage()}));
} else if (x instanceof RangeException) {
return Machine.make_error(new Store.Compound("domain_error",
new Object[]{x.getMessage(), ((RangeException) x).getCulprit()}));
} else {
return x;
}
}
/*****************************************************************/
/* (-)/2, (+)/3, (-)/3, (*)/3, (/)/3, (//)/3 and (rem)/3. */
/*****************************************************************/
/**
* -(A, B): [ISO 9.1.7]
* The predicate succeeds in B with the negation of A.
*/
private static Number arit_neg(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeElem.negate(alpha);
}
/**
* +(A, B, C): [ISO 9.1.7]
* The predicate succeeds in C with the sum of A and B.
*/
private static Number arit_add(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeElem.add(alpha, beta);
}
/**
* -(A, B, C):
* The predicate succeeds in C with A subtracted by B.
*/
private static Number arit_sub(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeElem.subtract(alpha, beta);
}
/**
* *(A, B, C): [ISO 9.1.7]
* The predicate succeeds in C with the product of A and B.
*/
private static Number arit_mul(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeElem.multiply(alpha, beta);
}
/**
* /(A, B, C): [ISO 9.1.7]
* The predicate succeeds in C with A float divided by B.
*/
private static Number arit_quot(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeElem.divide(alpha, beta);
}
/**
* //(A, B, C): [ISO 9.1.7]
* The predicate succeeds in C with A truncate divided by B.
*/
private static Number arit_intquot(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Special.check_integer(alpha);
Number beta = Machine.exec_eval(args[1]);
Special.check_integer(beta);
return ComputeElem.slashSlash(alpha, beta);
}
/**
* rem(A, B, C): [ISO 9.1.7]
* The predicate succeeds in C with A remainder B.
*/
private static Number arit_rem(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Special.check_integer(alpha);
Number beta = Machine.exec_eval(args[1]);
Special.check_integer(beta);
return ComputeElem.rem(alpha, beta);
}
/***************************************************************/
/* float/1, (^)/3, div/3 and mod/3. */
/***************************************************************/
/**
* float(A, B): [ISO 9.17]
* The predicate succeeds in B with the approximated A.
*/
private static Number arit_float(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return alpha instanceof Double ? alpha :
Double.valueOf(ComputeElem.narrow_float(alpha));
}
/**
* ^(A, B, C): [TC2 9.3.10]
* The predicate succeeds in C with A int power by B.
*/
private static Number arit_intpow(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeElem.intPow(alpha, beta);
}
/**
* div(A, B, C): [TC2 9.1.3]
* The predicate succeeds in C with A floor divided by B.
*/
private static Number arit_div(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Special.check_integer(alpha);
Number beta = Machine.exec_eval(args[1]);
Special.check_integer(beta);
return ComputeElem.div(alpha, beta);
}
/**
* mod(A, B, C): [ISO 9.1.7]
* The predicate succeeds in C with A modulus B.
*/
private static Number arit_mod(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Special.check_integer(alpha);
Number beta = Machine.exec_eval(args[1]);
Special.check_integer(beta);
return ComputeElem.mod(alpha, beta);
}
/****************************************************************/
/* abs/2, sign/2, min/3 and max/3 */
/****************************************************************/
/**
* abs(A, B): [ISO 9.1.7]
* The predicate succeeds in B with the absolute value of A.
*/
private static Number arit_abs(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeBits.abs(alpha);
}
/**
* sign(A, B): [ISO 9.1.4]
* The predicate succeeds in B with the sign of A.
*/
private static Number arit_sign(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeBits.signum(alpha);
}
/**
* min(A, B, C): [TC2 9.3.9]
* The predicate succeeds in C with the minimum of A and B.
*/
private static Number arit_min(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeCompare.min(alpha, beta);
}
/**
* max(A, B, C): [TC2 9.3.8]
* The predicate succeeds in C with the maximum of A and B.
*/
private static Number arit_max(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeCompare.max(alpha, beta);
}
/******************************************************************/
/* truncate/2, floor/2, ceiling/2 and round/2 */
/******************************************************************/
/**
* truncate(A, B): [ISO 9.1.7]
* The predicate succeeds in B with the truncate of A.
*/
private static Number arit_truncate(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeBits.truncate(alpha);
}
/**
* floor(A, B): [ISO 9.1.7]
* The predicate succeeds in B with the floor of A.
*/
private static Number arit_floor(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeBits.floor(alpha);
}
/**
* ceiling(A, B): [ISO 9.1.7]
* The predicate succeeds in B with the ceiling of A.
*/
private static Number arit_ceiling(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeBits.ceiling(alpha);
}
/**
* round(A, B): [ISO 9.1.7]
* The predicate succeeds in B with the rounding of A.
*/
private static Number arit_round(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeBits.round(alpha);
}
/*********************************************************************/
/* =:=/2, =\=/2, </2, >=/2, >/2 and =</2 */
/*********************************************************************/
/**
* X =:= Y: [ISO 8.7.1]
* The predicate succeeds when X number equals Y, otherwise fails.
*/
private static boolean test_numberequal(Object[] args) {
try {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeCompare.testEq(alpha, beta);
} catch (RuntimeException x) {
throw mapRuntime(x);
}
}
/**
* X =\= Y: [ISO 8.7.1]
* The predicate succeeds when X does not number equal Y, otherwise fails.
*/
private static boolean test_numbernotequal(Object[] args) {
try {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return !ComputeCompare.testEq(alpha, beta);
} catch (RuntimeException x) {
throw mapRuntime(x);
}
}
/**
* X < Y: [ISO 8.7.1]
* The predicate succeeds when X is number less than Y, otherwise fails.
*/
private static boolean test_numberless(Object[] args) {
try {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeCompare.computeCmp(alpha, beta) < 0;
} catch (RuntimeException x) {
throw mapRuntime(x);
}
}
/**
* X >= Y: [ISO 8.7.1]
* The predicate succeeds when X is number greater or equal to Y, otherwise fails.
*/
private static boolean test_numbergreaterequal(Object[] args) {
try {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeCompare.computeCmp(alpha, beta) >= 0;
} catch (RuntimeException x) {
throw mapRuntime(x);
}
}
/**
* X > Y: [ISO 8.7.1]
* The predicate succeeds when X is number greater than Y, otherwise fails.
*/
private static boolean test_numbergreater(Object[] args) {
try {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeCompare.computeCmp(alpha, beta) > 0;
} catch (RuntimeException x) {
throw mapRuntime(x);
}
}
/**
* X =< Y: [ISO 8.7.1]
* The predicate succeeds when X is number less or equal to Y, otherwise fails.
*/
private static boolean test_numberlessequal(Object[] args) {
try {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeCompare.computeCmp(alpha, beta) <= 0;
} catch (RuntimeException x) {
throw mapRuntime(x);
}
}
/******************************************************************/
/* sin/3, cos/2, tan/2, asin/2, acos/2, atan/2 and pi/1. */
/******************************************************************/
/**
* sin(A, B): [ISO 9.3.2]
* The predicate succeeds in B with the sine of A.
*/
private static Number arit_sin(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeElem.norm_float(Math.sin(
ComputeElem.narrow_float(alpha)));
}
/**
* cos(A, B): [ISO 9.3.3]
* The predicate succeeds in B with the cosine of A.
*/
private static Number arit_cos(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeElem.norm_float(Math.cos(
ComputeElem.narrow_float(alpha)));
}
/**
* tan(A, B): [TC2 9.3.14]
* The predicate succeeds in B with the tangent of A.
*/
private static Number arit_tan(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeElem.norm_float(Math.tan(
ComputeElem.narrow_float(alpha)));
}
/**
* asin(A, B): [TC2 9.3.11]
* The predicate succeeds in B with the arcus sine of A.
*/
private static Number arit_asin(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeElem.norm_float(Math.asin(
ComputeElem.narrow_float(alpha)));
}
/**
* acos(A, B): [TC2 9.3.12]
* The predicate succeeds in B with the arcus cosine of A.
*/
private static Number arit_acos(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeElem.norm_float(Math.acos(
ComputeElem.narrow_float(alpha)));
}
/**
* atan(A, B): [ISO 9.3.4]
* The predicate succeeds in B with the arcus tangent of A.
*/
private static Number arit_atan(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeElem.norm_float(Math.atan(
ComputeElem.narrow_float(alpha)));
}
/**
* pi(A): [TC2 9.3.15]
* The predicate succeeds in A with π.
*/
private static Number arit_pi(Object[] args) {
return DOUBLE_PI;
}
/******************************************************************/
/* (**)/3, exp/2, log/2, sqrt/2 and e/1 */
/******************************************************************/
/**
* **(A, B, C): [ISO 9.3.1]
* The predicate succeeds in C with A float power by B.
*/
private static Number arit_pow(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return ComputeElem.norm_float(Math.pow(
ComputeElem.narrow_float(alpha),
ComputeElem.narrow_float(beta)));
}
/**
* exp(A, B): [ISO 9.3.5]
* The predicate succeeds in B with e power by A.
*/
private static Number arit_exp(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeElem.norm_float(Math.exp(
ComputeElem.narrow_float(alpha)));
}
/**
* log(A, B): [ISO 9.3.6]
* The predicate succeeds in B with the natural logarithm of A.
*/
private static Number arit_log(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeElem.norm_float(Math.log(
ComputeElem.narrow_float(alpha)));
}
/**
* sqrt(A, B): [ISO 9.3.7]
* The predicate succeeds in B with the square root of A.
*/
private static Number arit_sqrt(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
return ComputeElem.norm_float(Math.sqrt(
ComputeElem.narrow_float(alpha)));
}
/**
* e(A): [N208 9.7.2]
* The predicate succeeds in A with the Euler number.
*/
private static Number arit_e(Object[] args) {
return DOUBLE_E;
}
/**
* epsilon(A): [N208 9.7.3]
* The predicate succeeds in A with the machine epsilon.
*/
private static Number arit_epsilon(Object[] args) {
return DOUBLE_EPSILON;
}
/**
* atan2(A, B, C): [TC2 9.3.13]
* The predicate succeeds in C with the arc tangent of A and B.
*/
private static Number arit_atan2(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
double y = ComputeElem.narrow_float(alpha);
double x = ComputeElem.narrow_float(beta);
if (y == 0 && x == 0) {
throw new ArithmeticException("undefined");
} else {
return ComputeElem.norm_float(Math.atan2(y, x));
}
}
/*********************************************************************/
/* (\)/2, (/\)/3, (\/)/3, (xor)/3, (>>)/3 and (<</3) */
/*********************************************************************/
/**
* \(A, B): [ISO 9.4.5]
* The predicate succeeds in B with the bitwise not of A.
*/
private static Number arit_not(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Special.check_integer(alpha);
return ComputeBits.not(alpha);
}
/**
* /\(A, B, C): [ISO 9.4.3]
* The predicate succeeds in C with the bitwise and of A and B.
*/
private static Number arit_and(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Special.check_integer(alpha);
Number beta = Machine.exec_eval(args[1]);
Special.check_integer(beta);
return ComputeBits.and(alpha, beta);
}
/**
* \/(A, B, C): [ISO 9.4.4]
* The predicate succeeds in C with the bitwise or of A and B.
*/
private static Number arit_or(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Special.check_integer(alpha);
Number beta = Machine.exec_eval(args[1]);
Special.check_integer(beta);
return ComputeBits.or(alpha, beta);
}
/**
* xor(A, B, C): [TC2 9.4.6]
* The predicate succeeds in C with the bitwise xor of A and B.
*/
private static Number arit_xor(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Special.check_integer(alpha);
Number beta = Machine.exec_eval(args[1]);
Special.check_integer(beta);
return ComputeBits.xor(alpha, beta);
}
/**
* >>(A, B, C): [ISO 9.4.1]
* The predicate succeeds in C with A shift right by B.
*/
private static Number arit_shiftright(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Special.check_integer(alpha);
Number beta = Machine.exec_eval(args[1]);
Special.check_integer(beta);
return ComputeBits.shiftRight(alpha, beta);
}
/**
* <<(A, B, C): [ISO 9.4.2]
* The predicate succeeds in C with A shift left by B.
*/
private static Number arit_shiftleft(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Special.check_integer(alpha);
Number beta = Machine.exec_eval(args[1]);
Special.check_integer(beta);
return ComputeBits.shiftLeft(alpha, beta);
}
/***************************************************************/
/* ==/2, \==/2, @<, @=<, @>, @>= and compare/3 */
/***************************************************************/
/**
* S == T: [ISO 8.4.1]
* The built-in succeeds when S and T are syntactically equivalent
* Prolog terms, otherwise the built-in fails.
*/
private static boolean test_equal(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
Object beta = Machine.exec_build(args[1]);
return equal_term(alpha, beta);
}
/**
* S \== T: [ISO 8.4.1]
* The built-in succeeds when S and T are not syntactically equivalent
* Prolog terms, otherwise the built-in fails.
*/
private static boolean test_notequal(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
Object beta = Machine.exec_build(args[1]);
return !equal_term(alpha, beta);
}
/**
* Determine whether two Prolog terms are syntactically equivalent.
* Tail recursive solution.
*
* @param first The first Prolog term.
* @param second The second Prolog term.
* @return boolean True if they are syntactically equivalent, otherwise false.
*/
private static boolean equal_term(Object first, Object second) {
for (; ; ) {
first = Machine.deref(first);
second = Machine.deref(second);
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 (!equal_term(t1[i], t2[i]))
return false;
}
first = t1[i];
second = t2[i];
}
}
/**
* X @< Y: [ISO 8.4.1]
* The predicate succeeds when X is syntactically less than Y, otherwise fails.
*/
private static boolean test_less(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
Object beta = Machine.exec_build(args[1]);
return compare_term(alpha, beta) < 0;
}
/**
* X @>= Y: [ISO 8.4.1]
* The predicate succeeds when X is syntactically greater or equal to Y, otherwise fails.
*/
private static boolean test_greaterequal(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
Object beta = Machine.exec_build(args[1]);
return compare_term(alpha, beta) >= 0;
}
/**
* X @> Y: [ISO 8.7.1]
* The predicate succeeds when X is syntactically greater than Y, otherwise fails.
*/
private static boolean test_greater(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
Object beta = Machine.exec_build(args[1]);
return compare_term(alpha, beta) > 0;
}
/**
* X @=< Y: [ISO 8.7.1]
* The predicate succeeds when X is syntactically less or equal to Y, otherwise fails.
*/
private static boolean test_lessequal(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
Object beta = Machine.exec_build(args[1]);
return compare_term(alpha, beta) <= 0;
}
private static boolean test_compare(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
Object beta = Machine.exec_build(args[1]);
Object gamma = Machine.exec_build(args[2]);
int k = compare_term(beta, gamma);
if (k < 0) {
beta = "<";
} else if (k == 0) {
beta = "=";
} else {
beta = ">";
}
return Machine.unify(alpha, beta);
}
/**
* Determine the syntactic relationship between two Prolog terms.
*
* @param first The first Prolog term.
* @param second The second Prolog term.
* @return number <0 for less, =0 for equal and >0 for greater
*/
private static int compare_term(Object first, Object second) {
for (; ; ) {
first = Machine.deref(first);
second = Machine.deref(second);
int i = compare_type(first);
int k = i - compare_type(second);
if (k != 0) return k;
switch (i) {
case 0:
return (((Store.Variable) first).flags & ~Machine.VAR_MASK_STATE) -
(((Store.Variable) second).flags & ~Machine.VAR_MASK_STATE);
case 1:
return ((Double) first).compareTo((Double) second);
case 2:
return ComputeCompare.integer_compare((Number) first, (Number) second);
case 3:
return Integer.compare(ComputeCompare.order_value(first),
ComputeCompare.order_value(second));
case 4:
return ((String) first).compareTo((String) second);
case 5:
Object[] t1 = ((Store.Compound) first).args;
Object[] t2 = ((Store.Compound) second).args;
k = t1.length - t2.length;
if (k != 0) return k;
k = ((String) ((Store.Compound) first).functor).compareTo(
(String) ((Store.Compound) second).functor);
if (k != 0) return k;
i = 0;
for (; i < t1.length - 1; i++) {
k = compare_term(t1[i], t2[i]);
if (k != 0) return k;
}
first = t1[i];
second = t2[i];
break;
default:
throw Machine.make_error(new Store.Compound(
"system_error", new Object[]{"unknown_type"}));
}
}
}
/**
* Determine the compare type of a Prolog term.
*
* @param first The Prolog term.
* @return number The compare type.
*/
private static int compare_type(Object first) {
if (Store.is_variable(first)) {
return 0;
} else if (Store.is_compound(first)) {
return 5;
} else if (Machine.is_atom(first)) {
return 4;
} else if (Machine.is_integer(first)) {
return 2;
} else if (Machine.is_float(first)) {
return 1;
} else {
return 3;
}
}
/******************************************************************/
/* atom_codes/2 and char_code/2 */
/******************************************************************/
/**
* atom_codes(A, L): [ISO 8.16.5]
* If A is a variable, the built-in succeeds in A with the atom
* for the Prolog list L. Otherwise the built-in succeeds in L
* with the Prolog list from the atom A.
*/
private static boolean test_atom_codes(Object[] args) {
Object text = Machine.deref(Machine.exec_build(args[0]));
if (Store.is_variable(text)) {
Object res = Machine.deref(Machine.exec_build(args[1]));
res = atom_codes_pack(res);
return Machine.unify(text, res);
} else {
Special.check_atom(text);
text = atom_codes_unpack((String) text);
return Machine.exec_unify(args[1], text);
}
}
public static String atom_codes_pack(Object temp) {
int i = 0;
StringBuilder buf = new StringBuilder();
while (Store.is_compound(temp) && ".".equals(((Store.Compound) temp).functor)
&& ((Store.Compound) temp).args.length == 2 && i < Special.MAX_ARITY) {
Object alpha = Machine.deref(((Store.Compound) temp).args[0]);
Special.check_integer(alpha);
if (Special.is_bigint(alpha))
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"code_point", alpha}));
int ch = ((Integer) alpha).intValue();
if (ch < 0 || ch > 0x10FFFF)
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"code_point", alpha}));
buf.appendCodePoint(ch);
i++;
temp = Machine.deref(((Store.Compound) temp).args[1]);
}
Special.check_nil(temp);
return buf.toString();
}
public static Object atom_codes_unpack(String text) {
Store.Compound back = null;
Object res = null;
int i = 0;
while (i < text.length()) {
int ch = text.codePointAt(i);
Store.Compound peek = new Store.Compound(".",
new Object[]{Integer.valueOf(ch), Store.UNDEF_OBJ});
if (back != null) {
back.args[1] = peek;
} else {
res = peek;
}
back = peek;
i += Character.charCount(ch);
}
if (back != null) {
back.args[1] = "[]";
} else {
res = "[]";
}
return res;
}
/**
* char_code(C, N): [ISO 8.16.6]
* If C is a variable, the built-in succeeds in C with the
* character for the code N. Otherwise the built-in succeeds
* in N with the code from character C.
*/
private static boolean test_char_code(Object[] args) {
Object text = Machine.deref(Machine.exec_build(args[0]));
if (Store.is_variable(text)) {
Object alpha = Machine.deref(Machine.exec_build(args[1]));
Special.check_integer(alpha);
int ch = (!Special.is_bigint(alpha) ? ((Integer) alpha).intValue() : -1);
if (ch < 0 || ch > 0x10FFFF)
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"code_point", alpha}));
if (Character.isBmpCodePoint(ch)) {
alpha = String.valueOf((char) ch);
} else {
alpha = new String(Character.toChars(ch));
}
return Machine.unify(text, alpha);
} else {
Special.check_atom(text);
int ch;
if (((String) text).length() == 0 ||
((String) text).length() != Character.charCount(ch = ((String) text).codePointAt(0)))
throw Machine.make_error(new Store.Compound("type_error",
new Object[]{"character", text}));
return Machine.exec_unify(args[1], Integer.valueOf(ch));
}
}
/******************************************************************/
/* atom_length/2 */
/******************************************************************/
/**
* atom_length(X, Y): [ISO 8.16.1]
* The predicate succeeds in Y with the length of the atom X.
*/
private static boolean test_atom_length(Object[] args) {
Object text = Machine.deref(Machine.exec_build(args[0]));
Special.check_atom(text);
int res = atom_count((String) text, 0, ((String) text).length());
return Machine.exec_unify(args[1], Integer.valueOf(res));
}
private static int atom_count(String text, int from, int to) {
int res = 0;
while (from < to) {
int ch = text.codePointAt(from);
from += Character.charCount(ch);
res++;
}
return res;
}
/******************************************************************/
/* atom_split/3 and atom_arg/3 */
/******************************************************************/
/**
* atom_split(A, D, L):
* The built-in succeeds when L is the split of the atom A by the delimiter D.
*/
private static boolean test_atom_split(Object[] args) {
Object text = Machine.deref(Machine.exec_build(args[0]));
Object dele = Machine.deref(Machine.exec_build(args[1]));
Special.check_atom(dele);
if (Store.is_variable(text)) {
Object res = Machine.deref(Machine.exec_build(args[2]));
Object val = atom_split_pack((String) dele, res);
return Machine.unify(text, val);
} else {
Special.check_atom(text);
text = atom_split_unpack((String) text, (String) dele);
return Machine.exec_unify(args[2], text);
}
}
private static String atom_split_pack(String dele, Object peek) {
StringBuilder buf = new StringBuilder();
int i = 0;
while (Store.is_compound(peek) && ".".equals(((Store.Compound) peek).functor)
&& ((Store.Compound) peek).args.length == 2 && i < Special.MAX_ARITY) {
Object val = Machine.deref(((Store.Compound) peek).args[0]);
Special.check_atom(val);
buf.append((String) val);
peek = Machine.deref(((Store.Compound) peek).args[1]);
if (!"[]".equals(peek))
buf.append(dele);
i++;
}
Special.check_nil(peek);
return buf.toString();
}
private static Object atom_split_unpack(String text, String dele) {
Object res = "[]";
int pos = text.length();
int found = (pos >= dele.length() ? text.lastIndexOf(dele, pos - dele.length()) : -1);
while (found != -1) {
Object val = text.substring(found + dele.length(), pos);
res = new Store.Compound(".", new Object[]{val, res});
pos = found;
found = (pos >= dele.length() ? text.lastIndexOf(dele, pos - dele.length()) : -1);
}
Object val = text.substring(0, pos);
res = new Store.Compound(".", new Object[]{val, res});
return res;
}
/**
* atom_arg(K, X, Y):
* The predicate succeeds in Y with the zero-based K-th code point of X.
*/
private static boolean test_atom_arg(Object[] args) {
Object alpha = Machine.deref(Machine.exec_build(args[0]));
Special.check_integer(alpha);
Object text = Machine.deref(Machine.exec_build(args[1]));
Special.check_atom(text);
int pos = (!Special.is_bigint(alpha) ? ((Integer) alpha).intValue() : -1);
pos = atom_offset((String) text, 0, pos);
if (pos < 0 || pos >= ((String) text).length())
return false;
return Machine.exec_unify(args[2], Integer.valueOf(((String) text).codePointAt(pos)));
}
private static int atom_offset(String text, int pos, int alpha) {
if (alpha < 0)
return -1;
while (alpha > 0 && pos < text.length()) {
int ch = text.codePointAt(pos);
pos += Character.charCount(ch);
alpha--;
}
if (alpha > 0)
return -1;
return pos;
}
/******************************************************************/
/* atom_concat/3 */
/******************************************************************/
/**
* atom_concat(X, Y, Z): [ISO 8.16.2]
* The built-in succeeds when Z is the concatenation of X and Y.
*/
private static Object special_atom_concat(Object[] args) {
Object first = Machine.deref(args[0]);
Object second = Machine.deref(args[1]);
Object third = Machine.deref(args[2]);
if (Store.is_variable(second)) {
if (Store.is_variable(first)) {
Special.check_atom(third);
return solve2_concat(args, null, 0, null);
} else {
Special.check_atom(first);
Special.check_atom(third);
if (!((String) third).startsWith((String) first))
return Boolean.FALSE;
if (!Machine.unify(second, ((String) third).substring(((String) first).length())))
return Boolean.FALSE;
}
} else if (Store.is_variable(first)) {
Special.check_atom(second);
Special.check_atom(third);
if (!((String) third).endsWith((String) second))
return Boolean.FALSE;
if (!Machine.unify(first, ((String) third).substring(0,
((String) third).length() - ((String) second).length())))
return Boolean.FALSE;
} else {
Special.check_atom(first);
Special.check_atom(second);
if (!Machine.unify(third, (String) first + (String) second))
return Boolean.FALSE;
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
private static Object solve_concat(Object rope, int at, Machine.Choice choice) {
Object goal = Machine.deref(((Store.Compound) Machine.call).args[0]);
return solve2_concat(((Store.Compound) goal).args, rope, at, choice);
}
private static Object solve2_concat(Object[] args, Object rope, int at, Machine.Choice choice) {
String text = (String) Machine.deref(args[2]);
Store.Variable mark = Machine.trail;
while (at <= text.length()) {
if (Machine.unify(args[0], text.substring(0, at)) &&
Machine.unify(args[1], text.substring(at))) {
at = atom_succ(text, at);
if (at <= text.length()) {
if (choice == null) {
choice = new Machine.Choice(Eval::solve_concat, null, at, mark);
} else {
choice.at = at;
}
Machine.more(choice);
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
Machine.unbind(mark);
at = atom_succ(text, at);
}
return Boolean.FALSE;
}
private static int atom_succ(String text, int at) {
if (at < text.length()) {
int ch = text.codePointAt(at);
return at + Character.charCount(ch);
} else {
return at + 1;
}
}
/******************************************************************/
/* sys_atom_match/3 and sys_atom_part/4 */
/******************************************************************/
/**
* sys_atom_match(X, Y, Z):
* The built-in succeeds if X has substring Y at Z.
*/
private static Object special_sys_atom_match(Object[] args) {
Object text = Machine.deref(args[0]);
Special.check_atom(text);
Object part = Machine.deref(args[1]);
Special.check_atom(part);
Object alpha = Machine.deref(args[2]);
if (Store.is_variable(alpha)) {
return solve2_match(args, Integer.valueOf(0), 0, null);
} else {
Special.check_integer(alpha);
if (Special.is_bigint(alpha))
return Boolean.FALSE;
int from = atom_offset((String) text, 0, ((Integer) alpha).intValue());
if (from < 0)
return Boolean.FALSE;
if (!((String) text).startsWith((String) part, from))
return Boolean.FALSE;
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
private static Object solve_match(Object rope, int at, Machine.Choice choice) {
Object goal = Machine.deref(((Store.Compound) Machine.call).args[0]);
return solve2_match(((Store.Compound) goal).args, rope, at, choice);
}
private static Object solve2_match(Object[] args, Object data, int at, Machine.Choice choice) {
String text = (String) Machine.deref(args[0]);
String part = (String) Machine.deref(args[1]);
int res = ((Integer) data).intValue();
Store.Variable mark = Machine.trail;
while (at + part.length() <= text.length()) {
int pos = text.indexOf(part, at);
if (pos < 0)
return Boolean.FALSE;
res += atom_count(text, at, pos);
at = pos;
if (Machine.unify(args[2], Integer.valueOf(res))) {
at = atom_succ(text, at);
res++;
if (at + part.length() <= text.length()) {
if (choice == null) {
choice = new Machine.Choice(Eval::solve_match, Integer.valueOf(res), at, mark);
} else {
choice.data = Integer.valueOf(res);
choice.at = at;
}
Machine.more(choice);
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return true;
}
Machine.unbind(mark);
at = atom_succ(text, at);
res++;
}
return false;
}
/**
* sys_atom_part(X, Y, Z, T):
* The built-in succeeds in T with the substring at
* offset Y and with length Z from X.
*/
private static Object special_sys_atom_part(Object[] args) {
Object text = Machine.deref(args[0]);
Special.check_atom(text);
Object alpha = Machine.deref(args[1]);
if (Store.is_variable(alpha)) {
Object beta = Machine.deref(args[2]);
Special.check_integer(beta);
if (Special.is_bigint(beta))
return Boolean.FALSE;
int pos = atom_offset((String) text, 0, ((Integer) beta).intValue());
if (pos < 0)
return Boolean.FALSE;
return solve2_part(args, new int[]{0, 0}, pos, null);
} else {
Special.check_integer(alpha);
Object beta = Machine.deref(args[2]);
Special.check_integer(beta);
if (Special.is_bigint(alpha))
return Boolean.FALSE;
int from = atom_offset((String) text, 0, ((Integer) alpha).intValue());
if (from < 0)
return Boolean.FALSE;
if (Special.is_bigint(beta))
return Boolean.FALSE;
int to = atom_offset((String) text, from, ((Integer) beta).intValue());
if (to < 0)
return Boolean.FALSE;
if (!Machine.unify(args[3],
((String) text).substring(from, to)))
return Boolean.FALSE;
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
private static Object solve_part(Object rope, int at, Machine.Choice choice) {
Object goal = Machine.deref(((Store.Compound) Machine.call).args[0]);
return solve2_part(((Store.Compound) goal).args, rope, at, choice);
}
private static Object solve2_part(Object[] args, Object data, int to, Machine.Choice choice) {
String text = (String) Machine.deref(args[0]);
int[] pair = (int[]) data;
Store.Variable mark = Machine.trail;
while (to <= text.length()) {
if (Machine.unify(args[1], Integer.valueOf(pair[1])) &&
Machine.unify(args[3], text.substring(pair[0], to))) {
pair[0] = atom_succ(text, pair[0]);
pair[1]++;
to = atom_succ(text, to);
if (to <= text.length()) {
if (choice == null) {
choice = new Machine.Choice(Eval::solve_part, pair, to, mark);
} else {
choice.at = to;
}
Machine.more(choice);
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
Machine.unbind(mark);
pair[0] = atom_succ(text, pair[0]);
pair[1]++;
to = atom_succ(text, to);
}
return Boolean.FALSE;
}
/******************************************************************/
/* sys_last_atom_match/3 and sys_last_atom_part/4 */
/******************************************************************/
/**
* sys_last_atom_match(X, Y, Z):
* The built-in succeeds if X has substring Y at Z.
*/
public static Object special_sys_last_atom_match(Object[] args) {
Object text = Machine.deref(args[0]);
Special.check_atom(text);
Object part = Machine.deref(args[1]);
Special.check_atom(part);
Object alpha = Machine.deref(args[2]);
if (Store.is_variable(alpha)) {
int at = ((String) text).length() - ((String) part).length();
int res = atom_count((String) text, 0, at);
return solve2_last_match(args, Integer.valueOf(res), at, null);
} else {
Special.check_integer(alpha);
if (Special.is_bigint(alpha))
return Boolean.FALSE;
int from = atom_offset((String) text, 0, ((Integer) alpha).intValue());
if (from < 0)
return Boolean.FALSE;
if (!((String) text).startsWith((String) part, from))
return Boolean.FALSE;
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
private static Object solve_last_match(Object rope, int at, Machine.Choice choice) {
Object goal = Machine.deref(((Store.Compound) Machine.call).args[0]);
return solve2_last_match(((Store.Compound) goal).args, rope, at, choice);
}
public static Object solve2_last_match(Object[] args, Object data, int at, Machine.Choice choice) {
String text = (String) Machine.deref(args[0]);
String part = (String) Machine.deref(args[1]);
int res = ((Integer) data).intValue();
Store.Variable mark = Machine.trail;
while (at >= 0) {
int pos = text.lastIndexOf(part, at);
if (pos < 0)
return false;
res -= atom_count(text, pos, at);
at = pos;
if (Machine.unify(args[2], Integer.valueOf(res))) {
at = atom_pred(text, at);
res--;
if (at >= 0) {
if (choice == null) {
choice = new Machine.Choice(Eval::solve_last_match, res, at, mark);
} else {
choice.data = res;
choice.at = at;
}
Machine.more(choice);
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return true;
}
Machine.unbind(mark);
at = atom_pred(text, at);
res--;
}
return false;
}
private static int atom_pred(String text, int at) {
if (0 < at) {
int ch = text.codePointBefore(at);
return at - Character.charCount(ch);
} else {
return at - 1;
}
}
/**
* sys_last_atom_part(X, Y, Z, T):
* The built-in succeeds in T with the substring at
* offset Y and with length Z from X.
*/
public static Object special_sys_last_atom_part(Object[] args) {
Object text = Machine.deref(args[0]);
Special.check_atom(text);
Object alpha = Machine.deref(args[1]);
if (Store.is_variable(alpha)) {
Object beta = Machine.deref(args[2]);
Special.check_integer(beta);
if (Special.is_bigint(beta))
return Boolean.FALSE;
int pos = last_atom_offset((String) text, ((String) text).length(),
((Integer) beta).intValue());
if (pos < 0)
return Boolean.FALSE;
int res = atom_count(((String) text), 0, pos);
return solve2_last_part(args, new int[]{pos, res},
((String) text).length(), null);
} else {
Special.check_integer(alpha);
Object beta = Machine.deref(args[2]);
Special.check_integer(beta);
if (Special.is_bigint(alpha))
return Boolean.FALSE;
int from = atom_offset((String) text, 0, ((Integer) alpha).intValue());
if (from < 0)
return Boolean.FALSE;
if (Special.is_bigint(beta))
return Boolean.FALSE;
int to = atom_offset((String) text, from, ((Integer) beta).intValue());
if (to < 0)
return Boolean.FALSE;
if (!Machine.unify(args[3],
((String) text).substring(from, to)))
return Boolean.FALSE;
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
private static int last_atom_offset(String text, int pos, int alpha) {
if (alpha < 0)
return -1;
while (alpha > 0 && 0 < pos) {
int ch = text.codePointBefore(pos);
pos -= Character.charCount(ch);
alpha--;
}
if (alpha > 0)
return -1;
return pos;
}
private static Object solve_last_part(Object rope, int at, Machine.Choice choice) {
Object goal = Machine.deref(((Store.Compound) Machine.call).args[0]);
return solve2_last_part(((Store.Compound) goal).args, rope, at, choice);
}
public static Object solve2_last_part(Object[] args, Object data, int to, Machine.Choice choice) {
String text = (String) Machine.deref(args[0]);
int[] pair = (int[]) data;
Store.Variable mark = Machine.trail;
while (pair[0] >= 0) {
if (Machine.unify(args[1], Integer.valueOf(pair[1])) &&
Machine.unify(args[3], text.substring(pair[0], to))) {
pair[0] = atom_pred(text, pair[0]);
pair[1]--;
to = atom_pred(text, to);
if (pair[0] >= 0) {
if (choice == null) {
choice = new Machine.Choice(Eval::solve_last_part, pair, to, mark);
} else {
choice.at = to;
}
Machine.more(choice);
}
Machine.cont(((Store.Compound) Machine.call).args[1]);
return Boolean.TRUE;
}
Machine.unbind(mark);
pair[0] = atom_pred(text, pair[0]);
pair[1]--;
to = atom_pred(text, to);
}
return Boolean.FALSE;
}
/*********************************************************************/
/* Eval Init */
/*********************************************************************/
public static void boot() {
// number specials, basic predicates
Store.add("$EVAL", 2, Special.make_check(Eval::test_eval));
// number specials, basic operations
Store.add("-", 2, Special.make_arithmetic(Eval::arit_neg));
Store.add("+", 3, Special.make_arithmetic(Eval::arit_add));
Store.add("-", 3, Special.make_arithmetic(Eval::arit_sub));
Store.add("*", 3, Special.make_arithmetic(Eval::arit_mul));
Store.add("/", 3, Special.make_arithmetic(Eval::arit_quot));
Store.add("//", 3, Special.make_arithmetic(Eval::arit_intquot));
Store.add("rem", 3, Special.make_arithmetic(Eval::arit_rem));
// number specials, more operations
Store.add("float", 2, Special.make_arithmetic(Eval::arit_float));
Store.add("^", 3, Special.make_arithmetic(Eval::arit_intpow));
Store.add("div", 3, Special.make_arithmetic(Eval::arit_div));
Store.add("mod", 3, Special.make_arithmetic(Eval::arit_mod));
// number specials, magnitude operations
Store.add("abs", 2, Special.make_arithmetic(Eval::arit_abs));
Store.add("sign", 2, Special.make_arithmetic(Eval::arit_sign));
Store.add("min", 3, Special.make_arithmetic(Eval::arit_min));
Store.add("max", 3, Special.make_arithmetic(Eval::arit_max));
// number specials, rounding operations
Store.add("truncate", 2, Special.make_arithmetic(Eval::arit_truncate));
Store.add("floor", 2, Special.make_arithmetic(Eval::arit_floor));
Store.add("ceiling", 2, Special.make_arithmetic(Eval::arit_ceiling));
Store.add("round", 2, Special.make_arithmetic(Eval::arit_round));
// number specials, magnitude predicates
Store.add("=:=", 2, Special.make_check(Eval::test_numberequal));
Store.add("=\\=", 2, Special.make_check(Eval::test_numbernotequal));
Store.add("<", 2, Special.make_check(Eval::test_numberless));
Store.add(">=", 2, Special.make_check(Eval::test_numbergreaterequal));
Store.add(">", 2, Special.make_check(Eval::test_numbergreater));
Store.add("=<", 2, Special.make_check(Eval::test_numberlessequal));
// number specials, trigonometric operations
Store.add("sin", 2, Special.make_arithmetic(Eval::arit_sin));
Store.add("cos", 2, Special.make_arithmetic(Eval::arit_cos));
Store.add("tan", 2, Special.make_arithmetic(Eval::arit_tan));
Store.add("asin", 2, Special.make_arithmetic(Eval::arit_asin));
Store.add("acos", 2, Special.make_arithmetic(Eval::arit_acos));
Store.add("atan", 2, Special.make_arithmetic(Eval::arit_atan));
Store.add("pi", 1, Special.make_arithmetic(Eval::arit_pi));
// number specials, exponential operations
Store.add("**", 3, Special.make_arithmetic(Eval::arit_pow));
Store.add("exp", 2, Special.make_arithmetic(Eval::arit_exp));
Store.add("log", 2, Special.make_arithmetic(Eval::arit_log));
Store.add("sqrt", 2, Special.make_arithmetic(Eval::arit_sqrt));
Store.add("e", 1, Special.make_arithmetic(Eval::arit_e));
Store.add("epsilon", 1, Special.make_arithmetic(Eval::arit_epsilon));
Store.add("atan2", 3, Special.make_arithmetic(Eval::arit_atan2));
// number specials, bitwise operations
Store.add("\\", 2, Special.make_arithmetic(Eval::arit_not));
Store.add("/\\", 3, Special.make_arithmetic(Eval::arit_and));
Store.add("\\/", 3, Special.make_arithmetic(Eval::arit_or));
Store.add("xor", 3, Special.make_arithmetic(Eval::arit_xor));
Store.add(">>", 3, Special.make_arithmetic(Eval::arit_shiftright));
Store.add("<<", 3, Special.make_arithmetic(Eval::arit_shiftleft));
// term specials, syntactic comparison
Store.add("==", 2, Special.make_check(Eval::test_equal));
Store.add("\\==", 2, Special.make_check(Eval::test_notequal));
Store.add("@<", 2, Special.make_check(Eval::test_less));
Store.add("@>=", 2, Special.make_check(Eval::test_greaterequal));
Store.add("@>", 2, Special.make_check(Eval::test_greater));
Store.add("@=<", 2, Special.make_check(Eval::test_lessequal));
Store.add("compare", 3, Special.make_check(Eval::test_compare));
// atom specials, deterministic
Store.add("atom_codes", 2, Special.make_check(Eval::test_atom_codes));
Store.add("char_code", 2, Special.make_check(Eval::test_char_code));
Store.add("atom_length", 2, Special.make_check(Eval::test_atom_length));
Store.add("atom_split", 3, Special.make_check(Eval::test_atom_split));
Store.add("atom_arg", 3, Special.make_check(Eval::test_atom_arg));
// atom specials, non-deterministic
Store.add("atom_concat", 3, Special.make_special(Eval::special_atom_concat));
Store.add("sys_atom_match", 3, Special.make_special(Eval::special_sys_atom_match));
Store.add("sys_atom_part", 4, Special.make_special(Eval::special_sys_atom_part));
Store.add("sys_last_atom_match", 3, Special.make_special(Eval::special_sys_last_atom_match));
Store.add("sys_last_atom_part", 4, Special.make_special(Eval::special_sys_last_atom_part));
}
}