@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 CHANGED
@@ -4,8 +4,9 @@
4
4
 
5
5
  From javascript:
6
6
 
7
- var k = require("@fraczak/k"),
8
- fn = k.compile("<.name,.nom,'?'>");
7
+ import k from "@fraczak/k";
8
+
9
+ const fn = k.compile("<.name,.nom,'?'>");
9
10
  console.log([{name:"x"},{nom:"y"},{}].map(fn));
10
11
  // returns: [ "x", "y", "?" ]
11
12
 
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": "1.3.4",
3
+ "version": "2.0.0",
4
4
  "description": "k-language for JSON-like data transformation",
5
- "main": "index.js",
5
+ "main": "index.mjs",
6
6
  "scripts": {
7
- "prepare": "coffee -c symbol-table.coffee; jiwson parser.jison",
8
- "prepublishOnly": "coffee -c *.coffee; echo '#!/usr/bin/env node' | cat - k.js > k.sh; echo '#!/usr/bin/env node' | cat - repl.js > repl.sh;",
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.sh",
20
- "k-repl": "./repl.sh"
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
@@ -1,6 +1,6 @@
1
1
  %{
2
2
 
3
- var s = require("./symbol-table");
3
+ import s from "./symbol-table.mjs";
4
4
 
5
5
  function fromEscString(escString) {
6
6
  const isSingleQuoted = escString.startsWith("'");
@@ -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
- var s = require("./symbol-table");
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
- if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
761
- exports.parser = parser;
762
- exports.Parser = parser.Parser;
763
- exports.parse = function () { return parser.parse.apply(parser, arguments); };
764
- exports.main = function commonjsMain (args) {
765
- if (!args[1]) {
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 };