functionalscript 0.32.4 → 0.34.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.
Files changed (90) hide show
  1. package/README.md +1 -1
  2. package/fs/asserts/module.f.d.ts +1 -1
  3. package/fs/asserts/module.f.js +4 -1
  4. package/fs/bnf/data/module.f.d.ts +0 -103
  5. package/fs/bnf/data/module.f.js +10 -246
  6. package/fs/bnf/data/proof.f.d.ts +0 -7
  7. package/fs/bnf/data/proof.f.js +3 -636
  8. package/fs/bnf/descent/module.f.d.ts +56 -0
  9. package/fs/bnf/descent/module.f.js +119 -0
  10. package/fs/bnf/descent/proof.f.d.ts +5 -0
  11. package/fs/bnf/descent/proof.f.js +296 -0
  12. package/fs/bnf/ll1/module.f.d.ts +72 -0
  13. package/fs/bnf/ll1/module.f.js +153 -0
  14. package/fs/bnf/ll1/proof.f.d.ts +9 -0
  15. package/fs/bnf/ll1/proof.f.js +358 -0
  16. package/fs/cas/cli/module.f.d.ts +6 -0
  17. package/fs/cas/cli/module.f.js +56 -0
  18. package/fs/cas/cli/proof.f.d.ts +14 -0
  19. package/fs/cas/cli/proof.f.js +149 -0
  20. package/fs/cas/mcp/module.f.d.ts +9 -17
  21. package/fs/cas/mcp/module.f.js +117 -83
  22. package/fs/cas/mcp/proof.f.d.ts +5 -1
  23. package/fs/cas/mcp/proof.f.js +79 -32
  24. package/fs/cas/module.f.d.ts +33 -27
  25. package/fs/cas/module.f.js +151 -126
  26. package/fs/cas/proof.f.d.ts +16 -13
  27. package/fs/cas/proof.f.js +255 -130
  28. package/fs/ci/config/module.f.d.ts +15 -15
  29. package/fs/ci/config/module.f.js +15 -15
  30. package/fs/ci/proof.f.js +8 -6
  31. package/fs/cli/proof.f.js +2 -12
  32. package/fs/djs/parser/module.f.d.ts +0 -5
  33. package/fs/djs/proof.f.js +5 -6
  34. package/fs/djs/serializer/module.f.d.ts +1 -3
  35. package/fs/djs/tokenizer-new/module.f.js +3 -2
  36. package/fs/djs/tokenizer-new/proof.f.d.ts +3 -0
  37. package/fs/djs/tokenizer-new/proof.f.js +458 -296
  38. package/fs/djs/transpiler/proof.f.js +10 -10
  39. package/fs/effects/list/module.f.d.ts +31 -0
  40. package/fs/effects/list/module.f.js +16 -0
  41. package/fs/effects/module.f.d.ts +11 -5
  42. package/fs/effects/module.f.js +16 -6
  43. package/fs/effects/node/module.f.d.ts +29 -3
  44. package/fs/effects/node/module.f.js +35 -1
  45. package/fs/effects/node/module.js +32 -18
  46. package/fs/effects/node/proof.f.js +36 -36
  47. package/fs/effects/node/virtual/module.f.d.ts +16 -2
  48. package/fs/effects/node/virtual/module.f.js +129 -20
  49. package/fs/effects/node/virtual/proof.f.d.ts +4 -0
  50. package/fs/effects/node/virtual/proof.f.js +47 -14
  51. package/fs/effects/proof.f.d.ts +4 -0
  52. package/fs/effects/proof.f.js +18 -1
  53. package/fs/emergent_testing/proof.f.js +3 -11
  54. package/fs/fjs/module.f.js +2 -8
  55. package/fs/fjs/proof.f.js +2 -11
  56. package/fs/html/module.f.js +6 -8
  57. package/fs/js/tokenizer/module.f.d.ts +5 -0
  58. package/fs/js/tokenizer/module.f.js +13 -0
  59. package/fs/json/serializer/module.f.js +0 -1
  60. package/fs/mcp/module.f.d.ts +1 -1
  61. package/fs/mime/module.f.d.ts +101 -5
  62. package/fs/mime/module.f.js +159 -6
  63. package/fs/mime/proof.f.d.ts +25 -0
  64. package/fs/mime/proof.f.js +193 -3
  65. package/fs/text/code_point/module.f.d.ts +39 -2
  66. package/fs/text/code_point/module.f.js +74 -2
  67. package/fs/text/code_point/proof.f.d.ts +8 -0
  68. package/fs/text/code_point/proof.f.js +72 -0
  69. package/fs/text/sgr/proof.f.js +2 -11
  70. package/fs/text/utf16/module.f.js +4 -26
  71. package/fs/text/utf8/module.f.d.ts +27 -0
  72. package/fs/text/utf8/module.f.js +8 -14
  73. package/fs/types/bigint/module.f.d.ts +8 -15
  74. package/fs/types/bigint/module.f.js +9 -22
  75. package/fs/types/bigint/proof.f.d.ts +0 -2
  76. package/fs/types/bigint/proof.f.js +6 -16
  77. package/fs/types/function/operator/module.f.d.ts +26 -0
  78. package/fs/types/list/module.f.d.ts +3 -0
  79. package/fs/types/result/module.d.ts +2 -4
  80. package/fs/types/result/module.js +9 -3
  81. package/package.json +3 -3
  82. package/issues/demo/data/data.f.js +0 -12
  83. package/issues/demo/data/shared.f.js +0 -3
  84. package/issues/demo/fs/app.js +0 -4
  85. package/issues/demo/fs/math.f.js +0 -4
  86. package/issues/demo/sample/proof.f.js +0 -13
  87. /package/{issues → todo}/031-json.f.d.ts +0 -0
  88. /package/{issues → todo}/031-json.f.js +0 -0
  89. /package/{issues → todo}/proof.f.d.ts +0 -0
  90. /package/{issues → todo}/proof.f.js +0 -0
package/README.md CHANGED
@@ -11,7 +11,7 @@ FunctionalScript is a safe, purely functional programming language and a strict
11
11
  as a subset of JavaScript.
12
12
  - [TypeScript](https://en.wikipedia.org/wiki/TypeScript), as a superset of JavaScript.
13
13
 
14
- [A working draft of the FunctionalScript specification](./issues/lang/README.md).
14
+ [A working draft of the FunctionalScript specification](./todo/lang/README.md).
15
15
 
16
16
  Learn more about
17
17
 
@@ -1,4 +1,4 @@
1
1
  export declare const todo: () => never;
2
2
  export declare const assert: (v: boolean, msg?: unknown) => asserts v;
3
- export declare const assertEq: <T>(a: T, b: T) => void;
3
+ export declare const assertEq: <T>(...x: readonly [T, T, unknown?]) => void;
4
4
  export type Assert<T extends true> = T;
@@ -3,4 +3,7 @@ export const assert = (v, msg = 'assertion failed') => {
3
3
  if (!v)
4
4
  throw msg;
5
5
  };
6
- export const assertEq = (a, b) => assert(a === b, [a, b]);
6
+ export const assertEq = (...x) => {
7
+ const [a, b] = x;
8
+ assert(a === b, x);
9
+ };
@@ -1,11 +1,3 @@
1
- /**
2
- * Provides grammar-to-data conversion and LL(1) dispatch/matching types and helpers
3
- * for FunctionalScript BNF rules.
4
- *
5
- * @module
6
- */
7
- import { type CodePoint } from '../../text/utf16/module.f.ts';
8
- import { type RangeMapArray } from '../../types/range_map/module.f.ts';
9
1
  import { type Rule as FRule } from '../module.f.ts';
10
2
  import { type StringMap } from '../../types/object/module.f.ts';
11
3
  /**
@@ -31,103 +23,8 @@ export type Variant = StringMap<string, string>;
31
23
  export type Rule = Variant | Sequence | TerminalRange;
32
24
  /** The full grammar */
33
25
  export type RuleSet = Readonly<Record<string, Rule>>;
34
- type EmptyTag = string | true | undefined;
35
- type EmptyTagEntry = string | boolean;
36
- type DispatchRule = {
37
- readonly emptyTag: EmptyTag;
38
- readonly rangeMap: Dispatch;
39
- };
40
- type Dispatch = RangeMapArray<DispatchResult>;
41
- type DispatchResult = DispatchRuleCollection | null;
42
- type DispatchRuleOrName = DispatchRule | string;
43
- type DispatchRuleCollection = {
44
- readonly tag: string | undefined;
45
- readonly rules: DispatchRuleOrName[];
46
- };
47
- type DispatchMap = StringMap<string, DispatchRule>;
48
- type EmptyTagMap = StringMap<string, EmptyTagEntry>;
49
- /**
50
- * Recursive descent matcher for a single named rule.
51
- */
52
- export type DescentMatchRule<T> = (name: string, tag: AstTag, s: readonly CodePointMeta<T>[], idx: number) => DescentMatchResult<T>;
53
- /**
54
- * Result tuple of a descent match operation: AST node, success flag, and next index.
55
- */
56
- export type DescentMatchResult<T> = readonly [AstRuleMeta<T>, boolean, number];
57
- /**
58
- * Entry-point recursive descent matcher.
59
- */
60
- export type DescentMatch<T> = (name: string, s: readonly CodePointMeta<T>[]) => DescentMatchResult<T>;
61
- /**
62
- * Code point value paired with metadata.
63
- */
64
- export type CodePointMeta<T> = readonly [CodePoint, T];
65
- /**
66
- * AST sequence for the metadata-aware parser.
67
- */
68
- export type AstSequenceMeta<T> = readonly (AstRuleMeta<T> | CodePointMeta<T>)[];
69
- /**
70
- * Metadata-aware AST node.
71
- */
72
- export type AstRuleMeta<T> = {
73
- readonly tag: AstTag;
74
- readonly sequence: AstSequenceMeta<T>;
75
- };
76
- /**
77
- * Represents a parsed Abstract Syntax Tree (AST) sequence.
78
- */
79
- export type AstSequence = readonly (AstRule | CodePoint)[];
80
- export type AstTag = string | true | undefined;
81
- /**
82
- * Represents a parsed AST rule, consisting of a rule name and its parsed sequence.
83
- */
84
- type AstRule = {
85
- readonly tag: AstTag;
86
- readonly sequence: AstSequence;
87
- };
88
- /**
89
- * Represents the remaining input after a match attempt, or `null` if no match is possible.
90
- */
91
- export type Remainder = readonly CodePoint[] | null;
92
- /**
93
- * Parsing result of {@link parser} and {@link parserRuleSet}.
94
- *
95
- * Represents the result of a match operation, including the parsed AST rule and the remainder of the input.
96
- */
97
- export type MatchResult = readonly [AstRule, boolean, Remainder];
98
- /**
99
- * LL(1) parser function for matching by rule name.
100
- */
101
- export type Match = (name: string, s: readonly CodePoint[]) => MatchResult;
102
- /**
103
- * Internal match function signature used by compiled dispatch rules.
104
- */
105
- export type MatchRule = (dr: DispatchRule, s: readonly CodePoint[]) => MatchResult;
106
26
  /**
107
27
  * Converts a functional grammar rule into serializable BNF data and returns
108
28
  * the generated rule set with the entry rule identifier.
109
29
  */
110
30
  export declare const toData: (fr: FRule) => readonly [RuleSet, string];
111
- /**
112
- * Builds a dispatch map for a {@link RuleSet} to enable predictive parsing.
113
- */
114
- export declare const dispatchMap: (ruleSet: RuleSet) => DispatchMap;
115
- /**
116
- * Creates a map that describes whether each rule can consume empty input and,
117
- * for tagged variants, which tag represents the empty match.
118
- */
119
- export declare const createEmptyTagMap: (data: readonly [RuleSet, string]) => EmptyTagMap;
120
- /**
121
- * Creates a recursive descent parser that preserves metadata for each consumed
122
- * code point.
123
- */
124
- export declare const descentParser: <T>(fr: FRule) => DescentMatch<T>;
125
- /**
126
- * Creates an LL(1) parser from a functional grammar rule.
127
- */
128
- export declare const parser: (fr: FRule) => Match;
129
- /**
130
- * Creates an LL(1) parser from an already materialized {@link RuleSet}.
131
- */
132
- export declare const parserRuleSet: (ruleSet: RuleSet) => Match;
133
- export {};
@@ -1,17 +1,19 @@
1
1
  /**
2
- * Provides grammar-to-data conversion and LL(1) dispatch/matching types and helpers
3
- * for FunctionalScript BNF rules.
2
+ * The serializable BNF intermediate representation (IR) and the
3
+ * {@link toData} conversion from the functional grammar.
4
+ *
5
+ * This module is the pure, parser-agnostic substrate: it defines the
6
+ * {@link RuleSet} data form (`Rule = Variant | Sequence | TerminalRange`) and
7
+ * converts a functional grammar into it. The automaton builders that consume a
8
+ * {@link RuleSet} live in their own sibling modules (`fs/bnf/ll1`,
9
+ * `fs/bnf/descent`, …), so the IR stays free of any one parser's machinery.
4
10
  *
5
11
  * @module
6
12
  */
7
13
  import { stringToCodePointList } from "../../text/utf16/module.f.js";
8
- import { strictEqual } from "../../types/function/operator/module.f.js";
9
14
  import { map, toArray } from "../../types/list/module.f.js";
10
- import { rangeMap } from "../../types/range_map/module.f.js";
11
- import { contains, set } from "../../types/string_set/module.f.js";
12
- import { contains as rangeContains } from "../../types/range/module.f.js";
13
- import { oneEncode, rangeDecode, } from "../module.f.js";
14
- import { definedEntries } from "../../types/object/module.f.js";
15
+ import { oneEncode, } from "../module.f.js";
16
+ import {} from "../../types/object/module.f.js";
15
17
  const { entries } = Object;
16
18
  const find = (map) => (fr) => {
17
19
  for (const [k, v] of entries(map)) {
@@ -89,241 +91,3 @@ export const toData = (fr) => {
89
91
  const [, ruleSet, id] = toDataAdd({})(fr);
90
92
  return [ruleSet, id];
91
93
  };
92
- const dispatchOp = rangeMap({
93
- union: a => b => {
94
- if (a === null) {
95
- return b;
96
- }
97
- if (b === null) {
98
- return a;
99
- }
100
- throw ['can not merge [', a, '][', b, ']'];
101
- },
102
- equal: strictEqual,
103
- def: null,
104
- });
105
- /**
106
- * Builds a dispatch map for a {@link RuleSet} to enable predictive parsing.
107
- */
108
- export const dispatchMap = (ruleSet) => {
109
- const addRuleToDispatch = (dr, name) => {
110
- if (dr === null)
111
- return null;
112
- return { tag: dr.tag, rules: [...dr.rules, name] };
113
- };
114
- const addTagToDispatch = (dr, tag) => {
115
- if (dr === null)
116
- return null;
117
- return { tag, rules: dr.rules };
118
- };
119
- const dispatchRule = (dm, name, current) => {
120
- if (name in dm) {
121
- return dm;
122
- }
123
- const newCurrent = set(name)(current);
124
- const rule = ruleSet[name];
125
- if (typeof rule === 'number') {
126
- const range = rangeDecode(rule);
127
- const dispatch = dispatchOp.fromRange(range)({ tag: undefined, rules: [] });
128
- const dr = { emptyTag: undefined, rangeMap: dispatch };
129
- return { ...dm, [name]: dr };
130
- }
131
- else if (rule instanceof Array) {
132
- let emptyTag = true;
133
- let result = [];
134
- for (const item of rule) {
135
- if (contains(item)(newCurrent)) {
136
- result = result.map(x => [addRuleToDispatch(x[0], item), x[1]]);
137
- }
138
- else {
139
- dm = dispatchRule(dm, item, newCurrent);
140
- const dr = dm[item];
141
- if (emptyTag === true) {
142
- result = result.map(x => [addRuleToDispatch(x[0], item), x[1]]);
143
- result = toArray(dispatchOp.merge(result)(dr.rangeMap));
144
- emptyTag = dr.emptyTag !== undefined ? true : undefined;
145
- }
146
- else {
147
- result = result.map(x => [addRuleToDispatch(x[0], item), x[1]]);
148
- }
149
- }
150
- }
151
- const dr = { emptyTag, rangeMap: result };
152
- return { ...dm, [name]: dr };
153
- }
154
- else {
155
- const entries = definedEntries(rule);
156
- let result = [];
157
- let emptyTag = undefined;
158
- for (const [tag, item] of entries) {
159
- dm = dispatchRule(dm, item, newCurrent);
160
- const dr = dm[item];
161
- if (dr.emptyTag !== undefined) {
162
- emptyTag = tag;
163
- }
164
- else {
165
- const d = dr.rangeMap.map(x => [addTagToDispatch(x[0], tag), x[1]]);
166
- result = toArray(dispatchOp.merge(result)(d));
167
- }
168
- }
169
- const dr = { emptyTag, rangeMap: result };
170
- return { ...dm, [name]: dr };
171
- }
172
- };
173
- let result = {};
174
- for (const k in ruleSet) {
175
- result = dispatchRule(result, k, null);
176
- }
177
- return result;
178
- };
179
- const emptyTagMapAdd = (ruleSet) => (map) => (name) => {
180
- if (name in map) {
181
- return [ruleSet, map, map[name]];
182
- }
183
- const rule = ruleSet[name];
184
- if (typeof rule === 'number') {
185
- return [ruleSet, { ...map, [name]: false }, false];
186
- }
187
- else if (rule instanceof Array) {
188
- map = { ...map, [name]: true };
189
- let emptyTag = rule.length == 0;
190
- for (const item of rule) {
191
- const [, newMap, itemEmptyTag] = emptyTagMapAdd(ruleSet)(map)(item);
192
- map = newMap;
193
- if (emptyTag === false) {
194
- emptyTag = itemEmptyTag !== false;
195
- }
196
- }
197
- return [ruleSet, { ...map, [name]: emptyTag }, emptyTag];
198
- }
199
- else {
200
- map = { ...map, [name]: true };
201
- const entries = definedEntries(rule);
202
- let emptyTag = false;
203
- for (const [tag, item] of entries) {
204
- const [, newMap, itemEmptyTag] = emptyTagMapAdd(ruleSet)(map)(item);
205
- map = newMap;
206
- if (itemEmptyTag !== false) {
207
- emptyTag = tag;
208
- }
209
- }
210
- return [ruleSet, { ...map, [name]: emptyTag }, emptyTag];
211
- }
212
- };
213
- /**
214
- * Creates a map that describes whether each rule can consume empty input and,
215
- * for tagged variants, which tag represents the empty match.
216
- */
217
- export const createEmptyTagMap = (data) => {
218
- return emptyTagMapAdd(data[0])({})(data[1])[1];
219
- };
220
- /**
221
- * Creates a recursive descent parser that preserves metadata for each consumed
222
- * code point.
223
- */
224
- export const descentParser = (fr) => {
225
- const data = toData(fr);
226
- const emptyTagMap = createEmptyTagMap(data);
227
- const getEmptyTag = (name) => {
228
- const res = emptyTagMap[name];
229
- return res === false ? undefined : res;
230
- };
231
- const f = (name, tag, cp, idx) => {
232
- const mrSuccess = (tag, sequence, idx) => [{ tag, sequence }, true, idx];
233
- const mrFail = (tag, sequence, idx) => [{ tag, sequence }, false, idx];
234
- const rule = data[0][name];
235
- if (typeof rule === 'number') {
236
- const emptyTag = getEmptyTag(name);
237
- if (idx >= cp.length) {
238
- return emptyTag === undefined ? mrFail(emptyTag, [], idx) : mrSuccess(emptyTag, [], idx);
239
- }
240
- const cpi = cp[idx];
241
- const range = rangeDecode(rule);
242
- if (rangeContains(range)(cpi[0])) {
243
- return mrSuccess(tag, [cpi], idx + 1);
244
- }
245
- return mrFail(emptyTag, [], idx);
246
- }
247
- else if (rule instanceof Array) {
248
- let seq = [];
249
- let tidx = idx;
250
- for (const item of rule) {
251
- const m = f(item, undefined, cp, tidx);
252
- const [astRule, success, nidx] = m;
253
- tidx = nidx;
254
- if (success === false) {
255
- return mrFail(tag, [], idx);
256
- }
257
- seq = [...seq, astRule];
258
- }
259
- return mrSuccess(tag, seq, tidx);
260
- }
261
- else {
262
- const entries = definedEntries(rule);
263
- const emptyTag = getEmptyTag(name);
264
- let emptyResult = mrFail(emptyTag, [], idx);
265
- for (const [tag, item] of entries) {
266
- const m = f(item, tag, cp, idx);
267
- if (m[1]) {
268
- if (idx !== m[2])
269
- return m;
270
- emptyResult = m;
271
- }
272
- }
273
- return emptyResult;
274
- }
275
- };
276
- const match = (name, cp) => {
277
- return f(name, undefined, cp, 0);
278
- };
279
- return match;
280
- };
281
- /**
282
- * Creates an LL(1) parser from a functional grammar rule.
283
- */
284
- export const parser = (fr) => {
285
- const data = toData(fr);
286
- return parserRuleSet(data[0]);
287
- };
288
- /**
289
- * Creates an LL(1) parser from an already materialized {@link RuleSet}.
290
- */
291
- export const parserRuleSet = (ruleSet) => {
292
- const map = dispatchMap(ruleSet);
293
- const f = (rule, cp) => {
294
- const mrSuccess = (tag, sequence, r) => [{ tag, sequence }, true, r];
295
- const mrFail = (tag, sequence, r) => [{ tag, sequence }, false, r];
296
- const { emptyTag, rangeMap } = rule;
297
- if (cp.length === 0) {
298
- return mrSuccess(emptyTag, [], emptyTag === undefined ? null : cp);
299
- }
300
- const cp0 = cp[0];
301
- const dr = dispatchOp.get(cp0)(rangeMap);
302
- if (dr === null) {
303
- if (emptyTag === undefined) {
304
- return mrFail(emptyTag, [], cp);
305
- }
306
- return mrSuccess(emptyTag, [], cp);
307
- }
308
- let seq = [cp0];
309
- let r = cp;
310
- const [_, ...restCp] = cp;
311
- r = restCp;
312
- const { tag, rules } = dr;
313
- for (const i of rules) {
314
- const rule = typeof i === 'string' ? map[i] : i;
315
- const res = f(rule, r);
316
- const [astRule, success, newR] = res;
317
- if (success === false) {
318
- return res;
319
- }
320
- seq = [...seq, astRule];
321
- if (newR === null) {
322
- return mrSuccess(tag, seq, null);
323
- }
324
- r = newR;
325
- }
326
- return mrSuccess(tag, seq, r);
327
- };
328
- return (name, cp) => f(map[name], cp);
329
- };
@@ -2,13 +2,6 @@ export declare const proof: {
2
2
  rangeDecode: () => void;
3
3
  rangeEncode: () => void;
4
4
  toData: (() => void)[];
5
- emptyTags: (() => void)[];
6
5
  variantTest: () => void;
7
- dispatch: (() => void)[];
8
- parser: (() => void)[];
9
- descentParser: (() => void)[];
10
- descentParserWithMeta: (() => void)[];
11
- repeat: (() => void)[];
12
- repeatParser: (() => void)[];
13
6
  example: () => void;
14
7
  };