@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/BIG_PICTURE.md
CHANGED
|
@@ -170,7 +170,7 @@ Functions `bit0`, `bit1`, and `zero` are "constant polymorphic functions", meani
|
|
|
170
170
|
|
|
171
171
|
- constant: if defined, they always return exactly the same value;
|
|
172
172
|
- polymorphic: they are defined for more than one pair of input and output type: functions
|
|
173
|
-
`
|
|
173
|
+
`bit0` and `bit1` are of type `X -> bit`, and `zero` is of type `X -> byte`, where `X`
|
|
174
174
|
denotes an unconstrained type pattern.
|
|
175
175
|
|
|
176
176
|
Functions `inc` and `inc3` are (non-polymorphic) functions of types
|
|
@@ -191,20 +191,29 @@ following constraints:
|
|
|
191
191
|
The type pattern for `Y` is _singleton_, as only one type fits the pattern,
|
|
192
192
|
whereas the other type patterns are not.
|
|
193
193
|
|
|
194
|
-
In this example, we were able to find the most general type pattern for all sub-expressions of the program.
|
|
194
|
+
In this example, we were able to find the most general type pattern for all sub-expressions of the program.
|
|
195
|
+
However, we still do not have a way to find the most general type patterns in the general case.
|
|
196
|
+
This is work in progress.
|
|
195
197
|
|
|
196
198
|
## Universal Schema Registry
|
|
197
199
|
|
|
198
|
-
Since the normalization process for types is fast and deterministic, we can build a universal schema registry that will store all invented types.
|
|
200
|
+
Since the normalization process for types is fast and deterministic, we can build a universal schema registry that will store all invented types.
|
|
201
|
+
The registry will be a key-value store, where the key is the hash of the normalized type, and the value is the normalized type itself.
|
|
199
202
|
|
|
200
203
|
All functions (non-polymorphic and polymorphic) will be renamed by the hash of their normalized definition and stored in the similar key-value store.
|
|
201
204
|
|
|
202
|
-
Non-polymorphic functions can be easily indexed by the hashes of their input and output types so that we can quickly find the function we need, e.g., for autocomplition.
|
|
203
|
-
|
|
205
|
+
Non-polymorphic functions can be easily indexed by the hashes of their input and output types so that we can quickly find the function we need, e.g., for autocomplition.
|
|
206
|
+
Searching for polymorphic functions is more complicated, as we need to find the function whose input and output type patterns fit given types.
|
|
204
207
|
|
|
205
208
|
## Serialization and Compilation
|
|
206
209
|
|
|
207
|
-
The language is designed to transform _codes_, i.e., serialized typed values, i.e., trees accepted by a tree automaton, into other _codes_.
|
|
210
|
+
The language is designed to transform _codes_, i.e., serialized typed values, i.e., trees accepted by a tree automaton, into other _codes_.
|
|
211
|
+
The transformation is done by partial functions as defined in the language.
|
|
212
|
+
The non-recursive and tail-recursive (and even some non-tail recursive) functions can be compiled into deterministic finite (pushdown) transducers.
|
|
213
|
+
|
|
214
|
+
### AND-OR graphs for enconding and decoding codes
|
|
215
|
+
|
|
216
|
+
|
|
208
217
|
|
|
209
218
|
## Linking with Other Languages
|
|
210
219
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { t, in_out } from './index.mjs';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import assert from 'assert';
|
|
4
|
+
|
|
5
|
+
// t(fs.readFileSync("./Examples/blowup.k").toString("utf8"), (annotated) => {
|
|
6
|
+
// // console.log(JSON.stringify(annotated,null,2));
|
|
7
|
+
// const {input,output} = in_out(annotated);
|
|
8
|
+
// console.log(input);
|
|
9
|
+
// console.log(output);
|
|
10
|
+
// assert.equal(output.pattern, '<...>');
|
|
11
|
+
// assert.equal(input.pattern, '(...)');
|
|
12
|
+
// console.log("OK");
|
|
13
|
+
// });
|
|
14
|
+
|
|
15
|
+
t(`
|
|
16
|
+
B = {{} u} A;
|
|
17
|
+
A = < .a, .b A, .c {() z} A, B >;
|
|
18
|
+
A
|
|
19
|
+
`, (annotated) => {
|
|
20
|
+
// console.log(JSON.stringify(annotated,null,2));
|
|
21
|
+
const {input,output} = in_out(annotated);
|
|
22
|
+
console.log(input);
|
|
23
|
+
console.log(output);
|
|
24
|
+
assert.equal(output.type, annotated.representatives["bnat"]);
|
|
25
|
+
assert.equal(input.type, annotated.representatives["pair"]);
|
|
26
|
+
console.log("OK");
|
|
27
|
+
});
|
|
@@ -3,8 +3,10 @@ import fs from 'node:fs';
|
|
|
3
3
|
import assert from 'assert';
|
|
4
4
|
|
|
5
5
|
t(fs.readFileSync("./Examples/bnat-patterns.k").toString("utf8"), (annotated) => {
|
|
6
|
+
// console.log(JSON.stringify(annotated,null,2));
|
|
6
7
|
const {input,output} = in_out(annotated);
|
|
7
|
-
|
|
8
|
-
assert.equal(
|
|
8
|
+
// console.log(output);
|
|
9
|
+
assert.equal(output.type, annotated.representatives["bnat"]);
|
|
10
|
+
assert.equal(input.type, annotated.representatives["pair"]);
|
|
9
11
|
console.log("OK");
|
|
10
12
|
});
|
|
@@ -9,7 +9,32 @@ $b {1 one, () two, () c} .one
|
|
|
9
9
|
|
|
10
10
|
`, (annotated) => {
|
|
11
11
|
const {input,output} = in_out(annotated);
|
|
12
|
-
|
|
13
|
-
assert.equal(
|
|
12
|
+
// console.log({input,output});
|
|
13
|
+
assert.equal(input.type, annotated.representatives["b"]);
|
|
14
|
+
assert.equal(output.type, "int");
|
|
14
15
|
console.log("OK");
|
|
15
|
-
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
t(`
|
|
19
|
+
$a = < int true, bool false > ;
|
|
20
|
+
$a .true
|
|
21
|
+
`, (annotated) => {
|
|
22
|
+
const {input,output} = in_out(annotated);
|
|
23
|
+
console.log({input,output});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
t(`
|
|
27
|
+
x = .x;
|
|
28
|
+
xy = x.y;
|
|
29
|
+
f = {
|
|
30
|
+
{ {5 y} x} xy i,
|
|
31
|
+
{ {true y} x} xy b
|
|
32
|
+
};
|
|
33
|
+
f .b
|
|
34
|
+
`, (annotated) => {
|
|
35
|
+
const {input,output} = in_out(annotated);
|
|
36
|
+
console.log({input,output});
|
|
37
|
+
assert.equal(input.pattern, '(...)');
|
|
38
|
+
assert.equal(output.type, "bool");
|
|
39
|
+
console.log("OK");
|
|
40
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { annotate } from "../index.mjs";
|
|
2
2
|
|
|
3
3
|
function in_out(annotated) {
|
|
4
|
-
const [input,output] = annotated.rels.__main__
|
|
5
|
-
annotated.
|
|
4
|
+
const [input,output] = annotated.rels.__main__.def.patterns.map( (pat) =>
|
|
5
|
+
annotated.rels.__main__.typePatternGraph.get_pattern(pat)
|
|
6
6
|
);
|
|
7
7
|
return { input, output };
|
|
8
8
|
}
|
|
@@ -4,7 +4,7 @@ import assert from 'assert';
|
|
|
4
4
|
|
|
5
5
|
t(fs.readFileSync("./Examples/nat.k").toString("utf8"), (annotated) => {
|
|
6
6
|
const {input,output} = in_out(annotated);
|
|
7
|
-
assert.equal(output.
|
|
8
|
-
assert.equal(input.
|
|
7
|
+
assert.equal(output.type, annotated.representatives["nat"]);
|
|
8
|
+
assert.equal(input.type, annotated.representatives["nat"]);
|
|
9
9
|
console.log("OK");
|
|
10
10
|
});
|
|
@@ -8,7 +8,7 @@ t(`$b = < {} true, {} false > ;
|
|
|
8
8
|
not not
|
|
9
9
|
`, (annotated) => {
|
|
10
10
|
const {input,output} = in_out(annotated);
|
|
11
|
-
assert.equal(input.
|
|
12
|
-
assert.equal(output.
|
|
11
|
+
assert.equal(input.type, annotated.representatives["b"]);
|
|
12
|
+
assert.equal(output.type, annotated.representatives["b"]);
|
|
13
13
|
console.log("OK");
|
|
14
14
|
});
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { t, in_out } from './index.mjs';
|
|
2
2
|
import assert from 'assert';
|
|
3
|
+
import hash from "../hash.mjs";
|
|
4
|
+
|
|
5
|
+
const unitCode = hash('$C0={};');
|
|
3
6
|
|
|
4
7
|
t('{}', (annotated) => {
|
|
5
8
|
const {input,output} = in_out(annotated);
|
|
6
|
-
assert.equal(input.
|
|
7
|
-
assert.equal(output.
|
|
9
|
+
assert.equal(input.pattern, '(...)');
|
|
10
|
+
assert.equal(output.type, unitCode);
|
|
8
11
|
console.log("OK");
|
|
9
12
|
});
|
|
10
13
|
|
|
@@ -12,10 +15,11 @@ t(`
|
|
|
12
15
|
$b = < {} true, {} false > ;
|
|
13
16
|
$pair = { b one, b two } ;
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
{() one, () two} $pair
|
|
16
19
|
`, (annotated) => {
|
|
17
20
|
const {input,output} = in_out(annotated);
|
|
18
|
-
|
|
19
|
-
assert.equal(
|
|
21
|
+
|
|
22
|
+
assert.equal(input.type, annotated.representatives["b"]);
|
|
23
|
+
assert.equal(output.type, annotated.representatives["pair"]);
|
|
20
24
|
console.log("OK");
|
|
21
25
|
});
|
|
@@ -8,7 +8,7 @@ t(`
|
|
|
8
8
|
rlz
|
|
9
9
|
`, (annotated) => {
|
|
10
10
|
const {input,output} = in_out(annotated);
|
|
11
|
-
assert.equal(output.
|
|
12
|
-
assert.equal(input.
|
|
11
|
+
assert.equal(output.type, annotated.representatives["nat"]);
|
|
12
|
+
assert.equal(input.type, annotated.representatives["nat"]);
|
|
13
13
|
console.log("OK");
|
|
14
14
|
});
|
|
@@ -3,26 +3,20 @@ import assert from 'assert';
|
|
|
3
3
|
|
|
4
4
|
t('[]', (annotated) => {
|
|
5
5
|
const {input,output} = in_out(annotated);
|
|
6
|
-
assert.equal(input.
|
|
7
|
-
assert.equal(output.
|
|
6
|
+
assert.equal(input.pattern, '(...)');
|
|
7
|
+
assert.equal(output.pattern, "[]");
|
|
8
8
|
console.log("OK");
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
-
t(
|
|
11
|
+
t("$int [ $int true, false ] .0", (annotated) => {
|
|
12
12
|
const {input,output} = in_out(annotated);
|
|
13
|
-
assert.equal(input.
|
|
14
|
-
assert.equal(output.type, "
|
|
13
|
+
assert.equal(input.type, "int");
|
|
14
|
+
assert.equal(output.type, "bool");
|
|
15
15
|
console.log("OK");
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
t(`$int [ $int true,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
assert.equal(output.code, "bool");
|
|
22
|
-
console.log("OK");
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// assert.throws(() => t(`$int [ $int true, 12 ]`), /Error/);
|
|
26
|
-
// console.log("OK");
|
|
18
|
+
assert.throws(() => t(`$int [ $int true, 12 ]`), /Error/);
|
|
19
|
+
console.log("The both errors are expected...");
|
|
20
|
+
console.log("OK");
|
|
27
21
|
|
|
28
22
|
// t(`[]`);
|
package/Graph.mjs
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
class Graph {
|
|
2
|
+
constructor(edges, vertices = {}) {
|
|
3
|
+
this.edges = edges;
|
|
4
|
+
this.vertices = vertices;
|
|
5
|
+
for (const dir of ['src', 'dst']) {
|
|
6
|
+
this[dir] = {};
|
|
7
|
+
for (let i=0; i < edges.length; i++) {
|
|
8
|
+
const e = edges[i];
|
|
9
|
+
if (vertices[e[dir]] == undefined) {
|
|
10
|
+
vertices[e[dir]] = {
|
|
11
|
+
_rem: "discovered"
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (this[dir][e[dir]] == null) {
|
|
15
|
+
this[dir][e[dir]] = [];
|
|
16
|
+
}
|
|
17
|
+
this[dir][e[dir]].push(i);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function sccs(graph) {
|
|
24
|
+
const stack = [];
|
|
25
|
+
const disc = {};
|
|
26
|
+
const low = {};
|
|
27
|
+
const inStack = {};
|
|
28
|
+
const sccs = [];
|
|
29
|
+
let time = 0;
|
|
30
|
+
|
|
31
|
+
const dfs = (u) => {
|
|
32
|
+
disc[u] = low[u] = time++;
|
|
33
|
+
stack.push(u);
|
|
34
|
+
inStack[u] = true;
|
|
35
|
+
|
|
36
|
+
for (const e of graph.src[u] || []) {
|
|
37
|
+
const v = graph.edges[e].dst;
|
|
38
|
+
if (disc[v] == undefined) {
|
|
39
|
+
dfs(v);
|
|
40
|
+
low[u] = Math.min(low[u], low[v]);
|
|
41
|
+
} else if (inStack[v]) {
|
|
42
|
+
low[u] = Math.min(low[u], disc[v]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (low[u] === disc[u]) {
|
|
47
|
+
const scc = [];
|
|
48
|
+
let w;
|
|
49
|
+
do {
|
|
50
|
+
w = stack.pop();
|
|
51
|
+
inStack[w] = false;
|
|
52
|
+
scc.push(w);
|
|
53
|
+
} while (w !== u);
|
|
54
|
+
sccs.push(scc);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
for (const x in graph.vertices) {
|
|
59
|
+
if (disc[x] == undefined) {
|
|
60
|
+
dfs(x);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return sccs;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function topoOrder(graph){
|
|
67
|
+
const starts = [];
|
|
68
|
+
const result = [];
|
|
69
|
+
const inDegree = {};
|
|
70
|
+
for (const v in graph.vertices) {
|
|
71
|
+
const degree = graph.dst[v]?.length || 0;
|
|
72
|
+
if (degree == 0) {
|
|
73
|
+
starts.push(v);
|
|
74
|
+
} else {
|
|
75
|
+
inDegree[v] = degree;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let x;
|
|
80
|
+
while (x = starts.pop()) {
|
|
81
|
+
result.push(x);
|
|
82
|
+
const outs = graph.src[x] || [];
|
|
83
|
+
for (const e of outs) {
|
|
84
|
+
const y = graph.edges[e].dst;
|
|
85
|
+
inDegree[y]--;
|
|
86
|
+
if (inDegree[y] == 0) {
|
|
87
|
+
starts.push(y);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export { Graph, sccs, topoOrder };
|
|
95
|
+
export default { Graph, sccs, topoOrder };
|