functionalscript 0.45.0 → 0.46.1
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 +5 -3
- package/fjs/asn.1/module.f.mjs +8 -1
- package/fjs/asn.1/proof.f.d.mts +10 -0
- package/fjs/asn.1/proof.f.mjs +16 -0
- package/fjs/basen/base128/module.f.mjs +22 -5
- package/fjs/bnf/data/module.f.d.mts +32 -6
- package/fjs/bnf/data/module.f.mjs +112 -7
- package/fjs/bnf/data/proof.f.d.mts +2 -0
- package/fjs/bnf/data/proof.f.mjs +74 -3
- package/fjs/bnf/data/types.d.ts +20 -2
- package/fjs/bnf/descent/module.f.d.mts +28 -14
- package/fjs/bnf/descent/module.f.mjs +122 -77
- package/fjs/bnf/descent/proof.f.d.mts +2 -0
- package/fjs/bnf/descent/proof.f.mjs +117 -31
- package/fjs/bnf/descent/types.d.ts +12 -14
- package/fjs/bnf/ll1/module.f.d.mts +64 -22
- package/fjs/bnf/ll1/module.f.mjs +214 -154
- package/fjs/bnf/ll1/proof.f.d.mts +15 -2
- package/fjs/bnf/ll1/proof.f.mjs +323 -149
- package/fjs/bnf/ll1/types.d.ts +16 -24
- package/fjs/bnf/matcher/module.f.d.mts +66 -0
- package/fjs/bnf/matcher/module.f.mjs +81 -0
- package/fjs/bnf/matcher/proof.f.d.mts +10 -0
- package/fjs/bnf/matcher/proof.f.mjs +79 -0
- package/fjs/bnf/matcher/types.d.ts +54 -0
- package/fjs/bnf/testlib.f.d.mts +31 -0
- package/fjs/bnf/testlib.f.mjs +80 -0
- package/fjs/cas/cli/module.f.d.mts +1 -1
- package/fjs/cas/cli/module.f.mjs +14 -20
- package/fjs/cas/cli/proof.f.d.mts +1 -3
- package/fjs/cas/cli/proof.f.mjs +44 -33
- package/fjs/cas/evo/module.f.d.mts +64 -18
- package/fjs/cas/evo/module.f.mjs +148 -70
- package/fjs/cas/evo/proof.f.d.mts +10 -1
- package/fjs/cas/evo/proof.f.mjs +305 -223
- package/fjs/cas/evo/types.d.ts +45 -9
- package/fjs/cas/module.f.d.mts +18 -32
- package/fjs/cas/module.f.mjs +129 -128
- package/fjs/cas/proof.f.d.mts +11 -8
- package/fjs/cas/proof.f.mjs +259 -147
- package/fjs/cas/types.d.ts +24 -10
- package/fjs/ci/config/module.f.d.mts +2 -2
- package/fjs/ci/config/module.f.mjs +2 -2
- package/fjs/ci/module.f.d.mts +5 -5
- package/fjs/ci/module.f.mjs +8 -7
- package/fjs/ci/nix/module.f.d.mts +7 -5
- package/fjs/ci/nix/module.f.mjs +13 -12
- package/fjs/ci/nix/proof.f.mjs +2 -2
- package/fjs/ci/proof.f.mjs +9 -5
- package/fjs/cli/module.f.d.mts +4 -6
- package/fjs/cli/module.f.mjs +4 -8
- package/fjs/cli/proof.f.mjs +17 -16
- package/fjs/cli/types.d.ts +2 -3
- package/fjs/common/monoid/types.d.ts +1 -1
- package/fjs/crypto/hmac/module.f.mjs +2 -2
- package/fjs/crypto/sha2/module.f.mjs +3 -1
- package/fjs/crypto/sha2/proof.f.d.mts +1 -0
- package/fjs/crypto/sha2/proof.f.mjs +24 -0
- package/fjs/crypto/sha2/types.d.ts +11 -0
- package/fjs/crypto/sign/module.f.mjs +2 -2
- package/fjs/dev/module.f.d.mts +13 -4
- package/fjs/dev/module.f.mjs +56 -27
- package/fjs/dev/update/module.f.d.mts +9 -4
- package/fjs/dev/update/module.f.mjs +14 -10
- package/fjs/dev/update/proof.f.d.mts +1 -3
- package/fjs/dev/update/proof.f.mjs +10 -5
- package/fjs/djs/module.f.d.mts +13 -5
- package/fjs/djs/module.f.mjs +31 -16
- package/fjs/djs/parser/module.f.d.mts +13 -3
- package/fjs/djs/parser/module.f.mjs +117 -16
- package/fjs/djs/parser/proof.f.d.mts +5 -1
- package/fjs/djs/parser/proof.f.mjs +274 -12
- package/fjs/djs/parser/types.d.ts +7 -1
- package/fjs/djs/proof.f.d.mts +18 -2
- package/fjs/djs/proof.f.mjs +187 -12
- package/fjs/djs/serializer/module.f.d.mts +25 -8
- package/fjs/djs/serializer/module.f.mjs +61 -15
- package/fjs/djs/serializer/proof.f.d.mts +5 -0
- package/fjs/djs/serializer/proof.f.mjs +23 -1
- package/fjs/djs/tokenizer/module.f.d.mts +17 -5
- package/fjs/djs/tokenizer/module.f.mjs +99 -60
- package/fjs/djs/tokenizer/proof.f.d.mts +1 -1
- package/fjs/djs/tokenizer/proof.f.mjs +74 -67
- package/fjs/djs/transpiler/module.f.d.mts +12 -7
- package/fjs/djs/transpiler/module.f.mjs +82 -56
- package/fjs/djs/transpiler/types.d.ts +7 -3
- package/fjs/djs/types.d.ts +7 -1
- package/fjs/effects/list/module.f.d.mts +14 -11
- package/fjs/effects/list/module.f.mjs +13 -11
- package/fjs/effects/list/types.d.ts +27 -7
- package/fjs/effects/memory/module.f.d.mts +2 -1
- package/fjs/effects/memory/module.f.mjs +3 -4
- package/fjs/effects/memory/proof.f.mjs +13 -7
- package/fjs/effects/memory/types.d.ts +4 -3
- package/fjs/effects/mock/module.f.d.mts +20 -4
- package/fjs/effects/mock/module.f.mjs +37 -5
- package/fjs/effects/mock/types.d.ts +10 -1
- package/fjs/effects/module.d.mts +4 -2
- package/fjs/effects/module.f.d.mts +466 -280
- package/fjs/effects/module.f.mjs +537 -299
- package/fjs/effects/module.mjs +2 -1
- package/fjs/effects/node/memory/module.d.mts +4 -2
- package/fjs/effects/node/memory/module.mjs +6 -3
- package/fjs/effects/node/memory/proof.mjs +10 -4
- package/fjs/effects/node/module.d.mts +4 -3
- package/fjs/effects/node/module.f.d.mts +168 -33
- package/fjs/effects/node/module.f.mjs +256 -52
- package/fjs/effects/node/module.mjs +57 -34
- package/fjs/effects/node/proof.f.d.mts +28 -2
- package/fjs/effects/node/proof.f.mjs +161 -42
- package/fjs/effects/node/types.d.ts +106 -18
- package/fjs/effects/node/virtual/module.f.d.mts +18 -4
- package/fjs/effects/node/virtual/module.f.mjs +110 -68
- package/fjs/effects/node/virtual/proof.f.d.mts +28 -2
- package/fjs/effects/node/virtual/proof.f.mjs +190 -9
- package/fjs/effects/proof.f.d.mts +69 -37
- package/fjs/effects/proof.f.mjs +410 -130
- package/fjs/effects/types.d.ts +161 -33
- package/fjs/emergent_testing/module.f.d.mts +19 -12
- package/fjs/emergent_testing/module.f.mjs +93 -33
- package/fjs/emergent_testing/proof.f.d.mts +21 -7
- package/fjs/emergent_testing/proof.f.mjs +166 -32
- package/fjs/emergent_testing/types.d.ts +22 -4
- package/fjs/fsm/module.f.d.mts +14 -4
- package/fjs/fsm/module.f.mjs +54 -37
- package/fjs/fsm/proof.f.d.mts +2 -0
- package/fjs/fsm/proof.f.mjs +83 -114
- package/fjs/js/keywords/module.f.d.mts +52 -0
- package/fjs/js/keywords/module.f.mjs +72 -0
- package/fjs/js/keywords/proof.f.d.mts +3 -0
- package/fjs/js/keywords/proof.f.mjs +13 -0
- package/fjs/js/tokenizer/module.f.d.mts +26 -6
- package/fjs/js/tokenizer/module.f.mjs +145 -159
- package/fjs/js/tokenizer/proof.f.d.mts +1 -0
- package/fjs/js/tokenizer/proof.f.mjs +54 -24
- package/fjs/js/tokenizer/types.d.ts +33 -24
- package/fjs/mcp/cas/module.f.d.mts +1 -6
- package/fjs/mcp/cas/module.f.mjs +55 -51
- package/fjs/mcp/cas/proof.f.d.mts +15 -0
- package/fjs/mcp/cas/proof.f.mjs +174 -0
- package/fjs/mcp/evo/module.f.d.mts +19 -10
- package/fjs/mcp/evo/module.f.mjs +48 -27
- package/fjs/mcp/evo/proof.f.d.mts +6 -1
- package/fjs/mcp/evo/proof.f.mjs +115 -31
- package/fjs/mcp/module.f.d.mts +4 -4
- package/fjs/mcp/module.f.mjs +6 -6
- package/fjs/mcp/proof.f.d.mts +5 -3
- package/fjs/mcp/proof.f.mjs +112 -46
- package/fjs/media/html/module.f.mjs +1 -1
- package/fjs/media/json/extended/module.f.d.mts +82 -0
- package/fjs/media/json/extended/module.f.mjs +153 -0
- package/fjs/media/json/extended/proof.f.d.mts +42 -0
- package/fjs/media/json/extended/proof.f.mjs +127 -0
- package/fjs/media/json/extended/types.d.ts +23 -0
- package/fjs/media/json/module.f.d.mts +8 -2
- package/fjs/media/json/module.f.mjs +43 -41
- package/fjs/media/json/number/module.f.d.mts +59 -0
- package/fjs/media/json/number/module.f.mjs +136 -0
- package/fjs/media/json/number/proof.f.d.mts +24 -0
- package/fjs/media/json/number/proof.f.mjs +86 -0
- package/fjs/media/json/number/types.d.ts +28 -0
- package/fjs/media/json/parser/module.f.d.mts +25 -13
- package/fjs/media/json/parser/module.f.mjs +114 -70
- package/fjs/media/json/parser/proof.f.d.mts +5 -0
- package/fjs/media/json/parser/proof.f.mjs +31 -1
- package/fjs/media/json/parser/types.d.ts +33 -14
- package/fjs/media/json/rtti/module.f.d.mts +1 -1
- package/fjs/media/json/rtti/module.f.mjs +1 -1
- package/fjs/media/json/rtti/proof.f.mjs +9 -9
- package/fjs/media/json/schema/module.f.mjs +3 -13
- package/fjs/media/json/schema/proof.f.d.mts +0 -1
- package/fjs/media/json/schema/proof.f.mjs +1 -2
- package/fjs/media/json/serializer/module.f.d.mts +32 -1
- package/fjs/media/json/serializer/module.f.mjs +64 -2
- package/fjs/media/json/tokenizer/module.f.mjs +7 -3
- package/fjs/media/json/tokenizer/proof.f.d.mts +6 -0
- package/fjs/media/json/tokenizer/proof.f.mjs +62 -21
- package/fjs/media/json/types.d.ts +36 -10
- package/fjs/media/lock/module.f.d.mts +100 -0
- package/fjs/media/lock/module.f.mjs +125 -0
- package/fjs/media/lock/proof.f.d.mts +33 -0
- package/fjs/media/lock/proof.f.mjs +196 -0
- package/fjs/media/lock/types.d.ts +15 -0
- package/fjs/media/module.f.d.mts +6 -5
- package/fjs/media/module.f.mjs +8 -7
- package/fjs/media/note/module.f.d.mts +121 -0
- package/fjs/media/note/module.f.mjs +131 -0
- package/fjs/media/note/proof.f.d.mts +29 -0
- package/fjs/media/note/proof.f.mjs +150 -0
- package/fjs/media/note/types.d.ts +10 -0
- package/fjs/media/proof.f.d.mts +4 -1
- package/fjs/media/proof.f.mjs +40 -21
- package/fjs/media/revision/module.f.d.mts +78 -7
- package/fjs/media/revision/module.f.mjs +119 -12
- package/fjs/media/revision/proof.f.d.mts +10 -0
- package/fjs/media/revision/proof.f.mjs +88 -0
- package/fjs/media/revision/types.d.ts +34 -5
- package/fjs/media/type/module.f.d.mts +33 -15
- package/fjs/media/type/module.f.mjs +35 -29
- package/fjs/media/type/proof.f.d.mts +2 -1
- package/fjs/media/type/proof.f.mjs +30 -10
- package/fjs/module.f.mjs +29 -8
- package/fjs/nanvm/proof.f.mjs +3 -3
- package/fjs/nanvm/rust/module.f.mjs +1 -1
- package/fjs/nanvm/update/module.f.d.mts +4 -4
- package/fjs/nanvm/update/module.f.mjs +8 -9
- package/fjs/nanvm/update/proof.f.mjs +4 -3
- package/fjs/proof.f.d.mts +3 -3
- package/fjs/proof.f.mjs +36 -10
- package/fjs/protocol/json_rpc/module.f.d.mts +2 -2
- package/fjs/protocol/json_rpc/module.f.mjs +3 -3
- package/fjs/protocol/json_rpc/proof.f.mjs +4 -4
- package/fjs/protocol/mcp/module.f.d.mts +10 -13
- package/fjs/protocol/mcp/module.f.mjs +74 -58
- package/fjs/protocol/mcp/proof.f.d.mts +13 -4
- package/fjs/protocol/mcp/proof.f.mjs +193 -61
- package/fjs/protocol/mcp/stdio/module.f.d.mts +15 -7
- package/fjs/protocol/mcp/stdio/module.f.mjs +38 -25
- package/fjs/protocol/mcp/stdio/proof.f.d.mts +4 -2
- package/fjs/protocol/mcp/stdio/proof.f.mjs +45 -12
- package/fjs/protocol/mcp/stdio/types.d.ts +1 -1
- package/fjs/protocol/mcp/types.d.ts +17 -6
- package/fjs/sul/id/module.f.d.mts +0 -1
- package/fjs/sul/id/module.f.mjs +2 -3
- package/fjs/sul/level/hash/module.f.mjs +2 -1
- package/fjs/sul/level/hash/proof.f.mjs +2 -2
- package/fjs/sul/module.f.mjs +18 -13
- package/fjs/text/code_point/module.f.d.mts +8 -0
- package/fjs/text/code_point/module.f.mjs +8 -1
- package/fjs/text/code_point/proof.f.d.mts +1 -0
- package/fjs/text/code_point/proof.f.mjs +11 -0
- package/fjs/text/sgr/module.f.d.mts +4 -6
- package/fjs/text/sgr/module.f.mjs +6 -7
- package/fjs/text/utf16/module.f.mjs +7 -2
- package/fjs/text/utf16/proof.f.mjs +3 -3
- package/fjs/text/utf8/module.f.mjs +4 -2
- package/fjs/types/array/module.f.mjs +14 -2
- package/fjs/types/bit_vec/module.f.d.mts +0 -2
- package/fjs/types/bit_vec/module.f.mjs +46 -32
- package/fjs/types/bit_vec/proof.f.mjs +2 -2
- package/fjs/types/btree/remove/module.f.mjs +1 -1
- package/fjs/types/btree/set/module.f.mjs +9 -11
- package/fjs/types/btree/set/proof.f.mjs +12 -0
- package/fjs/types/byte_set/module.f.d.mts +11 -4
- package/fjs/types/byte_set/module.f.mjs +14 -6
- package/fjs/types/byte_set/proof.f.mjs +7 -7
- package/fjs/types/function/compare/module.f.mjs +10 -3
- package/fjs/types/list/module.f.d.mts +1 -1
- package/fjs/types/list/module.f.mjs +1 -1
- package/fjs/types/nullable/module.f.d.mts +18 -4
- package/fjs/types/nullable/module.f.mjs +21 -4
- package/fjs/types/nullable/proof.f.d.mts +4 -0
- package/fjs/types/nullable/proof.f.mjs +15 -0
- package/fjs/types/object/module.f.d.mts +12 -2
- package/fjs/types/object/module.f.mjs +11 -1
- package/fjs/types/patricia_trie/module.f.mjs +26 -11
- package/fjs/types/result/module.f.d.mts +3 -3
- package/fjs/types/result/module.f.mjs +3 -3
- package/fjs/types/rtti/common/module.f.d.mts +25 -28
- package/fjs/types/rtti/common/module.f.mjs +36 -32
- package/fjs/types/rtti/common/proof.f.mjs +5 -5
- package/fjs/types/rtti/data/module.f.d.mts +14 -0
- package/fjs/types/rtti/data/module.f.mjs +25 -2
- package/fjs/types/rtti/data/proof.f.d.mts +1 -0
- package/fjs/types/rtti/data/proof.f.mjs +25 -2
- package/fjs/types/rtti/parse/module.f.d.mts +24 -14
- package/fjs/types/rtti/parse/module.f.mjs +37 -28
- package/fjs/types/rtti/parse/proof.f.d.mts +3 -2
- package/fjs/types/rtti/parse/proof.f.mjs +33 -14
- package/fjs/types/rtti/proof.f.mjs +3 -1
- package/fjs/types/rtti/ts/module.f.mjs +13 -17
- package/fjs/types/rtti/ts/types.d.ts +14 -1
- package/fjs/types/rtti/validate/module.f.d.mts +81 -19
- package/fjs/types/rtti/validate/module.f.mjs +107 -61
- package/fjs/types/rtti/validate/proof.f.d.mts +13 -10
- package/fjs/types/rtti/validate/proof.f.mjs +186 -197
- package/fjs/types/sorted_set/module.f.d.mts +18 -0
- package/fjs/types/sorted_set/module.f.mjs +22 -0
- package/fjs/types/sorted_set/proof.f.d.mts +1 -0
- package/fjs/types/sorted_set/proof.f.mjs +16 -1
- package/fjs/types/uint8array/module.f.d.mts +1 -1
- package/fjs/types/uint8array/module.f.mjs +1 -1
- package/fjs/website/module.f.d.mts +3 -3
- package/fjs/website/module.f.mjs +4 -7
- package/fjs/website/proof.f.mjs +2 -1
- package/package.json +2 -2
- package/fjs/dev/package_json/module.f.d.mts +0 -39
- package/fjs/dev/package_json/module.f.mjs +0 -40
- package/fjs/dev/package_json/proof.f.d.mts +0 -6
- package/fjs/dev/package_json/proof.f.mjs +0 -32
- package/fjs/effects/eff/module.f.d.mts +0 -20
- package/fjs/effects/eff/module.f.mjs +0 -70
- package/fjs/effects/eff/proof.f.d.mts +0 -15
- package/fjs/effects/eff/proof.f.mjs +0 -69
- package/fjs/effects/eff/types.d.ts +0 -71
- package/fjs/types/rtti/validate/types.d.ts +0 -6
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* @import { Result } from '../../types/result/types.ts'
|
|
8
8
|
* @import { ParseError } from '../parser/types.ts'
|
|
9
9
|
* @import { AstModule } from '../ast/types.ts'
|
|
10
|
+
* @import { Operation } from '../../effects/types.ts'
|
|
11
|
+
* @import { IoChannel } from '../../effects/node/types.ts'
|
|
10
12
|
* @import { Effect } from '../../effects/types.ts'
|
|
11
13
|
* @import { ReadFile } from '../../effects/node/types.ts'
|
|
12
14
|
* @import { ParseContext } from './types.ts'
|
|
@@ -19,10 +21,21 @@ import { setReplace, at } from '../../types/ordered_map/module.f.mjs'
|
|
|
19
21
|
import { stringToList } from '../../text/utf16/module.f.mjs'
|
|
20
22
|
import { concat as pathConcat } from '../../path/module.f.mjs'
|
|
21
23
|
import { parseFromTokens } from '../parser/module.f.mjs'
|
|
24
|
+
import { parse as jsonParse } from '../../media/json/module.f.mjs'
|
|
22
25
|
import { run } from '../ast/module.f.mjs'
|
|
23
|
-
import {
|
|
26
|
+
import { pure } from '../../effects/module.f.mjs'
|
|
27
|
+
import { catchStep, foldStep, mapStep, pureError, pureOk, step } from '../../effects/module.f.mjs'
|
|
24
28
|
import { readUtf8File } from '../../effects/node/module.f.mjs'
|
|
25
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Reads a file, reporting any failure as the one `ParseError` a caller can act
|
|
32
|
+
* on. Both readers want this and neither wants the node channel's vocabulary.
|
|
33
|
+
*
|
|
34
|
+
* @type {<O extends Operation>(e: Effect<O, string, IoChannel>) => Effect<O, string, ParseError>}
|
|
35
|
+
*/
|
|
36
|
+
const notFound = e =>
|
|
37
|
+
catchStep(e, () => pureError({ message: 'file not found', metadata: null }))
|
|
38
|
+
|
|
26
39
|
/** @type {(context: ParseContext) => (path: string) => Unknown} */
|
|
27
40
|
const mapDjs = context => path => {
|
|
28
41
|
const res = at(path)(context.complete)
|
|
@@ -33,82 +46,95 @@ const mapDjs = context => path => {
|
|
|
33
46
|
return res.djs
|
|
34
47
|
}
|
|
35
48
|
|
|
36
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* `catchStep` rather than a branch on the read's `Result`: however the read
|
|
51
|
+
* failed — missing file, unreadable, a runner without `readFile` — the answer
|
|
52
|
+
* a transpiler gives is the same `ParseError`, so the node channel is
|
|
53
|
+
* translated once here rather than travelling any further.
|
|
54
|
+
*
|
|
55
|
+
* @type {(path: string) => Effect<ReadFile, AstModule, ParseError>}
|
|
56
|
+
*/
|
|
37
57
|
const parseModule = path => step(
|
|
38
|
-
readUtf8File(path),
|
|
39
|
-
|
|
40
|
-
if (result[0] === 'error') {
|
|
41
|
-
return pure(error({ message: 'file not found', metadata: null }))
|
|
42
|
-
}
|
|
43
|
-
const tokens = tokenize(stringToList(result[1]))(path)
|
|
44
|
-
return pure(parseFromTokens(tokens))
|
|
45
|
-
})
|
|
58
|
+
notFound(readUtf8File(path)),
|
|
59
|
+
text => pure(parseFromTokens(tokenize(stringToList(text))(path))))
|
|
46
60
|
|
|
47
|
-
/** @type {(path: string) => (
|
|
48
|
-
const transpileWithImports = path =>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return pure({
|
|
64
|
-
...contextWithImports,
|
|
65
|
-
stack: drop(1)(contextWithImports.stack),
|
|
66
|
-
complete: setReplace(path)(djs)(contextWithImports.complete),
|
|
67
|
-
})
|
|
61
|
+
/** @type {(path: string) => (module: AstModule) => (context: ParseContext) => Effect<ReadFile, ParseContext, ParseError>} */
|
|
62
|
+
const transpileWithImports = path => module => context => {
|
|
63
|
+
const dir = pathConcat(path)('..')
|
|
64
|
+
const pathsCombine = listMap(pathConcat(dir))(module[0])
|
|
65
|
+
const pathsArray = toArray(pathsCombine)
|
|
66
|
+
const contextWithStack = { ...context, stack: { first: path, tail: context.stack } }
|
|
67
|
+
const x0 = foldStep(pureOk(pathsArray), contextWithStack, foldNextModuleOp)
|
|
68
|
+
return step(
|
|
69
|
+
x0,
|
|
70
|
+
contextWithImports => {
|
|
71
|
+
const args = toArray(listMap(mapDjs(contextWithImports))(pathsCombine))
|
|
72
|
+
const djs = { djs: run(module[1])(args) }
|
|
73
|
+
return pureOk({
|
|
74
|
+
...contextWithImports,
|
|
75
|
+
stack: drop(1)(contextWithImports.stack),
|
|
76
|
+
complete: setReplace(path)(djs)(contextWithImports.complete),
|
|
68
77
|
})
|
|
69
|
-
|
|
70
|
-
return pure({ ...context, error: parseModuleResult[1] })
|
|
78
|
+
})
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
/** @type {(path: string) => (context: ParseContext) => Effect<ReadFile, ParseContext>} */
|
|
81
|
+
/** @type {(path: string) => (context: ParseContext) => Effect<ReadFile, ParseContext, ParseError>} */
|
|
74
82
|
const foldNextModuleOp = path => context => {
|
|
75
|
-
if (context.error !== null) {
|
|
76
|
-
return pure(context)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
83
|
if (includes(path)(context.stack)) {
|
|
80
|
-
return
|
|
84
|
+
return pureError({ message: 'circular dependency', metadata: null })
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
if (at(path)(context.complete) !== null) {
|
|
84
|
-
return
|
|
88
|
+
return pureOk(context)
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
return step(
|
|
88
92
|
parseModule(path),
|
|
89
|
-
|
|
93
|
+
module => transpileWithImports(path)(module)(context))
|
|
90
94
|
}
|
|
91
95
|
|
|
96
|
+
/** @type {(path: string) => Effect<ReadFile, Unknown, ParseError>} */
|
|
97
|
+
const transpileModule = path => mapStep(
|
|
98
|
+
foldNextModuleOp(path)({ stack: null, complete: null }),
|
|
99
|
+
context => at(path)(context.complete)?.djs)
|
|
100
|
+
|
|
92
101
|
/**
|
|
93
|
-
*
|
|
102
|
+
* A JSON document is a value, not a module: it imports nothing and names
|
|
103
|
+
* nothing, so it needs no AST and no evaluation — `fjs/media/json` reads it
|
|
104
|
+
* and the value is the result.
|
|
94
105
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
106
|
+
* That reader reports its errors without a position, so the `ParseError` has
|
|
107
|
+
* no metadata and `fjs/djs`'s `compile` names the file instead of a line and
|
|
108
|
+
* column.
|
|
98
109
|
*
|
|
99
|
-
* @type {(path: string) => Effect<ReadFile,
|
|
110
|
+
* @type {(path: string) => Effect<ReadFile, Unknown, ParseError>}
|
|
100
111
|
*/
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const result = at(path)(context.complete)?.djs
|
|
109
|
-
return pure(ok(result))
|
|
112
|
+
const transpileJson = path => step(
|
|
113
|
+
notFound(readUtf8File(path)),
|
|
114
|
+
text => {
|
|
115
|
+
const json = jsonParse(text)
|
|
116
|
+
return pure(json[0] === 'error'
|
|
117
|
+
? error({ message: json[1], metadata: null })
|
|
118
|
+
: ok(json[1]))
|
|
110
119
|
})
|
|
111
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Transpiles the file at `path` into a single `Unknown` value.
|
|
123
|
+
*
|
|
124
|
+
* The extension names its language: a `.json` file is a JSON document, read by
|
|
125
|
+
* `fjs/media/json`, and anything else is a FunctionalScript module, whose
|
|
126
|
+
* imports are resolved recursively — each of them a module too, whatever it is
|
|
127
|
+
* called ([spec: the `__proto__` key](../../../spec/README.md#the-__proto__-key)).
|
|
128
|
+
*
|
|
129
|
+
* Returns `['ok', value]` on success, or `['error', ParseError]` on a parse
|
|
130
|
+
* failure, a missing file, or a circular dependency.
|
|
131
|
+
*
|
|
132
|
+
* @type {(path: string) => Effect<ReadFile, Unknown, ParseError>}
|
|
133
|
+
*/
|
|
134
|
+
export const transpile = path => path.endsWith('.json')
|
|
135
|
+
? transpileJson(path)
|
|
136
|
+
: transpileModule(path)
|
|
137
|
+
|
|
112
138
|
// ── Tests ────────────────────────────────────────────────────────────────────
|
|
113
139
|
|
|
114
140
|
export const proof = {
|
|
@@ -117,6 +143,6 @@ export const proof = {
|
|
|
117
143
|
// has already resolved into `context.complete`, so the `res === null`
|
|
118
144
|
// guard is an internal-invariant check unreachable through `transpile`'s
|
|
119
145
|
// public API. Call it directly with an empty `complete` map to cover it.
|
|
120
|
-
mapDjsUnresolvedImport: () => mapDjs({ complete: null, stack: null
|
|
146
|
+
mapDjsUnresolvedImport: () => mapDjs({ complete: null, stack: null })('missing.djs'),
|
|
121
147
|
},
|
|
122
148
|
}
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import type { Unknown } from '../types.ts';
|
|
7
7
|
import type { List } from '../../types/list/types.ts';
|
|
8
8
|
import type { OrderedMap } from '../../types/ordered_map/types.ts';
|
|
9
|
-
import type { ParseError } from '../parser/types.ts';
|
|
10
9
|
/** The evaluated DJS value produced for one successfully transpiled module. */
|
|
11
10
|
export type djsResult = {
|
|
12
11
|
djs: Unknown;
|
|
@@ -16,10 +15,15 @@ export type djsResult = {
|
|
|
16
15
|
*
|
|
17
16
|
* - `complete`: modules that have been fully parsed and evaluated, keyed by path.
|
|
18
17
|
* - `stack`: import chain currently being resolved (used to detect circular dependencies).
|
|
19
|
-
*
|
|
18
|
+
*
|
|
19
|
+
* There is no `error` field. It used to hold "the first parse error
|
|
20
|
+
* encountered, or `null` while everything is clean" — a hand-rolled error
|
|
21
|
+
* channel that every step had to set, and that three separate places had to
|
|
22
|
+
* test before doing any work. It is the effect's channel now
|
|
23
|
+
* (`Effect<ReadFile, ParseContext, ParseError>`), so `step` short-circuits and
|
|
24
|
+
* a context that exists is a context that is still good.
|
|
20
25
|
*/
|
|
21
26
|
export type ParseContext = {
|
|
22
27
|
readonly complete: OrderedMap<djsResult>;
|
|
23
28
|
readonly stack: List<string>;
|
|
24
|
-
readonly error: ParseError | null;
|
|
25
29
|
};
|
package/fjs/djs/types.d.ts
CHANGED
|
@@ -4,10 +4,16 @@
|
|
|
4
4
|
*
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
|
-
import type { Primitive as JsonPrimitive } from '../media/json/types.ts';
|
|
7
|
+
import type { Primitive as JsonPrimitive, TreeMapEntries } from '../media/json/types.ts';
|
|
8
8
|
export type Object = {
|
|
9
9
|
readonly [k in string]?: Unknown;
|
|
10
10
|
};
|
|
11
11
|
export type Array = readonly Unknown[];
|
|
12
12
|
export type Primitive = JsonPrimitive | bigint | undefined;
|
|
13
13
|
export type Unknown = Primitive | Object | Array;
|
|
14
|
+
/**
|
|
15
|
+
* How the serializer orders an object's entries — `sort` for canonical
|
|
16
|
+
* output, `identity` to keep insertion order. The same alias JSON and
|
|
17
|
+
* extended JSON instantiate, at DJS's leaf set.
|
|
18
|
+
*/
|
|
19
|
+
export type _MapEntries = TreeMapEntries<Primitive>;
|
|
@@ -5,28 +5,31 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module
|
|
7
7
|
*
|
|
8
|
-
* @import {
|
|
8
|
+
* @import { Operation } from "../types.ts"
|
|
9
|
+
* @import { Effect } from "../types.ts"
|
|
9
10
|
* @import { List, Next } from "./types.ts"
|
|
10
11
|
*/
|
|
11
|
-
import type {
|
|
12
|
+
import type { Operation } from "../types.ts";
|
|
13
|
+
import type { Effect } from "../types.ts";
|
|
12
14
|
import type { List, Next } from "./types.ts";
|
|
13
15
|
/**
|
|
14
16
|
* The empty `List`: a pure end-of-stream marker (`undefined`).
|
|
15
17
|
*
|
|
16
|
-
* The explicit `Effect<O, Next<O, T
|
|
17
|
-
* check, so the recursive payload type-checks without a cast.
|
|
18
|
-
* these two combinators
|
|
18
|
+
* The explicit `Effect<O, Next<O, T, E>, E>` return type lets the contextual
|
|
19
|
+
* type drive the check, so the recursive payload type-checks without a cast.
|
|
20
|
+
* Construct streams through these two combinators, and end a stream that
|
|
21
|
+
* *failed* with `pureError` rather than with either of them.
|
|
19
22
|
*
|
|
20
|
-
* Note:
|
|
21
|
-
* `List<O, T>`.
|
|
23
|
+
* Note: the expanded type is written out because TypeScript cannot convert
|
|
24
|
+
* `pureOk(...)` to `List<O, T, E>`.
|
|
22
25
|
*
|
|
23
|
-
* @type {<O extends Operation, T>() => Effect<O, Next<O, T
|
|
26
|
+
* @type {<O extends Operation, T, E>() => Effect<O, Next<O, T, E>, E>}
|
|
24
27
|
*/
|
|
25
|
-
export declare const empty: <O extends Operation, T>() => Effect<O, Next<O, T
|
|
28
|
+
export declare const empty: <O extends Operation, T, E>() => Effect<O, Next<O, T, E>, E>;
|
|
26
29
|
/**
|
|
27
30
|
* Prepends `first` to a {@link List} `tail`, as a pure cons cell. `tail` is an
|
|
28
31
|
* ordinary argument, so it is built before the cell is — see {@link Next}.
|
|
29
32
|
*
|
|
30
|
-
* @type {<O extends Operation, T>(first: T, tail: List<O, T>) => Effect<O, Next<O, T
|
|
33
|
+
* @type {<O extends Operation, T, E>(first: T, tail: List<O, T, E>) => Effect<O, Next<O, T, E>, E>}
|
|
31
34
|
*/
|
|
32
|
-
export declare const nonEmpty: <O extends Operation, T>(first: T, tail: List<O, T>) => Effect<O, Next<O, T
|
|
35
|
+
export declare const nonEmpty: <O extends Operation, T, E>(first: T, tail: List<O, T, E>) => Effect<O, Next<O, T, E>, E>;
|
|
@@ -5,32 +5,34 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module
|
|
7
7
|
*
|
|
8
|
-
* @import {
|
|
8
|
+
* @import { Operation } from "../types.ts"
|
|
9
|
+
* @import { Effect } from "../types.ts"
|
|
9
10
|
* @import { List, Next } from "./types.ts"
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
|
-
import {
|
|
13
|
+
import { pureOk } from "../module.f.mjs"
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* The empty `List`: a pure end-of-stream marker (`undefined`).
|
|
16
17
|
*
|
|
17
|
-
* The explicit `Effect<O, Next<O, T
|
|
18
|
-
* check, so the recursive payload type-checks without a cast.
|
|
19
|
-
* these two combinators
|
|
18
|
+
* The explicit `Effect<O, Next<O, T, E>, E>` return type lets the contextual
|
|
19
|
+
* type drive the check, so the recursive payload type-checks without a cast.
|
|
20
|
+
* Construct streams through these two combinators, and end a stream that
|
|
21
|
+
* *failed* with `pureError` rather than with either of them.
|
|
20
22
|
*
|
|
21
|
-
* Note:
|
|
22
|
-
* `List<O, T>`.
|
|
23
|
+
* Note: the expanded type is written out because TypeScript cannot convert
|
|
24
|
+
* `pureOk(...)` to `List<O, T, E>`.
|
|
23
25
|
*
|
|
24
|
-
* @type {<O extends Operation, T>() => Effect<O, Next<O, T
|
|
26
|
+
* @type {<O extends Operation, T, E>() => Effect<O, Next<O, T, E>, E>}
|
|
25
27
|
*/
|
|
26
28
|
export const empty = () =>
|
|
27
|
-
|
|
29
|
+
pureOk(undefined)
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* Prepends `first` to a {@link List} `tail`, as a pure cons cell. `tail` is an
|
|
31
33
|
* ordinary argument, so it is built before the cell is — see {@link Next}.
|
|
32
34
|
*
|
|
33
|
-
* @type {<O extends Operation, T>(first: T, tail: List<O, T>) => Effect<O, Next<O, T
|
|
35
|
+
* @type {<O extends Operation, T, E>(first: T, tail: List<O, T, E>) => Effect<O, Next<O, T, E>, E>}
|
|
34
36
|
*/
|
|
35
37
|
export const nonEmpty = (first, tail) =>
|
|
36
|
-
|
|
38
|
+
pureOk({ first, tail })
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
7
|
-
|
|
6
|
+
import type { Operation } from '../types.ts';
|
|
7
|
+
import type { Effect, NotImplemented } from '../types.ts';
|
|
8
|
+
export type NonEmpty<O extends Operation, T, E> = {
|
|
8
9
|
readonly first: T;
|
|
9
|
-
readonly tail: List<O, T>;
|
|
10
|
+
readonly tail: List<O, T, E>;
|
|
10
11
|
};
|
|
11
12
|
/**
|
|
12
13
|
* The payload of a `List` effect: the next cons cell, or `undefined` at
|
|
@@ -19,8 +20,27 @@ export type NonEmpty<O extends Operation, T> = {
|
|
|
19
20
|
* streaming comes from cells produced inside a command's continuation, where
|
|
20
21
|
* the tail is not reached until a runner performs the command.
|
|
21
22
|
*
|
|
22
|
-
* `Effect<O, Next<O, T
|
|
23
|
-
* be written as a return type (see `empty`).
|
|
23
|
+
* `Effect<O, Next<O, T, E>, E>` is used directly in places where
|
|
24
|
+
* `List<O, T, E>` cannot be written as a return type (see `empty`).
|
|
24
25
|
*/
|
|
25
|
-
export type Next<O extends Operation, T> = NonEmpty<O, T> | undefined;
|
|
26
|
-
|
|
26
|
+
export type Next<O extends Operation, T, E> = NonEmpty<O, T, E> | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* A stream of `T`s, pulled one cell at a time, which may fail with `E`.
|
|
29
|
+
*
|
|
30
|
+
* **The failure belongs to the cell, not to the item.** A producer that cannot
|
|
31
|
+
* deliver ends the stream by failing it, so there is no such thing as a stream
|
|
32
|
+
* that continues after an error and no tail to construct after one. Putting the
|
|
33
|
+
* failure in `T` instead — `List<O, IoResult<Vec>>`, as this used to be — made
|
|
34
|
+
* an `error` item and an `undefined` end-of-stream two values of one union that
|
|
35
|
+
* every consumer had to keep apart by hand, and left a failing producer
|
|
36
|
+
* obliged to supply a tail nobody would ever pull.
|
|
37
|
+
*
|
|
38
|
+
* It also made short-circuiting unfactorable: a combinator generic in `T`
|
|
39
|
+
* cannot look inside it, so every consumer hand-wrote the same
|
|
40
|
+
* `if (t === 'error') return …`. With the failure in the cell, `step` does it.
|
|
41
|
+
*
|
|
42
|
+
* The cost is that a stream can no longer report one bad item and carry on.
|
|
43
|
+
* Nothing wanted that; a reader that did would carry a `Result` in `T`
|
|
44
|
+
* deliberately, which remains expressible and now means what it says.
|
|
45
|
+
*/
|
|
46
|
+
export type List<O extends Operation, T, E = NotImplemented> = Effect<O, Next<O, T, E>, E>;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* generation strategy.
|
|
8
8
|
*
|
|
9
9
|
* Memory effects compose with other effects by unioning operation types, for
|
|
10
|
-
* example `Effect<IoOp | MemOp, T>` for a program that performs both I/O and
|
|
10
|
+
* example `Effect<IoOp | MemOp, T, E>` for a program that performs both I/O and
|
|
11
11
|
* memory operations.
|
|
12
12
|
*
|
|
13
13
|
* See `./types.ts` for the `Key`/`MemCreate`/`MemRead`/`MemWrite`/`MemOp`
|
|
@@ -31,4 +31,5 @@ export declare const create: <T>(value: T) => Effect<MemCreate, Key<T>>;
|
|
|
31
31
|
/** Reads the current contents of a typed memory slot. */
|
|
32
32
|
export declare const read: <T>(key: Key<T>) => Effect<MemRead, T>;
|
|
33
33
|
/** Replaces the current contents of a typed memory slot. */
|
|
34
|
+
/** @type {<T>(key: Key<T>, value: T) => Effect<MemWrite, void>} */
|
|
34
35
|
export declare const write: <T>(key: Key<T>, value: T) => Effect<MemWrite, void>;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* generation strategy.
|
|
8
8
|
*
|
|
9
9
|
* Memory effects compose with other effects by unioning operation types, for
|
|
10
|
-
* example `Effect<IoOp | MemOp, T>` for a program that performs both I/O and
|
|
10
|
+
* example `Effect<IoOp | MemOp, T, E>` for a program that performs both I/O and
|
|
11
11
|
* memory operations.
|
|
12
12
|
*
|
|
13
13
|
* See `./types.ts` for the `Key`/`MemCreate`/`MemRead`/`MemWrite`/`MemOp`
|
|
@@ -40,6 +40,5 @@ export const read =
|
|
|
40
40
|
(do_('memRead'))
|
|
41
41
|
|
|
42
42
|
/** Replaces the current contents of a typed memory slot. */
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
(do_('memWrite'))
|
|
43
|
+
/** @type {<T>(key: Key<T>, value: T) => Effect<MemWrite, void>} */
|
|
44
|
+
export const write = do_('memWrite')
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { assert, assertEq } from '../../asserts/module.f.mjs'
|
|
7
|
+
import { ok } from '../../types/result/module.f.mjs'
|
|
7
8
|
import { run } from '../mock/module.f.mjs'
|
|
8
|
-
import {
|
|
9
|
+
import { pureOk, step } from '../module.f.mjs'
|
|
9
10
|
import {
|
|
10
11
|
asBase, asNominal,
|
|
11
12
|
create, read, write,
|
|
@@ -30,20 +31,22 @@ const mock = {
|
|
|
30
31
|
return [{
|
|
31
32
|
next: state.next + 1,
|
|
32
33
|
values: { ...state.values, [id]: value },
|
|
33
|
-
}, key]
|
|
34
|
+
}, ok(key)]
|
|
34
35
|
},
|
|
35
36
|
memRead: key => state =>
|
|
36
|
-
[state, state.values[asBase(key)]],
|
|
37
|
+
[state, ok(state.values[asBase(key)])],
|
|
37
38
|
memWrite: (key, value) => state => {
|
|
38
39
|
const id = asBase(key)
|
|
39
40
|
assert(id in state.values, id)
|
|
40
41
|
return [{
|
|
41
42
|
...state,
|
|
42
43
|
values: { ...state.values, [id]: value },
|
|
43
|
-
}, undefined]
|
|
44
|
+
}, ok(undefined)]
|
|
44
45
|
},
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
// `step`: each link runs only because the previous one returned `ok`,
|
|
49
|
+
// and a runner that omitted a handler would propagate rather than be ignored.
|
|
47
50
|
const program = step(
|
|
48
51
|
create(1),
|
|
49
52
|
key => {
|
|
@@ -58,7 +61,8 @@ const program = step(
|
|
|
58
61
|
export const proof = {
|
|
59
62
|
roundTrip: () => {
|
|
60
63
|
const [state, result] = run(mock)(initial)(program)
|
|
61
|
-
|
|
64
|
+
assert(result[0] === 'ok', result)
|
|
65
|
+
assertEq(result[1], 42)
|
|
62
66
|
assertEq(state.values.k0, 42, state)
|
|
63
67
|
},
|
|
64
68
|
allocatesFreshKeys: () => {
|
|
@@ -66,8 +70,10 @@ export const proof = {
|
|
|
66
70
|
create('a'),
|
|
67
71
|
a => step(
|
|
68
72
|
create('b'),
|
|
69
|
-
b =>
|
|
70
|
-
const [state,
|
|
73
|
+
b => pureOk(/** @type {const} */ ([asBase(a), asBase(b)]))))
|
|
74
|
+
const [state, result] = run(mock)(initial)(effect)
|
|
75
|
+
assert(result[0] === 'ok', result)
|
|
76
|
+
const [a, b] = result[1]
|
|
71
77
|
assertEq(a, 'k0')
|
|
72
78
|
assertEq(b, 'k1')
|
|
73
79
|
assertEq(state.values.k0, 'a', state)
|
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { Phantom } from '../../types/phantom/types.ts';
|
|
7
7
|
import type { Nominal } from '../../types/nominal/types.ts';
|
|
8
|
+
import type { OpResult } from '../node/types.ts';
|
|
8
9
|
/** Nominal brand version for memory keys. */
|
|
9
10
|
export type _MemKeyHash = '3f114fa6036a8da026b827f0c3e6d901f5e81ad9a320e431ccce31451892d286';
|
|
10
11
|
/** Opaque handle for a value stored by the memory interpreter. */
|
|
11
12
|
export type Key<T> = Phantom<Nominal<'MemKey', _MemKeyHash, string>, T>;
|
|
12
13
|
/** Allocates a fresh memory slot and initializes it with `value`. */
|
|
13
|
-
export type MemCreate = readonly ['memCreate', <T>(value: T) => Key<T
|
|
14
|
+
export type MemCreate = readonly ['memCreate', <T>(value: T) => OpResult<Key<T>>];
|
|
14
15
|
/** Reads the current value stored at `key`. */
|
|
15
|
-
export type MemRead = readonly ['memRead', <T>(key: Key<T>) => T];
|
|
16
|
+
export type MemRead = readonly ['memRead', <T>(key: Key<T>) => OpResult<T>];
|
|
16
17
|
/** Replaces the current value stored at `key`. */
|
|
17
|
-
export type MemWrite = readonly ['memWrite', <T>(key: Key<T>, value: T) => void];
|
|
18
|
+
export type MemWrite = readonly ['memWrite', <T>(key: Key<T>, value: T) => OpResult<void>];
|
|
18
19
|
export type MemOp = MemCreate | MemRead | MemWrite;
|
|
@@ -5,10 +5,26 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module
|
|
7
7
|
*
|
|
8
|
-
* @import { Operation } from '../types.ts'
|
|
9
|
-
* @import { MemOperationMap, RunInstance } from './types.ts'
|
|
8
|
+
* @import { Commands, Effect, MatchResult, Operation } from '../types.ts'
|
|
9
|
+
* @import { MemOperationMap, PartialMemOperationMap, RunInstance } from './types.ts'
|
|
10
10
|
*/
|
|
11
|
-
import type { Operation } from '../types.ts';
|
|
12
|
-
import type { MemOperationMap, RunInstance } from './types.ts';
|
|
11
|
+
import type { Commands, Operation } from '../types.ts';
|
|
12
|
+
import type { MemOperationMap, PartialMemOperationMap, RunInstance } from './types.ts';
|
|
13
13
|
/** @type {<O extends Operation, S>(o: MemOperationMap<O, S>) => RunInstance<O, S>} */
|
|
14
14
|
export declare const run: <O extends Operation, S>(o: MemOperationMap<O, S>) => RunInstance<O, S>;
|
|
15
|
+
/**
|
|
16
|
+
* {@link run} for a runner that implements only part of `O`.
|
|
17
|
+
*
|
|
18
|
+
* A command in `commands` with no handler answers `error(notImplemented)`
|
|
19
|
+
* through the ordinary continuation, so a program that asks for something this
|
|
20
|
+
* runner lacks gets its control back and decides what to do. A command outside
|
|
21
|
+
* `commands` still panics — see `partialMatch`.
|
|
22
|
+
*
|
|
23
|
+
* **The injector lives here rather than at the call site.** `partialMatch`
|
|
24
|
+
* cannot build one because the shape of an answer is the runner's, not the
|
|
25
|
+
* operation's; this loop's is `(state) => [state, …]`, and writing it once here
|
|
26
|
+
* is the whole reason each runner supplies its own.
|
|
27
|
+
*
|
|
28
|
+
* @type {<O extends Operation, S>(commands: Commands<O>) => (o: PartialMemOperationMap<O, S>) => RunInstance<O, S>}
|
|
29
|
+
*/
|
|
30
|
+
export declare const partialRun: <O extends Operation, S>(commands: Commands<O>) => (o: PartialMemOperationMap<O, S>) => RunInstance<O, S>;
|
|
@@ -5,15 +5,47 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module
|
|
7
7
|
*
|
|
8
|
-
* @import { Operation } from '../types.ts'
|
|
9
|
-
* @import { MemOperationMap, RunInstance } from './types.ts'
|
|
8
|
+
* @import { Commands, Effect, MatchResult, Operation } from '../types.ts'
|
|
9
|
+
* @import { MemOperationMap, PartialMemOperationMap, RunInstance } from './types.ts'
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { match } from "../module.f.mjs"
|
|
12
|
+
import { match, partialMatch } from "../module.f.mjs"
|
|
13
|
+
import { notImplemented } from "../module.f.mjs"
|
|
14
|
+
import { error } from "../../types/result/module.f.mjs"
|
|
13
15
|
|
|
14
16
|
/** @type {<O extends Operation, S>(o: MemOperationMap<O, S>) => RunInstance<O, S>} */
|
|
15
|
-
export const run = o =>
|
|
16
|
-
|
|
17
|
+
export const run = o => _loop(match(o))
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* {@link run} for a runner that implements only part of `O`.
|
|
21
|
+
*
|
|
22
|
+
* A command in `commands` with no handler answers `error(notImplemented)`
|
|
23
|
+
* through the ordinary continuation, so a program that asks for something this
|
|
24
|
+
* runner lacks gets its control back and decides what to do. A command outside
|
|
25
|
+
* `commands` still panics — see `partialMatch`.
|
|
26
|
+
*
|
|
27
|
+
* **The injector lives here rather than at the call site.** `partialMatch`
|
|
28
|
+
* cannot build one because the shape of an answer is the runner's, not the
|
|
29
|
+
* operation's; this loop's is `(state) => [state, …]`, and writing it once here
|
|
30
|
+
* is the whole reason each runner supplies its own.
|
|
31
|
+
*
|
|
32
|
+
* @type {<O extends Operation, S>(commands: Commands<O>) => (o: PartialMemOperationMap<O, S>) => RunInstance<O, S>}
|
|
33
|
+
*/
|
|
34
|
+
export const partialRun = commands => o => {
|
|
35
|
+
/** @type {(command: string) => (state: any) => readonly[any, any]} */
|
|
36
|
+
const onMissing = command => state => [state, error(notImplemented(command))]
|
|
37
|
+
return _loop(partialMatch(commands, onMissing)(o))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The interpreter loop both runners share: step the effect, thread the state
|
|
42
|
+
* through the handler's transition, resume with the command's output.
|
|
43
|
+
*
|
|
44
|
+
* @type {<O extends Operation, S>(
|
|
45
|
+
* next: <O1 extends O, T, E>(e: Effect<O1, T, E>) => MatchResult<O1, T, E, (state: S) => readonly[S, any]>
|
|
46
|
+
* ) => RunInstance<O, S>}
|
|
47
|
+
*/
|
|
48
|
+
const _loop = next => state => effect => {
|
|
17
49
|
let s = state
|
|
18
50
|
let e = effect
|
|
19
51
|
while (true) {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
+
import type { Result } from "../../types/result/types.ts";
|
|
6
7
|
import type { Effect, Operation, Pr } from "../types.ts";
|
|
7
8
|
/**
|
|
8
9
|
* A synchronous, state-threading operation map. An entry takes the command's
|
|
@@ -12,4 +13,12 @@ import type { Effect, Operation, Pr } from "../types.ts";
|
|
|
12
13
|
export type MemOperationMap<O extends Operation, S> = {
|
|
13
14
|
readonly [K in O[0]]: (...payload: Pr<O, K>[0]) => (state: S) => readonly [S, Pr<O, K>[1]];
|
|
14
15
|
};
|
|
15
|
-
|
|
16
|
+
/**
|
|
17
|
+
* A {@link MemOperationMap} a runner may leave holes in — the state-threading
|
|
18
|
+
* counterpart of `PartialOperationMap`. An absent handler is an operation this
|
|
19
|
+
* runner does not implement, answered with `error(notImplemented)`.
|
|
20
|
+
*/
|
|
21
|
+
export type PartialMemOperationMap<O extends Operation, S> = {
|
|
22
|
+
readonly [K in O[0]]?: (...payload: Pr<O, K>[0]) => (state: S) => readonly [S, Pr<O, K>[1]];
|
|
23
|
+
};
|
|
24
|
+
export type RunInstance<O extends Operation, S> = (state: S) => <O1 extends O, T, E>(effect: Effect<O1, T, E>) => readonly [S, Result<T, E>];
|
package/fjs/effects/module.d.mts
CHANGED
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
* @module
|
|
6
6
|
*
|
|
7
7
|
* @import { Effect, Operation, ToAsyncOperationMap } from './types.ts'
|
|
8
|
+
* @import { Result } from '../types/result/types.ts'
|
|
8
9
|
*/
|
|
9
10
|
import type { Effect, Operation, ToAsyncOperationMap } from './types.ts';
|
|
11
|
+
import type { Result } from '../types/result/types.ts';
|
|
10
12
|
/**
|
|
11
13
|
* @template {Operation} O
|
|
12
14
|
* @param {ToAsyncOperationMap<O>} map
|
|
13
|
-
* @returns {<T>(effect: Effect<O, T>) => Promise<T
|
|
15
|
+
* @returns {<T, E>(effect: Effect<O, T, E>) => Promise<Result<T, E>>}
|
|
14
16
|
*/
|
|
15
|
-
export declare const asyncRun: <O extends Operation>(map: ToAsyncOperationMap<O>) => <T>(effect: Effect<O, T>) => Promise<T
|
|
17
|
+
export declare const asyncRun: <O extends Operation>(map: ToAsyncOperationMap<O>) => <T, E>(effect: Effect<O, T, E>) => Promise<Result<T, E>>;
|