diff --git a/packages/codemode/AGENTS.md b/packages/codemode/AGENTS.md index 47228beb77c..66f962e081e 100644 --- a/packages/codemode/AGENTS.md +++ b/packages/codemode/AGENTS.md @@ -1,5 +1,6 @@ # @opencode/codemode - `interpreter-support.md` is a checklist, not a changelog: check off newly added support and add unchecked items for significant gaps. Leave it alone for fixes and refactors. -- Program values are `Value` (`src/vm/runtime/objects.ts`). Host values are `unknown` and enter only through `fromHost` and `fromJson`; do not widen program-facing signatures to `unknown`. +- Program values are `Value` (`src/runtime/objects.ts`). Host values are `unknown` and enter only through `fromHost` and `fromJson`; do not widen program-facing signatures to `unknown`. - Each built-in object kind is one `Obj` subclass (`Wrapper` or `Opaque`) that overrides the hooks it needs. Ask the object instead of adding `instanceof` ladders. +- The core VM, compiler, prelude, snapshot, and stdlib modules must not import `effect`; Effect lives only in the host boundary and driver (`src/runtime/`, `src/openapi/`, and the top-level tool/runtime entrypoints). diff --git a/packages/codemode/README.md b/packages/codemode/README.md index 8b429a54edf..f5a2730f67f 100644 --- a/packages/codemode/README.md +++ b/packages/codemode/README.md @@ -246,7 +246,7 @@ Every value crossing in either direction is converted, never shared: arguments c copies, and a function inside a result is callable the same way. A global that shadows a built-in or another extension throws at `CodeMode.make`. -Functions inside a result have no data form, so a suspended VM run loses them by default: after a resume, calling one +Functions inside a result have no data form, so a suspended run loses them by default: after a resume, calling one throws a `TypeError`. An extension can preserve them across suspend and resume with `snapshot` hooks. `encode` receives a value one of the extension's functions returned, as the host function returned it, and returns plain data (JSON values and `Uint8Array`s); on resume, `decode` receives that data once per value and returns a host value of the same diff --git a/packages/codemode/script/bench.ts b/packages/codemode/script/bench.ts index 1940316ee73..0d9027846b6 100644 --- a/packages/codemode/script/bench.ts +++ b/packages/codemode/script/bench.ts @@ -6,7 +6,7 @@ import { numberOfDFGCompiles, reoptimizationRetryCount } from "bun:jsc" import { Effect, Schema } from "effect" import { CodeMode, Tool } from "../src/index.js" -import { Vm } from "../src/vm/vm.js" +import { Vm } from "../src/vm.js" const cases: ReadonlyArray = [ [ diff --git a/packages/codemode/script/disasm.ts b/packages/codemode/script/disasm.ts index 1d031790042..d3e114270ff 100644 --- a/packages/codemode/script/disasm.ts +++ b/packages/codemode/script/disasm.ts @@ -1,9 +1,9 @@ #!/usr/bin/env bun // The bytecode disassembler: pcs, ops, constants, handler and finally tables, local names, source lines. -import { sourceLocation } from "../src/vm/runtime/model.js" -import type { Code } from "../src/vm/code.js" -import { compileSource } from "../src/vm/compiler/compile.js" +import { sourceLocation } from "../src/runtime/model.js" +import type { Code } from "../src/code.js" +import { compileSource } from "../src/compiler/compile.js" import { BinOpSymbols, CheckBaseKind, @@ -13,8 +13,8 @@ import { OpNames, PutKind, UnaryOpSymbols, -} from "../src/vm/opcodes.js" -import { parseProgram } from "../src/vm/runtime/execute.js" +} from "../src/opcodes.js" +import { parseProgram } from "../src/runtime/execute.js" const formatFlags = (flags: number): string => { const names: Array = [] diff --git a/packages/codemode/script/prelude.ts b/packages/codemode/script/prelude.ts index ca4c5c92587..b57e1ff0783 100644 --- a/packages/codemode/script/prelude.ts +++ b/packages/codemode/script/prelude.ts @@ -1,15 +1,15 @@ #!/usr/bin/env bun -// Compiles the built-in sources (the prelude, the VM's internal helpers) ahead of time into src/vm/prelude/bytecode.json, -// which a process loads instead of parsing and compiling them (see src/vm/prelude/bytecode.ts). Run it after changing -// either source or the compiler; test/vm/prelude-bytecode.test.ts fails until then. +// Compiles the built-in sources (the prelude, the VM's internal helpers) ahead of time into src/prelude/bytecode.json, +// which a process loads instead of parsing and compiling them (see src/prelude/bytecode.ts). Run it after changing +// either source or the compiler; test/prelude-bytecode.test.ts fails until then. import { parse } from "acorn" -import { Source } from "../src/vm/runtime/source.js" -import { saveCodes } from "../src/vm/prelude/bytecode.js" -import { code } from "../src/vm/prelude/source.js" -import { compileSource } from "../src/vm/compiler/compile.js" -import { INTERNAL_SOURCE } from "../src/vm/internal-prelude.js" +import { Source } from "../src/runtime/source.js" +import { saveCodes } from "../src/prelude/bytecode.js" +import { code } from "../src/prelude/source.js" +import { compileSource } from "../src/compiler/compile.js" +import { INTERNAL_SOURCE } from "../src/internal-prelude.js" export const compileBuiltins = () => Object.fromEntries( @@ -23,5 +23,5 @@ export const compileBuiltins = () => ) if (import.meta.main) { - await Bun.write(new URL("../src/vm/prelude/bytecode.json", import.meta.url), `${JSON.stringify(compileBuiltins())}\n`) + await Bun.write(new URL("../src/prelude/bytecode.json", import.meta.url), `${JSON.stringify(compileBuiltins())}\n`) } diff --git a/packages/codemode/script/setup.ts b/packages/codemode/script/setup.ts index 03459c5140a..49603b79586 100644 --- a/packages/codemode/script/setup.ts +++ b/packages/codemode/script/setup.ts @@ -5,8 +5,8 @@ import { Effect } from "effect" import { CodeMode } from "../src/index.js" -import { Interpreter } from "../src/vm/runtime/interpreter.js" -import { createBuiltins } from "../src/vm/runtime/intrinsics.js" +import { Interpreter } from "../src/runtime/interpreter.js" +import { createBuiltins } from "../src/runtime/intrinsics.js" import { ToolRuntime } from "../src/tool-runtime.js" const index = process.argv.indexOf("--iterations") diff --git a/packages/codemode/src/vm/async.ts b/packages/codemode/src/async.ts similarity index 99% rename from packages/codemode/src/vm/async.ts rename to packages/codemode/src/async.ts index 9a323ee02f4..3eae192d5be 100644 --- a/packages/codemode/src/vm/async.ts +++ b/packages/codemode/src/async.ts @@ -1,4 +1,4 @@ -import type { Diagnostic } from "../codemode.js" +import type { Diagnostic } from "./codemode.js" import { normalizeError, locate } from "./runtime/errors.js" import { MAX_PENDING_PROMISES } from "./runtime/limits.js" import { type AstNode, IteratorSymbol, rangeError, typeError } from "./runtime/model.js" diff --git a/packages/codemode/src/vm/code.ts b/packages/codemode/src/code.ts similarity index 100% rename from packages/codemode/src/vm/code.ts rename to packages/codemode/src/code.ts diff --git a/packages/codemode/src/codemode.ts b/packages/codemode/src/codemode.ts index 219808df170..3e64f89b2fc 100644 --- a/packages/codemode/src/codemode.ts +++ b/packages/codemode/src/codemode.ts @@ -3,11 +3,11 @@ import type { Extension } from "./extension.js" import { scanTools } from "./scan.js" import { type Services, type ToolDescription, ToolRuntime } from "./tool-runtime.js" import type { Tools } from "./tools.js" -import { fromJson } from "./vm/data.js" -import { finishExecution, resumeProgram, type Running, type Setup, startProgram, SuspendError } from "./vm/runtime/execute.js" -import { extensionGlobals } from "./vm/runtime/extensions.js" -import { globalNames } from "./vm/runtime/globals.js" -import { fromBytes, type Snapshot, SnapshotError, type SnapshotHeader, toBytes } from "./vm/snapshot/snapshot.js" +import { fromJson } from "./data.js" +import { finishExecution, resumeProgram, type Running, type Setup, startProgram, SuspendError } from "./runtime/execute.js" +import { extensionGlobals } from "./runtime/extensions.js" +import { globalNames } from "./runtime/globals.js" +import { fromBytes, type Snapshot, SnapshotError, type SnapshotHeader, toBytes } from "./snapshot/snapshot.js" export { fromBytes, scanTools, SnapshotError, SuspendError, toBytes } export type { Snapshot, SnapshotHeader } @@ -173,7 +173,7 @@ export type Runtime = { } /** - * One run of a program on the VM. `run()` runs it in the current fiber until it ends or is suspended, and owns its host + * One run of a program. `run()` runs it in the current fiber until it ends or is suspended, and owns its host * calls: interrupting `run()` interrupts them. A program runs once: running it again is a defect. */ export type Program = { diff --git a/packages/codemode/src/vm/compiler/compile.ts b/packages/codemode/src/compiler/compile.ts similarity index 100% rename from packages/codemode/src/vm/compiler/compile.ts rename to packages/codemode/src/compiler/compile.ts diff --git a/packages/codemode/src/vm/compiler/scope.ts b/packages/codemode/src/compiler/scope.ts similarity index 100% rename from packages/codemode/src/vm/compiler/scope.ts rename to packages/codemode/src/compiler/scope.ts diff --git a/packages/codemode/src/vm/data.ts b/packages/codemode/src/data.ts similarity index 95% rename from packages/codemode/src/vm/data.ts rename to packages/codemode/src/data.ts index 8fabac36cc6..8a3dd2f1d32 100644 --- a/packages/codemode/src/vm/data.ts +++ b/packages/codemode/src/data.ts @@ -1,5 +1,3 @@ -export * as Data from "./data.js" - import type { Json } from "./snapshot/codec.js" import type { Interpreter } from "./runtime/interpreter.js" import { Arr, define, Obj, type Value } from "./runtime/objects.js" diff --git a/packages/codemode/src/extension.ts b/packages/codemode/src/extension.ts index 3c65a77afce..8ca6b9b8332 100644 --- a/packages/codemode/src/extension.ts +++ b/packages/codemode/src/extension.ts @@ -13,7 +13,7 @@ import type { Effect } from "effect" * promise of an asynchronous global and by throwing from a synchronous one. Functions inside a global object are * called the same way, named by their path (`fs.readFile`). * - * Programs can also `import` or `require` a global by its Node module name; see `interpreter/modules.ts`. + * Programs can also `import` or `require` a global by its Node module name; see `runtime/modules.ts`. */ export type Extension> = Readonly>> = { readonly name: string diff --git a/packages/codemode/src/vm/generators.ts b/packages/codemode/src/generators.ts similarity index 100% rename from packages/codemode/src/vm/generators.ts rename to packages/codemode/src/generators.ts diff --git a/packages/codemode/src/vm/host.ts b/packages/codemode/src/host.ts similarity index 99% rename from packages/codemode/src/vm/host.ts rename to packages/codemode/src/host.ts index 67b4fe737d7..d1fdc3fd594 100644 --- a/packages/codemode/src/vm/host.ts +++ b/packages/codemode/src/host.ts @@ -1,4 +1,4 @@ -import type { Diagnostic } from "../codemode.js" +import type { Diagnostic } from "./codemode.js" import { fromJson, type Json } from "./data.js" import { startExtensionCall } from "./runtime/extensions.js" import type { Interpreter } from "./runtime/interpreter.js" @@ -7,7 +7,7 @@ import { Arr, PromiseObj, type Value } from "./runtime/objects.js" import { promiseLike } from "./runtime/promises.js" import type { Completion } from "./runtime/signals.js" import { type ExtensionRequest, HostCall, type HostRequest, Resolving } from "./scheduler.js" -import type { ExtensionInvocation } from "../tool-runtime.js" +import type { ExtensionInvocation } from "./tool-runtime.js" import type { Code } from "./code.js" import { internalCode, tryFastBoundaryOrJson, VmIntrinsic } from "./internal-prelude.js" import { type FrameMode, Mode, type Vm } from "./vm.js" diff --git a/packages/codemode/src/vm/internal-prelude.ts b/packages/codemode/src/internal-prelude.ts similarity index 100% rename from packages/codemode/src/vm/internal-prelude.ts rename to packages/codemode/src/internal-prelude.ts diff --git a/packages/codemode/src/vm/opcodes.ts b/packages/codemode/src/opcodes.ts similarity index 99% rename from packages/codemode/src/vm/opcodes.ts rename to packages/codemode/src/opcodes.ts index 0f84a541fe9..d81ef7a6f9f 100644 --- a/packages/codemode/src/vm/opcodes.ts +++ b/packages/codemode/src/opcodes.ts @@ -1,4 +1,4 @@ -import type { DiagnosticKind } from "../codemode.js" +import type { DiagnosticKind } from "./codemode.js" import type { ErrorType } from "./runtime/intrinsics.js" /** Uninitialized lexical binding sentinel (temporal dead zone). */ diff --git a/packages/codemode/src/vm/prelude/bytecode.json b/packages/codemode/src/prelude/bytecode.json similarity index 100% rename from packages/codemode/src/vm/prelude/bytecode.json rename to packages/codemode/src/prelude/bytecode.json diff --git a/packages/codemode/src/vm/prelude/bytecode.ts b/packages/codemode/src/prelude/bytecode.ts similarity index 100% rename from packages/codemode/src/vm/prelude/bytecode.ts rename to packages/codemode/src/prelude/bytecode.ts diff --git a/packages/codemode/src/vm/prelude/helpers.ts b/packages/codemode/src/prelude/helpers.ts similarity index 99% rename from packages/codemode/src/vm/prelude/helpers.ts rename to packages/codemode/src/prelude/helpers.ts index f213fade8a9..1d02f065d84 100644 --- a/packages/codemode/src/vm/prelude/helpers.ts +++ b/packages/codemode/src/prelude/helpers.ts @@ -33,7 +33,7 @@ import { } from "../runtime/objects.js" import { builtinCursor, requireIteratorObject } from "../runtime/operations.js" import { containsOpaqueReference, describeValue, isOpaque } from "../runtime/references.js" -import { compareText } from "../../tool-runtime.js" +import { compareText } from "../tool-runtime.js" import { Invoke } from "../runtime/signals.js" // The prelude's privileged helpers: leaf built-ins (they never call program code) bound only in the prelude's scope. diff --git a/packages/codemode/src/vm/prelude/prelude.ts b/packages/codemode/src/prelude/prelude.ts similarity index 100% rename from packages/codemode/src/vm/prelude/prelude.ts rename to packages/codemode/src/prelude/prelude.ts diff --git a/packages/codemode/src/vm/prelude/source.ts b/packages/codemode/src/prelude/source.ts similarity index 100% rename from packages/codemode/src/vm/prelude/source.ts rename to packages/codemode/src/prelude/source.ts diff --git a/packages/codemode/src/vm/runtime/callback.ts b/packages/codemode/src/runtime/callback.ts similarity index 100% rename from packages/codemode/src/vm/runtime/callback.ts rename to packages/codemode/src/runtime/callback.ts diff --git a/packages/codemode/src/vm/runtime/driver.ts b/packages/codemode/src/runtime/driver.ts similarity index 99% rename from packages/codemode/src/vm/runtime/driver.ts rename to packages/codemode/src/runtime/driver.ts index f5e77e0e2d5..e9039c1d43f 100644 --- a/packages/codemode/src/vm/runtime/driver.ts +++ b/packages/codemode/src/runtime/driver.ts @@ -1,7 +1,7 @@ import { Cause, type Context, Effect, Exit, Fiber } from "effect" import type { Json } from "../data.js" import type { HostCall } from "../scheduler.js" -import { type ToolRuntime, toolExpression } from "../../tool-runtime.js" +import { type ToolRuntime, toolExpression } from "../tool-runtime.js" import { locate } from "./errors.js" import { PendingThrow } from "./model.js" import type { Vm } from "../vm.js" diff --git a/packages/codemode/src/vm/runtime/errors.ts b/packages/codemode/src/runtime/errors.ts similarity index 97% rename from packages/codemode/src/vm/runtime/errors.ts rename to packages/codemode/src/runtime/errors.ts index 83748ec9a1b..4e9ce352fc2 100644 --- a/packages/codemode/src/vm/runtime/errors.ts +++ b/packages/codemode/src/runtime/errors.ts @@ -1,6 +1,6 @@ -import type { Diagnostic } from "../../codemode.js" -import { ToolError } from "../../tool-error.js" -import { ToolRuntimeError } from "../../tool-runtime.js" +import type { Diagnostic } from "../codemode.js" +import { ToolError } from "../tool-error.js" +import { ToolRuntimeError } from "../tool-runtime.js" import { type AstNode, formatLocation, PendingThrow, Throw, sourceLocation } from "./model.js" import { containsRuntimeReference } from "./references.js" import { createErrorValue, type ErrorType, isErrorType } from "./intrinsics.js" diff --git a/packages/codemode/src/vm/runtime/execute.ts b/packages/codemode/src/runtime/execute.ts similarity index 97% rename from packages/codemode/src/vm/runtime/execute.ts rename to packages/codemode/src/runtime/execute.ts index f4e5c1c9af8..20bb53d9262 100644 --- a/packages/codemode/src/vm/runtime/execute.ts +++ b/packages/codemode/src/runtime/execute.ts @@ -1,8 +1,8 @@ import { parse, type Program } from "acorn" import { Cause, Deferred, Effect, Option, Schema } from "effect" -import type { DataValue, Diagnostic, Outcome, ResolvedExecutionLimits, Result, Suspended } from "../../codemode.js" +import type { DataValue, Diagnostic, Outcome, ResolvedExecutionLimits, Result, Suspended } from "../codemode.js" import { fromBytes, header, type Snapshot, SnapshotError, toBytes } from "../snapshot/snapshot.js" -import { ToolRuntime } from "../../tool-runtime.js" +import { ToolRuntime } from "../tool-runtime.js" import { normalizeError } from "./errors.js" import { createBuiltins } from "./intrinsics.js" import { Interpreter } from "./interpreter.js" @@ -47,17 +47,6 @@ export const finishExecution = (outcome: Effect.Effect): Ef } }) -export const executeProgram = ( - code: string, - prepared: ToolRuntime.Prepared, - limits: ResolvedExecutionLimits, - hooks: ToolRuntime.Hooks, - globals?: Globals, - bindings?: Globals, - lossy = false, -): Effect.Effect => - finishExecution(startProgram({ prepared, limits, hooks, globals, lossy }, code, bindings).run()) - /** A program ready to run on the VM: nothing runs until `run`. */ export const startProgram = ( setup: Setup, diff --git a/packages/codemode/src/vm/runtime/extensions.ts b/packages/codemode/src/runtime/extensions.ts similarity index 99% rename from packages/codemode/src/vm/runtime/extensions.ts rename to packages/codemode/src/runtime/extensions.ts index 1d335deba86..dc6f776f203 100644 --- a/packages/codemode/src/vm/runtime/extensions.ts +++ b/packages/codemode/src/runtime/extensions.ts @@ -1,6 +1,6 @@ import { Effect } from "effect" -import { type Extension, isAsync } from "../../extension.js" -import { hooked } from "../../tool-runtime.js" +import { type Extension, isAsync } from "../extension.js" +import { hooked } from "../tool-runtime.js" import { errorMessage, errorType } from "./errors.js" import type { Interpreter } from "./interpreter.js" import { createErrorValue } from "./intrinsics.js" diff --git a/packages/codemode/src/vm/runtime/generators.ts b/packages/codemode/src/runtime/generators.ts similarity index 100% rename from packages/codemode/src/vm/runtime/generators.ts rename to packages/codemode/src/runtime/generators.ts diff --git a/packages/codemode/src/vm/runtime/globals.ts b/packages/codemode/src/runtime/globals.ts similarity index 99% rename from packages/codemode/src/vm/runtime/globals.ts rename to packages/codemode/src/runtime/globals.ts index 6e5c3a31893..6909da9d0a1 100644 --- a/packages/codemode/src/vm/runtime/globals.ts +++ b/packages/codemode/src/runtime/globals.ts @@ -15,7 +15,7 @@ import { headersGlobal } from "../stdlib/headers.js" import { iteratorGlobals } from "../stdlib/iterator.js" import { coercion } from "../stdlib/value.js" import { base64Global, cryptoGlobal, structuredCloneGlobal } from "../stdlib/web.js" -import { ToolReference } from "../../tool-runtime.js" +import { ToolReference } from "../tool-runtime.js" import { errorGlobal } from "./errors.js" import { errorTypes } from "./intrinsics.js" import { constants, constructor, methods, native, receiver } from "./native.js" diff --git a/packages/codemode/src/vm/runtime/interpreter.ts b/packages/codemode/src/runtime/interpreter.ts similarity index 98% rename from packages/codemode/src/vm/runtime/interpreter.ts rename to packages/codemode/src/runtime/interpreter.ts index 8522a6e2b81..f546d804600 100644 --- a/packages/codemode/src/vm/runtime/interpreter.ts +++ b/packages/codemode/src/runtime/interpreter.ts @@ -1,4 +1,4 @@ -import type { ToolRuntime } from "../../tool-runtime.js" +import type { ToolRuntime } from "../tool-runtime.js" import type { ExtensionRequest } from "../scheduler.js" import type { HostBridge } from "../snapshot/codec.js" import { Vm } from "../vm.js" diff --git a/packages/codemode/src/vm/runtime/intrinsic-names.ts b/packages/codemode/src/runtime/intrinsic-names.ts similarity index 100% rename from packages/codemode/src/vm/runtime/intrinsic-names.ts rename to packages/codemode/src/runtime/intrinsic-names.ts diff --git a/packages/codemode/src/vm/runtime/intrinsics.ts b/packages/codemode/src/runtime/intrinsics.ts similarity index 100% rename from packages/codemode/src/vm/runtime/intrinsics.ts rename to packages/codemode/src/runtime/intrinsics.ts diff --git a/packages/codemode/src/vm/runtime/limits.ts b/packages/codemode/src/runtime/limits.ts similarity index 100% rename from packages/codemode/src/vm/runtime/limits.ts rename to packages/codemode/src/runtime/limits.ts diff --git a/packages/codemode/src/vm/runtime/model.ts b/packages/codemode/src/runtime/model.ts similarity index 98% rename from packages/codemode/src/vm/runtime/model.ts rename to packages/codemode/src/runtime/model.ts index bbdccc41ccf..e40187d78cb 100644 --- a/packages/codemode/src/vm/runtime/model.ts +++ b/packages/codemode/src/runtime/model.ts @@ -1,6 +1,6 @@ import type { Node } from "acorn" import type { ErrorType } from "./intrinsics.js" -import type { DiagnosticKind } from "../../codemode.js" +import type { DiagnosticKind } from "../codemode.js" import type { ErrorObj, Value } from "./objects.js" /** Any parsed node; the compiler narrows on `type`, and diagnostics read `loc`. */ diff --git a/packages/codemode/src/vm/runtime/modules.ts b/packages/codemode/src/runtime/modules.ts similarity index 100% rename from packages/codemode/src/vm/runtime/modules.ts rename to packages/codemode/src/runtime/modules.ts diff --git a/packages/codemode/src/vm/runtime/native.ts b/packages/codemode/src/runtime/native.ts similarity index 100% rename from packages/codemode/src/vm/runtime/native.ts rename to packages/codemode/src/runtime/native.ts diff --git a/packages/codemode/src/vm/runtime/objects.ts b/packages/codemode/src/runtime/objects.ts similarity index 99% rename from packages/codemode/src/vm/runtime/objects.ts rename to packages/codemode/src/runtime/objects.ts index cef4d7ae3af..ad09b37256b 100644 --- a/packages/codemode/src/vm/runtime/objects.ts +++ b/packages/codemode/src/runtime/objects.ts @@ -1,4 +1,4 @@ -import { ToolReference } from "../../tool-runtime.js" +import { ToolReference } from "../tool-runtime.js" import type { Builtins } from "./intrinsics.js" import { checkArrayLength } from "./limits.js" import { diff --git a/packages/codemode/src/vm/runtime/operations.ts b/packages/codemode/src/runtime/operations.ts similarity index 99% rename from packages/codemode/src/vm/runtime/operations.ts rename to packages/codemode/src/runtime/operations.ts index 01cf75ca039..93d772b72e8 100644 --- a/packages/codemode/src/vm/runtime/operations.ts +++ b/packages/codemode/src/runtime/operations.ts @@ -1,5 +1,5 @@ import type { Expression, MemberExpression, NewExpression, Super } from "acorn" -import { ToolReference } from "../../tool-runtime.js" +import { ToolReference } from "../tool-runtime.js" import { type AstNode, invalidData, typeError } from "./model.js" import { checkStringLength } from "./limits.js" import { locate } from "./errors.js" diff --git a/packages/codemode/src/vm/runtime/promises.ts b/packages/codemode/src/runtime/promises.ts similarity index 100% rename from packages/codemode/src/vm/runtime/promises.ts rename to packages/codemode/src/runtime/promises.ts diff --git a/packages/codemode/src/vm/runtime/references.ts b/packages/codemode/src/runtime/references.ts similarity index 97% rename from packages/codemode/src/vm/runtime/references.ts rename to packages/codemode/src/runtime/references.ts index 05cf8427f6e..c2c4a25bcd5 100644 --- a/packages/codemode/src/vm/runtime/references.ts +++ b/packages/codemode/src/runtime/references.ts @@ -1,4 +1,4 @@ -import { ToolReference } from "../../tool-runtime.js" +import { ToolReference } from "../tool-runtime.js" import { invalidData } from "./model.js" import { Callable, getOwn, isRuntimeReference, Obj, Opaque, ownKeys, type Value } from "./objects.js" diff --git a/packages/codemode/src/vm/runtime/signals.ts b/packages/codemode/src/runtime/signals.ts similarity index 100% rename from packages/codemode/src/vm/runtime/signals.ts rename to packages/codemode/src/runtime/signals.ts diff --git a/packages/codemode/src/vm/runtime/source.ts b/packages/codemode/src/runtime/source.ts similarity index 100% rename from packages/codemode/src/vm/runtime/source.ts rename to packages/codemode/src/runtime/source.ts diff --git a/packages/codemode/src/vm/runtime/table.ts b/packages/codemode/src/runtime/table.ts similarity index 100% rename from packages/codemode/src/vm/runtime/table.ts rename to packages/codemode/src/runtime/table.ts diff --git a/packages/codemode/src/scan.ts b/packages/codemode/src/scan.ts index 4313acb11c4..3e6d499e331 100644 --- a/packages/codemode/src/scan.ts +++ b/packages/codemode/src/scan.ts @@ -1,8 +1,8 @@ import type { AnyNode, BlockStatement, ModuleDeclaration, Pattern, Program, Statement } from "acorn" import { Result } from "effect" import type { Diagnostic } from "./codemode.js" -import { parseProgram } from "./vm/runtime/execute.js" -import { formatLocation } from "./vm/runtime/model.js" +import { parseProgram } from "./runtime/execute.js" +import { formatLocation } from "./runtime/model.js" /** * Extracts every `tools.` referenced by a Code Mode program, in first-seen order. Fails on syntax errors, diff --git a/packages/codemode/src/vm/scheduler.ts b/packages/codemode/src/scheduler.ts similarity index 99% rename from packages/codemode/src/vm/scheduler.ts rename to packages/codemode/src/scheduler.ts index 9de0cddd576..3d372013db8 100644 --- a/packages/codemode/src/vm/scheduler.ts +++ b/packages/codemode/src/scheduler.ts @@ -1,5 +1,5 @@ import type { Json } from "./data.js" -import type { ExtensionInvocation } from "../tool-runtime.js" +import type { ExtensionInvocation } from "./tool-runtime.js" import { locate } from "./runtime/errors.js" import type { AstNode } from "./runtime/model.js" import type { Callable, Cursor, GeneratorObj, Obj, PromiseObj, Value } from "./runtime/objects.js" diff --git a/packages/codemode/src/vm/snapshot.ts b/packages/codemode/src/snapshot.ts similarity index 99% rename from packages/codemode/src/vm/snapshot.ts rename to packages/codemode/src/snapshot.ts index a61d0e920eb..cc8c5b7835e 100644 --- a/packages/codemode/src/vm/snapshot.ts +++ b/packages/codemode/src/snapshot.ts @@ -1,4 +1,4 @@ -import packageJson from "../../package.json" with { type: "json" } +import packageJson from "../package.json" with { type: "json" } import type { Interruption } from "./runtime/signals.js" import { staticNames, unchanged } from "./runtime/intrinsic-names.js" import { Fn, Obj } from "./runtime/objects.js" diff --git a/packages/codemode/src/vm/snapshot/codec.ts b/packages/codemode/src/snapshot/codec.ts similarity index 98% rename from packages/codemode/src/vm/snapshot/codec.ts rename to packages/codemode/src/snapshot/codec.ts index f48a0291879..4345a199dfa 100644 --- a/packages/codemode/src/vm/snapshot/codec.ts +++ b/packages/codemode/src/snapshot/codec.ts @@ -39,8 +39,8 @@ import { deleted, OrderedTable } from "../runtime/table.js" import { AsyncFromSyncIterator } from "../generators.js" import { HostCall, Resolving } from "../scheduler.js" import { TextDecoderObj } from "../stdlib/bytes.js" -import { ToolError, toolError } from "../../tool-error.js" -import { ToolReference, ToolRuntimeError } from "../../tool-runtime.js" +import { ToolError, toolError } from "../tool-error.js" +import { ToolReference, ToolRuntimeError } from "../tool-runtime.js" // A graph codec for a run's state: every object reachable from the roots becomes one record, so identity, sharing, // and cycles survive, and every value inside a record is tagged JSON. Built-ins, AST nodes, bytecode, and the VM's @@ -57,7 +57,7 @@ export type Json = null | boolean | number | string | ReadonlyArray | { re * - `["s", name]` an interpreter symbol; * - `["i", name]` a built-in or host global, unchanged since the runtime was made; * - `["a", source, index]` an AST node (a call site, an error's location); - * - `["x", data]` something the engine names itself (the VM's compiled code, by source and function index); + * - `["x", data]` something the VM names itself (compiled code, by source and function index); * - `["r", id]` another record. */ export type Encoded = string | number | boolean | null | ReadonlyArray @@ -110,9 +110,9 @@ export type EncodeEnv = { readonly lost: Array readonly strict: boolean readonly hosts?: HostBridge | undefined - /** More classes to save, an engine's own (the VM's frames and closures), after the built-in ones. */ + /** More classes to save (the VM's frames and closures), after the built-in ones. */ readonly specs?: ReadonlyArray | undefined - /** The data an engine names an object or symbol by, saved as `["x", data]`, instead of copying it. */ + /** The data the VM names an object or symbol by, saved as `["x", data]`, instead of copying it. */ readonly external?: ((value: object | symbol) => Json | undefined) | undefined } diff --git a/packages/codemode/src/vm/snapshot/snapshot.ts b/packages/codemode/src/snapshot/snapshot.ts similarity index 97% rename from packages/codemode/src/vm/snapshot/snapshot.ts rename to packages/codemode/src/snapshot/snapshot.ts index 238bafdff4f..c911ac61f79 100644 --- a/packages/codemode/src/vm/snapshot/snapshot.ts +++ b/packages/codemode/src/snapshot/snapshot.ts @@ -1,5 +1,5 @@ import type { Interpreter } from "../runtime/interpreter.js" -import type { ToolCall } from "../../tool-runtime.js" +import type { ToolCall } from "../tool-runtime.js" import { type Encoded, type Record, SnapshotError } from "./codec.js" export { SnapshotError } @@ -16,7 +16,7 @@ export const fromBytes = (bytes: Uint8Array): unknown => { } } -/** The snapshot format this build writes and reads: the bytecode VM's (see `src/vm/snapshot.ts`). */ +/** The snapshot format this build writes and reads (see `src/snapshot.ts`). */ export const FORMAT = 2 /** diff --git a/packages/codemode/src/vm/stdlib/array.ts b/packages/codemode/src/stdlib/array.ts similarity index 99% rename from packages/codemode/src/vm/stdlib/array.ts rename to packages/codemode/src/stdlib/array.ts index 1799066113f..fbd300a82e4 100644 --- a/packages/codemode/src/vm/stdlib/array.ts +++ b/packages/codemode/src/stdlib/array.ts @@ -23,7 +23,7 @@ import { import { describeValue, rejectCircularInsertion } from "../runtime/references.js" import { requireCallback, withPrimitives } from "../runtime/callback.js" import type { Interpreter } from "../runtime/interpreter.js" -import { compareText } from "../../tool-runtime.js" +import { compareText } from "../tool-runtime.js" const arrayLikeSource = (source: Value): { readonly length: number; readonly source: Obj } => { // JS would treat a promise as an empty array-like; that would hide a missing `await`. diff --git a/packages/codemode/src/vm/stdlib/bytes.ts b/packages/codemode/src/stdlib/bytes.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/bytes.ts rename to packages/codemode/src/stdlib/bytes.ts diff --git a/packages/codemode/src/vm/stdlib/collections.ts b/packages/codemode/src/stdlib/collections.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/collections.ts rename to packages/codemode/src/stdlib/collections.ts diff --git a/packages/codemode/src/vm/stdlib/console.ts b/packages/codemode/src/stdlib/console.ts similarity index 98% rename from packages/codemode/src/vm/stdlib/console.ts rename to packages/codemode/src/stdlib/console.ts index c4e4f7fd68c..34ff060368e 100644 --- a/packages/codemode/src/vm/stdlib/console.ts +++ b/packages/codemode/src/stdlib/console.ts @@ -1,6 +1,6 @@ import { type Method, methods } from "../runtime/native.js" import { entries, get, Arr, Obj, type Value } from "../runtime/objects.js" -import { ToolReference } from "../../tool-runtime.js" +import { ToolReference } from "../tool-runtime.js" import { containsOpaqueReference } from "../runtime/references.js" import type { Interpreter } from "../runtime/interpreter.js" diff --git a/packages/codemode/src/vm/stdlib/date.ts b/packages/codemode/src/stdlib/date.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/date.ts rename to packages/codemode/src/stdlib/date.ts diff --git a/packages/codemode/src/vm/stdlib/headers.ts b/packages/codemode/src/stdlib/headers.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/headers.ts rename to packages/codemode/src/stdlib/headers.ts diff --git a/packages/codemode/src/vm/stdlib/iterator.ts b/packages/codemode/src/stdlib/iterator.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/iterator.ts rename to packages/codemode/src/stdlib/iterator.ts diff --git a/packages/codemode/src/vm/stdlib/json.ts b/packages/codemode/src/stdlib/json.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/json.ts rename to packages/codemode/src/stdlib/json.ts diff --git a/packages/codemode/src/vm/stdlib/math.ts b/packages/codemode/src/stdlib/math.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/math.ts rename to packages/codemode/src/stdlib/math.ts diff --git a/packages/codemode/src/vm/stdlib/number.ts b/packages/codemode/src/stdlib/number.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/number.ts rename to packages/codemode/src/stdlib/number.ts diff --git a/packages/codemode/src/vm/stdlib/object.ts b/packages/codemode/src/stdlib/object.ts similarity index 99% rename from packages/codemode/src/vm/stdlib/object.ts rename to packages/codemode/src/stdlib/object.ts index 09e8482a6a1..60886115eaa 100644 --- a/packages/codemode/src/vm/stdlib/object.ts +++ b/packages/codemode/src/stdlib/object.ts @@ -22,7 +22,7 @@ import { primitivePrototype } from "../runtime/intrinsics.js" import { describeValue, rejectCircularInsertion } from "../runtime/references.js" import { invokeMethod } from "../runtime/callback.js" import type { Interpreter } from "../runtime/interpreter.js" -import { ToolReference } from "../../tool-runtime.js" +import { ToolReference } from "../tool-runtime.js" // ToObject for enumeration. export const enumerableSource = (ctx: Interpreter, label: string, value: Value, node?: AstNode): Obj => { diff --git a/packages/codemode/src/vm/stdlib/regexp.ts b/packages/codemode/src/stdlib/regexp.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/regexp.ts rename to packages/codemode/src/stdlib/regexp.ts diff --git a/packages/codemode/src/vm/stdlib/string.ts b/packages/codemode/src/stdlib/string.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/string.ts rename to packages/codemode/src/stdlib/string.ts diff --git a/packages/codemode/src/vm/stdlib/url.ts b/packages/codemode/src/stdlib/url.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/url.ts rename to packages/codemode/src/stdlib/url.ts diff --git a/packages/codemode/src/vm/stdlib/value.ts b/packages/codemode/src/stdlib/value.ts similarity index 100% rename from packages/codemode/src/vm/stdlib/value.ts rename to packages/codemode/src/stdlib/value.ts diff --git a/packages/codemode/src/vm/stdlib/web.ts b/packages/codemode/src/stdlib/web.ts similarity index 98% rename from packages/codemode/src/vm/stdlib/web.ts rename to packages/codemode/src/stdlib/web.ts index 4c18668d973..75b62f8c772 100644 --- a/packages/codemode/src/vm/stdlib/web.ts +++ b/packages/codemode/src/stdlib/web.ts @@ -24,7 +24,7 @@ import { import { createErrorValue, isErrorType } from "../runtime/intrinsics.js" import { describeValue } from "../runtime/references.js" import type { Interpreter } from "../runtime/interpreter.js" -import { ToolReference } from "../../tool-runtime.js" +import { ToolReference } from "../tool-runtime.js" // WebIDL DOMString conversion: a missing argument is a TypeError, anything else stringifies. Invalid input is a // TypeError as well; browsers throw a DOMException named InvalidCharacterError, which CodeMode does not have. diff --git a/packages/codemode/src/tool-runtime.ts b/packages/codemode/src/tool-runtime.ts index 26823b10c53..8910a44c6b8 100644 --- a/packages/codemode/src/tool-runtime.ts +++ b/packages/codemode/src/tool-runtime.ts @@ -1,5 +1,5 @@ import { Cause, Effect, Exit, Formatter, Schema } from "effect" -import type { Json } from "./vm/data.js" +import type { Json } from "./data.js" import type { DiagnosticKind } from "./codemode.js" import { toolError } from "./tool-error.js" import { diff --git a/packages/codemode/src/vm/vm.ts b/packages/codemode/src/vm.ts similarity index 99% rename from packages/codemode/src/vm/vm.ts rename to packages/codemode/src/vm.ts index de0842903b7..fc6003ed8d1 100644 --- a/packages/codemode/src/vm/vm.ts +++ b/packages/codemode/src/vm.ts @@ -1,5 +1,5 @@ import { parse, type Expression, type MemberExpression, type NewExpression } from "acorn" -import type { Diagnostic } from "../codemode.js" +import type { Diagnostic } from "./codemode.js" import { conversions } from "./runtime/callback.js" import { locate, materialize } from "./runtime/errors.js" import type { Interpreter } from "./runtime/interpreter.js" @@ -81,7 +81,7 @@ import type { HostCall, Stop } from "./scheduler.js" import { compiledPrelude } from "./prelude/prelude.js" import { constructRegExp } from "./stdlib/regexp.js" import { enumerableSource } from "./stdlib/object.js" -import { ToolReference } from "../tool-runtime.js" +import { ToolReference } from "./tool-runtime.js" import { registerAsyncIntrinsics, type SettlingTarget, VmScheduler } from "./async.js" import type { Code } from "./code.js" import { type CaptureOptions, captureVm, type RestoreOptions, restoreVm } from "./snapshot.js" diff --git a/packages/codemode/test/array-callbacks-test262.test.ts b/packages/codemode/test/array-callbacks-test262.test.ts index a538072bfe6..4dd98009516 100644 --- a/packages/codemode/test/array-callbacks-test262.test.ts +++ b/packages/codemode/test/array-callbacks-test262.test.ts @@ -56,7 +56,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/array-core-test262.test.ts b/packages/codemode/test/array-core-test262.test.ts index 1b436b5f3da..b1c3d67447a 100644 --- a/packages/codemode/test/array-core-test262.test.ts +++ b/packages/codemode/test/array-core-test262.test.ts @@ -69,7 +69,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/vm/build-id.test.ts b/packages/codemode/test/build-id.test.ts similarity index 87% rename from packages/codemode/test/vm/build-id.test.ts rename to packages/codemode/test/build-id.test.ts index cac3e5ad9b3..27c84b726e7 100644 --- a/packages/codemode/test/vm/build-id.test.ts +++ b/packages/codemode/test/build-id.test.ts @@ -4,7 +4,7 @@ import path from "node:path" // The snapshot build id hashes only the package's own bytecode, codecs, and built-ins, so it is the same in every // process, whatever it imported first. -const root = path.join(import.meta.dir, "../..") +const root = path.join(import.meta.dir, "..") const output = async (command: Array) => { const child = Bun.spawn(command, { cwd: root, stdout: "pipe", stderr: "pipe" }) @@ -15,7 +15,7 @@ const output = async (command: Array) => { describe("build id", () => { test("the build id is the same whatever a process imported first", async () => { - const fixture = path.join(import.meta.dir, "../fixtures/build-id.ts") + const fixture = path.join(import.meta.dir, "fixtures/build-id.ts") const ids = await Promise.all( [[], ["--preload", "./test/test262/run.ts"], ["--preload", "./src/index.ts"]].map((preload) => output(["bun", ...preload, fixture]), @@ -28,6 +28,6 @@ describe("build id", () => { // A process with the test262 harness loaded saves the run; the child that resumes it has not loaded it. test("a run saved with the test262 harness loaded resumes in another process", async () => { - await output(["bun", "test", "--preload", "./test/test262/run.ts", "test/vm/suspend.test.ts", "-t", "another process"]) + await output(["bun", "test", "--preload", "./test/test262/run.ts", "test/suspend.test.ts", "-t", "another process"]) }, 15_000) }) diff --git a/packages/codemode/test/vm/limits.test.ts b/packages/codemode/test/bytecode-limits.test.ts similarity index 97% rename from packages/codemode/test/vm/limits.test.ts rename to packages/codemode/test/bytecode-limits.test.ts index bcb129767b2..7834457af05 100644 --- a/packages/codemode/test/vm/limits.test.ts +++ b/packages/codemode/test/bytecode-limits.test.ts @@ -1,13 +1,13 @@ import { describe, expect, test } from "bun:test" -import { createBuiltins } from "../../src/vm/runtime/intrinsics.js" -import { Interpreter } from "../../src/vm/runtime/interpreter.js" -import type { ToolRuntime } from "../../src/tool-runtime.js" -import { CodeBuilder, CodeSizeOverflow, hashOf } from "../../src/vm/code.js" -import { compileSource } from "../../src/vm/compiler/compile.js" -import { CodeFlags, EMPTY_CELLS, Op, packWord, PutKind } from "../../src/vm/opcodes.js" -import { Mode } from "../../src/vm/vm.js" -import { parseVmSource, type RunOptions, runProgram } from "./run.js" -import { verifyAll, verifyCode } from "./verify.js" +import { createBuiltins } from "../src/runtime/intrinsics.js" +import { Interpreter } from "../src/runtime/interpreter.js" +import type { ToolRuntime } from "../src/tool-runtime.js" +import { CodeBuilder, CodeSizeOverflow, hashOf } from "../src/code.js" +import { compileSource } from "../src/compiler/compile.js" +import { CodeFlags, EMPTY_CELLS, Op, packWord, PutKind } from "../src/opcodes.js" +import { Mode } from "../src/vm.js" +import { parseVmSource, type RunOptions, runProgram } from "./run-program.js" +import { verifyAll, verifyCode } from "./verify-bytecode.js" const emptyTools = { calls: [], @@ -534,8 +534,9 @@ describe("per-function wide jumps past 65,535 words and snapshot round-trips", ( mainRes: [21, 10, expectedPadA * 2, 378, 13, 7, "late-reject", "ok"], gSteps: [1, 10, 20, expectedGenPad + 4, 18], }) - }) + }, 15_000) + // Compiling a >65,535-word program and round-tripping 8 full snapshots takes ~8-9s on loaded Windows runners. test("top-level script >65,535 words runs correctly and survives snapshot round-trips at pc > 65,535", () => { const src = ` function hoistedTop(n) { return n + 42 } @@ -602,5 +603,5 @@ describe("per-function wide jumps past 65,535 words and snapshot round-trips", ( expect(roundTripped).toEqual({ ok: true, value: expected, toolCalls: [] }) expect(trips).toBeGreaterThan(2) expect(sawHighPc).toBe(true) - }) + }, 15_000) }) diff --git a/packages/codemode/test/callbacks.test.ts b/packages/codemode/test/callbacks.test.ts index 5b736205f8f..9722ae19a1a 100644 --- a/packages/codemode/test/callbacks.test.ts +++ b/packages/codemode/test/callbacks.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Effect, Schema } from "effect" -import { CodeMode, Tool } from "./lib/index.js" +import { CodeMode, Tool } from "../src/index.js" // Callback acceptance is one gate shared by array methods, sort, string replacers, // Array.from mappers, Map/Set/URLSearchParams forEach, and promise reactions: diff --git a/packages/codemode/test/codemode.test.ts b/packages/codemode/test/codemode.test.ts index 4258ffa9c83..c9f4cd10015 100644 --- a/packages/codemode/test/codemode.test.ts +++ b/packages/codemode/test/codemode.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Cause, Effect, Schema } from "effect" -import { CodeMode, Extension, Tool, toolError } from "./lib/index.js" +import { CodeMode, Extension, Tool, toolError } from "../src/index.js" const run = (tool: Tool.Tool) => Effect.runPromise(CodeMode.make({ tools: { host: { call: tool } } }).execute("return await tools.host.call({})")) diff --git a/packages/codemode/test/constructor-test262.test.ts b/packages/codemode/test/constructor-test262.test.ts index 368e71a883d..c038f3f21c3 100644 --- a/packages/codemode/test/constructor-test262.test.ts +++ b/packages/codemode/test/constructor-test262.test.ts @@ -14,7 +14,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/date-test262.test.ts b/packages/codemode/test/date-test262.test.ts index 04c5256c417..ffda8cef4bf 100644 --- a/packages/codemode/test/date-test262.test.ts +++ b/packages/codemode/test/date-test262.test.ts @@ -44,7 +44,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/enumeration.test.ts b/packages/codemode/test/enumeration.test.ts index e5feef46d5c..c46b6048d5b 100644 --- a/packages/codemode/test/enumeration.test.ts +++ b/packages/codemode/test/enumeration.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Effect, Schema } from "effect" -import { CodeMode, Tool } from "./lib/index.js" +import { CodeMode, Tool } from "../src/index.js" // Key enumeration: Object.keys and for...in share one surface over plain objects, arrays // (index strings), and tool references (namespace/tool names from the supplied tools), so a diff --git a/packages/codemode/test/errors.test.ts b/packages/codemode/test/errors.test.ts index 4aa1636c288..8cbb483c247 100644 --- a/packages/codemode/test/errors.test.ts +++ b/packages/codemode/test/errors.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" // One failure is one program error object, and rethrowing it keeps the diagnostic it started with. const run = (code: string) => Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/extensions.test.ts b/packages/codemode/test/extensions.test.ts index 1dda1501431..5e66727559e 100644 --- a/packages/codemode/test/extensions.test.ts +++ b/packages/codemode/test/extensions.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Context, Effect, Schema } from "effect" -import { CodeMode, Extension, Tool } from "./lib/index.js" +import { CodeMode, Extension, Tool } from "../src/index.js" const held: Array = [] const config = { retries: 3, nested: { deep: true } } diff --git a/packages/codemode/test/fixtures/build-id.ts b/packages/codemode/test/fixtures/build-id.ts index 47a2a0f4a35..22b5b1018d6 100644 --- a/packages/codemode/test/fixtures/build-id.ts +++ b/packages/codemode/test/fixtures/build-id.ts @@ -1,8 +1,8 @@ // Prints this process's snapshot build id, from a runtime made with as few of the package's modules as it takes, so // the id can be compared across entry points (`bun --preload build-id.ts`). -import { Interpreter } from "../../src/vm/runtime/interpreter.js" -import { createBuiltins } from "../../src/vm/runtime/intrinsics.js" -import { buildId } from "../../src/vm/snapshot.js" +import { Interpreter } from "../../src/runtime/interpreter.js" +import { createBuiltins } from "../../src/runtime/intrinsics.js" +import { buildId } from "../../src/snapshot.js" import { ToolRuntime } from "../../src/tool-runtime.js" new Interpreter({ tools: ToolRuntime.make(ToolRuntime.prepare({}), undefined, {}), builtins: createBuiltins() }) diff --git a/packages/codemode/test/fixtures/prelude-roundtrip.ts b/packages/codemode/test/fixtures/prelude-roundtrip.ts index 026c320919d..e3f52f35f73 100644 --- a/packages/codemode/test/fixtures/prelude-roundtrip.ts +++ b/packages/codemode/test/fixtures/prelude-roundtrip.ts @@ -2,9 +2,9 @@ // prelude frame was on the stack. import { Effect } from "effect" import { CodeMode } from "../../src/index.js" -import { CodeFlags } from "../../src/vm/opcodes.js" -import { setRoundTrip } from "../../src/vm/runtime/execute.js" -import { Vm } from "../../src/vm/vm.js" +import { CodeFlags } from "../../src/opcodes.js" +import { setRoundTrip } from "../../src/runtime/execute.js" +import { Vm } from "../../src/vm.js" setRoundTrip(true) diff --git a/packages/codemode/test/for-await-test262.test.ts b/packages/codemode/test/for-await-test262.test.ts index 0863b1827c7..fcbbcb85ccb 100644 --- a/packages/codemode/test/for-await-test262.test.ts +++ b/packages/codemode/test/for-await-test262.test.ts @@ -14,7 +14,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const execute = (code: string) => Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/generator-test262.test.ts b/packages/codemode/test/generator-test262.test.ts index b8569713ddb..9afa501c215 100644 --- a/packages/codemode/test/generator-test262.test.ts +++ b/packages/codemode/test/generator-test262.test.ts @@ -12,7 +12,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const execute = (code: string) => Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/groupby-test262.test.ts b/packages/codemode/test/groupby-test262.test.ts index 152ec86bede..bf27ad846e9 100644 --- a/packages/codemode/test/groupby-test262.test.ts +++ b/packages/codemode/test/groupby-test262.test.ts @@ -30,7 +30,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const execute = (code: string) => Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/json-callbacks-test262.test.ts b/packages/codemode/test/json-callbacks-test262.test.ts index 8a0e16efa34..384ec6ece4b 100644 --- a/packages/codemode/test/json-callbacks-test262.test.ts +++ b/packages/codemode/test/json-callbacks-test262.test.ts @@ -28,7 +28,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/labeled-control-test262.test.ts b/packages/codemode/test/labeled-control-test262.test.ts index 8d7196ca06e..37866b17cb4 100644 --- a/packages/codemode/test/labeled-control-test262.test.ts +++ b/packages/codemode/test/labeled-control-test262.test.ts @@ -12,7 +12,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const execute = (code: string) => Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/lexical-test262.test.ts b/packages/codemode/test/lexical-test262.test.ts index 0666e6da650..6f67a9acb9b 100644 --- a/packages/codemode/test/lexical-test262.test.ts +++ b/packages/codemode/test/lexical-test262.test.ts @@ -26,7 +26,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/lib/index.ts b/packages/codemode/test/lib/index.ts deleted file mode 100644 index 53fe6d36e96..00000000000 --- a/packages/codemode/test/lib/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "../../src/index.js" diff --git a/packages/codemode/test/limits.test.ts b/packages/codemode/test/limits.test.ts index 7cc035b3110..781089e398c 100644 --- a/packages/codemode/test/limits.test.ts +++ b/packages/codemode/test/limits.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test" import { Cause, Deferred, Effect, Exit, Fiber, Schema } from "effect" -import { CodeMode, Tool } from "./lib/index.js" -import { MAX_ARRAY_LENGTH, MAX_PENDING_PROMISES, MAX_STRING_LENGTH } from "../src/vm/runtime/limits.js" +import { CodeMode, Tool } from "../src/index.js" +import { MAX_ARRAY_LENGTH, MAX_PENDING_PROMISES, MAX_STRING_LENGTH } from "../src/runtime/limits.js" const runtime = CodeMode.make({ tools: {} }) @@ -40,7 +40,7 @@ describe("one built-in cannot build an unbounded value", () => { }) // split and matchAll share the same result check but must build ten million items first to reach it, - // which is too slow for CI. + // which is too slow for CI; flat() over MAX_ARRAY_LENGTH (10M) elements still needs a 15s budget on Windows. test("arrays: constructor, length, Array.from, concat, flat", async () => { expect(await value(`return Array(${A}).length`)).toBe(A) for (const code of [ @@ -54,7 +54,7 @@ describe("one built-in cannot build an unbounded value", () => { "RangeError: Invalid array length", ) } - }) + }, 15_000) test("promises: too many pending at once, while settled ones do not count", async () => { const n = MAX_PENDING_PROMISES diff --git a/packages/codemode/test/new-expression.test.ts b/packages/codemode/test/new-expression.test.ts index 1be0c5cd337..0beafad48fb 100644 --- a/packages/codemode/test/new-expression.test.ts +++ b/packages/codemode/test/new-expression.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Effect, Schema } from "effect" -import { CodeMode, Tool } from "./lib/index.js" +import { CodeMode, Tool } from "../src/index.js" // `new` is supported syntax; only the callee decides whether construction succeeds. A callee without // construction support is a TypeError naming it, like JS, rather than an unsupported-syntax diagnostic diff --git a/packages/codemode/test/object-coercion-test262.test.ts b/packages/codemode/test/object-coercion-test262.test.ts index d89133ae5a5..adba9e8bd62 100644 --- a/packages/codemode/test/object-coercion-test262.test.ts +++ b/packages/codemode/test/object-coercion-test262.test.ts @@ -37,7 +37,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/openapi.test.ts b/packages/codemode/test/openapi.test.ts index 3a320385329..e82484ea6c9 100644 --- a/packages/codemode/test/openapi.test.ts +++ b/packages/codemode/test/openapi.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test" import { Effect, Layer, Option } from "effect" import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" -import { CodeMode, OpenAPI, Tool } from "./lib/index.js" +import { CodeMode, OpenAPI, Tool } from "../src/index.js" import { inputTypeScript, outputTypeScript } from "../src/tool-schema.js" const baseUrl = "http://localhost:4096" diff --git a/packages/codemode/test/parity.test.ts b/packages/codemode/test/parity.test.ts index 4d7bd129f26..72b00a447a5 100644 --- a/packages/codemode/test/parity.test.ts +++ b/packages/codemode/test/parity.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" // Runs a CodeMode program with no host tools and returns the CodeMode.Result. These tests pin the // JS-parity behaviors for the "99% of ordinary defensive JavaScript just works" goal: cases where diff --git a/packages/codemode/test/preload.ts b/packages/codemode/test/preload.ts index aa8ac22ade7..2f099491715 100644 --- a/packages/codemode/test/preload.ts +++ b/packages/codemode/test/preload.ts @@ -1,5 +1,5 @@ -import { setRoundTrip } from "../src/vm/runtime/execute.js" -import { nativeRule } from "../src/vm/runtime/objects.js" +import { setRoundTrip } from "../src/runtime/execute.js" +import { nativeRule } from "../src/runtime/objects.js" // Every test run checks that natives are made only with the intrinsics. nativeRule.check = true diff --git a/packages/codemode/test/vm/prelude-bytecode.test.ts b/packages/codemode/test/prelude-bytecode.test.ts similarity index 77% rename from packages/codemode/test/vm/prelude-bytecode.test.ts rename to packages/codemode/test/prelude-bytecode.test.ts index 04d466f1588..1f8ea7daa9c 100644 --- a/packages/codemode/test/vm/prelude-bytecode.test.ts +++ b/packages/codemode/test/prelude-bytecode.test.ts @@ -1,10 +1,10 @@ import { describe, expect, test } from "bun:test" -import { compileBuiltins } from "../../script/prelude.js" -import saved from "../../src/vm/prelude/bytecode.json" with { type: "json" } -import { compiledPrelude } from "../../src/vm/prelude/prelude.js" -import { hashOf } from "../../src/vm/code.js" -import { getInternalPrelude } from "../../src/vm/internal-prelude.js" -import { moduleUrl, runProgram } from "./run.js" +import { compileBuiltins } from "../script/prelude.js" +import saved from "../src/prelude/bytecode.json" with { type: "json" } +import { compiledPrelude } from "../src/prelude/prelude.js" +import { hashOf } from "../src/code.js" +import { getInternalPrelude } from "../src/internal-prelude.js" +import { moduleUrl, runProgram } from "./run-program.js" // The built-in sources are compiled ahead of time (script/prelude.ts); a process loads that bytecode instead. @@ -25,8 +25,8 @@ describe("precompiled built-ins", () => { } // A fresh process runs a program that calls into the prelude, and its source is still unparsed. const script = ` - import { runProgram } from ${moduleUrl("run.js")} - import { compiledPrelude } from ${moduleUrl("../../src/vm/prelude/prelude.js")} + import { runProgram } from ${moduleUrl("run-program.js")} + import { compiledPrelude } from ${moduleUrl("../src/prelude/prelude.js")} const result = runProgram("return [3, 1, 2].map((x) => x * 2).sort((a, b) => a - b)") console.log(JSON.stringify([result.ok && result.value, typeof compiledPrelude().codes[0].sourceObj.tree]))` const child = Bun.spawn(["bun", "-e", script], { stdout: "pipe", stderr: "inherit" }) diff --git a/packages/codemode/test/promise-test262.test.ts b/packages/codemode/test/promise-test262.test.ts index 130c85770bf..d2b60659b2d 100644 --- a/packages/codemode/test/promise-test262.test.ts +++ b/packages/codemode/test/promise-test262.test.ts @@ -14,7 +14,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const execute = (code: string) => Effect.runPromise(CodeMode.execute({ code, tools: {}, limits: { timeoutMs: 1_000 } })) diff --git a/packages/codemode/test/promise.test.ts b/packages/codemode/test/promise.test.ts index 4d84c77ec94..947e3a50d69 100644 --- a/packages/codemode/test/promise.test.ts +++ b/packages/codemode/test/promise.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Cause, Deferred, Effect, Exit, Schema } from "effect" -import { CodeMode, Tool, toolError } from "./lib/index.js" +import { CodeMode, Tool, toolError } from "../src/index.js" // Wave 5 acceptance suite: first-class promise values. Un-awaited tool calls start eagerly as // host work, `await` settles them, Promise.all/allSettled/race/resolve/reject are diff --git a/packages/codemode/test/regexp-math-test262.test.ts b/packages/codemode/test/regexp-math-test262.test.ts index d12562d10b2..bd85d3ef2db 100644 --- a/packages/codemode/test/regexp-math-test262.test.ts +++ b/packages/codemode/test/regexp-math-test262.test.ts @@ -41,7 +41,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/vm/resumable.test.ts b/packages/codemode/test/resumable.test.ts similarity index 95% rename from packages/codemode/test/vm/resumable.test.ts rename to packages/codemode/test/resumable.test.ts index 8ab9ad6492b..8bc794f4e3f 100644 --- a/packages/codemode/test/vm/resumable.test.ts +++ b/packages/codemode/test/resumable.test.ts @@ -1,16 +1,16 @@ import { describe, expect, test } from "bun:test" import path from "node:path" -import { parseProgram } from "../../src/vm/runtime/execute.js" -import { Interpreter } from "../../src/vm/runtime/interpreter.js" -import { createBuiltins } from "../../src/vm/runtime/intrinsics.js" -import { getOwn, Native, nativeRule, Obj, remove, set } from "../../src/vm/runtime/objects.js" -import { CodeMode } from "../lib/index.js" -import { decode, encode } from "../../src/vm/snapshot/codec.js" -import { Lost, PendingThrow } from "../../src/vm/runtime/model.js" -import { normalizeError } from "../../src/vm/runtime/errors.js" +import { parseProgram } from "../src/runtime/execute.js" +import { Interpreter } from "../src/runtime/interpreter.js" +import { createBuiltins } from "../src/runtime/intrinsics.js" +import { getOwn, Native, nativeRule, Obj, remove, set } from "../src/runtime/objects.js" +import { CodeMode } from "../src/index.js" +import { decode, encode } from "../src/snapshot/codec.js" +import { Lost, PendingThrow } from "../src/runtime/model.js" +import { normalizeError } from "../src/runtime/errors.js" import { Effect } from "effect" -import { ToolRuntime } from "../../src/tool-runtime.js" -import { nodeId, sourceOf } from "../../src/vm/runtime/source.js" +import { ToolRuntime } from "../src/tool-runtime.js" +import { nodeId, sourceOf } from "../src/runtime/source.js" // Groundwork for suspending and resuming a run: everything the state refers to has a stable name. @@ -281,7 +281,7 @@ describe("heap as data", () => { describe("prelude", () => { test("a run saved and restored while prelude built-ins run continues in their frames", async () => { - const child = Bun.spawn(["bun", path.join(import.meta.dir, "../fixtures/prelude-roundtrip.ts")], { + const child = Bun.spawn(["bun", path.join(import.meta.dir, "fixtures/prelude-roundtrip.ts")], { stdout: "pipe", stderr: "inherit", }) @@ -320,7 +320,6 @@ describe("lost values", () => { unchanged: () => false, anchorOf: () => undefined, nodeId: () => undefined, - astArray: () => undefined, lost, strict: false, }) @@ -328,7 +327,6 @@ describe("lost values", () => { named: () => undefined, anchor: () => undefined, node: () => undefined, - astArray: () => undefined, interruption: () => { throw new Error("no interruption is saved") }, diff --git a/packages/codemode/test/vm/run.ts b/packages/codemode/test/run-program.ts similarity index 54% rename from packages/codemode/test/vm/run.ts rename to packages/codemode/test/run-program.ts index 933358ef328..6277b8d88ca 100644 --- a/packages/codemode/test/vm/run.ts +++ b/packages/codemode/test/run-program.ts @@ -1,18 +1,19 @@ import path from "node:path" import { pathToFileURL } from "node:url" -import { parse, type Program } from "acorn" -import type { DataValue, Diagnostic, Result } from "../../src/codemode.js" -import { normalizeError } from "../../src/vm/runtime/errors.js" -import { createBuiltins } from "../../src/vm/runtime/intrinsics.js" -import { Interpreter } from "../../src/vm/runtime/interpreter.js" -import { formatLocation, PendingThrow, sourceLocation } from "../../src/vm/runtime/model.js" -import type { Value } from "../../src/vm/runtime/objects.js" -import { Interruption } from "../../src/vm/runtime/signals.js" -import { Source } from "../../src/vm/runtime/source.js" -import type { ToolRuntime } from "../../src/tool-runtime.js" -import type { Snapshot } from "../../src/vm/snapshot/snapshot.js" +import type { Program } from "acorn" +import type { DataValue, Diagnostic, Result } from "../src/codemode.js" +import { normalizeError } from "../src/runtime/errors.js" +import { parseProgram } from "../src/runtime/execute.js" +import { createBuiltins } from "../src/runtime/intrinsics.js" +import { Interpreter } from "../src/runtime/interpreter.js" +import { PendingThrow } from "../src/runtime/model.js" +import type { Value } from "../src/runtime/objects.js" +import { Interruption } from "../src/runtime/signals.js" +import type { Source } from "../src/runtime/source.js" +import type { ToolRuntime } from "../src/tool-runtime.js" +import type { Snapshot } from "../src/snapshot/snapshot.js" -/** A quoted `file:` URL for a module relative to `test/vm`, to import from a script run with `bun -e` on any platform. */ +/** A quoted `file:` URL for a module relative to `test`, to import from a script run with `bun -e` on any platform. */ export const moduleUrl = (relative: string) => JSON.stringify(pathToFileURL(path.join(import.meta.dir, relative)).href) @@ -36,7 +37,6 @@ export type RunOptions = { export const parseVmSource = ( code: string, - id = "main", ): | { readonly ok: true; readonly program: Program; readonly source: Source } | { readonly ok: false; readonly error: Diagnostic } => { @@ -44,38 +44,8 @@ export const parseVmSource = ( return { ok: false, error: { kind: "ParseError", message: "Code cannot be empty." } } } try { - const program = parse(code, { - ecmaVersion: "latest", - sourceType: "script", - allowReturnOutsideFunction: true, - allowAwaitOutsideFunction: true, - allowImportExportEverywhere: true, - locations: true, - }) - const exported = program.body.find((statement) => statement.type.startsWith("Export")) - if (exported) { - const location = sourceLocation(exported) - return { - ok: false, - error: { - kind: "ParseError", - message: `SyntaxError: Exports aren't available. Return the result instead.${formatLocation(location)}`, - location, - }, - } - } - return { ok: true, program, source: new Source(id, code, program) } + return parseProgram(code) } catch (error) { - if (error instanceof SyntaxError && "loc" in error) { - const loc = (error as SyntaxError & { readonly loc: { readonly line: number; readonly column: number } }).loc - const location = { line: loc.line, column: loc.column + 1 } - const reason = error.message.replace(/ \(\d+:\d+\)$/, "") - const text = `${reason.endsWith(".") ? reason : `${reason}.`} Code must be plain JavaScript written as a program body.` - return { - ok: false, - error: { kind: "ParseError", message: `SyntaxError: ${text}${formatLocation(location)}`, location }, - } - } if (error instanceof RangeError) { return { ok: false, error: normalizeError(error) } } @@ -173,49 +143,3 @@ export const runProgram = (code: string, options?: RunOptions): Result => { } } } - -const WARMUP_SCRIPT = ` -function fib(n) { return n < 2 ? n : fib(n - 1) + fib(n - 2) } -let sum = 0 -for (let i = 0; i < 400; i++) sum = (sum + i * 3) % 10007 -const closures = [] -for (let i = 0; i < 16; i++) { - let s = "v" + i - let o = { x: i, y: s } - closures.push(() => o.x + s.length) -} -for (const fn of closures) sum += fn() -const arr = Array.from({ length: 64 }, (_, i) => (i * 17) % 64) -const mapped = arr.map((x) => x * 2).filter((x) => x % 3 !== 0) -sum += mapped.reduce((a, b) => a + b, 0) -const sorted = mapped.slice(0, 32).sort((a, b) => a - b) -sum += sorted.length + fib(8) -outer: for (let i = 0; i < 3; i++) { - try { - for (const x of [1, 2, 3]) { - try { - if (x === 2) continue - if (i === 1 && x === 3) break outer - sum += x - } finally { sum += 1 } - } - } catch (e) { sum -= 1 } finally { sum += 2 } -} -const { a = 1, b: [c = 2, ...rest] = [3, 4, 5] } = { b: [10, 20, 30] } -return sum + a + c + rest.length -` - -let warmed = false - -/** - * Startup training program (J3): exercises the VM dispatch loop with diverse types - * (numbers, strings, objects, arrays, closures, cells, try/catch/finally, iteration, destructuring) - * so JSC's DFG/FTL tiers up `Vm.prototype.exec` with polymorphic value profiles. - */ -export const warmupVm = (rounds = 8): void => { - if (warmed) return - warmed = true - for (let i = 0; i < rounds; i++) { - runProgram(WARMUP_SCRIPT) - } -} diff --git a/packages/codemode/test/scan.test.ts b/packages/codemode/test/scan.test.ts index e4327f019e6..f6a876901b1 100644 --- a/packages/codemode/test/scan.test.ts +++ b/packages/codemode/test/scan.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Effect, Result } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" describe("CodeMode.scanTools", () => { test("extracts dotted, bracketed and nested static tool calls in first-seen order", () => { diff --git a/packages/codemode/test/set-methods-test262.test.ts b/packages/codemode/test/set-methods-test262.test.ts index 2aa857ed864..7d94aac1406 100644 --- a/packages/codemode/test/set-methods-test262.test.ts +++ b/packages/codemode/test/set-methods-test262.test.ts @@ -71,7 +71,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/signature.test.ts b/packages/codemode/test/signature.test.ts index 2594ebc160f..ed41e9b02c2 100644 --- a/packages/codemode/test/signature.test.ts +++ b/packages/codemode/test/signature.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Effect, Schema, SchemaGetter } from "effect" -import { CodeMode, Tool } from "./lib/index.js" +import { CodeMode, Tool } from "../src/index.js" import { decodeInput, inputProperties, diff --git a/packages/codemode/test/vm/snapshot.test.ts b/packages/codemode/test/snapshot.test.ts similarity index 91% rename from packages/codemode/test/vm/snapshot.test.ts rename to packages/codemode/test/snapshot.test.ts index a42e6e247ff..509b9f47e2d 100644 --- a/packages/codemode/test/vm/snapshot.test.ts +++ b/packages/codemode/test/snapshot.test.ts @@ -1,14 +1,14 @@ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "../../src/index.js" -import { createBuiltins } from "../../src/vm/runtime/intrinsics.js" -import { Interpreter } from "../../src/vm/runtime/interpreter.js" -import { type Snapshot, SnapshotError } from "../../src/vm/snapshot/snapshot.js" -import { ToolRuntime } from "../../src/tool-runtime.js" -import { hashOf } from "../../src/vm/code.js" -import { compileSource } from "../../src/vm/compiler/compile.js" -import { moduleUrl, parseVmSource, runProgram } from "./run.js" -import { buildId } from "../../src/vm/snapshot.js" +import { CodeMode } from "../src/index.js" +import { createBuiltins } from "../src/runtime/intrinsics.js" +import { Interpreter } from "../src/runtime/interpreter.js" +import { type Snapshot, SnapshotError } from "../src/snapshot/snapshot.js" +import { ToolRuntime } from "../src/tool-runtime.js" +import { hashOf } from "../src/code.js" +import { compileSource } from "../src/compiler/compile.js" +import { moduleUrl, parseVmSource, runProgram } from "./run-program.js" +import { buildId } from "../src/snapshot.js" // The VM's snapshots: a run saved and restored into a fresh runtime anywhere it slices goes on as if it never stopped. @@ -268,13 +268,13 @@ describe("determinism", () => { const codes = Object.values(programs) const local = { hashes: codes.map((code) => hashOf(compileSource(parse(code)))), build: (runtime(), buildId()) } const script = ` - import { hashOf } from ${moduleUrl("../../src/vm/code.js")} - import { compileSource } from ${moduleUrl("../../src/vm/compiler/compile.js")} - import { parseVmSource } from ${moduleUrl("run.js")} - import { buildId } from ${moduleUrl("../../src/vm/snapshot.js")} - import { createBuiltins } from ${moduleUrl("../../src/vm/runtime/intrinsics.js")} - import { Interpreter } from ${moduleUrl("../../src/vm/runtime/interpreter.js")} - import { ToolRuntime } from ${moduleUrl("../../src/tool-runtime.js")} + import { hashOf } from ${moduleUrl("../src/code.js")} + import { compileSource } from ${moduleUrl("../src/compiler/compile.js")} + import { parseVmSource } from ${moduleUrl("run-program.js")} + import { buildId } from ${moduleUrl("../src/snapshot.js")} + import { createBuiltins } from ${moduleUrl("../src/runtime/intrinsics.js")} + import { Interpreter } from ${moduleUrl("../src/runtime/interpreter.js")} + import { ToolRuntime } from ${moduleUrl("../src/tool-runtime.js")} new Interpreter({ tools: ToolRuntime.make(ToolRuntime.prepare({}), undefined, {}), builtins: createBuiltins() }) const codes = ${JSON.stringify(codes)} console.log(JSON.stringify({ hashes: codes.map((code) => hashOf(compileSource(parseVmSource(code).source))), build: buildId() }))` diff --git a/packages/codemode/test/vm/state.test.ts b/packages/codemode/test/state.test.ts similarity index 92% rename from packages/codemode/test/vm/state.test.ts rename to packages/codemode/test/state.test.ts index 16eab1f9636..a085113421b 100644 --- a/packages/codemode/test/vm/state.test.ts +++ b/packages/codemode/test/state.test.ts @@ -2,21 +2,21 @@ import { describe, expect, test } from "bun:test" import { Glob } from "bun" import path from "node:path" import { Effect, Schema } from "effect" -import { CodeMode, Tool } from "../lib/index.js" -import { parseProgram } from "../../src/vm/runtime/execute.js" -import { Interpreter } from "../../src/vm/runtime/interpreter.js" -import { createBuiltins } from "../../src/vm/runtime/intrinsics.js" -import { GeneratorObj, type Native, nativeRule, Obj, PromiseObj, type Value } from "../../src/vm/runtime/objects.js" -import { normal } from "../../src/vm/runtime/signals.js" -import { ToolRuntime } from "../../src/tool-runtime.js" -import { Code } from "../../src/vm/code.js" -import { AsyncFromSyncIterator } from "../../src/vm/generators.js" -import { VmIntrinsic } from "../../src/vm/internal-prelude.js" -import { Cell, CodeFlags } from "../../src/vm/opcodes.js" -import type { Stop } from "../../src/vm/scheduler.js" -import { CustomIter, Frame, Mode, Vm } from "../../src/vm/vm.js" +import { CodeMode, Tool } from "../src/index.js" +import { parseProgram } from "../src/runtime/execute.js" +import { Interpreter } from "../src/runtime/interpreter.js" +import { createBuiltins } from "../src/runtime/intrinsics.js" +import { GeneratorObj, type Native, nativeRule, Obj, PromiseObj, type Value } from "../src/runtime/objects.js" +import { normal } from "../src/runtime/signals.js" +import { ToolRuntime } from "../src/tool-runtime.js" +import { Code } from "../src/code.js" +import { AsyncFromSyncIterator } from "../src/generators.js" +import { VmIntrinsic } from "../src/internal-prelude.js" +import { Cell, CodeFlags } from "../src/opcodes.js" +import type { Stop } from "../src/scheduler.js" +import { CustomIter, Frame, Mode, Vm } from "../src/vm.js" -// The VM (`src/vm`) runs programs as bytecode frames, and keeps the jobs, promises, and host calls they wait on as +// The VM (`src/vm.ts`) runs programs as bytecode frames, and keeps the jobs, promises, and host calls they wait on as // data: a frame is its code, pc, and registers, and every suspension point is one. The Effect driver only does what // the VM's stops ask. @@ -218,6 +218,7 @@ describe("vm", () => { expect(next).toEqual({ kind: "done", completion: normal(2450) }) }) + // Sorting 300,000 strings (to cross multiple 65,536-item merge steps) with tripEvery = 1 takes ~7s on Windows CI. test("a large default sort runs in bounded native steps, and sorts as JS does", () => { const words = Array.from({ length: 300_000 }, (_, i) => ((i * 7919) % 300_007).toString(36)) const vm = vmFor(` @@ -246,7 +247,7 @@ describe("vm", () => { 9100 in sorted, ]), }) - }) + }, 15_000) test("concurrent tool calls stop the VM once, with every call in one batch", () => { const vm = vmFor(`return await Promise.all([1, 2, 3].map((value) => tools.echo({ value })))`) @@ -383,11 +384,24 @@ describe("vm", () => { }) test("the VM does not import Effect", async () => { - const root = path.join(import.meta.dir, "../..") + const root = path.join(import.meta.dir, "..") + const host = new Set([ + "src/codemode.ts", + "src/extension.ts", + "src/scan.ts", + "src/tool-error.ts", + "src/tool-runtime.ts", + "src/tool-schema.ts", + "src/tool.ts", + "src/runtime/driver.ts", + "src/runtime/execute.ts", + "src/runtime/extensions.ts", + "src/runtime/signals.ts", + ]) // Glob paths use the platform's separator. - const files = (await Array.fromAsync(new Glob("src/vm/**/*.ts").scan({ cwd: root }))).filter( - (file) => !file.split(path.sep).join("/").startsWith("src/vm/runtime/"), - ) + const files = (await Array.fromAsync(new Glob("src/**/*.ts").scan({ cwd: root }))) + .map((file) => file.split(path.sep).join("/")) + .filter((file) => !file.startsWith("src/openapi/") && !host.has(file)) expect(files.length).toBeGreaterThan(0) for (const file of files) { expect(await Bun.file(path.join(root, file)).text()).not.toMatch(/from "effect"/) diff --git a/packages/codemode/test/stdlib.test.ts b/packages/codemode/test/stdlib.test.ts index 9212fe34a04..9c0d01672cc 100644 --- a/packages/codemode/test/stdlib.test.ts +++ b/packages/codemode/test/stdlib.test.ts @@ -16,7 +16,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect, Schema } from "effect" -import { CodeMode, Tool } from "./lib/index.js" +import { CodeMode, Tool } from "../src/index.js" // Standard-library value types: Date, RegExp, Map, Set. Programs use them as ordinary JS; // intra-CodeMode checkpoints (Object.* helpers, spread, coercion inputs) preserve the live diff --git a/packages/codemode/test/string-core-test262.test.ts b/packages/codemode/test/string-core-test262.test.ts index 30400130715..9173fe352da 100644 --- a/packages/codemode/test/string-core-test262.test.ts +++ b/packages/codemode/test/string-core-test262.test.ts @@ -151,7 +151,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" type Argument = string | number | undefined type Outcome = "undefined" | "length" | "RangeError" diff --git a/packages/codemode/test/string-date-methods-test262.test.ts b/packages/codemode/test/string-date-methods-test262.test.ts index 24a5013c8ec..41757052756 100644 --- a/packages/codemode/test/string-date-methods-test262.test.ts +++ b/packages/codemode/test/string-date-methods-test262.test.ts @@ -24,7 +24,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/string-regexp-test262.test.ts b/packages/codemode/test/string-regexp-test262.test.ts index 513de982739..fa0d6f709d6 100644 --- a/packages/codemode/test/string-regexp-test262.test.ts +++ b/packages/codemode/test/string-regexp-test262.test.ts @@ -82,7 +82,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" type Vector = { readonly path: string diff --git a/packages/codemode/test/string-search-test262.test.ts b/packages/codemode/test/string-search-test262.test.ts index 6abf045fe71..b596fc7bf9a 100644 --- a/packages/codemode/test/string-search-test262.test.ts +++ b/packages/codemode/test/string-search-test262.test.ts @@ -102,7 +102,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/vm/suspend.test.ts b/packages/codemode/test/suspend.test.ts similarity index 99% rename from packages/codemode/test/vm/suspend.test.ts rename to packages/codemode/test/suspend.test.ts index e43c17a0526..7471f9b55d6 100644 --- a/packages/codemode/test/vm/suspend.test.ts +++ b/packages/codemode/test/suspend.test.ts @@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test" import { tmpdir } from "node:os" import path from "node:path" import { Context, Effect, Fiber, Schema } from "effect" -import { CodeMode, Extension, Tool } from "../../src/index.js" +import { CodeMode, Extension, Tool } from "../src/index.js" // Suspending a run, saving its state, and resuming it in a brand-new runtime. @@ -450,7 +450,7 @@ describe("suspend", () => { test("the snapshot codec does not import Effect", async () => { for (const file of ["codec.ts", "snapshot.ts"]) { - expect(await Bun.file(path.join(import.meta.dir, "../../src/vm/snapshot", file)).text()).not.toMatch( + expect(await Bun.file(path.join(import.meta.dir, "../src/snapshot", file)).text()).not.toMatch( /from "effect"/, ) } @@ -479,7 +479,7 @@ describe("resume", () => { const file = path.join(tmpdir(), `codemode-${crypto.randomUUID()}.state`) await Bun.write(file, CodeMode.toBytes(suspended.state)) try { - const child = Bun.spawn(["bun", path.join(import.meta.dir, "../fixtures/resume-process.ts"), file], { + const child = Bun.spawn(["bun", path.join(import.meta.dir, "fixtures/resume-process.ts"), file], { stdout: "pipe", stderr: "inherit", }) diff --git a/packages/codemode/test/test262/run.ts b/packages/codemode/test/test262/run.ts index 0775e76517b..1f8dd8d91ec 100644 --- a/packages/codemode/test/test262/run.ts +++ b/packages/codemode/test/test262/run.ts @@ -1,15 +1,15 @@ -// Runs one vendored test262 file verbatim on the bytecode VM. The harness (assert, Test262Error, compareArray, $DONE, +// Runs one vendored test262 file verbatim. The harness (assert, Test262Error, compareArray, $DONE, // $DONOTEVALUATE) is host-provided, except `assert` itself: a program function made by the prelude, so that // `assert.throws` can call the function it tests and catch what it throws as plain program code. Its checks and // failure messages are the host's (`$assert`). import path from "node:path" import { Effect } from "effect" -import { executeProgram } from "../../src/vm/runtime/execute.js" -import type { Interpreter } from "../../src/vm/runtime/interpreter.js" -import { Throw } from "../../src/vm/runtime/model.js" -import { createErrorValue } from "../../src/vm/runtime/intrinsics.js" -import { constructor, fn, methods } from "../../src/vm/runtime/native.js" -import { Callable, define, get, hidden, Arr, Fn, Obj, type Value } from "../../src/vm/runtime/objects.js" +import { finishExecution, startProgram } from "../../src/runtime/execute.js" +import type { Interpreter } from "../../src/runtime/interpreter.js" +import { Throw } from "../../src/runtime/model.js" +import { createErrorValue } from "../../src/runtime/intrinsics.js" +import { constructor, fn, methods } from "../../src/runtime/native.js" +import { Callable, define, get, hidden, Arr, Fn, Obj, type Value } from "../../src/runtime/objects.js" import { ToolRuntime } from "../../src/tool-runtime.js" export const root = import.meta.dir @@ -29,8 +29,11 @@ type Frontmatter = { negative?: { phase: "parse" | "resolution" | "runtime"; type: string } } -const limits = { timeoutMs: 5000, maxToolCalls: undefined, maxOutputBytes: undefined } -const prepared = ToolRuntime.prepare({}) +const setup = { + prepared: ToolRuntime.prepare({}), + limits: { timeoutMs: 5000, maxToolCalls: undefined, maxOutputBytes: undefined }, + hooks: {}, +} // One line, on the line of the "use strict" directive, so the test's own line numbers stay as they are. const prelude = [ @@ -52,10 +55,17 @@ export const run = async (file: string): Promise => { // work instead, so drain explicitly. const drain = meta.flags?.includes("async") ? "\nfor (let i = 0; i < 100; i++) await null" : "" const result = await Effect.runPromise( - executeProgram(`"use strict"; ${prelude}\n${source}${drain}`, prepared, limits, {}, (ctx) => - harness(ctx, (error) => { - done ??= { error } - }), + finishExecution( + startProgram( + { + ...setup, + globals: (ctx) => + harness(ctx, (error) => { + done ??= { error } + }), + }, + `"use strict"; ${prelude}\n${source}${drain}`, + ).run(), ), ) if (meta.negative !== undefined) { diff --git a/packages/codemode/test/tool-paths.test.ts b/packages/codemode/test/tool-paths.test.ts index 76c4a875c44..a739d651510 100644 --- a/packages/codemode/test/tool-paths.test.ts +++ b/packages/codemode/test/tool-paths.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Effect, Schema } from "effect" -import { CodeMode, Namespace, Tool } from "./lib/index.js" +import { CodeMode, Namespace, Tool } from "../src/index.js" const echo = (description: string, result: string) => Tool.make({ diff --git a/packages/codemode/test/var-hoisting-test262.test.ts b/packages/codemode/test/var-hoisting-test262.test.ts index a1729841f49..667603f5232 100644 --- a/packages/codemode/test/var-hoisting-test262.test.ts +++ b/packages/codemode/test/var-hoisting-test262.test.ts @@ -21,7 +21,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const value = async (code: string) => { const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} })) diff --git a/packages/codemode/test/vm/verify.ts b/packages/codemode/test/verify-bytecode.ts similarity index 99% rename from packages/codemode/test/vm/verify.ts rename to packages/codemode/test/verify-bytecode.ts index 0dce361a801..9babd65dbc4 100644 --- a/packages/codemode/test/vm/verify.ts +++ b/packages/codemode/test/verify-bytecode.ts @@ -1,5 +1,5 @@ -import type { Code } from "../../src/vm/code.js" -import { CheckBaseKind, CondKind, ImportKind, Op, OpNames } from "../../src/vm/opcodes.js" +import type { Code } from "../src/code.js" +import { CheckBaseKind, CondKind, ImportKind, Op, OpNames } from "../src/opcodes.js" /** * Stack-depth verifier (C5): runs abstract interpretation over packed bytecode independent of `CodeBuilder`, diff --git a/packages/codemode/test/vm/vm.test.ts b/packages/codemode/test/vm.test.ts similarity index 98% rename from packages/codemode/test/vm/vm.test.ts rename to packages/codemode/test/vm.test.ts index 5570bab289c..b33c1cfb2c9 100644 --- a/packages/codemode/test/vm/vm.test.ts +++ b/packages/codemode/test/vm.test.ts @@ -1,9 +1,9 @@ import { describe, expect, test } from "bun:test" -import { disassembleSource } from "../../script/disasm.js" -import { hashOf } from "../../src/vm/code.js" -import { compileSource } from "../../src/vm/compiler/compile.js" -import { verifyAll } from "./verify.js" -import { parseVmSource, runProgram, warmupVm } from "./run.js" +import { disassembleSource } from "../script/disasm.js" +import { hashOf } from "../src/code.js" +import { compileSource } from "../src/compiler/compile.js" +import { verifyAll } from "./verify-bytecode.js" +import { parseVmSource, runProgram } from "./run-program.js" const val = (code: string) => { const parsed = parseVmSource(code) @@ -496,7 +496,6 @@ describe("generators, async functions, async generators, yield*, and for-await", describe("built-ins, prelude, and coercion", () => { test("array callbacks, sort, Map/Set, Object.groupBy, JSON reviver/replacer, and ToPrimitive", () => { - warmupVm(2) expect( val(` const arr = Array.from({ length: 6 }, (_, i) => i + 1) diff --git a/packages/codemode/test/web-wpt.test.ts b/packages/codemode/test/web-wpt.test.ts index dc9e1a64d9a..05e51d06457 100644 --- a/packages/codemode/test/web-wpt.test.ts +++ b/packages/codemode/test/web-wpt.test.ts @@ -13,7 +13,7 @@ */ import { describe, expect, test } from "bun:test" import { Effect } from "effect" -import { CodeMode } from "./lib/index.js" +import { CodeMode } from "../src/index.js" const base64Cases = (await Bun.file(new URL("./fixtures/wpt-base64.json", import.meta.url)).json()) as Array< [string, Array | null]