@opencode/codemode 0.0.0-beta-19500 → 0.0.0-dev-19274
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -6
- package/dist/codemode.d.ts +12 -9
- package/dist/codemode.js +9 -5
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/interpreter/errors.d.ts +6 -4
- package/dist/interpreter/errors.js +10 -25
- package/dist/interpreter/execute.d.ts +3 -4
- package/dist/interpreter/execute.js +18 -11
- package/dist/interpreter/iterator.d.ts +13 -0
- package/dist/interpreter/iterator.js +4 -0
- package/dist/interpreter/methods.d.ts +16 -3
- package/dist/interpreter/methods.js +290 -101
- package/dist/interpreter/model.d.ts +79 -10
- package/dist/interpreter/model.js +102 -2
- package/dist/interpreter/promises.d.ts +13 -15
- package/dist/interpreter/promises.js +52 -70
- package/dist/interpreter/references.d.ts +0 -1
- package/dist/interpreter/references.js +77 -57
- package/dist/interpreter/runtime.d.ts +95 -16
- package/dist/interpreter/runtime.js +960 -549
- package/dist/openapi/spec.js +6 -3
- package/dist/stdlib/collections.d.ts +1 -6
- package/dist/stdlib/collections.js +1 -117
- package/dist/stdlib/console.d.ts +2 -3
- package/dist/stdlib/console.js +28 -39
- package/dist/stdlib/date.d.ts +4 -5
- package/dist/stdlib/date.js +12 -34
- package/dist/stdlib/json.d.ts +6 -3
- package/dist/stdlib/json.js +63 -40
- package/dist/stdlib/math.d.ts +7 -3
- package/dist/stdlib/math.js +153 -85
- package/dist/stdlib/number.d.ts +4 -2
- package/dist/stdlib/number.js +37 -30
- package/dist/stdlib/object.d.ts +6 -6
- package/dist/stdlib/object.js +87 -84
- package/dist/stdlib/promise.d.ts +2 -0
- package/dist/stdlib/promise.js +1 -0
- package/dist/stdlib/regexp.d.ts +7 -6
- package/dist/stdlib/regexp.js +34 -48
- package/dist/stdlib/string.d.ts +3 -1
- package/dist/stdlib/string.js +17 -20
- package/dist/stdlib/url.d.ts +6 -10
- package/dist/stdlib/url.js +25 -102
- package/dist/stdlib/value.d.ts +7 -8
- package/dist/stdlib/value.js +56 -56
- package/dist/tool-runtime.d.ts +15 -16
- package/dist/tool-runtime.js +150 -13
- package/dist/values.d.ts +16 -22
- package/dist/values.js +17 -23
- package/package.json +1 -1
- package/dist/data.d.ts +0 -25
- package/dist/data.js +0 -153
- package/dist/interpreter/globals.d.ts +0 -13
- package/dist/interpreter/globals.js +0 -63
- package/dist/interpreter/host.d.ts +0 -41
- package/dist/interpreter/host.js +0 -44
- package/dist/interpreter/objects.d.ts +0 -37
- package/dist/interpreter/objects.js +0 -151
- package/dist/interpreter/runner.d.ts +0 -24
- package/dist/interpreter/runner.js +0 -45
- package/dist/stdlib/array.d.ts +0 -3
- package/dist/stdlib/array.js +0 -68
- package/dist/stdlib/web.d.ts +0 -4
- package/dist/stdlib/web.js +0 -20
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
import type { Node } from "acorn";
|
|
2
1
|
import type { Effect } from "effect";
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import type { SafeObject } from "../tool-runtime.js";
|
|
3
|
+
import type { CodeModePromise, CodeModeRegExp, CodeModeURL } from "../values.js";
|
|
4
|
+
export type SourcePosition = {
|
|
5
|
+
line: number;
|
|
6
|
+
column: number;
|
|
7
|
+
};
|
|
8
|
+
export type SourceLocation = {
|
|
9
|
+
start: SourcePosition;
|
|
10
|
+
end: SourcePosition;
|
|
11
|
+
};
|
|
12
|
+
export type AstNode = {
|
|
13
|
+
type: string;
|
|
14
|
+
loc?: SourceLocation;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
};
|
|
17
|
+
export type ProgramNode = AstNode & {
|
|
18
|
+
type: "Program";
|
|
19
|
+
body: Array<AstNode>;
|
|
20
|
+
};
|
|
8
21
|
export type Binding = {
|
|
9
22
|
mutable: boolean;
|
|
10
23
|
value: unknown;
|
|
@@ -23,9 +36,17 @@ export type StatementResult = {
|
|
|
23
36
|
label?: string;
|
|
24
37
|
};
|
|
25
38
|
export type MemberReference = {
|
|
26
|
-
target:
|
|
39
|
+
target: SafeObject | Array<unknown> | CodeModeRegExp | CodeModeURL;
|
|
27
40
|
key: PropertyKey;
|
|
28
41
|
};
|
|
42
|
+
export declare class CodeModeFunction {
|
|
43
|
+
readonly parameters: ReadonlyArray<AstNode>;
|
|
44
|
+
readonly body: AstNode;
|
|
45
|
+
readonly capturedScopes: ReadonlyArray<Map<string, Binding>>;
|
|
46
|
+
readonly async: boolean;
|
|
47
|
+
readonly generator: boolean;
|
|
48
|
+
constructor(parameters: ReadonlyArray<AstNode>, body: AstNode, capturedScopes: ReadonlyArray<Map<string, Binding>>, async: boolean, generator: boolean);
|
|
49
|
+
}
|
|
29
50
|
export type GeneratorRequestKind = "next" | "return" | "throw";
|
|
30
51
|
export declare class CodeModeGenerator {
|
|
31
52
|
readonly asynchronous: boolean;
|
|
@@ -46,14 +67,51 @@ export declare class ComputedValue {
|
|
|
46
67
|
readonly value: unknown;
|
|
47
68
|
constructor(value: unknown);
|
|
48
69
|
}
|
|
70
|
+
export declare class PromiseNamespace {
|
|
71
|
+
}
|
|
72
|
+
export declare class SymbolNamespace {
|
|
73
|
+
}
|
|
49
74
|
export declare const AsyncIteratorSymbol: unique symbol;
|
|
50
75
|
export declare const IteratorSymbol: unique symbol;
|
|
51
76
|
export declare const IteratorSymbols: readonly [typeof AsyncIteratorSymbol, typeof IteratorSymbol];
|
|
77
|
+
export type PromiseMethodName = "all" | "allSettled" | "race" | "any" | "resolve" | "reject";
|
|
78
|
+
export declare class PromiseMethodReference {
|
|
79
|
+
readonly name: PromiseMethodName;
|
|
80
|
+
constructor(name: PromiseMethodName);
|
|
81
|
+
}
|
|
52
82
|
export type PromiseInstanceMethodName = "then" | "catch" | "finally";
|
|
53
83
|
export declare class PromiseInstanceMethodReference {
|
|
54
|
-
readonly promise:
|
|
84
|
+
readonly promise: CodeModePromise;
|
|
55
85
|
readonly name: PromiseInstanceMethodName;
|
|
56
|
-
constructor(promise:
|
|
86
|
+
constructor(promise: CodeModePromise, name: PromiseInstanceMethodName);
|
|
87
|
+
}
|
|
88
|
+
export declare class PromiseCapabilityFunction {
|
|
89
|
+
readonly settle: (value: unknown) => void;
|
|
90
|
+
constructor(settle: (value: unknown) => void);
|
|
91
|
+
}
|
|
92
|
+
export type GlobalNamespaceName = "Object" | "Math" | "JSON" | "Array" | "console" | "Date" | "RegExp" | "Map" | "Set" | "URL" | "URLSearchParams";
|
|
93
|
+
export declare class GlobalNamespace {
|
|
94
|
+
readonly name: GlobalNamespaceName;
|
|
95
|
+
constructor(name: GlobalNamespaceName);
|
|
96
|
+
}
|
|
97
|
+
export declare class GlobalMethodReference {
|
|
98
|
+
readonly namespace: Exclude<GlobalNamespaceName, "JSON"> | "Number" | "String";
|
|
99
|
+
readonly name: string;
|
|
100
|
+
constructor(namespace: Exclude<GlobalNamespaceName, "JSON"> | "Number" | "String", name: string);
|
|
101
|
+
}
|
|
102
|
+
export declare class JsonMethodReference {
|
|
103
|
+
readonly name: "parse" | "stringify";
|
|
104
|
+
constructor(name: "parse" | "stringify");
|
|
105
|
+
}
|
|
106
|
+
export declare class CoercionFunction {
|
|
107
|
+
readonly name: "Number" | "String" | "Boolean" | "parseInt" | "parseFloat" | "isFinite" | "isNaN";
|
|
108
|
+
constructor(name: "Number" | "String" | "Boolean" | "parseInt" | "parseFloat" | "isFinite" | "isNaN");
|
|
109
|
+
}
|
|
110
|
+
export declare class UriFunction {
|
|
111
|
+
readonly name: "encodeURI" | "encodeURIComponent" | "decodeURI" | "decodeURIComponent";
|
|
112
|
+
constructor(name: "encodeURI" | "encodeURIComponent" | "decodeURI" | "decodeURIComponent");
|
|
113
|
+
}
|
|
114
|
+
export declare class SearchFunction {
|
|
57
115
|
}
|
|
58
116
|
export declare class ProgramThrow {
|
|
59
117
|
readonly value: unknown;
|
|
@@ -63,7 +121,13 @@ export declare class GeneratorReturn {
|
|
|
63
121
|
readonly value: unknown;
|
|
64
122
|
constructor(value: unknown);
|
|
65
123
|
}
|
|
124
|
+
export declare class ErrorConstructorReference {
|
|
125
|
+
readonly name: string;
|
|
126
|
+
constructor(name: string);
|
|
127
|
+
}
|
|
128
|
+
export type DiagnosticKind = "ParseError" | "UnsupportedSyntax" | "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "InvalidDataValue" | "ToolCallLimitExceeded" | "TimeoutExceeded" | "ToolFailure" | "ExecutionFailure";
|
|
66
129
|
export declare const OptionalShortCircuit: unique symbol;
|
|
130
|
+
export declare const supportedSyntaxMessage = "Supported orchestration syntax: tools.* calls (they return promises - resolve them with await), data literals, destructuring, optional chaining, template literals, conditionals, switch, loops (incl. for...of and for...in over object/array/tools keys), arrow functions, spread, try/catch, array methods (map/filter/find/findIndex/some/every/reduce/flatMap/forEach/sort/slice/concat/indexOf/lastIndexOf/at/flat/reverse/includes/join), string methods (incl. match/matchAll/replace/split with regular expressions), Date/RegExp/Map/Set/URL/URLSearchParams, URI encoding helpers, Object/Math/JSON helpers, captured console.log/warn/error/dir/table, Promise.all/allSettled/race/any/resolve/reject over arrays mixing promises and plain values for parallel tool calls, promise chaining with .then/.catch/.finally, and new Promise((resolve, reject) => ...) construction.";
|
|
67
131
|
export declare class InterpreterRuntimeError extends Error {
|
|
68
132
|
readonly kind: DiagnosticKind;
|
|
69
133
|
readonly suggestions?: ReadonlyArray<string> | undefined;
|
|
@@ -72,9 +136,14 @@ export declare class InterpreterRuntimeError extends Error {
|
|
|
72
136
|
constructor(message: string, node?: AstNode, kind?: DiagnosticKind, suggestions?: ReadonlyArray<string> | undefined);
|
|
73
137
|
as(errorName: string): this;
|
|
74
138
|
}
|
|
75
|
-
export declare const supportedSyntaxMessage = "This is a restricted JavaScript-like language. Supported: plain and async functions, data literals, destructuring, standard control flow, await and Promise, and built-ins such as Array, Object, Math, JSON, Date, RegExp, Map, Set, and URL. Unsupported: classes, this, getters/setters, tagged templates, BigInt, and custom Symbols. Use plain functions and data objects instead.";
|
|
76
139
|
export declare const unsupportedSyntax: (kind: string, node: AstNode) => InterpreterRuntimeError;
|
|
77
140
|
export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
|
|
141
|
+
export declare const asNode: (value: unknown, context: string) => AstNode;
|
|
142
|
+
export declare const getArray: (node: AstNode, key: string) => Array<unknown>;
|
|
143
|
+
export declare const getString: (node: AstNode, key: string) => string;
|
|
144
|
+
export declare const getBoolean: (node: AstNode, key: string) => boolean;
|
|
145
|
+
export declare const getOptionalNode: (node: AstNode, key: string) => AstNode | undefined;
|
|
146
|
+
export declare const getNode: (node: AstNode, key: string) => AstNode;
|
|
78
147
|
export declare const sourceLocation: (node: AstNode) => {
|
|
79
148
|
readonly line: number;
|
|
80
149
|
readonly column: number;
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
export class CodeModeFunction {
|
|
2
|
+
parameters;
|
|
3
|
+
body;
|
|
4
|
+
capturedScopes;
|
|
5
|
+
async;
|
|
6
|
+
generator;
|
|
7
|
+
constructor(parameters, body, capturedScopes, async, generator) {
|
|
8
|
+
this.parameters = parameters;
|
|
9
|
+
this.body = body;
|
|
10
|
+
this.capturedScopes = capturedScopes;
|
|
11
|
+
this.async = async;
|
|
12
|
+
this.generator = generator;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
1
15
|
export class CodeModeGenerator {
|
|
2
16
|
asynchronous;
|
|
3
17
|
request;
|
|
@@ -28,9 +42,19 @@ export class ComputedValue {
|
|
|
28
42
|
this.value = value;
|
|
29
43
|
}
|
|
30
44
|
}
|
|
45
|
+
export class PromiseNamespace {
|
|
46
|
+
}
|
|
47
|
+
export class SymbolNamespace {
|
|
48
|
+
}
|
|
31
49
|
export const AsyncIteratorSymbol = Symbol("codemode.async-iterator");
|
|
32
50
|
export const IteratorSymbol = Symbol("codemode.iterator");
|
|
33
51
|
export const IteratorSymbols = [AsyncIteratorSymbol, IteratorSymbol];
|
|
52
|
+
export class PromiseMethodReference {
|
|
53
|
+
name;
|
|
54
|
+
constructor(name) {
|
|
55
|
+
this.name = name;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
34
58
|
export class PromiseInstanceMethodReference {
|
|
35
59
|
promise;
|
|
36
60
|
name;
|
|
@@ -39,6 +63,46 @@ export class PromiseInstanceMethodReference {
|
|
|
39
63
|
this.name = name;
|
|
40
64
|
}
|
|
41
65
|
}
|
|
66
|
+
export class PromiseCapabilityFunction {
|
|
67
|
+
settle;
|
|
68
|
+
constructor(settle) {
|
|
69
|
+
this.settle = settle;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export class GlobalNamespace {
|
|
73
|
+
name;
|
|
74
|
+
constructor(name) {
|
|
75
|
+
this.name = name;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export class GlobalMethodReference {
|
|
79
|
+
namespace;
|
|
80
|
+
name;
|
|
81
|
+
constructor(namespace, name) {
|
|
82
|
+
this.namespace = namespace;
|
|
83
|
+
this.name = name;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export class JsonMethodReference {
|
|
87
|
+
name;
|
|
88
|
+
constructor(name) {
|
|
89
|
+
this.name = name;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export class CoercionFunction {
|
|
93
|
+
name;
|
|
94
|
+
constructor(name) {
|
|
95
|
+
this.name = name;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export class UriFunction {
|
|
99
|
+
name;
|
|
100
|
+
constructor(name) {
|
|
101
|
+
this.name = name;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export class SearchFunction {
|
|
105
|
+
}
|
|
42
106
|
export class ProgramThrow {
|
|
43
107
|
value;
|
|
44
108
|
constructor(value) {
|
|
@@ -51,7 +115,14 @@ export class GeneratorReturn {
|
|
|
51
115
|
this.value = value;
|
|
52
116
|
}
|
|
53
117
|
}
|
|
118
|
+
export class ErrorConstructorReference {
|
|
119
|
+
name;
|
|
120
|
+
constructor(name) {
|
|
121
|
+
this.name = name;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
54
124
|
export const OptionalShortCircuit = Symbol("codemode.optional-short-circuit");
|
|
125
|
+
export const supportedSyntaxMessage = "Supported orchestration syntax: tools.* calls (they return promises - resolve them with await), data literals, destructuring, optional chaining, template literals, conditionals, switch, loops (incl. for...of and for...in over object/array/tools keys), arrow functions, spread, try/catch, array methods (map/filter/find/findIndex/some/every/reduce/flatMap/forEach/sort/slice/concat/indexOf/lastIndexOf/at/flat/reverse/includes/join), string methods (incl. match/matchAll/replace/split with regular expressions), Date/RegExp/Map/Set/URL/URLSearchParams, URI encoding helpers, Object/Math/JSON helpers, captured console.log/warn/error/dir/table, Promise.all/allSettled/race/any/resolve/reject over arrays mixing promises and plain values for parallel tool calls, promise chaining with .then/.catch/.finally, and new Promise((resolve, reject) => ...) construction.";
|
|
55
126
|
export class InterpreterRuntimeError extends Error {
|
|
56
127
|
kind;
|
|
57
128
|
suggestions;
|
|
@@ -70,10 +141,39 @@ export class InterpreterRuntimeError extends Error {
|
|
|
70
141
|
return this;
|
|
71
142
|
}
|
|
72
143
|
}
|
|
73
|
-
// Orient the agent rather than enumerate JavaScript; interpreter-support.md is the full matrix.
|
|
74
|
-
export const supportedSyntaxMessage = "This is a restricted JavaScript-like language. Supported: plain and async functions, data literals, destructuring, standard control flow, await and Promise, and built-ins such as Array, Object, Math, JSON, Date, RegExp, Map, Set, and URL. Unsupported: classes, this, getters/setters, tagged templates, BigInt, and custom Symbols. Use plain functions and data objects instead.";
|
|
75
144
|
export const unsupportedSyntax = (kind, node) => new InterpreterRuntimeError(`Syntax '${kind}' is not supported. ${supportedSyntaxMessage}`, node, "UnsupportedSyntax", [supportedSyntaxMessage]);
|
|
76
145
|
export const isRecord = (value) => typeof value === "object" && value !== null;
|
|
146
|
+
export const asNode = (value, context) => {
|
|
147
|
+
if (!isRecord(value) || typeof value.type !== "string") {
|
|
148
|
+
throw new InterpreterRuntimeError(`Invalid AST node while reading ${context}.`);
|
|
149
|
+
}
|
|
150
|
+
return value;
|
|
151
|
+
};
|
|
152
|
+
export const getArray = (node, key) => {
|
|
153
|
+
const value = node[key];
|
|
154
|
+
if (!Array.isArray(value))
|
|
155
|
+
throw new InterpreterRuntimeError(`Expected '${key}' to be an array.`, node);
|
|
156
|
+
return value;
|
|
157
|
+
};
|
|
158
|
+
export const getString = (node, key) => {
|
|
159
|
+
const value = node[key];
|
|
160
|
+
if (typeof value !== "string")
|
|
161
|
+
throw new InterpreterRuntimeError(`Expected '${key}' to be a string.`, node);
|
|
162
|
+
return value;
|
|
163
|
+
};
|
|
164
|
+
export const getBoolean = (node, key) => {
|
|
165
|
+
const value = node[key];
|
|
166
|
+
if (typeof value !== "boolean")
|
|
167
|
+
throw new InterpreterRuntimeError(`Expected '${key}' to be a boolean.`, node);
|
|
168
|
+
return value;
|
|
169
|
+
};
|
|
170
|
+
export const getOptionalNode = (node, key) => {
|
|
171
|
+
const value = node[key];
|
|
172
|
+
if (value === undefined || value === null)
|
|
173
|
+
return undefined;
|
|
174
|
+
return asNode(value, key);
|
|
175
|
+
};
|
|
176
|
+
export const getNode = (node, key) => asNode(node[key], key);
|
|
77
177
|
export const sourceLocation = (node) => ({
|
|
78
178
|
line: Math.max(1, (node.loc?.start.line ?? 2) - 1),
|
|
79
179
|
column: Math.max(1, (node.loc?.start.column ?? 4) - 3),
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Effect, Exit, Scope } from "effect";
|
|
2
2
|
import type { Diagnostic } from "../codemode.js";
|
|
3
|
-
import { type AstNode, InterpreterRuntimeError, PromiseInstanceMethodReference } from "./model.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { type AstNode, InterpreterRuntimeError, PromiseInstanceMethodReference, PromiseMethodReference } from "./model.js";
|
|
4
|
+
import { type CallbackRunner } from "./methods.js";
|
|
5
|
+
import { CodeModePromise } from "../values.js";
|
|
6
|
+
import type { SyncIteratorRunner } from "./iterator.js";
|
|
7
7
|
export declare class PromiseRuntime<R> {
|
|
8
8
|
private readonly scope;
|
|
9
9
|
private readonly active;
|
|
@@ -12,20 +12,18 @@ export declare class PromiseRuntime<R> {
|
|
|
12
12
|
private readonly failures;
|
|
13
13
|
private nextID;
|
|
14
14
|
constructor(scope: Scope.Scope);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<Values.Promise, never, R>;
|
|
19
|
-
markObserved(promise: Values.Promise): void;
|
|
20
|
-
await(promise: Values.Promise): Effect.Effect<Exit.Exit<unknown, unknown>>;
|
|
15
|
+
create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<CodeModePromise, never, R>;
|
|
16
|
+
markObserved(promise: CodeModePromise): void;
|
|
17
|
+
await(promise: CodeModePromise): Effect.Effect<Exit.Exit<unknown, unknown>>;
|
|
21
18
|
fork(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<void, never, R>;
|
|
22
19
|
diagnostics(): Array<Diagnostic>;
|
|
23
20
|
interrupt(): Effect.Effect<Array<Diagnostic>>;
|
|
24
21
|
}
|
|
25
22
|
export declare const selfResolutionError: (node?: AstNode) => InterpreterRuntimeError;
|
|
26
|
-
export declare const resolvePromiseValue: <R>(runner:
|
|
27
|
-
promise?:
|
|
23
|
+
export declare const resolvePromiseValue: <R>(runner: CallbackRunner<R>, value: unknown, node: AstNode, own?: {
|
|
24
|
+
promise?: CodeModePromise;
|
|
28
25
|
}) => Effect.Effect<unknown, unknown, R>;
|
|
29
|
-
export declare const resolvePromise: <R>(runner:
|
|
30
|
-
export declare const
|
|
31
|
-
export declare const
|
|
26
|
+
export declare const resolvePromise: <R>(runner: CallbackRunner<R>, promises: PromiseRuntime<R>, value: unknown, node: AstNode) => Effect.Effect<CodeModePromise, never, R>;
|
|
27
|
+
export declare const invokePromiseMethod: <R>(runner: CallbackRunner<R> & SyncIteratorRunner<R>, promises: PromiseRuntime<R>, ref: PromiseMethodReference, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
28
|
+
export declare const invokePromiseInstanceMethod: <R>(runner: CallbackRunner<R>, promises: PromiseRuntime<R>, ref: PromiseInstanceMethodReference, args: Array<unknown>, node: AstNode) => Effect.Effect<CodeModePromise, never, R>;
|
|
29
|
+
export declare const constructPromise: <R>(runner: CallbackRunner<R>, promises: PromiseRuntime<R>, executor: unknown, node: AstNode) => Effect.Effect<CodeModePromise, unknown, R>;
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
import { Cause, Deferred, Effect, Exit, Fiber, Scope } from "effect";
|
|
2
|
-
import { InterpreterRuntimeError, ProgramThrow, PromiseInstanceMethodReference } from "./model.js";
|
|
3
|
-
import { get, ProgramArray, ProgramFunction, ProgramObject, record } from "./objects.js";
|
|
4
|
-
import { HostFunction, requiresNew, sync } from "./host.js";
|
|
2
|
+
import { CodeModeFunction, InterpreterRuntimeError, ProgramThrow, PromiseCapabilityFunction, PromiseInstanceMethodReference, PromiseMethodReference, } from "./model.js";
|
|
5
3
|
import { caughtErrorValue, normalizeError } from "./errors.js";
|
|
4
|
+
import { applyCollectionCallback, isSupportedCallback } from "./methods.js";
|
|
6
5
|
import { typeofValue } from "./references.js";
|
|
7
6
|
import { createAggregateErrorValue } from "../stdlib/value.js";
|
|
8
|
-
import {
|
|
9
|
-
import { applyCollectionCallback, isSupportedCallback } from "./runner.js";
|
|
10
|
-
// A `resolve`/`reject` handed to an executor or thenable: calling it settles the capability.
|
|
11
|
-
const capability = (name, settle) => sync(name, (args) => {
|
|
12
|
-
settle(args[0]);
|
|
13
|
-
return undefined;
|
|
14
|
-
});
|
|
7
|
+
import { CodeModePromise } from "../values.js";
|
|
15
8
|
// Observation only controls rejection reporting; program completion interrupts all promise work.
|
|
16
9
|
export class PromiseRuntime {
|
|
17
10
|
scope;
|
|
@@ -23,20 +16,12 @@ export class PromiseRuntime {
|
|
|
23
16
|
constructor(scope) {
|
|
24
17
|
this.scope = scope;
|
|
25
18
|
}
|
|
26
|
-
// Resolution bodies need the promise's own identity to reject `resolve(promise)` self-resolution.
|
|
27
|
-
createWithSelf(body) {
|
|
28
|
-
const self = {};
|
|
29
|
-
return Effect.map(this.create(body(self)), (promise) => {
|
|
30
|
-
self.promise = promise;
|
|
31
|
-
return promise;
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
19
|
create(effect) {
|
|
35
20
|
return Effect.suspend(() => {
|
|
36
21
|
// Allocate before forking so reruns get distinct IDs and diagnostics retain creation order.
|
|
37
22
|
const id = this.nextID++;
|
|
38
23
|
return Effect.map(Effect.forkIn(effect, this.scope, { startImmediately: true }), (fiber) => {
|
|
39
|
-
const promise = new
|
|
24
|
+
const promise = new CodeModePromise(fiber);
|
|
40
25
|
this.active.add(promise);
|
|
41
26
|
this.ids.set(promise, id);
|
|
42
27
|
fiber.addObserver((exit) => {
|
|
@@ -87,19 +72,23 @@ export const selfResolutionError = (node) => new InterpreterRuntimeError("Chaini
|
|
|
87
72
|
export const resolvePromiseValue = (runner, value, node, own) => {
|
|
88
73
|
if (own?.promise !== undefined && value === own.promise)
|
|
89
74
|
return Effect.fail(selfResolutionError(node));
|
|
90
|
-
if (value instanceof
|
|
75
|
+
if (value instanceof CodeModePromise)
|
|
91
76
|
return runner.settlePromise(value);
|
|
92
|
-
if (!(value
|
|
77
|
+
if (value === null || typeof value !== "object" || !Object.hasOwn(value, "then"))
|
|
93
78
|
return Effect.succeed(value);
|
|
94
|
-
const then =
|
|
79
|
+
const then = value.then;
|
|
95
80
|
if (typeofValue(then) !== "function")
|
|
96
81
|
return Effect.succeed(value);
|
|
97
82
|
return Effect.gen(function* () {
|
|
98
83
|
// Promise resolution invokes a thenable's method in a later job.
|
|
99
84
|
yield* Effect.yieldNow;
|
|
100
85
|
const deferred = Deferred.makeUnsafe();
|
|
101
|
-
const resolve =
|
|
102
|
-
|
|
86
|
+
const resolve = new PromiseCapabilityFunction((result) => {
|
|
87
|
+
Deferred.doneUnsafe(deferred, Exit.succeed(result));
|
|
88
|
+
});
|
|
89
|
+
const reject = new PromiseCapabilityFunction((reason) => {
|
|
90
|
+
Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(reason)));
|
|
91
|
+
});
|
|
103
92
|
const executed = yield* Effect.exit(runner.invokeCallable(then, [resolve, reject], node));
|
|
104
93
|
if (!Exit.isSuccess(executed)) {
|
|
105
94
|
if (Cause.hasInterruptsOnly(executed.cause))
|
|
@@ -110,22 +99,25 @@ export const resolvePromiseValue = (runner, value, node, own) => {
|
|
|
110
99
|
});
|
|
111
100
|
};
|
|
112
101
|
export const resolvePromise = (runner, promises, value, node) => {
|
|
113
|
-
if (value instanceof
|
|
102
|
+
if (value instanceof CodeModePromise)
|
|
114
103
|
return Effect.succeed(value);
|
|
115
|
-
|
|
104
|
+
const box = {};
|
|
105
|
+
return Effect.map(promises.create(resolvePromiseValue(runner, value, node, box)), (promise) => {
|
|
106
|
+
box.promise = promise;
|
|
107
|
+
return promise;
|
|
108
|
+
});
|
|
116
109
|
};
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
if (name === "resolve") {
|
|
110
|
+
export const invokePromiseMethod = (runner, promises, ref, args, node) => {
|
|
111
|
+
if (ref.name === "resolve") {
|
|
120
112
|
return resolvePromise(runner, promises, args[0], node);
|
|
121
113
|
}
|
|
122
|
-
if (name === "reject") {
|
|
114
|
+
if (ref.name === "reject") {
|
|
123
115
|
return promises.create(Effect.fail(new ProgramThrow(args[0])));
|
|
124
116
|
}
|
|
125
117
|
return promises.create(Effect.gen(function* () {
|
|
126
118
|
const cursor = yield* runner.syncIterator(args[0], node);
|
|
127
119
|
if (cursor === undefined) {
|
|
128
|
-
throw new InterpreterRuntimeError(`Promise.${name} expects an array or other synchronous iterable.`, node).as("TypeError");
|
|
120
|
+
throw new InterpreterRuntimeError(`Promise.${ref.name} expects an array or other synchronous iterable.`, node).as("TypeError");
|
|
129
121
|
}
|
|
130
122
|
const items = [];
|
|
131
123
|
while (true) {
|
|
@@ -136,25 +128,28 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
|
|
|
136
128
|
promises.markObserved(item);
|
|
137
129
|
items.push(item);
|
|
138
130
|
}
|
|
139
|
-
if (name === "all") {
|
|
140
|
-
return
|
|
131
|
+
if (ref.name === "all") {
|
|
132
|
+
return yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(promises.await(item))), { concurrency: "unbounded" }));
|
|
141
133
|
}
|
|
142
|
-
if (name === "allSettled") {
|
|
134
|
+
if (ref.name === "allSettled") {
|
|
143
135
|
const outcomes = [];
|
|
144
136
|
for (const item of items) {
|
|
145
137
|
const exit = yield* promises.await(item);
|
|
146
138
|
if (Exit.isSuccess(exit)) {
|
|
147
|
-
outcomes.push(
|
|
139
|
+
outcomes.push(Object.assign(Object.create(null), { status: "fulfilled", value: exit.value }));
|
|
148
140
|
continue;
|
|
149
141
|
}
|
|
150
142
|
if (Cause.hasInterruptsOnly(exit.cause))
|
|
151
143
|
return yield* Effect.failCause(exit.cause);
|
|
152
|
-
outcomes.push(
|
|
144
|
+
outcomes.push(Object.assign(Object.create(null), {
|
|
145
|
+
status: "rejected",
|
|
146
|
+
reason: caughtErrorValue(Cause.squash(exit.cause)),
|
|
147
|
+
}));
|
|
153
148
|
}
|
|
154
149
|
yield* Effect.yieldNow;
|
|
155
|
-
return
|
|
150
|
+
return outcomes;
|
|
156
151
|
}
|
|
157
|
-
if (name === "race") {
|
|
152
|
+
if (ref.name === "race") {
|
|
158
153
|
if (items.length === 0) {
|
|
159
154
|
throw new InterpreterRuntimeError("Promise.race([]) would never settle; provide at least one promise or value.", node);
|
|
160
155
|
}
|
|
@@ -180,15 +175,21 @@ export const invokePromiseInstanceMethod = (runner, promises, ref, args, node) =
|
|
|
180
175
|
const onRejected = reactionHandler(ref.name === "then" ? args[1] : args[0], method, node);
|
|
181
176
|
return chainReaction(runner, promises, ref.promise, onFulfilled, onRejected, method, node);
|
|
182
177
|
};
|
|
183
|
-
const constructPromise = (runner, promises, executor, node) => {
|
|
184
|
-
if (!(executor instanceof
|
|
178
|
+
export const constructPromise = (runner, promises, executor, node) => {
|
|
179
|
+
if (!(executor instanceof CodeModeFunction)) {
|
|
185
180
|
throw new InterpreterRuntimeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).", node).as("TypeError");
|
|
186
181
|
}
|
|
187
182
|
return Effect.gen(function* () {
|
|
188
183
|
const deferred = Deferred.makeUnsafe();
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
|
|
184
|
+
const box = {};
|
|
185
|
+
const promise = yield* promises.create(Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(runner, value, node, box)));
|
|
186
|
+
box.promise = promise;
|
|
187
|
+
const resolve = new PromiseCapabilityFunction((value) => {
|
|
188
|
+
Deferred.doneUnsafe(deferred, Exit.succeed(value));
|
|
189
|
+
});
|
|
190
|
+
const reject = new PromiseCapabilityFunction((value) => {
|
|
191
|
+
Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(value)));
|
|
192
|
+
});
|
|
192
193
|
const executed = yield* Effect.exit(runner.invokeFunction(executor, [resolve, reject]));
|
|
193
194
|
if (!Exit.isSuccess(executed)) {
|
|
194
195
|
if (Cause.hasInterruptsOnly(executed.cause))
|
|
@@ -223,15 +224,20 @@ const reactionExit = (promises, source) => Effect.gen(function* () {
|
|
|
223
224
|
return exit;
|
|
224
225
|
});
|
|
225
226
|
const chainReaction = (runner, promises, source, onFulfilled, onRejected, method, node) => {
|
|
226
|
-
|
|
227
|
+
const box = {};
|
|
228
|
+
const body = Effect.gen(function* () {
|
|
227
229
|
const exit = yield* reactionExit(promises, source);
|
|
228
230
|
const handler = Exit.isSuccess(exit) ? onFulfilled : onRejected;
|
|
229
231
|
if (handler === undefined)
|
|
230
232
|
return yield* exit;
|
|
231
233
|
const input = Exit.isSuccess(exit) ? exit.value : caughtErrorValue(Cause.squash(exit.cause));
|
|
232
234
|
const result = yield* applyCollectionCallback(runner, handler, method, node)([input]);
|
|
233
|
-
return yield* resolvePromiseValue(runner, result, node,
|
|
234
|
-
})
|
|
235
|
+
return yield* resolvePromiseValue(runner, result, node, box);
|
|
236
|
+
});
|
|
237
|
+
return Effect.map(promises.create(body), (derived) => {
|
|
238
|
+
box.promise = derived;
|
|
239
|
+
return derived;
|
|
240
|
+
});
|
|
235
241
|
};
|
|
236
242
|
const chainFinally = (runner, promises, source, cleanup, method, node) => promises.create(Effect.gen(function* () {
|
|
237
243
|
const exit = yield* reactionExit(promises, source);
|
|
@@ -245,27 +251,3 @@ const chainFinally = (runner, promises, source, cleanup, method, node) => promis
|
|
|
245
251
|
}
|
|
246
252
|
return yield* exit;
|
|
247
253
|
}));
|
|
248
|
-
export const promiseGlobal = (runner, promises) => {
|
|
249
|
-
// Combinators are not callbacks: `[p].map(Promise.resolve)` must ask for an arrow function.
|
|
250
|
-
const statics = new Map(promiseStatics.map((name) => [
|
|
251
|
-
name,
|
|
252
|
-
new HostFunction({
|
|
253
|
-
name: `Promise.${name}`,
|
|
254
|
-
call: (args, node) => invokePromiseMethod(runner, promises, name, args, node),
|
|
255
|
-
callback: false,
|
|
256
|
-
}),
|
|
257
|
-
]));
|
|
258
|
-
return new HostFunction({
|
|
259
|
-
name: "Promise",
|
|
260
|
-
call: requiresNew("Promise"),
|
|
261
|
-
construct: (args, node) => constructPromise(runner, promises, args[0], node),
|
|
262
|
-
instanceOf: (value) => value instanceof Values.Promise,
|
|
263
|
-
// Unknown statics fail loudly so a missing await cannot hide behind `undefined`.
|
|
264
|
-
members: (key, node) => {
|
|
265
|
-
const method = typeof key === "string" ? statics.get(key) : undefined;
|
|
266
|
-
if (method !== undefined)
|
|
267
|
-
return method;
|
|
268
|
-
throw new InterpreterRuntimeError(`Promise.${String(key)} is not available. Available: Promise.all, Promise.allSettled, Promise.race, Promise.any, Promise.resolve, and Promise.reject; consume promises with await.`, node);
|
|
269
|
-
},
|
|
270
|
-
});
|
|
271
|
-
};
|
|
@@ -3,5 +3,4 @@ export declare const isRuntimeReference: (value: unknown) => boolean;
|
|
|
3
3
|
export declare const containsRuntimeReference: (value: unknown) => boolean;
|
|
4
4
|
export declare const containsOpaqueReference: (value: unknown) => boolean;
|
|
5
5
|
export declare const rejectCircularInsertion: (container: object, value: unknown, label: string, node: AstNode, seen?: Set<object>) => void;
|
|
6
|
-
export declare const describeValue: (value: unknown) => string;
|
|
7
6
|
export declare const typeofValue: (value: unknown) => string;
|