import type es from 'estree';
import { RuntimeSourceError } from '../errors/runtimeSourceError';
import type { Context, Environment, Node, StatementSequence, Value } from '../types';
import Closure from './closure';
import { type Control, Transformers } from './interpreter';
import { type ControlItem, type EnvArray, type Instr } from './types';
/**
 * Typeguard for commands to check if they are scheme values.
 *
 * @param command A ControlItem
 * @returns true if the ControlItem is a scheme value, false otherwise.
 */
export declare const isSchemeValue: (command: ControlItem) => boolean;
/**
 * Typeguard for Instr to distinguish between program statements and instructions.
 *
 * @param command A ControlItem
 * @returns true if the ControlItem is an instruction and false otherwise.
 */
export declare const isInstr: (command: ControlItem) => command is Instr;
/**
 * Typeguard for Node to distinguish between program statements and instructions.
 *
 * @param command A ControlItem
 * @returns true if the ControlItem is a Node or StatementSequence, false if it is an instruction.
 */
export declare const isNode: (command: ControlItem) => command is Node;
/**
 * Typeguard for esReturnStatement. To verify if a Node is an esReturnStatement.
 *
 * @param node a Node
 * @returns true if node is an esReturnStatement, false otherwise.
 */
export declare const isReturnStatement: (node: Node) => node is es.ReturnStatement;
/**
 * Typeguard for esIfStatement. To verify if a Node is an esIfStatement.
 *
 * @param node a Node
 * @returns true if node is an esIfStatement, false otherwise.
 */
export declare const isIfStatement: (node: Node) => node is es.IfStatement;
/**
 * Typeguard for esBlockStatement. To verify if a Node is a block statement.
 *
 * @param node a Node
 * @returns true if node is an esBlockStatement, false otherwise.
 */
export declare const isBlockStatement: (node: Node) => node is es.BlockStatement;
/**
 * Typeguard for StatementSequence. To verify if a ControlItem is a statement sequence.
 *
 * @param node a ControlItem
 * @returns true if node is a StatementSequence, false otherwise.
 */
export declare const isStatementSequence: (node: ControlItem) => node is StatementSequence;
/**
 * Typeguard for esRestElement. To verify if a Node is a block statement.
 *
 * @param node a Node
 * @returns true if node is an esRestElement, false otherwise.
 */
export declare const isRestElement: (node: Node) => node is es.RestElement;
/**
 * Generate a unique id, for use in environments, arrays and closures.
 *
 * @param context the context used to provide the new unique id
 * @returns a unique id
 */
export declare const uniqueId: (context: Context) => string;
/**
 * Returns whether `item` is an array with `id` and `environment` properties already attached.
 */
export declare const isEnvArray: (item: any) => item is EnvArray;
/**
 * Returns whether `item` is a non-closure function that returns a stream.
 * If the function has been called already and we have the result, we can
 * pass it in here as a 2nd argument for stronger checking
 */
export declare const isStreamFn: (item: any, result?: any) => result is [any, () => any];
/**
 * Adds the properties `id` and `environment` to the given array, and adds the array to the
 * current environment's heap. Adds the array to the heap of `envOverride` instead if it's defined.
 *
 * @param context the context used to provide the current environment and new unique id
 * @param array the array to attach properties to, and for addition to the heap
 */
export declare const handleArrayCreation: (context: Context, array: any[], envOverride?: Environment) => void;
/**
 * A helper function for handling sequences of statements.
 * Statements must be pushed in reverse order, and each statement is separated by a pop
 * instruction so that only the result of the last statement remains on stash.
 * Value producing statements have an extra pop instruction.
 *
 * @param seq Array of statements.
 * @returns Array of commands to be pushed into control.
 */
export declare const handleSequence: (seq: es.Program["body"]) => ControlItem[];
/**
 * This function is used for ConditionalExpressions and IfStatements, to create the sequence
 * of control items to be added.
 */
export declare const reduceConditional: (node: es.IfStatement | es.ConditionalExpression) => ControlItem[];
/**
 * To determine if a control item is value producing. JavaScript distinguishes value producing
 * statements and non-value producing statements.
 * Refer to https://sourceacademy.nus.edu.sg/sicpjs/4.1.2 exercise 4.8.
 *
 * @param command Control item to determine if it is value producing.
 * @returns true if it is value producing, false otherwise.
 */
export declare const valueProducing: (command: Node) => boolean;
/**
 * To determine if a control item changes the environment.
 * There is a change in the environment when
 *  1. pushEnvironment() is called when creating a new frame, if there are variable declarations.
 *     Called in Program, BlockStatement, and Application instructions.
 *  2. there is an assignment.
 *     Called in Assignment and Array Assignment instructions.
 *  3. a new object is created.
 *     Called in ExpressionStatement that contains an ArrowFunctionExpression, or an ArrowFunctionExpression
 *
 * @param command Control item to check against.
 * @returns true if it changes the environment, false otherwise.
 */
export declare const envChanging: (command: ControlItem) => boolean;
/**
 * To determine if the function is simple.
 * Simple functions contain a single return statement.
 *
 * @param node The function to check against.
 * @returns true if the function is simple, false otherwise.
 */
export declare const isSimpleFunction: (node: any) => boolean;
/**
 * Transformers
 */
export declare const currentTransformers: (context: Context) => Transformers;
export declare const setTransformers: (context: Context, transformers: Transformers) => void;
/**
 * Environments
 */
export declare const currentEnvironment: (context: Context) => Environment;
export declare const createEnvironment: (context: Context, closure: Closure, args: Value[], callExpression: es.CallExpression) => Environment;
export declare const popEnvironment: (context: Context) => Environment | undefined;
export declare const pushEnvironment: (context: Context, environment: Environment) => void;
export declare const createBlockEnvironment: (context: Context, name?: string) => Environment;
export declare const createProgramEnvironment: (context: Context, isPrelude: boolean) => Environment;
export declare function declareIdentifier(context: Context, name: string, node: Node, environment: Environment, constant?: boolean): Environment;
export declare function declareFunctionsAndVariables(context: Context, node: es.BlockStatement | es.Program, environment: Environment): void;
export declare function defineVariable(context: Context, name: string, value: Value, constant: boolean | undefined, node: es.VariableDeclaration | es.ImportDeclaration): Environment;
export declare const getVariable: (context: Context, name: string, node: es.Identifier) => any;
export declare const setVariable: (context: Context, name: string, value: any, node: es.AssignmentExpression) => undefined;
export declare const handleRuntimeError: (context: Context, error: RuntimeSourceError) => never;
export declare const checkNumberOfArguments: (context: Context, callee: Closure | Value, args: Value[], exp: es.CallExpression) => undefined;
/**
 * This function can be used to check for a stack overflow.
 * The current limit is set to be a control size of 1.0 x 10^5, if the control
 * flows beyond this limit an error is thrown.
 * This corresponds to about 10mb of space according to tests ran.
 */
export declare const checkStackOverFlow: (context: Context, control: Control) => void;
/**
 * Checks whether an `if` statement returns in every possible branch.
 * @param body The `if` statement to be checked
 * @return `true` if every branch has a return statement, else `false`.
 */
export declare const hasReturnStatementIf: (statement: es.IfStatement) => boolean;
/**
 * Checks whether a block returns in every possible branch.
 * @param body The block to be checked
 * @return `true` if every branch has a return statement, else `false`.
 */
export declare const hasReturnStatement: (block: es.BlockStatement | StatementSequence) => boolean;
/**
 * Checks whether a block OR any of its child blocks has a `break` statement.
 * @param body The block to be checked
 * @return `true` if there is a `break` statement, else `false`.
 */
export declare const hasBreakStatement: (block: es.BlockStatement | StatementSequence) => boolean;
/**
 * Checks whether a block OR any of its child blocks has a `continue` statement.
 * @param body The block to be checked
 * @return `true` if there is a `continue` statement, else `false`.
 */
export declare const hasContinueStatement: (block: es.BlockStatement | StatementSequence) => boolean;
/**
 * Checks whether the evaluation of the given control item depends on the current environment.
 * The item is also considered environment dependent if its evaluation introduces
 * environment dependent items
 * @param item The control item to be checked
 * @return `true` if the item is environment depedent, else `false`.
 */
export declare function isEnvDependent(item: ControlItem | null | undefined): boolean;
