/*
 * Copyright (C) 2020 Kestrel Institute (http://www.kestrel.edu)
 * License: A 3-clause BSD license. See the LICENSE file distributed with ACL2.
 * Author: Alessandro Coglio (coglio@kestrel.edu)
 */

package edu.kestrel.acl2.aij;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * Representation of ACL2 native functions in terms,
 * and implementation of these functions in Java.
 * These are functions that are natively implemented  in Java,
 * as opposed to the functions that are defined via terms
 * (see {@link Acl2DefinedFunction}).
 * <p>
 * These native functions include:
 * <ul>
 * <li>The ACL2 primitive functions,
 *     i.e. the ones listed in the {@code primitive} topic of the ACL2 manual.
 *     These functions do not have an {@code unnormalized-body} property,
 *     and thus they are not part of the defined functions
 *     (see {@link Acl2DefinedFunction}).</li>
 * <li>The ACL2 "pseudo-function" {@code or},
 *     described in {@link Acl2FunctionCall#eval(Acl2Value[])}.</li>
 * <li>The ACL2 built-in function {@code nonnegative-integer-quotient}.
 *     This function has an {@code unnormalized-body} property,
 *     but is implemented natively in Java for efficiency.
 *     Note that it is actually implemented by raw Lisp code in ACL2.</li>
 * <li>The ACL2 built-in function {@code string-append}.
 *     This function has an {@code unnormalized-body} property,
 *     which is an {@code mbe} whose {@code :exec} part
 *     calls the ACL2 built-in macro {@code concatenate},
 *     which is implemented by raw Lisp code.
 *     However, the ACL2 definition of {@code concatenate}
 *     expands to {@code string-append},
 *     causing an infinite loop in code generated by ATJ (which AIJ supports)
 *     when guards are assumed satisfied
 *     (i.e. when ATJ's {@code :guard} input is {@code t}),
 *     in which case ATJ would generate code
 *     from the {@code :exec} part of {@code string-append}.
 *     By implementing {@code string-append} natively,
 *     the infinite loop is avoided,
 *     and the implementation is more efficient anyhow.</li>
 * <li>The ACL2 built-in function {@code len}.
 *     This function has an {@code unnormalized-body} property,
 *     but is implemented natively in Java for efficiency.
 *     Note that it is actually implemented by raw Lisp code in ACL2.</li>
 * <li>The ACL2 built-in function {@code char}.
 *     This function has an {@code unnormalized-body} property,
 *     but is implemented natively in Java for efficiency.
 *     Note that it is actually implemented by raw Lisp code in ACL2.</li>
 * </ul>
 * More native functions could be added here in the future,
 * e.g. as optimized implementations of other ACL2 built-in functions.
 * <p>
 * These native functions are implemented in the {@code exec...} static methods,
 * which are public so that these implementations
 * are available to code external to AIJ:
 * in particular, they are called by
 * the Java code generated by ATJ in the shallow embedding approach;
 * in fact, this is the motivation for these methods being public.
 * The stated preconditions of these public methods must be satisfied
 * by the Java code generated by ATJ that calls them;
 * they are not checked by these public methods for efficiency,
 * since these methods may be called over and over again during the execution
 * of the shallowly embedded ACL2 code.
 * <p>
 * These public methods operate on ACL2 values
 * in the same way as the corresponding ACL2 functions.
 * The methods that take {@link Acl2Value} arguments
 * operate on all the ACL2 values, regardless of guards:
 * in other words, they run as if guard checking were off,
 * i.e. they run "in the logic", as the ACL2 documentation says sometimes.
 * Some of these methods have overloaded variants
 * that operate on narrower types and may return narrower results:
 * they are equivalent to the ones that operate on all ACL2 values,
 * but may be more efficient.
 * Some of these overloaded variants have stated preconditions that,
 * together with the narrower types, correspond exactly to the guards:
 * thus, these methods can be called when the guards are satisfied.
 * Some of these overloaded variants have argument types
 * that are strictly narrower than the types corresponding to the guards;
 * these are used when the arguments are statically known to have those types.
 * <p>
 * Each native function is represented by
 * a singleton instance of a direct subclass of this class.
 * Each such singleton instance calls the appropriate {@code exec...} method
 * in its {@link Acl2Function#apply(Acl2Value[])} method.
 * <p>
 * The direct subclasses that represent the native functions
 * are private nested classes of this class.
 * This way, only code in this class can create instances of those classes,
 * which it does just once per class, thus ensuring the singleton property.
 */
public abstract class Acl2NativeFunction extends Acl2NamedFunction {

    //////////////////////////////////////// private members:

    /**
     * Arity of this native function.
     * Invariant: non-negative.
     */
    private final int arity;

    /**
     * Constructs a native function with the given name and arity.
     *
     * @param name  Name of the native function.
     *              Invariant: not null.
     * @param arity Arity of the native function.
     *              Invariant: non-negative.
     */
    private Acl2NativeFunction(Acl2Symbol name, int arity) {
        super(name);
        this.arity = arity;
    }

    /**
     * All the native functions.
     * These are stored as the values of a map
     * that has the names of the native functions as keys.
     * The map is created in advance by the static initializer,
     * and the native functions are reused
     * by the {@link #getInstance(Acl2Symbol)} method;
     * In other words, the native functions are interned.
     * Invariant: not null, no null keys, no null values.
     */
    private static final Map<Acl2Symbol, Acl2NativeFunction> functions =
            new HashMap<>();

    static {
        functions.put(Acl2Symbol.CHARACTERP, new Characterp());
        functions.put(Acl2Symbol.STRINGP, new Stringp());
        functions.put(Acl2Symbol.SYMBOLP, new Symbolp());
        functions.put(Acl2Symbol.INTEGERP, new Integerp());
        functions.put(Acl2Symbol.RATIONALP, new Rationalp());
        functions.put(Acl2Symbol.COMPLEX_RATIONALP, new ComplexRationalp());
        functions.put(Acl2Symbol.ACL2_NUMBERP, new Acl2Numberp());
        functions.put(Acl2Symbol.CONSP, new Consp());
        functions.put(Acl2Symbol.CHAR_CODE, new CharCode());
        functions.put(Acl2Symbol.CODE_CHAR, new CodeChar());
        functions.put(Acl2Symbol.COERCE, new Coerce());
        functions.put(Acl2Symbol.INTERN_IN_PACKAGE_OF_SYMBOL,
                new InternInPackageOfSymbol());
        functions.put(Acl2Symbol.SYMBOL_PACKAGE_NAME, new SymbolPackageName());
        functions.put(Acl2Symbol.SYMBOL_NAME, new SymbolName());
        functions.put(Acl2Symbol.PKG_IMPORTS, new PkgImports());
        functions.put(Acl2Symbol.PKG_WITNESS, new PkgWitness());
        functions.put(Acl2Symbol.UNARY_MINUS, new UnaryMinus());
        functions.put(Acl2Symbol.UNARY_SLASH, new UnarySlash());
        functions.put(Acl2Symbol.BINARY_PLUS, new BinaryPlus());
        functions.put(Acl2Symbol.BINARY_STAR, new BinaryStar());
        functions.put(Acl2Symbol.LESS_THAN, new LessThan());
        functions.put(Acl2Symbol.COMPLEX, new Complex());
        functions.put(Acl2Symbol.REALPART, new RealPart());
        functions.put(Acl2Symbol.IMAGPART, new ImagPart());
        functions.put(Acl2Symbol.NUMERATOR, new Numerator());
        functions.put(Acl2Symbol.DENOMINATOR, new Denominator());
        functions.put(Acl2Symbol.CONS, new Cons());
        functions.put(Acl2Symbol.CAR, new Car());
        functions.put(Acl2Symbol.CDR, new Cdr());
        functions.put(Acl2Symbol.EQUAL, new Equal());
        functions.put(Acl2Symbol.BAD_ATOM_LESS_THAN_OR_EQUAL_TO,
                new BadAtomLessThanOrEqualTo());
        functions.put(Acl2Symbol.IF, new If());
        functions.put(Acl2Symbol.OR, new Or());
        functions.put(Acl2Symbol.NONNEGATIVE_INTEGER_QUOTIENT,
                new NonnegativeIntegerQuotient());
        functions.put(Acl2Symbol.STRING_APPEND, new StringAppend());
        functions.put(Acl2Symbol.LEN, new Len());
        functions.put(Acl2Symbol.CHAR, new Char());
    }

    /**
     * Representation of the {@code characterp} ACL2 primitive function.
     */
    private static final class Characterp extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Characterp() {
            super(Acl2Symbol.CHARACTERP, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execCharacterp(values[0]);
        }
    }

    /**
     * Representation of the {@code stringp} ACL2 primitive function.
     */
    private static final class Stringp extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Stringp() {
            super(Acl2Symbol.STRINGP, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execStringp(values[0]);
        }
    }

    /**
     * Representation of the {@code symbolp} ACL2 primitive function.
     */
    private static final class Symbolp extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Symbolp() {
            super(Acl2Symbol.SYMBOLP, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execSymbolp(values[0]);
        }
    }

    /**
     * Representation of the {@code integerp} ACL2 primitive function.
     */
    private static final class Integerp extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Integerp() {
            super(Acl2Symbol.INTEGERP, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execIntegerp(values[0]);
        }
    }

    /**
     * Representation of the {@code rationalp} ACL2 primitive function.
     */
    private static final class Rationalp extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Rationalp() {
            super(Acl2Symbol.RATIONALP, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execRationalp(values[0]);
        }
    }

    /**
     * Representation of the {@code complex-rationalp} ACL2 primitive function.
     */
    private static final class ComplexRationalp extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private ComplexRationalp() {
            super(Acl2Symbol.COMPLEX_RATIONALP, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execComplexRationalp(values[0]);
        }
    }

    /**
     * Representation of the {@code acl2-numberp} ACL2 primitive function.
     */
    private static final class Acl2Numberp extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Acl2Numberp() {
            super(Acl2Symbol.ACL2_NUMBERP, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execAcl2Numberp(values[0]);
        }
    }

    /**
     * Representation of the {@code consp} ACL2 primitive function.
     */
    private static final class Consp extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Consp() {
            super(Acl2Symbol.CONSP, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execConsp(values[0]);
        }
    }

    /**
     * Representation of the {@code char-code} ACL2 primitive function.
     */
    private static final class CharCode extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private CharCode() {
            super(Acl2Symbol.CHAR_CODE, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execCharCode(values[0]);
        }
    }

    /**
     * Representation of the {@code code-char} ACL2 primitive function.
     */
    private static final class CodeChar extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private CodeChar() {
            super(Acl2Symbol.CODE_CHAR, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execCodeChar(values[0]);
        }
    }

    /**
     * Representation of the {@code coerce} ACL2 primitive function.
     */
    private static final class Coerce extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Coerce() {
            super(Acl2Symbol.COERCE, 2);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execCoerce(values[0], values[1]);
        }
    }

    /**
     * Representation of
     * the {@code intern-in-package-of-symbol} ACL2 primitive function.
     */
    private static final class InternInPackageOfSymbol
            extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private InternInPackageOfSymbol() {
            super(Acl2Symbol.INTERN_IN_PACKAGE_OF_SYMBOL, 2);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execInternInPackageOfSymbol(values[0], values[1]);
        }
    }

    /**
     * Representation of
     * the {@code symbol-package-name} ACL2 primitive function.
     */
    private static final class SymbolPackageName extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private SymbolPackageName() {
            super(Acl2Symbol.SYMBOL_PACKAGE_NAME, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execSymbolPackageName(values[0]);
        }
    }

    /**
     * Representation of the {@code symbol-name} ACL2 primitive function.
     */
    private static final class SymbolName extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private SymbolName() {
            super(Acl2Symbol.SYMBOL_NAME, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execSymbolName(values[0]);
        }
    }

    /**
     * Representation of the {@code pkg-imports} ACL2 primitive function.
     */
    private static final class PkgImports extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private PkgImports() {
            super(Acl2Symbol.PKG_IMPORTS, 1);
        }

        /**
         * Applies this native function to the given values.
         * An exception is thrown if the string does not name a known package
         * (this includes the case in which
         * the string is not a valid package name).
         * This is in accordance with
         * the ACL2 manual page for {@code pkg-imports},
         * which says that evaluation fails in this case.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         * @throws Acl2UndefinedPackageException If the package name is invalid
         *                                       or the package is not defined.
         */
        @Override
        Acl2Value apply(Acl2Value[] values)
                throws Acl2UndefinedPackageException {
            return execPkgImports(values[0]);
        }
    }

    /**
     * Representation of the {@code pkg-witness} ACL2 primitive function.
     */
    private static final class PkgWitness extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private PkgWitness() {
            super(Acl2Symbol.PKG_WITNESS, 1);
        }

        /**
         * Applies this native function to the given values.
         * An exception is thrown if the string does not name a known package
         * (this includes the case in which
         * the string is not a valid package name).
         * This is in accordance with
         * the ACL2 manual page for {@code pkg-witness},
         * which says that evaluation fails in this case.
         *
         * @throws Acl2UndefinedPackageException If the package name is invalid
         *                                       or the package is not defined.
         */
        @Override
        Acl2Value apply(Acl2Value[] values)
                throws Acl2UndefinedPackageException {
            return execPkgWitness(values[0]);
        }
    }

    /**
     * Representation of the {@code unary--} ACL2 primitive function.
     */
    private static final class UnaryMinus extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private UnaryMinus() {
            super(Acl2Symbol.UNARY_MINUS, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execUnaryMinus(values[0]);
        }
    }

    /**
     * Representation of the {@code unary-/} ACL2 primitive function.
     */
    private static final class UnarySlash extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private UnarySlash() {
            super(Acl2Symbol.UNARY_SLASH, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execUnarySlash(values[0]);
        }
    }

    /**
     * Representation of the {@code binary-+} ACL2 primitive function.
     */
    private static final class BinaryPlus extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private BinaryPlus() {
            super(Acl2Symbol.BINARY_PLUS, 2);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execBinaryPlus(values[0], values[1]);
        }
    }

    /**
     * Representation of the {@code binary-*} ACL2 primitive function.
     */
    private static final class BinaryStar extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private BinaryStar() {
            super(Acl2Symbol.BINARY_STAR, 2);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execBinaryStar(values[0], values[1]);
        }
    }

    /**
     * Representation of the {@code <} ACL2 primitive function.
     */
    private static final class LessThan extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private LessThan() {
            super(Acl2Symbol.LESS_THAN, 2);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execLessThan(values[0], values[1]);
        }
    }

    /**
     * Representation of the {@code complex} ACL2 primitive function.
     */
    private static final class Complex extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Complex() {
            super(Acl2Symbol.COMPLEX, 2);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execComplex(values[0], values[1]);
        }
    }

    /**
     * Representation of the {@code realpart} ACL2 primitive function.
     */
    private static final class RealPart extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private RealPart() {
            super(Acl2Symbol.REALPART, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execRealPart(values[0]);
        }
    }

    /**
     * Representation of the {@code imagpart} ACL2 primitive function.
     */
    private static final class ImagPart extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private ImagPart() {
            super(Acl2Symbol.IMAGPART, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execImagPart(values[0]);
        }
    }

    /**
     * Representation of the {@code numerator} ACL2 primitive function.
     */
    private static final class Numerator extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Numerator() {
            super(Acl2Symbol.NUMERATOR, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execNumerator(values[0]);
        }
    }

    /**
     * Representation of the {@code denominator} ACL2 primitive function.
     */
    private static final class Denominator extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Denominator() {
            super(Acl2Symbol.DENOMINATOR, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execDenominator(values[0]);
        }
    }

    /**
     * Representation of the {@code cons} ACL2 primitive function.
     */
    private static final class Cons extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Cons() {
            super(Acl2Symbol.CONS, 2);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execCons(values[0], values[1]);
        }
    }

    /**
     * Representation of the {@code car} ACL2 primitive function.
     */
    private static final class Car extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Car() {
            super(Acl2Symbol.CAR, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execCar(values[0]);
        }
    }

    /**
     * Representation of the {@code cdr} ACL2 primitive function.
     */
    private static final class Cdr extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Cdr() {
            super(Acl2Symbol.CDR, 1);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execCdr(values[0]);
        }
    }

    /**
     * Representation of the {@code equal} ACL2 primitive function.
     */
    private static final class Equal extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Equal() {
            super(Acl2Symbol.EQUAL, 2);
        }

        /**
         * Applies this native function to the given values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execEqual(values[0], values[1]);
        }
    }

    /**
     * Representation of the {@code bad-atom<=} ACL2 primitive function.
     */
    private static final class BadAtomLessThanOrEqualTo
            extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private BadAtomLessThanOrEqualTo() {
            super(Acl2Symbol.BAD_ATOM_LESS_THAN_OR_EQUAL_TO, 2);
        }

        /**
         * Applies this native function to the given values.
         * The ACL2 manual does not really document this function,
         * but the release notes for Version 2.9.1 of ACL2 say that
         * this function returns {@code nil} on values that are not bad atoms.
         * This is confirmed by inspecting
         * the Common Lisp code that implements this function
         * in the source code of ACL2.
         * ACL2 values in AIJ are never bad atoms
         * because there is no way to construct them without modifying AIJ
         * (in particular, {@link Acl2Value} and its subclasses
         * cannot be subclassed outside the AIJ package);
         * thus, this native implementation always returns {@code nil}.
         * This application never fails.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execBadAtomLessThanOrEqualTo(values[0], values[1]);
        }
    }

    /**
     * Representation of the {@code if} ACL2 primitive function.
     */
    private static final class If extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private If() {
            super(Acl2Symbol.IF, 3);
        }

        /**
         * Applies this native function to the given ACL2 values.
         * This is normally not used during execution,
         * because {@code if} is evaluated non-strictly
         * (see {@link Acl2FunctionCall#eval(Acl2Value[])}.
         * However, if code external to AIJ calls
         * {@link Acl2NamedFunction#call(Acl2Value[])}
         * to evaluate a call of {@code if} on some argument values,
         * then we use this method below to return the result.
         * This application never fails.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execIf(values[0], values[1], values[2]);
        }

        /**
         * Checks if this function is the {@code if} ACL2 primitive function.
         * This overrides the default implementation in
         * {@link Acl2NativeFunction#isIf()}.
         *
         * @return {@code true}.
         */
        @Override
        boolean isIf() {
            return true;
        }
    }

    /**
     * Representation of the {@code or} ACL2 "pseudo-function".
     */
    private static final class Or extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Or() {
            super(Acl2Symbol.OR, 2);
        }

        /**
         * Applies this native function to the given ACL2 values.
         * This is normally not used during execution,
         * because {@code or} is evaluated non-strictly
         * (see {@link Acl2FunctionCall#eval(Acl2Value[])}.
         * However, if code external to AIJ calls
         * {@link Acl2NamedFunction#call(Acl2Value[])}
         * to evaluate a call of {@code or} on some argument values,
         * then we use this method below to return the result.
         * This application never fails.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            Acl2Value x = values[0];
            Acl2Value y = values[1];
            if (x.equals(Acl2Symbol.NIL))
                return y;
            else
                return x;
        }

        /**
         * Checks if this function is the {@code or} ACL2 "pseudo-function".
         * This overrides the default implementation in
         * {@link Acl2NativeFunction#isOr()}.
         *
         * @return {@code true}
         */
        @Override
        boolean isOr() {
            return true;
        }
    }

    /**
     * Representation of the {@code nonnegative-integer-quotient}
     * ACL2 built-in function.
     */
    private static final class NonnegativeIntegerQuotient
            extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private NonnegativeIntegerQuotient() {
            super(Acl2Symbol.NONNEGATIVE_INTEGER_QUOTIENT, 2);
        }

        /**
         * Applies this native function to the given ACL2 values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execNonnegativeIntegerQuotient(values[0], values[1]);
        }
    }

    /**
     * Representation of the {@code string-append}
     * ACL2 built-in function.
     */
    private static final class StringAppend extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private StringAppend() {
            super(Acl2Symbol.STRING_APPEND, 2);
        }

        /**
         * Applies this native function to the given ACL2 values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execStringAppend(values[0], values[1]);
        }
    }

    /**
     * Representation of the {@code len}
     * ACL2 built-in function.
     */
    private static final class Len extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Len() {
            super(Acl2Symbol.LEN, 1);
        }

        /**
         * Applies this native function to the given ACL2 values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execLen(values[0]);
        }
    }

    /**
     * Representation of the {@code char}
     * ACL2 built-in function.
     */
    private static final class Char extends Acl2NativeFunction {

        /**
         * Constructs this native function.
         */
        private Char() {
            super(Acl2Symbol.CHAR, 2);
        }

        /**
         * Applies this native function to the given ACL2 values.
         *
         * @param values The actual arguments to pass to the function.
         *               Invariant: not null, no null elements.
         * @return The result of the function on the given arguments.
         */
        @Override
        Acl2Value apply(Acl2Value[] values) {
            return execChar(values[0], values[1]);
        }
    }

    //////////////////////////////////////// package-private members:

    /**
     * Returns the number of parameters of this native function.
     */
    int getArity() {
        return arity;
    }

    /**
     * Checks if this native function is the {@code if} ACL2 primitive function.
     * This default implementation, which returns {@code false},
     * is overridden in {@link If}.
     *
     * @return {@code false}.
     */
    @Override
    boolean isIf() {
        return false;
    }

    /**
     * Checks if this native function is the {@code or} ACL2 "pseudo-function".
     * This default implementation, which returns {@code false},
     * is overridden in {@link Or}.
     *
     * @return {@code false}.
     */
    @Override
    boolean isOr() {
        return false;
    }

    /**
     * Returns the native function with the given name.
     * If the symbol argument names a native function,
     * the unique object that represents it is returned.
     * Otherwise, null is returned;
     * it is intentional not to return an error in this case,
     * see {@link Acl2NamedFunction#make(Acl2Symbol)}.
     *
     * @param name The name of the native function.
     *             Invariant: not null.
     * @return The native function,
     * or null if the argument does not name a native function.
     */
    static Acl2NativeFunction getInstance(Acl2Symbol name) {
        return functions.get(name);
    }

    //////////////////////////////////////// public members:

    /**
     * Defines this native function.
     * This always throws an exception,
     * because native functions cannot be defined.
     * This method is needed to implement its abstract counterpart
     * in {@link Acl2NamedFunction#define(Acl2Symbol[], Acl2Term)}.
     *
     * @param parameters The formal parameters of the function definition.
     * @param body       The body of the function definition.
     * @throws IllegalArgumentException Always.
     */
    @Override
    public void define(Acl2Symbol[] parameters, Acl2Term body) {
        throw new IllegalArgumentException
                ("Attempting to define the native function "
                        + this.getName() + ".");
    }

    /**
     * Executes the native implementation of
     * the {@code characterp} ACL2 primitive function.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Symbol execCharacterp(Acl2Value x) {
        return x.characterp();
    }

    /**
     * Executed the native implementation of
     * the {@code characterp} ACL2 primitive function,
     * returning a Java boolean instead of an ACL2 boolean.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static boolean execCharacterpBoolean(Acl2Value x) {
        return x.characterpBoolean();
    }

    /**
     * Executes the native implementation of
     * the {@code stringp} ACL2 primitive function.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Symbol execStringp(Acl2Value x) {
        return x.stringp();
    }

    /**
     * Executes the native implementation of
     * the {@code stringp} ACL2 primitive function,
     * returning a Java boolean instead of an ACL2 boolean.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static boolean execStringpBoolean(Acl2Value x) {
        return x.stringpBoolean();
    }

    /**
     * Executes the native implementation of
     * the {@code symbolp} ACL2 primitive function.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Symbol execSymbolp(Acl2Value x) {
        return x.symbolp();
    }

    /**
     * Executes the native implementation of
     * the {@code symbolp} ACL2 primitive function,
     * returning a Java boolean instead of an ACL2 boolean.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static boolean execSymbolpBoolean(Acl2Value x) {
        return x.symbolpBoolean();
    }

    /**
     * Executes the native implementation of
     * the {@code integerp} ACL2 primitive function.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Symbol execIntegerp(Acl2Value x) {
        return x.integerp();
    }

    /**
     * Executes the native implementation of
     * the {@code integerp} ACL2 primitive function,
     * returning a Java boolean instead of an ACL2 boolean.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static boolean execIntegerpBoolean(Acl2Value x) {
        return x.integerpBoolean();
    }

    /**
     * Executes the native implementation of
     * the {@code rationalp} ACL2 primitive function.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Symbol execRationalp(Acl2Value x) {
        return x.rationalp();
    }

    /**
     * Executes the native implementation of
     * the {@code rationalp} ACL2 primitive function,
     * returning a Java boolean instead of an ACL2 boolean.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static boolean execRationalpBoolean(Acl2Value x) {
        return x.rationalpBoolean();
    }

    /**
     * Executes the native implementation of
     * the {@code complex-rationalp} ACL2 primitive function.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Symbol execComplexRationalp(Acl2Value x) {
        return x.complexRationalp();
    }

    /**
     * Executes the native implementation of
     * the {@code complex-rationalp} ACL2 primitive function,
     * returning a Java boolean instead of an ACL2 boolean.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static boolean execComplexRationalpBoolean(Acl2Value x) {
        return x.complexRationalpBoolean();
    }

    /**
     * Executes the native implementation of
     * the {@code acl2-numberp} ACL2 primitive function.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Symbol execAcl2Numberp(Acl2Value x) {
        return x.acl2Numberp();
    }

    /**
     * Executes the native implementation of
     * the {@code acl2-numberp} ACL2 primitive function,
     * returning a Java boolean instead of an ACL2 boolean.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static boolean execAcl2NumberpBoolean(Acl2Value x) {
        return x.acl2NumberpBoolean();
    }

    /**
     * Executes the native implementation of
     * the {@code consp} ACL2 primitive function.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Symbol execConsp(Acl2Value x) {
        return x.consp();
    }

    /**
     * Executes the native implementation of
     * the {@code consp} ACL2 primitive function,
     * returning a Java boolean instead of an ACL2 boolean.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static boolean execConspBoolean(Acl2Value x) {
        return x.conspBoolean();
    }

    /**
     * Executes the native implementation of
     * the {@code char-code} ACL2 primitive function,
     * on any value.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Integer execCharCode(Acl2Value x) {
        return x.charCode();
    }

    /**
     * Executes the native implementation of
     * the {@code char-code} ACL2 primitive function,
     * on an ACL2 character.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Integer execCharCode(Acl2Character x) {
        // it is not clear how this compares to x.charCode() in speed:
        return Acl2Integer.make(x.getJavaChar());
    }

    /**
     * Executes the native implementation of
     * the {@code char-code} ACL2 primitive function,
     * on a Java character.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null, below 256.
     * @return The result of the function on the given argument.
     */
    public static Acl2Integer execCharCode(char x) {
        return Acl2Integer.make(x);
    }

    /**
     * Executes the native implementation of
     * the {@code code-char} ACL2 primitive function,
     * on any value.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Character execCodeChar(Acl2Value x) {
        return x.codeChar();
    }

    /**
     * Executes the native implementation of
     * the {@code code-char} ACL2 primitive function,
     * on a non-negative integer below 256.
     *
     * @param x The actual argument to pass to the function.
     *          Preconditions: not null, non-negative, and below 256.
     * @return The result of the function on the given argument.
     */
    public static Acl2Character execCodeChar(Acl2Integer x) {
        // this should be faster than x.codeChar()
        // because we can avoid checking that the integer is in range:
        return Acl2Character.imake((char) x.getJavaInt());
    }

    /**
     * Executes the native implementation of
     * the {@code code-char} ACL2 primitive function,
     * on a non-negative integer below 256,
     * returning a Java character instead of an ACL2 character.
     *
     * @param x The actual argument to pass to the function.
     *          Preconditions: not null, non-negative, and below 256.
     * @return The result of the function on the given argument.
     */
    public static char execCodeCharChar(Acl2Integer x) {
        // this should be faster than x.codeChar()
        // because we can avoid checking that the integer is in range:
        return (char) x.getJavaInt();
    }

    /**
     * Executes the native implementation of
     * the {@code coerce} ACL2 primitive function,
     * on any values.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Value execCoerce(Acl2Value x, Acl2Value y) {
        if (y.equals(Acl2Symbol.LIST))
            return x.coerceToList();
        else
            return x.coerceToString();
    }

    /**
     * Executes the native implementation of
     * the {@code coerce} ACL2 primitive function,
     * on a value and a symbol that satisfy the guard of the function.
     *
     * @param x The first actual argument to pass to the function.
     *          Preconditions: not null,
     *          instance of {@link Acl2String}
     *          if {@code y} represents the symbol {@code LIST},
     *          representation of a {@code character-listp} value
     *          if {@code y} represents the symbol {@code STRING}.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null,
     *          representation of either the symbol {@code LIST}
     *          or the symbol {@code STRING}.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Value execCoerce(Acl2Value x, Acl2Symbol y) {
        if (y.equals(Acl2Symbol.LIST)) {
            // it is not clear if this can be made faster
            // by knowing that x is an ACL2 string:
            return x.coerceToList();
        } else {
            // similar to the code in Acl2ConsPair.coerceToString(),
            // with some optimizations enabled by the fact that
            // x is known to be an ACL2 list of characters:
            List<Acl2Character> charList = new LinkedList<>();
            for (Acl2Value list = x;
                 !list.equals(Acl2Symbol.NIL);
                 list = list.cdr()) {
                charList.add((Acl2Character) list.car());
            }
            int size = charList.size();
            char[] charArray = new char[size];
            for (int i = 0; i < size; ++i)
                charArray[i] = charList.get(i).getJavaChar();
            return Acl2String.imake(new String(charArray));
        }
    }

    /**
     * Executes the native implementation of
     * the {@code intern-in-package-of-symbol} ACL2 primitive function,
     * on any values.
     *
     * @param str The first actual argument to pass to the function.
     *            Precondition: not null.
     * @param sym The second actual argument to pass to the function.
     *            Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Symbol execInternInPackageOfSymbol(Acl2Value str,
                                                         Acl2Value sym) {
        return str.internThisInPackageOf(sym);
    }

    /**
     * Executes the native implementation of
     * the {@code intern-in-package-of-symbol} ACL2 primitive function,
     * on an ACL2 string and a symbol.
     *
     * @param str The first actual argument to pass to the function.
     *            Precondition: not null.
     * @param sym The second actual argument to pass to the function.
     *            Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Symbol execInternInPackageOfSymbol(Acl2String str,
                                                         Acl2Symbol sym) {
        // this may be faster than str.internThisInPackageOf(sym),
        // followed by sym.internInPackageOfThis(str):
        return Acl2Symbol.imake(sym.getPackageName(), str);
    }

    /**
     * Executes the native implementation of
     * the {@code intern-in-package-of-symbol} ACL2 primitive function,
     * on a Java string and a symbol.
     *
     * @param str The first actual argument to pass to the function.
     *            Precondition: not null, no elements above 255.
     * @param sym The second actual argument to pass to the function.
     *            Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Symbol execInternInPackageOfSymbol(String str,
                                                         Acl2Symbol sym) {
        // this may be faster than str.internThisInPackageOf(sym),
        // followed by sym.internInPackageOfThis(Acl2String.imake(str)):
        return Acl2Symbol.imake(sym.getPackageName(), str);
    }

    /**
     * Executes the native implementation of
     * the {@code symbol-package-name} ACL2 primitive function,
     * on any value.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2String execSymbolPackageName(Acl2Value x) {
        return x.symbolPackageName();
    }

    /**
     * Executes the native implementation of
     * the {@code symbol-package-name} ACL2 primitive function,
     * on a symbol.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2String execSymbolPackageName(Acl2Symbol x) {
        // it is not clear if this can be made faster
        // by knowing that x is an ACL2 symbol:
        return x.symbolPackageName();
    }

    /**
     * Executes the native implementation of
     * the {@code symbol-package-name} ACL2 primitive function,
     * on a symbol,
     * returning a Java string instead of an ACL2 string.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static String execSymbolPackageNameString(Acl2Symbol x) {
        // it is not clear if this can be made faster
        // by knowing that x is an ACL2 symbol:
        return x.symbolPackageName().getJavaString();
    }

    /**
     * Executes the native implementation of
     * the {@code symbol-name} ACL2 primitive function,
     * on any value.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2String execSymbolName(Acl2Value x) {
        return x.symbolName();
    }

    /**
     * Executes the native implementation of
     * the {@code symbol-name} ACL2 primitive function,
     * on a symbol.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2String execSymbolName(Acl2Symbol x) {
        // it is not clear how this compares to x.symbolName() in speed:
        return x.getName();
    }

    /**
     * Executes the native implementation of
     * the {@code symbol-name} ACL2 primitive function,
     * on a symbol,
     * * returning a Java string instead of an ACL2 string..
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static String execSymbolNameString(Acl2Symbol x) {
        // it is not clear how this compares to x.symbolName() in speed:
        return x.getName().getJavaString();
    }

    /**
     * Executes the native implementation of
     * the {@code pkg-imports} ACL2 primitive function,
     * on any value.
     *
     * @param pkg The actual argument to pass to the function.
     *            Precondition: not null.
     * @return The result of the function on the given argument.
     * @throws Acl2UndefinedPackageException If the package name is invalid
     *                                       or the package is not defined.
     */
    public static Acl2Value execPkgImports(Acl2Value pkg)
            throws Acl2UndefinedPackageException {
        return pkg.pkgImports();
    }

    /**
     * Executes the native implementation of
     * the {@code pkg-imports} ACL2 primitive function,
     * on an ACL2 string.
     *
     * @param pkg The actual argument to pass to the function.
     *            Precondition: not null.
     * @return The result of the function on the given argument.
     * @throws Acl2UndefinedPackageException If the package name is invalid
     *                                       or the package is not defined.
     */
    public static Acl2Value execPkgImports(Acl2String pkg)
            throws Acl2UndefinedPackageException {
        // it is not clear if this can be made faster
        // by knowing that pkg is an ACL2 string:
        return pkg.pkgImports();
    }

    /**
     * Executes the native implementation of
     * the {@code pkg-imports} ACL2 primitive function,
     * on a Java string.
     *
     * @param pkg The actual argument to pass to the function.
     *            Precondition: not null, no elements above 255.
     * @return The result of the function on the given argument.
     * @throws Acl2UndefinedPackageException If the package name is invalid
     *                                       or the package is not defined.
     */
    public static Acl2Value execPkgImports(String pkg)
            throws Acl2UndefinedPackageException {
        // it is not clear if this can be made faster
        // by knowing that pkg is a Java string:
        return Acl2String.imake(pkg).pkgImports();
    }

    /**
     * Executes the native implementation of
     * the {@code pkg-witness} ACL2 primitive function,
     * on any value.
     *
     * @param pkg The actual argument to pass to the function.
     *            Precondition: not null.
     * @return The result of the function on the given argument.
     * @throws Acl2UndefinedPackageException If the package name is invalid
     *                                       or the package is not defined.
     */
    public static Acl2Symbol execPkgWitness(Acl2Value pkg)
            throws Acl2UndefinedPackageException {
        return pkg.pkgWitness();
    }

    /**
     * Executes the native implementation of
     * the {@code pkg-witness} ACL2 primitive function,
     * on an ACL2 string.
     *
     * @param pkg The actual argument to pass to the function.
     *            Precondition: not null.
     * @return The result of the function on the given argument.
     * @throws Acl2UndefinedPackageException If the package name is invalid
     *                                       or the package is not defined.
     */
    public static Acl2Symbol execPkgWitness(Acl2String pkg)
            throws Acl2UndefinedPackageException {
        // it is not clear if this can be made faster
        // by knowing that pkg is an ACL2 string:
        return pkg.pkgWitness();
    }

    /**
     * Executes the native implementation of
     * the {@code pkg-witness} ACL2 primitive function,
     * on a Java string.
     *
     * @param pkg The actual argument to pass to the function.
     *            Precondition: not null, no elements above 255.
     * @return The result of the function on the given argument.
     * @throws Acl2UndefinedPackageException If the package name is invalid
     *                                       or the package is not defined.
     */
    public static Acl2Symbol execPkgWitness(String pkg)
            throws Acl2UndefinedPackageException {
        // it is not clear if this can be made faster
        // by knowing that pkg is an ACL2 string:
        return Acl2String.imake(pkg).pkgWitness();
    }

    /**
     * Executes the native implementation of
     * the {@code unary--} ACL2 primitive function,
     * on any value.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Number execUnaryMinus(Acl2Value x) {
        return x.negate();
    }

    /**
     * Executes the native implementation of
     * the {@code unary--} ACL2 primitive function,
     * on a number.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Number execUnaryMinus(Acl2Number x) {
        // it is not clear if this can be made faster
        // by knowing that x is a number:
        return x.negate();
    }

    /**
     * Executes the native implementation of
     * the {@code unary--} ACL2 primitive function,
     * on a rational.
     * Since rationals are closed under this operation,
     * the result is a rational.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Rational execUnaryMinus(Acl2Rational x) {
        return x.negate();
    }

    /**
     * Executes the native implementation of
     * the {@code unary--} ACL2 primitive function,
     * on an integer.
     * Since integers are closed under this operation,
     * the result is an integer.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Integer execUnaryMinus(Acl2Integer x) {
        return x.negate();
    }

    /**
     * Executes the native implementation of
     * the {@code unary-/} ACL2 primitive function,
     * on any value.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Number execUnarySlash(Acl2Value x) {
        return x.reciprocate();
    }

    /**
     * Executes the native implementation of
     * the {@code unary-/} ACL2 primitive function,
     * on a non-zero number.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null, not 0.
     * @return The result of the function on the given argument.
     */
    public static Acl2Number execUnarySlash(Acl2Number x) {
        return x.reciprocateNonZero();
    }

    /**
     * Executes the native implementation of
     * the {@code unary-/} ACL2 primitive function,
     * on a non-zero rational.
     * Since rationals are closed under this operation,
     * the result is a rational.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null, not 0.
     * @return The result of the function on the given argument.
     */
    public static Acl2Rational execUnarySlash(Acl2Rational x) {
        return x.reciprocateNonZero();
    }

    /**
     * Executes the native implementation of
     * the {@code binary-+} ACL2 primitive function,
     * on any values.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Number execBinaryPlus(Acl2Value x, Acl2Value y) {
        return x.addValue(y);
    }

    /**
     * Executes the native implementation of
     * the {@code binary-+} ACL2 primitive function,
     * on numbers.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Number execBinaryPlus(Acl2Number x, Acl2Number y) {
        // this should be slightly faster than x.addValue(y),
        // which in turn calls y.addNumber(x):
        return x.addNumber(y);
    }

    /**
     * Executes the native implementation of
     * the {@code binary-+} ACL2 primitive function,
     * on rationals.
     * Since rationals are closed under this operation,
     * the result is a rational.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Rational execBinaryPlus(Acl2Rational x, Acl2Rational y) {
        // this should be slightly faster than x.addNumber(y),
        // which in turn calls y.addRational(x):
        return x.addRational(y);
    }

    /**
     * Executes the native implementation of
     * the {@code binary-+} ACL2 primitive function,
     * on integers.
     * Since integers are closed under this operation,
     * the result is an integer.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Integer execBinaryPlus(Acl2Integer x, Acl2Integer y) {
        // this should be slightly faster than x.addRational(y),
        // which in turn calls y.addInteger(x):
        return x.addInteger(y);
    }

    /**
     * Executes the native implementation of
     * the {@code binary-*} ACL2 primitive function,
     * on any values.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Number execBinaryStar(Acl2Value x, Acl2Value y) {
        return x.multiplyValue(y);
    }

    /**
     * Executes the native implementation of
     * the {@code binary-*} ACL2 primitive function,
     * on numbers.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Number execBinaryStar(Acl2Number x, Acl2Number y) {
        // this should be slightly faster than x.multiplyValue(y),
        // which in turn calls y.multiplyNumber(x):
        return x.multiplyNumber(y);
    }

    /**
     * Executes the native implementation of
     * the {@code binary-*} ACL2 primitive function,
     * on rationals.
     * Since rationals are closed under this operation,
     * the result is a rational.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Rational execBinaryStar(Acl2Rational x, Acl2Rational y) {
        // this should be slightly faster than x.multiplyNumber(y),
        // which in turn calls y.multiplyRational(x):
        return x.multiplyRational(y);
    }

    /**
     * Executes the native implementation of
     * the {@code binary-*} ACL2 primitive function,
     * on integers.
     * Since integers are closed under this operation,
     * the result is an integer.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Integer execBinaryStar(Acl2Integer x, Acl2Integer y) {
        // this should be slightly faster than x.multiplyRational(y),
        // which in turn calls y.multiplyInteger(x):
        return x.multiplyInteger(y);
    }

    /**
     * Executes the native implementation of
     * the {@code <} ACL2 primitive function,
     * on any values.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Symbol execLessThan(Acl2Value x, Acl2Value y) {
        int realCmp = x.realpart().compareTo(y.realpart());
        if (realCmp < 0 ||
                realCmp == 0 && x.imagpart().compareTo(y.imagpart()) < 0)
            return Acl2Symbol.T;
        else
            return Acl2Symbol.NIL;
    }

    /**
     * Executes the native implementation of
     * the {@code <} ACL2 primitive function,
     * on rationals.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Symbol execLessThan(Acl2Rational x, Acl2Rational y) {
        // this should be generally faster than the code in execLessThan():
        if (x.compareToRational(y) < 0)
            return Acl2Symbol.T;
        else
            return Acl2Symbol.NIL;
    }

    /**
     * Executes the native implementation of
     * the {@code <} ACL2 primitive function,
     * on rationals,
     * returning a Java boolean instead of an ACL2 boolean.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static boolean execLessThanBoolean(Acl2Rational x, Acl2Rational y) {
        return x.compareToRational(y) < 0;
    }

    /**
     * Executes the native implementation of
     * the {@code complex} ACL2 primitive function,
     * on any values.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Number execComplex(Acl2Value x, Acl2Value y) {
        return Acl2Number.imake(x.rfix(), y.rfix());
    }

    /**
     * Executes the native implementation of
     * the {@code complex} ACL2 primitive function,
     * on rationals.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Number execComplex(Acl2Rational x, Acl2Rational y) {
        // this avoids calling rfix():
        return Acl2Number.imake(x, y);
    }

    /**
     * Executes the native implementation of
     * the {@code realpart} ACL2 primitive function,
     * on any value.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Rational execRealPart(Acl2Value x) {
        return x.realpart();
    }

    /**
     * Executes the native implementation of
     * the {@code realpart} ACL2 primitive function,
     * on a number.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Rational execRealPart(Acl2Number x) {
        // it is not clear how this compares to x.realpart() in speed:
        return x.getRealPart();
    }

    /**
     * Executes the native implementation of
     * the {@code imagpart} ACL2 primitive function,
     * on any value.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Rational execImagPart(Acl2Value x) {
        return x.imagpart();
    }

    /**
     * Executes the native implementation of
     * the {@code imagpart} ACL2 primitive function,
     * on a number.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Rational execImagPart(Acl2Number x) {
        // it is not clear how this compares to x.imagpart() in speed:
        return x.getImaginaryPart();
    }

    /**
     * Executes the native implementation of
     * the {@code numerator} ACL2 primitive function,
     * on any value.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Integer execNumerator(Acl2Value x) {
        return x.numerator();
    }

    /**
     * Executes the native implementation of
     * the {@code numerator} ACL2 primitive function,
     * on a rational.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Integer execNumerator(Acl2Rational x) {
        // it is not clear how this compares to x.numerator() in speed:
        return x.getNumerator();
    }

    /**
     * Executes the native implementation of
     * the {@code denominator} ACL2 primitive function,
     * on any value.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Integer execDenominator(Acl2Value x) {
        return x.denominator();
    }

    /**
     * Executes the native implementation of
     * the {@code denominator} ACL2 primitive function,
     * on a rational.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Integer execDenominator(Acl2Rational x) {
        // it is not clear how this compares to x.denominator() in speed:
        return x.getDenominator();
    }

    /**
     * Executes the native implementation of
     * the {@code cons} ACL2 primitive function.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2ConsPair execCons(Acl2Value x, Acl2Value y) {
        return Acl2ConsPair.imake(x, y);
    }

    /**
     * Executes the native implementation of
     * the {@code car} ACL2 primitive function.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Value execCar(Acl2Value x) {
        return x.car();
    }

    /**
     * Executes the native implementation of
     * the {@code cdr} ACL2 primitive function.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Value execCdr(Acl2Value x) {
        return x.cdr();
    }

    /**
     * Executes the native implementation of
     * the {@code equal} ACL2 primitive function.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Symbol execEqual(Acl2Value x, Acl2Value y) {
        if (x.equals(y))
            return Acl2Symbol.T;
        else
            return Acl2Symbol.NIL;
    }

    /**
     * Executes the native implementation of
     * the {@code equal} ACL2 primitive function,
     * returning a Java boolean instead of an ACL2 boolean.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static boolean execEqualBoolean(Acl2Value x, Acl2Value y) {
        return x.equals(y);
    }

    /**
     * Executes the native implementation of
     * the {@code bad-atom<=} ACL2 primitive function.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Symbol execBadAtomLessThanOrEqualTo(Acl2Value x,
                                                          Acl2Value y) {
        return Acl2Symbol.NIL;
    }

    /**
     * Executes the native implementation of
     * the {@code if} ACL2 primitive function.
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @param z The third actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Value execIf(Acl2Value x, Acl2Value y, Acl2Value z) {
        if (x.equals(Acl2Symbol.NIL))
            return z;
        else
            return y;
    }

    /**
     * Executes the native implementation of
     * the {@code or} ACL2 "pseudo-function".
     *
     * @param x The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param y The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Value execOr(Acl2Value x, Acl2Value y) {
        if (x.equals(Acl2Symbol.NIL))
            return y;
        else
            return x;
    }

    /**
     * Executes the native implementation of
     * the {@code nonnegative-integer-quotient} ACL2 built-in function,
     * on any values.
     *
     * @param i The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param j The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Integer execNonnegativeIntegerQuotient(Acl2Value i,
                                                             Acl2Value j) {
        if (i instanceof Acl2Integer && j instanceof Acl2Integer)
            return execNonnegativeIntegerQuotient
                    ((Acl2Integer) i, (Acl2Integer) j);
        else
            return Acl2Integer.ZERO;
    }

    /**
     * Executes the native implementation of
     * the {@code nonnegative-integer-quotient} ACL2 built-in function,
     * on integers.
     *
     * @param i The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param j The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Integer execNonnegativeIntegerQuotient(Acl2Integer i,
                                                             Acl2Integer j) {
        if (i.compareToInteger(Acl2Integer.ZERO) >= 0 &&
                j.compareToInteger(Acl2Integer.ZERO) > 0)
            return (i.divide(j));
        else
            return Acl2Integer.ZERO;
    }

    /**
     * Executes the native implementation of
     * the {@code string-append} ACL2 built-in function,
     * on any values.
     *
     * @param str1 The first actual argument to pass to the function.
     *             Precondition: not null.
     * @param str2 The second actual argument to pass to the function.
     *             Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2String execStringAppend(Acl2Value str1, Acl2Value str2) {
        return str1.stringAppendValueRight(str2);
    }

    /**
     * Executes the native implementation of
     * the {@code string-append} ACL2 built-in function,
     * on ACL2 strings.
     *
     * @param str1 The first actual argument to pass to the function.
     *             Precondition: not null.
     * @param str2 The second actual argument to pass to the function.
     *             Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2String execStringAppend(Acl2String str1,
                                              Acl2String str2) {
        return str2.stringAppendStringLeft(str1);
    }

    /**
     * Executes the native implementation of
     * the {@code string-append} ACL2 built-in function,
     * on Java strings.
     *
     * @param str1 The first actual argument to pass to the function.
     *             Precondition: not null, no elements above 255.
     * @param str2 The second actual argument to pass to the function.
     *             Precondition: not null, no elements above 255.
     * @return The result of the function on the given arguments.
     */
    public static String execStringAppend(String str1, String str2) {
        return str1.concat(str2);
    }

    /**
     * Executes the native implementation of
     * the {@code len} ACL2 built-in function.
     *
     * @param x The actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given argument.
     */
    public static Acl2Integer execLen(Acl2Value x) {
        // we scan the list until we reach the end or the maximum int value:
        int len = 0;
        while (x instanceof Acl2ConsPair && len >= 0) {
            ++len;
            x = x.cdr();
        }
        // if still len >= 0, it we have reached the end of the list:
        if (len >= 0) return Acl2Integer.make(len);
        // if instead len < 0,
        // the length is 2^31 or more
        // (because int wrapped around,
        // so it was 2^31 - 1 just before scanning the last scanned element),
        // so we keep counting with Acl2Integer objects,
        // starting with 2^31:
        Acl2Integer lenObj = Acl2Integer.make(Integer.MAX_VALUE); // 2^31 - 1
        lenObj = lenObj.addInteger(Acl2Integer.ONE); // 2^31
        while (x instanceof Acl2ConsPair) {
            lenObj = lenObj.addInteger(Acl2Integer.ONE);
            x = x.cdr();
        }
        return lenObj;
    }

    /**
     * Executes the native implementation of
     * the {@code char} ACL2 built-in function,
     * on any values.
     *
     * @param s The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param n The second actual argument to pass to the function.
     *          Precondition: not null.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Value execChar(Acl2Value s, Acl2Value n) {
        return s.charAt(n);
    }

    /**
     * Executes the native implementation of
     * the {@code char} ACL2 built-in function,
     * on an ACL2 string and an ACL2 integer.
     *
     * @param s The first actual argument to pass to the function.
     *          Precondition: not null.
     * @param n The second actual argument to pass to the function.
     *          Precondition: not null, non-negative, below the string length.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Character execChar(Acl2String s, Acl2Integer n) {
        // this should be faster than s.charAt(n):
        return n.charAtThisIndexInRange(s.getJavaString());
    }

    /**
     * Executes the native implementation of
     * the {@code char} ACL2 built-in function,
     * on a Java string and an ACL2 integer.
     *
     * @param s The first actual argument to pass to the function.
     *          Precondition: not null, no elements above 255.
     * @param n The second actual argument to pass to the function.
     *          Precondition: not null, non-negative, below the string length.
     * @return The result of the function on the given arguments.
     */
    public static Acl2Character execChar(String s, Acl2Integer n) {
        return Acl2Character.imake(s.charAt(n.getJavaBigInteger().intValue()));
    }

    /**
     * Executes the native implementation of
     * the {@code char} ACL2 built-in function,
     * on a Java string and an ACL2 integer,
     * returning a Java character instead of an ACL2 character.
     *
     * @param s The first actual argument to pass to the function.
     *          Precondition: not null, no elements above 255.
     * @param n The second actual argument to pass to the function.
     *          Precondition: not null, non-negative, below the string length.
     * @return The result of the function on the given arguments.
     */
    public static char execCharChar(String s, Acl2Integer n) {
        return s.charAt(n.getJavaBigInteger().intValue());
    }

}
