@barnum/barnum 0.3.0 → 0.4.0
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/artifacts/linux-arm64/barnum +0 -0
- package/artifacts/linux-x64/barnum +0 -0
- package/artifacts/macos-arm64/barnum +0 -0
- package/artifacts/macos-x64/barnum +0 -0
- package/artifacts/win-x64/barnum.exe +0 -0
- package/dist/all.d.ts +41 -10
- package/dist/all.d.ts.map +1 -0
- package/dist/all.js +1 -1
- package/dist/ast.d.ts +199 -98
- package/dist/ast.d.ts.map +1 -0
- package/dist/ast.js +271 -233
- package/dist/bind.d.ts +9 -12
- package/dist/bind.d.ts.map +1 -0
- package/dist/bind.js +14 -51
- package/dist/builtins/array.d.ts +36 -0
- package/dist/builtins/array.d.ts.map +1 -0
- package/dist/builtins/array.js +93 -0
- package/dist/builtins/index.d.ts +6 -0
- package/dist/builtins/index.d.ts.map +1 -0
- package/dist/builtins/index.js +5 -0
- package/dist/builtins/scalar.d.ts +12 -0
- package/dist/builtins/scalar.d.ts.map +1 -0
- package/dist/builtins/scalar.js +41 -0
- package/dist/builtins/struct.d.ts +25 -0
- package/dist/builtins/struct.d.ts.map +1 -0
- package/dist/builtins/struct.js +67 -0
- package/dist/builtins/tagged-union.d.ts +54 -0
- package/dist/builtins/tagged-union.d.ts.map +1 -0
- package/dist/builtins/tagged-union.js +81 -0
- package/dist/builtins/with-resource.d.ts +23 -0
- package/dist/builtins/with-resource.d.ts.map +1 -0
- package/dist/builtins/with-resource.js +35 -0
- package/dist/chain.d.ts +1 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +3 -3
- package/dist/effect-id.d.ts +1 -0
- package/dist/effect-id.d.ts.map +1 -0
- package/dist/handler.d.ts +7 -6
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +5 -21
- package/dist/index.d.ts +10 -6
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -2
- package/dist/iterator.d.ts +32 -0
- package/dist/iterator.d.ts.map +1 -0
- package/dist/iterator.js +123 -0
- package/dist/option.d.ts +74 -0
- package/dist/option.d.ts.map +1 -0
- package/dist/option.js +141 -0
- package/dist/pipe.d.ts +11 -10
- package/dist/pipe.d.ts.map +1 -0
- package/dist/pipe.js +5 -4
- package/dist/race.d.ts +5 -4
- package/dist/race.d.ts.map +1 -0
- package/dist/race.js +17 -42
- package/dist/recursive.d.ts +9 -3
- package/dist/recursive.d.ts.map +1 -0
- package/dist/recursive.js +18 -13
- package/dist/result.d.ts +50 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +117 -0
- package/dist/run.d.ts +9 -2
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +37 -20
- package/dist/runtime.d.ts +6 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +7 -0
- package/dist/schema.d.ts +1 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schemas.d.ts +5 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +13 -0
- package/dist/try-catch.d.ts +2 -1
- package/dist/try-catch.d.ts.map +1 -0
- package/dist/try-catch.js +10 -9
- package/dist/values.d.ts +6 -0
- package/dist/values.d.ts.map +1 -0
- package/dist/values.js +12 -0
- package/dist/worker.d.ts +5 -1
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +15 -3
- package/package.json +8 -6
- package/src/all.ts +118 -74
- package/src/ast.ts +773 -350
- package/src/bind.ts +32 -62
- package/src/builtins/array.ts +121 -0
- package/src/builtins/index.ts +17 -0
- package/src/builtins/scalar.ts +49 -0
- package/src/builtins/struct.ts +111 -0
- package/src/builtins/tagged-union.ts +142 -0
- package/src/builtins/with-resource.ts +69 -0
- package/src/chain.ts +4 -4
- package/src/handler.ts +12 -28
- package/src/index.ts +24 -17
- package/src/iterator.ts +243 -0
- package/src/option.ts +199 -0
- package/src/pipe.ts +123 -78
- package/src/race.ts +41 -51
- package/src/recursive.ts +44 -27
- package/src/result.ts +168 -0
- package/src/run.ts +53 -25
- package/src/runtime.ts +16 -0
- package/src/schemas.ts +21 -0
- package/src/try-catch.ts +14 -10
- package/src/values.ts +21 -0
- package/src/worker.ts +17 -2
- package/dist/builtins.d.ts +0 -257
- package/dist/builtins.js +0 -600
- package/src/builtins.ts +0 -804
package/src/pipe.ts
CHANGED
|
@@ -3,91 +3,136 @@ import {
|
|
|
3
3
|
type PipeIn,
|
|
4
4
|
type Pipeable,
|
|
5
5
|
type TypedAction,
|
|
6
|
-
|
|
6
|
+
toAction,
|
|
7
7
|
} from "./ast.js";
|
|
8
|
-
import {
|
|
8
|
+
import { chain } from "./chain.js";
|
|
9
|
+
import { identity } from "./builtins/index.js";
|
|
9
10
|
|
|
10
|
-
export function pipe<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
a1: Pipeable<
|
|
73
|
-
a2: Pipeable<
|
|
74
|
-
a3: Pipeable<
|
|
75
|
-
a4: Pipeable<
|
|
76
|
-
a5: Pipeable<
|
|
77
|
-
a6: Pipeable<
|
|
78
|
-
a7: Pipeable<
|
|
79
|
-
a8: Pipeable<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
11
|
+
export function pipe<TStep1, TStep2>(
|
|
12
|
+
a1: Pipeable<TStep1, TStep2>,
|
|
13
|
+
): TypedAction<PipeIn<TStep1>, TStep2>;
|
|
14
|
+
export function pipe<TStep1, TStep2, TStep3>(
|
|
15
|
+
a1: Pipeable<TStep1, TStep2>,
|
|
16
|
+
a2: Pipeable<TStep2, TStep3>,
|
|
17
|
+
): TypedAction<PipeIn<TStep1>, TStep3>;
|
|
18
|
+
export function pipe<TStep1, TStep2, TStep3, TStep4>(
|
|
19
|
+
a1: Pipeable<TStep1, TStep2>,
|
|
20
|
+
a2: Pipeable<TStep2, TStep3>,
|
|
21
|
+
a3: Pipeable<TStep3, TStep4>,
|
|
22
|
+
): TypedAction<PipeIn<TStep1>, TStep4>;
|
|
23
|
+
export function pipe<TStep1, TStep2, TStep3, TStep4, TStep5>(
|
|
24
|
+
a1: Pipeable<TStep1, TStep2>,
|
|
25
|
+
a2: Pipeable<TStep2, TStep3>,
|
|
26
|
+
a3: Pipeable<TStep3, TStep4>,
|
|
27
|
+
a4: Pipeable<TStep4, TStep5>,
|
|
28
|
+
): TypedAction<PipeIn<TStep1>, TStep5>;
|
|
29
|
+
export function pipe<TStep1, TStep2, TStep3, TStep4, TStep5, TStep6>(
|
|
30
|
+
a1: Pipeable<TStep1, TStep2>,
|
|
31
|
+
a2: Pipeable<TStep2, TStep3>,
|
|
32
|
+
a3: Pipeable<TStep3, TStep4>,
|
|
33
|
+
a4: Pipeable<TStep4, TStep5>,
|
|
34
|
+
a5: Pipeable<TStep5, TStep6>,
|
|
35
|
+
): TypedAction<PipeIn<TStep1>, TStep6>;
|
|
36
|
+
export function pipe<TStep1, TStep2, TStep3, TStep4, TStep5, TStep6, TStep7>(
|
|
37
|
+
a1: Pipeable<TStep1, TStep2>,
|
|
38
|
+
a2: Pipeable<TStep2, TStep3>,
|
|
39
|
+
a3: Pipeable<TStep3, TStep4>,
|
|
40
|
+
a4: Pipeable<TStep4, TStep5>,
|
|
41
|
+
a5: Pipeable<TStep5, TStep6>,
|
|
42
|
+
a6: Pipeable<TStep6, TStep7>,
|
|
43
|
+
): TypedAction<PipeIn<TStep1>, TStep7>;
|
|
44
|
+
export function pipe<
|
|
45
|
+
TStep1,
|
|
46
|
+
TStep2,
|
|
47
|
+
TStep3,
|
|
48
|
+
TStep4,
|
|
49
|
+
TStep5,
|
|
50
|
+
TStep6,
|
|
51
|
+
TStep7,
|
|
52
|
+
TStep8,
|
|
53
|
+
>(
|
|
54
|
+
a1: Pipeable<TStep1, TStep2>,
|
|
55
|
+
a2: Pipeable<TStep2, TStep3>,
|
|
56
|
+
a3: Pipeable<TStep3, TStep4>,
|
|
57
|
+
a4: Pipeable<TStep4, TStep5>,
|
|
58
|
+
a5: Pipeable<TStep5, TStep6>,
|
|
59
|
+
a6: Pipeable<TStep6, TStep7>,
|
|
60
|
+
a7: Pipeable<TStep7, TStep8>,
|
|
61
|
+
): TypedAction<PipeIn<TStep1>, TStep8>;
|
|
62
|
+
export function pipe<
|
|
63
|
+
TStep1,
|
|
64
|
+
TStep2,
|
|
65
|
+
TStep3,
|
|
66
|
+
TStep4,
|
|
67
|
+
TStep5,
|
|
68
|
+
TStep6,
|
|
69
|
+
TStep7,
|
|
70
|
+
TStep8,
|
|
71
|
+
TStep9,
|
|
72
|
+
>(
|
|
73
|
+
a1: Pipeable<TStep1, TStep2>,
|
|
74
|
+
a2: Pipeable<TStep2, TStep3>,
|
|
75
|
+
a3: Pipeable<TStep3, TStep4>,
|
|
76
|
+
a4: Pipeable<TStep4, TStep5>,
|
|
77
|
+
a5: Pipeable<TStep5, TStep6>,
|
|
78
|
+
a6: Pipeable<TStep6, TStep7>,
|
|
79
|
+
a7: Pipeable<TStep7, TStep8>,
|
|
80
|
+
a8: Pipeable<TStep8, TStep9>,
|
|
81
|
+
): TypedAction<PipeIn<TStep1>, TStep9>;
|
|
82
|
+
export function pipe<
|
|
83
|
+
TStep1,
|
|
84
|
+
TStep2,
|
|
85
|
+
TStep3,
|
|
86
|
+
TStep4,
|
|
87
|
+
TStep5,
|
|
88
|
+
TStep6,
|
|
89
|
+
TStep7,
|
|
90
|
+
TStep8,
|
|
91
|
+
TStep9,
|
|
92
|
+
TStep10,
|
|
93
|
+
>(
|
|
94
|
+
a1: Pipeable<TStep1, TStep2>,
|
|
95
|
+
a2: Pipeable<TStep2, TStep3>,
|
|
96
|
+
a3: Pipeable<TStep3, TStep4>,
|
|
97
|
+
a4: Pipeable<TStep4, TStep5>,
|
|
98
|
+
a5: Pipeable<TStep5, TStep6>,
|
|
99
|
+
a6: Pipeable<TStep6, TStep7>,
|
|
100
|
+
a7: Pipeable<TStep7, TStep8>,
|
|
101
|
+
a8: Pipeable<TStep8, TStep9>,
|
|
102
|
+
a9: Pipeable<TStep9, TStep10>,
|
|
103
|
+
): TypedAction<PipeIn<TStep1>, TStep10>;
|
|
104
|
+
export function pipe<
|
|
105
|
+
TStep1,
|
|
106
|
+
TStep2,
|
|
107
|
+
TStep3,
|
|
108
|
+
TStep4,
|
|
109
|
+
TStep5,
|
|
110
|
+
TStep6,
|
|
111
|
+
TStep7,
|
|
112
|
+
TStep8,
|
|
113
|
+
TStep9,
|
|
114
|
+
TStep10,
|
|
115
|
+
TStep11,
|
|
116
|
+
>(
|
|
117
|
+
a1: Pipeable<TStep1, TStep2>,
|
|
118
|
+
a2: Pipeable<TStep2, TStep3>,
|
|
119
|
+
a3: Pipeable<TStep3, TStep4>,
|
|
120
|
+
a4: Pipeable<TStep4, TStep5>,
|
|
121
|
+
a5: Pipeable<TStep5, TStep6>,
|
|
122
|
+
a6: Pipeable<TStep6, TStep7>,
|
|
123
|
+
a7: Pipeable<TStep7, TStep8>,
|
|
124
|
+
a8: Pipeable<TStep8, TStep9>,
|
|
125
|
+
a9: Pipeable<TStep9, TStep10>,
|
|
126
|
+
a10: Pipeable<TStep10, TStep11>,
|
|
127
|
+
): TypedAction<PipeIn<TStep1>, TStep11>;
|
|
83
128
|
export function pipe(...actions: Action[]): Action {
|
|
84
129
|
if (actions.length === 0) {
|
|
85
|
-
return identity;
|
|
130
|
+
return identity();
|
|
86
131
|
}
|
|
87
132
|
if (actions.length === 1) {
|
|
88
133
|
return actions[0];
|
|
89
134
|
}
|
|
90
|
-
return actions.reduceRight(
|
|
91
|
-
(
|
|
135
|
+
return actions.reduceRight((rest, first) =>
|
|
136
|
+
toAction(chain(toAction(first), toAction(rest))),
|
|
92
137
|
);
|
|
93
138
|
}
|
package/src/race.ts
CHANGED
|
@@ -1,43 +1,32 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type Action,
|
|
3
3
|
type Pipeable,
|
|
4
|
-
type Result,
|
|
4
|
+
type Result as ResultT,
|
|
5
5
|
type TypedAction,
|
|
6
|
+
toAction,
|
|
6
7
|
typedAction,
|
|
7
8
|
buildRestartBranchAction,
|
|
8
|
-
TAG_BREAK,
|
|
9
|
-
IDENTITY,
|
|
10
9
|
} from "./ast.js";
|
|
10
|
+
import { chain } from "./chain.js";
|
|
11
|
+
import { identity, tag } from "./builtins/index.js";
|
|
12
|
+
import { Result } from "./result.js";
|
|
11
13
|
import {
|
|
12
14
|
allocateRestartHandlerId,
|
|
13
15
|
type RestartHandlerId,
|
|
14
16
|
} from "./effect-id.js";
|
|
15
17
|
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
// Shared AST fragments
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
const TAG_OK: Action = {
|
|
21
|
-
kind: "Invoke",
|
|
22
|
-
handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Ok" } },
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const TAG_ERR: Action = {
|
|
26
|
-
kind: "Invoke",
|
|
27
|
-
handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Err" } },
|
|
28
|
-
};
|
|
29
|
-
|
|
30
18
|
/**
|
|
31
19
|
* `Chain(Tag("Break"), RestartPerform(id))` — shared by race branches.
|
|
32
20
|
* The winning branch tags its result as Break, then performs. The handler
|
|
33
21
|
* restarts the body; Branch takes the Break arm (identity), `RestartHandle` exits.
|
|
34
22
|
*/
|
|
35
23
|
function breakPerform(restartHandlerId: RestartHandlerId): Action {
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
24
|
+
return toAction(
|
|
25
|
+
chain(toAction(tag("Break", "LoopResult")), {
|
|
26
|
+
kind: "RestartPerform",
|
|
27
|
+
restart_handler_id: restartHandlerId,
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
41
30
|
}
|
|
42
31
|
|
|
43
32
|
// ---------------------------------------------------------------------------
|
|
@@ -53,7 +42,7 @@ function breakPerform(restartHandlerId: RestartHandlerId): Action {
|
|
|
53
42
|
*
|
|
54
43
|
* Compiled form (restart+Branch, same substrate as loop/earlyReturn):
|
|
55
44
|
* `Chain(Tag("Continue"),`
|
|
56
|
-
* `RestartHandle(id,
|
|
45
|
+
* `RestartHandle(id, GetIndex(0),`
|
|
57
46
|
* `Branch({`
|
|
58
47
|
* `Continue: All(Chain(a, breakPerform), Chain(b, breakPerform), ...),`
|
|
59
48
|
* `Break: identity,`
|
|
@@ -68,16 +57,14 @@ export function race<TIn, TOut>(
|
|
|
68
57
|
const restartHandlerId = allocateRestartHandlerId();
|
|
69
58
|
const perform = breakPerform(restartHandlerId);
|
|
70
59
|
|
|
71
|
-
const branches = actions.map((action) =>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
rest: perform,
|
|
75
|
-
}));
|
|
60
|
+
const branches = actions.map((action) =>
|
|
61
|
+
toAction(chain(toAction(action), toAction(perform))),
|
|
62
|
+
);
|
|
76
63
|
|
|
77
64
|
const allAction: Action = { kind: "All", actions: branches };
|
|
78
65
|
|
|
79
66
|
return typedAction(
|
|
80
|
-
buildRestartBranchAction(restartHandlerId, allAction,
|
|
67
|
+
buildRestartBranchAction(restartHandlerId, allAction, toAction(identity())),
|
|
81
68
|
);
|
|
82
69
|
}
|
|
83
70
|
|
|
@@ -93,10 +80,10 @@ export function race<TIn, TOut>(
|
|
|
93
80
|
*
|
|
94
81
|
* To preserve data across a sleep, use `bindInput`.
|
|
95
82
|
*/
|
|
96
|
-
export function sleep(ms: number): TypedAction<any,
|
|
97
|
-
return typedAction<any,
|
|
83
|
+
export function sleep(ms: number): TypedAction<any, void> {
|
|
84
|
+
return typedAction<any, void>({
|
|
98
85
|
kind: "Invoke",
|
|
99
|
-
handler: { kind: "Builtin", builtin: { kind: "Sleep",
|
|
86
|
+
handler: { kind: "Builtin", builtin: { kind: "Sleep", ms } },
|
|
100
87
|
});
|
|
101
88
|
}
|
|
102
89
|
|
|
@@ -153,31 +140,34 @@ Object.defineProperty(dynamicSleep, "__definition", {
|
|
|
153
140
|
export function withTimeout<TIn, TOut>(
|
|
154
141
|
ms: Pipeable<TIn, number>,
|
|
155
142
|
body: Pipeable<TIn, TOut>,
|
|
156
|
-
): TypedAction<TIn,
|
|
143
|
+
): TypedAction<TIn, ResultT<TOut, void>> {
|
|
157
144
|
const restartHandlerId = allocateRestartHandlerId();
|
|
158
145
|
const perform = breakPerform(restartHandlerId);
|
|
159
146
|
|
|
160
|
-
// Branch 1: body → Tag("Ok") →
|
|
161
|
-
const bodyBranch
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
147
|
+
// Branch 1: body → Tag("Ok") → Break → RestartPerform
|
|
148
|
+
const bodyBranch = toAction(
|
|
149
|
+
chain(
|
|
150
|
+
toAction(chain(toAction(body), toAction(Result.ok()))),
|
|
151
|
+
toAction(perform),
|
|
152
|
+
),
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
// Branch 2: ms → sleep() → Tag("Err") → Break → RestartPerform
|
|
156
|
+
const sleepBranch = toAction(
|
|
157
|
+
chain(
|
|
158
|
+
toAction(
|
|
159
|
+
chain(
|
|
160
|
+
toAction(chain(toAction(ms), toAction(DYNAMIC_SLEEP_INVOKE))),
|
|
161
|
+
toAction(Result.err()),
|
|
162
|
+
),
|
|
163
|
+
),
|
|
164
|
+
toAction(perform),
|
|
165
|
+
),
|
|
166
|
+
);
|
|
177
167
|
|
|
178
168
|
const allAction: Action = { kind: "All", actions: [bodyBranch, sleepBranch] };
|
|
179
169
|
|
|
180
170
|
return typedAction(
|
|
181
|
-
buildRestartBranchAction(restartHandlerId, allAction,
|
|
171
|
+
buildRestartBranchAction(restartHandlerId, allAction, toAction(identity())),
|
|
182
172
|
);
|
|
183
173
|
}
|
package/src/recursive.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
type Action,
|
|
3
3
|
type Pipeable,
|
|
4
4
|
type TypedAction,
|
|
5
|
+
toAction,
|
|
5
6
|
typedAction,
|
|
6
7
|
branch,
|
|
7
8
|
} from "./ast.js";
|
|
@@ -10,10 +11,10 @@ import { chain } from "./chain.js";
|
|
|
10
11
|
import {
|
|
11
12
|
constant,
|
|
12
13
|
identity,
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
getField,
|
|
15
|
+
getIndex,
|
|
15
16
|
tag,
|
|
16
|
-
} from "./builtins.js";
|
|
17
|
+
} from "./builtins/index.js";
|
|
17
18
|
import { allocateResumeHandlerId } from "./effect-id.js";
|
|
18
19
|
|
|
19
20
|
// ---------------------------------------------------------------------------
|
|
@@ -28,16 +29,14 @@ type FunctionRefs<TDefs extends FunctionDef[]> = {
|
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Constraint for the entry-point callback return type. Only requires the
|
|
31
|
-
* output phantom
|
|
32
|
-
*
|
|
32
|
+
* output phantom field — omits __in and __in_co so that actions with
|
|
33
|
+
* any input type (e.g. pipelines starting from a call token) are assignable.
|
|
33
34
|
*/
|
|
34
35
|
type BodyResult<TOut> = Action & {
|
|
35
36
|
__out?: () => TOut;
|
|
36
|
-
__out_contra?: (output: TOut) => void;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
const UNUSED_STATE: any = undefined;
|
|
39
|
+
const UNUSED_STATE = null;
|
|
41
40
|
|
|
42
41
|
// ---------------------------------------------------------------------------
|
|
43
42
|
// defineRecursiveFunctions
|
|
@@ -58,6 +57,12 @@ const UNUSED_STATE: any = undefined;
|
|
|
58
57
|
* is Chain(Tag("CallN"), ResumePerform(id)). The handler dispatches to the
|
|
59
58
|
* correct function body by tag. The caller's pipeline is preserved as a
|
|
60
59
|
* ResumePerformFrame across each call.
|
|
60
|
+
*
|
|
61
|
+
* **Known limitation:** concurrent calls to the same function do not work
|
|
62
|
+
* as expected. `all(f(x), f(x))` will NOT call `f` twice — both branches
|
|
63
|
+
* perform on the same ResumeHandle, and the second perform will not
|
|
64
|
+
* execute independently. Use sequential calls (chain/then) instead of
|
|
65
|
+
* concurrent calls (all) when calling recursive functions multiple times.
|
|
61
66
|
*/
|
|
62
67
|
export function defineRecursiveFunctions<TDefs extends FunctionDef[]>(
|
|
63
68
|
bodiesFn: (...fns: FunctionRefs<TDefs>) => {
|
|
@@ -76,37 +81,49 @@ export function defineRecursiveFunctions<TDefs extends FunctionDef[]>(
|
|
|
76
81
|
// Call tokens: Chain(Tag("CallN"), ResumePerform(resumeHandlerId))
|
|
77
82
|
const fnCount = bodiesFn.length;
|
|
78
83
|
const callTokens = Array.from({ length: fnCount }, (_, i) =>
|
|
79
|
-
typedAction(
|
|
84
|
+
typedAction(
|
|
85
|
+
toAction(
|
|
86
|
+
chain(
|
|
87
|
+
toAction(tag(`Call${i}`, "RecursiveDispatch")),
|
|
88
|
+
toAction(resumePerform),
|
|
89
|
+
),
|
|
90
|
+
),
|
|
91
|
+
),
|
|
80
92
|
);
|
|
81
93
|
|
|
82
94
|
// Get function body ASTs
|
|
83
|
-
const bodyActions =
|
|
84
|
-
...(callTokens as FunctionRefs<TDefs>)
|
|
85
|
-
)
|
|
95
|
+
const bodyActions = (
|
|
96
|
+
bodiesFn(...(callTokens as FunctionRefs<TDefs>)) as Pipeable[]
|
|
97
|
+
).map(toAction);
|
|
86
98
|
|
|
87
|
-
// Branch cases: CallN →
|
|
99
|
+
// Branch cases: CallN → GetField("value") → bodyN
|
|
88
100
|
const cases: Record<string, Action> = {};
|
|
89
101
|
for (let i = 0; i < bodyActions.length; i++) {
|
|
90
|
-
cases[`Call${i}`] =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
) as Action;
|
|
102
|
+
cases[`Call${i}`] = toAction(
|
|
103
|
+
chain(toAction(getField("value")), toAction(bodyActions[i])),
|
|
104
|
+
);
|
|
94
105
|
}
|
|
95
106
|
|
|
96
107
|
// Return curried entry-point combinator
|
|
97
108
|
return <TOut>(entryFn: (...fns: FunctionRefs<TDefs>) => BodyResult<TOut>) => {
|
|
98
|
-
const userBody = entryFn(...(callTokens as FunctionRefs<TDefs>))
|
|
109
|
+
const userBody = toAction(entryFn(...(callTokens as FunctionRefs<TDefs>)));
|
|
99
110
|
|
|
100
111
|
return typedAction<any, TOut>(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
toAction(
|
|
113
|
+
chain(toAction(all(identity(), constant(UNUSED_STATE))), {
|
|
114
|
+
kind: "ResumeHandle",
|
|
115
|
+
resume_handler_id: resumeHandlerId,
|
|
116
|
+
body: toAction(
|
|
117
|
+
chain(toAction(getIndex(0).unwrap()), toAction(userBody)),
|
|
118
|
+
),
|
|
119
|
+
handler: toAction(
|
|
120
|
+
all(
|
|
121
|
+
chain(toAction(getIndex(0).unwrap()), toAction(branch(cases))),
|
|
122
|
+
constant(UNUSED_STATE),
|
|
123
|
+
),
|
|
124
|
+
),
|
|
125
|
+
}),
|
|
126
|
+
),
|
|
110
127
|
);
|
|
111
128
|
};
|
|
112
129
|
}
|
package/src/result.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Option as OptionT,
|
|
3
|
+
type Pipeable,
|
|
4
|
+
type Result as ResultT,
|
|
5
|
+
type ResultDef,
|
|
6
|
+
type TypedAction,
|
|
7
|
+
branch,
|
|
8
|
+
} from "./ast.js";
|
|
9
|
+
import { chain } from "./chain.js";
|
|
10
|
+
import { constant, drop, identity, panic, tag } from "./builtins/index.js";
|
|
11
|
+
import { Option } from "./option.js";
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Result namespace — combinators for Result<TValue, TError> tagged unions
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
export const Result = {
|
|
18
|
+
/** Tag combinator: wrap value as `Result.Ok`. `TValue → Result<TValue, TError>` */
|
|
19
|
+
ok<TValue, TError = never>(): TypedAction<TValue, ResultT<TValue, TError>> {
|
|
20
|
+
return tag<"Result", ResultDef<TValue, TError>, "Ok">("Ok", "Result");
|
|
21
|
+
},
|
|
22
|
+
/** Tag combinator: wrap value as `Result.Err`. `TError → Result<TValue, TError>` */
|
|
23
|
+
err<TValue = never, TError = unknown>(): TypedAction<
|
|
24
|
+
TError,
|
|
25
|
+
ResultT<TValue, TError>
|
|
26
|
+
> {
|
|
27
|
+
return tag<"Result", ResultDef<TValue, TError>, "Err">("Err", "Result");
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
/** Transform the Ok value. `Result<TValue, TError> → Result<TOut, TError>` */
|
|
31
|
+
map<TValue, TOut, TError>(
|
|
32
|
+
action: Pipeable<TValue, TOut>,
|
|
33
|
+
): TypedAction<ResultT<TValue, TError>, ResultT<TOut, TError>> {
|
|
34
|
+
return branch({
|
|
35
|
+
Ok: chain(action, Result.ok<TOut, TError>()),
|
|
36
|
+
Err: Result.err<TOut, TError>(),
|
|
37
|
+
}) as TypedAction<ResultT<TValue, TError>, ResultT<TOut, TError>>;
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
/** Transform the Err value. `Result<TValue, TError> → Result<TValue, TErrorOut>` */
|
|
41
|
+
mapErr<TValue, TError, TErrorOut>(
|
|
42
|
+
action: Pipeable<TError, TErrorOut>,
|
|
43
|
+
): TypedAction<ResultT<TValue, TError>, ResultT<TValue, TErrorOut>> {
|
|
44
|
+
return branch({
|
|
45
|
+
Ok: Result.ok<TValue, TErrorOut>(),
|
|
46
|
+
Err: chain(action, Result.err<TValue, TErrorOut>()),
|
|
47
|
+
}) as TypedAction<ResultT<TValue, TError>, ResultT<TValue, TErrorOut>>;
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Monadic bind (flatMap) for Ok. If Ok, pass value to action which
|
|
52
|
+
* returns Result<TOut, TError>. If Err, propagate.
|
|
53
|
+
*/
|
|
54
|
+
andThen<TValue, TOut, TError>(
|
|
55
|
+
action: Pipeable<TValue, ResultT<TOut, TError>>,
|
|
56
|
+
): TypedAction<ResultT<TValue, TError>, ResultT<TOut, TError>> {
|
|
57
|
+
return branch({
|
|
58
|
+
Ok: action,
|
|
59
|
+
Err: Result.err<TOut, TError>(),
|
|
60
|
+
}) as TypedAction<ResultT<TValue, TError>, ResultT<TOut, TError>>;
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/** Fallback on Err. If Ok, keep it. If Err, pass error to fallback. */
|
|
64
|
+
or<TValue, TError, TErrorOut>(
|
|
65
|
+
fallback: Pipeable<TError, ResultT<TValue, TErrorOut>>,
|
|
66
|
+
): TypedAction<ResultT<TValue, TError>, ResultT<TValue, TErrorOut>> {
|
|
67
|
+
return branch({
|
|
68
|
+
Ok: Result.ok<TValue, TErrorOut>(),
|
|
69
|
+
Err: fallback,
|
|
70
|
+
}) as TypedAction<ResultT<TValue, TError>, ResultT<TValue, TErrorOut>>;
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Extract the Ok value or panic. `Result<TValue, TError> → TValue`
|
|
75
|
+
*
|
|
76
|
+
* Panics (fatal, not caught by tryCatch) if the value is Err.
|
|
77
|
+
*/
|
|
78
|
+
unwrap<TValue, TError>(): TypedAction<ResultT<TValue, TError>, TValue> {
|
|
79
|
+
return branch({
|
|
80
|
+
Ok: identity<TValue>(),
|
|
81
|
+
Err: panic("called unwrap on Err"),
|
|
82
|
+
}) as TypedAction<ResultT<TValue, TError>, TValue>;
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Extract Ok or compute default from Err. `Result<TValue, TError> → TValue`
|
|
87
|
+
*/
|
|
88
|
+
unwrapOr<TValue, TError>(
|
|
89
|
+
defaultAction: Pipeable<TError, TValue>,
|
|
90
|
+
): TypedAction<ResultT<TValue, TError>, TValue> {
|
|
91
|
+
return branch({
|
|
92
|
+
Ok: identity<TValue>(),
|
|
93
|
+
Err: defaultAction,
|
|
94
|
+
}) as TypedAction<ResultT<TValue, TError>, TValue>;
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Convert Ok to Some, Err to None. `Result<TValue, TError> → Option<TValue>`
|
|
99
|
+
*/
|
|
100
|
+
asOkOption<TValue, TError>(): TypedAction<
|
|
101
|
+
ResultT<TValue, TError>,
|
|
102
|
+
OptionT<TValue>
|
|
103
|
+
> {
|
|
104
|
+
return branch({
|
|
105
|
+
Ok: Option.some<TValue>(),
|
|
106
|
+
Err: chain(drop, Option.none<TValue>()),
|
|
107
|
+
}) as TypedAction<ResultT<TValue, TError>, OptionT<TValue>>;
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Convert Err to Some, Ok to None. `Result<TValue, TError> → Option<TError>`
|
|
112
|
+
*/
|
|
113
|
+
asErrOption<TValue, TError>(): TypedAction<
|
|
114
|
+
ResultT<TValue, TError>,
|
|
115
|
+
OptionT<TError>
|
|
116
|
+
> {
|
|
117
|
+
return branch({
|
|
118
|
+
Ok: chain(drop, Option.none<TError>()),
|
|
119
|
+
Err: Option.some<TError>(),
|
|
120
|
+
}) as TypedAction<ResultT<TValue, TError>, OptionT<TError>>;
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Swap Result/Option nesting.
|
|
125
|
+
* `Result<Option<TValue>, TError> → Option<Result<TValue, TError>>`
|
|
126
|
+
*/
|
|
127
|
+
transpose<TValue, TError>(): TypedAction<
|
|
128
|
+
ResultT<OptionT<TValue>, TError>,
|
|
129
|
+
OptionT<ResultT<TValue, TError>>
|
|
130
|
+
> {
|
|
131
|
+
return branch({
|
|
132
|
+
Ok: branch({
|
|
133
|
+
Some: chain(
|
|
134
|
+
Result.ok<TValue, TError>(),
|
|
135
|
+
Option.some<ResultT<TValue, TError>>(),
|
|
136
|
+
),
|
|
137
|
+
None: chain(drop, Option.none<ResultT<TValue, TError>>()),
|
|
138
|
+
}),
|
|
139
|
+
Err: chain(
|
|
140
|
+
Result.err<TValue, TError>(),
|
|
141
|
+
Option.some<ResultT<TValue, TError>>(),
|
|
142
|
+
),
|
|
143
|
+
}) as TypedAction<
|
|
144
|
+
ResultT<OptionT<TValue>, TError>,
|
|
145
|
+
OptionT<ResultT<TValue, TError>>
|
|
146
|
+
>;
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Test if the value is Ok. `Result<TValue, TError> → boolean`
|
|
151
|
+
*/
|
|
152
|
+
isOk<TValue, TError>(): TypedAction<ResultT<TValue, TError>, boolean> {
|
|
153
|
+
return branch({
|
|
154
|
+
Ok: constant<boolean>(true),
|
|
155
|
+
Err: constant<boolean>(false),
|
|
156
|
+
}) as TypedAction<ResultT<TValue, TError>, boolean>;
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Test if the value is Err. `Result<TValue, TError> → boolean`
|
|
161
|
+
*/
|
|
162
|
+
isErr<TValue, TError>(): TypedAction<ResultT<TValue, TError>, boolean> {
|
|
163
|
+
return branch({
|
|
164
|
+
Ok: constant<boolean>(false),
|
|
165
|
+
Err: constant<boolean>(true),
|
|
166
|
+
}) as TypedAction<ResultT<TValue, TError>, boolean>;
|
|
167
|
+
},
|
|
168
|
+
} as const;
|