import { Native } from '@stemcmicro/native';
export { NATIVE_MAX, NATIVE_MIN, Native, code_from_native_sym, is_native_sym, native_sym } from '@stemcmicro/native';
import { ExprContext, LambdaExpr, ExprHandler } from '@stemcmicro/context';
import { U, Cons, Atom } from '@stemcmicro/tree';
import { Directive } from '@stemcmicro/directive';
import * as _stemcmicro_atoms from '@stemcmicro/atoms';
import { CellHost, Tensor, Sym, Cell, Uom } from '@stemcmicro/atoms';
import { ProgramEnv, ProgramControl, ProgramIO, StackFunction, Stack, ProgramIOListener } from '@stemcmicro/stack';
export { create_algebra_as_blades } from '@stemcmicro/helpers';

type Sign = -1 | 0 | 1;
type TFLAGS = number;
/**
 * Corresponds to the 'name' property on an Atom.
 */
type FEATURE = "Blade" | "Boo" | "Cell" | "Flt" | "Imu" | "Map" | "Rat" | "Sym" | "Tensor" | "Uom";
declare const ALL_FEATURES: FEATURE[];
declare function directive_from_flag(value: boolean | undefined): number;
/**
 *
 */
interface PrintHandler {
    print(...items: string[]): void;
}
type CompareFn = (lhs: U, rhs: U) => Sign;
/**
 *
 */
interface ExprComparator {
    compare(lhs: U, rhs: U, $: ExtensionEnv): Sign;
}
/**
 * Not to be confused with a LambdaExpr.
 * Here the first argument is the expression including the operator.
 */
type EvalFunction = (expr: Cons, $: ExtensionEnv) => U;
interface Predicates {
    /**
     * An algebraic number is any number that is a root of a non-zero polynomial having rational coefficients.
     * All algebraic numbers are complex.
     * An algebraic number may or may not be real.
     * Includes all rational numbers.
     */
    algebraic: boolean;
    /**
     * An element of the field of antihermitian operators.
     * Defaults to false.
     */
    antihermitian: boolean;
    /**
     * A commutative expression.
     * A commutative expression commutes with all other expressions under multiplication.
     * If an expression a has commutative then a * b == b * a for any other expression b (even if b is not commutative).
     * Unlike all other assumptions predicates commutative must always be true or false and can never be undefined.
     * Also unlike all other predicates commutative defaults to true.
     */
    commutative: boolean;
    /**
     * A complex number is any number of the form x+i*y where x and y are real.
     * All complex numbers are finite. Includes all real numbers.
     */
    complex: boolean;
    extended_negative: boolean;
    extended_nonnegative: boolean;
    extended_nonpositive: boolean;
    extended_nonzero: boolean;
    extended_positive: boolean;
    /**
     * A finite expression.
     * Any expression that is not infinite is considered finite.
     */
    finite: boolean;
    /**
     * An element of the field of Hermitian operators.
     */
    hermitian: boolean;
    /**
     * The extension of the complex numbers to include infinitesimals and infinite numbers.
     */
    hypercomplex: boolean;
    /**
     * The extension of the real numbers to include infinitesimals and infinite numbers.
     */
    hyperreal: boolean;
    imaginary: boolean;
    /**
     * An infinite expression.
     */
    infinite: boolean;
    infinitesimal: boolean;
    integer: boolean;
    irrational: boolean;
    negative: boolean;
    noninteger: boolean;
    nonnegative: boolean;
    nonpositive: boolean;
    nonzero: boolean;
    /**
     * A real number that is greater than zero.
     * All positive numbers are finite so infinity is not positive.
     */
    positive: boolean;
    rational: boolean;
    real: boolean;
    /**
     * A complex number that is not algebraic.
     * All transcendental numbers are complex.
     * A transcendental number may or may not be real but can never be rational.
     * Defaults to false.
     */
    transcendental: boolean;
    zero: boolean;
}
interface AtomListener {
    reset(from: U, to: U, source: Cell): void;
}
/**
 *
 */
interface ExtensionEnv extends ExprContext, ProgramEnv, ProgramControl, Pick<ProgramIO, "listeners"> {
    addAtomListener(subscriber: AtomListener): void;
    removeAtomListener(subscriber: AtomListener): void;
    getCellHost(): CellHost;
    setCellHost(host: CellHost): void;
    getProlog(): readonly string[];
    getPrintHandler(): PrintHandler;
    setPrintHandler(handler: PrintHandler): void;
    abs(expr: U): U;
    algebra(metric: Tensor<U>, labels: Tensor<U>): Tensor<U>;
    /**
     *
     */
    add(...args: U[]): U;
    arccos(expr: U): U;
    arcsin(expr: U): U;
    arctan(expr: U): U;
    arg(expr: U): U;
    clock(expr: U): U;
    conj(expr: U): U;
    cos(expr: U): U;
    clearBindings(): void;
    clearOperators(): void;
    compareFn(opr: Sym): CompareFn;
    component(tensor: Tensor<U>, indices: U): U;
    /**
     * Defines the implementation of a function that is used to transform (name ...) expressions.
     */
    defineEvalFunction(opr: Sym, evalFunction: EvalFunction): void;
    defineFunction(match: U, lambda: LambdaExpr): void;
    defineStackFunction(opr: Sym, stackFunction: StackFunction): void;
    defineExtension(builder: ExtensionBuilder<U>, immediate?: boolean): void;
    defineUserSymbol(name: Sym): void;
    derivedEnv(): ExtensionEnv;
    divide(lhs: U, rhs: U): U;
    /**
     *
     */
    equals(lhs: U, rhs: U): boolean;
    evaluate(opr: Native, ...args: U[]): U;
    exp(expr: U): U;
    factor(expr: U): U;
    /**
     *
     */
    factorize(poly: U, x: U): U;
    float(expr: U): U;
    getDirective(directive: number): number;
    getSymbolPredicates(sym: Sym): Predicates;
    /**
     * Used during rendering.
     */
    getSymbolPrintName(sym: Sym): string;
    getSymbolUsrFunc(sym: Sym): U;
    getSymbolsInfo(): {
        sym: Sym;
        value: U;
    }[];
    /**
     * Used to make the environment ready after all operator builders have been added.
     */
    buildOperators(): void;
    im(expr: U): U;
    /**
     *
     */
    inner(lhs: U, rhs: U): U;
    /**
     * Generalized predicate testing.
     * @param predicate
     * @param expr
     */
    is(predicate: Sym, expr: U): boolean;
    iscomplex(expr: U): boolean;
    isExpanding(): boolean;
    isFactoring(): boolean;
    /**
     * Meaning is imaginary valued. i.e. evaluates to i times a real number.
     */
    isimag(expr: U): boolean;
    isinfinite(expr: U): boolean;
    isinfinitesimal(expr: U): boolean;
    isminusone(expr: U): boolean;
    isnegative(expr: U): boolean;
    /**
     * @deprecated The implementation doesn't need a full context.
     */
    isone(expr: U): boolean;
    ispositive(expr: U): boolean;
    isreal(expr: U): boolean;
    /**
     * Determines whether expr is scalar-valued.
     */
    isscalar(expr: U): boolean;
    /**
     * A convenience for appling the predicate function to the expression.
     */
    iszero(expr: U): boolean;
    /**
     *
     */
    log(expr: U): U;
    /**
     *
     */
    multiply(...args: U[]): U;
    /**
     *
     */
    negate(expr: U): U;
    extensionFor(expr: U): Extension<U> | undefined;
    /**
     *
     */
    outer(...args: U[]): U;
    polar(expr: U): U;
    /**
     *
     */
    power(base: U, expo: U): U;
    re(expr: U): U;
    rect(expr: U): U;
    remove(varName: Sym): void;
    pushDirective(directive: number, value: number): void;
    popDirective(): void;
    setSymbolOrder(sym: Sym, order: ExprComparator): void;
    setSymbolPredicates(sym: Sym, predicates: Partial<Predicates>): void;
    setSymbolPrintName(sym: Sym, printName: string): void;
    setSymbolUsrFunc(sym: Sym, usrfunc: U): void;
    simplify(expr: U): U;
    sin(expr: U): U;
    sqrt(expr: U): U;
    st(expr: U): U;
    subst(newExpr: U, oldExpr: U, expr: U): U;
    /**
     *
     */
    subtract(lhs: U, rhs: U): U;
    toInfixString(expr: U): string;
    toLatexString(expr: U): string;
    toSExprString(expr: U): string;
    transform(expr: U): [TFLAGS, U];
    valueOf(expr: U): U;
}
/**
 * The interface that MUST be implemented by extensions to the environment.
 * The type parameter,T, allows you to constrain the argument types of the
 * methods that you implement. e.g. If isKind() only matches a Cons, then set T
 * to be Cons. If isKind() only matches Sym, set T to be Sym. In more general
 * cases, use a more general type. The rule is that isKind determines which expression are matched,
 * and when the other method are called (they all contain at least one argument that matches T),
 * it determines the possible dynamic types for T.
 */
interface ExtensionBuilder<T extends U> {
    create(config: Readonly<EnvConfig>): Extension<T>;
}
/**
 *
 */
interface Extension<T extends U> extends ExprHandler<T> {
    readonly hash: string;
    readonly name: string;
    readonly phases?: number;
    readonly dependencies?: FEATURE[];
    iscons(): this is Extension<Cons>;
    operator(): Sym;
    isKind(expr: U, env: ExprContext): boolean;
    toHumanString(expr: T, env: ExprContext): string;
    toInfixString(expr: T, env: ExprContext): string;
    toLatexString(expr: T, env: ExprContext): string;
    toListString(expr: T, env: ExprContext): string;
    /**
     * This method assumes that the opr is in the operator slot of a combination.
     * Except for Sym, that's an experimental proposition.
     */
    evaluate(opr: T, argList: Cons, $: ExprContext): [TFLAGS, U];
    transform(expr: T, $: ExprContext): [TFLAGS, U];
    valueOf(expr: T, $: ExprContext): U;
}

interface EnvConfig {
    allowUndeclaredVars: "Err" | "Nil";
    assumes: {
        [name: string]: Partial<Predicates>;
    };
    dependencies: FEATURE[];
    enable: Directive[];
    disable: Directive[];
    noOptimize: boolean;
    useCaretForExponentiation: boolean;
    useDerivativeShorthandLowerD: boolean;
    useIntegersForPredicates: boolean;
    useParenForTensors: boolean;
}

interface ExprHandlerBuilder<T extends U> {
    create(): ExprHandler<T>;
}
declare class AtomExtensionBuilderFromExprHandlerBuilder<T extends Atom> implements ExtensionBuilder<T> {
    readonly builder: ExprHandlerBuilder<T>;
    readonly type: string;
    readonly guard: (expr: Atom) => boolean;
    constructor(builder: ExprHandlerBuilder<T>, type: string, guard: (expr: Atom) => boolean);
    create(config: Readonly<EnvConfig>): Extension<T>;
}

interface EnvOptions {
    allowUndeclaredVars: "Err" | "Nil";
    assumes?: {
        [name: string]: Partial<Predicates>;
    };
    dependencies?: FEATURE[];
    enable?: Directive[];
    disable?: Directive[];
    noOptimize?: boolean;
    useCaretForExponentiation?: boolean;
    useDerivativeShorthandLowerD?: boolean;
    useIntegersForPredicates?: boolean;
    useParenForTensors?: boolean;
}
declare function create_env(options?: EnvOptions): ExtensionEnv;

declare function simplify(x: U, env: ExprContext): U;

declare function assert_sym(expr: U): Sym;

type TYPE_UOM_NAME = "ampere" | "candela" | "coulomb" | "farad" | "henry" | "hertz" | "joule" | "kelvin" | "kilogram" | "meter" | "metre" | "mole" | "newton" | "ohm" | "one" | "pascal" | "second" | "siemens" | "tesla" | "volt" | "watt" | "weber";
declare const UOM_NAMES: TYPE_UOM_NAME[];
declare function create_uom(name: TYPE_UOM_NAME): Uom;

/**
 *
 */
interface PrintConfig {
    pushDirective(directive: number, value: number): void;
    popDirective(): void;
    getBinding(opr: Sym, target: Cons): U;
    getDirective(directive: number): number;
    getSymbolPrintName(sym: Sym): string;
    handlerFor<T extends U>(expr: T): ExprHandler<T>;
    valueOf(expr: U): U;
}

declare function render_as_ascii(expr: U, $: PrintConfig): string;

declare function render_as_human(expr: U, $: PrintConfig): string;

declare function render_as_infix(expr: U, $: PrintConfig): string;

declare function render_as_latex(expr: U, $: PrintConfig): string;

/**
 * The standard way of serializing to s-expr format.
 * @param expr The expression to be rendered.
 * @param $ The extension environment.
 */
declare function render_as_sexpr(expr: U, $: PrintConfig): string;

/**
 * @param p
 * @param x
 * @returns
 */
declare function roots(p: U, x: U, $: ExprContext): Tensor;

interface ExprTransformOptions {
    autoExpand?: boolean;
    autoFactor?: boolean;
    /**
     * Directives that become enabled by setting to true.
     */
    enable?: Directive[];
    /**
     * Directives that become disabled by setting to false.
     */
    disable?: Directive[];
    useIntegersForPredicates?: boolean;
}
interface ScriptExecuteOptions extends ExprTransformOptions {
    /**
     * Determines whether execptions are caught and returned in the errors property.
     */
    catchExceptions?: boolean;
}
interface ScriptContextOptions extends ScriptExecuteOptions {
    /**
     * The default is ???.
     */
    allowUndeclaredVars?: "Err" | "Nil";
    /**
     * The assumptions about unbound symbols.
     */
    assumes?: {
        [name: string]: Partial<Predicates>;
    };
    dependencies?: string[];
    /**
     * Determines whether the circumflex (caret) character, '^', will be used during parsing to denote exponentiation.
     * The alternative is to use '**', freeing the caret character for use with outer products which is convenient
     * in applications using Geometric Algebra. The default value is false.
     */
    useCaretForExponentiation?: boolean;
    useDerivativeShorthandLowerD?: boolean;
    /**
     * Determines whether test functions will return boolean or integer values.
     *
     * The default is false.
     */
    useIntegersForPredicates?: boolean;
    /**
     * Determines whether parentheses, "(" and ")", or square brackets, "[" and "]", will be used to delimit tensors.
     */
    useParenForTensors?: boolean;
}
declare function init_env($: ExtensionEnv, options?: ScriptContextOptions): void;
declare function env_term($: ExtensionEnv): void;

/**
 * Evaluates the parse tree using the operators defined in the environment.
 * @param tree The parse tree.
 * @param options The opti
 * @param $ The environment defining the operators.
 * @returns The return values (zero or one), print outputs, and errors.
 */
declare function transform_tree(tree: U, options: ExprTransformOptions, $: ExtensionEnv): {
    value: U;
    prints: string[];
    errors: Error[];
};

/**
 * 'last'
 */
declare const RESERVED_KEYWORD_LAST: _stemcmicro_atoms.Sym;
/**
 * 'tty'
 */
declare const RESERVED_KEYWORD_TTY: _stemcmicro_atoms.Sym;

declare class Thing {
    readonly proto: unknown;
    getter: unknown;
    setter: unknown;
    properties: unknown;
    constructor(proto: unknown);
}
interface Scope {
    thing: Thing;
    evaluate(opr: Native, ...args: U[]): U;
    hasBinding(sym: Sym, target: Cons): boolean;
    getBinding(sym: Sym, target: Cons): U;
    setBinding(sym: Sym, binding: U): void;
    hasUserFunction(sym: Sym): boolean;
    getUserFunction(sym: Sym): U;
    setUserFunction(sym: Sym, usrfunc: U): void;
    valueOf(expr: U): U;
}
declare class State {
    readonly input: U;
    readonly $: Scope;
    /**
     * For use by evaluators. Let's the evaluator know it is being called for the first time.
     * The evaluator is responsible for updating the value to false if it chooses to use it.
     */
    firstTime: boolean;
    /**
     * MUST be initialized to false.
     */
    done: boolean;
    doneArg: boolean[];
    /**
     * For use by evaluators to keep track of evaluated arguments.
     */
    argValues: U[];
    /**
     * Contains the value from the previous invocation of the evaluator.
     */
    value: U;
    /**
     * The inputs from the invocation of the module.
     */
    inputs: U[];
    /**
     * The values from the invocation of the module.
     */
    values: U[];
    doneCallee: number;
    doneArgs: boolean;
    funcThis: unknown;
    func: unknown;
    arguments: unknown;
    constructor(input: U, $: Scope);
}
interface StepperHandler {
    atom(after: U, before: U): void;
}
interface StepperConfig {
    allowUndeclaredVars: boolean;
}
declare class Stepper {
    #private;
    POLYFILL_TIMEOUT: number;
    /**
     * @param module
     * @param options
     * @param initFunc
     */
    constructor(module: Cons, options?: Partial<StepperConfig>, initFunc?: (runner: Stepper, globalObject: Thing) => void);
    createScope(node: unknown, parentScope: Scope): Scope;
    createObjectProto(proto: unknown | null): Thing;
    defineFunction(name: Sym, lambda: LambdaExpr): void;
    initGlobal(globalObject: Thing): void;
    run(handler?: StepperHandler): boolean;
    /**
     * Execute one step of the interpreter.
     * @returns true if there are more instructions to execute.
     */
    next(handler?: StepperHandler): boolean;
    get stack(): Stack<State>;
    addListener(listener: ProgramIOListener): void;
    removeListener(listener: ProgramIOListener): void;
}

export { ALL_FEATURES, AtomExtensionBuilderFromExprHandlerBuilder, type ExtensionEnv, type FEATURE, RESERVED_KEYWORD_LAST, RESERVED_KEYWORD_TTY, type Scope, State, Stepper, type StepperConfig, type StepperHandler, Thing, UOM_NAMES, assert_sym, create_env, create_uom, directive_from_flag, env_term, init_env, render_as_ascii, render_as_human, render_as_infix, render_as_latex, render_as_sexpr, roots, simplify, transform_tree };
