functionalscript 0.22.0 → 0.23.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/fs/asn.1/module.f.js +2 -1
- package/fs/cas/proof.f.d.ts +9 -0
- package/fs/cas/proof.f.js +96 -2
- package/fs/ci/config/module.f.d.ts +2 -2
- package/fs/ci/config/module.f.js +2 -2
- package/fs/crypto/pow/module.f.d.ts +37 -0
- package/fs/crypto/pow/module.f.js +72 -0
- package/fs/crypto/pow/proof.f.d.ts +33 -0
- package/fs/crypto/pow/proof.f.js +161 -0
- package/fs/dev/module.f.js +2 -2
- package/fs/emergent_testing/all.test.d.ts +1 -1
- package/fs/emergent_testing/all.test.js +2 -2
- package/fs/emergent_testing/example.f.d.ts +13 -0
- package/fs/emergent_testing/example.f.js +31 -0
- package/fs/emergent_testing/module.d.ts +1 -1
- package/fs/emergent_testing/module.js +3 -3
- package/fs/emergent_testing/scenarios/all.d.ts +1 -1
- package/fs/emergent_testing/scenarios/all.js +1 -3
- package/fs/fjs/module.js +2 -2
- package/fs/io/module.d.ts +20 -2
- package/fs/io/module.js +20 -5
- package/fs/path/module.f.d.ts +4 -0
- package/fs/path/module.f.js +5 -1
- package/fs/path/proof.f.d.ts +1 -0
- package/fs/path/proof.f.js +28 -2
- package/fs/types/bigint/module.f.d.ts +0 -15
- package/fs/types/bigint/module.f.js +0 -15
- package/fs/types/bigint/proof.f.js +2 -1
- package/fs/types/bit_vec/module.f.js +2 -2
- package/fs/types/function/compare/module.f.d.ts +12 -0
- package/fs/types/function/compare/module.f.js +12 -0
- package/fs/types/function/compare/proof.f.js +31 -1
- package/fs/types/function/operator/module.f.d.ts +0 -2
- package/fs/types/function/operator/module.f.js +0 -2
- package/fs/types/function/operator/proof.f.d.ts +0 -2
- package/fs/types/function/operator/proof.f.js +2 -18
- package/fs/types/number/module.f.js +4 -4
- package/package.json +1 -1
package/fs/asn.1/module.f.js
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
*
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
|
-
import { bitLength
|
|
7
|
+
import { bitLength } from "../types/bigint/module.f.js";
|
|
8
8
|
import { empty, isVec, length, msb, uint, unpack, vec, vec8 } from "../types/bit_vec/module.f.js";
|
|
9
9
|
import { identity } from "../types/function/module.f.js";
|
|
10
|
+
import { max } from "../types/function/compare/module.f.js";
|
|
10
11
|
import { encode as b128encode, decode as b128decode } from "../base128/module.f.js";
|
|
11
12
|
const { popFront: pop, listToVec } = msb;
|
|
12
13
|
const pop8 = pop(8n);
|
package/fs/cas/proof.f.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
export declare const proof: {
|
|
2
|
+
mainAdd: () => void;
|
|
3
|
+
mainAddWrongArgs: () => void;
|
|
4
|
+
mainGetFound: () => void;
|
|
5
|
+
mainGetNotFound: () => void;
|
|
6
|
+
mainGetWrongArgs: () => void;
|
|
7
|
+
mainGetInvalidHash: () => void;
|
|
8
|
+
mainList: () => void;
|
|
9
|
+
mainNoCmd: () => void;
|
|
10
|
+
mainUnknownCmd: () => void;
|
|
2
11
|
casWrite: () => void;
|
|
3
12
|
casReadPassthrough: () => void;
|
|
4
13
|
};
|
package/fs/cas/proof.f.js
CHANGED
|
@@ -1,9 +1,103 @@
|
|
|
1
|
-
import { cas } from "./module.f.js";
|
|
1
|
+
import { cas, main } from "./module.f.js";
|
|
2
2
|
import { sha256 } from "../crypto/sha2/module.f.js";
|
|
3
|
-
import { empty, length } from "../types/bit_vec/module.f.js";
|
|
3
|
+
import { empty, length, vec8 } from "../types/bit_vec/module.f.js";
|
|
4
4
|
import { pure } from "../types/effects/module.f.js";
|
|
5
5
|
import { run } from "../types/effects/mock/module.f.js";
|
|
6
|
+
import { emptyState, virtual } from "../types/effects/node/virtual/module.f.js";
|
|
6
7
|
export const proof = {
|
|
8
|
+
mainAdd: () => {
|
|
9
|
+
const content = vec8(0x2an);
|
|
10
|
+
const state = { ...emptyState, root: { myfile: content } };
|
|
11
|
+
const [finalState, exitCode] = virtual(state)(main(['add', 'myfile']));
|
|
12
|
+
if (exitCode !== 0) {
|
|
13
|
+
throw ['expected exit 0', exitCode];
|
|
14
|
+
}
|
|
15
|
+
if (finalState.stdout.length === 0) {
|
|
16
|
+
throw 'expected hash in stdout';
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
mainAddWrongArgs: () => {
|
|
20
|
+
const [finalState, exitCode] = virtual(emptyState)(main(['add']));
|
|
21
|
+
if (exitCode !== 1) {
|
|
22
|
+
throw ['expected exit 1', exitCode];
|
|
23
|
+
}
|
|
24
|
+
if (finalState.stderr.length === 0) {
|
|
25
|
+
throw 'expected error in stderr';
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
mainGetFound: () => {
|
|
29
|
+
const content = vec8(0x2an);
|
|
30
|
+
const state = { ...emptyState, root: { myfile: content } };
|
|
31
|
+
const [state1, exitCode1] = virtual(state)(main(['add', 'myfile']));
|
|
32
|
+
if (exitCode1 !== 0) {
|
|
33
|
+
throw ['expected add exit 0', exitCode1];
|
|
34
|
+
}
|
|
35
|
+
const hashStr = state1.stdout.trim();
|
|
36
|
+
const [, exitCode2] = virtual(state1)(main(['get', hashStr, 'output']));
|
|
37
|
+
if (exitCode2 !== 0) {
|
|
38
|
+
throw ['expected get exit 0', exitCode2];
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
mainGetNotFound: () => {
|
|
42
|
+
// valid cBase32 hash that has not been stored
|
|
43
|
+
const content = vec8(0x2an);
|
|
44
|
+
const state = { ...emptyState, root: { myfile: content } };
|
|
45
|
+
const [state1] = virtual(state)(main(['add', 'myfile']));
|
|
46
|
+
const hashStr = state1.stdout.trim();
|
|
47
|
+
// use an empty store so the hash is not found
|
|
48
|
+
const [finalState, exitCode] = virtual(emptyState)(main(['get', hashStr, 'output']));
|
|
49
|
+
if (exitCode !== 1) {
|
|
50
|
+
throw ['expected exit 1', exitCode];
|
|
51
|
+
}
|
|
52
|
+
if (finalState.stderr.length === 0) {
|
|
53
|
+
throw 'expected error in stderr';
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
mainGetWrongArgs: () => {
|
|
57
|
+
const [finalState, exitCode] = virtual(emptyState)(main(['get']));
|
|
58
|
+
if (exitCode !== 1) {
|
|
59
|
+
throw ['expected exit 1', exitCode];
|
|
60
|
+
}
|
|
61
|
+
if (finalState.stderr.length === 0) {
|
|
62
|
+
throw 'expected error in stderr';
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
mainGetInvalidHash: () => {
|
|
66
|
+
const [finalState, exitCode] = virtual(emptyState)(main(['get', 'not-a-valid-hash', 'output']));
|
|
67
|
+
if (exitCode !== 1) {
|
|
68
|
+
throw ['expected exit 1', exitCode];
|
|
69
|
+
}
|
|
70
|
+
if (finalState.stderr.length === 0) {
|
|
71
|
+
throw 'expected error in stderr';
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
mainList: () => {
|
|
75
|
+
const content = vec8(0x2an);
|
|
76
|
+
const state = { ...emptyState, root: { myfile: content } };
|
|
77
|
+
const [state1] = virtual(state)(main(['add', 'myfile']));
|
|
78
|
+
const [, exitCode] = virtual(state1)(main(['list']));
|
|
79
|
+
if (exitCode !== 0) {
|
|
80
|
+
throw ['expected exit 0', exitCode];
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
mainNoCmd: () => {
|
|
84
|
+
const [finalState, exitCode] = virtual(emptyState)(main([]));
|
|
85
|
+
if (exitCode !== 1) {
|
|
86
|
+
throw ['expected exit 1', exitCode];
|
|
87
|
+
}
|
|
88
|
+
if (finalState.stderr.length === 0) {
|
|
89
|
+
throw 'expected error in stderr';
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
mainUnknownCmd: () => {
|
|
93
|
+
const [finalState, exitCode] = virtual(emptyState)(main(['bogus']));
|
|
94
|
+
if (exitCode !== 1) {
|
|
95
|
+
throw ['expected exit 1', exitCode];
|
|
96
|
+
}
|
|
97
|
+
if (finalState.stderr.length === 0) {
|
|
98
|
+
throw 'expected error in stderr';
|
|
99
|
+
}
|
|
100
|
+
},
|
|
7
101
|
casWrite: () => {
|
|
8
102
|
const store = {
|
|
9
103
|
read: (_key) => pure(undefined),
|
|
@@ -20,7 +20,7 @@ export declare const images: {
|
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
22
|
export declare const bun = "1.3.14";
|
|
23
|
-
export declare const deno = "2.8.
|
|
23
|
+
export declare const deno = "2.8.2";
|
|
24
24
|
export declare const playwright = "1.60.0";
|
|
25
25
|
export declare const node: {
|
|
26
26
|
readonly default: "26.3.0";
|
|
@@ -28,7 +28,7 @@ export declare const node: {
|
|
|
28
28
|
};
|
|
29
29
|
export declare const wasmtime = "45.0.0";
|
|
30
30
|
export declare const wasmer = "7.1.0";
|
|
31
|
-
export declare const tsgo = "7.0.0-dev.
|
|
31
|
+
export declare const tsgo = "7.0.0-dev.20260604.1";
|
|
32
32
|
export declare const actions: {
|
|
33
33
|
readonly 'actions/checkout': "v6";
|
|
34
34
|
readonly 'actions/setup-node': "v6";
|
package/fs/ci/config/module.f.js
CHANGED
|
@@ -23,7 +23,7 @@ export const images = {
|
|
|
23
23
|
// https://bun.sh/
|
|
24
24
|
export const bun = '1.3.14';
|
|
25
25
|
// https://deno.com/
|
|
26
|
-
export const deno = '2.8.
|
|
26
|
+
export const deno = '2.8.2';
|
|
27
27
|
// https://www.npmjs.com/package/playwright
|
|
28
28
|
export const playwright = '1.60.0';
|
|
29
29
|
// https://nodejs.org/en/download
|
|
@@ -36,7 +36,7 @@ export const wasmtime = '45.0.0';
|
|
|
36
36
|
// https://github.com/wasmerio/wasmer/releases
|
|
37
37
|
export const wasmer = '7.1.0';
|
|
38
38
|
// https://www.npmjs.com/package/@typescript/native-preview?activeTab=versions
|
|
39
|
-
export const tsgo = '7.0.0-dev.
|
|
39
|
+
export const tsgo = '7.0.0-dev.20260604.1';
|
|
40
40
|
// GitHub Action versions used by CI step builders. The key is the action
|
|
41
41
|
// `owner/name`; call sites compose the full ref as
|
|
42
42
|
// `` `${name}@${actions[name]}` ``.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Vec } from '../../types/bit_vec/module.f.ts';
|
|
2
|
+
import type { Nullable } from '../../types/nullable/module.f.ts';
|
|
3
|
+
import { type Sha2 } from '../sha2/module.f.ts';
|
|
4
|
+
/** Genesis-block compact target (`0x1d00ffff`). */
|
|
5
|
+
export declare const genesisNBits = 486604799n;
|
|
6
|
+
/** Genesis-block uint256 target decoded from {@link genesisNBits}. */
|
|
7
|
+
export declare const genesisTarget = 26959535291011309493156476344723991336010898738574164086137773096960n;
|
|
8
|
+
/**
|
|
9
|
+
* Decodes compact **nBits** (32-bit block-header "bits") to a uint256 target:
|
|
10
|
+
*
|
|
11
|
+
* - `exponent = nBits >> 24`
|
|
12
|
+
* - `mantissa = nBits & 0xffffff`
|
|
13
|
+
* - `target = mantissa × 2^(8 × (exponent − 3))`
|
|
14
|
+
*
|
|
15
|
+
* Returns `null` for malformed encodings per Bitcoin `SetCompact` rules (negative
|
|
16
|
+
* sign bit, overflow, target wider than 256 bits).
|
|
17
|
+
*
|
|
18
|
+
* @param nBits - Compact target encoding.
|
|
19
|
+
* @returns Decoded target, or `null` when **nBits** is invalid.
|
|
20
|
+
*/
|
|
21
|
+
export declare const targetFromNBits: (nBits: bigint) => Nullable<bigint>;
|
|
22
|
+
export type Pow = {
|
|
23
|
+
/** Hash `data` with the configured `Sha2`; digest as big-endian uint256. */
|
|
24
|
+
readonly hashInt: (data: Vec) => bigint;
|
|
25
|
+
/** Whether `hashInt(data) <= targetFromNBits(nBits)`; `false` when **nBits** is invalid. */
|
|
26
|
+
readonly meets: (nBits: bigint) => (data: Vec) => boolean;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Builds PoW helpers for a hash function (typical consumer: {@link sha256}).
|
|
30
|
+
*
|
|
31
|
+
* @param hash - SHA-2 configuration whose digest is compared as uint256.
|
|
32
|
+
*/
|
|
33
|
+
export declare const pow: (hash: Sha2) => Pow;
|
|
34
|
+
/** SHA-256 proof-of-work (`pow(sha256)`). */
|
|
35
|
+
export declare const sha256Pow: Pow;
|
|
36
|
+
/** Bitcoin block-header PoW; same as {@link sha256Pow}. */
|
|
37
|
+
export declare const bitcoinPow: Pow;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bitcoin-style proof-of-work: compact **nBits** target decoding and
|
|
3
|
+
* hash-vs-target verification using an injected SHA-2 hash.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
import { mask } from "../../types/bigint/module.f.js";
|
|
8
|
+
import { uint } from "../../types/bit_vec/module.f.js";
|
|
9
|
+
import { computeSync, sha256 } from "../sha2/module.f.js";
|
|
10
|
+
const nBitsMantissa = mask(24n);
|
|
11
|
+
const mantissaSign = 0x00800000n;
|
|
12
|
+
const mantissaBody = 0x007fffffn;
|
|
13
|
+
const exponentShift = 24n;
|
|
14
|
+
const uint256Mask = mask(256n);
|
|
15
|
+
/** Genesis-block compact target (`0x1d00ffff`). */
|
|
16
|
+
export const genesisNBits = 0x1d00ffffn;
|
|
17
|
+
/** Genesis-block uint256 target decoded from {@link genesisNBits}. */
|
|
18
|
+
export const genesisTarget = 0x00000000ffff0000000000000000000000000000000000000000000000000000n;
|
|
19
|
+
const decodeShift = (exponent) => 8n * (exponent - 3n);
|
|
20
|
+
const compactTarget = (exponent) => (mantissa) => {
|
|
21
|
+
const shift = decodeShift(exponent);
|
|
22
|
+
return shift >= 0n ? mantissa << shift : mantissa >> -shift;
|
|
23
|
+
};
|
|
24
|
+
const negativeNBits = (mantissa) => mantissa !== 0n && (mantissa & mantissaSign) !== 0n;
|
|
25
|
+
const overflowNBits = (exponent) => (mantissa) => (target) => target !== 0n &&
|
|
26
|
+
(exponent > 34n || (mantissa !== 0n && (mantissa & mantissaBody) === 0n));
|
|
27
|
+
/**
|
|
28
|
+
* Decodes compact **nBits** (32-bit block-header "bits") to a uint256 target:
|
|
29
|
+
*
|
|
30
|
+
* - `exponent = nBits >> 24`
|
|
31
|
+
* - `mantissa = nBits & 0xffffff`
|
|
32
|
+
* - `target = mantissa × 2^(8 × (exponent − 3))`
|
|
33
|
+
*
|
|
34
|
+
* Returns `null` for malformed encodings per Bitcoin `SetCompact` rules (negative
|
|
35
|
+
* sign bit, overflow, target wider than 256 bits).
|
|
36
|
+
*
|
|
37
|
+
* @param nBits - Compact target encoding.
|
|
38
|
+
* @returns Decoded target, or `null` when **nBits** is invalid.
|
|
39
|
+
*/
|
|
40
|
+
export const targetFromNBits = (nBits) => {
|
|
41
|
+
const exponent = nBits >> exponentShift;
|
|
42
|
+
const mantissa = nBits & nBitsMantissa;
|
|
43
|
+
if (negativeNBits(mantissa)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const target = compactTarget(exponent)(mantissa);
|
|
47
|
+
if (overflowNBits(exponent)(mantissa)(target)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (target > uint256Mask) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return target;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Builds PoW helpers for a hash function (typical consumer: {@link sha256}).
|
|
57
|
+
*
|
|
58
|
+
* @param hash - SHA-2 configuration whose digest is compared as uint256.
|
|
59
|
+
*/
|
|
60
|
+
export const pow = (hash) => {
|
|
61
|
+
const c = computeSync(hash);
|
|
62
|
+
const hashInt = (data) => uint(c([data]));
|
|
63
|
+
const meets = (nBits) => (data) => {
|
|
64
|
+
const target = targetFromNBits(nBits);
|
|
65
|
+
return target !== null && hashInt(data) <= target;
|
|
66
|
+
};
|
|
67
|
+
return { hashInt, meets };
|
|
68
|
+
};
|
|
69
|
+
/** SHA-256 proof-of-work (`pow(sha256)`). */
|
|
70
|
+
export const sha256Pow = pow(sha256);
|
|
71
|
+
/** Bitcoin block-header PoW; same as {@link sha256Pow}. */
|
|
72
|
+
export const bitcoinPow = sha256Pow;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare const proof: {
|
|
2
|
+
targetFromNBits: {
|
|
3
|
+
genesis: () => void;
|
|
4
|
+
block0HashWithinGenesisTarget: () => void;
|
|
5
|
+
exponent3: () => void;
|
|
6
|
+
exponent2: () => void;
|
|
7
|
+
hardTargetOne: () => void;
|
|
8
|
+
zero: () => void;
|
|
9
|
+
negative: () => void;
|
|
10
|
+
negativeHighMantissa: () => void;
|
|
11
|
+
overflowExponent: () => void;
|
|
12
|
+
exceeds256: () => void;
|
|
13
|
+
};
|
|
14
|
+
meets: {
|
|
15
|
+
easy: () => void;
|
|
16
|
+
hard: () => void;
|
|
17
|
+
genesisFailsSample: () => void;
|
|
18
|
+
zeroTargetRejectsSample: () => void;
|
|
19
|
+
invalidNBits: () => void;
|
|
20
|
+
hashLeqTarget: () => void;
|
|
21
|
+
};
|
|
22
|
+
hashInt: {
|
|
23
|
+
sha256Sample: () => void;
|
|
24
|
+
sha256Empty: () => void;
|
|
25
|
+
sha224: () => void;
|
|
26
|
+
stable: () => void;
|
|
27
|
+
};
|
|
28
|
+
pow: {
|
|
29
|
+
sha256Pow: () => void;
|
|
30
|
+
bitcoinPow: () => void;
|
|
31
|
+
independentInstances: () => void;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { utf8 } from "../../text/module.f.js";
|
|
2
|
+
import { empty, uint } from "../../types/bit_vec/module.f.js";
|
|
3
|
+
import { computeSync, sha224, sha256 } from "../sha2/module.f.js";
|
|
4
|
+
import { bitcoinPow, genesisNBits, genesisTarget, pow, sha256Pow, targetFromNBits } from "./module.f.js";
|
|
5
|
+
const p256 = sha256Pow;
|
|
6
|
+
const p224 = pow(sha224);
|
|
7
|
+
const sample = utf8('functionalscript pow proof');
|
|
8
|
+
const emptyData = empty;
|
|
9
|
+
/** Target large enough for {@link sample} under SHA-256 (`0x207fffff`). */
|
|
10
|
+
const easyNBits = 0x207fffffn;
|
|
11
|
+
/** Compact encoding for target `1` (`0x03000001`). */
|
|
12
|
+
const hardNBits = 0x03000001n;
|
|
13
|
+
/** SHA-256 of the empty message (NIST / Bitcoin block merkle uses this primitive). */
|
|
14
|
+
const sha256EmptyHash = 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855n;
|
|
15
|
+
/** Bitcoin block #0 header hash as big-endian uint256. */
|
|
16
|
+
const block0Hash = 0x000000000019d6689c085ae165831e934ff763ae46a2a6cffb388491c27dc990n;
|
|
17
|
+
const expectNull = (nBits) => {
|
|
18
|
+
if (targetFromNBits(nBits) !== null) {
|
|
19
|
+
throw nBits;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export const proof = {
|
|
23
|
+
targetFromNBits: {
|
|
24
|
+
genesis: () => {
|
|
25
|
+
if (targetFromNBits(genesisNBits) !== genesisTarget) {
|
|
26
|
+
throw 'genesis target';
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
block0HashWithinGenesisTarget: () => {
|
|
30
|
+
if (block0Hash > genesisTarget) {
|
|
31
|
+
throw 'block0 hash exceeds genesis target';
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
exponent3: () => {
|
|
35
|
+
if (targetFromNBits(0x030000ffn) !== 0xffn) {
|
|
36
|
+
throw 'exponent 3';
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
exponent2: () => {
|
|
40
|
+
if (targetFromNBits(0x02008000n) !== 0x80n) {
|
|
41
|
+
throw 'exponent 2';
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
hardTargetOne: () => {
|
|
45
|
+
if (targetFromNBits(hardNBits) !== 1n) {
|
|
46
|
+
throw 'hard target';
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
zero: () => {
|
|
50
|
+
if (targetFromNBits(0n) !== 0n) {
|
|
51
|
+
throw 'zero nBits';
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
negative: () => {
|
|
55
|
+
expectNull(0x01800001n);
|
|
56
|
+
},
|
|
57
|
+
negativeHighMantissa: () => {
|
|
58
|
+
expectNull(0x22ffffffn);
|
|
59
|
+
},
|
|
60
|
+
overflowExponent: () => {
|
|
61
|
+
expectNull(0x23000001n);
|
|
62
|
+
},
|
|
63
|
+
exceeds256: () => {
|
|
64
|
+
expectNull(0x227fffffn);
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
meets: {
|
|
68
|
+
easy: () => {
|
|
69
|
+
if (!p256.meets(easyNBits)(sample)) {
|
|
70
|
+
throw 'easy nBits should pass';
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
hard: () => {
|
|
74
|
+
if (p256.meets(hardNBits)(sample)) {
|
|
75
|
+
throw 'target 1 should fail';
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
genesisFailsSample: () => {
|
|
79
|
+
if (p256.meets(genesisNBits)(sample)) {
|
|
80
|
+
throw 'genesis target too hard for sample';
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
zeroTargetRejectsSample: () => {
|
|
84
|
+
if (p256.meets(0n)(sample)) {
|
|
85
|
+
throw 'non-zero hash vs zero target';
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
invalidNBits: () => {
|
|
89
|
+
if (p256.meets(0x01800001n)(sample)) {
|
|
90
|
+
throw 'invalid nBits should not pass';
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
hashLeqTarget: () => {
|
|
94
|
+
const h = p256.hashInt(sample);
|
|
95
|
+
const target = targetFromNBits(easyNBits);
|
|
96
|
+
if (target === null) {
|
|
97
|
+
throw 'easy nBits decode';
|
|
98
|
+
}
|
|
99
|
+
if (h > target) {
|
|
100
|
+
throw 'hash above easy target';
|
|
101
|
+
}
|
|
102
|
+
if (!(h <= target)) {
|
|
103
|
+
throw 'hash <= target';
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
hashInt: {
|
|
108
|
+
sha256Sample: () => {
|
|
109
|
+
const digest = computeSync(sha256)([sample]);
|
|
110
|
+
if (p256.hashInt(sample) !== uint(digest)) {
|
|
111
|
+
throw 'sha256 sample';
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
sha256Empty: () => {
|
|
115
|
+
if (p256.hashInt(emptyData) !== sha256EmptyHash) {
|
|
116
|
+
throw 'sha256 empty constant';
|
|
117
|
+
}
|
|
118
|
+
const digest = computeSync(sha256)([emptyData]);
|
|
119
|
+
if (p256.hashInt(emptyData) !== uint(digest)) {
|
|
120
|
+
throw 'sha256 empty';
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
sha224: () => {
|
|
124
|
+
const digest = computeSync(sha224)([sample]);
|
|
125
|
+
if (p224.hashInt(sample) !== uint(digest)) {
|
|
126
|
+
throw 'sha224';
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
stable: () => {
|
|
130
|
+
if (p256.hashInt(sample) !== p256.hashInt(sample)) {
|
|
131
|
+
throw 'stable';
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
pow: {
|
|
136
|
+
sha256Pow: () => {
|
|
137
|
+
const built = pow(sha256);
|
|
138
|
+
if (sha256Pow.hashInt(sample) !== built.hashInt(sample)) {
|
|
139
|
+
throw 'hashInt';
|
|
140
|
+
}
|
|
141
|
+
if (sha256Pow.meets(easyNBits)(sample) !== built.meets(easyNBits)(sample)) {
|
|
142
|
+
throw 'meets';
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
bitcoinPow: () => {
|
|
146
|
+
if (bitcoinPow.hashInt(sample) !== sha256Pow.hashInt(sample)) {
|
|
147
|
+
throw 'bitcoinPow';
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
independentInstances: () => {
|
|
151
|
+
const a = pow(sha256);
|
|
152
|
+
const b = pow(sha256);
|
|
153
|
+
if (a.hashInt(sample) !== b.hashInt(sample)) {
|
|
154
|
+
throw 'hashInt';
|
|
155
|
+
}
|
|
156
|
+
if (a.meets(easyNBits)(sample) !== b.meets(easyNBits)(sample)) {
|
|
157
|
+
throw 'meets';
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
};
|
package/fs/dev/module.f.js
CHANGED
|
@@ -7,7 +7,7 @@ import { begin, pure } from "../types/effects/module.f.js";
|
|
|
7
7
|
import { parse as jsonParse } from "../json/module.f.js";
|
|
8
8
|
import { record, unknown as rttiUnknown } from "../types/rtti/module.f.js";
|
|
9
9
|
import { parse as rttiParse } from "../types/rtti/parse/module.f.js";
|
|
10
|
-
import { relativize } from "../path/module.f.js";
|
|
10
|
+
import { relativize, toPosix } from "../path/module.f.js";
|
|
11
11
|
export const env = ({ process: { env } }) => a => {
|
|
12
12
|
const r = Object.getOwnPropertyDescriptor(env, a);
|
|
13
13
|
return r === undefined ? undefined :
|
|
@@ -74,7 +74,7 @@ const { fromEntries } = Object;
|
|
|
74
74
|
*/
|
|
75
75
|
export const loadModuleMap = (env) => {
|
|
76
76
|
const initCwd = env['INIT_CWD'];
|
|
77
|
-
const s = initCwd === undefined ? '.' :
|
|
77
|
+
const s = initCwd === undefined ? '.' : toPosix(initCwd);
|
|
78
78
|
const prefix = s === '.' ? '' : s;
|
|
79
79
|
// TODO: there are multiple `all` effects here,
|
|
80
80
|
// we should consider optimize them by ALIQ technique or something similar.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import './module.ts';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "./module.js";
|
|
2
2
|
// we need `await` for Playwright.
|
|
3
|
-
await run()
|
|
3
|
+
// await run()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const add: (a: number, b: number) => number;
|
|
2
|
+
export declare const mul: (a: number, b: number) => number;
|
|
3
|
+
export declare const sqr: (a: number) => number;
|
|
4
|
+
export declare const todo: () => never;
|
|
5
|
+
export declare const proof: {
|
|
6
|
+
addTest: () => void;
|
|
7
|
+
mulTest: (() => void)[];
|
|
8
|
+
throw: {
|
|
9
|
+
todo: () => never;
|
|
10
|
+
divByZero: () => bigint;
|
|
11
|
+
};
|
|
12
|
+
generateSqrTests: () => (() => void)[];
|
|
13
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const add = (a, b) => a + b;
|
|
2
|
+
export const mul = (a, b) => a * b;
|
|
3
|
+
export const sqr = (a) => mul(a, a);
|
|
4
|
+
export const todo = () => { throw "not implemented"; };
|
|
5
|
+
const checkMul = (a, b, r) => {
|
|
6
|
+
if (mul(a, b) !== r) {
|
|
7
|
+
throw `mul(${a}, ${b}) !== ${r}`;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
export const proof = {
|
|
11
|
+
addTest: () => {
|
|
12
|
+
if (add(2, 2) !== 4) {
|
|
13
|
+
throw "something wrong with the math";
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
mulTest: [
|
|
17
|
+
() => checkMul(2, 3, 6),
|
|
18
|
+
() => checkMul(22, 34, 748),
|
|
19
|
+
() => checkMul(-2, 3, -6),
|
|
20
|
+
() => checkMul(-2, -3, 6),
|
|
21
|
+
],
|
|
22
|
+
throw: {
|
|
23
|
+
todo,
|
|
24
|
+
divByZero: () => 5n / 0n,
|
|
25
|
+
},
|
|
26
|
+
generateSqrTests: () => [1, 2, 3, 5].map(a => () => {
|
|
27
|
+
if (sqr(a) !== a * a) {
|
|
28
|
+
throw `sqr(${a})`;
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { runEffect } from "../io/module.js";
|
|
2
2
|
import { register } from "./module.f.js";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
// we need `await` for Playwright.
|
|
4
|
+
await runEffect(register);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import '../module.ts';
|
package/fs/fjs/module.js
CHANGED
package/fs/io/module.d.ts
CHANGED
|
@@ -5,5 +5,23 @@ export declare const asyncImport: (v: string) => Promise<Module>;
|
|
|
5
5
|
export declare const tryCatch: <T>(f: () => T) => Result<T, unknown>;
|
|
6
6
|
export declare const io: Io;
|
|
7
7
|
export type NodeRun = (p: NodeProgram) => Promise<never>;
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Runs a `NodeProgram` against the real Node `io` and process arguments,
|
|
10
|
+
* resolving to its exit code **without** terminating the process.
|
|
11
|
+
*
|
|
12
|
+
* Use this when the caller must stay alive afterwards — e.g. when proofs are
|
|
13
|
+
* registered under an external test runner (Node `--test`, Bun, Playwright)
|
|
14
|
+
* that owns the process lifecycle. For a standalone CLI entry point that should
|
|
15
|
+
* exit with the program's code, use the default {@link run} export instead.
|
|
16
|
+
*/
|
|
17
|
+
export declare const runEffect: (p: NodeProgram) => Promise<number>;
|
|
18
|
+
/**
|
|
19
|
+
* CLI entry point: runs a `NodeProgram` via {@link runEffect}, then calls
|
|
20
|
+
* `process.exit` with its exit code. The `Promise<never>` return type reflects
|
|
21
|
+
* that control never returns to the caller — the process terminates.
|
|
22
|
+
*
|
|
23
|
+
* This is the default export so a `bin` script can simply
|
|
24
|
+
* `import run from '.../io/module.js'; run(main)`.
|
|
25
|
+
*/
|
|
26
|
+
declare const run: NodeRun;
|
|
27
|
+
export default run;
|
package/fs/io/module.js
CHANGED
|
@@ -125,8 +125,23 @@ export const io = {
|
|
|
125
125
|
playwrightTestContext,
|
|
126
126
|
engine: isPlaywright ? 'playwright' : 'Bun' in globalThis ? 'bun' : 'node',
|
|
127
127
|
};
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Runs a `NodeProgram` against the real Node `io` and process arguments,
|
|
130
|
+
* resolving to its exit code **without** terminating the process.
|
|
131
|
+
*
|
|
132
|
+
* Use this when the caller must stay alive afterwards — e.g. when proofs are
|
|
133
|
+
* registered under an external test runner (Node `--test`, Bun, Playwright)
|
|
134
|
+
* that owns the process lifecycle. For a standalone CLI entry point that should
|
|
135
|
+
* exit with the program's code, use the default {@link run} export instead.
|
|
136
|
+
*/
|
|
137
|
+
export const runEffect = runProgram(io)(io.process.argv.slice(2));
|
|
138
|
+
/**
|
|
139
|
+
* CLI entry point: runs a `NodeProgram` via {@link runEffect}, then calls
|
|
140
|
+
* `process.exit` with its exit code. The `Promise<never>` return type reflects
|
|
141
|
+
* that control never returns to the caller — the process terminates.
|
|
142
|
+
*
|
|
143
|
+
* This is the default export so a `bin` script can simply
|
|
144
|
+
* `import run from '.../io/module.js'; run(main)`.
|
|
145
|
+
*/
|
|
146
|
+
const run = async (p) => process.exit(await runEffect(p));
|
|
147
|
+
export default run;
|
package/fs/path/module.f.d.ts
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import type { Reduce, Unary } from '../types/function/operator/module.f.ts';
|
|
7
|
+
/**
|
|
8
|
+
* Converts Windows separators (`\`) to POSIX separators (`/`).
|
|
9
|
+
*/
|
|
10
|
+
export declare const toPosix: (path: string) => string;
|
|
7
11
|
/**
|
|
8
12
|
* Splits a path into normalized segments.
|
|
9
13
|
*
|
package/fs/path/module.f.js
CHANGED
|
@@ -21,6 +21,10 @@ const foldNormalizeOp = input => state => {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Converts Windows separators (`\`) to POSIX separators (`/`).
|
|
26
|
+
*/
|
|
27
|
+
export const toPosix = (path) => path.replaceAll('\\', '/');
|
|
24
28
|
/**
|
|
25
29
|
* Splits a path into normalized segments.
|
|
26
30
|
*
|
|
@@ -29,7 +33,7 @@ const foldNormalizeOp = input => state => {
|
|
|
29
33
|
* separators are converted to POSIX separators.
|
|
30
34
|
*/
|
|
31
35
|
export const parse = (path) => {
|
|
32
|
-
const split = path
|
|
36
|
+
const split = toPosix(path).split('/');
|
|
33
37
|
return toArray(fold(foldNormalizeOp)([])(split));
|
|
34
38
|
};
|
|
35
39
|
/**
|
package/fs/path/proof.f.d.ts
CHANGED
package/fs/path/proof.f.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { concat, normalize, relativize } from "./module.f.js";
|
|
1
|
+
import { concat, normalize, relativize, toPosix } from "./module.f.js";
|
|
2
2
|
const normalizeTest = [
|
|
3
3
|
() => {
|
|
4
4
|
const norm = normalize("dir/file.json");
|
|
@@ -65,4 +65,30 @@ const relativizeTest = [
|
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
];
|
|
68
|
-
|
|
68
|
+
const toPosixTest = [
|
|
69
|
+
() => {
|
|
70
|
+
const p = toPosix('a\\b\\c');
|
|
71
|
+
if (p !== 'a/b/c') {
|
|
72
|
+
throw p;
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
() => {
|
|
76
|
+
const p = toPosix('a/b/c');
|
|
77
|
+
if (p !== 'a/b/c') {
|
|
78
|
+
throw p;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
() => {
|
|
82
|
+
const p = toPosix('C:\\Users\\x');
|
|
83
|
+
if (p !== 'C:/Users/x') {
|
|
84
|
+
throw p;
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
() => {
|
|
88
|
+
const p = toPosix('');
|
|
89
|
+
if (p !== '') {
|
|
90
|
+
throw p;
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
export const proof = { normalizeTest, concatTest, relativizeTest, toPosixTest };
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
* const logValue = log2(8n) // 3n
|
|
14
14
|
* const bitCount = bitLength(255n) // 8n
|
|
15
15
|
* const bitmask = mask(5n) // 31n
|
|
16
|
-
* const m = min(3n)(13n) // 3n
|
|
17
16
|
* const c = combination([3n, 2n, 1n]) // 60n
|
|
18
17
|
* ```
|
|
19
18
|
*/
|
|
@@ -130,20 +129,6 @@ export declare const bitLength: (v: bigint) => bigint;
|
|
|
130
129
|
* ```
|
|
131
130
|
*/
|
|
132
131
|
export declare const mask: (len: bigint) => bigint;
|
|
133
|
-
/**
|
|
134
|
-
* Returns the smaller of two `bigint` values.
|
|
135
|
-
*
|
|
136
|
-
* @param a - The first bigint.
|
|
137
|
-
* @returns A function that takes the second bigint and returns the smaller value.
|
|
138
|
-
*/
|
|
139
|
-
export declare const min: (a: bigint) => (b: bigint) => bigint;
|
|
140
|
-
/**
|
|
141
|
-
* Returns the larger of two `bigint` values.
|
|
142
|
-
*
|
|
143
|
-
* @param a - The first bigint.
|
|
144
|
-
* @returns A function that takes the second bigint and returns the larger value.
|
|
145
|
-
*/
|
|
146
|
-
export declare const max: (a: bigint) => (b: bigint) => bigint;
|
|
147
132
|
/**
|
|
148
133
|
* Calculates the partial factorial `b!/a!`.
|
|
149
134
|
*
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
* const logValue = log2(8n) // 3n
|
|
14
14
|
* const bitCount = bitLength(255n) // 8n
|
|
15
15
|
* const bitmask = mask(5n) // 31n
|
|
16
|
-
* const m = min(3n)(13n) // 3n
|
|
17
16
|
* const c = combination([3n, 2n, 1n]) // 60n
|
|
18
17
|
* ```
|
|
19
18
|
*/
|
|
@@ -174,20 +173,6 @@ export const bitLength = (v) => log2(abs(v)) + 1n;
|
|
|
174
173
|
* ```
|
|
175
174
|
*/
|
|
176
175
|
export const mask = (len) => (1n << len) - 1n;
|
|
177
|
-
/**
|
|
178
|
-
* Returns the smaller of two `bigint` values.
|
|
179
|
-
*
|
|
180
|
-
* @param a - The first bigint.
|
|
181
|
-
* @returns A function that takes the second bigint and returns the smaller value.
|
|
182
|
-
*/
|
|
183
|
-
export const min = (a) => (b) => a < b ? a : b;
|
|
184
|
-
/**
|
|
185
|
-
* Returns the larger of two `bigint` values.
|
|
186
|
-
*
|
|
187
|
-
* @param a - The first bigint.
|
|
188
|
-
* @returns A function that takes the second bigint and returns the larger value.
|
|
189
|
-
*/
|
|
190
|
-
export const max = (a) => (b) => a < b ? b : a;
|
|
191
176
|
/**
|
|
192
177
|
* Calculates the partial factorial `b!/a!`.
|
|
193
178
|
*
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { sum, abs, serialize, log2, bitLength, mask,
|
|
1
|
+
import { sum, abs, serialize, log2, bitLength, mask, combination, factorial, divUp, roundUp } from "./module.f.js";
|
|
2
|
+
import { min } from "../function/compare/module.f.js";
|
|
2
3
|
const oldLog2 = (v) => {
|
|
3
4
|
if (v <= 0n) {
|
|
4
5
|
return -1n;
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
*
|
|
22
22
|
* @module
|
|
23
23
|
*/
|
|
24
|
-
import { bitLength, divUp, mask,
|
|
24
|
+
import { bitLength, divUp, mask, xor } from "../bigint/module.f.js";
|
|
25
25
|
import { flip, identity } from "../function/module.f.js";
|
|
26
26
|
import { fold, iterable, map } 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
|
+
import { cmp, max, min } from "../function/compare/module.f.js";
|
|
30
30
|
/**
|
|
31
31
|
* An empty vector of bits.
|
|
32
32
|
*/
|
|
@@ -24,6 +24,18 @@ export type Cmp2<A, B> = [
|
|
|
24
24
|
B
|
|
25
25
|
] extends [bigint, bigint] ? bigint : never;
|
|
26
26
|
export declare const cmp: <A extends Cmp1>(a: A) => <B extends Cmp2<A, B>>(b: B) => Sign;
|
|
27
|
+
/**
|
|
28
|
+
* Returns the smaller of two comparable values. The `Cmp2<A, B>` constraint
|
|
29
|
+
* is the same one `cmp` uses: it rejects calls that mix incompatible primitive
|
|
30
|
+
* types (e.g. `min(1)("a")`) at compile time.
|
|
31
|
+
*/
|
|
32
|
+
export declare const min: <A extends Cmp1>(a: A) => <B extends Cmp2<A, B>>(b: B) => A | B;
|
|
33
|
+
/**
|
|
34
|
+
* Returns the larger of two comparable values. The `Cmp2<A, B>` constraint
|
|
35
|
+
* is the same one `cmp` uses: it rejects calls that mix incompatible primitive
|
|
36
|
+
* types (e.g. `max(1)("a")`) at compile time.
|
|
37
|
+
*/
|
|
38
|
+
export declare const max: <A extends Cmp1>(a: A) => <B extends Cmp2<A, B>>(b: B) => A | B;
|
|
27
39
|
/**
|
|
28
40
|
* Binary search over `[0, len)`. `probe(mid)` returns the sign of the search
|
|
29
41
|
* key relative to the element at `mid` (`-1` before, `0` at, `1` after). On a
|
|
@@ -4,6 +4,18 @@ export const index5 = cmp => ([v0, v1]) => {
|
|
|
4
4
|
return (_0 <= 0 ? _0 + 1 : cmp(v1) + 3);
|
|
5
5
|
};
|
|
6
6
|
export const cmp = (a) => (b) => a < b ? -1 : a > b ? 1 : 0;
|
|
7
|
+
/**
|
|
8
|
+
* Returns the smaller of two comparable values. The `Cmp2<A, B>` constraint
|
|
9
|
+
* is the same one `cmp` uses: it rejects calls that mix incompatible primitive
|
|
10
|
+
* types (e.g. `min(1)("a")`) at compile time.
|
|
11
|
+
*/
|
|
12
|
+
export const min = (a) => (b) => cmp(a)(b) < 0 ? a : b;
|
|
13
|
+
/**
|
|
14
|
+
* Returns the larger of two comparable values. The `Cmp2<A, B>` constraint
|
|
15
|
+
* is the same one `cmp` uses: it rejects calls that mix incompatible primitive
|
|
16
|
+
* types (e.g. `max(1)("a")`) at compile time.
|
|
17
|
+
*/
|
|
18
|
+
export const max = (a) => (b) => cmp(a)(b) > 0 ? a : b;
|
|
7
19
|
/**
|
|
8
20
|
* Binary search over `[0, len)`. `probe(mid)` returns the sign of the search
|
|
9
21
|
* key relative to the element at `mid` (`-1` before, `0` at, `1` after). On a
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cmp } from "./module.f.js";
|
|
1
|
+
import { cmp, min, max } from "./module.f.js";
|
|
2
2
|
export const proof = () => {
|
|
3
3
|
{
|
|
4
4
|
const result = cmp(true)(false);
|
|
@@ -37,4 +37,34 @@ export const proof = () => {
|
|
|
37
37
|
// const f = (a: string|number, b: string|number) => cmp(a)(b) // compilation error
|
|
38
38
|
// const f = (a: number, b: string|number) => cmp(a)(b) // compilation error
|
|
39
39
|
}
|
|
40
|
+
{
|
|
41
|
+
if (min(3)(5) !== 3) {
|
|
42
|
+
throw 'min(3)(5)';
|
|
43
|
+
}
|
|
44
|
+
if (min(7)(2) !== 2) {
|
|
45
|
+
throw 'min(7)(2)';
|
|
46
|
+
}
|
|
47
|
+
if (min(3n)(13n) !== 3n) {
|
|
48
|
+
throw 'min(3n)(13n)';
|
|
49
|
+
}
|
|
50
|
+
if (min("a")("b") !== "a") {
|
|
51
|
+
throw 'min("a")("b")';
|
|
52
|
+
}
|
|
53
|
+
// const _ = min(1)("a") // compilation error
|
|
54
|
+
}
|
|
55
|
+
{
|
|
56
|
+
if (max(3)(5) !== 5) {
|
|
57
|
+
throw 'max(3)(5)';
|
|
58
|
+
}
|
|
59
|
+
if (max(7)(2) !== 7) {
|
|
60
|
+
throw 'max(7)(2)';
|
|
61
|
+
}
|
|
62
|
+
if (max(3n)(13n) !== 13n) {
|
|
63
|
+
throw 'max(3n)(13n)';
|
|
64
|
+
}
|
|
65
|
+
if (max("a")("b") !== "b") {
|
|
66
|
+
throw 'max("a")("b")';
|
|
67
|
+
}
|
|
68
|
+
// const _ = max(1)("a") // compilation error
|
|
69
|
+
}
|
|
40
70
|
};
|
|
@@ -18,7 +18,5 @@ export declare const foldToScan: <I, O>(fold: Fold<I, O>) => (prior: O) => Scan<
|
|
|
18
18
|
export type Reduce<T> = Fold<T, T>;
|
|
19
19
|
export declare const reduceToScan: <T>(op: Reduce<T>) => Scan<T, T>;
|
|
20
20
|
export declare const addition: Reduce<number>;
|
|
21
|
-
export declare const min: Reduce<number>;
|
|
22
|
-
export declare const max: Reduce<number>;
|
|
23
21
|
export declare const increment: (b: number) => number;
|
|
24
22
|
export declare const counter: () => (b: number) => number;
|
|
@@ -12,7 +12,5 @@ export const foldToScan = (fold) => (prior) => i => {
|
|
|
12
12
|
};
|
|
13
13
|
export const reduceToScan = (op) => init => [init, foldToScan(op)(init)];
|
|
14
14
|
export const addition = a => b => a + b;
|
|
15
|
-
export const min = a => b => a < b ? a : b;
|
|
16
|
-
export const max = a => b => a > b ? a : b;
|
|
17
15
|
export const increment = addition(1);
|
|
18
16
|
export const counter = () => increment;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { join, concat, logicalNot, strictEqual, addition,
|
|
1
|
+
import { join, concat, logicalNot, strictEqual, addition, increment, foldToScan, reduceToScan, } from "./module.f.js";
|
|
2
2
|
const joinTest = () => {
|
|
3
3
|
const result = join(', ')('world')('hello');
|
|
4
4
|
if (result !== 'hello, world') {
|
|
@@ -33,22 +33,6 @@ const additionTest = () => {
|
|
|
33
33
|
throw result;
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
|
-
const minTest = () => {
|
|
37
|
-
if (min(3)(5) !== 3) {
|
|
38
|
-
throw 'min(3)(5)';
|
|
39
|
-
}
|
|
40
|
-
if (min(7)(2) !== 2) {
|
|
41
|
-
throw 'min(7)(2)';
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
const maxTest = () => {
|
|
45
|
-
if (max(3)(5) !== 5) {
|
|
46
|
-
throw 'max(3)(5)';
|
|
47
|
-
}
|
|
48
|
-
if (max(7)(2) !== 7) {
|
|
49
|
-
throw 'max(7)(2)';
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
36
|
const incrementTest = () => {
|
|
53
37
|
if (increment(4) !== 5) {
|
|
54
38
|
throw 'increment(4)';
|
|
@@ -79,4 +63,4 @@ const reduceToScanTest = () => {
|
|
|
79
63
|
throw v1;
|
|
80
64
|
}
|
|
81
65
|
};
|
|
82
|
-
export const proof = { joinTest, concatTest, logicalNotTest, strictEqualTest, additionTest,
|
|
66
|
+
export const proof = { joinTest, concatTest, logicalNotTest, strictEqualTest, additionTest, incrementTest, foldToScanTest, reduceToScanTest };
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
7
|
import { reduce } from "../list/module.f.js";
|
|
8
|
-
import { addition
|
|
9
|
-
import { cmp as uCmp } from "../function/compare/module.f.js";
|
|
8
|
+
import { addition } from "../function/operator/module.f.js";
|
|
9
|
+
import { cmp as uCmp, min as uMin, max as uMax } from "../function/compare/module.f.js";
|
|
10
10
|
export const sum = reduce(addition)(0);
|
|
11
|
-
export const min = reduce(
|
|
12
|
-
export const max = reduce(
|
|
11
|
+
export const min = reduce((uMin))(null);
|
|
12
|
+
export const max = reduce((uMax))(null);
|
|
13
13
|
export const cmp = uCmp;
|
|
14
14
|
const mo = [
|
|
15
15
|
[0x5555_5555, 1],
|