functionalscript 0.9.1 → 0.9.3
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 +3 -3
- package/bnf/data/test.f.d.ts +2 -0
- package/bnf/data/test.f.js +39 -2
- package/bnf/module.f.d.ts +6 -2
- package/bnf/module.f.js +10 -11
- package/cas/module.f.d.ts +14 -13
- package/cas/module.f.js +78 -60
- package/ci/module.f.d.ts +3 -2
- package/ci/module.f.js +6 -8
- package/ci/module.js +3 -3
- package/crypto/hmac/test.f.js +1 -1
- package/crypto/sign/test.f.js +1 -1
- package/dev/module.f.d.ts +1 -1
- package/dev/module.f.js +13 -6
- package/dev/tf/all.test.js +2 -2
- package/dev/tf/module.f.js +2 -2
- package/dev/version/module.f.d.ts +2 -11
- package/dev/version/module.f.js +17 -15
- package/dev/version/test.f.d.ts +3 -1
- package/dev/version/test.f.js +26 -11
- package/djs/parser-new/module.f.d.ts +3 -0
- package/djs/parser-new/module.f.js +149 -0
- package/djs/parser-new/test.f.d.ts +5 -0
- package/djs/parser-new/test.f.js +202 -0
- package/djs/serializer/module.f.js +6 -6
- package/fjs/module.f.d.ts +1 -1
- package/fjs/module.f.js +3 -2
- package/fsc/module.f.js +1 -1
- package/io/module.d.ts +4 -0
- package/io/module.f.d.ts +10 -4
- package/io/module.f.js +28 -0
- package/io/module.js +7 -1
- package/json/module.f.js +3 -3
- package/package.json +3 -2
- package/path/module.f.d.ts +1 -0
- package/path/module.f.js +6 -3
- package/text/utf16/module.f.js +1 -1
- package/text/utf8/module.f.d.ts +1 -1
- package/types/asn.1/module.f.d.ts +62 -0
- package/types/asn.1/module.f.js +276 -0
- package/types/asn.1/test.f.d.ts +44 -0
- package/types/asn.1/test.f.js +312 -0
- package/types/base128/module.f.d.ts +15 -0
- package/types/base128/module.f.js +38 -0
- package/types/base128/test.f.d.ts +2 -0
- package/types/base128/test.f.js +26 -0
- package/types/bit_vec/module.f.d.ts +15 -3
- package/types/bit_vec/module.f.js +22 -2
- package/types/bit_vec/test.f.d.ts +1 -0
- package/types/bit_vec/test.f.js +28 -6
- package/types/effect/mock/module.f.d.ts +5 -0
- package/types/effect/mock/module.f.js +14 -0
- package/types/effect/module.d.ts +2 -0
- package/types/effect/module.f.d.ts +23 -0
- package/types/effect/module.f.js +14 -0
- package/types/effect/module.js +11 -0
- package/types/effect/node/module.f.d.ts +56 -0
- package/types/effect/node/module.f.js +8 -0
- package/types/effect/node/test.f.d.ts +28 -0
- package/types/effect/node/test.f.js +277 -0
- package/types/effect/node/virtual/module.f.d.ts +16 -0
- package/types/effect/node/virtual/module.f.js +103 -0
- package/types/function/module.f.d.ts +1 -1
- package/types/function/module.f.js +1 -1
- package/types/function/test.f.js +1 -1
- package/types/list/module.f.js +4 -4
- package/website/module.d.ts +1 -0
- package/website/module.f.d.ts +3 -0
- package/website/module.f.js +9 -0
- package/website/module.js +3 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { empty, vec, vec8 } from "../bit_vec/module.f.js";
|
|
2
|
+
import { asBase } from "../nominal/module.f.js";
|
|
3
|
+
import { encode, decode } from "./module.f.js";
|
|
4
|
+
const test = (a, b) => {
|
|
5
|
+
const encoded = encode(a);
|
|
6
|
+
if (encoded !== b) {
|
|
7
|
+
throw `encoded: ${asBase(encoded).toString(16)}, expected: ${asBase(b).toString(16)}`;
|
|
8
|
+
}
|
|
9
|
+
const [decoded, rest] = decode(b);
|
|
10
|
+
if (decoded !== a) {
|
|
11
|
+
throw `decoded: ${decoded.toString(16)}, expected: ${a.toString(16)}`;
|
|
12
|
+
}
|
|
13
|
+
if (rest !== empty) {
|
|
14
|
+
throw `rest: ${asBase(rest).toString(16)}, expected: ${asBase(empty).toString(16)}`;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
export default () => {
|
|
18
|
+
test(0n, vec8(0n));
|
|
19
|
+
test(1n, vec8(1n));
|
|
20
|
+
test(0x7fn, vec8(0x7fn));
|
|
21
|
+
test(0x80n, vec(16n)(0x8100n));
|
|
22
|
+
test(0x81n, vec(16n)(0x8101n));
|
|
23
|
+
test(0x82n, vec(16n)(0x8102n));
|
|
24
|
+
test(0x3fffn, vec(16n)(0xff7fn));
|
|
25
|
+
test(0x4000n, vec(24n)(0x818000n));
|
|
26
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { Fold, Reduce as OpReduce } from
|
|
2
|
-
import { type List, type Thunk } from
|
|
3
|
-
import { type Nominal } from
|
|
1
|
+
import type { Fold, Reduce as OpReduce } from '../function/operator/module.f.ts';
|
|
2
|
+
import { type List, type Thunk } from '../list/module.f.ts';
|
|
3
|
+
import { type Nominal } from '../nominal/module.f.ts';
|
|
4
|
+
import { type Sign } from '../function/compare/module.f.ts';
|
|
4
5
|
/**
|
|
5
6
|
* A vector of bits represented as a signed `bigint`.
|
|
6
7
|
*/
|
|
@@ -185,3 +186,14 @@ export declare const listToVec: ({ concat }: BitOrder) => (list: List<Vec>) => V
|
|
|
185
186
|
* Repeats a vector to create a padded block of the desired length.
|
|
186
187
|
*/
|
|
187
188
|
export declare const repeat: Fold<bigint, Vec>;
|
|
189
|
+
export declare const isVec: <T>(v: Vec | T) => v is Vec;
|
|
190
|
+
/**
|
|
191
|
+
* Lexically compares two vectors based on their unsigned integer values,
|
|
192
|
+
* normalizing them to the same length. If the values are equal,
|
|
193
|
+
* the shorter vector is considered smaller.
|
|
194
|
+
*
|
|
195
|
+
* a < b => -1
|
|
196
|
+
* a > b => 1
|
|
197
|
+
* a === b => 0
|
|
198
|
+
*/
|
|
199
|
+
export declare const msbCmp: (av: Vec) => (bv: Vec) => Sign;
|
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
*
|
|
22
22
|
* @module
|
|
23
23
|
*/
|
|
24
|
-
import {
|
|
24
|
+
import { bitLength, mask, max, min, xor } from "../bigint/module.f.js";
|
|
25
25
|
import { flip } from "../function/module.f.js";
|
|
26
26
|
import { fold } from "../list/module.f.js";
|
|
27
27
|
import { asBase, asNominal } from "../nominal/module.f.js";
|
|
28
28
|
import { repeat as mRepeat } from "../monoid/module.f.js";
|
|
29
|
+
import { cmp } from "../function/compare/module.f.js";
|
|
29
30
|
/**
|
|
30
31
|
* An empty vector of bits.
|
|
31
32
|
*/
|
|
@@ -55,7 +56,7 @@ export const vec = (len) => {
|
|
|
55
56
|
const lastBit = 1n << last;
|
|
56
57
|
return ui => {
|
|
57
58
|
// normalize `u`
|
|
58
|
-
const u = m &
|
|
59
|
+
const u = m & ui;
|
|
59
60
|
//
|
|
60
61
|
const sign = u >> last;
|
|
61
62
|
const x = sign !== 0n ? u : -(u ^ lastBit);
|
|
@@ -202,3 +203,22 @@ export const listToVec = ({ concat }) => fold(flip(concat))(empty);
|
|
|
202
203
|
* Repeats a vector to create a padded block of the desired length.
|
|
203
204
|
*/
|
|
204
205
|
export const repeat = mRepeat({ identity: empty, operation: lsb.concat });
|
|
206
|
+
export const isVec = (v) => typeof v === 'bigint';
|
|
207
|
+
/**
|
|
208
|
+
* Lexically compares two vectors based on their unsigned integer values,
|
|
209
|
+
* normalizing them to the same length. If the values are equal,
|
|
210
|
+
* the shorter vector is considered smaller.
|
|
211
|
+
*
|
|
212
|
+
* a < b => -1
|
|
213
|
+
* a > b => 1
|
|
214
|
+
* a === b => 0
|
|
215
|
+
*/
|
|
216
|
+
export const msbCmp = (av) => (bv) => {
|
|
217
|
+
const au = unpack(av);
|
|
218
|
+
const bu = unpack(bv);
|
|
219
|
+
const al = au.length;
|
|
220
|
+
const bl = bu.length;
|
|
221
|
+
const { a, b } = msbNorm(au)(bu)(min(al)(bl));
|
|
222
|
+
const result = cmp(a)(b);
|
|
223
|
+
return result !== 0 ? result : cmp(al)(bl);
|
|
224
|
+
};
|
package/types/bit_vec/test.f.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mask } from "../bigint/module.f.js";
|
|
2
2
|
import { asBase, asNominal } from "../nominal/module.f.js";
|
|
3
|
-
import { length, empty, uint, vec, lsb, msb, repeat, vec8 } from "./module.f.js";
|
|
3
|
+
import { length, empty, uint, vec, lsb, msb, repeat, vec8, msbCmp } from "./module.f.js";
|
|
4
4
|
const unsafeVec = (a) => asNominal(a);
|
|
5
5
|
// 0x8 = 0b1000 = 0 + 8
|
|
6
6
|
// 0x9 = 0b1001 = 1 + 8
|
|
@@ -347,16 +347,16 @@ export default {
|
|
|
347
347
|
const v = vec(len)(ui);
|
|
348
348
|
const x = asBase(v);
|
|
349
349
|
if (x !== raw) {
|
|
350
|
-
throw x
|
|
350
|
+
throw `x: ${x}, raw: ${raw}`;
|
|
351
351
|
}
|
|
352
352
|
const len2 = length(v);
|
|
353
353
|
if (len2 !== len) {
|
|
354
354
|
throw len2;
|
|
355
355
|
}
|
|
356
356
|
const u = uint(v);
|
|
357
|
-
const mui = mask(len) &
|
|
357
|
+
const mui = mask(len) & ui;
|
|
358
358
|
if (u !== mui) {
|
|
359
|
-
throw u;
|
|
359
|
+
throw [u, mui];
|
|
360
360
|
}
|
|
361
361
|
};
|
|
362
362
|
// 0n
|
|
@@ -373,7 +373,15 @@ export default {
|
|
|
373
373
|
() => c(2n)(1n)(-3n),
|
|
374
374
|
() => c(2n)(2n)(2n),
|
|
375
375
|
() => c(2n)(3n)(3n),
|
|
376
|
-
|
|
376
|
+
// -1 is 0b.....1
|
|
377
|
+
// -2 is 0b....10
|
|
378
|
+
// -3 is 0b...101
|
|
379
|
+
// -4 is 0b...100
|
|
380
|
+
// -5 is 0b..1011
|
|
381
|
+
// -6 is 0b..1010
|
|
382
|
+
// -7 is 0b..1011, cut 0b11, vec: -0b11
|
|
383
|
+
// -8 is 0b..1100 = ~(8-1) = ~7
|
|
384
|
+
() => c(2n)(-7n)(-3n), //< overflow.
|
|
377
385
|
];
|
|
378
386
|
},
|
|
379
387
|
concat2: () => {
|
|
@@ -420,5 +428,19 @@ export default {
|
|
|
420
428
|
if (repeat(7n)(vec(5n)(0x13n)) !== vec(35n)(21059194483n)) {
|
|
421
429
|
throw 'repeat failed';
|
|
422
430
|
}
|
|
431
|
+
},
|
|
432
|
+
msbCmp: () => {
|
|
433
|
+
const c = (a) => (b) => (r) => {
|
|
434
|
+
const result = msbCmp(a)(b);
|
|
435
|
+
if (result !== r) {
|
|
436
|
+
throw `result: ${result}, expected: ${r}`;
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
c(vec(4n)(0x5n))(vec(4n)(0x5n))(0); // 0b0101 == 0b0101
|
|
440
|
+
c(vec(4n)(0x5n))(vec(4n)(0x6n))(-1); // 0b0101 < 0b0110
|
|
441
|
+
c(vec(4n)(0x6n))(vec(4n)(0x5n))(1); // 0b0110 > 0b0101
|
|
442
|
+
c(vec(4n)(0x5n))(vec(5n)(0x5n))(1); // 0b0101_ < 0b00101
|
|
443
|
+
c(vec(5n)(0x5n))(vec(4n)(0x5n))(-1); // 0b00101 < 0b0101_
|
|
444
|
+
c(vec(4n)(0x5n))(vec(5n)(0xan))(-1); // 0b0101_ < 0b01010
|
|
423
445
|
}
|
|
424
446
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Effect, Operations } from "../module.f.ts";
|
|
2
|
+
export type MemOperationMap<O extends Operations, S> = {
|
|
3
|
+
readonly [K in keyof O]: (state: S, payload: O[K][0]) => readonly [S, O[K][1]];
|
|
4
|
+
};
|
|
5
|
+
export declare const run: <O extends Operations, S>(o: MemOperationMap<O, S>) => (state: S) => <O1 extends O, T>(effect: Effect<O1, T>) => readonly [S, T];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const run = (o) => (state) => (effect) => {
|
|
2
|
+
let s = state;
|
|
3
|
+
let e = effect;
|
|
4
|
+
while (true) {
|
|
5
|
+
if ('pure' in e) {
|
|
6
|
+
return [s, e.pure];
|
|
7
|
+
}
|
|
8
|
+
const [cmd, payload, cont] = e.do;
|
|
9
|
+
const operation = o[cmd];
|
|
10
|
+
const [ns, m] = operation(s, payload);
|
|
11
|
+
s = ns;
|
|
12
|
+
e = cont(m);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type Operations = {
|
|
2
|
+
readonly [command in string]: readonly [input: unknown, output: unknown];
|
|
3
|
+
};
|
|
4
|
+
export type Effect<O extends Operations, T> = Pure<O, T> | Do<O, T>;
|
|
5
|
+
export type Map<O extends Operations, T> = {
|
|
6
|
+
readonly pipe: <O1 extends Operations, R>(f: (_: T) => Effect<O1, R>) => Effect<O | O1, R>;
|
|
7
|
+
readonly map: <O1 extends Operations, R>(f: (_: T) => R) => Effect<O | O1, R>;
|
|
8
|
+
};
|
|
9
|
+
export type Pure<O extends Operations, T> = {
|
|
10
|
+
readonly pure: T;
|
|
11
|
+
} & Map<O, T>;
|
|
12
|
+
export declare const pure: <O extends Operations, T>(value: T) => Pure<O, T>;
|
|
13
|
+
export type One<O extends Operations, T, K extends keyof O & string> = readonly [K, O[K][0], (input: O[K][1]) => Effect<O, T>];
|
|
14
|
+
export type Do<O extends Operations, T> = {
|
|
15
|
+
readonly do: {
|
|
16
|
+
readonly [K in keyof O & string]: One<O, T, K>;
|
|
17
|
+
}[keyof O & string];
|
|
18
|
+
} & Map<O, T>;
|
|
19
|
+
export declare const do_: <O extends Operations, K extends keyof O & string>(cmd: K, payload: O[K][0]) => Do<O, O[K][1]>;
|
|
20
|
+
export type ToAsyncOperationMap<O extends Operations> = {
|
|
21
|
+
readonly [K in keyof O]: (payload: O[K][0]) => Promise<O[K][1]>;
|
|
22
|
+
};
|
|
23
|
+
export declare const all: <O extends Operations, T>(set: readonly Effect<O, T>[]) => Effect<O, readonly T[]>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const pure = (value) => ({
|
|
2
|
+
pure: value,
|
|
3
|
+
pipe: e => e(value),
|
|
4
|
+
map: f => pure(f(value))
|
|
5
|
+
});
|
|
6
|
+
const doFull = (cmd, payload, cont) => ({
|
|
7
|
+
do: [cmd, payload, cont],
|
|
8
|
+
pipe: e => doFull(cmd, payload, x => cont(x).pipe(e)),
|
|
9
|
+
map: f => doFull(cmd, payload, x => cont(x).map(f))
|
|
10
|
+
});
|
|
11
|
+
export const do_ = (cmd, payload) => doFull(cmd, payload, pure);
|
|
12
|
+
const empty = pure([]);
|
|
13
|
+
// TODO: replace with either a `Do` operation or as an addition to `Pure` and `Do`.
|
|
14
|
+
export const all = (set) => set.reduce((previous, current) => previous.pipe(previousResult => current.map(currentResult => [...previousResult, currentResult])), empty);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const asyncRun = (map) => async (effect) => {
|
|
2
|
+
while (true) {
|
|
3
|
+
if ('pure' in effect) {
|
|
4
|
+
return effect.pure;
|
|
5
|
+
}
|
|
6
|
+
const [command, payload, continuation] = effect.do;
|
|
7
|
+
const operation = map[command];
|
|
8
|
+
const result = await operation(payload);
|
|
9
|
+
effect = continuation(result);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Vec } from '../../bit_vec/module.f.ts';
|
|
2
|
+
import type { Result } from '../../result/module.f.ts';
|
|
3
|
+
import { type Do, type Effect, type ToAsyncOperationMap } from '../module.f.ts';
|
|
4
|
+
export type IoResult<T> = Result<T, unknown>;
|
|
5
|
+
export type Fetch = {
|
|
6
|
+
readonly fetch: readonly [string, IoResult<Vec>];
|
|
7
|
+
};
|
|
8
|
+
export declare const fetch: (url: string) => Do<Fetch, IoResult<Vec>>;
|
|
9
|
+
export type MakeDirectoryOptions = {
|
|
10
|
+
readonly recursive: true;
|
|
11
|
+
};
|
|
12
|
+
export type MkdirParam = readonly [string, MakeDirectoryOptions?];
|
|
13
|
+
export type Mkdir = {
|
|
14
|
+
readonly mkdir: readonly [MkdirParam, IoResult<void>];
|
|
15
|
+
};
|
|
16
|
+
export declare const mkdir: (...p: MkdirParam) => Do<Mkdir, IoResult<void>>;
|
|
17
|
+
export type ReadFile = {
|
|
18
|
+
readonly readFile: readonly [string, IoResult<Vec>];
|
|
19
|
+
};
|
|
20
|
+
export declare const readFile: (path: string) => Do<ReadFile, IoResult<Vec>>;
|
|
21
|
+
/**
|
|
22
|
+
* Represents a directory entry (file or directory) in the filesystem
|
|
23
|
+
* @see https://nodejs.org/api/fs.html#class-fsdirent
|
|
24
|
+
*/
|
|
25
|
+
export type Dirent = {
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly parentPath: string;
|
|
28
|
+
readonly isFile: boolean;
|
|
29
|
+
};
|
|
30
|
+
export type ReaddirOptions = {
|
|
31
|
+
readonly recursive?: true;
|
|
32
|
+
};
|
|
33
|
+
export type ReaddirParam = readonly [string, ReaddirOptions];
|
|
34
|
+
export type Readdir = {
|
|
35
|
+
readonly readdir: readonly [ReaddirParam, IoResult<readonly Dirent[]>];
|
|
36
|
+
};
|
|
37
|
+
export declare const readdir: (...p: ReaddirParam) => Do<Readdir, IoResult<readonly Dirent[]>>;
|
|
38
|
+
export type WriteFileParam = readonly [string, Vec];
|
|
39
|
+
export type WriteFile = {
|
|
40
|
+
readonly writeFile: readonly [WriteFileParam, IoResult<void>];
|
|
41
|
+
};
|
|
42
|
+
export declare const writeFile: (...p: WriteFileParam) => Do<WriteFile, IoResult<void>>;
|
|
43
|
+
export type Fs = Mkdir & ReadFile & Readdir & WriteFile;
|
|
44
|
+
export type Error = {
|
|
45
|
+
readonly error: readonly [string, void];
|
|
46
|
+
};
|
|
47
|
+
export declare const error: (msg: string) => Do<Error, void>;
|
|
48
|
+
export type Log = {
|
|
49
|
+
readonly log: readonly [string, void];
|
|
50
|
+
};
|
|
51
|
+
export declare const log: (msg: string) => Do<Log, void>;
|
|
52
|
+
export type Console = Log & Error;
|
|
53
|
+
export type NodeOperations = Fetch & Console & Fs;
|
|
54
|
+
export type NodeEffect<T> = Effect<NodeOperations, T>;
|
|
55
|
+
export type NodeOperationMap = ToAsyncOperationMap<NodeOperations>;
|
|
56
|
+
export type NodeProgram = (argv: readonly string[]) => NodeEffect<number>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { do_ } from "../module.f.js";
|
|
2
|
+
export const fetch = (url) => do_('fetch', url);
|
|
3
|
+
export const mkdir = (...p) => do_('mkdir', p);
|
|
4
|
+
export const readFile = (path) => do_('readFile', path);
|
|
5
|
+
export const readdir = (...p) => do_('readdir', p);
|
|
6
|
+
export const writeFile = (...p) => do_('writeFile', p);
|
|
7
|
+
export const error = (msg) => do_('error', msg);
|
|
8
|
+
export const log = (msg) => do_('log', msg);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
map: () => void;
|
|
3
|
+
fetch: () => void;
|
|
4
|
+
mkdir: {
|
|
5
|
+
one: () => void;
|
|
6
|
+
rec: () => void;
|
|
7
|
+
nonRec: () => void;
|
|
8
|
+
};
|
|
9
|
+
readFile: {
|
|
10
|
+
one: () => void;
|
|
11
|
+
nested: () => void;
|
|
12
|
+
noSuchFile: () => void;
|
|
13
|
+
nestedPath: () => void;
|
|
14
|
+
};
|
|
15
|
+
readdir: {
|
|
16
|
+
one: () => void;
|
|
17
|
+
nonRecursive: () => void;
|
|
18
|
+
nested: () => void;
|
|
19
|
+
noSuchDir: () => void;
|
|
20
|
+
};
|
|
21
|
+
writeFile: {
|
|
22
|
+
one: () => void;
|
|
23
|
+
overwrite: () => void;
|
|
24
|
+
nestedPath: () => void;
|
|
25
|
+
directory: () => void;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export default _default;
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { empty, isVec, uint, vec8 } from "../../bit_vec/module.f.js";
|
|
2
|
+
import { run } from "../mock/module.f.js";
|
|
3
|
+
import { fetch, mkdir, readdir, readFile, writeFile } from "./module.f.js";
|
|
4
|
+
import { emptyState, virtual } from "./virtual/module.f.js";
|
|
5
|
+
export default {
|
|
6
|
+
map: () => {
|
|
7
|
+
let e = readFile('hello').map(([k, v]) => {
|
|
8
|
+
if (k === 'error') {
|
|
9
|
+
throw v;
|
|
10
|
+
}
|
|
11
|
+
return uint(v) * 2n;
|
|
12
|
+
});
|
|
13
|
+
//
|
|
14
|
+
while (true) {
|
|
15
|
+
if ('pure' in e) {
|
|
16
|
+
const result = e.pure;
|
|
17
|
+
if (result !== 0x2an) {
|
|
18
|
+
throw result;
|
|
19
|
+
}
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const [cmd, p, cont] = e.do;
|
|
23
|
+
if (cmd !== 'readFile') {
|
|
24
|
+
throw cmd;
|
|
25
|
+
}
|
|
26
|
+
if (p !== 'hello') {
|
|
27
|
+
throw p;
|
|
28
|
+
}
|
|
29
|
+
e = cont(['ok', vec8(0x15n)]);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
fetch: () => {
|
|
33
|
+
const v = run(virtual);
|
|
34
|
+
const [_, [t, result]] = v({
|
|
35
|
+
...emptyState,
|
|
36
|
+
internet: {
|
|
37
|
+
'https://example.com/data': vec8(0x2an),
|
|
38
|
+
},
|
|
39
|
+
})(fetch('https://example.com/data'));
|
|
40
|
+
if (t === 'error') {
|
|
41
|
+
throw result;
|
|
42
|
+
}
|
|
43
|
+
if (!isVec(result)) {
|
|
44
|
+
throw result;
|
|
45
|
+
}
|
|
46
|
+
if (uint(result) !== 0x2an) {
|
|
47
|
+
throw result;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
mkdir: {
|
|
51
|
+
one: () => {
|
|
52
|
+
const v = run(virtual);
|
|
53
|
+
const [state, [t, result]] = v(emptyState)(mkdir('a'));
|
|
54
|
+
if (t === 'error') {
|
|
55
|
+
throw result;
|
|
56
|
+
}
|
|
57
|
+
const a = state.root.a;
|
|
58
|
+
if (a === undefined || isVec(a)) {
|
|
59
|
+
throw a;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
rec: () => {
|
|
63
|
+
const [state, [t, result]] = run(virtual)(emptyState)(mkdir('tmp/cache', { recursive: true }));
|
|
64
|
+
if (t !== 'ok') {
|
|
65
|
+
throw result;
|
|
66
|
+
}
|
|
67
|
+
const tmp = state.root.tmp;
|
|
68
|
+
if (tmp === undefined || isVec(tmp)) {
|
|
69
|
+
throw state.root;
|
|
70
|
+
}
|
|
71
|
+
const cache = tmp.cache;
|
|
72
|
+
if (cache === undefined || isVec(cache)) {
|
|
73
|
+
throw tmp;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
nonRec: () => {
|
|
77
|
+
const [state, [t, result]] = run(virtual)(emptyState)(mkdir('tmp/cache'));
|
|
78
|
+
if (t !== 'error') {
|
|
79
|
+
throw result;
|
|
80
|
+
}
|
|
81
|
+
if (state.root.tmp !== undefined) {
|
|
82
|
+
throw state.root.tmp;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
readFile: {
|
|
87
|
+
one: () => {
|
|
88
|
+
const v = run(virtual);
|
|
89
|
+
const initial = {
|
|
90
|
+
...emptyState,
|
|
91
|
+
root: {
|
|
92
|
+
hello: vec8(0x2an),
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
const [state, [t, result]] = v(initial)(readFile('hello'));
|
|
96
|
+
if (t === 'error') {
|
|
97
|
+
throw result;
|
|
98
|
+
}
|
|
99
|
+
if (!isVec(result)) {
|
|
100
|
+
throw result;
|
|
101
|
+
}
|
|
102
|
+
if (uint(result) !== 0x2an) {
|
|
103
|
+
throw result;
|
|
104
|
+
}
|
|
105
|
+
if (state.root.hello === undefined) {
|
|
106
|
+
throw state.root;
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
nested: () => {
|
|
110
|
+
const [_, [tag, result]] = run(virtual)({
|
|
111
|
+
...emptyState,
|
|
112
|
+
root: { tmp: { cache: vec8(0x15n) } }
|
|
113
|
+
})(readFile('tmp/cache'));
|
|
114
|
+
if (tag === 'error') {
|
|
115
|
+
throw result;
|
|
116
|
+
}
|
|
117
|
+
if (uint(result) !== 0x15n) {
|
|
118
|
+
throw result;
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
noSuchFile: () => {
|
|
122
|
+
const [_, [t, result]] = run(virtual)(emptyState)(readFile('hello'));
|
|
123
|
+
if (t !== 'error') {
|
|
124
|
+
throw result;
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
nestedPath: () => {
|
|
128
|
+
const [_, [t, result]] = run(virtual)(emptyState)(readFile('tmp/cache'));
|
|
129
|
+
if (t !== 'error') {
|
|
130
|
+
throw result;
|
|
131
|
+
}
|
|
132
|
+
if (result !== 'no such file') {
|
|
133
|
+
throw result;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
readdir: {
|
|
138
|
+
one: () => {
|
|
139
|
+
const [_, [t, result]] = run(virtual)({
|
|
140
|
+
...emptyState,
|
|
141
|
+
root: {
|
|
142
|
+
file: vec8(0x2an),
|
|
143
|
+
dir: {
|
|
144
|
+
a: empty
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
})(readdir('', { recursive: true }));
|
|
148
|
+
if (t !== 'ok') {
|
|
149
|
+
throw result;
|
|
150
|
+
}
|
|
151
|
+
const file = result.find(x => x.name === 'file');
|
|
152
|
+
if (file === undefined || file.parentPath !== '' || !file.isFile) {
|
|
153
|
+
throw `file: ${file}`;
|
|
154
|
+
}
|
|
155
|
+
const dirA = result.find(x => x.name === 'a');
|
|
156
|
+
if (dirA === undefined || dirA.parentPath !== '/dir') {
|
|
157
|
+
throw `dirA: ${dirA?.parentPath}`;
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
nonRecursive: () => {
|
|
161
|
+
const [_, [t, result]] = run(virtual)({
|
|
162
|
+
...emptyState,
|
|
163
|
+
root: {
|
|
164
|
+
file: vec8(0x2an),
|
|
165
|
+
dir: {
|
|
166
|
+
a: empty
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
})(readdir('', {}));
|
|
170
|
+
if (t !== 'ok') {
|
|
171
|
+
throw result;
|
|
172
|
+
}
|
|
173
|
+
if (result.length !== 2) {
|
|
174
|
+
throw result;
|
|
175
|
+
}
|
|
176
|
+
const file = result.find(x => x.name === 'file');
|
|
177
|
+
if (file === undefined) {
|
|
178
|
+
throw file;
|
|
179
|
+
}
|
|
180
|
+
const dir = result.find(x => x.name === 'dir');
|
|
181
|
+
if (dir === undefined) {
|
|
182
|
+
throw dir;
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
nested: () => {
|
|
186
|
+
const [_, [t, result]] = run(virtual)({
|
|
187
|
+
...emptyState,
|
|
188
|
+
root: { tmp: { cache: vec8(0x15n) } }
|
|
189
|
+
})(readdir('tmp', { recursive: true }));
|
|
190
|
+
if (t !== 'ok') {
|
|
191
|
+
throw result;
|
|
192
|
+
}
|
|
193
|
+
if (result.length !== 1) {
|
|
194
|
+
throw result;
|
|
195
|
+
}
|
|
196
|
+
const [r0] = result;
|
|
197
|
+
if (r0.name !== 'cache') {
|
|
198
|
+
throw r0;
|
|
199
|
+
}
|
|
200
|
+
if (r0.parentPath !== 'tmp') {
|
|
201
|
+
throw r0;
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
noSuchDir: () => {
|
|
205
|
+
const [_, [t, result]] = run(virtual)(emptyState)(readdir('tmp', { recursive: true }));
|
|
206
|
+
if (t !== 'error') {
|
|
207
|
+
throw result;
|
|
208
|
+
}
|
|
209
|
+
if (result !== 'invalid path') {
|
|
210
|
+
throw result;
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
writeFile: {
|
|
215
|
+
one: () => {
|
|
216
|
+
const [state, [t, result]] = run(virtual)(emptyState)(writeFile('hello', vec8(0x2an)));
|
|
217
|
+
if (t !== 'ok') {
|
|
218
|
+
throw result;
|
|
219
|
+
}
|
|
220
|
+
const file = state.root.hello;
|
|
221
|
+
if (!isVec(file)) {
|
|
222
|
+
throw file;
|
|
223
|
+
}
|
|
224
|
+
if (uint(file) !== 0x2an) {
|
|
225
|
+
throw file;
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
overwrite: () => {
|
|
229
|
+
const [state, [t, result]] = run(virtual)({
|
|
230
|
+
...emptyState,
|
|
231
|
+
root: {
|
|
232
|
+
hello: vec8(0x15n),
|
|
233
|
+
},
|
|
234
|
+
})(writeFile('hello', vec8(0x2an)));
|
|
235
|
+
if (t !== 'ok') {
|
|
236
|
+
throw result;
|
|
237
|
+
}
|
|
238
|
+
const file = state.root.hello;
|
|
239
|
+
if (!isVec(file)) {
|
|
240
|
+
throw file;
|
|
241
|
+
}
|
|
242
|
+
if (uint(file) !== 0x2an) {
|
|
243
|
+
throw file;
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
nestedPath: () => {
|
|
247
|
+
const [state, [t, result]] = run(virtual)(emptyState)(writeFile('tmp/cache', vec8(0x2an)));
|
|
248
|
+
if (t !== 'error') {
|
|
249
|
+
throw result;
|
|
250
|
+
}
|
|
251
|
+
if (result !== 'invalid file') {
|
|
252
|
+
throw result;
|
|
253
|
+
}
|
|
254
|
+
if (state.root.tmp !== undefined) {
|
|
255
|
+
throw state.root;
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
directory: () => {
|
|
259
|
+
const [state, [t, result]] = run(virtual)({
|
|
260
|
+
...emptyState,
|
|
261
|
+
root: {
|
|
262
|
+
tmp: {},
|
|
263
|
+
},
|
|
264
|
+
})(writeFile('tmp', vec8(0x2an)));
|
|
265
|
+
if (t !== 'error') {
|
|
266
|
+
throw result;
|
|
267
|
+
}
|
|
268
|
+
if (result !== 'invalid file') {
|
|
269
|
+
throw result;
|
|
270
|
+
}
|
|
271
|
+
const tmp = state.root.tmp;
|
|
272
|
+
if (tmp === undefined || isVec(tmp)) {
|
|
273
|
+
throw tmp;
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Vec } from "../../../bit_vec/module.f.ts";
|
|
2
|
+
import type { MemOperationMap } from "../../mock/module.f.ts";
|
|
3
|
+
import type { NodeOperations } from "../module.f.ts";
|
|
4
|
+
export type VirtualDir = {
|
|
5
|
+
readonly [name in string]?: VirtualDir | Vec;
|
|
6
|
+
};
|
|
7
|
+
export type VirtualState = {
|
|
8
|
+
stdout: string;
|
|
9
|
+
stderr: string;
|
|
10
|
+
root: VirtualDir;
|
|
11
|
+
internet: {
|
|
12
|
+
readonly [url: string]: Vec;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export declare const emptyState: VirtualState;
|
|
16
|
+
export declare const virtual: MemOperationMap<NodeOperations, VirtualState>;
|