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