UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

359 lines (358 loc) 11.1 kB
import { SourceLocation } from 'acorn'; import * as es from 'estree'; import { EnvTree } from './createContext'; import Heap from './cse-machine/heap'; import { Control, Stash, Transformers } from './cse-machine/interpreter'; import type { ModuleFunctions } from './modules/moduleTypes'; import { Representation } from './alt-langs/mapper'; /** * Defines functions that act as built-ins, but might rely on * different implementations. e.g display() in a web application. */ export interface CustomBuiltIns { rawDisplay: (value: Value, str: string, externalContext: any) => Value; prompt: (value: Value, str: string, externalContext: any) => string | null; alert: (value: Value, str: string, externalContext: any) => void; visualiseList: (list: any, externalContext: any) => void; } export declare enum ErrorType { IMPORT = "Import", RUNTIME = "Runtime", SYNTAX = "Syntax", TYPE = "Type" } export declare enum ErrorSeverity { WARNING = "Warning", ERROR = "Error" } export interface SourceError { type: ErrorType; severity: ErrorSeverity; location: es.SourceLocation; explain(): string; elaborate(): string; } export interface Comment { type: 'Line' | 'Block'; value: string; start: number; end: number; loc: SourceLocation | undefined; } export type ExecutionMethod = 'native' | 'auto' | 'cse-machine'; export declare enum Chapter { SOURCE_1 = 1, SOURCE_2 = 2, SOURCE_3 = 3, SOURCE_4 = 4, FULL_JS = -1, HTML = -2, FULL_TS = -3, PYTHON_1 = -4, PYTHON_2 = -5, PYTHON_3 = -6, PYTHON_4 = -7, FULL_PYTHON = -8, SCHEME_1 = -9, SCHEME_2 = -10, SCHEME_3 = -11, SCHEME_4 = -12, FULL_SCHEME = -13, FULL_C = -14, FULL_JAVA = -15, LIBRARY_PARSER = 100 } export declare enum Variant { DEFAULT = "default", TYPED = "typed", NATIVE = "native", WASM = "wasm", EXPLICIT_CONTROL = "explicit-control" } export type LanguageOptions = Record<string, string>; export interface Language { chapter: Chapter; variant: Variant; languageOptions?: LanguageOptions; } export type ValueWrapper = LetWrapper | ConstWrapper; export interface LetWrapper { kind: 'let'; getValue: () => Value; assignNewValue: <T>(newValue: T) => T; } export interface ConstWrapper { kind: 'const'; getValue: () => Value; } export interface NativeStorage { builtins: Map<string, Value>; previousProgramsIdentifiers: Set<string>; operators: Map<string, (...operands: Value[]) => Value>; maxExecTime: number; evaller: null | ((program: string) => Value); loadedModules: Record<string, ModuleFunctions>; loadedModuleTypes: Record<string, Record<string, string>>; } export interface Context<T = any> { /** The source version used */ chapter: Chapter; /** The external symbols that exist in the Context. */ externalSymbols: string[]; /** All the errors gathered */ errors: SourceError[]; /** Runtime Specific state */ runtime: { transformers?: Transformers; break: boolean; debuggerOn: boolean; isRunning: boolean; environmentTree: EnvTree; environments: Environment[]; nodes: Node[]; control: Control | null; stash: Stash | null; objectCount: number; envStepsTotal: number; breakpointSteps: number[]; changepointSteps: number[]; }; numberOfOuterEnvironments: number; prelude: string | null; /** the state of the debugger */ debugger: { /** External observers watching this context */ status: boolean; state: { it: IterableIterator<T>; }; }; /** * Used for storing external properties. * For e.g, this can be used to store some application-related * context for use in your own built-in functions (like `display(a)`) */ externalContext?: T; /** * Used for storing the native context and other values */ nativeStorage: NativeStorage; /** * Describes the language processor to be used for evaluation */ executionMethod: ExecutionMethod; /** * Describes the strategy / paradigm to be used for evaluation * Examples: concurrent */ variant: Variant; /** * Describes the custom language option to be used for evaluation */ languageOptions: LanguageOptions; /** * Contains the evaluated code that has not yet been typechecked. */ unTypecheckedCode: string[]; typeEnvironment: TypeEnvironment; /** * Storage container for module specific information and state */ moduleContexts: { [name: string]: ModuleContext; }; /** * Programs previously executed in this context */ previousPrograms: es.Program[]; /** * Whether the evaluation timeout should be increased */ shouldIncreaseEvaluationTimeout: boolean; } export type ModuleContext = { state: null | any; tabs: null | any[]; }; export interface BlockFrame { type: string; loc?: es.SourceLocation | null; enclosingLoc?: es.SourceLocation | null; children: (DefinitionNode | BlockFrame)[]; } export interface DefinitionNode { name: string; type: string; loc?: es.SourceLocation | null; } export interface Frame { [name: string]: any; } export type Value = any; export type AllowedDeclarations = 'const' | 'let'; export interface Environment { readonly id: string; name: string; tail: Environment | null; callExpression?: es.CallExpression; head: Frame; heap: Heap; thisContext?: Value; } export interface Error { status: 'error'; } export interface Finished { status: 'finished'; context: Context; value: Value; representation?: Representation; } export interface SuspendedCseEval { status: 'suspended-cse-eval'; context: Context; } export type Result = Finished | Error | SuspendedCseEval; /** * StatementSequence : A sequence of statements not surrounded by braces. * It is *not* a block, and thus does not trigger environment creation when evaluated. * * The current ESTree specification does not have this node type, so we define it here. */ export interface StatementSequence extends es.BaseStatement { type: 'StatementSequence'; body: Array<es.Statement>; innerComments?: Array<Comment> | undefined; } /** * js-slang's custom Node type - this should be used wherever es.Node is used. */ export type Node = { isEnvDependent?: boolean; } & (es.Node | StatementSequence | es.MaybeNamedClassDeclaration | es.MaybeNamedFunctionDeclaration); export interface Directive extends es.ExpressionStatement { type: 'ExpressionStatement'; expression: es.Literal; directive: string; } /** For use in the substituter, to differentiate between a function declaration in the expression position, * which has an id, as opposed to function expressions. */ export interface FunctionDeclarationExpression extends es.FunctionExpression { id: es.Identifier; body: es.BlockStatement; } /** * For use in the substituter: call expressions can be reduced into an expression if the block * only contains a single return statement; or a block, but has to be in the expression position. * This is NOT compliant with the ES specifications, just as an intermediate step during substitutions. */ export interface BlockExpression extends es.BaseExpression { type: 'BlockExpression'; body: es.Statement[]; } export type substituterNodes = Node | BlockExpression; export { Instruction as SVMInstruction, Program as SVMProgram, Address as SVMAddress, Argument as SVMArgument, Offset as SVMOffset, SVMFunction } from './vm/svml-compiler'; export type ContiguousArrayElementExpression = Exclude<es.ArrayExpression['elements'][0], null>; export type ContiguousArrayElements = ContiguousArrayElementExpression[]; export type PrimitiveType = 'boolean' | 'null' | 'number' | 'string' | 'undefined'; export type TSAllowedTypes = 'any' | 'void'; export declare const disallowedTypes: readonly ["bigint", "never", "object", "symbol", "unknown"]; export type TSDisallowedTypes = (typeof disallowedTypes)[number]; export type TSBasicType = PrimitiveType | TSAllowedTypes | TSDisallowedTypes; export type NodeWithInferredType<T extends Node> = InferredType & T; export type FuncDeclWithInferredTypeAnnotation = NodeWithInferredType<es.FunctionDeclaration> & TypedFuncDecl; export type InferredType = Untypable | Typed | NotYetTyped; export interface TypedFuncDecl { functionInferredType?: Type; } export interface Untypable { typability?: 'Untypable'; inferredType?: Type; } export interface NotYetTyped { typability?: 'NotYetTyped'; inferredType?: Type; } export interface Typed { typability?: 'Typed'; inferredType?: Type; } export type Constraint = 'none' | 'addable'; export type Type = Primitive | Variable | FunctionType | List | Pair | SArray | UnionType | LiteralType; export interface Primitive { kind: 'primitive'; name: PrimitiveType | TSAllowedTypes; value?: string | number | boolean; } export interface Variable { kind: 'variable'; name: string; constraint: Constraint; typeArgs?: Type[]; } export interface FunctionType { kind: 'function'; parameterTypes: Type[]; returnType: Type; } export interface List { kind: 'list'; elementType: Type; typeAsPair?: Pair; } export interface Pair { kind: 'pair'; headType: Type; tailType: Type; } export interface SArray { kind: 'array'; elementType: Type; } export interface UnionType { kind: 'union'; types: Type[]; } export interface LiteralType { kind: 'literal'; value: string | number | boolean; } export type BindableType = Type | ForAll | PredicateType; export interface ForAll { kind: 'forall'; polyType: Type; typeParams?: Variable[]; } export interface PredicateType { kind: 'predicate'; ifTrueType: Type | ForAll; } export type PredicateTest = { node: NodeWithInferredType<es.CallExpression>; ifTrueType: Type | ForAll; argVarName: string; }; /** * Each element in the TypeEnvironment array represents a different scope * (e.g. first element is the global scope, last element is the closest). * Within each scope, variable types/declaration kinds, as well as type aliases, are stored. */ export type TypeEnvironment = { typeMap: Map<string, BindableType>; declKindMap: Map<string, AllowedDeclarations>; typeAliasMap: Map<string, Type | ForAll>; }[]; /** * Helper type to recursively make properties that are also objects * partial * * By default, `Partial<Array<T>>` is equivalent to `Array<T | undefined>`. For this type, `Array<T>` will be * transformed to Array<Partial<T>> instead */ export type RecursivePartial<T> = T extends Array<any> ? Array<RecursivePartial<T[number]>> : T extends Record<any, any> ? Partial<{ [K in keyof T]: RecursivePartial<T[K]>; }> : T; export type NodeTypeToNode<T extends Node['type']> = Extract<Node, { type: T; }>;