Java "eval"

         
package nova;
import doglet.fastlib;
import java.math.*;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
/**
* 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.
*
* 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.
*
* 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.
*
* 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.
*
* Trademarks
* Jekejeke is a registered trademark of XLOG Technologies AG.
*/
public final class eval {
public static final BigInteger NEG_MIN_INTEGER = BigInteger.valueOf(-(long) Integer.MIN_VALUE);
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));
public static final Double DOUBLE_PINF = Double.valueOf(Double.POSITIVE_INFINITY);
public static final Double DOUBLE_NINF = Double.valueOf(Double.NEGATIVE_INFINITY);
public static final Double DOUBLE_NAN = Double.valueOf(Double.NaN);
public static final int NUM_INTEGER = 0;
public static final int NUM_BIG_INTEGER = 1;
public static final int NUM_DOUBLE = 2;
public static final int NUM_SPECIAL = 3;
/******************************************************************/
/* is/2, (-)/2, abs/2 and sign/2 */
/******************************************************************/
/**
* X is Y: [ISO 8.6.1]
* The predicate succeeds in X with the evaluation of Y.
*/
private static boolean test_eval(Object[] args) {
Number res = Machine.exec_eval(args[1]);
return Machine.exec_unify(args[0], res);
}
/**
* -(A, B): [ISO 9.1.7]
* The predicate succeeds in B with the negation of A.
* This implements NaN propagation IEEE 754-2019 §6.2.3.
*/
private static Number arit_neg(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
if (alpha instanceof Integer) {
int x = alpha.intValue();
if (x != Integer.MIN_VALUE) {
return Integer.valueOf(-x);
} else {
return NEG_MIN_INTEGER;
}
} else if (alpha instanceof BigInteger) {
return special.norm_bigint(((BigInteger) alpha).negate());
} else {
return Double.valueOf(-alpha.doubleValue());
}
}
/**
* 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]);
if (alpha instanceof Integer) {
int x = alpha.intValue();
if (x != Integer.MIN_VALUE) {
return Integer.valueOf(Math.abs(x));
} else {
return NEG_MIN_INTEGER;
}
} else if (alpha instanceof BigInteger) {
return special.norm_bigint(((BigInteger) alpha).abs());
} else {
return Double.valueOf(Math.abs(special.narrow_float(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]);
if (Machine.is_integer(alpha)) {
return Integer.valueOf(integer_signum(alpha));
} else {
return Double.valueOf(Math.signum(special.narrow_float(alpha)));
}
}
/*****************************************************************/
/* (+)/3, (-)/3, (*)/3, (/)/3, (//)/3 and (rem)/3. */
/*****************************************************************/
/**
* +(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 add(alpha, beta);
}
public static Number add(Number m, Number n) {
switch (Math.max(numType(m), numType(n))) {
case NUM_INTEGER:
return special.norm_smallint((long) m.intValue() + n.intValue());
case NUM_BIG_INTEGER:
return special.norm_bigint(special.widen_bigint(m).add(
special.widen_bigint(n)));
default:
return special.norm_float(special.narrow_float(m) +
special.narrow_float(n));
}
}
/**
* -(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 subtract(alpha, beta);
}
public static Number subtract(Number m, Number n) {
switch (Math.max(numType(m), numType(n))) {
case NUM_INTEGER:
return special.norm_smallint((long) m.intValue() - n.intValue());
case NUM_BIG_INTEGER:
return special.norm_bigint(special.widen_bigint(m).subtract(
special.widen_bigint(n)));
default:
return special.norm_float(special.narrow_float(m) -
special.narrow_float(n));
}
}
/**
* *(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]);
switch (Math.max(numType(alpha), numType(beta))) {
case NUM_INTEGER:
return special.norm_smallint((long) alpha.intValue() * beta.intValue());
case NUM_BIG_INTEGER:
return special.norm_bigint(special.widen_bigint(alpha).multiply(
special.widen_bigint(beta)));
default:
return special.norm_float(special.narrow_float(alpha) *
special.narrow_float(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]);
double d = special.narrow_float(beta);
if (d == 0.0)
throw Machine.make_error(new Store.Compound("evaluation_error",
new Object[]{"zero_divisor"}));
return special.norm_float(special.narrow_float(alpha) / d);
}
/**
* //(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);
if (alpha instanceof Integer && beta instanceof Integer) {
int u = beta.intValue();
if (u == 0)
throw Machine.make_error(new Store.Compound("evaluation_error",
new Object[]{"zero_divisor"}));
int v = alpha.intValue();
if (v == Integer.MIN_VALUE && u == -1) {
return NEG_MIN_INTEGER;
} else {
return Integer.valueOf(v / u);
}
} else {
BigInteger p = special.widen_bigint(beta);
if (p.signum() == 0)
throw Machine.make_error(new Store.Compound("evaluation_error",
new Object[]{"zero_divisor"}));
return special.norm_bigint(special.widen_bigint(alpha).divide(p));
}
}
/**
* 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);
if (alpha instanceof Integer && beta instanceof Integer) {
int u = beta.intValue();
if (u == 0)
throw Machine.make_error(new Store.Compound("evaluation_error",
new Object[]{"zero_divisor"}));
return Integer.valueOf(alpha.intValue() % u);
} else {
BigInteger p = special.widen_bigint(beta);
if (p.signum() == 0)
throw Machine.make_error(new Store.Compound("evaluation_error",
new Object[]{"zero_divisor"}));
return special.norm_bigint(special.widen_bigint(alpha).remainder(p));
}
}
/***************************************************************/
/* 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 Double.valueOf(special.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]);
switch (Math.max(numType(alpha), numType(beta))) {
case NUM_INTEGER:
int y = beta.intValue();
if (y < 0)
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"not_less_than_zero", beta}));
int x = alpha.intValue();
if (x != Integer.MIN_VALUE && bitlength(Math.abs(x)) * y < 63) {
return special.norm_smallint(intPow(x, y));
} else {
return special.norm_bigint(BigInteger.valueOf(x).pow(y));
}
case NUM_BIG_INTEGER:
if (beta instanceof BigInteger)
throw Machine.make_error(new Store.Compound("representation_error",
new Object[]{"int"}));
y = beta.intValue();
if (y < 0)
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"not_less_than_zero", beta}));
return special.norm_bigint(((BigInteger) alpha).pow(y));
default:
return special.norm_float(Math.pow(
special.narrow_float(alpha), special.narrow_float(beta)));
}
}
private static long intPow(long m, int n) {
long r = 1;
while (n != 0) {
if ((n & 1) != 0)
r *= m;
n >>= 1;
if (n != 0)
m *= m;
}
return r;
}
private static int bitlength(long m) {
return 64 - Long.numberOfLeadingZeros(m);
}
/**
* 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);
if (alpha instanceof Integer && beta instanceof Integer) {
int u = beta.intValue();
if (u == 0)
throw Machine.make_error(new Store.Compound("evaluation_error",
new Object[]{"zero_divisor"}));
int v = alpha.intValue();
if (v == Integer.MIN_VALUE && u == -1) {
return NEG_MIN_INTEGER;
} else {
return Integer.valueOf(Math.floorDiv(v, u));
}
} else {
BigInteger p = special.widen_bigint(beta);
if (p.signum() == 0)
throw Machine.make_error(new Store.Compound("evaluation_error",
new Object[]{"zero_divisor"}));
BigInteger val = bigDiv(special.widen_bigint(alpha), p);
return special.norm_bigint(val);
}
}
private static BigInteger bigDiv(BigInteger v, BigInteger u) {
BigInteger h;
if ((v.signum() < 0) != (u.signum() < 0)) {
BigInteger[] res = v.divideAndRemainder(u);
h = res[0];
if (res[1].signum() != 0)
h = h.subtract(BigInteger.ONE);
} else {
h = v.divide(u);
}
return h;
}
/**
* 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);
if (alpha instanceof Integer && beta instanceof Integer) {
int u = beta.intValue();
if (u == 0)
throw Machine.make_error(new Store.Compound("evaluation_error",
new Object[]{"zero_divisor"}));
return Integer.valueOf(Math.floorMod(alpha.intValue(), u));
} else {
BigInteger p = special.widen_bigint(beta);
if (p.signum() == 0)
throw Machine.make_error(new Store.Compound("evaluation_error",
new Object[]{"zero_divisor"}));
BigInteger val = bigMod(special.widen_bigint(alpha), p);
return special.norm_bigint(val);
}
}
private static BigInteger bigMod(BigInteger v, BigInteger u) {
BigInteger res = v.remainder(u);
if ((v.signum() < 0) != (u.signum() < 0)) {
if (res.signum() != 0)
res = res.add(u);
}
return res;
}
/****************************************************************/
/* min/3, max/3, inf/1 and nan/1 */
/****************************************************************/
public static int integer_signum(Number num) {
if (num instanceof Integer) {
return Integer.signum(num.intValue());
} else {
return ((BigInteger) num).signum();
}
}
/**
* min(A, B, C): [TC2 9.3.9]
* The predicate succeeds in C with the minimum of A and B.
* This implements minimumNumber IEEE 754-2019 §9.6.
*/
private static Number arit_min(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
switch (Math.max(numTypeWithInf(alpha), numTypeWithInf(beta))) {
case NUM_INTEGER:
case NUM_BIG_INTEGER:
if (integer_compare(alpha, beta) > 0)
return beta;
return alpha;
case NUM_DOUBLE:
double a = special.narrow_float(alpha);
double b = special.narrow_float(beta);
if (a > b) {
alpha = beta;
a = b;
}
return (alpha instanceof Double ? alpha : Double.valueOf(a));
default:
if (eval.DOUBLE_NAN.equals(alpha))
return beta;
if (eval.DOUBLE_NAN.equals(beta))
return alpha;
if (eval.DOUBLE_PINF.equals(alpha))
return beta;
if (eval.DOUBLE_PINF.equals(beta))
return alpha;
if (eval.DOUBLE_NINF.equals(alpha))
return alpha;
return beta;
}
}
/**
* max(A, B, C): [TC2 9.3.8]
* The predicate succeeds in C with the maximum of A and B.
* This implements maximumNumber IEEE 754-2019 §9.6.
*/
private static Number arit_max(Object[] args) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
switch (Math.max(numTypeWithInf(alpha), numTypeWithInf(beta))) {
case NUM_INTEGER:
case NUM_BIG_INTEGER:
if (integer_compare(alpha, beta) < 0)
return beta;
return alpha;
case NUM_DOUBLE:
double a = special.narrow_float(alpha);
double b = special.narrow_float(beta);
if (a < b) {
alpha = beta;
a = b;
}
return (alpha instanceof Double ? alpha : Double.valueOf(a));
default:
if (eval.DOUBLE_NAN.equals(alpha))
return beta;
if (eval.DOUBLE_NAN.equals(beta))
return alpha;
if (eval.DOUBLE_NINF.equals(alpha))
return beta;
if (eval.DOUBLE_NINF.equals(beta))
return alpha;
if (eval.DOUBLE_PINF.equals(alpha))
return alpha;
return beta;
}
}
/**
* inf(A):
* The predicate succeeds in A with positive infinity.
*/
private static Number arit_inf(Object[] args) {
return DOUBLE_PINF;
}
/**
* nan(A):
* The predicate succeeds in A with not a number.
*/
private static Number arit_nan(Object[] args) {
return DOUBLE_NAN;
}
/******************************************************************/
/* truncate/2, floor/2, ceiling/2 and round/2 */
/******************************************************************/
private static final long MIN_SAFE_LONG = -9007199254740991L;
private static final long MAX_SAFE_LONG = 9007199254740991L;
/**
* 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]);
if (Machine.is_integer(alpha)) {
return alpha;
} else {
double d = special.narrow_float(alpha);
if (MIN_SAFE_LONG <= d && d <= MAX_SAFE_LONG) {
return special.norm_smallint((long) d);
} else {
return toInteger(d);
}
}
}
/**
* 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]);
if (Machine.is_integer(alpha)) {
return alpha;
} else {
return toInteger(Math.floor(special.narrow_float(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]);
if (Machine.is_integer(alpha)) {
return alpha;
} else {
return toInteger(Math.ceil(special.narrow_float(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]);
if (Machine.is_integer(alpha)) {
return alpha;
} else {
double d = special.narrow_float(alpha);
if (MIN_SAFE_LONG <= d && d <= MAX_SAFE_LONG) {
return special.norm_smallint(Math.round(d));
} else {
return toInteger(d);
}
}
}
private static Number toInteger(double d) {
if (Long.MIN_VALUE <= d && d <= Long.MAX_VALUE) {
return special.norm_smallint((long) d);
} else {
int y = Math.getExponent(d) - 52;
long x = (long)Math.scalb(d, -y);
return BigInteger.valueOf(x).shiftLeft(y);
}
}
/*********************************************************************/
/* =:=/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) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return number_equal(alpha, beta);
}
/**
* 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) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return !number_equal(alpha, beta);
}
/**
* Check whether two Prolog numbers are equal.
* This implement compareQuietEqual IEEE 754-2019 §5.6.1.
*
* @param alpha The first Prolog number.
* @param beta The second Prolog number.
* @return True if they are equal, false otherwise.
*/
private static boolean number_equal(Number alpha, Number beta) {
switch (Math.max(numTypeWithInf(alpha), numTypeWithInf(beta))) {
case NUM_INTEGER:
case NUM_BIG_INTEGER:
return alpha.equals(beta);
case NUM_DOUBLE:
return special.narrow_float(alpha)
== special.narrow_float(beta);
default:
if (eval.DOUBLE_NAN.equals(alpha))
return false;
if (eval.DOUBLE_NAN.equals(beta))
return false;
return alpha.equals(beta);
}
}
/**
* 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) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return number_less(alpha, beta);
}
/**
* 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) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return number_lessequal(beta, alpha);
}
/**
* 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) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return number_less(beta, alpha);
}
/**
* 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) {
Number alpha = Machine.exec_eval(args[0]);
Number beta = Machine.exec_eval(args[1]);
return number_lessequal(alpha, beta);
}
/**
* Determine whether a Prolog numbers is less than a Prolog number.
* This implement compareQuietLess IEEE 754-2019 §5.6.1.
*
* @param alpha The first Prolog number.
* @param beta The second Prolog number.
* @return True if the first is less than the second, otherwise false.
*/
private static boolean number_less(Number alpha, Number beta) {
switch (Math.max(numTypeWithInf(alpha), numTypeWithInf(beta))) {
case NUM_INTEGER:
case NUM_BIG_INTEGER:
return integer_compare(alpha, beta) < 0;
case NUM_DOUBLE:
return Double.compare(special.narrow_float(alpha),
special.narrow_float(beta)) < 0;
default:
if (eval.DOUBLE_NAN.equals(alpha))
return false;
if (eval.DOUBLE_NAN.equals(beta))
return false;
if (alpha.equals(beta))
return false;
if (eval.DOUBLE_PINF.equals(beta))
return true;
return eval.DOUBLE_NINF.equals(alpha);
}
}
/**
* Determine whether a Prolog numbers is less or equal than a Prolog number.
* This implement compareQuietLessEqual IEEE 754-2019 §5.6.1.
*
* @param alpha The first Prolog number.
* @param beta The second Prolog number.
* @return True if the first is less or equal than the second, otherwise false.
*/
private static boolean number_lessequal(Number alpha, Number beta) {
switch (Math.max(numTypeWithInf(alpha), numTypeWithInf(beta))) {
case NUM_INTEGER:
case NUM_BIG_INTEGER:
return integer_compare(alpha, beta) <= 0;
case NUM_DOUBLE:
return Double.compare(special.narrow_float(alpha),
special.narrow_float(beta)) <= 0;
default:
if (eval.DOUBLE_NAN.equals(alpha))
return false;
if (eval.DOUBLE_NAN.equals(beta))
return false;
if (alpha.equals(beta))
return true;
if (eval.DOUBLE_PINF.equals(beta))
return true;
return eval.DOUBLE_NINF.equals(alpha);
}
}
private static int numType(Number m) {
if (m instanceof Integer) {
return NUM_INTEGER;
} else if (m instanceof BigInteger) {
return NUM_BIG_INTEGER;
} else {
return NUM_DOUBLE;
}
}
private static int numTypeWithInf(Number m) {
if (m instanceof Integer) {
return NUM_INTEGER;
} else if (m instanceof BigInteger) {
return NUM_BIG_INTEGER;
} else if (!Machine.is_special(m)) {
return NUM_DOUBLE;
} else {
return NUM_SPECIAL;
}
}
public static int integer_compare(Number alfa, Number beta) {
if (alfa instanceof Integer) {
if (beta instanceof Integer) {
return ((Integer) alfa).compareTo((Integer) beta);
} else {
return -((BigInteger) beta).signum();
}
} else {
if (beta instanceof Integer) {
return ((BigInteger) alfa).signum();
} else {
return ((BigInteger) alfa).compareTo((BigInteger) beta);
}
}
}
/******************************************************************/
/* 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 special.norm_float(Math.sin(
special.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 special.norm_float(Math.cos(
special.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 special.norm_float(Math.tan(
special.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 special.norm_float(Math.asin(
special.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 special.norm_float(Math.acos(
special.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 special.norm_float(Math.atan(
special.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, e/1, epsilon/1 and atan2/3 */
/******************************************************************/
/**
* **(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 special.norm_float(Math.pow(
special.narrow_float(alpha),
special.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 special.norm_float(Math.exp(
special.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 special.norm_float(Math.log(
special.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 special.norm_float(Math.sqrt(
special.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 = special.narrow_float(alpha);
double x = special.narrow_float(beta);
if (y == 0.0 && x == 0.0) {
throw Machine.make_error(new Store.Compound("evaluation_error",
new Object[]{"undefined"}));
} else {
return special.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);
if (alpha instanceof Integer) {
return Integer.valueOf(~alpha.intValue());
} else {
return special.norm_bigint(((BigInteger) alpha).not());
}
}
/**
* /\(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);
if (alpha instanceof Integer && beta instanceof Integer) {
return Integer.valueOf(alpha.intValue() & beta.intValue());
} else {
BigInteger val = special.widen_bigint(alpha).and(
special.widen_bigint(beta));
return special.norm_bigint(val);
}
}
/**
* \/(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);
if (alpha instanceof Integer && beta instanceof Integer) {
return Integer.valueOf(alpha.intValue() | beta.intValue());
} else {
BigInteger val = special.widen_bigint(alpha).or(
special.widen_bigint(beta));
return special.norm_bigint(val);
}
}
/**
* 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);
if (alpha instanceof Integer && beta instanceof Integer) {
return Integer.valueOf(alpha.intValue() ^ beta.intValue());
} else {
BigInteger val = special.widen_bigint(alpha).xor(
special.widen_bigint(beta));
return special.norm_bigint(val);
}
}
/**
* >>(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);
if (alpha instanceof Integer && beta instanceof Integer) {
int y = beta.intValue();
if (y == 0) {
return alpha;
} else if (y > 0 && y <= 31) {
return Integer.valueOf(alpha.intValue() >> y);
} else if (y < 0 && -31 <= y) {
long val = (long) alpha.intValue() << (-y);
return special.norm_smallint(val);
} else {
return special.norm_bigint(BigInteger.valueOf(alpha.intValue()).shiftRight(y));
}
} else {
if (beta instanceof BigInteger)
throw Machine.make_error(new Store.Compound("representation_error",
new Object[]{"int"}));
int y = beta.intValue();
return special.norm_bigint(((BigInteger) alpha).shiftRight(y));
}
}
/**
* <<(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);
if (alpha instanceof Integer && beta instanceof Integer) {
int y = beta.intValue();
if (y == 0) {
return alpha;
} else if (y > 0 && y <= 31) {
long val = (long) alpha.intValue() << y;
return special.norm_smallint(val);
} else if (y < 0 && -31 <= y) {
return Integer.valueOf(alpha.intValue() >> (-y));
} else {
return special.norm_bigint(BigInteger.valueOf(alpha.intValue()).shiftLeft(y));
}
} else {
if (beta instanceof BigInteger)
throw Machine.make_error(new Store.Compound("representation_error",
new Object[]{"int"}));
int y = beta.intValue();
return special.norm_bigint(((BigInteger) alpha).shiftLeft(y));
}
}
/***************************************************************/
/* ==/2 and \==/2 */
/***************************************************************/
/**
* 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.
* Can handle cyclic terms and deep recursion.
*
* @param first The first Prolog term.
* @param second The second Prolog term.
* @return True if they are syntactically equivalent, otherwise false.
*/
public static boolean equal_term(Object first, Object second) {
List stack = null;
List log = null;
try {
for (; ; ) {
first = Store.deref(first);
second = Store.deref(second);
if (!Store.is_structure(first)) {
if (!Objects.equals(first, second))
break;
} else if (!Store.is_structure(second)) {
break;
} else if (((Store.Structure) first).args.length !=
((Store.Structure) second).args.length) {
break;
} else {
first = Machine.union_find((Store.Structure) first);
second = Machine.union_find((Store.Structure) second);
if (first != second) {
if (Machine.is_frozen(first) && Machine.is_frozen(second) &&
((Machine.Frozen)first).hash != ((Machine.Frozen)second).hash)
break;
if (!((Store.Structure) first).functor.equals(
((Store.Structure) second).functor))
break;
log = Machine.union_add(log, (Store.Structure) first,
(Store.Structure) second);
if (0 != ((Store.Structure) first).args.length - 1) {
Store.Item item2 = new Store.Item((Store.Structure)first, second, 0);
stack = Store.stack_push(stack, item2);
}
first = ((Store.Structure) first).args[0];
second = ((Store.Structure) second).args[0];
continue;
}
}
Store.Item item = (Store.Item)Store.stack_peek(stack);
if (item == null) {
return true;
} else {
item.idx++;
first = item.first.args[item.idx];
second = ((Store.Structure)item.second).args[item.idx];
if (item.idx == item.first.args.length - 1)
Store.stack_pop(stack);
}
}
return false;
} finally {
Machine.union_undo(log);
}
}
/******************************************************************/
/* Visitor Triple */
/******************************************************************/
public static class Triple {
public Object backup;
public Object accum;
public Object[] children;
/**
* Create a visitor triple.
*
* @param backup The backup functor.
* @param accum The accumlated value.
* @param children The argument children.
*/
public Triple(Object backup, Object accum, Object[] children) {
this.backup = backup;
this.accum = accum;
this.children = children;
}
}
/**
* Check whether an object is a visitor triple.
*
* @param obj The object.
* @return boolean True if the object is a triple, otherwise false.
*/
public static boolean is_triple(Object obj) {
return obj instanceof Triple;
}
/***************************************************************/
/* term_hash/2 */
/***************************************************************/
/**
* term_hash(X, H):
* The predicate succeeds in H with the term hash of the term X.
*/
private static boolean test_term_hash(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
Object res;
try {
res = walk_compute(alpha, eval::init_hash, eval::union_hash);
} finally {
walk_uncompute(alpha);
}
return Machine.exec_unify(args[1], res);
}
private static Integer init_hash(Object first) {
if (Store.is_compound(first)) {
return Integer.valueOf(Objects.hashCode(((Store.Structure) first).functor));
} else if (Store.is_variable(first)) {
return Integer.valueOf(Store.variable_serno((Store.Variable) first));
} else if (Machine.is_frozen(first)) {
return Integer.valueOf(((Machine.Frozen)first).hash);
} else {
return Integer.valueOf(Objects.hashCode(first));
}
}
private static Integer union_hash(Object alpha, Object beta) {
int first = ((Integer)alpha).intValue();
int second = ((Integer)beta).intValue();
return Integer.valueOf(first * 31 + second);
}
public static Object walk_compute(Object first, Function init, BiFunction reduce) {
List stack = null;
for (; ; ) {
first = Store.deref(first);
if (Store.is_compound(first)) {
if (!is_triple(((Store.Structure) first).functor)) {
((Store.Structure) first).functor = new Triple(
((Store.Structure) first).functor,
init.apply(first), null);
((Store.Compound) first).walk &= ~Store.VAR_MASK_SERNO;
stack = Store.stack_push(stack, first);
first = ((Store.Structure) first).args[0];
continue;
} else {
first = ((Triple) ((Store.Structure) first).functor).accum;
}
} else {
first = init.apply(first);
}
Store.Compound item = (Store.Compound) Store.stack_peek(stack);
while (item != null &&
(item.walk & Store.VAR_MASK_SERNO) == item.args.length - 1) {
first = reduce.apply(((Triple) item.functor).accum, first);
((Triple) item.functor).accum = first;
Store.stack_pop(stack);
item = (Store.Compound) Store.stack_peek(stack);
}
if (item == null) {
return first;
} else {
first = reduce.apply(((Triple) item.functor).accum, first);
((Triple) item.functor).accum = first;
item.walk++;
first = item.args[item.walk & Store.VAR_MASK_SERNO];
}
}
}
public static void walk_uncompute(Object first) {
List stack = null;
for (; ; ) {
first = Store.deref(first);
if (Store.is_compound(first)) {
if (is_triple(((Store.Structure) first).functor)) {
((Store.Structure) first).functor = ((Triple) ((Store.Structure) first).functor).backup;
if (0 != ((Store.Structure) first).args.length - 1) {
((Store.Compound) first).walk &= ~Store.VAR_MASK_SERNO;
stack = Store.stack_push(stack, first);
}
first = ((Store.Structure) first).args[0];
continue;
}
}
Store.Compound item = (Store.Compound) Store.stack_peek(stack);
if (item == null) {
return;
} else {
item.walk++;
first = item.args[item.walk & Store.VAR_MASK_SERNO];
if ((item.walk & Store.VAR_MASK_SERNO) == item.args.length - 1)
Store.stack_pop(stack);
}
}
}
/******************************************************************/
/* 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.exec_deref(args[0]);
if (Store.is_variable(text) || Machine.is_pending(text)) {
Object res = Machine.exec_build(args[1]);
res = atom_codes_pack(res);
return Machine.exec_unify(text, res);
} else {
text = Machine.exec_build(text);
special.check_atom(text);
text = atom_codes_unpack((String) text);
return Machine.exec_unify(args[1], text);
}
}
private static String atom_codes_pack(Object peek) {
int i = 0;
StringBuilder buf = new StringBuilder();
while (Store.is_structure(peek) &&
".".equals(((Store.Structure) peek).functor) &&
((Store.Structure) peek).args.length == 2 &&
i < special.MAX_ARITY) {
Object alpha = Store.deref(((Store.Structure) peek).args[0]);
special.check_integer(alpha);
int ch = (!Machine.is_bigint(alpha) ? ((Integer) alpha).intValue() : -1);
if (ch < 0 || ch > 0x10FFFF)
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"character_code", alpha}));
buf.appendCodePoint(ch);
i++;
peek = Store.deref(((Store.Structure) peek).args[1]);
}
special.check_nil(peek);
return buf.toString();
}
private static Object atom_codes_unpack(String text) {
Store.Structure back = null;
Object res = null;
int i = 0;
while (i < text.length()) {
int ch = text.codePointAt(i);
Store.Structure 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.exec_deref(args[0]);
if (Store.is_variable(text) || Machine.is_pending(text)) {
Object alpha = Machine.exec_build(args[1]);
special.check_integer(alpha);
int ch = (!Machine.is_bigint(alpha) ? ((Integer) alpha).intValue() : -1);
if (ch < 0 || ch > 0x10FFFF)
throw Machine.make_error(new Store.Compound("domain_error",
new Object[]{"character_code", alpha}));
if (Character.isBmpCodePoint(ch)) {
alpha = String.valueOf((char) ch);
} else {
alpha = new String(Character.toChars(ch));
}
return Machine.exec_unify(text, alpha);
} else {
text = Machine.exec_build(text);
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 and atom_join/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.exec_build(args[0]);
special.check_atom(text);
int res = ((String)text).codePointCount(0, ((String) text).length());
return Machine.exec_unify(args[1], Integer.valueOf(res));
}
/**
* atom_join(L, A):
* The built-in succeeds in A with the join of the atoms L.
*/
private static boolean test_atom_join(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
Object res = atom_join(alpha);
return Machine.exec_unify(args[1], res);
}
private static String atom_join(Object peek) {
StringBuilder buf = new StringBuilder();
int i = 0;
while (Store.is_structure(peek) &&
".".equals(((Store.Structure) peek).functor) &&
((Store.Structure) peek).args.length == 2 &&
i < special.MAX_ARITY) {
Object val = Store.deref(((Store.Structure) peek).args[0]);
special.check_atom(val);
buf.append((String) val);
peek = Store.deref(((Store.Structure) peek).args[1]);
i++;
}
special.check_nil(peek);
return buf.toString();
}
/******************************************************************/
/* 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 = Store.deref(args[0]);
Object second = Store.deref(args[1]);
Object third = Store.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, first + (String) second))
return Boolean.FALSE;
}
Machine.cont(((Store.Structure) Machine.call).args[1]);
return Boolean.TRUE;
}
private static Object solve_concat(Object rope, int at, Machine.Choice choice) {
Object goal = Store.deref(((Store.Structure) Machine.call).args[0]);
return solve2_concat(((Store.Structure) goal).args, rope, at, choice);
}
private static Object solve2_concat(Object[] args, Object rope, int at, Machine.Choice choice) {
String text = (String) Store.deref(args[2]);
Store.Variable mark = Machine.trail;
while (at <= text.length()) {
if (Machine.unify(args[0], text.substring(0, at))) {
if (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.Structure) 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 = Store.deref(args[0]);
special.check_atom(text);
Object part = Store.deref(args[1]);
special.check_atom(part);
Object alpha = Store.deref(args[2]);
if (Store.is_variable(alpha)) {
return solve2_match(args, Integer.valueOf(0), 0, null);
} else {
special.check_integer(alpha);
if (Machine.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.Structure) Machine.call).args[1]);
return Boolean.TRUE;
}
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;
}
private static Object solve_match(Object rope, int at, Machine.Choice choice) {
Object goal = Store.deref(((Store.Structure) Machine.call).args[0]);
return solve2_match(((Store.Structure) goal).args, rope, at, choice);
}
private static Object solve2_match(Object[] args, Object data, int at, Machine.Choice choice) {
String text = (String) Store.deref(args[0]);
String part = (String) Store.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 += text.codePointCount(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.Structure) Machine.call).args[1]);
return Boolean.TRUE;
}
Machine.unbind(mark);
at = atom_succ(text, at);
res++;
}
return Boolean.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 = Store.deref(args[0]);
special.check_atom(text);
Object alpha = Store.deref(args[1]);
if (Store.is_variable(alpha)) {
Object beta = Store.deref(args[2]);
special.check_integer(beta);
if (Machine.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 = Store.deref(args[2]);
special.check_integer(beta);
if (Machine.is_bigint(alpha))
return Boolean.FALSE;
int from = atom_offset((String) text, 0, ((Integer) alpha).intValue());
if (from < 0)
return Boolean.FALSE;
if (Machine.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.Structure) Machine.call).args[1]);
return Boolean.TRUE;
}
private static Object solve_part(Object rope, int at, Machine.Choice choice) {
Object goal = Store.deref(((Store.Structure) Machine.call).args[0]);
return solve2_part(((Store.Structure) goal).args, rope, at, choice);
}
private static Object solve2_part(Object[] args, Object data, int to, Machine.Choice choice) {
String text = (String) Store.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]))) {
if (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.Structure) 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 = Store.deref(args[0]);
special.check_atom(text);
Object part = Store.deref(args[1]);
special.check_atom(part);
Object alpha = Store.deref(args[2]);
if (Store.is_variable(alpha)) {
int at = ((String) text).length() - ((String) part).length();
if (at < 0)
return Boolean.FALSE;
int res = ((String) text).codePointCount(0, at);
return solve2_last_match(args, Integer.valueOf(res), at, null);
} else {
special.check_integer(alpha);
if (Machine.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.Structure) Machine.call).args[1]);
return Boolean.TRUE;
}
private static Object solve_last_match(Object rope, int at, Machine.Choice choice) {
Object goal = Store.deref(((Store.Structure) Machine.call).args[0]);
return solve2_last_match(((Store.Structure) goal).args, rope, at, choice);
}
public static Object solve2_last_match(Object[] args, Object data, int at, Machine.Choice choice) {
String text = (String) Store.deref(args[0]);
String part = (String) Store.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 Boolean.FALSE;
res -= text.codePointCount(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.Structure) Machine.call).args[1]);
return Boolean.TRUE;
}
Machine.unbind(mark);
at = atom_pred(text, at);
res--;
}
return Boolean.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 = Store.deref(args[0]);
special.check_atom(text);
Object alpha = Store.deref(args[1]);
if (Store.is_variable(alpha)) {
Object beta = Store.deref(args[2]);
special.check_integer(beta);
if (Machine.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 = ((String) text).codePointCount(0, pos);
return solve2_last_part(args, new int[]{pos, res},
((String) text).length(), null);
} else {
special.check_integer(alpha);
Object beta = Store.deref(args[2]);
special.check_integer(beta);
if (Machine.is_bigint(alpha))
return Boolean.FALSE;
int from = atom_offset((String) text, 0, ((Integer) alpha).intValue());
if (from < 0)
return Boolean.FALSE;
if (Machine.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.Structure) 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 = Store.deref(((Store.Structure) Machine.call).args[0]);
return solve2_last_part(((Store.Structure) goal).args, rope, at, choice);
}
public static Object solve2_last_part(Object[] args, Object data, int to, Machine.Choice choice) {
String text = (String) Store.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]))) {
if (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.Structure) 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.set("is", 2, special.make_check(eval::test_eval));
Store.set("-", 2, special.make_arithmetic(eval::arit_neg));
Store.set("abs", 2, special.make_arithmetic(eval::arit_abs));
Store.set("sign", 2, special.make_arithmetic(eval::arit_sign));
// number specials, basic operations
Store.set("+", 3, special.make_arithmetic(eval::arit_add));
Store.set("-", 3, special.make_arithmetic(eval::arit_sub));
Store.set("*", 3, special.make_arithmetic(eval::arit_mul));
Store.set("/", 3, special.make_arithmetic(eval::arit_quot));
Store.set("//", 3, special.make_arithmetic(eval::arit_intquot));
Store.set("rem", 3, special.make_arithmetic(eval::arit_rem));
// number specials, more operations
Store.set("float", 2, special.make_arithmetic(eval::arit_float));
Store.set("^", 3, special.make_arithmetic(eval::arit_intpow));
Store.set("div", 3, special.make_arithmetic(eval::arit_div));
Store.set("mod", 3, special.make_arithmetic(eval::arit_mod));
// number specials, magnitude operations
Store.set("min", 3, special.make_arithmetic(eval::arit_min));
Store.set("max", 3, special.make_arithmetic(eval::arit_max));
Store.set("inf", 1, special.make_arithmetic(eval::arit_inf));
Store.set("nan", 1, special.make_arithmetic(eval::arit_nan));
// number specials, rounding operations
Store.set("truncate", 2, special.make_arithmetic(eval::arit_truncate));
Store.set("floor", 2, special.make_arithmetic(eval::arit_floor));
Store.set("ceiling", 2, special.make_arithmetic(eval::arit_ceiling));
Store.set("round", 2, special.make_arithmetic(eval::arit_round));
// number specials, magnitude predicates
Store.set("=:=", 2, special.make_check(eval::test_numberequal));
Store.set("=\\=", 2, special.make_check(eval::test_numbernotequal));
Store.set("<", 2, special.make_check(eval::test_numberless));
Store.set(">=", 2, special.make_check(eval::test_numbergreaterequal));
Store.set(">", 2, special.make_check(eval::test_numbergreater));
Store.set("=<", 2, special.make_check(eval::test_numberlessequal));
// number specials, trigonometric operations
Store.set("sin", 2, special.make_arithmetic(eval::arit_sin));
Store.set("cos", 2, special.make_arithmetic(eval::arit_cos));
Store.set("tan", 2, special.make_arithmetic(eval::arit_tan));
Store.set("asin", 2, special.make_arithmetic(eval::arit_asin));
Store.set("acos", 2, special.make_arithmetic(eval::arit_acos));
Store.set("atan", 2, special.make_arithmetic(eval::arit_atan));
Store.set("pi", 1, special.make_arithmetic(eval::arit_pi));
// number specials, exponential operations
Store.set("**", 3, special.make_arithmetic(eval::arit_pow));
Store.set("exp", 2, special.make_arithmetic(eval::arit_exp));
Store.set("log", 2, special.make_arithmetic(eval::arit_log));
Store.set("sqrt", 2, special.make_arithmetic(eval::arit_sqrt));
Store.set("e", 1, special.make_arithmetic(eval::arit_e));
Store.set("epsilon", 1, special.make_arithmetic(eval::arit_epsilon));
Store.set("atan2", 3, special.make_arithmetic(eval::arit_atan2));
// number specials, bitwise operations
Store.set("\\", 2, special.make_arithmetic(eval::arit_not));
Store.set("/\\", 3, special.make_arithmetic(eval::arit_and));
Store.set("\\/", 3, special.make_arithmetic(eval::arit_or));
Store.set("xor", 3, special.make_arithmetic(eval::arit_xor));
Store.set(">>", 3, special.make_arithmetic(eval::arit_shiftright));
Store.set("<<", 3, special.make_arithmetic(eval::arit_shiftleft));
// term specials, miscellaneous equality
Store.set("==", 2, special.make_check(eval::test_equal));
Store.set("\\==", 2, special.make_check(eval::test_notequal));
Store.set("term_hash", 2, special.make_check(eval::test_term_hash));
// atom specials, deterministic
Store.set("atom_codes", 2, special.make_check(eval::test_atom_codes));
Store.set("char_code", 2, special.make_check(eval::test_char_code));
Store.set("atom_length", 2, special.make_check(eval::test_atom_length));
Store.set("atom_join", 2, special.make_check(eval::test_atom_join));
// atom specials, non-deterministic
Store.set("atom_concat", 3, special.make_special(eval::special_atom_concat));
Store.set("sys_atom_match", 3, special.make_special(eval::special_sys_atom_match));
Store.set("sys_atom_part", 4, special.make_special(eval::special_sys_atom_part));
Store.set("sys_last_atom_match", 3, special.make_special(eval::special_sys_last_atom_match));
Store.set("sys_last_atom_part", 4, special.make_special(eval::special_sys_last_atom_part));
}
}

Use Privacy (c) 2005-2026 XLOG Technologies AG