@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/pretty.mjs
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { find } from "./codes.mjs";
|
|
2
|
+
import { TypePatternGraph } from "./typing.mjs";
|
|
3
|
+
|
|
1
4
|
function compareAs(fn) {
|
|
2
5
|
return function (a, b) {
|
|
3
6
|
[a, b] = [a, b].map(fn);
|
|
@@ -9,12 +12,12 @@ function compareAs(fn) {
|
|
|
9
12
|
|
|
10
13
|
const nameRE = /^[a-zA-Z0-9_][a-zA-Z0-9_?!]*$/;
|
|
11
14
|
|
|
12
|
-
function prettyCode_labels (
|
|
15
|
+
function prettyCode_labels (representatives, label_ref_map) {
|
|
13
16
|
return Object.keys(label_ref_map)
|
|
14
17
|
.sort( compareAs((x) => x) )
|
|
15
18
|
.map( (label) => {
|
|
16
19
|
const plabel = nameRE.test(label) ? label : `'${label}'`;
|
|
17
|
-
return `${prettyCode(
|
|
20
|
+
return `${prettyCode(representatives, {
|
|
18
21
|
code: "ref",
|
|
19
22
|
ref: label_ref_map[label],
|
|
20
23
|
})} ${plabel}`;
|
|
@@ -22,21 +25,21 @@ function prettyCode_labels (codes, representatives, label_ref_map) {
|
|
|
22
25
|
.join(", ");
|
|
23
26
|
};
|
|
24
27
|
|
|
25
|
-
function prettyCode (
|
|
28
|
+
function prettyCode (representatives, codeExp) {
|
|
26
29
|
switch (codeExp.code) {
|
|
27
30
|
case "ref":
|
|
28
31
|
const name = representatives[codeExp.ref] || codeExp.ref;
|
|
29
32
|
if (name.startsWith(":")) {
|
|
30
|
-
return prettyCode(
|
|
33
|
+
return prettyCode(representatives, find(name));
|
|
31
34
|
} else {
|
|
32
35
|
return name;
|
|
33
36
|
}
|
|
34
37
|
case "product":
|
|
35
|
-
return `{${prettyCode_labels(
|
|
38
|
+
return `{${prettyCode_labels(representatives, codeExp.product)}}`;
|
|
36
39
|
case "union":
|
|
37
|
-
return `< ${prettyCode_labels(
|
|
40
|
+
return `< ${prettyCode_labels(representatives, codeExp.union)} >`;
|
|
38
41
|
case "vector":
|
|
39
|
-
return `[${prettyCode(
|
|
42
|
+
return `[${prettyCode(representatives, {code:'ref', ref:codeExp.vector})}]`;
|
|
40
43
|
// return `[${representatives[codeExp.vector] || codeExp.vector}]`;
|
|
41
44
|
default:
|
|
42
45
|
return ":error";
|
|
@@ -44,28 +47,31 @@ function prettyCode (codes, representatives, codeExp) {
|
|
|
44
47
|
};
|
|
45
48
|
|
|
46
49
|
function prettyFilter (prettyCode, filter) {
|
|
47
|
-
const fieldsStr = (
|
|
48
|
-
Object.keys(
|
|
49
|
-
`${
|
|
50
|
-
)
|
|
50
|
+
const fieldsStr = () => {
|
|
51
|
+
const fields = Object.keys(filter.fields).map( (key) =>
|
|
52
|
+
`${prettyFilter(prettyCode, filter.fields[key])} ${key}`
|
|
53
|
+
);
|
|
54
|
+
if (filter.open) fields.push("...");
|
|
55
|
+
return fields.join(", ");
|
|
56
|
+
}
|
|
51
57
|
switch (filter.type) {
|
|
58
|
+
|
|
59
|
+
case "code":
|
|
60
|
+
return `$${prettyCode({code: "ref",ref: filter.code,})}`;
|
|
52
61
|
case "name":
|
|
53
62
|
return filter.name;
|
|
54
|
-
case "code":
|
|
55
|
-
return `$${prettyCode({
|
|
56
|
-
code: "ref",
|
|
57
|
-
ref: filter.code,
|
|
58
|
-
})}`;
|
|
59
63
|
case "vector":
|
|
60
|
-
return `[${prettyFilter(prettyCode, filter.vector)}]`;
|
|
64
|
+
return `[${prettyFilter(prettyCode, filter.vector)}]${filter.name ? "=" + filter.name : ""}`;
|
|
61
65
|
case null:
|
|
62
|
-
|
|
66
|
+
if (filter.name && Object.keys(filter.fields).length == 0)
|
|
67
|
+
return filter.name;
|
|
68
|
+
return `(${fieldsStr()})${filter.name ? "=" + filter.name : ""}`;
|
|
63
69
|
case "union":
|
|
64
|
-
return `<${fieldsStr(
|
|
70
|
+
return `<${fieldsStr()}>${filter.name ? "=" + filter.name : ""}`;
|
|
65
71
|
case "product":
|
|
66
|
-
return `{${fieldsStr(
|
|
72
|
+
return `{${fieldsStr()}}${filter.name ? "=" + filter.name : ""}`;
|
|
67
73
|
}
|
|
68
|
-
throw new Error(
|
|
74
|
+
throw new Error(`Unknown filter type ${filter.type} in ${JSON.stringify(filter)}`);
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
function prettyRel (prettyCode, exp) {
|
|
@@ -123,5 +129,76 @@ function prettyRel (prettyCode, exp) {
|
|
|
123
129
|
return pretty(exp);
|
|
124
130
|
};
|
|
125
131
|
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
|
|
133
|
+
function patterns2filters(typePatternGraph, ...patternIds) {
|
|
134
|
+
const newTypePatternGraph = new TypePatternGraph();
|
|
135
|
+
const renamed = typePatternGraph.clone(patternIds, newTypePatternGraph);
|
|
136
|
+
const newPatternIds = patternIds.map((id) => newTypePatternGraph.find(renamed[id]));
|
|
137
|
+
|
|
138
|
+
// inDegree - all open patterns, i.e. (...), {...}, <...>,
|
|
139
|
+
// with inDegree > 1 are variables
|
|
140
|
+
const inDegree = newTypePatternGraph.patterns.nodes.map((x) => 0);
|
|
141
|
+
newPatternIds.forEach( id => inDegree[id]++);
|
|
142
|
+
newTypePatternGraph.edges.forEach( outEdges =>
|
|
143
|
+
Object.values( outEdges ).forEach( destMap =>
|
|
144
|
+
Object.values(destMap).forEach( dst =>
|
|
145
|
+
inDegree[dst]++ )
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
// variables - variables which will have to be added as extra filters
|
|
150
|
+
const variables = inDegree.reduce( (variables, degree, i) => {
|
|
151
|
+
if (degree > 1) variables[i] = "fresh";
|
|
152
|
+
return variables;
|
|
153
|
+
}, {});
|
|
154
|
+
|
|
155
|
+
const buildFilter = (path, patternId, i) => {
|
|
156
|
+
let named_filter = {};
|
|
157
|
+
const pattern = newTypePatternGraph.get_pattern(patternId);
|
|
158
|
+
if (variables[patternId] && pattern.pattern != 'type') {
|
|
159
|
+
const name = `X${patternId}`;
|
|
160
|
+
if (variables[patternId] == "done")
|
|
161
|
+
return { type: 'name', name: name };
|
|
162
|
+
variables[patternId] = "done";
|
|
163
|
+
named_filter = { name: name };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
const edges = newTypePatternGraph.edges[patternId];
|
|
168
|
+
const fields = () =>
|
|
169
|
+
Object.keys(edges).reduce( (fields, key) =>{
|
|
170
|
+
fields[key] = buildFilter([...path, key], Object.values(edges[key])[0], i);
|
|
171
|
+
return fields;
|
|
172
|
+
}, {});
|
|
173
|
+
|
|
174
|
+
switch (pattern.pattern) {
|
|
175
|
+
case 'type':
|
|
176
|
+
return {type: "code", code: pattern.type, ...named_filter};
|
|
177
|
+
case '[]':
|
|
178
|
+
return {
|
|
179
|
+
type: "vector",
|
|
180
|
+
vector: buildFilter([...path, "vector-member"], Object.values(edges["vector-member"])[0], i),
|
|
181
|
+
...named_filter
|
|
182
|
+
};
|
|
183
|
+
case '(...)':
|
|
184
|
+
return { type: null, open: true, fields: fields(), ...named_filter };
|
|
185
|
+
case '{...}':
|
|
186
|
+
return { type: 'product', open: true, fields: fields(), ...named_filter };
|
|
187
|
+
case '<...>':
|
|
188
|
+
return { type: 'union', open: true, fields: fields(), ...named_filter };
|
|
189
|
+
case '()':
|
|
190
|
+
return { type: null, fields: fields(), ...named_filter };
|
|
191
|
+
case '{}':
|
|
192
|
+
return { type: 'product', fields: fields(), ...named_filter };
|
|
193
|
+
case '<>':
|
|
194
|
+
return { type: 'union', fields: fields(), ...named_filter };
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const filters = newPatternIds.map( (id, i) => buildFilter([], id, i) );
|
|
199
|
+
return filters;
|
|
200
|
+
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export default { prettyCode, prettyRel, patterns2filters };
|
|
204
|
+
export { prettyCode, prettyRel, patterns2filters };
|
package/repl.mjs
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import k from "./index.mjs";
|
|
4
4
|
import {run, closeVector } from "./run.mjs";
|
|
5
|
-
import { prettyCode, prettyRel } from "./pretty.mjs";
|
|
5
|
+
import { prettyCode, prettyRel, patterns2filters } from "./pretty.mjs";
|
|
6
|
+
import { find } from "./codes.mjs";
|
|
6
7
|
|
|
7
8
|
import fs from "node:fs";
|
|
8
9
|
|
|
@@ -13,13 +14,16 @@ console.log("Very! experimental repl shell for 'k-language'...");
|
|
|
13
14
|
const help = function () {
|
|
14
15
|
console.log(" --h print help");
|
|
15
16
|
console.log(" --a print codes and relations");
|
|
16
|
-
console.log(" --c print codes");
|
|
17
|
+
console.log(" --c print aliased codes");
|
|
18
|
+
console.log(" --C CODE print code definition");
|
|
17
19
|
console.log(" --r print rels");
|
|
18
|
-
console.log(" --
|
|
20
|
+
console.log(" --p pretty-print last value");
|
|
21
|
+
console.log(" --pp print last value via node.js 'console.log'");
|
|
19
22
|
console.log(" --s reg store the last value in register 'reg'");
|
|
20
23
|
console.log(" --g reg get the value from register 'reg'");
|
|
21
24
|
console.log(" --regs print registers names");
|
|
22
25
|
console.log(" --l file.k load 'file.k'");
|
|
26
|
+
console.log(" --x rel Print out the type of 'rel'");
|
|
23
27
|
};
|
|
24
28
|
|
|
25
29
|
help();
|
|
@@ -27,6 +31,8 @@ help();
|
|
|
27
31
|
const re__l = /^[ \n\t]*(?:--l[ ]+)(.+)[ ]*?$/;
|
|
28
32
|
const re__s = /^[ \n\t]*(?:--s[ ]+)(.+)[ ]*?$/;
|
|
29
33
|
const re__g = /^[ \n\t]*(?:--g[ ]+)(.+)[ ]*?$/;
|
|
34
|
+
const re__x = /^[ \n\t]*(?:--x[ ]+)(.+)[ ]*?$/;
|
|
35
|
+
const re__C = /^[ \n\t]*(?:--C[ ]+)(.+)[ ]*?$/;
|
|
30
36
|
|
|
31
37
|
const registers = {};
|
|
32
38
|
|
|
@@ -41,93 +47,125 @@ const registers = {};
|
|
|
41
47
|
buffer = [last];
|
|
42
48
|
todo = [todo, ...rest];
|
|
43
49
|
for (i = 0, len = todo.length; i < len; i++) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
val
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
for (relName in ref1) {
|
|
75
|
-
relExps = ref1[relName];
|
|
76
|
-
result[relName] = relExps.map(prettyRel);
|
|
50
|
+
try {
|
|
51
|
+
line = todo[i];
|
|
52
|
+
if (val === void 0) {
|
|
53
|
+
val = {};
|
|
54
|
+
}
|
|
55
|
+
if (line.match(/^[ \n\t]*(?:--h)?$/)) {
|
|
56
|
+
// --h
|
|
57
|
+
help();
|
|
58
|
+
} else if (line.match(/^[ \n\t]*\^$/)) {
|
|
59
|
+
val = closeVector(val);
|
|
60
|
+
console.log(`=> ${JSON.stringify(val)}`);
|
|
61
|
+
} else if (line.match(re__l)) {
|
|
62
|
+
// --l
|
|
63
|
+
file = line.match(re__l)[1];
|
|
64
|
+
console.log(` -- loading file: ${file} ...`);
|
|
65
|
+
kScript = fs.readFileSync(file).toString();
|
|
66
|
+
console.log(` ----------------------------- compiling file: ${file} ...`);
|
|
67
|
+
// console.log(kScript);
|
|
68
|
+
val = k.compile("+++" + kScript + "\n()")(val);
|
|
69
|
+
console.log(`=> ${JSON.stringify(val)}`);
|
|
70
|
+
} else if (line.match(/^[ \n\t]*(?:--a)?$/)) {
|
|
71
|
+
// --a
|
|
72
|
+
val = run.defs;
|
|
73
|
+
console.log(val);
|
|
74
|
+
// --r
|
|
75
|
+
} else if (line.match(/^[ \n\t]*(?:--r)?$/)) {
|
|
76
|
+
console.log(
|
|
77
|
+
(function (defs, result) {
|
|
78
|
+
if (defs == null) {
|
|
79
|
+
return result;
|
|
77
80
|
}
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (defs == null) {
|
|
91
|
-
return result;
|
|
92
|
-
}
|
|
93
|
-
ref1 = defs.codes;
|
|
94
|
-
for (codeName in ref1) {
|
|
95
|
-
codeExp = ref1[codeName];
|
|
96
|
-
result[codeName] = prettyCode(
|
|
97
|
-
defs.codes,
|
|
98
|
-
defs.representatives,
|
|
99
|
-
codeExp
|
|
81
|
+
return (function (prettyRel) {
|
|
82
|
+
var ref1, relName;
|
|
83
|
+
ref1 = defs.rels;
|
|
84
|
+
for (relName in ref1) {
|
|
85
|
+
result[relName] = prettyRel(ref1[relName].def);
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
})(
|
|
89
|
+
prettyRel.bind(
|
|
90
|
+
null,
|
|
91
|
+
prettyCode.bind(null, defs.representatives)
|
|
92
|
+
)
|
|
100
93
|
);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
94
|
+
})(run.defs, {}));
|
|
95
|
+
// --c
|
|
96
|
+
} else if (line.match(/^[ \n\t]*(?:--c)?$/)) {
|
|
97
|
+
console.log(
|
|
98
|
+
(function (defs, result) {
|
|
99
|
+
for (const codeName of Object.keys(defs.representatives || {})) {
|
|
100
|
+
const codeExp = find(defs.representatives[codeName] || codeName);
|
|
101
|
+
result[codeName] = prettyCode(
|
|
102
|
+
defs.representatives,
|
|
103
|
+
codeExp
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
})(run.defs || {}, {})
|
|
108
|
+
);
|
|
109
|
+
// --C
|
|
110
|
+
} else if (line.match(re__C)) {
|
|
111
|
+
let codeName = line.match(re__C)[1];
|
|
112
|
+
if (codeName.startsWith("?"))
|
|
113
|
+
codeName = codeName.slice(1);
|
|
114
|
+
if (codeName.startsWith("$"))
|
|
115
|
+
codeName = codeName.slice(1);
|
|
116
|
+
const canonicalName = run.defs.representatives[codeName] || codeName;
|
|
117
|
+
const codeExp = find( canonicalName );
|
|
118
|
+
console.log(` $ ${canonicalName} = ${prettyCode(run.defs.representatives, codeExp)}; -- ${codeExp.def}`);
|
|
119
|
+
// --pp
|
|
120
|
+
} else if (line.match(/^[ \n\t]*(?:--pp)?$/)) {
|
|
121
|
+
console.log(val);
|
|
105
122
|
// --p
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
} else if (line.match(/^[ \n\t]*(?:--p)?$/)) {
|
|
124
|
+
console.log(JSON.stringify(val, null, 2));
|
|
125
|
+
// --regs
|
|
126
|
+
} else if (line.match(/^[ \n\t]*(?:--regs)?$/)) {
|
|
127
|
+
console.log(` -- registers: ${Object.keys(registers).join(", ")}`);
|
|
128
|
+
// --s
|
|
129
|
+
} else if (line.match(re__s)) {
|
|
130
|
+
let reg = line.match(re__s)[1];
|
|
131
|
+
registers[reg] = val;
|
|
132
|
+
console.log(` -- current value stored in register: '${reg}'`);
|
|
133
|
+
// --g
|
|
134
|
+
} else if (line.match(re__g)) {
|
|
135
|
+
console.log(" -- getting value from register...");
|
|
136
|
+
let reg = line.match(re__g)[1];
|
|
137
|
+
val = registers[reg];
|
|
138
|
+
console.log(val);
|
|
139
|
+
// --x
|
|
140
|
+
} else if (line.match(re__x)) {
|
|
141
|
+
const relName = line.match(re__x)[1];
|
|
142
|
+
const rel = run.defs?.rels[relName];
|
|
143
|
+
if (!rel) {
|
|
144
|
+
console.log(` -- relation '${relName}' not found`);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const filters = patterns2filters(rel.typePatternGraph, ...rel.def.patterns);
|
|
148
|
+
// console.log(filters);
|
|
149
|
+
// console.log(" variables:", JSON.stringify(variables));
|
|
150
|
+
// console.log(JSON.stringify({filters, variables}, null, 2));
|
|
151
|
+
// for (const filter of filters) {
|
|
152
|
+
const pcodef= prettyCode.bind(null, run.defs.representatives);
|
|
153
|
+
const filtersStr = filters.map( x => prettyRel(pcodef, {op: "filter", filter: x}));
|
|
154
|
+
console.log(` ${relName} : ${filtersStr[0]} --> ${filtersStr[1]}`);
|
|
155
|
+
// }
|
|
156
|
+
// ------ k code
|
|
157
|
+
} else if (!line.match(/^[ \n\t]*(?:#.*)?$/)) {
|
|
158
|
+
try {
|
|
159
|
+
val = k.run(`+++ ${line}\n ()`, val);
|
|
160
|
+
console.log(`=> ${JSON.stringify(val)}`);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
e = error;
|
|
163
|
+
console.error("ERROR:");
|
|
164
|
+
console.error(e);
|
|
165
|
+
}
|
|
130
166
|
}
|
|
167
|
+
} catch (e) {
|
|
168
|
+
console.error(e.message);
|
|
131
169
|
}
|
|
132
170
|
}
|
|
133
171
|
}
|
package/run.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import assert from "assert";
|
|
2
|
+
import { find } from "./codes.mjs";
|
|
2
3
|
|
|
3
4
|
const modulo = (a, b) => ((+a % (b = +b)) + b) % b;
|
|
4
5
|
const valid = (x) => (isNaN(x) ? undefined : x);
|
|
@@ -54,13 +55,14 @@ const builtin = {
|
|
|
54
55
|
},
|
|
55
56
|
FDIV: ([x, y]) => x / y,
|
|
56
57
|
CONCAT: (strs) => strs.join(""),
|
|
58
|
+
toVEC: (str) => [...str],
|
|
57
59
|
true: () => true,
|
|
58
60
|
false: () => false,
|
|
59
61
|
null: () => null,
|
|
60
62
|
toJSON: (x) => JSON.stringify(x),
|
|
61
63
|
fromJSON: (x) => JSON.parse(x),
|
|
62
|
-
CONS: (
|
|
63
|
-
SNOC: (x) => (x.length > 1 ?
|
|
64
|
+
CONS: ({car, cdr}) => { try { return [car, ...cdr]; } catch (e) { return undefined; } },
|
|
65
|
+
SNOC: (x) => (x.length > 1 ? {car: x[0], cdr: x.slice(1)} : undefined),
|
|
64
66
|
toDateMsec: (x) => new Date(x).getTime(),
|
|
65
67
|
toDateStr: (x) => new Date(x).toISOString(),
|
|
66
68
|
};
|
|
@@ -72,12 +74,9 @@ const codes = {
|
|
|
72
74
|
};
|
|
73
75
|
|
|
74
76
|
function verify(code, value) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// console.log {code,value, representatives, defCodes}
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
77
|
+
"use strict";
|
|
78
|
+
if (code == null) return false;
|
|
79
|
+
code = find(code);
|
|
81
80
|
switch (code.code) {
|
|
82
81
|
case "vector":
|
|
83
82
|
if (!Array.isArray(value)) return false;
|
|
@@ -98,11 +97,8 @@ function verify(code, value) {
|
|
|
98
97
|
if (fields.length !== 1) return false;
|
|
99
98
|
return verify(code.union[fields[0]], value[fields[0]]);
|
|
100
99
|
}
|
|
101
|
-
default:
|
|
102
|
-
|
|
103
|
-
if (c != null) return verify(c, value);
|
|
104
|
-
return codes[code](value);
|
|
105
|
-
}
|
|
100
|
+
default:
|
|
101
|
+
return codes[code.code](value);
|
|
106
102
|
}
|
|
107
103
|
}
|
|
108
104
|
|
|
@@ -131,10 +127,10 @@ function run(exp, value) {
|
|
|
131
127
|
case "str":
|
|
132
128
|
case "int":
|
|
133
129
|
return exp[exp.op];
|
|
134
|
-
case "ref":
|
|
130
|
+
case "ref": {
|
|
135
131
|
const defn = run.defs.rels[exp.ref];
|
|
136
|
-
if (defn !=
|
|
137
|
-
exp = defn
|
|
132
|
+
if (defn != undefined) {
|
|
133
|
+
exp = defn.def;
|
|
138
134
|
continue;
|
|
139
135
|
}
|
|
140
136
|
const builtin_func = builtin[exp.ref];
|
|
@@ -142,6 +138,7 @@ function run(exp, value) {
|
|
|
142
138
|
return builtin_func(value);
|
|
143
139
|
}
|
|
144
140
|
throw(`Unknown ref: '${exp.ref}'`);
|
|
141
|
+
}
|
|
145
142
|
case "dot":
|
|
146
143
|
// a hack to allow something like 'null . null' or '0 . 0' to work by returning unit
|
|
147
144
|
if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
package/symbol-table.mjs
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
},
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
const identity = {
|
|
10
|
-
op: "identity",
|
|
11
|
-
};
|
|
1
|
+
import hash from "./hash.mjs";
|
|
2
|
+
|
|
3
|
+
const unitCode = hash('$C0={};');
|
|
4
|
+
|
|
5
|
+
const identity = {op: "identity"}
|
|
12
6
|
|
|
13
7
|
function is_identity_rel(rel) {
|
|
14
8
|
return rel.op === "identity";
|
|
@@ -46,7 +40,9 @@ function is_full_rel(rel) {
|
|
|
46
40
|
case "vector":
|
|
47
41
|
return Object.values(rel[rel.op]).every(is_full_rel);
|
|
48
42
|
case "product":
|
|
49
|
-
return Object.values(rel[rel.op]).every(({ exp }) =>
|
|
43
|
+
return Object.values(rel[rel.op]).every(({ exp }) =>
|
|
44
|
+
is_full_rel(exp)
|
|
45
|
+
);
|
|
50
46
|
default:
|
|
51
47
|
return false;
|
|
52
48
|
}
|
|
@@ -81,7 +77,7 @@ function comp_first(e1, e2) {
|
|
|
81
77
|
};
|
|
82
78
|
}
|
|
83
79
|
|
|
84
|
-
function comp
|
|
80
|
+
function comp(e1, e2) {
|
|
85
81
|
const result = comp_first(e1, e2);
|
|
86
82
|
if (result.op !== "comp") return result;
|
|
87
83
|
result.comp = result.comp.reduceRight(
|
|
@@ -91,7 +87,8 @@ function comp (e1, e2) {
|
|
|
91
87
|
return result;
|
|
92
88
|
}
|
|
93
89
|
|
|
94
|
-
|
|
90
|
+
|
|
91
|
+
function union(rels) {
|
|
95
92
|
const list = [];
|
|
96
93
|
label: for (const rel of rels) {
|
|
97
94
|
const new_rels = rel.op === "union" ? rel.union : [rel];
|
|
@@ -105,32 +102,38 @@ function union (rels) {
|
|
|
105
102
|
op: "union",
|
|
106
103
|
union: list,
|
|
107
104
|
};
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
function as_ref (codeExp) {
|
|
111
|
-
if (codeExp.code === "ref") return codeExp.ref;
|
|
112
|
-
const newName = `:${Object.keys(codes).length}`;
|
|
113
|
-
codes[newName] = codeExp;
|
|
114
|
-
return newName;
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
function add_rel (name, rel) {
|
|
118
|
-
if (rels[name] == null) rels[name] = [];
|
|
119
|
-
rels[name].push(rel);
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
function add_code (name, code) {
|
|
123
|
-
codes[name] = code;
|
|
124
105
|
}
|
|
125
106
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
107
|
+
class SymbolTable {
|
|
108
|
+
constructor() {
|
|
109
|
+
this.rels = {}; // name -> {def: rel_exp}
|
|
110
|
+
this.codes = {
|
|
111
|
+
[unitCode]: {
|
|
112
|
+
code: "product",
|
|
113
|
+
product: {},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
as_ref(codeExp) {
|
|
119
|
+
if (codeExp.code === "ref") return codeExp.ref;
|
|
120
|
+
const newName = `:${Object.keys(this.codes).length}`;
|
|
121
|
+
this.codes[newName] = codeExp;
|
|
122
|
+
return newName;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
add_rel(name, rel) {
|
|
126
|
+
if (this.rels[name] != undefined)
|
|
127
|
+
console.error(`SymbolTable: rel ${name} already defined (lines ${rel.start?.line}:${rel.start?.column}...${rel.end?.line}:${rel.end?.column})`);
|
|
128
|
+
|
|
129
|
+
this.rels[name] = {def: rel};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
add_code(name, code) {
|
|
133
|
+
this.codes[name] = code;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export default { SymbolTable, comp, union, identity };
|
|
138
|
+
export { SymbolTable, comp, union, identity };
|
|
139
|
+
|
package/test-filters.mjs
CHANGED
|
@@ -23,7 +23,7 @@ const annotated = k.annotate(`
|
|
|
23
23
|
const test1 = unify_with_code(
|
|
24
24
|
annotated.codes,
|
|
25
25
|
annotated.representatives["pair"],
|
|
26
|
-
annotated.rels['f1']
|
|
26
|
+
annotated.rels['f1'].def.filter,
|
|
27
27
|
{}
|
|
28
28
|
);
|
|
29
29
|
console.log(JSON.stringify(test1, null, 2));
|
|
@@ -31,7 +31,7 @@ console.log(JSON.stringify(test1, null, 2));
|
|
|
31
31
|
const test2 = unify_with_code(
|
|
32
32
|
annotated.codes,
|
|
33
33
|
annotated.representatives["pair"],
|
|
34
|
-
annotated.rels['f2']
|
|
34
|
+
annotated.rels['f2'].def.filter,
|
|
35
35
|
{}
|
|
36
36
|
);
|
|
37
37
|
console.log(JSON.stringify(test2, null, 2));
|
|
@@ -39,7 +39,7 @@ console.log(JSON.stringify(test2, null, 2));
|
|
|
39
39
|
const test3 = unify_with_code(
|
|
40
40
|
annotated.codes,
|
|
41
41
|
annotated.representatives["list"],
|
|
42
|
-
annotated.rels['f3']
|
|
42
|
+
annotated.rels['f3'].def.filter,
|
|
43
43
|
{}
|
|
44
44
|
);
|
|
45
45
|
console.log(JSON.stringify(test3, null, 2));
|
package/typing-test.mjs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import t from './typing.mjs';
|
|
2
|
+
// const t = await import('./typing.mjs');
|
|
3
|
+
const g = new t.typePatternGraph();
|
|
4
|
+
|
|
5
|
+
const pu = {pattern: '(...)', fields: []};
|
|
6
|
+
|
|
7
|
+
// x = .x; { { 5 x } x i, { true x } x b }
|
|
8
|
+
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
|
9
|
+
|
|
10
|
+
for (var i = 0; i < 16; i++) { g.addNewNode(pu); }
|
|
11
|
+
|
|
12
|
+
g.addNewNode({pattern: '(...)'}, {x: [1]}); // 16
|
|
13
|
+
g.unify("y:input", 0,16); // 17
|
|
14
|
+
|
|
15
|
+
//
|
|
16
|
+
g.unify('main:input',2,3,4,9,10); // 18
|
|
17
|
+
|
|
18
|
+
g.addNewNode({pattern: '{}'}, {i: [8], b: [14]}); // 19
|
|
19
|
+
g.unify("main:output", 15,19); // 20
|
|
20
|
+
|
|
21
|
+
g.unify('comp:chain',6,7); // 21
|
|
22
|
+
g.unify('comp:chain',12,13); // 22
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
// {5 x}
|
|
26
|
+
g.addNewNode({pattern: '<...>'}, {x: [5]}); // 23
|
|
27
|
+
g.unify('variant:output',6,23); // 24
|
|
28
|
+
|
|
29
|
+
// {true x}
|
|
30
|
+
g.addNewNode({pattern: '<...>'}, {x: [11]}); // 25
|
|
31
|
+
g.unify('variant:output',12,25); // 26
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
// 5
|
|
35
|
+
g.addNewNode({pattern: 'type', type: 'int'}); // 27
|
|
36
|
+
g.unify('5:outout',5,27); // 28
|
|
37
|
+
|
|
38
|
+
// true
|
|
39
|
+
g.addNewNode({pattern: 'type', type: 'bool'}); // 29
|
|
40
|
+
g.unify('true:output',11,29); // 30
|