import type { DeepReadonly } from 'ts-essentials';
import type { RNode } from '../model';
import type { RNumber } from '../nodes/r-number';
import type { RString } from '../nodes/r-string';
import type { RLogical } from '../nodes/r-logical';
import type { RSymbol } from '../nodes/r-symbol';
import type { RAccess } from '../nodes/r-access';
import type { RBinaryOp } from '../nodes/r-binary-op';
import type { RPipe } from '../nodes/r-pipe';
import type { RUnaryOp } from '../nodes/r-unary-op';
import type { RFunctionCall } from '../nodes/r-function-call';
import { EmptyArgument } from '../nodes/r-function-call';
import type { RForLoop } from '../nodes/r-for-loop';
import type { RWhileLoop } from '../nodes/r-while-loop';
import type { RRepeatLoop } from '../nodes/r-repeat-loop';
import type { RNext } from '../nodes/r-next';
import type { RBreak } from '../nodes/r-break';
import type { RComment } from '../nodes/r-comment';
import type { RLineDirective } from '../nodes/r-line-directive';
import type { RIfThenElse } from '../nodes/r-if-then-else';
import type { RExpressionList } from '../nodes/r-expression-list';
import type { RFunctionDefinition } from '../nodes/r-function-definition';
import type { RArgument } from '../nodes/r-argument';
import type { RParameter } from '../nodes/r-parameter';
/**
 * Called during the down-pass, will pe propagated to children and used in the up-pass (see {@link StatefulFoldFunctions}).
 * <p>
 * Exists for leafs as well for consistency reasons.
 */
export type DownFold<Info, Down> = (node: RNode<Info>, down: Down) => Down;
/**
 * All fold functions besides `down` are called after the down-pass in conventional fold-fashion.
 * The `down` argument holds information obtained during the down-pass, issued by the `down` function.
 */
export interface StatefulFoldFunctions<Info, Down, Up> {
    down: DownFold<Info, Down>;
    foldNumber: (num: RNumber<Info>, down: Down) => Up;
    foldString: (str: RString<Info>, down: Down) => Up;
    foldLogical: (logical: RLogical<Info>, down: Down) => Up;
    foldSymbol: (symbol: RSymbol<Info>, down: Down) => Up;
    foldAccess: (node: RAccess<Info>, name: Up, access: readonly (typeof EmptyArgument | Up)[], down: Down) => Up;
    foldBinaryOp: (op: RBinaryOp<Info>, lhs: Up, rhs: Up, down: Down) => Up;
    foldPipe: (op: RPipe<Info>, lhs: Up, rhs: Up, down: Down) => Up;
    foldUnaryOp: (op: RUnaryOp<Info>, operand: Up, down: Down) => Up;
    loop: {
        foldFor: (loop: RForLoop<Info>, variable: Up, vector: Up, body: Up, down: Down) => Up;
        foldWhile: (loop: RWhileLoop<Info>, condition: Up, body: Up, down: Down) => Up;
        foldRepeat: (loop: RRepeatLoop<Info>, body: Up, down: Down) => Up;
        foldNext: (next: RNext<Info>, down: Down) => Up;
        foldBreak: (next: RBreak<Info>, down: Down) => Up;
    };
    other: {
        foldComment: (comment: RComment<Info>, down: Down) => Up;
        foldLineDirective: (comment: RLineDirective<Info>, down: Down) => Up;
    };
    /** The `otherwise` argument is `undefined` if the `else` branch is missing */
    foldIfThenElse: (ifThenExpr: RIfThenElse<Info>, cond: Up, then: Up, otherwise: Up | undefined, down: Down) => Up;
    foldExprList: (exprList: RExpressionList<Info>, grouping: [start: Up, end: Up] | undefined, expressions: Up[], down: Down) => Up;
    functions: {
        foldFunctionDefinition: (definition: RFunctionDefinition<Info>, params: Up[], body: Up, down: Down) => Up;
        /** folds named and unnamed function calls */
        foldFunctionCall: (call: RFunctionCall<Info>, functionNameOrExpression: Up, args: (Up | typeof EmptyArgument)[], down: Down) => Up;
        /** The `name` is `undefined` if the argument is unnamed, the value, if we have something like `x=,...` */
        foldArgument: (argument: RArgument<Info>, name: Up | undefined, value: Up | undefined, down: Down) => Up;
        /** The `defaultValue` is `undefined` if the argument was not initialized with a default value */
        foldParameter: (parameter: RParameter<Info>, name: Up, defaultValue: Up | undefined, down: Down) => Up;
    };
}
/**
 * Folds in old functional-fashion over the AST structure but allowing for a down function which can pass context to child nodes.
 */
export declare function foldAstStateful<Info, Down, Up>(ast: RNode<Info>, down: Down, folds: DeepReadonly<StatefulFoldFunctions<Info, Down, Up>>): Up;
