import { Sym, CellHost, Tensor, Rat, Cell } from 'math-expression-atoms';
import { LambdaExpr, ExprContext } from 'math-expression-context';
import { U, Cons } from 'math-expression-tree';
import { Native } from 'math-expression-native';

declare class Stack<T> {
    #private;
    tos: number;
    constructor(elements?: T[]);
    get length(): number;
    get top(): T;
    peek(index: number): T;
    push(element: T): void;
    pushItems(items: T[]): void;
    pop(): T;
    popItems(n: number): T[];
    copy(): Stack<T>;
    /**
     * Changes the order of the top two elements on the stack.
     */
    swap(): void;
}

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): boolean;
    getBinding(sym: string | Sym): 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: ExprEngineListener): void;
    removeListener(listener: ExprEngineListener): void;
}

declare enum SyntaxKind {
    /**
     * STEMC Scripting Language.
     */
    STEMCscript = 1,
    /**
     * ClojureScript Programming Language.
     */
    ClojureScript = 2,
    /**
     * Eigenmath Scripting Language by George Weigt.
     */
    Eigenmath = 3,
    PythonScript = 4
}
declare function human_readable_syntax_kind(syntaxKind: SyntaxKind): string;
declare const syntaxKinds: SyntaxKind[];

interface EnvConfig {
    allowUndeclaredVars: UndeclaredVars;
    assumes: {
        [name: string]: Partial<Predicates>;
    };
    dependencies: FEATURE[];
    enable: Directive[];
    disable: Directive[];
    noOptimize: boolean;
    useCaretForExponentiation: boolean;
    useDerivativeShorthandLowerD: boolean;
    useIntegersForPredicates: boolean;
    useParenForTensors: boolean;
    syntaxKind: SyntaxKind;
}

type Sign = -1 | 0 | 1;
type TFLAGS = number;
/**
 * Corresponds to the 'name' property on an Atom.
 */
type FEATURE = 'Blade' | 'Boo' | 'Flt' | 'Imu' | 'Map' | 'Rat' | 'Sym' | 'Tensor' | 'Uom';
/**
 * Determines how an expression is evaluated.
 */
declare enum Directive {
    /**
     * Convert familiar expressions to canonical form. Mutually exclusive with familiarize.
     */
    canonicalize = 0,
    /**
     * Replace sin with cos. Mutually exclusive with convertCosToSim.
     */
    convertSinToCos = 1,
    /**
     * Replace cos with sin. Mutually exclusive with convertSinToCos.
     */
    convertCosToSin = 2,
    /**
     * Convert canonical expressions to familiar form. Mutually exclusive with canonicalize.
     */
    familiarize = 3,
    /**
     * Is not the same as the expand function.
     * Mutually exclusive with factoring.
     */
    expanding = 4,
    /**
     * Determines whether abs(a + b + c ...) is expanded.
     */
    expandAbsSum = 5,
    /**
     * Determines whether cos(a + b + c ...) is expanded.
     */
    expandCosSum = 6,
    /**
    * Determines whether (a + b + c ...) raised to a positive integer exponent is expanded.
    * The default is true.
    */
    expandPowSum = 7,
    /**
     * Determines whether cos(a + b + c ...) is expanded.
     */
    expandSinSum = 8,
    /**
    * Determines whether numeric types are converted to floating point numbers for numeric evaluation.
    *
    * The default value as false.
    */
    evaluatingAsFloat = 9,
    /**
     * Determines whether complex numbers are driven towards clock form.
     * The other possibilities are polar and rectanglular.
     *
     * The default value is false.
     */
    complexAsClock = 10,
    /**
     * Determines whether complex numbers are driven towards polar form.
     * The other possibilities are clock and rectanglular.
     *
     * The default value is false.
     */
    complexAsPolar = 11,
    /**
     * Determines whether complex numbers are driven towards rectangular form.
     * The other possibilities are clock and polar.
     *
     * The default value is false.
     */
    complexAsRectangular = 12,
    /**
     * Determines whether exponential functions are converted ti exponential form.
     */
    convertExpToTrig = 13,
    /**
     * Determines whether trigonometric functions are converted to exponential form.
     *
     * The default is false.
     */
    convertTrigToExp = 14,
    /**
     * Determines whether zero terms are kept in sums in attempt to preserve the dynamic type.
     * The alternative is to use a canonical zero value, usually that for rational numbers.
     *
     * The default value is false.
     */
    keepZeroTermsInSums = 15,
    /**
     * Is not the same as the factor function.
     * Mutually exclusive with expanding.
     */
    factoring = 16,
    /**
     * Determines whether floating point numbers are rendered as EcmaScript numbers.
     * If not, floating point numbers are rendered in a proprietary format.
     *
     * The default value is false.
     */
    renderFloatAsEcmaScript = 17,
    /**
     * Determines whether caret token '^' will be used for exponentiation or for the exterior product.
     * Using the caret token for exponetitation is common in mathematical tools but not in programming languages.
     *
     * The default value is false.
     */
    useCaretForExponentiation = 18,
    /**
     * Determines whether test funtions will return Boo or Rat values.
     *
     * The default value is false.
     */
    useIntegersForPredicates = 19,
    useParenForTensors = 20
}
/**
 *
 */
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 ConsExpr = (expr: Cons, $: ExtensionEnv) => U;
type KeywordRunner = ($: ExtensionEnv) => void;
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 ExtensionEnv extends ExprContext {
    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(sym: Sym): CompareFn;
    component(tensor: Tensor<U>, indices: U): U;
    /**
     * Defines the implementation of a function that is used to transform (name ...) expressions.
     */
    defineConsTransformer(opr: Sym, consExpr: ConsExpr): void;
    defineFunction(match: U, lambda: LambdaExpr): void;
    /**
     * e.g. clearall
     */
    defineKeyword(sym: Sym, runner: KeywordRunner): void;
    defineOperator(builder: OperatorBuilder<U>): void;
    defineAssociative(opr: Sym, id: Rat): void;
    defineUserSymbol(sym: Sym): void;
    derivedEnv(): ExtensionEnv;
    divide(lhs: U, rhs: U): U;
    /**
     *
     */
    equals(lhs: U, rhs: U): boolean;
    evaluate(opr: Native, ...args: U[]): U;
    executeProlog(prolog: readonly string[]): void;
    exp(expr: U): U;
    factor(expr: U): U;
    /**
     *
     */
    factorize(poly: U, x: U): U;
    float(expr: U): U;
    getCustomDirective(directive: string): boolean;
    getDirective(directive: Directive): boolean;
    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;
    /**
     * @deprecated Use getDirective(Directive.expanding)
     */
    isExpanding(): boolean;
    /**
     * @deprecated Use getDirective(Directive.factoring)
     */
    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;
    /**
     * Returns the operator for interacting with the expression.
     * Operator(s) are reference counted and so the operator MUST be released when no longer needed.
     * User-defined atoms may not have an operator.
     */
    operatorFor(expr: U): Operator<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;
    setCustomDirective(directive: string, value: boolean): void;
    pushDirective(directive: Directive, value: boolean): 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 OperatorBuilder<T extends U> {
    create($: ExtensionEnv, config: Readonly<EnvConfig>): Operator<T>;
}
/**
 * Use to evaluate any kind of expression.
 * This is the means of extending the system to include other atoms.
 * Every object in the system is an opaque handle.
 */
interface Operator<T extends U> {
    readonly name?: string;
    /**
     * Determines which expressions this operator matches.
     */
    readonly hash: string;
    /**
     * Determines whether this operator is for evaluating list expressions.
     */
    iscons(): this is Operator<Cons>;
    /**
     * The symbol that this operator represents.
     *
     * i.e. (operator arg0 arg1 ...)
     *
     * If this operator is not for list expressions, the implementation should throw an error.
     */
    operator(): Sym | never;
    /**
     * Determines the modes in which this operator is active.
     */
    readonly phases?: number;
    /**
     *
     */
    readonly dependencies?: FEATURE[];
    /**
     * Determines whether this operator can be used to evaluate the expression.
     */
    isKind(expr: U): expr is T;
    subst(expr: T, oldExpr: U, newExpr: U): U;
    toInfixString(expr: T): string;
    toLatexString(expr: T): string;
    toListString(expr: T): string;
    /**
     * Applies the procedure managed by this extension to the argList.
     * @param argList
     */
    evaluate(opr: T, argList: Cons): [TFLAGS, U];
    /**
     * Evaluates the expression and also returns some information about the returned expression.
     */
    transform(expr: T): [TFLAGS, U];
    /**
     * Evaluates the expression.
     */
    valueOf(expr: T): U;
}
interface Extension<T extends U> {
    readonly hash: string;
    readonly name: string;
    readonly phases?: number;
    readonly dependencies?: FEATURE[];
    iscons(): this is Extension<Cons>;
    operator(): Sym;
    isKind(expr: U, $: ExtensionEnv): boolean;
    subst(expr: T, oldExpr: U, newExpr: U, $: ExtensionEnv): U;
    toInfixString(expr: T, $: ExtensionEnv): string;
    toLatexString(expr: T, $: ExtensionEnv): string;
    toListString(expr: T, $: ExtensionEnv): string;
    evaluate(expr: T, argList: Cons, $: ExtensionEnv): [TFLAGS, U];
    transform(expr: T, $: ExtensionEnv): [TFLAGS, U];
    valueOf(expr: T, $: ExtensionEnv): U;
}

interface ParseConfig {
    useCaretForExponentiation: boolean;
    useParenForTensors: boolean;
}
interface RenderConfig {
    format: 'Ascii' | 'Human' | 'Infix' | 'LaTeX' | 'SExpr' | 'SVG';
    useCaretForExponentiation: boolean;
    useParenForTensors: boolean;
}
declare enum Concept {
    Last = 1,
    TTY = 2
}
interface AtomListener {
    reset(from: U, to: U, source: Cell): void;
}
interface ExprEngineListener {
    output(output: string): void;
}
interface ExprEngine {
    clearBindings(): void;
    executeProlog(prolog: string[]): void;
    executeScript(sourceText: string): {
        values: U[];
        prints: string[];
        errors: Error[];
    };
    defineFunction(name: Sym, lambda: LambdaExpr): void;
    parse(sourceText: string, options?: Partial<ParseConfig>): {
        trees: U[];
        errors: Error[];
    };
    parseModule(sourceText: string, options?: Partial<ParseConfig>): {
        module: Cons;
        errors: Error[];
    };
    valueOf(expr: U): U;
    getBinding(sym: Sym): U;
    hasBinding(sym: Sym): boolean;
    setBinding(sym: Sym, binding: U): void;
    hasUserFunction(sym: Sym): boolean;
    getUserFunction(sym: Sym): U;
    setUserFunction(sym: Sym, usrfunc: U): void;
    symbol(concept: Concept): Sym;
    renderAsString(expr: U, config?: Partial<RenderConfig>): string;
    addAtomListener(listener: AtomListener): void;
    removeAtomListener(listener: AtomListener): void;
    addListener(listener: ExprEngineListener): void;
    removeListener(listener: ExprEngineListener): void;
    release(): void;
}
/**
 * Determines the action upon attempts to access an undeclared variable.
 */
declare enum UndeclaredVars {
    Err = 1,// ClojureScript
    Nil = 2
}
interface EngineConfig {
    allowUndeclaredVars: UndeclaredVars;
    prolog: string[];
    syntaxKind: SyntaxKind;
    useCaretForExponentiation: boolean;
    useDerivativeShorthandLowerD: boolean;
    useIntegersForPredicates: boolean;
}
declare function create_engine(options?: Partial<EngineConfig>): ExprEngine;

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;
    /**
     * Determines what kind of parser is used for the sourceText.
     */
    syntaxKind?: SyntaxKind;
}
interface ScriptContextOptions extends ScriptExecuteOptions {
    /**
     * The default is ???.
     */
    allowUndeclaredVars?: UndeclaredVars;
    /**
     * 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;
    /**
     *
     */
    prolog?: string[];
    /**
     * 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;
}
interface ScriptContext {
    readonly $: ExtensionEnv;
    clearBindings(): void;
    defineFunction(pattern: U, impl: LambdaExpr): void;
    getSymbolProps(sym: Sym): Predicates;
    getBinding(sym: Sym): U;
    getSymbolsInfo(): {
        sym: Sym;
        value: U;
    }[];
    evaluate(tree: U, options?: ExprTransformOptions): {
        value: U;
        prints: string[];
        errors: Error[];
    };
    executeProlog(prolog: string[]): void;
    executeScript(sourceText: string, options?: ScriptExecuteOptions): {
        values: U[];
        prints: string[];
        errors: Error[];
    };
    renderAsAscii(expr: U): string;
    renderAsHuman(expr: U): string;
    renderAsInfix(expr: U): string;
    renderAsLaTeX(expr: U): string;
    renderAsSExpr(expr: U): string;
    addRef(): void;
    release(): void;
}
/**
 * TODO: The REP should migrate toward the ExprEngine API.
 * @deprecated Used only by development REPL.
 */
declare function create_script_context(contextOptions?: ScriptContextOptions): ScriptContext;

export { type AtomListener, Concept, type EngineConfig, type ExprEngine, type ExprEngineListener, type FEATURE, type ParseConfig, type RenderConfig, type Scope, Stack, State, Stepper, type StepperConfig, type StepperHandler, SyntaxKind, Thing, UndeclaredVars, create_engine, create_script_context, human_readable_syntax_kind, syntaxKinds };
