@fraczak/k 3.0.2 → 3.1.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/BIG_PICTURE.md +15 -6
- package/Code-derivation-tests/blowup.mjs +27 -0
- package/Code-derivation-tests/bnat.mjs +4 -2
- package/Code-derivation-tests/built-in.mjs +1 -1
- package/Code-derivation-tests/dot.mjs +28 -3
- package/Code-derivation-tests/index.mjs +2 -2
- package/Code-derivation-tests/loop.mjs +1 -1
- package/Code-derivation-tests/nat.mjs +2 -2
- package/Code-derivation-tests/not-not.mjs +2 -2
- package/Code-derivation-tests/product.mjs +9 -5
- package/Code-derivation-tests/rlz.mjs +2 -2
- package/Code-derivation-tests/vector.mjs +8 -14
- package/Graph.mjs +95 -0
- package/TYPING.md +368 -0
- package/aaa.txt +203033 -0
- package/codes.mjs +60 -8
- package/hash.mjs +6 -5
- package/index.mjs +7 -38
- package/k.mjs +3 -3
- package/package.json +1 -1
- package/parser.jison +14 -6
- package/parser.mjs +68 -62
- package/patterns.mjs +386 -534
- package/repl.mjs +13 -7
- package/run.mjs +7 -5
- package/symbol-table.mjs +44 -41
- package/test-filters.mjs +3 -3
- package/typing-test.mjs +40 -0
- package/typing.mjs +528 -0
- package/TODO.md +0 -54
package/patterns.mjs
CHANGED
|
@@ -1,601 +1,453 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
import hash from "./hash.mjs";
|
|
3
|
+
import { TypePatternGraph } from "./typing.mjs";
|
|
4
|
+
import { Graph, sccs, topoOrder } from "./Graph.mjs";
|
|
5
|
+
import codes from "./codes.mjs";
|
|
3
6
|
|
|
7
|
+
const unitCode = codes.unitCode;
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
// 1. Normalized code graph (i.e., codes and representatives)
|
|
7
|
-
// 2. a pattern is defined by triples:
|
|
8
|
-
// { code: [null, codeId],
|
|
9
|
-
// type: [null, product, union, vector, code],
|
|
10
|
-
// closed: [true, false] }
|
|
9
|
+
function relDefToString(relDef) {
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
const dumpPatterns = (rel) => {
|
|
12
|
+
switch (rel.op) {
|
|
13
|
+
case "product":
|
|
14
|
+
return [].concat(rel.patterns, ...rel.product.map(({exp}) => dumpPatterns(exp)));
|
|
15
|
+
case "union":
|
|
16
|
+
return [].concat(rel.patterns, ...rel.union.map(exp => dumpPatterns(exp)));
|
|
17
|
+
case "comp":
|
|
18
|
+
return [].concat(rel.patterns, ...rel.comp.map(exp => dumpPatterns(exp)));
|
|
19
|
+
case "vector":
|
|
20
|
+
return [].concat(rel.patterns, ...rel.vector.map(exp => dumpPatterns(exp)));
|
|
21
|
+
case "caret":
|
|
22
|
+
return [].concat(rel.patterns, dumpPatterns(rel.caret));
|
|
23
|
+
case "ref":
|
|
24
|
+
case "int":
|
|
25
|
+
case "str":
|
|
26
|
+
case "identity":
|
|
27
|
+
case "dot":
|
|
28
|
+
case "code":
|
|
29
|
+
case "pipe":
|
|
30
|
+
return [...rel.patterns];
|
|
31
|
+
}
|
|
32
|
+
throw new Error("NOT EXPECTED OP:", rel);
|
|
33
|
+
};
|
|
13
34
|
|
|
14
|
-
|
|
35
|
+
return JSON.stringify(dumpPatterns(relDef.def).map((x) => {
|
|
36
|
+
const { pattern, fields, type} = relDef.typePatternGraph.get_pattern(x);
|
|
37
|
+
return {pattern, fields, type};
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
15
40
|
|
|
16
|
-
function
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
// representatives:{"{}": "BG", ...}
|
|
20
|
-
// rels: {"rlz": [{op: comp,...}, ...], ...}
|
|
21
|
-
|
|
22
|
-
// OUTPUT: returns pattern graph:
|
|
23
|
-
// { patternNodes: [{code,type,closed},...],
|
|
24
|
-
// patternEdges: {src: {label: dst, ...}}...}
|
|
25
|
-
// as well as it will annotate rels; each rel node will have property "patterns: [i, o]"
|
|
41
|
+
function compactRel(relDef, name = "") {
|
|
42
|
+
const {def, typePatternGraph, varRefs } = relDef;
|
|
43
|
+
// console.log("COMPACTING typePatternGraph of size", typePatternGraph.size());
|
|
26
44
|
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
const codeToPattern = {}; // e.g., {"{}": 0, ...} - in order to collapse patterns resolved to the same code
|
|
45
|
+
const newTypePatternGraph = new TypePatternGraph();
|
|
46
|
+
const renumbering = typePatternGraph.cloneAll(newTypePatternGraph);
|
|
31
47
|
|
|
32
|
-
|
|
33
|
-
// 1.1 initialize patternNodes and rels
|
|
48
|
+
newTypePatternGraph.turnSingletonPatternsIntoCodes();
|
|
34
49
|
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
const pattern_i = { _id: i, code: null, type: null, closed: false}
|
|
38
|
-
patternNodes.push(pattern_i);
|
|
50
|
+
const copyRel = (rel) => {
|
|
51
|
+
const newRel = {...rel, patterns:[renumbering[rel.patterns[0]], renumbering[rel.patterns[1]]]};
|
|
39
52
|
switch (rel.op) {
|
|
40
53
|
case "product":
|
|
41
|
-
rel
|
|
54
|
+
newRel.product = rel.product.map(({label, exp}) => ({label, exp: copyRel(exp)}));
|
|
42
55
|
break;
|
|
43
56
|
case "union":
|
|
57
|
+
newRel.union = rel.union.map(exp => copyRel(exp));
|
|
58
|
+
break;
|
|
44
59
|
case "comp":
|
|
45
|
-
|
|
46
|
-
rel[rel.op].forEach((exp) => augment(exp));
|
|
60
|
+
newRel.comp = rel.comp.map(exp => copyRel(exp));
|
|
47
61
|
break;
|
|
48
|
-
case "
|
|
49
|
-
|
|
62
|
+
case "vector":
|
|
63
|
+
newRel.vector = rel.vector.map(exp => copyRel(exp));
|
|
50
64
|
break;
|
|
51
65
|
case "caret":
|
|
52
|
-
|
|
53
|
-
break;
|
|
54
|
-
case "filter":
|
|
55
|
-
// do nothing for now
|
|
56
|
-
console.log("filter ignored", rel);
|
|
66
|
+
newRel.caret = copyRel(rel.caret);
|
|
57
67
|
break;
|
|
58
68
|
case "ref":
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
case "int":
|
|
70
|
+
case "str":
|
|
71
|
+
case "identity":
|
|
72
|
+
case "dot":
|
|
73
|
+
case "code":
|
|
61
74
|
case "pipe":
|
|
62
75
|
break;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
76
|
+
default:
|
|
77
|
+
console.error("NOT EXPECTED OP:", rel);
|
|
78
|
+
break;
|
|
79
|
+
};
|
|
80
|
+
return newRel;
|
|
81
|
+
};
|
|
82
|
+
const newDef = copyRel(def);
|
|
83
|
+
const newVarRefs = varRefs.map(x => ({
|
|
84
|
+
...x,
|
|
85
|
+
inputPatternId: renumbering[x.inputPatternId],
|
|
86
|
+
outputPatternId: renumbering[x.outputPatternId]
|
|
87
|
+
}));;
|
|
88
|
+
|
|
89
|
+
// console.log(`COMPACTED ${name}.typePatternGraph`, typePatternGraph.size(), '->', newTypePatternGraph.size());
|
|
90
|
+
return {def: newDef, typePatternGraph: newTypePatternGraph, varRefs: newVarRefs};
|
|
91
|
+
}
|
|
75
92
|
|
|
76
|
-
|
|
93
|
+
function patterns(usedCodes, representatives, rels) {
|
|
94
|
+
codes.register(usedCodes);
|
|
95
|
+
// INPUT:
|
|
96
|
+
// codes: {"BG": {"code": "product", "product": {}}, ...}
|
|
97
|
+
// representatives:{"{}": "BG", ...}
|
|
98
|
+
// rels: {"rlz": [{op: comp,...}, ...], ...}
|
|
99
|
+
|
|
77
100
|
|
|
78
|
-
// 1
|
|
79
|
-
|
|
80
|
-
const eq = patternNodes.map((_, i) => i); // equivalence classes over patternNodes, e.g., [0, 1, 0, ...]}
|
|
81
|
-
|
|
82
|
-
function getRep(i) {
|
|
83
|
-
while (eq[i] !== i) { i = eq[i]; }
|
|
84
|
-
return i;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
for (const node_id in eq) { patternEdges[node_id]={}; }
|
|
88
|
-
|
|
89
|
-
// -------- helper functions --------
|
|
101
|
+
// 1 INITIALIZATION
|
|
102
|
+
// 1.1 initialize patternNodes and rels
|
|
90
103
|
|
|
91
|
-
function
|
|
92
|
-
const op = rel.op;
|
|
93
|
-
// console.log(`Inspecting ${op} ${JSON.stringify(rel)}`);
|
|
104
|
+
function augment(rel, rootDef) {
|
|
94
105
|
try {
|
|
95
|
-
switch (op) {
|
|
106
|
+
switch (rel.op) {
|
|
96
107
|
case "product":
|
|
97
|
-
|
|
108
|
+
rel["product"].forEach(({label, exp}) => {
|
|
109
|
+
augment(exp, rootDef)
|
|
110
|
+
});
|
|
111
|
+
augmentProduct(rel,rootDef);
|
|
112
|
+
break;
|
|
98
113
|
case "union":
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
114
|
+
rel["union"].forEach((exp) => {
|
|
115
|
+
augment(exp,rootDef);
|
|
116
|
+
});
|
|
117
|
+
augmentUnion(rel,rootDef);
|
|
118
|
+
break;
|
|
119
|
+
case "comp":
|
|
120
|
+
rel["comp"].forEach((exp) => {
|
|
121
|
+
augment(exp,rootDef);
|
|
122
|
+
});
|
|
123
|
+
augmentComp(rel,rootDef);
|
|
124
|
+
break;
|
|
104
125
|
case "vector":
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
126
|
+
rel["vector"].forEach((exp) => {
|
|
127
|
+
augment(exp,rootDef);
|
|
128
|
+
});
|
|
129
|
+
augmentVector(rel,rootDef);
|
|
130
|
+
break;
|
|
131
|
+
case "code":
|
|
132
|
+
rel["code"] = representatives[rel.code] || rel.code;
|
|
133
|
+
rel.patterns = [];
|
|
134
|
+
rel.patterns[0] = rootDef.typePatternGraph.getTypeId(rel["code"]);
|
|
135
|
+
rel.patterns[1] = rel.patterns[0];
|
|
136
|
+
break;
|
|
137
|
+
case "caret":
|
|
138
|
+
augment(rel.caret,rootDef);
|
|
139
|
+
rel.patterns = [
|
|
140
|
+
rel.caret.patterns[0],
|
|
141
|
+
rootDef.typePatternGraph.addNewNode(
|
|
142
|
+
{pattern: '[]'},
|
|
143
|
+
{"vector-member": [rel.caret.patterns[1]]})
|
|
144
|
+
];
|
|
145
|
+
break;
|
|
146
|
+
case "pipe":
|
|
147
|
+
rel.patterns = [];
|
|
148
|
+
rel.patterns[1] = rootDef.typePatternGraph.addNewNode();
|
|
149
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode(
|
|
150
|
+
{pattern: '[]'},
|
|
151
|
+
{"vector-member": [rel.patterns[1]]});
|
|
152
|
+
break;
|
|
153
|
+
|
|
110
154
|
case "ref":
|
|
111
|
-
|
|
155
|
+
augmentRef(rel, rootDef);
|
|
156
|
+
break;
|
|
157
|
+
//----------------
|
|
158
|
+
|
|
112
159
|
case "int":
|
|
113
|
-
|
|
160
|
+
rel.patterns = [];
|
|
161
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
162
|
+
rel.patterns[1] = rootDef.typePatternGraph.getTypeId('int');
|
|
163
|
+
break;
|
|
114
164
|
case "str":
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
165
|
+
rel.patterns = [];
|
|
166
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
167
|
+
rel.patterns[1] = rootDef.typePatternGraph.getTypeId('string');
|
|
168
|
+
break;
|
|
169
|
+
case "identity":
|
|
170
|
+
rel.patterns = [];
|
|
171
|
+
rel.patterns[0] = rel.patterns[1] = rootDef.typePatternGraph.addNewNode();
|
|
172
|
+
break;
|
|
173
|
+
case "dot":
|
|
174
|
+
rel.patterns = [];
|
|
175
|
+
rel.patterns[1] = rootDef.typePatternGraph.addNewNode();
|
|
176
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode({pattern: '(...)'}, { [rel.dot]: [rel.patterns[1]] });
|
|
177
|
+
break;
|
|
178
|
+
|
|
179
|
+
default:
|
|
180
|
+
console.error("NOT EXPECTED OP:", rel);
|
|
181
|
+
break;
|
|
122
182
|
}
|
|
123
|
-
throw new Error(`Unknown op: ${op}`);
|
|
124
183
|
} catch (e) {
|
|
125
|
-
console.error(`Code Derivation Error for '${op}' (lines ${rel.start?.line}:${rel.start?.column}...${rel.end?.line}:${rel.end?.column}): ${e.message}.`);
|
|
184
|
+
console.error(`Code Derivation Error for '${rel.op}' (lines ${rel.start?.line}:${rel.start?.column}...${rel.end?.line}:${rel.end?.column}): ${e.message}.`);
|
|
126
185
|
throw e;
|
|
127
186
|
}
|
|
128
187
|
}
|
|
129
|
-
|
|
130
|
-
function updatePattern(pattern, {code, type, closed}) {
|
|
131
|
-
if (code) {
|
|
132
|
-
type = "code";
|
|
133
|
-
closed = true;
|
|
134
|
-
if (pattern.code == code && pattern.type == type && pattern.closed == closed) {
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
if (pattern.code) {
|
|
138
|
-
throw new Error(`Cannot update pattern with code: ${pattern.code} -> ${code}`);
|
|
139
|
-
}
|
|
140
|
-
if (pattern.type && pattern.type != codes[code]?.code) {
|
|
141
|
-
throw new Error(`Cannot update pattern with code '${code}': pattern type: ${pattern.type} -> code type: ${codes[code]?.code || 'built-in'}`);
|
|
142
|
-
}
|
|
143
|
-
pattern.code = code;
|
|
144
|
-
pattern.closed = true;
|
|
145
|
-
pattern.type = "code";
|
|
146
|
-
return true;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (pattern.code) {
|
|
150
|
-
// TODO: check for potential type mismatch between 'type' and 'code.code'
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
let changed = false;
|
|
155
|
-
|
|
156
|
-
if (type) {
|
|
157
|
-
if (! pattern.type) {
|
|
158
|
-
pattern.type = type;
|
|
159
|
-
changed = true;
|
|
160
|
-
} else if (pattern.type != type) {
|
|
161
|
-
throw new Error(`Cannot update pattern ${JSON.stringify(pattern)} with ${JSON.stringify({code, type, closed})}`);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (closed && (! pattern.closed)) {
|
|
166
|
-
pattern.closed = closed;
|
|
167
|
-
return true;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return changed;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function join(i, j) {
|
|
174
|
-
const iRep = getRep(i);
|
|
175
|
-
const jRep = getRep(j);
|
|
176
|
-
if (iRep == jRep) { return false; }
|
|
177
|
-
// create new representative
|
|
178
|
-
const iPattern = patternNodes[iRep];
|
|
179
|
-
const jPattern = patternNodes[jRep];
|
|
180
|
-
|
|
181
|
-
const newRep = patternNodes.length;
|
|
182
|
-
const newPattern = {
|
|
183
|
-
_id: newRep,
|
|
184
|
-
code: null, type: null, closed: false,
|
|
185
|
-
_from: `(${iPattern._from || iRep},${jPattern._from || jRep})`};
|
|
186
|
-
patternNodes[newRep] = newPattern;
|
|
187
|
-
patternEdges[newRep] = {};
|
|
188
|
-
eq[iRep] = eq[jRep] = eq[newRep] = newRep;
|
|
189
|
-
// we still have to merge patterns and migrate edges
|
|
190
|
-
updatePattern(newPattern, iPattern);
|
|
191
|
-
updatePattern(newPattern, jPattern);
|
|
192
|
-
migrateEdges(jRep, newRep);
|
|
193
|
-
migrateEdges(iRep, newRep);
|
|
194
|
-
|
|
195
|
-
return newRep;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function migrateEdges(from_i, to_j) {
|
|
199
|
-
const iEdges = patternEdges[from_i];
|
|
200
|
-
const jEdges = patternEdges[to_j];
|
|
201
|
-
for (const label in iEdges) {
|
|
202
|
-
const iTarget = iEdges[label];
|
|
203
|
-
const jTarget = jEdges[label];
|
|
204
|
-
if (jTarget) {
|
|
205
|
-
const newTarget = join(iTarget, jTarget);
|
|
206
|
-
if (newTarget) {
|
|
207
|
-
jEdges[label] = newTarget;
|
|
208
|
-
}
|
|
209
|
-
} else {
|
|
210
|
-
jEdges[label] = iTarget;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function addEdge(src, label, target) {
|
|
216
|
-
// console.log("addEdge", src, label, target, "old target", patternEdges[src][label] || "none");
|
|
217
|
-
const srcPattern = patternNodes[getRep(src)];
|
|
218
|
-
if (srcPattern.type == "code") {
|
|
219
|
-
const code = codes[representatives[srcPattern.code] || srcPattern.code];
|
|
220
|
-
if (code.code == "product" || code.code == "union" ) {
|
|
221
|
-
return updatePattern(patternNodes[getRep(target)], {code: code[code.code][label]})
|
|
222
|
-
}
|
|
223
|
-
throw new Error(`Cannot add edge ${label} to code ${JSON.stringify(code)}`);
|
|
224
|
-
}
|
|
225
|
-
if (srcPattern.type == 'vector') {
|
|
226
|
-
if (/^(0|[1-9][0-9]*)$/.test(label)) {
|
|
227
|
-
const old_target = patternEdges[src]['vector-member'];
|
|
228
|
-
if (old_target) {
|
|
229
|
-
const newTarget = join(old_target, target);
|
|
230
|
-
if (newTarget) {
|
|
231
|
-
patternEdges[src][label] = newTarget;
|
|
232
|
-
return true;
|
|
233
|
-
}
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
patternEdges[src]['vector-member'] = target;
|
|
237
|
-
return true;
|
|
238
|
-
}
|
|
239
|
-
throw new Error(`Cannot add edge ${label} to code ${JSON.stringify(code)}`);
|
|
240
|
-
}
|
|
241
|
-
const old_target = patternEdges[src][label];
|
|
242
|
-
if (old_target) {
|
|
243
|
-
const newTarget = join(old_target, target);
|
|
244
|
-
if (newTarget) {
|
|
245
|
-
patternEdges[src][label] = newTarget;
|
|
246
|
-
return true;
|
|
247
|
-
}
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (srcPattern.closed) {
|
|
252
|
-
throw new Error(`Cannot add edge ${label} to pattern ${JSON.stringify(srcPattern)}`);
|
|
253
|
-
}
|
|
254
|
-
patternEdges[src][label] = target;
|
|
255
|
-
return true;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function inspectInt(rel) {
|
|
259
|
-
const o_pattern = patternNodes[rel.patterns[1]];
|
|
260
|
-
return updatePattern(o_pattern, {code: "int", type: "code", closed: true});
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function inspectStr(rel) {
|
|
264
|
-
const o_pattern = patternNodes[rel.patterns[1]];
|
|
265
|
-
return updatePattern(o_pattern, {code: "string", type: "code", closed: true});
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function inspectPipe(rel) {
|
|
269
|
-
const old_i = getRep(rel.patterns[0]);
|
|
270
|
-
const old_o = getRep(rel.patterns[1]);
|
|
271
|
-
const old_i_pattern = patternNodes[old_i];
|
|
272
|
-
|
|
273
|
-
let modified = updatePattern(old_i_pattern, {type: "vector", closed: true});
|
|
274
|
-
|
|
275
|
-
let member_i = patternEdges[old_i]["vector-member"];
|
|
276
|
-
if (member_i == undefined ) {
|
|
277
|
-
modified = true;
|
|
278
|
-
member_i = patternNodes.length;
|
|
279
|
-
patternNodes.push({ _id: member_i, code: null, type: null, closed: false})
|
|
280
|
-
patternEdges[old_i]["vector-member"] = member_i;
|
|
281
|
-
eq[member_i] = member_i;
|
|
282
|
-
}
|
|
283
|
-
member_i = getRep(member_i);
|
|
284
|
-
modified = join(member_i, old_o) || modified;
|
|
285
|
-
console.log([old_i,old_o,member_i].map( x => [x,patternNodes[x]]));
|
|
286
|
-
return modified;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
function inspectCaret(rel) {
|
|
290
|
-
let modified = join(rel.patterns[0], rel.caret.patterns[0]);
|
|
291
|
-
const old_o = getRep(rel.patterns[1]);
|
|
292
|
-
const old_o_pattern = patternNodes[old_o];
|
|
293
|
-
|
|
294
|
-
modified = updatePattern(old_o_pattern, {type: "vector", closed: true});
|
|
295
|
-
|
|
296
|
-
let member_o = patternEdges[old_o]["vector-member"];
|
|
297
|
-
if (member_o == undefined ) {
|
|
298
|
-
modified = true;
|
|
299
|
-
member_o = patternNodes.length;
|
|
300
|
-
patternNodes.push({ _id: member_o, code: null, type: null, closed: false})
|
|
301
|
-
patternEdges[old_o]["vector-member"] = member_o;
|
|
302
|
-
eq[member_o] = member_o;
|
|
303
|
-
}
|
|
304
|
-
member_o = getRep(member_o);
|
|
305
|
-
modified = join(rel.caret.patterns[1], member_o) || modified;
|
|
306
|
-
return modified;
|
|
307
|
-
}
|
|
308
188
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const old_i = getRep(rel.patterns[0]);
|
|
312
|
-
const old_o = getRep(rel.patterns[1]);
|
|
313
|
-
const old_i_pattern = patternNodes[old_i];
|
|
314
|
-
const old_o_pattern = patternNodes[old_o];
|
|
315
|
-
const field = rel.dot;
|
|
316
|
-
if (old_i_pattern.type == "code") {
|
|
317
|
-
if (old_i_pattern.code == "int" || old_i_pattern.code == "bool" || old_i_pattern.code == "string") {
|
|
318
|
-
return updatePattern(old_o_pattern, {code: "product", type: "code", closed: true, product: []});
|
|
319
|
-
}
|
|
320
|
-
const code = codes[representatives[old_i_pattern.code] || old_i_pattern.code];
|
|
321
|
-
if (code.code == "product" || code.code == "union" || code.code == "vector") {
|
|
322
|
-
const target_code = code[code.code][field];
|
|
323
|
-
if (target_code)
|
|
324
|
-
return updatePattern(old_o_pattern, {code: target_code});
|
|
325
|
-
}
|
|
326
|
-
throw new Error(`Cannot find field ${field} in code ${JSON.stringify(code)}`);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return addEdge(old_i, field, old_o);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function inspectProduct(rel) {
|
|
189
|
+
function augmentProduct(rel,rootDef) {
|
|
190
|
+
rel.patterns = [];
|
|
333
191
|
switch (rel.product.length) {
|
|
334
|
-
case 0:
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
//
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
const old_o = getRep(rel.patterns[1]);
|
|
352
|
-
const old_o_pattern = patternNodes[old_o];
|
|
353
|
-
|
|
354
|
-
const exp_i = getRep(exp.patterns[0]);
|
|
355
|
-
const exp_o = getRep(exp.patterns[1]);
|
|
192
|
+
case 0:
|
|
193
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
194
|
+
rel.patterns[1] = rootDef.typePatternGraph.getTypeId(unitCode);
|
|
195
|
+
break;
|
|
196
|
+
case 1:
|
|
197
|
+
// union/variant constructor: %old_i { %exp_i exp %exp_o field } %old_o
|
|
198
|
+
rel.patterns[0] = rel.product[0].exp.patterns[0];
|
|
199
|
+
rel.patterns[1] = rootDef.typePatternGraph.addNewNode({pattern: '<...>'},
|
|
200
|
+
{[rel.product[0].label]: [rel.product[0].exp.patterns[1]]});
|
|
201
|
+
break;
|
|
202
|
+
default:
|
|
203
|
+
// product constructor %old_i { %exp0_i exp0 %exp0_o field0, ... %expk_i expk %expk_o fieldk } %old_o
|
|
204
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
205
|
+
rootDef.typePatternGraph.unify(
|
|
206
|
+
"product:input",
|
|
207
|
+
rel.patterns[0],
|
|
208
|
+
...rel.product.map(({exp}) => exp.patterns[0]));
|
|
356
209
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
// product constructor %old_i { %exp0_i exp0 %exp0_o field0, ... %expk_i expk %expk_o fieldk } %old_o
|
|
366
|
-
var modified = rel.product.reduce((modified, {label,exp}) =>
|
|
367
|
-
inspect(exp) || modified, false);
|
|
368
|
-
|
|
369
|
-
const fields = rel.product.map(({label, exp}) =>
|
|
370
|
-
({label, exp_i: getRep(exp.patterns[0]), exp_o: getRep(exp.patterns[1])}));
|
|
371
|
-
|
|
372
|
-
const old_i = getRep(rel.patterns[0]);
|
|
373
|
-
const old_o = getRep(rel.patterns[1]);
|
|
374
|
-
const old_o_pattern = patternNodes[old_o];
|
|
375
|
-
|
|
376
|
-
for (const {label, exp_i, exp_o} of fields) {
|
|
377
|
-
modified = join(exp_i, old_i) || modified;
|
|
378
|
-
modified = addEdge(old_o, label, exp_o) || modified;
|
|
379
|
-
}
|
|
380
|
-
modified = updatePattern(old_o_pattern, {type: "product", closed: true}) || modified;
|
|
381
|
-
// check that patternEdges coincide with field labels
|
|
382
|
-
const patternEdgeLabels = Object.keys(patternEdges[old_o]);
|
|
383
|
-
const labels = fields.reduce( (labels,{label}) =>
|
|
384
|
-
({[label]: true, ...labels}), {});
|
|
385
|
-
|
|
386
|
-
for (const label of patternEdgeLabels) {
|
|
387
|
-
if (!labels[label]) {
|
|
388
|
-
throw new Error(`Label '${label}' not allowed for pattern ${JSON.stringify({...old_o_pattern, fields})}`);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
return modified;
|
|
210
|
+
rel.patterns[1] = rootDef.typePatternGraph.addNewNode({pattern: '{}'},
|
|
211
|
+
rel.product.reduce((edges, {label, exp}) => {
|
|
212
|
+
edges[label] = [exp.patterns[1]];
|
|
213
|
+
return edges;
|
|
214
|
+
}, {})
|
|
215
|
+
);
|
|
216
|
+
};
|
|
392
217
|
}
|
|
393
218
|
|
|
394
|
-
function
|
|
395
|
-
|
|
396
|
-
const old_o = getRep(rel.patterns[1]);
|
|
219
|
+
function augmentUnion(rel,rootDef) {
|
|
220
|
+
rel.patterns = [];
|
|
397
221
|
if (rel.union.length == 0) {
|
|
398
|
-
|
|
222
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
223
|
+
rel.patterns[1] = rootDef.typePatternGraph.addNewNode({pattern: '<>'});
|
|
224
|
+
} else {
|
|
225
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
226
|
+
rootDef.typePatternGraph.unify(
|
|
227
|
+
"union:input",
|
|
228
|
+
rel.patterns[0],
|
|
229
|
+
...rel.union.map(exp => exp.patterns[0]));
|
|
230
|
+
|
|
231
|
+
rel.patterns[1] = rootDef.typePatternGraph.addNewNode();
|
|
232
|
+
rootDef.typePatternGraph.unify(
|
|
233
|
+
"union:output",
|
|
234
|
+
rel.patterns[1],
|
|
235
|
+
...rel.union.map(exp => exp.patterns[1]));
|
|
399
236
|
}
|
|
400
|
-
// union: %old_i < %exp0_i exp0 %exp0_o, ... %expk_i expk %expk_o > %old_o
|
|
401
|
-
|
|
402
|
-
const modified = rel.union.reduce((modified, exp) => {
|
|
403
|
-
var new_modified = inspect(exp) || modified;
|
|
404
|
-
new_modified = join(rel.patterns[0], exp.patterns[0]) || modified;
|
|
405
|
-
new_modified = join(rel.patterns[1], exp.patterns[1]) || modified;
|
|
406
|
-
return new_modified;
|
|
407
|
-
}, false);
|
|
408
|
-
return modified;
|
|
409
237
|
}
|
|
410
238
|
|
|
411
|
-
function
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const old_i = getRep(rel.patterns[0]);
|
|
416
|
-
const [modified,pattern_o] = rel.comp.reduce(([modified,pattern_i], exp) => {
|
|
417
|
-
var new_modified = inspect(exp) || modified;
|
|
418
|
-
new_modified = join(pattern_i, exp.patterns[0]) || modified;
|
|
419
|
-
return [new_modified, exp.patterns[1]];
|
|
420
|
-
}, [false, old_i]);
|
|
421
|
-
return join(pattern_o, rel.patterns[1]) || modified;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
function inspectIdentity(rel) {
|
|
425
|
-
return join(rel.patterns[0], rel.patterns[1]);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
function inspectVector(rel) {
|
|
429
|
-
const old_o = getRep(rel.patterns[1]);
|
|
430
|
-
var modified = updatePattern(patternNodes[old_o], {type: "vector", closed: true});
|
|
431
|
-
if (rel.vector.length == 0) {
|
|
432
|
-
return modified;
|
|
433
|
-
}
|
|
434
|
-
// vector: %old_i [ %exp0_i exp0 %exp0_o, ... %expk_i expk %expk_o] %old_o
|
|
435
|
-
|
|
436
|
-
let member_o = patternEdges[old_o]["vector-member"];
|
|
437
|
-
if (member_o) {
|
|
438
|
-
member_o = getRep(patternEdges[old_o]["vector-member"]);
|
|
239
|
+
function augmentComp(rel,rootDef) {
|
|
240
|
+
rel.patterns = [];
|
|
241
|
+
if (rel.comp.length == 0) {
|
|
242
|
+
rel.patterns[0] = rel.patterns[1] = rootDef.typePatternGraph.addNewNode();
|
|
439
243
|
} else {
|
|
440
|
-
modified = true;
|
|
441
|
-
member_o = patternNodes.length;
|
|
442
|
-
patternNodes.push({ _id: member_o, code: null, type: null, closed: false})
|
|
443
|
-
patternEdges[old_o]["vector-member"] = member_o;
|
|
444
|
-
eq[member_o] = member_o;
|
|
445
|
-
}
|
|
446
244
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}, modified);
|
|
453
|
-
return modified;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
function inspectCode(rel) {
|
|
457
|
-
const old_i = getRep(rel.patterns[0]);
|
|
458
|
-
var modified = updatePattern(patternNodes[old_i], {code: representatives[rel.code] || rel.code});
|
|
459
|
-
return join(old_i, rel.patterns[1]) || modified;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
function inspectRef(rel) {
|
|
463
|
-
const relDefs = rels[rel.ref];
|
|
464
|
-
if (!relDefs) {
|
|
465
|
-
switch (rel.ref) {
|
|
466
|
-
case "_log!":
|
|
467
|
-
return inspectIdentity(rel);
|
|
468
|
-
case "true":
|
|
469
|
-
case "false": return updatePattern(patternNodes[rel.patterns[1]], {code: "bool"});
|
|
470
|
-
|
|
471
|
-
case "PLUS":
|
|
472
|
-
case "TIMES":
|
|
473
|
-
// should add updating the input parrent to code `$[int]`
|
|
474
|
-
// console.log("PLUS/TIMES", rel);
|
|
475
|
-
return updatePattern(patternNodes[rel.patterns[1]], {code: "int"});
|
|
476
|
-
case "CONCAT":
|
|
477
|
-
return updatePattern(patternNodes[rel.patterns[1]], {code: "string"});
|
|
478
|
-
case "toDateMsec":
|
|
479
|
-
return updatePattern(patternNodes[rel.patterns[1]], {code: "int"});
|
|
480
|
-
case "toJSON":
|
|
481
|
-
return updatePattern(patternNodes[rel.patterns[1]], {code: "string"});
|
|
482
|
-
case "toDateStr":
|
|
483
|
-
return updatePattern(patternNodes[rel.patterns[1]], {code: "string"});
|
|
484
|
-
|
|
485
|
-
// TO DO
|
|
486
|
-
case "GT":
|
|
487
|
-
case "EQ":
|
|
488
|
-
case "null":
|
|
489
|
-
case "DIV":
|
|
490
|
-
case "FDIV":
|
|
491
|
-
case "fromJSON":
|
|
492
|
-
case "CONS":
|
|
493
|
-
case "SNOC":
|
|
494
|
-
return false;
|
|
495
|
-
}
|
|
496
|
-
throw new Error(`No definition found for ${rel.ref}`);
|
|
497
|
-
}
|
|
498
|
-
// For now we assume only the first def which does not throw!!!!
|
|
499
|
-
// That's good enough if all defs are typed by different input codes.
|
|
500
|
-
for (const def of relDefs) {
|
|
501
|
-
try {
|
|
502
|
-
// var modified = join(def.patterns[0], rel.patterns[0]);
|
|
503
|
-
var modified = updatePattern(
|
|
504
|
-
patternNodes[getRep(rel.patterns[0])],
|
|
505
|
-
patternNodes[getRep(def.patterns[0])]
|
|
245
|
+
for (let i = 0; i < rel.comp.length - 1; i++) {
|
|
246
|
+
rootDef.typePatternGraph.unify(
|
|
247
|
+
"comp:chain",
|
|
248
|
+
rel.comp[i].patterns[1],
|
|
249
|
+
rel.comp[i+1].patterns[0]
|
|
506
250
|
);
|
|
507
|
-
|
|
508
|
-
// modified = join(def.patterns[1], rel.patterns[1]) || modified;
|
|
509
|
-
modified = updatePattern(
|
|
510
|
-
patternNodes[getRep(rel.patterns[1])],
|
|
511
|
-
patternNodes[getRep(def.patterns[1])]
|
|
512
|
-
) || modified;
|
|
513
|
-
|
|
514
|
-
return modified;
|
|
515
|
-
} catch (e) {}
|
|
516
|
-
}
|
|
517
|
-
throw new Error(`No matching definition found for ${rel.ref}`);
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
// --------- main loop --------------
|
|
522
|
-
|
|
523
|
-
// 2. loop until no more changes
|
|
524
|
-
|
|
525
|
-
let changed = true;
|
|
526
|
-
while (changed) {
|
|
527
|
-
changed = false;
|
|
528
|
-
for (const relName in rels) {
|
|
529
|
-
const defs = rels[relName];
|
|
530
|
-
for (const def of defs) {
|
|
531
|
-
changed = inspect(def) || changed;
|
|
532
251
|
}
|
|
252
|
+
|
|
253
|
+
rel.patterns[0] = rel.comp[0].patterns[0];
|
|
254
|
+
rel.patterns[1] = rel.comp[rel.comp.length - 1].patterns[1];
|
|
533
255
|
}
|
|
534
256
|
}
|
|
535
257
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
258
|
+
function augmentVector(rel,rootDef) {
|
|
259
|
+
rel.patterns = [];
|
|
260
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
261
|
+
rootDef.typePatternGraph.unify(
|
|
262
|
+
"vector:input",
|
|
263
|
+
rel.patterns[0],
|
|
264
|
+
...rel.vector.map(exp => exp.patterns[0]));
|
|
265
|
+
|
|
266
|
+
let member = rootDef.typePatternGraph.addNewNode();
|
|
267
|
+
rootDef.typePatternGraph.unify(
|
|
268
|
+
"vector:output",
|
|
269
|
+
member,
|
|
270
|
+
...rel.vector.map(exp => exp.patterns[1])
|
|
271
|
+
);
|
|
272
|
+
rel.patterns[1] = rootDef.typePatternGraph.addNewNode({pattern: '[]'}, {"vector-member": [member]});
|
|
273
|
+
}
|
|
545
274
|
|
|
546
|
-
function
|
|
547
|
-
rel.patterns
|
|
548
|
-
rel.
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
275
|
+
function augmentRef(rel,rootDef) {
|
|
276
|
+
rel.patterns = [];
|
|
277
|
+
if (rel.ref in rels) {
|
|
278
|
+
rel.patterns = [rootDef.typePatternGraph.addNewNode(), rootDef.typePatternGraph.addNewNode()];
|
|
279
|
+
rootDef.varRefs.push( {
|
|
280
|
+
varName: rel.ref,
|
|
281
|
+
inputPatternId: rel.patterns[0],
|
|
282
|
+
outputPatternId: rel.patterns[1],
|
|
283
|
+
start: rel.start,
|
|
284
|
+
end: rel.end
|
|
285
|
+
});
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
// it is built-in
|
|
289
|
+
switch (rel.ref) {
|
|
290
|
+
case "_log!":
|
|
291
|
+
rel.patterns[0] = rel.patterns[1] = rootDef.typePatternGraph.addNewNode();
|
|
552
292
|
break;
|
|
553
|
-
case "
|
|
554
|
-
case "
|
|
555
|
-
|
|
556
|
-
rel[
|
|
293
|
+
case "true":
|
|
294
|
+
case "false":
|
|
295
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
296
|
+
rel.patterns[1] = rootDef.typePatternGraph.getTypeId('bool');
|
|
297
|
+
break;
|
|
298
|
+
case "PLUS":
|
|
299
|
+
case "TIMES":
|
|
300
|
+
rel.patterns[1] = rootDef.typePatternGraph.getTypeId('int');
|
|
301
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode({pattern: '[]'}, {"vector-member": [rel.patterns[1]]});
|
|
302
|
+
break;
|
|
303
|
+
case "CONCAT":
|
|
304
|
+
rel.patterns[1] = rootDef.typePatternGraph.getTypeId('string');
|
|
305
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode({pattern: '[]'}, {"vector-member": [rel.patterns[1]]});
|
|
306
|
+
break;
|
|
307
|
+
case "toVEC":
|
|
308
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
309
|
+
rel.patterns[1] = rootDef.typePatternGraph.addNewNode({pattern: '[]'}, {"vector-member": [rel.patterns[0]]});
|
|
310
|
+
break;
|
|
311
|
+
case "toDateMsec":
|
|
312
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
313
|
+
rel.patterns[1] = rootDef.typePatternGraph.getTypeId('int');
|
|
314
|
+
break;
|
|
315
|
+
case "toJSON":
|
|
316
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
317
|
+
rel.patterns[1] = rootDef.typePatternGraph.getTypeId('string');
|
|
318
|
+
break;
|
|
319
|
+
case "toDateStr":
|
|
320
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode();
|
|
321
|
+
rel.patterns[1] = rootDef.typePatternGraph.getTypeId('string');
|
|
322
|
+
break;
|
|
323
|
+
case "GT":
|
|
324
|
+
case "EQ":
|
|
325
|
+
rel.patterns[0] = rel.patterns[1] = rootDef.typePatternGraph.addNewNode({pattern: '[]'}, {"vector-member": [rootDef.typePatternGraph.addNewNode()]});
|
|
326
|
+
break;
|
|
327
|
+
case "fromJSON":
|
|
328
|
+
rel.patterns[0] = rootDef.typePatternGraph.getTypeId('string');
|
|
329
|
+
rel.patterns[1] = rootDef.typePatternGraph.addNewNode();
|
|
330
|
+
break;
|
|
331
|
+
case "CONS": {
|
|
332
|
+
let member = rootDef.typePatternGraph.addNewNode();
|
|
333
|
+
rel.patterns[1] = rootDef.typePatternGraph.addNewNode({pattern: '[]'}, {"vector-member": [member]});
|
|
334
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode({pattern: '{}'}, {"car": [member], "cdr": [rel.patterns[1]]});
|
|
335
|
+
}; break;
|
|
336
|
+
case "SNOC": {
|
|
337
|
+
let member = rootDef.typePatternGraph.addNewNode();
|
|
338
|
+
rel.patterns[0] = rootDef.typePatternGraph.addNewNode({pattern: '[]'}, {"vector-member": [member]});
|
|
339
|
+
rel.patterns[1] = rootDef.typePatternGraph.addNewNode({pattern: '{}'}, {"car": [member], "cdr": [rel.patterns[0]]});
|
|
340
|
+
}; break;
|
|
341
|
+
// TO DO
|
|
342
|
+
case "null":
|
|
343
|
+
case "DIV":
|
|
344
|
+
case "FDIV":
|
|
345
|
+
rel.patterns = [rootDef.typePatternGraph.addNewNode(), rootDef.typePatternGraph.addNewNode()];
|
|
346
|
+
break;
|
|
347
|
+
default:
|
|
348
|
+
throw new Error(`No definition found for ${rel.ref}`);
|
|
557
349
|
}
|
|
558
|
-
}
|
|
350
|
+
}
|
|
559
351
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
}
|
|
352
|
+
// ==================================================================================
|
|
353
|
+
// ----------------------------------------------------------------------------------
|
|
354
|
+
// 1. Initialize the typePatternGraph and varRefs for each relation
|
|
564
355
|
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
356
|
+
for (const relName in rels) {
|
|
357
|
+
const rootDef = rels[relName];
|
|
358
|
+
rootDef.typePatternGraph = new TypePatternGraph();
|
|
359
|
+
rootDef.varRefs = []; // the list of non-built references as pointers to AST nodes
|
|
360
|
+
augment(rootDef.def, rootDef);
|
|
568
361
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
// 2. Compute DAG of strongly connected components in varRefs
|
|
365
|
+
// A rel_1 -> rel_2 if rel1,varRefs contains a reference to {op: "ref", ref: rel_2}
|
|
366
|
+
|
|
367
|
+
const graph = new Graph(
|
|
368
|
+
// 1st argument: edges
|
|
369
|
+
[].concat(...Object.keys(rels).map( relName =>
|
|
370
|
+
rels[relName].varRefs.map( ({varName}) =>
|
|
371
|
+
({src: relName, dst: varName})))),
|
|
372
|
+
// 2nd argument: vertices
|
|
373
|
+
rels
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
const sccs_ = sccs(graph);
|
|
377
|
+
|
|
378
|
+
const DAGnodes = sccs_.reduce ((nodes, scc) =>
|
|
379
|
+
({...nodes, [scc[0]]: {scc}}), {});
|
|
380
|
+
const fromRelNameToDAGnode = Object.keys(DAGnodes).reduce((map, node) =>
|
|
381
|
+
DAGnodes[node].scc.reduce((map, relName) => ({...map, [relName]: node}), map), {});
|
|
382
|
+
const DAGedges = [].concat(
|
|
383
|
+
...Object.keys(rels).map( x =>
|
|
384
|
+
rels[x].varRefs.map(({ varName }) =>
|
|
385
|
+
({src: fromRelNameToDAGnode[x], dst: fromRelNameToDAGnode[varName]})
|
|
386
|
+
) // don't forget to remove loops
|
|
387
|
+
.filter(({src, dst}) => src !== dst )
|
|
388
|
+
)
|
|
389
|
+
);
|
|
390
|
+
const DAG = new Graph(DAGedges, DAGnodes);
|
|
391
|
+
|
|
392
|
+
// 3. Topological sort of the DAG
|
|
393
|
+
|
|
394
|
+
const sccInOrder = topoOrder(DAG);
|
|
395
|
+
|
|
396
|
+
// 4. For each strongly connected component C in a bottom-up order
|
|
397
|
+
|
|
398
|
+
for (const scc of sccInOrder.reverse()) {
|
|
399
|
+
// console.log(`SCC: { ${DAGnodes[scc].scc} }`);
|
|
400
|
+
|
|
401
|
+
const maxNumberOfIterations = 10;
|
|
402
|
+
|
|
403
|
+
for (let iteration = 1; iteration <= maxNumberOfIterations; iteration++) {
|
|
404
|
+
|
|
405
|
+
// console.log(`>>>>>> Iteration ${iteration} for SCC: { ${DAGnodes[scc].scc} }`);
|
|
406
|
+
// 4.1 For every r in C, compute the new typePatternGraph of r, i.e.:
|
|
407
|
+
|
|
408
|
+
let before = JSON.stringify(DAGnodes[scc].scc.map( relName => {
|
|
409
|
+
const relDef = rels[relName];
|
|
410
|
+
// console.log("-----------------------------------");
|
|
411
|
+
// console.log(relDefToString(relDef));
|
|
412
|
+
rels[relName] = compactRel(relDef,relName);
|
|
413
|
+
// console.log(relDefToString(rels[relName]));
|
|
414
|
+
return relDefToString(rels[relName]);
|
|
415
|
+
}));
|
|
416
|
+
|
|
417
|
+
let after = JSON.stringify(DAGnodes[scc].scc.map( relName => {
|
|
418
|
+
const relDef = compactRel(rels[relName],relName);
|
|
419
|
+
for (let i = 0; i < relDef.varRefs.length; i++) {
|
|
420
|
+
// console.log(` ####### Processing ${relName}(..x${i}=${relDef.varRefs[i].varName}..)`);
|
|
421
|
+
let varRel = relDef.varRefs[i];
|
|
422
|
+
let { varName } = varRel;
|
|
423
|
+
try {
|
|
424
|
+
let varRootDef = rels[varName];
|
|
425
|
+
let varInputPatternId = varRootDef.typePatternGraph.find(varRootDef.def.patterns[0]);
|
|
426
|
+
let varOutputPatternId = varRootDef.typePatternGraph.find(varRootDef.def.patterns[1]);
|
|
427
|
+
let cloned = varRootDef.typePatternGraph.clone([varInputPatternId, varOutputPatternId], relDef.typePatternGraph);
|
|
428
|
+
|
|
429
|
+
relDef.typePatternGraph.unify(`ref:input ${relName}(${varName})`, varRel.inputPatternId, cloned[varInputPatternId]);
|
|
430
|
+
relDef.typePatternGraph.unify("ref:output", varRel.outputPatternId, cloned[varOutputPatternId]);
|
|
431
|
+
} catch (e) {
|
|
432
|
+
console.error(`Type Error in call to ${varName} in definition of ${relName}: lines ${varRel.start?.line}:${varRel.start?.column}...${varRel.end?.line}:${varRel.end?.column}): ${e.message}.`);
|
|
433
|
+
throw e;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
579
436
|
|
|
580
|
-
|
|
437
|
+
rels[relName] = compactRel(relDef,relName);
|
|
438
|
+
|
|
439
|
+
return relDefToString(rels[relName]);
|
|
440
|
+
}));
|
|
581
441
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
if (newPatternEdges[i][label] == i) {
|
|
586
|
-
if (node.type == "product") {
|
|
587
|
-
throw new Error("Loop in product code!");
|
|
588
|
-
}
|
|
589
|
-
node.type = "union";
|
|
442
|
+
if (before == after) {
|
|
443
|
+
// console.log("SUCCESS!");
|
|
444
|
+
break;
|
|
590
445
|
}
|
|
591
|
-
}
|
|
446
|
+
} // while
|
|
447
|
+
|
|
592
448
|
}
|
|
593
|
-
|
|
594
|
-
return { patternNodes: newPatternNodes, patternEdges: newPatternEdges };
|
|
595
449
|
}
|
|
596
450
|
|
|
597
|
-
|
|
598
|
-
|
|
599
451
|
export default { patterns };
|
|
600
452
|
export { patterns };
|
|
601
453
|
|