@fraczak/k 5.1.1 → 6.0.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 (99) hide show
  1. package/Code-derivation-tests/blowup.mjs +3 -3
  2. package/Code-derivation-tests/bnat.mjs +2 -2
  3. package/Code-derivation-tests/codec-witness-pattern.mjs +50 -0
  4. package/Code-derivation-tests/convergence-strategy.mjs +24 -0
  5. package/Code-derivation-tests/dot.mjs +12 -9
  6. package/Code-derivation-tests/filter-syntax.mjs +21 -0
  7. package/Code-derivation-tests/loop.mjs +8 -2
  8. package/Code-derivation-tests/nat.mjs +1 -1
  9. package/Code-derivation-tests/not-not.mjs +3 -3
  10. package/Code-derivation-tests/pattern-envelope.mjs +68 -0
  11. package/Code-derivation-tests/rlz.mjs +2 -2
  12. package/{BIG_PICTURE.md → DOCS/BIG_PICTURE.md} +103 -50
  13. package/DOCS/REPL.md +191 -0
  14. package/DOCS/book/01-introduction.md +51 -0
  15. package/DOCS/book/02-syntax-and-values.md +111 -0
  16. package/DOCS/book/03-types-as-finite-automata.md +156 -0
  17. package/DOCS/book/04-partial-functions-and-composition.md +146 -0
  18. package/DOCS/book/05-typing-filters-and-normalization.md +111 -0
  19. package/DOCS/book.md +54 -0
  20. package/README.md +204 -508
  21. package/TypeGraph.mjs +43 -0
  22. package/TypePatternGraph.mjs +251 -0
  23. package/Value.mjs +192 -0
  24. package/augmentation.mjs +198 -0
  25. package/codecs/BINARY_FORMAT.md +53 -0
  26. package/codecs/POLYMORPHIC_BINARY_FORMAT.md +303 -0
  27. package/codecs/README.md +215 -0
  28. package/codecs/example-pipeline.mjs +149 -0
  29. package/codecs/ieee.mjs +140 -0
  30. package/codecs/int.mjs +104 -0
  31. package/codecs/json-codec.mjs +215 -0
  32. package/codecs/json.mjs +40 -0
  33. package/codecs/k-parse.mjs +90 -0
  34. package/codecs/k-pattern.mjs +75 -0
  35. package/codecs/k-print.mjs +46 -0
  36. package/codecs/runtime/codec.mjs +768 -0
  37. package/codecs/runtime/ieee-pattern.mjs +30 -0
  38. package/codecs/runtime/pattern-json.mjs +96 -0
  39. package/codecs/runtime/prefix-codec.mjs +425 -0
  40. package/codecs/runtime/show-value.mjs +68 -0
  41. package/codecs/runtime/typeFromValue.mjs +34 -0
  42. package/codecs/runtime/unicode-string.mjs +220 -0
  43. package/codecs/show.mjs +41 -0
  44. package/codecs/string-codec.mjs +80 -0
  45. package/codecs/unit.mjs +51 -0
  46. package/codecs/utf16.mjs +66 -0
  47. package/codecs/utf8.mjs +37 -0
  48. package/codes.mjs +146 -44
  49. package/compiler.mjs +111 -0
  50. package/convergence.mjs +197 -0
  51. package/core.k +197 -0
  52. package/export.mjs +22 -32
  53. package/hash.mjs +29 -31
  54. package/index.mjs +41 -15
  55. package/k-vscode/.vscode/launch.json +14 -0
  56. package/k-vscode/README.md +65 -0
  57. package/k-vscode/language-configuration.json +42 -0
  58. package/k-vscode/package.json +57 -0
  59. package/k-vscode/snippets/k.json +92 -0
  60. package/k-vscode/syntaxes/k.tmLanguage.json +243 -0
  61. package/k.mjs +56 -54
  62. package/object.mjs +517 -0
  63. package/objects/README.md +38 -0
  64. package/objects/compile-lib.mjs +42 -0
  65. package/objects/compile.mjs +42 -0
  66. package/objects/decompile.mjs +32 -0
  67. package/package.json +18 -8
  68. package/parser.jison +27 -46
  69. package/parser.mjs +68 -100
  70. package/pretty.mjs +21 -40
  71. package/repl2.mjs +652 -0
  72. package/run.mjs +264 -231
  73. package/symbol-table.mjs +3 -17
  74. package/test-fingerprint.mjs +7 -7
  75. package/test-hash-fuzz.mjs +107 -0
  76. package/test-hash-normalization.mjs +134 -0
  77. package/test-k-object.mjs +74 -0
  78. package/test-repl2.mjs +95 -0
  79. package/test.mjs +45 -70
  80. package/tests.sh +10 -1
  81. package/typing.mjs +129 -676
  82. package/unification.mjs +157 -0
  83. package/valueIO.mjs +54 -0
  84. package/valueParser.jison +143 -0
  85. package/valueParser.mjs +713 -0
  86. package/Code-derivation-tests/built-in.mjs +0 -19
  87. package/Code-derivation-tests/vector.mjs +0 -19
  88. package/Filters/bug.k +0 -3
  89. package/Filters/composing.k +0 -15
  90. package/Filters/filter.k +0 -9
  91. package/TODO.md +0 -53
  92. package/TYPING.md +0 -365
  93. package/k-repl.cast +0 -1913
  94. package/k.cast +0 -618
  95. package/my-objects.json +0 -6
  96. package/patterns.mjs +0 -543
  97. package/repl.mjs +0 -213
  98. package/test-filters.mjs +0 -45
  99. package/typing-test.mjs +0 -40
package/typing.mjs CHANGED
@@ -1,706 +1,159 @@
1
- import { Graph } from "./Graph.mjs";
2
- import codes from "./codes.mjs";
3
-
4
- const unitCode = codes.unitCode;
1
+ import { TypePatternGraph } from "./TypePatternGraph.mjs";
5
2
 
6
3
  function asSet(vector) {
7
4
  return Array.from(new Set(vector));
8
- };
9
-
10
- function setUnion(...vectors) {
11
- const unionSet = new Set();
12
- for (const v of vectors) {
13
- for (const element of v) {
14
- unionSet.add(element);
15
- }
16
- }
17
- return Array.from(unionSet);
18
- }
19
-
20
- function subsetP(v1,v2) {
21
- const v2Set = new Set(v2);
22
- return v1.every(x => v2Set.has(x));
23
- }
24
-
25
- function eqsetP(v1,v2) {
26
- const v1Set = new Set(v1);
27
- const v2Set = new Set(v2);
28
- if (v1Set.size != v2Set.size) return false;
29
-
30
- for (const value of v1Set) {
31
- if (!v2Set.has(value)) {
32
- return false;
33
- }
34
- }
35
- return true;
36
- }
37
-
38
- const matchAllPattern = {pattern: '(...)', fields: []};
39
- /*
40
- $Pattern = <
41
- string code,
42
- open? product,
43
- open? union,
44
- {} vector,
45
- open? unknown
46
- >;
47
- $open? = < {} open, {} closed >;
48
-
49
- we use the string notation:
50
- '(...)' | '{...}' | '<...>' | '()' | '[]' | '{}' | '<>' | 'type'
51
- e.g.:
52
- {pattern: '()'},
53
- {pattern: '<...>'}
54
- {pattern: 'type', type: code_name}
55
- */
56
-
57
- class TypePatternForest {
58
- constructor() {
59
- this.nodes = [];
60
- this.parent = [];
61
- }
62
-
63
- // Find the root of the set containing `x`
64
- find(x) {
65
- if (this.nodes[x] == undefined)
66
- throw new Error(`Node of id='${x}' not found in the forest`);
67
- let result = x;
68
- let parent = this.parent[result];
69
- while (parent != undefined) {
70
- parent = this.parent[result = parent];
71
- if (parent == result) {
72
- console.log("Can happen a loop in the forest? It shouldn't!");
73
- break;
74
- }
75
-
76
- }
77
- return result;
78
- }
79
-
80
- addChildren(parentId, childrenIds) {
81
- const parent = this.find(parentId);
82
- childrenIds.forEach(childId => {
83
- const child = this.find(childId);
84
- if (this.nodes[child].pattern != 'type')
85
- this.parent[child] = parent;
86
- });
87
- }
88
-
89
- addNewNode(flatTypePattern, children = []) {
90
- const that = this;
91
- const id = this.nodes.length;
92
- // const node = {...flatTypePattern, _id: id};
93
- const node = {...flatTypePattern}
94
- that.nodes.push(node);
95
- Array.from(new Set(children.map(that.find.bind(that))))
96
- .forEach(rep => {that.parent[rep] = id});
97
- return id;
98
- }
99
5
  }
100
6
 
101
- class TypePatternGraph {
102
- constructor() {
103
- this.patterns = new TypePatternForest();
104
- this.edges = []; // an edge at index i is a map {lab: asMapSet([i1,...]), ...}
105
- // representing `patterns.node[i] --[lab]--> {i1:i1,...}, ...
106
- this.codeId = { }; // type-name -> index
107
- }
108
-
109
- turnSingletonPatternsIntoCodes() {
110
- const singletonPatterns = this.findSingletonPatterns();
111
- const newCodeDefs= {}
112
- for(const patternId of singletonPatterns) {
113
- const pattern = this.get_pattern(patternId);
114
- switch (pattern.pattern) {
115
- case '<>':
116
- case '{}': {
117
- const code = (pattern.pattern == '<>') ? 'union' : 'product';
118
- const fieldsWithDest = this.edges[patternId];
119
- newCodeDefs[`-${patternId}-`] = {
120
- code: code,
121
- [code]: Object.keys(fieldsWithDest).reduce((fields, lab) => {
122
- const auxDests = Object.values(fieldsWithDest[lab]).map(id => this.find(id));
123
- const destAsMapSet = auxDests.reduce( (mapSet, x) => ({...mapSet, [JSON.stringify(x)]: x}), {});
124
- const dests = Object.values(destAsMapSet);
125
- if (dests.length != 1) {
126
- throw new Error(`Expected one destination for ${lab} in ${patternId}`);
127
- }
128
- const destPattern = this.get_pattern(dests[0]);
129
- fields[lab] = (destPattern.pattern == 'type') ? destPattern.type : `-${dests[0]}-`;
130
- return fields;
131
- }, {})
132
- };
133
- }; break;
134
- case '[]': {
135
- const auxDests = Object.values(this.edges[patternId]["vector-member"]).map(id => this.find(id));
136
- const destAsMapSet = auxDests.reduce( (mapSet, x) => ({...mapSet, [JSON.stringify(x)]: x}), {});
137
- const dests = Object.values(destAsMapSet);
138
- if (dests.length != 1) {
139
- // console.log(dests.map(d => this.get_pattern(d)));
140
- throw new Error(`Expected one destination 'vector-member' in ${JSON.stringify(pattern)}, but got ${JSON.stringify(dests)}`);
141
- }
142
- const destPattern = this.get_pattern(dests[0]);
143
- newCodeDefs[`-${patternId}-`] = {
144
- code: 'vector',
145
- vector: (destPattern.pattern == 'type') ? destPattern.type : `-${dests[0]}-`
146
- };
147
- }; break;
148
- default:
149
- throw new Error(`Unexpected pattern ${JSON.stringify(pattern)}`);
7
+ function getCompressed(typePatternGraph) {
8
+ const newTypePatternGraph = new TypePatternGraph(typePatternGraph.registerCodeDef, typePatternGraph.findCode);
9
+
10
+ const rootPatternIds = typePatternGraph.patterns.nodes
11
+ .map((x, i) => i)
12
+ .filter((i) => typePatternGraph.find(i) == i);
13
+
14
+ const renamedRoots = {};
15
+ for (const oldId of rootPatternIds) {
16
+ const pattern = typePatternGraph.get_pattern(oldId);
17
+ renamedRoots[oldId] = (pattern.pattern == "type")
18
+ ? newTypePatternGraph.getTypeId(pattern.type)
19
+ : newTypePatternGraph.patterns.addNewNode(pattern);
20
+ }
21
+
22
+ for (const oldId of rootPatternIds) {
23
+ const newId = renamedRoots[oldId];
24
+ const pattern = typePatternGraph.get_pattern(oldId);
25
+ if (pattern.pattern == "type") {
26
+ continue;
27
+ }
28
+ const edges = typePatternGraph.edges[oldId];
29
+ newTypePatternGraph.edges[newId] = {};
30
+ for (const lab in edges) {
31
+ const mapped = [];
32
+ const seen = new Set();
33
+ for (const dst of edges[lab]) {
34
+ const mappedId = renamedRoots[typePatternGraph.find(dst)];
35
+ if (!seen.has(mappedId)) {
36
+ seen.add(mappedId);
37
+ mapped.push(mappedId);
38
+ }
150
39
  }
151
- }
152
- // - add them all to 'codes'
153
- const representatives = codes.register(newCodeDefs);
154
-
155
- for( const id of singletonPatterns) {
156
- this.unify('singleton', id, this.getTypeId(representatives[`-${id}-`]));
40
+ newTypePatternGraph.edges[newId][lab] = mapped;
157
41
  }
158
42
  }
159
43
 
160
-
161
- get_pattern(id) {
162
- return this.patterns.nodes[this.find(id)];
44
+ const renamed = {};
45
+ for (let id = 0; id < typePatternGraph.patterns.nodes.length; id++) {
46
+ renamed[id] = renamedRoots[typePatternGraph.find(id)];
163
47
  }
164
48
 
165
- find(id) {
166
- return this.patterns.find(id);
167
- }
168
-
169
- findSingletonPatterns() {
170
- const gNodes = this.patterns.nodes.map((x,i) => i).filter(x => this.patterns.parent[x] == undefined);
171
- const gEdges = [].concat(
172
- ...gNodes.map(x =>
173
- [].concat(
174
- ...Object.values(this.edges[x]).map( asMap =>
175
- [].concat(...Object.values(asMap).map(y =>
176
- ({src: x, dst: this.find(y)}))
177
- )
178
- )
179
- )
180
- )
181
- );
182
-
183
- const gEdgesWithoutParrallelEdges = Array.from(new Set(gEdges));
184
- const gGraph = new Graph(gEdgesWithoutParrallelEdges);
185
- const queue = gNodes.filter(x =>
186
- this.patterns.nodes[x].pattern in {'()':1, '(...)':1,'{...}':1, '<...>':1});
187
- const excludedSet = new Set(queue);
49
+ newTypePatternGraph.turnSingletonPatternsIntoCodes();
188
50
 
189
- while (queue.length > 0) {
190
- const x = queue.pop();
191
- for (const e of gGraph.dst[x] || []) {
192
- const y = gGraph.edges[e].src;
193
- if (excludedSet.has(y)) continue;
194
- excludedSet.add(y);
195
- queue.push(y);
196
- }
197
- }
198
-
199
- return gNodes.filter(x => !((excludedSet.has(x)) || (this.patterns.nodes[x].pattern == 'type')));
51
+ for (const id in renamed) {
52
+ renamed[id] = newTypePatternGraph.find(renamed[id]);
200
53
  }
201
54
 
202
- getCompressed() {
203
- const newTypePatternGraph = new TypePatternGraph();
204
- const renamed = this.cloneAll(newTypePatternGraph);
205
-
206
- newTypePatternGraph.turnSingletonPatternsIntoCodes();
207
-
208
- Object.keys(renamed).forEach( id => {
209
- renamed[id] = newTypePatternGraph.find(renamed[id]);
210
- });
211
-
212
- // console.log("newTypePatternGraph", newTypePatternGraph);
213
- // console.log("nodes", newTypePatternGraph.patterns.nodes);
214
- // console.log("edges", newTypePatternGraph.edges);
215
-
216
- const rootPatternIds = newTypePatternGraph.patterns.nodes.map((x,i) => i)
217
- .filter(x => newTypePatternGraph.find(x) == x);
218
-
219
- // console.log("rootPatternIds", rootPatternIds);
220
-
221
- const equivalence = rootPatternIds.reduce( (equivalence,i) => {
222
- const pattern = newTypePatternGraph.get_pattern(i);
223
- switch (pattern.pattern) {
224
- case 'type':
225
- case '(...)':
226
- case '{...}':
227
- case '<...>':
228
- equivalence.push([i]);
229
- break;
230
- default:
231
- equivalence[0].push(i);
232
- };
233
- return equivalence;
234
- }, [[]]).filter(x => x.length > 0);
235
-
236
- const reps = equivalence.reduce( (reps,eqClass) => {
237
- eqClass.forEach( x => reps[x] = eqClass);
238
- return reps;
239
- }, {});
240
-
241
- // console.log("equivalence", equivalence);
55
+ const compressedRootPatternIds = newTypePatternGraph.patterns.nodes.map((x,i) => i)
56
+ .filter(x => newTypePatternGraph.find(x) == x);
242
57
 
243
- let count = 0;
244
- const areDifferent = (i1,i2) => {
245
- count++;
246
- const p1 = newTypePatternGraph.get_pattern(i1);
247
- const p2 = newTypePatternGraph.get_pattern(i2);
248
- if (p1.pattern != p2.pattern) return true;
249
- const e1 = newTypePatternGraph.edges[i1];
250
- const e2 = newTypePatternGraph.edges[i2];
251
- if (Object.keys(e1).length != Object.keys(e2).length) return true;
252
- for (const lab in e1) {
253
- if (e2[lab] == undefined) return true;
254
- const dests1 = Object.values(e1[lab])[0];
255
- const dests2 = Object.values(e2[lab])[0];
256
- if (reps[dests1] != reps[dests2]) return true;
58
+ const equivalence = compressedRootPatternIds.reduce( (equivalence,i) => {
59
+ const pattern = newTypePatternGraph.get_pattern(i);
60
+ switch (pattern.pattern) {
61
+ case 'type':
62
+ case '(...)':
63
+ case '{...}':
64
+ case '<...>':
65
+ equivalence.push([i]);
66
+ break;
67
+ default:
68
+ equivalence[0].push(i);
69
+ };
70
+ return equivalence;
71
+ }, [[]]).filter(x => x.length > 0);
72
+
73
+ const reps = equivalence.reduce( (reps,eqClass) => {
74
+ eqClass.forEach( x => reps[x] = eqClass);
75
+ return reps;
76
+ }, {});
77
+
78
+ let count = 0;
79
+ const areDifferent = (i1,i2) => {
80
+ count++;
81
+ const p1 = newTypePatternGraph.get_pattern(i1);
82
+ const p2 = newTypePatternGraph.get_pattern(i2);
83
+ if (p1.pattern != p2.pattern) return true;
84
+ const e1 = newTypePatternGraph.edges[i1];
85
+ const e2 = newTypePatternGraph.edges[i2];
86
+ if (Object.keys(e1).length != Object.keys(e2).length) return true;
87
+ for (const lab in e1) {
88
+ if (e2[lab] == undefined) return true;
89
+ const dests1 = Object.values(e1[lab])[0];
90
+ const dests2 = Object.values(e2[lab])[0];
91
+ if (reps[dests1] != reps[dests2]) return true;
92
+ }
93
+ return false;
94
+ }
95
+ let changed = true;
96
+ let count2 = 0;
97
+ while (changed) {
98
+ count2++;
99
+ changed = false;
100
+ const equivalenceSize = equivalence.length;
101
+ for (let eqClassPos = 0; eqClassPos < equivalenceSize; eqClassPos++) {
102
+ const eqClass = equivalence[eqClassPos];
103
+ const oldClass = [eqClass[0]];
104
+ const newClass = [];
105
+ for (let i = 1; i < eqClass.length; i++) {
106
+ if (areDifferent(oldClass[0],eqClass[i])) {
107
+ newClass.push(eqClass[i]);
108
+ } else {
109
+ oldClass.push(eqClass[i]);
110
+ }
257
111
  }
258
- return false;
259
- }
260
- let changed = true;
261
- let count2 = 0;
262
- while (changed) {
263
- count2++;
264
- changed = false;
265
- const equivalenceSize = equivalence.length;
266
- for (let eqClassPos = 0; eqClassPos < equivalenceSize; eqClassPos++) {
267
- const eqClass = equivalence[eqClassPos];
268
- const oldClass = [eqClass[0]];
269
- const newClass = [];
270
- for (let i = 1; i < eqClass.length; i++) {
271
- if (areDifferent(oldClass[0],eqClass[i])) {
272
- newClass.push(eqClass[i]);
273
- } else {
274
- oldClass.push(eqClass[i]);
275
- }
112
+ if (newClass.length > 0) {
113
+ changed = true;
114
+ equivalence.push(newClass);
115
+ equivalence[eqClassPos] = oldClass;
116
+ for (const i of newClass) {
117
+ reps[i] = newClass;
276
118
  }
277
- if (newClass.length > 0) {
278
- changed = true;
279
- equivalence.push(newClass);
280
- equivalence[eqClassPos] = oldClass;
281
- for (const i of newClass) {
282
- reps[i] = newClass;
283
- }
284
- for (const i of oldClass) {
285
- reps[i] = oldClass;
286
- }
119
+ for (const i of oldClass) {
120
+ reps[i] = oldClass;
287
121
  }
288
122
  }
289
123
  }
290
-
291
- // console.log("equivalence (final)", equivalence);
292
- // console.log("reps", reps);
293
-
294
- const compressedTypePatternGraph = new TypePatternGraph();
295
- const newIds = {};
296
- for (const eqClass of equivalence) {
297
- // console.log("eqClass", eqClass);
298
- const oldId = eqClass[0];
299
- const pattern = newTypePatternGraph.get_pattern(oldId);
300
- const newId = (() => {
301
- if (pattern.pattern == 'type') return compressedTypePatternGraph.getTypeId(pattern.type);
302
- return compressedTypePatternGraph.patterns.addNewNode(pattern);
303
- })();
304
- newIds[oldId] = newId;
305
- }
306
- for (const oldId in newIds) {
307
- const newId = newIds[oldId];
308
- const pattern = newTypePatternGraph.get_pattern(oldId);
309
- // const newPattern = compressedTypePatternGraph.get_pattern(newId);
310
- // console.log("patterns", pattern, newPattern);
311
- if (pattern.pattern == 'type')
312
- continue;
313
- const edges = newTypePatternGraph.edges[oldId];
314
- // console.log("edges", edges);
315
- compressedTypePatternGraph.edges[newId] = {};
316
- for (const lab in edges) {
317
- // console.log("edges[lab]", edges[lab]);
318
- compressedTypePatternGraph.edges[newId][lab] = asSet(edges[lab].map(x =>
319
- newIds[reps[newTypePatternGraph.find(x)][0]]));
320
- }
321
- }
322
-
323
- const remapping = Object.keys(renamed).reduce( (remapping,id) => {
324
- return {...remapping, [id]: newIds[ reps[renamed[id]][0] ]};
325
- }, {});
326
-
327
- // console.log("remapping", remapping);
328
- // console.log("compressedTypePatternGraph", compressedTypePatternGraph);
329
- // console.log("nodes", compressedTypePatternGraph.patterns.nodes);
330
- // console.log("edges", compressedTypePatternGraph.edges);
331
- // console.log("--------------------")
332
-
333
- return {typePatternGraph: compressedTypePatternGraph, remapping};
334
- }
335
-
336
- clone(roots,targetGraph = this) {
337
- const result = {}; // mapping from original ids to cloned ids
338
- const find = (x) => this.find(x);
339
- let ids = [...roots];
340
- while (ids.length > 0) {
341
- const old_id = ids.pop();
342
- const i = find(old_id);
343
- if (i in result) {
344
- result[old_id] = result[i];
345
- continue;
346
- }
347
- const cloned = (pattern => {
348
- if (pattern.pattern == 'type') return targetGraph.getTypeId(pattern.type);
349
- return targetGraph.patterns.addNewNode(pattern);
350
- })(this.patterns.nodes[i]);
351
- result[i] = cloned;
352
- result[old_id] = cloned;
353
- if (this.patterns.nodes[i].pattern == 'type')
354
- continue;
355
- const edges = this.edges[i];
356
- for (const lab in edges) {
357
- ids = ids.concat(Object.values(edges[lab]));
358
- }
359
- }
360
- for (const i in result) {
361
- if (i != find(i)) continue;
362
- if (this.patterns.nodes[i].pattern == 'type')
363
- continue;
364
- const edges = this.edges[i];
365
- const new_id = result[i];
366
- targetGraph.edges[new_id] = {};
367
- for (const lab in edges) {
368
- targetGraph.edges[new_id][lab] = asSet(edges[lab].map(x => result[find(x)]));
369
- }
370
- }
371
- return result;
372
- }
373
-
374
- cloneAll(targetGraph = this) {
375
- return this.clone(this.patterns.nodes.map((x,i) => i), targetGraph);
376
- }
377
-
378
- unify_two_patterns(p1, p2) {
379
- // console.log(`unify_two_patterns(${JSON.stringify(p1)}, ${JSON.stringify(p2)})`);
380
- switch (p1.pattern) {
381
- case '(...)':
382
- switch (p2.pattern) {
383
- case '(...)':
384
- return {...p2, fields: setUnion(p1.fields, p2.fields)};
385
- case '{...}':
386
- return {...p2, fields: setUnion(p1.fields, p2.fields)};
387
- case '<...>':
388
- return {...p2, fields: setUnion(p1.fields, p2.fields)};
389
- case '()':
390
- if (subsetP(p1.fields, p2.fields)) return p2;
391
- throw new Error(`Cannot unify (${p1.fields},...) with (${p2.fields})`);
392
- case '[]':
393
- if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/))) return p2;
394
- throw new Error(`Cannot unify [] with (${p1.fields},...)`);
395
- case '{}':
396
- if (subsetP(p1.fields, p2.fields)) return p2;
397
- throw new Error(`Cannot unify (${p1.fields},...) with {${p2.fields}}`);
398
- case '<>':
399
- if (subsetP(p1.fields, p2.fields)) return p2;
400
- throw new Error(`Cannot unify (${p1.fields},...) with <${p2.fields}>`);
401
- case 'type': {
402
- const code = codes.find(p2.type);
403
- switch (code.code) {
404
- case '@int':
405
- // supports (2 .2) which returns unit
406
- if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/)))
407
- return p2;
408
- break;
409
- case '@string':
410
- return p2;
411
- case '@bool':
412
- if (p1.fields.every(x => `${x}`.match(/^true|false$/)))
413
- return p2;
414
- break;
415
- case 'product':
416
- case 'union': {
417
- let p2_fields = Object.keys(code[code.code]);
418
- if (subsetP(p1.fields, p2_fields)) return {...p2, fields: p2_fields};
419
- }; break;
420
- case 'vector':
421
- return {...p2, fields: ['vector-member']};
422
- }
423
- throw new Error(`Cannot unify ${JSON.stringify(p1)} with code ${p2.type}:${code.def}`);
424
- }
425
- } ;
426
- break;
427
- case '{...}':
428
- switch (p2.pattern) {
429
- case '{...}':
430
- return {...p2, fields: setUnion(p1.fields, p2.fields)};
431
- case '<...>':
432
- throw new Error('Cannot unify {...} with <...>');
433
- case '()':
434
- if (subsetP(p1.fields, p2.fields))
435
- return {pattern: '{}', fields: p2.fields};
436
- case '[]':
437
- if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/))) return p2;
438
- throw new Error(`Cannot unify [] with {${p1.fields},...}`);
439
- case '{}':
440
- if (subsetP(p1.fields, p2.fields)) return p2;
441
- throw new Error(`Cannot unify {${p1.fields},...} with {${p2.fields}}`);
442
- case '<>':
443
- throw new Error('Cannot unify {...} with <>');
444
- case 'type': {
445
- const code = codes.find(p2.type);
446
- switch (code.code) {
447
- case 'product':{
448
- let p2_fields = Object.keys(code[code.code]);
449
- if (subsetP(p1.fields, p2_fields)) return {...p2, fields: p2_fields};
450
- };
451
- }
452
- throw new Error(`Cannot unify ${JSON.stringify(p1)} with code ${p2.type}:${code.def}`);
453
- }
454
- };
455
- break;
456
- case '<...>':
457
- switch (p2.pattern) {
458
- case '<...>':
459
- return {pattern: '<...>', fields: setUnion(p1.fields, p2.fields)};
460
- case '()':
461
- if (subsetP(p1.fields, p2.fields))
462
- return {pattern: '<>', fields: p2.fields};
463
- throw new Error(`Cannot unify <${p1.fields},...> with (${p2.fields})`);
464
- case '[]':
465
- throw new Error('Cannot unify <...> with []');
466
- case '{}':
467
- throw new Error('Cannot unify <...> with {}');
468
- case '<>':
469
- if (subsetP(p1.fields, p2.fields)) return p2;
470
- throw new Error(`Cannot unify <${p1.fields},...> with <${p2.fields}>`);
471
- case 'type':{
472
- const code = codes.find(p2.type);
473
- switch (code.code) {
474
- case '@int':
475
- // supports (2 .2) which returns unit
476
- if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/)))
477
- return p2;
478
- break;
479
- case '@string':
480
- return p2;
481
- case '@bool':
482
- if (p1.fields.every(x => `${x}`.match(/^true|false$/)))
483
- return p2;
484
- break;
485
- case 'union': {
486
- let p2_fields = Object.keys(code[code.code]);
487
- if (subsetP(p1.fields, p2_fields)) return {...p2, fields: p2_fields};
488
- }
489
- }
490
- throw new Error(`Cannot unify ${JSON.stringify(p1)} with code ${p2.type}:${code.def}`);
491
- };
492
- };
493
- break;
494
- case '()': // Pattern '()' can be introduced by filter e.g., ?(X x, Y x)
495
- switch (p2.pattern) {
496
- case '()':
497
- if (eqsetP(p1.fields, p2.fields)) return p2;
498
- throw new Error(`Cannot unify (${p1.fields}) with (${p2.fields})`);
499
- case '{}':
500
- if (eqsetP(p1.fields, p2.fields)) return p2;
501
- throw new Error(`Cannot unify (${p1.fields}) with {${p2.fields}}`);
502
- case '[]':
503
- if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/))) return p2;
504
- throw new Error(`Cannot unify [] with (${p1.fields})`);
505
- case '<>':
506
- if (eqsetP(p1.fields, p2.fields)) return p2;
507
- throw new Error(`Cannot unify (${p1.fields}) with <${p2.fields}>`);
508
- case 'type':{
509
- const code = codes.find(p2.type);
510
- switch (code.code) {
511
- case '@int':
512
- if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/)))
513
- return p2;
514
- break;
515
- case '@string':
516
- return p2;
517
- case '@bool':
518
- if (p1.fields.every(x => `${x}`.match(/^true|false$/)))
519
- return p2;
520
- break;
521
- case 'product':
522
- case 'union': {
523
- let p2_fields = Object.keys(code[code.code]);
524
- if (eqsetP(p1.fields, p2_fields)) return {...p2, fields: p2_fields};
525
- }; break;
526
- case 'vector':
527
- if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/)))
528
- return {...p2, fields: ['vector-member']};
529
- }
530
- throw new Error(`Cannot unify ${JSON.stringify(p1)} with code ${p2.type}:${code.def}`);
531
- };
532
- };
533
- break;
534
- case '[]':
535
- switch (p2.pattern) {
536
- case '{}':
537
- // if (p2.fields.every(x => `${x}`.match(/^[0-9]+$/)))
538
- // return p1;
539
- throw new Error(`Cannot unify [] with {${p2.fields}}`);
540
- case '[]':
541
- return p1;
542
- case '<>':
543
- throw new Error('Cannot unify [] with <>');
544
- case 'type': {
545
- const code = codes.find(p2.type);
546
- switch (code.code) {
547
- case 'vector':
548
- return {...p2, fields: ['vector-member']};
549
- }
550
- throw new Error(`Cannot unify ${JSON.stringify(p1)} with code ${p2.type}:${code.def}`);
551
- };
552
- };
553
- break;
554
- case '{}':
555
- switch (p2.pattern) {
556
- case '{}':
557
- if (eqsetP(p1.fields, p2.fields)) return p2;
558
- throw new Error(`Cannot unify {${p1.fields}} with {${p2.fields}}`);
559
- case '<>':
560
- throw new Error('Cannot unify {} with <>');
561
- case 'type': {
562
- const code = codes.find(p2.type);
563
- switch (code.code) {
564
- case 'product':{
565
- let p2_fields = Object.keys(code[code.code]);
566
- if (eqsetP(p1.fields, p2_fields)) return {...p2, fields: p2_fields};
567
- };
568
- }
569
- throw new Error(`Cannot unify ${JSON.stringify(p1)} with code ${p2.type}:${code.def}`);
570
- }
571
- };
572
- break;
573
- case '<>':
574
- switch (p2.pattern) {
575
- case '<>':
576
- if (eqsetP(p1.fields, p2.fields)) return p2;
577
- throw new Error(`Cannot unify <${p1.fields}> with <${p2.fields}>`);
578
- case 'type': {
579
- const code = codes.find(p2.type);
580
- switch (code.code) {
581
- case 'union':{
582
- let p2_fields = Object.keys(code[code.code]);
583
- if (eqsetP(p1.fields, p2_fields)) return {...p2, fields: p2_fields};
584
- };
585
- }
586
- throw new Error(`Cannot unify ${JSON.stringify(p1)} with code ${p2.type}:${code.def}`);
587
- }
588
- };
589
- break;
590
- case 'type':
591
- switch (p2.pattern) {
592
- case 'type':
593
- if (p1.type != p2.type)
594
- throw new Error(`Cannot unify different types: ${p1.type}:${codes.find(p1.type).def} and ${p2.type}:${codes.find(p2.type).def}`);
595
- return p2;
596
- };
597
- break;
598
- }
599
- return this.unify_two_patterns(p2, p1);
600
- }
601
-
602
- unify_patterns(...patterns) {
603
- const unify_two_patterns = this.unify_two_patterns.bind(this);
604
- return patterns.reduce(unify_two_patterns, {pattern: '(...)', fields: []});
605
124
  }
606
125
 
607
- unify(rule, ...ids) {
608
- const find = (x) => this.find(x);
609
- const reps = Array.from(new Set(ids.map(find)));
610
- if (reps.length < 2) return false;
611
- const rep_patters = reps.map(x => {
612
- const pattern = this.get_pattern(x);
613
- const fields = Object.keys(this.edges[x] || {});
614
- return {...pattern, fields: fields};
615
- });
616
-
617
- const new_pattern = (() => { try {
618
- return {...this.unify_patterns(...rep_patters), rule : rule}
619
- } catch (e) {
620
- e.message = `Unification rule "${rule}"\n - ${e.message}`;
621
- throw e;
622
- } })();
623
- const new_id = (() => {
624
- if (new_pattern.pattern == 'type') {
625
- const id = this.getTypeId(new_pattern.type);
626
- this.patterns.addChildren(id, reps);
627
- return id;
628
- };
629
- return this.patterns.addNewNode(new_pattern, reps);
126
+ const compressedTypePatternGraph = new TypePatternGraph(typePatternGraph.registerCodeDef, typePatternGraph.findCode);
127
+ const newIds = {};
128
+ for (const eqClass of equivalence) {
129
+ const oldId = eqClass[0];
130
+ const pattern = newTypePatternGraph.get_pattern(oldId);
131
+ const newId = (() => {
132
+ if (pattern.pattern == 'type') return compressedTypePatternGraph.getTypeId(pattern.type);
133
+ return compressedTypePatternGraph.patterns.addNewNode(pattern);
630
134
  })();
631
- // console.log(" * new ", JSON.stringify({new_id, new_pattern}));
632
- // console.log(" ", JSON.stringify(rep_patters));
633
- this.edges[new_id] = {};
634
-
635
- for (const i of reps) {
636
- const edges = this.edges[i];
637
- for (const lab in edges) {
638
- // if the pattern is [] all labels are treated as 'vector-member'
639
- const new_lab = new_pattern.pattern == '[]' ? 'vector-member' : lab;
640
- const dests = asSet(edges[lab].map(find));
641
- this.edges[new_id][new_lab] = asSet([...(this.edges[new_id][new_lab] || []), ...dests]);
642
- }
643
- }
644
- // add stuff for types
645
- if (new_pattern.pattern == 'type') {
646
- const code = codes.find(new_pattern.type);
647
- switch (code.code) {
648
- case '@int':
649
- case '@string':
650
- case '@bool': {
651
- // all edges are goin to unit type
652
- const unit_id = this.getTypeId(unitCode);
653
- for (const lab in this.edges[new_id]) {
654
- this.edges[new_id][lab] = asSet([unit_id]);
655
- }
656
- }; break;
657
- case 'product':
658
- case 'union':{
659
- const type_fields = Object.keys(code[code.code]);
660
- for (const lab of type_fields) {
661
- const target_type_id = this.getTypeId(code[code.code][lab]);
662
- this.edges[new_id][lab]= asSet([...(this.edges[new_id][lab] ||[]), target_type_id]);
663
- }
664
- }; break;
665
- case 'vector': {
666
-
667
- const target_type_id = this.getTypeId(code.vector);
668
-
669
- this.edges[new_id] = {
670
- 'vector-member': asSet([ target_type_id, ...[].concat(...Object.values(this.edges[new_id]))])
671
- }
672
- }
673
- }
674
- }
675
- for ( const lab of Object.keys(this.edges[new_id]) ) {
676
- this.unify(rule+'.', ...this.edges[new_id][lab]);
677
- }
678
-
679
- return true;
135
+ newIds[oldId] = newId;
680
136
  }
681
-
682
- addNewNode(pattern = matchAllPattern, fields = {}) {
683
- const id = this.patterns.addNewNode(pattern);
684
- const find = (x) => this.patterns.find(x);
685
- this.edges[id] = {};
686
- for (const [lab,dest] of Object.entries(fields)) {
687
- this.edges[id][lab] = asSet(dest.map(find));
137
+ for (const oldId in newIds) {
138
+ const newId = newIds[oldId];
139
+ const pattern = newTypePatternGraph.get_pattern(oldId);
140
+ if (pattern.pattern == 'type')
141
+ continue;
142
+ const edges = newTypePatternGraph.edges[oldId];
143
+ compressedTypePatternGraph.edges[newId] = {};
144
+ for (const lab in edges) {
145
+ compressedTypePatternGraph.edges[newId][lab] = asSet(edges[lab].map(x =>
146
+ newIds[reps[newTypePatternGraph.find(x)][0]]));
688
147
  }
689
- return id;
690
- }
691
-
692
- getTypeId(type) {
693
- if (type == undefined) throw new Error("code name cannot be 'undefined'! "); //TODO: remove after testing
694
- if ( this.codeId[type] == undefined )
695
- this.codeId[type] = this.addNewNode({pattern: 'type', type: type});
696
- return this.codeId[type];
697
148
  }
698
149
 
699
- size() {
700
- const typeNodes = this.patterns.nodes.filter(x => x.pattern == 'type').length;
701
- return [this.patterns.nodes.length,typeNodes];
150
+ const remapping = {};
151
+ for (const id in renamed) {
152
+ remapping[id] = newIds[ reps[renamed[id]][0] ];
702
153
  }
154
+
155
+ return {typePatternGraph: compressedTypePatternGraph, remapping};
703
156
  }
704
157
 
705
- export { TypePatternGraph };
706
- export default { TypePatternGraph };
158
+ export { TypePatternGraph, getCompressed };
159
+ export default { TypePatternGraph, getCompressed };