@fraczak/k 4.0.3 → 5.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 +28 -21
- package/README.md +158 -154
- package/TODO.md +18 -0
- package/TYPING.md +2 -2
- package/export.mjs +177 -0
- package/index.mjs +3 -15
- package/k-repl.cast +1913 -0
- package/k.cast +618 -0
- package/package.json +1 -1
- package/patterns.mjs +22 -8
- package/pretty.mjs +26 -41
- package/repl.mjs +47 -28
- package/run.mjs +5 -1
- package/TYPES.md +0 -32
- package/demo.cast +0 -1772
- package/demo.gif +0 -0
- package/demo2.cast +0 -1705
- package/demo_optimized.gif +0 -0
- package/sc.py +0 -25
package/package.json
CHANGED
package/patterns.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import hash from "./hash.mjs";
|
|
|
3
3
|
import { TypePatternGraph } from "./typing.mjs";
|
|
4
4
|
import { Graph, sccs, topoOrder } from "./Graph.mjs";
|
|
5
5
|
import codes from "./codes.mjs";
|
|
6
|
+
import { assignCanonicalNames } from "./export.mjs";
|
|
6
7
|
|
|
7
8
|
const unitCode = codes.unitCode;
|
|
8
9
|
|
|
@@ -101,6 +102,7 @@ function patterns(representatives, rels) {
|
|
|
101
102
|
// representatives:{"{}": "BG", ...}
|
|
102
103
|
// rels: {"rlz": [{op: comp,...}, ...], ...}
|
|
103
104
|
|
|
105
|
+
const relAlias = {};
|
|
104
106
|
|
|
105
107
|
// 1 INITIALIZATION
|
|
106
108
|
// 1.1 initialize patternNodes and rels
|
|
@@ -416,7 +418,7 @@ function patterns(representatives, rels) {
|
|
|
416
418
|
for (const relName in rels) {
|
|
417
419
|
const rootDef = rels[relName];
|
|
418
420
|
rootDef.typePatternGraph = new TypePatternGraph();
|
|
419
|
-
rootDef.varRefs = []; // the list of non-
|
|
421
|
+
rootDef.varRefs = []; // the list of references to non-builtin rels as pointers to AST nodes
|
|
420
422
|
rootDef.patternVars = {};
|
|
421
423
|
augment(rootDef.def, rootDef);
|
|
422
424
|
delete rootDef.patternVars;
|
|
@@ -453,12 +455,16 @@ function patterns(representatives, rels) {
|
|
|
453
455
|
|
|
454
456
|
// 3. Topological sort of the DAG
|
|
455
457
|
|
|
456
|
-
const sccInOrder = topoOrder(DAG);
|
|
458
|
+
const sccInOrder = topoOrder(DAG).reverse();
|
|
457
459
|
|
|
458
460
|
// 4. For each strongly connected component C in a bottom-up order
|
|
461
|
+
|
|
462
|
+
// we will also generate the canonical representation of the relations in C and replace
|
|
463
|
+
// the name to the relation by the hash of the canonical representation
|
|
464
|
+
|
|
465
|
+
// console.log("----- SCC in order", sccInOrder);
|
|
459
466
|
|
|
460
|
-
for (const scc of sccInOrder
|
|
461
|
-
// console.log(`SCC: { ${DAGnodes[scc].scc} }`);
|
|
467
|
+
for (const scc of sccInOrder) {
|
|
462
468
|
|
|
463
469
|
const maxNumberOfIterations = 10;
|
|
464
470
|
|
|
@@ -497,9 +503,7 @@ function patterns(representatives, rels) {
|
|
|
497
503
|
throw e;
|
|
498
504
|
}
|
|
499
505
|
}
|
|
500
|
-
|
|
501
506
|
rels[relName] = compactRel(relDef,relName);
|
|
502
|
-
|
|
503
507
|
return relDefToString(rels[relName]);
|
|
504
508
|
}));
|
|
505
509
|
|
|
@@ -507,9 +511,19 @@ function patterns(representatives, rels) {
|
|
|
507
511
|
// console.log("SUCCESS!");
|
|
508
512
|
break;
|
|
509
513
|
}
|
|
510
|
-
} //
|
|
511
|
-
|
|
514
|
+
} // end of iteration loop
|
|
515
|
+
|
|
516
|
+
DAGnodes[scc].scc.forEach( relName => {
|
|
517
|
+
const relDef = rels[relName];
|
|
518
|
+
const canonical = relDefToString(relDef);
|
|
519
|
+
const h = hash(canonical);
|
|
520
|
+
relAlias[relName] = h;
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
assignCanonicalNames(DAGnodes[scc].scc, rels, relAlias);
|
|
524
|
+
|
|
512
525
|
}
|
|
526
|
+
return relAlias;
|
|
513
527
|
}
|
|
514
528
|
|
|
515
529
|
export default { patterns };
|
package/pretty.mjs
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
import { find } from "./codes.mjs";
|
|
2
2
|
import { TypePatternGraph } from "./typing.mjs";
|
|
3
3
|
|
|
4
|
-
function compareAs(fn) {
|
|
5
|
-
return function (a, b) {
|
|
6
|
-
[a, b] = [a, b].map(fn);
|
|
7
|
-
if (a < b) return -1;
|
|
8
|
-
if (a > b) return 1;
|
|
9
|
-
return 0;
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
|
|
13
4
|
const nameRE = /^[a-zA-Z0-9_][a-zA-Z0-9_?!]*$/;
|
|
5
|
+
function pLabel_(label) {
|
|
6
|
+
return nameRE.test(label) ? ` ${label}` : `${JSON.stringify(label)}`;
|
|
7
|
+
}
|
|
8
|
+
function pLabel(label) {
|
|
9
|
+
return nameRE.test(label) ? `${label}` : `${JSON.stringify(label)}`;
|
|
10
|
+
}
|
|
14
11
|
|
|
15
12
|
function prettyCode_labels (representatives, label_ref_map) {
|
|
16
13
|
return Object.keys(label_ref_map)
|
|
17
|
-
.sort(
|
|
14
|
+
.sort()
|
|
18
15
|
.map( (label) => {
|
|
19
|
-
const plabel = nameRE.test(label) ? label : `'${label}'`;
|
|
20
16
|
return `${prettyCode(representatives, {
|
|
21
17
|
code: "ref",
|
|
22
18
|
ref: label_ref_map[label],
|
|
23
|
-
})}
|
|
19
|
+
})}${pLabel_(label)}`;
|
|
24
20
|
})
|
|
25
21
|
.join(", ");
|
|
26
22
|
};
|
|
@@ -46,10 +42,10 @@ function prettyCode (representatives, codeExp) {
|
|
|
46
42
|
}
|
|
47
43
|
};
|
|
48
44
|
|
|
49
|
-
function prettyFilter (
|
|
45
|
+
function prettyFilter ( filter ) {
|
|
50
46
|
const fieldsStr = () => {
|
|
51
47
|
const fields = Object.keys(filter.fields).map( (key) =>
|
|
52
|
-
`${prettyFilter(
|
|
48
|
+
`${prettyFilter(filter.fields[key])}${pLabel_(key)}`
|
|
53
49
|
);
|
|
54
50
|
if (filter.open) fields.push("...");
|
|
55
51
|
return fields.join(", ");
|
|
@@ -57,11 +53,11 @@ function prettyFilter (prettyCode, filter) {
|
|
|
57
53
|
switch (filter.type) {
|
|
58
54
|
|
|
59
55
|
case "code":
|
|
60
|
-
return `$${
|
|
56
|
+
return `$${filter.code}`;
|
|
61
57
|
case "name":
|
|
62
58
|
return filter.name;
|
|
63
59
|
case "vector":
|
|
64
|
-
return `[${prettyFilter(
|
|
60
|
+
return `[${prettyFilter(filter.vector)}]${filter.name ? "=" + filter.name : ""}`;
|
|
65
61
|
case null:
|
|
66
62
|
if (filter.name && Object.keys(filter.fields).length == 0)
|
|
67
63
|
return filter.name;
|
|
@@ -74,12 +70,13 @@ function prettyFilter (prettyCode, filter) {
|
|
|
74
70
|
throw new Error(`Unknown filter type ${filter.type} in ${JSON.stringify(filter)}`);
|
|
75
71
|
}
|
|
76
72
|
|
|
77
|
-
function prettyRel (
|
|
73
|
+
function prettyRel (exp) {
|
|
78
74
|
"use strict";
|
|
79
75
|
const pretty = (exp) => {
|
|
80
76
|
switch (exp.op) {
|
|
81
77
|
case "filter":
|
|
82
|
-
return
|
|
78
|
+
if (exp.filter.type == 'code') return `$${exp.filter.code}`;
|
|
79
|
+
return `?${prettyFilter(exp.filter)}`;
|
|
83
80
|
case "pipe":
|
|
84
81
|
return `|`;
|
|
85
82
|
case "caret":
|
|
@@ -101,27 +98,16 @@ function prettyRel (prettyCode, exp) {
|
|
|
101
98
|
case "dot":
|
|
102
99
|
if ("number" === typeof exp.dot) {
|
|
103
100
|
return `.${exp.dot}`;
|
|
104
|
-
} else
|
|
105
|
-
return `.${exp.dot}`;
|
|
106
|
-
} else {
|
|
107
|
-
return `'${exp.dot}'`;
|
|
108
|
-
}
|
|
109
|
-
break;
|
|
101
|
+
} else
|
|
102
|
+
return `.${pLabel(exp.dot)}`;
|
|
110
103
|
case "code":
|
|
111
|
-
return `$${
|
|
112
|
-
code: "ref",
|
|
113
|
-
ref: exp.code,
|
|
114
|
-
})}`;
|
|
104
|
+
return `$${exp.code}`;
|
|
115
105
|
case "product":
|
|
116
106
|
return (function (labelled) {
|
|
117
107
|
return `{${labelled.join(", ")}}`;
|
|
118
108
|
})(
|
|
119
109
|
exp.product.map(function ({ label, exp }) {
|
|
120
|
-
|
|
121
|
-
return `${pretty(exp)} ${label}`;
|
|
122
|
-
} else {
|
|
123
|
-
return `${pretty(exp)} '${label}'`;
|
|
124
|
-
}
|
|
110
|
+
return `${pretty(exp)}${pLabel_(label)}`;
|
|
125
111
|
})
|
|
126
112
|
);
|
|
127
113
|
}
|
|
@@ -148,25 +134,24 @@ function patterns2filters(typePatternGraph, ...patternIds) {
|
|
|
148
134
|
|
|
149
135
|
// variables - variables which will have to be added as extra filters
|
|
150
136
|
const variables = inDegree.reduce( (variables, degree, i) => {
|
|
151
|
-
if (degree > 1) variables[i] =
|
|
137
|
+
if (degree > 1) variables[i] = true;
|
|
152
138
|
return variables;
|
|
153
139
|
}, {});
|
|
154
140
|
|
|
141
|
+
const filterVars = {};
|
|
155
142
|
const buildFilter = (path, patternId, i) => {
|
|
156
143
|
let named_filter = {};
|
|
157
144
|
const pattern = newTypePatternGraph.get_pattern(patternId);
|
|
158
145
|
if (variables[patternId] && pattern.pattern != 'type') {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
named_filter = { name: name };
|
|
146
|
+
if (filterVars[patternId])
|
|
147
|
+
return { type: 'name', name: filterVars[patternId] };
|
|
148
|
+
filterVars[patternId] = `X${Object.keys(filterVars).length}`;
|
|
149
|
+
named_filter = { name: filterVars[patternId] };
|
|
164
150
|
}
|
|
165
151
|
|
|
166
|
-
|
|
167
152
|
const edges = newTypePatternGraph.edges[patternId];
|
|
168
153
|
const fields = () =>
|
|
169
|
-
Object.keys(edges).reduce( (fields, key) =>{
|
|
154
|
+
Object.keys(edges).sort().reduce( (fields, key) =>{
|
|
170
155
|
fields[key] = buildFilter([...path, key], Object.values(edges[key])[0], i);
|
|
171
156
|
return fields;
|
|
172
157
|
}, {});
|
package/repl.mjs
CHANGED
|
@@ -6,14 +6,17 @@ import k from "./index.mjs";
|
|
|
6
6
|
import {run, closeVector } from "./run.mjs";
|
|
7
7
|
import { prettyCode, prettyRel, patterns2filters } from "./pretty.mjs";
|
|
8
8
|
import { find } from "./codes.mjs";
|
|
9
|
+
import { exportRelation } from "./export.mjs";
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
let DEBUG_FLAG = false;
|
|
12
13
|
|
|
13
14
|
console.log("Very! experimental repl shell for 'k-language'...");
|
|
14
15
|
|
|
15
16
|
const help = function () {
|
|
16
|
-
|
|
17
|
+
console.log(` --debug toggle debug flag: [${DEBUG_FLAG?'ON':'OFF'}]`);
|
|
18
|
+
if (DEBUG_FLAG)
|
|
19
|
+
console.log(" --load loads codes and relations as value");
|
|
17
20
|
console.log(" --c print aliased codes");
|
|
18
21
|
console.log(" --C code print 'code' definition");
|
|
19
22
|
console.log(" --r print relations");
|
|
@@ -88,40 +91,42 @@ function evaluate(line) {
|
|
|
88
91
|
// console.log(kScript);
|
|
89
92
|
val = k.compile("+++\n" + kScript + "\n()")(val);
|
|
90
93
|
printVal();
|
|
91
|
-
} else if (line.match(/^[ \n\t]*--debug$/)) {
|
|
92
94
|
// --debug
|
|
95
|
+
} else if (line.match(/^[ \n\t]*--debug$/)) {
|
|
96
|
+
DEBUG_FLAG = ! DEBUG_FLAG;
|
|
97
|
+
// --load
|
|
98
|
+
} else if (line.match(/^[ \n\t]*--load$/)) {
|
|
93
99
|
val = run.defs;
|
|
94
100
|
console.log(val);
|
|
95
101
|
// --r
|
|
96
102
|
} else if (line.match(/^[ \n\t]*(?:--r)?$/)) {
|
|
97
|
-
console.log(
|
|
103
|
+
console.log("BUILT-IN:", run.builtin);
|
|
104
|
+
console.log("USER-DEFINED:",
|
|
98
105
|
(function (defs, result) {
|
|
99
106
|
if (defs == null) {
|
|
100
107
|
return result;
|
|
101
108
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
})(
|
|
109
|
-
prettyRel.bind(
|
|
110
|
-
null,
|
|
111
|
-
prettyCode.bind(null, defs.representatives)
|
|
112
|
-
)
|
|
113
|
-
);
|
|
109
|
+
|
|
110
|
+
for (const relName in defs.rels) {
|
|
111
|
+
if (relName != "__main__")
|
|
112
|
+
result[relName] = prettyRel(defs.rels[relName].def);
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
114
115
|
})(run.defs, {}));
|
|
115
116
|
// --c
|
|
116
117
|
} else if (line.match(/^[ \n\t]*(?:--c)?$/)) {
|
|
117
118
|
console.log(
|
|
118
119
|
(function (defs, result) {
|
|
119
120
|
for (const codeName of Object.keys(defs.representatives || {})) {
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
const codeRep = defs.representatives[codeName] || codeName;
|
|
122
|
+
if (codeName == codeRep) {
|
|
123
|
+
result[codeName] = prettyCode(
|
|
124
|
+
defs.representatives,
|
|
125
|
+
find(codeRep)
|
|
126
|
+
);
|
|
127
|
+
} else if (! codeName.startsWith(":")) {
|
|
128
|
+
result[codeName] = codeRep;
|
|
129
|
+
}
|
|
125
130
|
}
|
|
126
131
|
return result;
|
|
127
132
|
})(run.defs || {}, {})
|
|
@@ -161,18 +166,33 @@ function evaluate(line) {
|
|
|
161
166
|
const relName = line.match(re__R)[1];
|
|
162
167
|
const rel = run.defs?.rels[relName];
|
|
163
168
|
if (!rel) {
|
|
169
|
+
if (relName in run.builtin) {
|
|
170
|
+
console.log(` -- builtin relation: ${relName}\n ${relName} = ${run.builtin[relName]}`);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
164
173
|
console.log(` -- relation '${relName}' not found`);
|
|
165
174
|
return;
|
|
166
175
|
}
|
|
176
|
+
const canonicalRelName = run.defs.relAlias[relName];
|
|
167
177
|
const filters = patterns2filters(rel.typePatternGraph, ...rel.def.patterns);
|
|
168
178
|
// console.log(filters);
|
|
169
179
|
// console.log(" variables:", JSON.stringify(variables));
|
|
170
180
|
// console.log(JSON.stringify({filters, variables}, null, 2));
|
|
171
181
|
// for (const filter of filters) {
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
console.log(` ${relName} : ${filtersStr[0]} --> ${filtersStr[1]}`);
|
|
175
|
-
console.log(` ${relName} = ${prettyRel(
|
|
182
|
+
const filtersStr = filters.map( x => prettyRel( {op: "filter", filter: x}));
|
|
183
|
+
// console.log(` -- canonical relation name: ${canonicalRelName} --`);
|
|
184
|
+
// console.log(` ${relName} : ${filtersStr[0]} --> ${filtersStr[1]}`);
|
|
185
|
+
// console.log(` ${relName} = ${prettyRel(rel.def)};`);
|
|
186
|
+
// console.log(` ${relName} = ${prettyRel(rel.simplified)};`);
|
|
187
|
+
console.log({
|
|
188
|
+
name: canonicalRelName,
|
|
189
|
+
type: `${filtersStr[0]} --> ${filtersStr[1]}`,
|
|
190
|
+
def: prettyRel(rel.simplified)
|
|
191
|
+
});
|
|
192
|
+
if (DEBUG_FLAG) {
|
|
193
|
+
val = exportRelation(run.defs.rels, run.defs.relAlias, relName);
|
|
194
|
+
console.log(val);
|
|
195
|
+
}
|
|
176
196
|
// }
|
|
177
197
|
// ------ k code
|
|
178
198
|
} else if (!line.match(/^[ \n\t]*(?:#.*)?$/)) {
|
|
@@ -180,12 +200,11 @@ function evaluate(line) {
|
|
|
180
200
|
val = k.run(`+++\n${line}\n()`, val);
|
|
181
201
|
printVal();
|
|
182
202
|
} catch (error) {
|
|
183
|
-
|
|
184
|
-
console.error("ERROR:");
|
|
185
|
-
console.error(e);
|
|
203
|
+
console.error(error.message);
|
|
186
204
|
}
|
|
187
205
|
}
|
|
188
206
|
} catch (e) {
|
|
189
207
|
console.error(e.message);
|
|
208
|
+
console.error(e);
|
|
190
209
|
}
|
|
191
210
|
}
|
package/run.mjs
CHANGED
|
@@ -248,7 +248,9 @@ function run(exp, value) {
|
|
|
248
248
|
}
|
|
249
249
|
case "caret": {
|
|
250
250
|
const result = run(exp.caret, value);
|
|
251
|
-
assert(isOpen(result), "CARET (^): Only an 'open' vector can be closed.");
|
|
251
|
+
// assert(isOpen(result), "CARET (^): Only an 'open' vector can be closed.");
|
|
252
|
+
if (! isOpen(result))
|
|
253
|
+
throw new Error(`Type Error (line: ${exp.end?.line}:${exp.end?.column}): CARET (^): Only 'unboxed' values can be 'boxed'.`)
|
|
252
254
|
return [...result];
|
|
253
255
|
}
|
|
254
256
|
case "filter": {
|
|
@@ -261,5 +263,7 @@ function run(exp, value) {
|
|
|
261
263
|
};
|
|
262
264
|
}
|
|
263
265
|
|
|
266
|
+
run.builtin = builtin;
|
|
267
|
+
|
|
264
268
|
export default run;
|
|
265
269
|
export { run , closeVector };
|
package/TYPES.md
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# What if we concider partial functions as filter-to-filter mappings?
|
|
2
|
-
|
|
3
|
-
## Examples
|
|
4
|
-
|
|
5
|
-
```k
|
|
6
|
-
.x :: ( X x, ... ) -> X
|
|
7
|
-
{ f1 x1, f2 x2, ..., fn xn } :: X -> { f1(X) x1, f2(X) x2, ..., fn(X) xn }
|
|
8
|
-
{ f x } :: X -> < f(X) x, ... >
|
|
9
|
-
< f1, f2, ..., fn > :: X -> f1(X) // f1 == f2 == ... == fn
|
|
10
|
-
[ f1, f2, ..., fn ] :: X -> [f1(X)] // f1 == f2 == ... == fn
|
|
11
|
-
$code ::
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Let's consider the following example:
|
|
15
|
-
|
|
16
|
-
```k
|
|
17
|
-
$nat = < {} _, nat s >;
|
|
18
|
-
z = {{} _}; -- X -> <{} _, ...>
|
|
19
|
-
s = {() s}; -- X -> <X s, ...>
|
|
20
|
-
|
|
21
|
-
add =
|
|
22
|
-
<
|
|
23
|
-
{.x ._ if, .y then} .then,
|
|
24
|
-
{.x .s x, .y s y } add
|
|
25
|
-
>
|
|
26
|
-
;
|
|
27
|
-
|
|
28
|
-
double = {() x, () y} add;
|
|
29
|
-
|
|
30
|
-
z s s $nat double;
|
|
31
|
-
```
|
|
32
|
-
|