@fraczak/k 1.3.4 → 2.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/README.md +3 -2
- package/codes.mjs +104 -0
- package/index.mjs +35 -0
- package/k.mjs +92 -0
- package/package.json +6 -9
- package/parser.jison +1 -1
- package/{parser.js → parser.mjs} +9 -17
- package/pretty.mjs +95 -0
- package/repl.mjs +112 -0
- package/run.mjs +142 -0
- package/symbol-table.mjs +133 -0
- package/test.mjs +143 -0
- package/codes.coffee +0 -81
- package/codes.js +0 -134
- package/index.coffee +0 -28
- package/index.js +0 -49
- package/k.coffee +0 -59
- package/k.js +0 -93
- package/k.sh +0 -94
- package/pretty.coffee +0 -74
- package/pretty.js +0 -106
- package/repl.coffee +0 -62
- package/repl.js +0 -101
- package/repl.sh +0 -102
- package/run.coffee +0 -117
- package/run.js +0 -229
- package/symbol-table.coffee +0 -90
- package/symbol-table.js +0 -165
- package/test.coffee +0 -68
- package/test.js +0 -161
package/README.md
CHANGED
package/codes.mjs
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
function are_different(classes, representatives, name1, name2, codes) {
|
|
2
|
+
if (name1 === name2) return false;
|
|
3
|
+
const code1 = codes[name1];
|
|
4
|
+
const code2 = codes[name2];
|
|
5
|
+
if (code1.code !== code2.code) return true;
|
|
6
|
+
switch (code1.code) {
|
|
7
|
+
case "union":
|
|
8
|
+
case "product":
|
|
9
|
+
const [fields1, fields2] = [code1, code2].map((code) => {
|
|
10
|
+
const arg = code[code.code];
|
|
11
|
+
return Object.keys(arg).reduce((fields, label) => {
|
|
12
|
+
const ref = representatives[arg[label]];
|
|
13
|
+
fields[label] = ref != null ? ref : arg[label];
|
|
14
|
+
return fields;
|
|
15
|
+
}, {});
|
|
16
|
+
});
|
|
17
|
+
if (Object.keys(fields1).length !== Object.keys(fields2).length)
|
|
18
|
+
return true;
|
|
19
|
+
|
|
20
|
+
for (const field in fields1) {
|
|
21
|
+
if (fields2[field] !== fields1[field]) return true;
|
|
22
|
+
}
|
|
23
|
+
break;
|
|
24
|
+
case "vector":
|
|
25
|
+
const [arg1, arg2] = [code1, code2].map(
|
|
26
|
+
({ vector }) => representatives[vector] || vector
|
|
27
|
+
);
|
|
28
|
+
if (arg1 !== arg2) return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function minimize(codes) {
|
|
34
|
+
const names = Object.keys(codes);
|
|
35
|
+
const classes = {};
|
|
36
|
+
classes["{}"] = names;
|
|
37
|
+
const representatives = names.reduce((representatives, name) => {
|
|
38
|
+
representatives[name] = "{}";
|
|
39
|
+
return representatives;
|
|
40
|
+
}, {});
|
|
41
|
+
let changed = true;
|
|
42
|
+
while (changed) {
|
|
43
|
+
changed = false;
|
|
44
|
+
for (const name1 in classes) {
|
|
45
|
+
const [eq_names, dif_names] = classes[name1].reduce(
|
|
46
|
+
([eq_names, dif_names], name2) => {
|
|
47
|
+
if (are_different(classes, representatives, name1, name2, codes)) {
|
|
48
|
+
dif_names.push(name2);
|
|
49
|
+
} else {
|
|
50
|
+
eq_names.push(name2);
|
|
51
|
+
}
|
|
52
|
+
return [eq_names, dif_names];
|
|
53
|
+
},
|
|
54
|
+
[[], []]
|
|
55
|
+
);
|
|
56
|
+
classes[name1] = eq_names;
|
|
57
|
+
|
|
58
|
+
if (dif_names.length > 0) {
|
|
59
|
+
const new_rep = dif_names[0];
|
|
60
|
+
changed = true;
|
|
61
|
+
classes[new_rep] = dif_names;
|
|
62
|
+
dif_names.forEach((name) => (representatives[name] = new_rep));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { classes, representatives };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalize(label_ref_map, representatives) {
|
|
70
|
+
return Object.keys(label_ref_map).reduce((result, label) => {
|
|
71
|
+
const name = label_ref_map[label];
|
|
72
|
+
result[label] = representatives[name] || name;
|
|
73
|
+
return result;
|
|
74
|
+
}, {});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function normalizeAll(codes, representatives) {
|
|
78
|
+
return Object.keys(codes).reduce(function (normalized, name) {
|
|
79
|
+
if (name === representatives[name]) {
|
|
80
|
+
const code = codes[name];
|
|
81
|
+
|
|
82
|
+
switch (code.code) {
|
|
83
|
+
case "union":
|
|
84
|
+
case "product":
|
|
85
|
+
normalized[name] = { code: code.code };
|
|
86
|
+
normalized[name][code.code] = normalize(
|
|
87
|
+
code[code.code],
|
|
88
|
+
representatives
|
|
89
|
+
);
|
|
90
|
+
break;
|
|
91
|
+
case "vector":
|
|
92
|
+
normalized[name] = {
|
|
93
|
+
code: "vector",
|
|
94
|
+
vector: representatives[code.vector] || code.vector,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return normalized;
|
|
100
|
+
}, {});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default { minimize, normalize, normalizeAll };
|
|
104
|
+
export { minimize, normalize, normalizeAll };
|
package/index.mjs
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { parse } from "./parser.mjs";
|
|
2
|
+
|
|
3
|
+
import run from "./run.mjs";
|
|
4
|
+
|
|
5
|
+
import t from "./codes.mjs";
|
|
6
|
+
|
|
7
|
+
function finalize(codes) {
|
|
8
|
+
const representatives = t.minimize(codes).representatives;
|
|
9
|
+
return {
|
|
10
|
+
codes: t.normalizeAll(codes, representatives),
|
|
11
|
+
representatives,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function compile(script) {
|
|
16
|
+
const { defs, exp } = parse(script);
|
|
17
|
+
const { codes, representatives } = finalize(defs.codes);
|
|
18
|
+
run.defs = {
|
|
19
|
+
codes,
|
|
20
|
+
representatives,
|
|
21
|
+
rels: defs.rels,
|
|
22
|
+
};
|
|
23
|
+
return run.bind(null, exp);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
compile.doc = "Transforms k-script (string) into a function";
|
|
27
|
+
|
|
28
|
+
function runScriptOnData(script, data) {
|
|
29
|
+
return compile(script)(data);
|
|
30
|
+
}
|
|
31
|
+
runScriptOnData.doc = "Run 'script' (string) on 'data': (script,data) -> data";
|
|
32
|
+
|
|
33
|
+
export default { compile, run: runScriptOnData, parse };
|
|
34
|
+
|
|
35
|
+
export { compile, runScriptOnData as run, parse };
|
package/k.mjs
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import k from "./index.mjs";
|
|
5
|
+
|
|
6
|
+
const splice = [].splice;
|
|
7
|
+
|
|
8
|
+
const prog = process.argv[1];
|
|
9
|
+
|
|
10
|
+
let kScript, jsonStream, oneJson;
|
|
11
|
+
|
|
12
|
+
({ kScript, jsonStream, oneJson } = (function (oneJson, args) {
|
|
13
|
+
let e;
|
|
14
|
+
try {
|
|
15
|
+
kScript = (function (arg) {
|
|
16
|
+
if (arg == null) {
|
|
17
|
+
throw new Error();
|
|
18
|
+
}
|
|
19
|
+
if (arg === "-k") {
|
|
20
|
+
return fs.readFileSync(args.shift()).toString("utf8");
|
|
21
|
+
} else {
|
|
22
|
+
return arg;
|
|
23
|
+
}
|
|
24
|
+
})(args.shift());
|
|
25
|
+
kScript = k.compile(kScript);
|
|
26
|
+
jsonStream = (function (arg) {
|
|
27
|
+
if (arg === "-1") {
|
|
28
|
+
oneJson = true;
|
|
29
|
+
arg = args.shift();
|
|
30
|
+
}
|
|
31
|
+
if (arg == null) {
|
|
32
|
+
return process.stdin;
|
|
33
|
+
}
|
|
34
|
+
return fs.createReadStream(arg);
|
|
35
|
+
})(args.shift());
|
|
36
|
+
return { kScript, jsonStream, oneJson };
|
|
37
|
+
} catch (error) {
|
|
38
|
+
e = error;
|
|
39
|
+
console.error(e);
|
|
40
|
+
console.error(`Usage: ${prog} ( k-expr | -k k-file ) [ -1 ] [ json-file ]`);
|
|
41
|
+
console.error(` E.g., echo '{\"a\": 12}' | ${prog} '[(),()]'`);
|
|
42
|
+
return process.exit(-1);
|
|
43
|
+
}
|
|
44
|
+
})(false, process.argv.slice(2)));
|
|
45
|
+
|
|
46
|
+
if (oneJson) {
|
|
47
|
+
(function (buffer) {
|
|
48
|
+
jsonStream.on("data", function (data) {
|
|
49
|
+
return buffer.push(data);
|
|
50
|
+
});
|
|
51
|
+
return jsonStream.on("end", function () {
|
|
52
|
+
var e;
|
|
53
|
+
try {
|
|
54
|
+
return console.log(
|
|
55
|
+
JSON.stringify(kScript(JSON.parse(buffer.join(""))))
|
|
56
|
+
);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
e = error;
|
|
59
|
+
return console.error(e);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
})([]);
|
|
63
|
+
} else {
|
|
64
|
+
(function (buffer, line) {
|
|
65
|
+
return jsonStream.on("data", function (data) {
|
|
66
|
+
var e, first, i, json, last, len, ref, rest, results, todo;
|
|
67
|
+
[first, ...rest] = data.toString("utf8").split("\n");
|
|
68
|
+
buffer.push(first);
|
|
69
|
+
if (rest.length > 0) {
|
|
70
|
+
todo = buffer.join("");
|
|
71
|
+
(ref = rest), ([...rest] = ref), ([last] = splice.call(rest, -1));
|
|
72
|
+
buffer = [last];
|
|
73
|
+
todo = [todo, ...rest];
|
|
74
|
+
results = [];
|
|
75
|
+
for (i = 0, len = todo.length; i < len; i++) {
|
|
76
|
+
json = todo[i];
|
|
77
|
+
if (!json.match(/^[ \n\t]*(?:#.*)?$/)) {
|
|
78
|
+
try {
|
|
79
|
+
console.log(JSON.stringify(kScript(JSON.parse(json))));
|
|
80
|
+
} catch (error) {
|
|
81
|
+
e = error;
|
|
82
|
+
console.error(`Problem [line ${line}]: '${json}'`);
|
|
83
|
+
console.error(e);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
results.push((line = line + 1));
|
|
87
|
+
}
|
|
88
|
+
return results;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
})([], 0);
|
|
92
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fraczak/k",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "k-language for JSON-like data transformation",
|
|
5
|
-
"main": "index.
|
|
5
|
+
"main": "index.mjs",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"prepare": "
|
|
8
|
-
"
|
|
9
|
-
"all": "coffee -c *.coffee; npm run prepare; npm run prepublishOnly",
|
|
10
|
-
"test": "coffee -c symbol-table.coffee; jiwson parser.jison; coffee test.coffee"
|
|
7
|
+
"prepare": "jiwson -m es6 parser.jison -o parser.mjs",
|
|
8
|
+
"test": "node test.mjs"
|
|
11
9
|
},
|
|
12
10
|
"repository": {
|
|
13
11
|
"type": "git",
|
|
@@ -16,11 +14,10 @@
|
|
|
16
14
|
"author": "Wojciech Fraczak",
|
|
17
15
|
"license": "ISC",
|
|
18
16
|
"bin": {
|
|
19
|
-
"k": "./k.
|
|
20
|
-
"k-repl": "./repl.
|
|
17
|
+
"k": "./k.mjs",
|
|
18
|
+
"k-repl": "./repl.mjs"
|
|
21
19
|
},
|
|
22
20
|
"devDependencies": {
|
|
23
|
-
"coffeescript": "^2.7.0",
|
|
24
21
|
"jiwson": "^0.1.1"
|
|
25
22
|
}
|
|
26
23
|
}
|
package/parser.jison
CHANGED
package/{parser.js → parser.mjs}
RENAMED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
/* parser generated by jison 0.1.1 */
|
|
2
3
|
/*
|
|
3
4
|
Returns a Parser object of the following structure:
|
|
@@ -74,7 +75,7 @@
|
|
|
74
75
|
|
|
75
76
|
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
import s from "./symbol-table.mjs";
|
|
78
79
|
|
|
79
80
|
function fromEscString(escString) {
|
|
80
81
|
const isSingleQuoted = escString.startsWith("'");
|
|
@@ -756,20 +757,11 @@ Parser.prototype = parser;parser.Parser = Parser;
|
|
|
756
757
|
return new Parser;
|
|
757
758
|
})();
|
|
758
759
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
console.log('Usage: '+args[0]+' FILE');
|
|
767
|
-
process.exit(1);
|
|
768
|
-
}
|
|
769
|
-
var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8");
|
|
770
|
-
return exports.parser.parse(source);
|
|
771
|
-
};
|
|
772
|
-
if (typeof module !== 'undefined' && require.main === module) {
|
|
773
|
-
exports.main(process.argv.slice(1));
|
|
760
|
+
const ___parser = parser;
|
|
761
|
+
const ___Parser = parser.Parser;
|
|
762
|
+
const ___parse = parser.parse.bind(parser);
|
|
763
|
+
export {
|
|
764
|
+
___parser as parser,
|
|
765
|
+
___Parser as Parser,
|
|
766
|
+
___parse as parse
|
|
774
767
|
}
|
|
775
|
-
}
|
package/pretty.mjs
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
function compareAs(fn) {
|
|
2
|
+
return function (a, b) {
|
|
3
|
+
[a, b] = [a, b].map(fn);
|
|
4
|
+
if (a < b) return -1;
|
|
5
|
+
if (a > b) return 1;
|
|
6
|
+
return 0;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const nameRE = /^[a-zA-Z0-9_][a-zA-Z0-9_?!]*$/;
|
|
11
|
+
|
|
12
|
+
function prettyCode_labels (codes, representatives, label_ref_map) {
|
|
13
|
+
return Object.keys(label_ref_map)
|
|
14
|
+
.sort( compareAs((x) => x) )
|
|
15
|
+
.map( (label) => {
|
|
16
|
+
const plabel = nameRE.test(label) ? label : `'${label}'`;
|
|
17
|
+
return `${prettyCode(codes, representatives, {
|
|
18
|
+
code: "ref",
|
|
19
|
+
ref: label_ref_map[label],
|
|
20
|
+
})} ${plabel}`;
|
|
21
|
+
})
|
|
22
|
+
.join(", ");
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function prettyCode (codes, representatives, codeExp) {
|
|
26
|
+
switch (codeExp.code) {
|
|
27
|
+
case "ref":
|
|
28
|
+
const name = representatives[codeExp.ref] || codeExp.ref;
|
|
29
|
+
if (name.startsWith(":")) {
|
|
30
|
+
return prettyCode(codes, representatives, codes[name]);
|
|
31
|
+
} else {
|
|
32
|
+
return name;
|
|
33
|
+
}
|
|
34
|
+
case "product":
|
|
35
|
+
return `{${prettyCode_labels(codes, representatives, codeExp.product)}}`;
|
|
36
|
+
case "union":
|
|
37
|
+
return `<${prettyCode_labels(codes, representatives, codeExp.union)}>`;
|
|
38
|
+
case "vector":
|
|
39
|
+
return `[${representatives[codeExp.vector] || codeExp.vector}]`;
|
|
40
|
+
default:
|
|
41
|
+
return ":error";
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function prettyRel (prettyCode, exp) {
|
|
46
|
+
"use strict";
|
|
47
|
+
const pretty = (exp) => {
|
|
48
|
+
switch (exp.op) {
|
|
49
|
+
case "vector":
|
|
50
|
+
return `[${exp.vector.map(pretty).join(", ")}]`;
|
|
51
|
+
case "union":
|
|
52
|
+
return `<${exp.union.map(pretty).join(", ")}>`;
|
|
53
|
+
case "ref":
|
|
54
|
+
return exp.ref;
|
|
55
|
+
case "identity":
|
|
56
|
+
return "()";
|
|
57
|
+
case "comp":
|
|
58
|
+
return exp.comp.map(pretty).join(" ");
|
|
59
|
+
case "str":
|
|
60
|
+
return `'${exp.str}'`;
|
|
61
|
+
case "int":
|
|
62
|
+
return exp.int;
|
|
63
|
+
case "dot":
|
|
64
|
+
if ("number" === typeof exp.dot) {
|
|
65
|
+
return `.${exp.dot}`;
|
|
66
|
+
} else if (nameRE.test(exp.dot)) {
|
|
67
|
+
return `.${exp.dot}`;
|
|
68
|
+
} else {
|
|
69
|
+
return `'${exp.dot}'`;
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
case "code":
|
|
73
|
+
return `$${prettyCode({
|
|
74
|
+
code: "ref",
|
|
75
|
+
ref: exp.code,
|
|
76
|
+
})}`;
|
|
77
|
+
case "product":
|
|
78
|
+
return (function (labelled) {
|
|
79
|
+
return `{${labelled.join(", ")}}`;
|
|
80
|
+
})(
|
|
81
|
+
exp.product.map(function ({ label, exp }) {
|
|
82
|
+
if (nameRE.test(label)) {
|
|
83
|
+
return `${pretty(exp)} ${label}`;
|
|
84
|
+
} else {
|
|
85
|
+
return `${pretty(exp)} '${label}'`;
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
return pretty(exp);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export default { prettyCode, prettyRel };
|
|
95
|
+
export { prettyCode, prettyRel };
|
package/repl.mjs
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import k from "./index.mjs";
|
|
4
|
+
import run from "./run.mjs";
|
|
5
|
+
import { prettyCode, prettyRel } from "./pretty.mjs";
|
|
6
|
+
|
|
7
|
+
import fs from "node:fs";
|
|
8
|
+
|
|
9
|
+
const splice = [].splice;
|
|
10
|
+
|
|
11
|
+
console.log("Very! experimental repl shell for 'k-language'...");
|
|
12
|
+
|
|
13
|
+
const help = function () {
|
|
14
|
+
console.log(" --h print help");
|
|
15
|
+
console.log(" --a print codes and relations");
|
|
16
|
+
console.log(" --c print codes");
|
|
17
|
+
console.log(" --r print rels");
|
|
18
|
+
return console.log(" --l file.k load 'file.k'");
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
help();
|
|
22
|
+
|
|
23
|
+
const re = /^[ \n\t]*(?:--l[ ]+)(.+[^ ])[ ]*?$/;
|
|
24
|
+
|
|
25
|
+
(function (val, buffer) {
|
|
26
|
+
return process.stdin.on("data", function (data) {
|
|
27
|
+
var e, file, first, i, kScript, last, len, line, ref, rest, results, todo;
|
|
28
|
+
[first, ...rest] = data.toString("utf8").split("\n");
|
|
29
|
+
buffer.push(first);
|
|
30
|
+
if (rest.length > 0) {
|
|
31
|
+
todo = buffer.join("");
|
|
32
|
+
(ref = rest), ([...rest] = ref), ([last] = splice.call(rest, -1));
|
|
33
|
+
buffer = [last];
|
|
34
|
+
todo = [todo, ...rest];
|
|
35
|
+
results = [];
|
|
36
|
+
for (i = 0, len = todo.length; i < len; i++) {
|
|
37
|
+
line = todo[i];
|
|
38
|
+
if (val === void 0) {
|
|
39
|
+
val = {};
|
|
40
|
+
}
|
|
41
|
+
if (line.match(/^[ \n\t]*(?:--h)?$/)) {
|
|
42
|
+
results.push(help());
|
|
43
|
+
} else if (line.match(re)) {
|
|
44
|
+
file = line.match(re)[1];
|
|
45
|
+
console.log(`-- loading file: ${file} ...`);
|
|
46
|
+
kScript = fs.readFileSync(file).toString();
|
|
47
|
+
val = k.compile(kScript)(val);
|
|
48
|
+
results.push(console.log(`=> ${JSON.stringify(val)}`));
|
|
49
|
+
} else if (line.match(/^[ \n\t]*(?:--a)?$/)) {
|
|
50
|
+
results.push(console.log(JSON.stringify(run.defs, " ", 2)));
|
|
51
|
+
} else if (line.match(/^[ \n\t]*(?:--r)?$/)) {
|
|
52
|
+
results.push(
|
|
53
|
+
console.log(
|
|
54
|
+
(function (defs, result) {
|
|
55
|
+
if (defs == null) {
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
return (function (prettyRel) {
|
|
59
|
+
var ref1, relExps, relName;
|
|
60
|
+
ref1 = defs.rels;
|
|
61
|
+
for (relName in ref1) {
|
|
62
|
+
relExps = ref1[relName];
|
|
63
|
+
result[relName] = relExps.map(prettyRel);
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
})(
|
|
67
|
+
prettyRel.bind(
|
|
68
|
+
null,
|
|
69
|
+
prettyCode.bind(null, defs.codes, defs.representatives)
|
|
70
|
+
)
|
|
71
|
+
);
|
|
72
|
+
})(run.defs, {})
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
} else if (line.match(/^[ \n\t]*(?:--c)?$/)) {
|
|
76
|
+
results.push(
|
|
77
|
+
console.log(
|
|
78
|
+
(function (defs, result) {
|
|
79
|
+
var codeExp, codeName, ref1;
|
|
80
|
+
if (defs == null) {
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
ref1 = defs.codes;
|
|
84
|
+
for (codeName in ref1) {
|
|
85
|
+
codeExp = ref1[codeName];
|
|
86
|
+
result[codeName] = prettyCode(
|
|
87
|
+
defs.codes,
|
|
88
|
+
defs.representatives,
|
|
89
|
+
codeExp
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
})(run.defs, {})
|
|
94
|
+
)
|
|
95
|
+
);
|
|
96
|
+
} else if (!line.match(/^[ \n\t]*(?:#.*)?$/)) {
|
|
97
|
+
try {
|
|
98
|
+
val = k.run(`${line} ()`, val);
|
|
99
|
+
results.push(console.log(`=> ${JSON.stringify(val)}`));
|
|
100
|
+
} catch (error) {
|
|
101
|
+
e = error;
|
|
102
|
+
console.error("ERROR:");
|
|
103
|
+
results.push(console.error(e));
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
results.push(void 0);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return results;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
})({}, []);
|
package/run.mjs
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
const modulo = (a, b) => ((+a % (b = +b)) + b) % b;
|
|
2
|
+
const valid = (x) => (isNaN(x) ? undefined : x);
|
|
3
|
+
|
|
4
|
+
const builtin = {
|
|
5
|
+
"_log!": (arg) => {
|
|
6
|
+
console.error(`_log!: ${JSON.stringify(arg)}`);
|
|
7
|
+
return arg;
|
|
8
|
+
},
|
|
9
|
+
GT: (args) => {
|
|
10
|
+
const [last, ...rest] = args;
|
|
11
|
+
const [ok, _] = rest.reduce(
|
|
12
|
+
([ok, last], x) => [ok && last > x, x],
|
|
13
|
+
[true, last]
|
|
14
|
+
);
|
|
15
|
+
if (ok) return args;
|
|
16
|
+
},
|
|
17
|
+
EQ: (args) => {
|
|
18
|
+
const [first, ...rest] = args;
|
|
19
|
+
const ok = rest.reduce((ok, x) => ok && first === x, true);
|
|
20
|
+
if (ok) return args;
|
|
21
|
+
},
|
|
22
|
+
PLUS: (args) => valid(args.reduce((res, x) => res + x, 0)),
|
|
23
|
+
TIMES: (args) => valid(args.reduce((res, x) => res * x, 1)),
|
|
24
|
+
DIV: ([x, y]) => {
|
|
25
|
+
const div = Math.floor(x / y);
|
|
26
|
+
const rem = modulo(x, y);
|
|
27
|
+
if (x === div * y + rem) return { div, rem };
|
|
28
|
+
},
|
|
29
|
+
FDIV: ([x, y]) => x / y,
|
|
30
|
+
CONCAT: (strs) => strs.join(""),
|
|
31
|
+
true: () => true,
|
|
32
|
+
false: () => false,
|
|
33
|
+
null: () => null,
|
|
34
|
+
toJSON: (x) => JSON.stringify(x),
|
|
35
|
+
fromJSON: (x) => JSON.parse(x),
|
|
36
|
+
CONS: ([x, y]) => [x, ...y],
|
|
37
|
+
SNOC: (x) => (x.length > 1 ? [x[0], x.slice(1)] : undefined),
|
|
38
|
+
toDateMsec: (x) => new Date(x).getTime(),
|
|
39
|
+
toDateStr: (x) => new Date(x).toISOString(),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const codes = {
|
|
43
|
+
int: (x) => Number.isInteger(x),
|
|
44
|
+
string: (x) => x instanceof String || "string" === typeof x,
|
|
45
|
+
bool: (x) => x === true || x === false,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
function verify(code, value) {
|
|
49
|
+
if (code == null) {
|
|
50
|
+
// representatives = run.defs.representatives
|
|
51
|
+
// defCodes = JSON.stringify run.defs.codes
|
|
52
|
+
// console.log {code,value, representatives, defCodes}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
switch (code.code) {
|
|
56
|
+
case "vector":
|
|
57
|
+
if (!Array.isArray(value)) return false;
|
|
58
|
+
return value.every((x) => verify(code.vector, x));
|
|
59
|
+
case "product":
|
|
60
|
+
if ("object" !== typeof value) return false;
|
|
61
|
+
else {
|
|
62
|
+
const fields = Object.keys(value);
|
|
63
|
+
if (fields.length !== Object.keys(code.product).length) return false;
|
|
64
|
+
return fields.every((label) =>
|
|
65
|
+
verify(code.product[label], value[label])
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
case "union":
|
|
69
|
+
if ("object" !== typeof value) return false;
|
|
70
|
+
else {
|
|
71
|
+
const fields = Object.keys(value);
|
|
72
|
+
if (fields.length !== 1) return false;
|
|
73
|
+
return verify(code.union[fields[0]], value[fields[0]]);
|
|
74
|
+
}
|
|
75
|
+
default: {
|
|
76
|
+
const c = run.defs.codes[run.defs.representatives[code]];
|
|
77
|
+
if (c != null) return verify(c, value);
|
|
78
|
+
return codes[code](value);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function run(exp, value) {
|
|
84
|
+
"use strict";
|
|
85
|
+
if (value === undefined) return;
|
|
86
|
+
switch (exp.op) {
|
|
87
|
+
case "code":
|
|
88
|
+
if (verify(exp.code, value)) {
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
case "identity":
|
|
93
|
+
return value;
|
|
94
|
+
case "str":
|
|
95
|
+
case "int":
|
|
96
|
+
return exp[exp.op];
|
|
97
|
+
case "ref":
|
|
98
|
+
const defn = run.defs.rels[exp.ref];
|
|
99
|
+
if (defn != null) {
|
|
100
|
+
return run(defn[defn.length - 1], value);
|
|
101
|
+
}
|
|
102
|
+
return builtin[exp.ref](value);
|
|
103
|
+
case "dot":
|
|
104
|
+
return value[exp.dot];
|
|
105
|
+
case "comp":
|
|
106
|
+
return exp.comp.reduce((value, exp) => {
|
|
107
|
+
if (value !== undefined) return run(exp, value);
|
|
108
|
+
}, value);
|
|
109
|
+
case "union":
|
|
110
|
+
for (let i = 0, len = exp.union.length; i < len; i++) {
|
|
111
|
+
const result = run(exp.union[i], value);
|
|
112
|
+
if (result !== undefined) {
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
case "vector": {
|
|
118
|
+
const result = [];
|
|
119
|
+
for (let i = 0, len = exp.vector.length; i < len; i++) {
|
|
120
|
+
const r = run(exp.vector[i], value);
|
|
121
|
+
if (r === undefined) return;
|
|
122
|
+
result.push(r);
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
case "product": {
|
|
127
|
+
const result = {};
|
|
128
|
+
for (let i = 0, len = exp.product.length; i < len; i++) {
|
|
129
|
+
const { label, exp: e } = exp.product[i];
|
|
130
|
+
const r = run(e, value);
|
|
131
|
+
if (r === undefined) return;
|
|
132
|
+
result[label] = r;
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
default:
|
|
137
|
+
return console.error(exp.op);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export default run;
|
|
142
|
+
export { run };
|