@fraczak/k 1.3.3 → 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/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 };
@@ -0,0 +1,133 @@
1
+ const rels = {};
2
+ const codes = {
3
+ "{}": {
4
+ code: "product",
5
+ product: {},
6
+ },
7
+ };
8
+
9
+ const identity = {
10
+ op: "identity",
11
+ };
12
+
13
+ function is_identity_rel(rel) {
14
+ return rel.op === "identity";
15
+ }
16
+
17
+ function is_constant_rel(rel) {
18
+ switch (rel.op) {
19
+ case "int":
20
+ case "str":
21
+ return true;
22
+ case "vector":
23
+ return Object.values(rel[rel.op]).every(is_constant_rel);
24
+ case "product":
25
+ return Object.values(rel[rel.op]).every(({ exp }) =>
26
+ is_constant_rel(exp)
27
+ );
28
+ default:
29
+ return false;
30
+ }
31
+ }
32
+
33
+ function is_empty_rel(rel) {
34
+ return rel.op === "union" && rel.union.length === 0;
35
+ }
36
+
37
+ function is_full_rel(rel) {
38
+ if (is_constant_rel(rel)) return true;
39
+ switch (rel.op) {
40
+ case "int":
41
+ case "str":
42
+ case "identity":
43
+ return true;
44
+ case "comp":
45
+ return rel.comp.every(is_full_rel);
46
+ case "vector":
47
+ return Object.values(rel[rel.op]).every(is_full_rel);
48
+ case "product":
49
+ return Object.values(rel[rel.op]).every(({ exp }) => is_full_rel(exp));
50
+ default:
51
+ return false;
52
+ }
53
+ }
54
+
55
+ function comp_first(e1, e2) {
56
+ if (is_identity_rel(e1)) return e2;
57
+ if (is_identity_rel(e2)) return e1;
58
+ if (is_empty_rel(e1)) return e1;
59
+ if (is_empty_rel(e2)) return e2;
60
+ if (e1.op === "comp" && e2.op === "comp")
61
+ return {
62
+ op: "comp",
63
+ comp: [].concat(e1.comp, e2.comp),
64
+ };
65
+ if (e1.op === "comp")
66
+ return {
67
+ op: "comp",
68
+ comp: [].concat(e1.comp, [e2]),
69
+ };
70
+ if (e2.op === "comp")
71
+ return {
72
+ op: "comp",
73
+ comp: [].concat([e1], e2.comp),
74
+ };
75
+ return {
76
+ op: "comp",
77
+ comp: [e1, e2],
78
+ };
79
+ }
80
+
81
+ function comp (e1, e2) {
82
+ const result = comp_first(e1, e2);
83
+ if (result.op !== "comp") return result;
84
+ result.comp = result.comp.reduceRight(
85
+ (c, e) => (c[0] && is_constant_rel(c[0]) && is_full_rel(e) ? c : [e, ...c]),
86
+ []
87
+ );
88
+ return result;
89
+ }
90
+
91
+ function union (rels) {
92
+ const list = [];
93
+ label: for (const rel of rels) {
94
+ const new_rels = rel.op === "union" ? rel.union : [rel];
95
+ for (const new_rel of new_rels) {
96
+ list.push(new_rel);
97
+ if (is_full_rel(new_rel)) break label;
98
+ }
99
+ }
100
+ if (list.length === 1) return list[0];
101
+ return {
102
+ op: "union",
103
+ union: list,
104
+ };
105
+ };
106
+
107
+ function as_ref (codeExp) {
108
+ if (codeExp.code === "ref") return codeExp.ref;
109
+ const newName = `:${Object.keys(codes).length}`;
110
+ codes[newName] = codeExp;
111
+ return newName;
112
+ };
113
+
114
+ function add_rel (name, rel) {
115
+ if (rels[name] == null) rels[name] = [];
116
+ rels[name].push(rel);
117
+ };
118
+
119
+ function add_code (name, code) {
120
+ codes[name] = code;
121
+ }
122
+
123
+ export default {
124
+ identity,
125
+ comp,
126
+ union,
127
+ rels,
128
+ codes,
129
+ add_rel,
130
+ add_code,
131
+ as_ref,
132
+ };
133
+ export { identity, comp, union, rels, codes, add_rel, add_code, as_ref };
package/test.mjs ADDED
@@ -0,0 +1,143 @@
1
+ import k from "./index.mjs";
2
+
3
+ [
4
+ ["ANYTHING...", "()"],
5
+ ["ANYTHING...", '{"ala" name, 23 age}'],
6
+ [
7
+ {
8
+ year: 2002,
9
+ age: 19,
10
+ },
11
+ "[.year, .age]",
12
+ ],
13
+ ["duplicate me", "[(), ()]"],
14
+ ["nesting", "[[[()]]]"],
15
+ ["nesting and accessing", "[[()]] {() nested, .0.0 val}"],
16
+ [
17
+ {
18
+ test: "parse integer",
19
+ },
20
+ "0000",
21
+ ],
22
+ [
23
+ {
24
+ x: 3,
25
+ y: 4,
26
+ },
27
+ "[.y,.x] PLUS",
28
+ ],
29
+ ].map(function ([data, script]) {
30
+ console.log(`k_expression = '${script}';`);
31
+ console.log(`k.run(k_expression,${JSON.stringify(data)});`);
32
+ console.log(`// RETURNS: ${JSON.stringify(k.run(script, data))}`);
33
+ return console.log("");
34
+ });
35
+
36
+ let k_expression =
37
+ '{.name nom, <[.age, 18] GT .0, [.age, 12] GT "ado", "enfant"> age}';
38
+
39
+ let k_fn = k.compile(k_expression);
40
+
41
+ console.log(`var k_fn = k.compile('${k_expression}');`);
42
+
43
+ console.log("");
44
+
45
+ [
46
+ {
47
+ age: 23,
48
+ name: "Emily",
49
+ },
50
+ {
51
+ age: 16,
52
+ name: "Katrina",
53
+ },
54
+ {
55
+ age: 2,
56
+ name: "Mark",
57
+ },
58
+ ].map(function (data) {
59
+ console.log(`k_fn(${JSON.stringify(data)});`);
60
+ console.log(`// RETURNS: ${JSON.stringify(k_fn(data))}`);
61
+ return console.log("");
62
+ });
63
+
64
+ k_expression = "$t = < i: int, t: [ t ] > ; <$t, $int>";
65
+
66
+ k_fn = k.compile(k_expression);
67
+
68
+ console.log(`var k_fn = k.compile('${k_expression}');`);
69
+
70
+ console.log("");
71
+
72
+ [
73
+ 1,
74
+ {
75
+ i: 1,
76
+ },
77
+ [
78
+ {
79
+ i: 2,
80
+ },
81
+ {
82
+ i: 3,
83
+ },
84
+ {
85
+ t: [],
86
+ },
87
+ ],
88
+ {
89
+ t: [
90
+ {
91
+ i: 2,
92
+ },
93
+ {
94
+ i: 3,
95
+ },
96
+ {
97
+ t: [],
98
+ },
99
+ ],
100
+ },
101
+ ].map(function (data) {
102
+ console.log(`k_fn(${JSON.stringify(data)});`);
103
+ console.log(`// RETURNS: ${JSON.stringify(k_fn(data))}`);
104
+ return console.log("");
105
+ });
106
+
107
+ k_expression = "$ < < [ int ] ints, [ bool ] bools > list, string None>";
108
+
109
+ k_fn = k.compile(k_expression);
110
+
111
+ console.log(`var k_fn = k.compile('${k_expression}');`);
112
+
113
+ console.log("");
114
+
115
+ [
116
+ {
117
+ None: "None",
118
+ },
119
+ {
120
+ list: {
121
+ ints: [],
122
+ },
123
+ },
124
+ {
125
+ list: {
126
+ ints: [1, 2, 3],
127
+ },
128
+ },
129
+ {
130
+ list: {
131
+ bools: [true, false],
132
+ },
133
+ },
134
+ {
135
+ list: {
136
+ bools: [true, 0],
137
+ },
138
+ },
139
+ ].map(function (data) {
140
+ console.log(`k_fn(${JSON.stringify(data)});`);
141
+ console.log(`// RETURNS: ${JSON.stringify(k_fn(data))}`);
142
+ return console.log("");
143
+ });
package/codes.coffee DELETED
@@ -1,81 +0,0 @@
1
-
2
- are_different = (classes, representatives, name1, name2, codes) ->
3
- # console.log {classes, representatives, name1, name2, codes}
4
- return false if name1 is name2
5
- code1 = codes[name1]
6
- code2 = codes[name2]
7
- # console.log {name1, code1, name2, code2}
8
- return true unless code1.code is code2.code
9
- switch code1.code
10
- when "union", "product"
11
- [fields1,fields2] = [code1, code2]. map (code) ->
12
- do (arg = code[code.code]) ->
13
- Object.keys(arg).reduce (fields, label) ->
14
- fields[label] = representatives[arg[label]] ? arg[label]
15
- fields
16
- , {}
17
- return true unless Object.keys(fields1).length is Object.keys(fields2).length
18
- for field,rep of fields1
19
- # console.log {field,rep1:rep,rep2:fields2[field]}
20
- return true unless fields2[field] is rep
21
- when "vector"
22
- [arg1,arg2] = [code1, code2]. map ({vector}) ->
23
- representatives[vector] ? vector
24
- return true unless arg1 is arg2
25
- false
26
-
27
- minimize = (codes) ->
28
- names = Object.keys codes
29
- classes = {}
30
- classes["{}"] = names
31
- representatives = names.reduce (representatives, name) ->
32
- representatives[name] = "{}"
33
- representatives
34
- , {}
35
- changed = true
36
- while changed
37
- changed = false
38
- for name1, eq_names of classes
39
- code = codes[name1]
40
- [eq_names, dif_names] = eq_names.reduce ([eq_names, dif_names], name2) ->
41
- if are_different(classes, representatives, name1, name2, codes)
42
- dif_names.push name2
43
- else
44
- eq_names.push name2
45
- [eq_names,dif_names]
46
- , [[],[]]
47
- classes[name1] = eq_names
48
- do (new_rep = dif_names[0]) ->
49
- if new_rep?
50
- changed = true
51
- classes[new_rep] = dif_names
52
- for x in dif_names
53
- representatives[x] = new_rep
54
- {classes,representatives}
55
-
56
- normalize = (label_ref_map, representatives) ->
57
- # console.log {label_ref_map, representatives}
58
- Object.keys(label_ref_map).reduce (result, label) ->
59
- result[label] = do (name = label_ref_map[label]) ->
60
- representatives[name] ? name
61
- result
62
- , {}
63
-
64
- normalizeAll = (codes,representatives) ->
65
- names = Object.keys codes
66
- normalized = names.reduce (normalized, name) ->
67
- if name is representatives[name]
68
- do (code = codes[name]) ->
69
- switch code.code
70
- when "union", "product"
71
- normalized[name] = { code: code.code }
72
- normalized[name][code.code] = normalize code[code.code], representatives
73
- when "vector"
74
- normalized[name] = {code:"vector", vector: representatives[code.vector] ? code.vector}
75
-
76
- normalized
77
- , {}
78
-
79
- module.exports = {minimize,normalize,normalizeAll}
80
-
81
-
package/codes.js DELETED
@@ -1,134 +0,0 @@
1
- // Generated by CoffeeScript 2.7.0
2
- (function() {
3
- var are_different, minimize, normalize, normalizeAll;
4
-
5
- are_different = function(classes, representatives, name1, name2, codes) {
6
- var arg1, arg2, code1, code2, field, fields1, fields2, rep;
7
- if (name1 === name2) {
8
- // console.log {classes, representatives, name1, name2, codes}
9
- return false;
10
- }
11
- code1 = codes[name1];
12
- code2 = codes[name2];
13
- if (code1.code !== code2.code) {
14
- // console.log {name1, code1, name2, code2}
15
- return true;
16
- }
17
- switch (code1.code) {
18
- case "union":
19
- case "product":
20
- [fields1, fields2] = [code1, code2].map(function(code) {
21
- return (function(arg) {
22
- return Object.keys(arg).reduce(function(fields, label) {
23
- var ref;
24
- fields[label] = (ref = representatives[arg[label]]) != null ? ref : arg[label];
25
- return fields;
26
- }, {});
27
- })(code[code.code]);
28
- });
29
- if (Object.keys(fields1).length !== Object.keys(fields2).length) {
30
- return true;
31
- }
32
- for (field in fields1) {
33
- rep = fields1[field];
34
- if (fields2[field] !== rep) {
35
-
36
- // console.log {field,rep1:rep,rep2:fields2[field]}
37
- return true;
38
- }
39
- }
40
- break;
41
- case "vector":
42
- [arg1, arg2] = [code1, code2].map(function({vector}) {
43
- var ref;
44
- return (ref = representatives[vector]) != null ? ref : vector;
45
- });
46
- if (arg1 !== arg2) {
47
- return true;
48
- }
49
- }
50
- return false;
51
- };
52
-
53
- minimize = function(codes) {
54
- var changed, classes, code, dif_names, eq_names, name1, names, representatives;
55
- names = Object.keys(codes);
56
- classes = {};
57
- classes["{}"] = names;
58
- representatives = names.reduce(function(representatives, name) {
59
- representatives[name] = "{}";
60
- return representatives;
61
- }, {});
62
- changed = true;
63
- while (changed) {
64
- changed = false;
65
- for (name1 in classes) {
66
- eq_names = classes[name1];
67
- code = codes[name1];
68
- [eq_names, dif_names] = eq_names.reduce(function([eq_names, dif_names], name2) {
69
- if (are_different(classes, representatives, name1, name2, codes)) {
70
- dif_names.push(name2);
71
- } else {
72
- eq_names.push(name2);
73
- }
74
- return [eq_names, dif_names];
75
- }, [[], []]);
76
- classes[name1] = eq_names;
77
- (function(new_rep) {
78
- var i, len, results, x;
79
- if (new_rep != null) {
80
- changed = true;
81
- classes[new_rep] = dif_names;
82
- results = [];
83
- for (i = 0, len = dif_names.length; i < len; i++) {
84
- x = dif_names[i];
85
- results.push(representatives[x] = new_rep);
86
- }
87
- return results;
88
- }
89
- })(dif_names[0]);
90
- }
91
- }
92
- return {classes, representatives};
93
- };
94
-
95
- normalize = function(label_ref_map, representatives) {
96
- // console.log {label_ref_map, representatives}
97
- return Object.keys(label_ref_map).reduce(function(result, label) {
98
- result[label] = (function(name) {
99
- var ref;
100
- return (ref = representatives[name]) != null ? ref : name;
101
- })(label_ref_map[label]);
102
- return result;
103
- }, {});
104
- };
105
-
106
- normalizeAll = function(codes, representatives) {
107
- var names, normalized;
108
- names = Object.keys(codes);
109
- return normalized = names.reduce(function(normalized, name) {
110
- if (name === representatives[name]) {
111
- (function(code) {
112
- var ref;
113
- switch (code.code) {
114
- case "union":
115
- case "product":
116
- normalized[name] = {
117
- code: code.code
118
- };
119
- return normalized[name][code.code] = normalize(code[code.code], representatives);
120
- case "vector":
121
- return normalized[name] = {
122
- code: "vector",
123
- vector: (ref = representatives[code.vector]) != null ? ref : code.vector
124
- };
125
- }
126
- })(codes[name]);
127
- }
128
- return normalized;
129
- }, {});
130
- };
131
-
132
- module.exports = {minimize, normalize, normalizeAll};
133
-
134
- }).call(this);
package/index.coffee DELETED
@@ -1,28 +0,0 @@
1
- {parse} = require "./parser.js"
2
- run = require "./run"
3
- t = require "./codes"
4
-
5
-
6
- finalize = (codes) ->
7
- representatives = t.minimize(codes).representatives
8
- codes = t.normalizeAll codes, representatives
9
-
10
- {codes, representatives}
11
-
12
-
13
- compile = (script) ->
14
- do ({defs,exp} = parse script) ->
15
- # console.log defs
16
- {codes, representatives} = finalize defs.codes
17
- # console.log {codes, representatives}
18
- run.defs = {codes, representatives, rels: defs.rels}
19
-
20
- (data) -> run exp, data
21
-
22
- compile.doc = "Transforms k-script (string) into a function"
23
-
24
- runScriptOnData = (script, data) ->
25
- compile(script) data
26
- runScriptOnData.doc = "Run 'script' (string) on 'data': (script,data) -> data"
27
-
28
- module.exports = {compile, run: runScriptOnData, parse}
package/index.js DELETED
@@ -1,49 +0,0 @@
1
- // Generated by CoffeeScript 2.7.0
2
- (function() {
3
- var compile, finalize, parse, run, runScriptOnData, t;
4
-
5
- ({parse} = require("./parser.js"));
6
-
7
- run = require("./run");
8
-
9
- t = require("./codes");
10
-
11
- finalize = function(codes) {
12
- var representatives;
13
- representatives = t.minimize(codes).representatives;
14
- codes = t.normalizeAll(codes, representatives);
15
- return {codes, representatives};
16
- };
17
-
18
- compile = function(script) {
19
- return (function({defs, exp}) {
20
- var codes, representatives;
21
- // console.log defs
22
- ({codes, representatives} = finalize(defs.codes));
23
- // console.log {codes, representatives}
24
- run.defs = {
25
- codes,
26
- representatives,
27
- rels: defs.rels
28
- };
29
- return function(data) {
30
- return run(exp, data);
31
- };
32
- })(parse(script));
33
- };
34
-
35
- compile.doc = "Transforms k-script (string) into a function";
36
-
37
- runScriptOnData = function(script, data) {
38
- return compile(script)(data);
39
- };
40
-
41
- runScriptOnData.doc = "Run 'script' (string) on 'data': (script,data) -> data";
42
-
43
- module.exports = {
44
- compile,
45
- run: runScriptOnData,
46
- parse
47
- };
48
-
49
- }).call(this);