js-slang
Version:
Javascript-based implementations of Source, written in Typescript
206 lines (205 loc) • 9.99 kB
TypeScript
import * as es from 'estree';
import { Context } from '..';
import { RuntimeSourceError } from '../errors/runtimeSourceError';
import { type Environment, type Node, type StatementSequence, type Value } from '../types';
import { Control, Transformers } from './interpreter';
import { EnvArray, ControlItem, Instr } from './types';
import Closure from './closure';
/**
* 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 esIdentifier. To verify if a Node is an esIdentifier.
*
* @param node a Node
* @returns true if node is an esIdentifier, false otherwise.
*/
export declare const isIdentifier: (node: Node) => node is es.Identifier;
/**
* 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.Statement[]) => 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, environment: Environment): void;
export declare function hasDeclarations(node: es.BlockStatement): boolean;
export declare function hasImportDeclarations(node: es.BlockStatement): boolean;
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;
export declare const hasBreakStatementIf: (statement: es.IfStatement) => 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;
export declare const hasContinueStatementIf: (statement: es.IfStatement) => 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;