@fraczak/k 1.1.0 → 1.1.1
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 +13 -9
- package/bnat.k +1 -1
- package/code.k +2 -2
- package/codes.coffee +107 -0
- package/codes.js +167 -0
- package/fib.k +1 -1
- package/index.coffee +15 -1
- package/index.js +19 -2
- package/package.json +2 -1
- package/parser.jison +9 -9
- package/parser.js +9 -9
- package/run.coffee +9 -7
- package/run.js +16 -14
- package/symbol-table.coffee +53 -3
- package/symbol-table.js +90 -4
package/README.md
CHANGED
|
@@ -48,9 +48,9 @@ Elementary partial functions are:
|
|
|
48
48
|
3. There is a number of built-in functions: `GT`, `EQ`, `PLUS`,
|
|
49
49
|
`TIMES`, `MINUS`, `DIV`, `CONCAT`, `toJSON`, `fromJSON`, `CONS`, `SNOC`. For example
|
|
50
50
|
|
|
51
|
-
[1, 2, 3] PLUS --> integer constant 6
|
|
52
|
-
[4, 4] TIMES toJSON --> string constant "16"
|
|
53
|
-
[3, 2] GT --> vector constant [3, 2]
|
|
51
|
+
[1, 2, 3] PLUS --> integer constant function 6
|
|
52
|
+
[4, 4] TIMES toJSON --> string constant function "16"
|
|
53
|
+
[3, 2] GT --> vector constant function [3, 2]
|
|
54
54
|
[3, 4] GT --> is not defined!
|
|
55
55
|
|
|
56
56
|
A more interesting example could be:
|
|
@@ -70,18 +70,22 @@ Elementary partial functions are:
|
|
|
70
70
|
[1,()] GT 1,
|
|
71
71
|
[dec factorial, ()] TIMES
|
|
72
72
|
>;
|
|
73
|
-
{
|
|
73
|
+
{ () x, factorial "x!" }
|
|
74
74
|
|
|
75
75
|
## Value encodings (also called _types_ or _codes_)
|
|
76
76
|
|
|
77
77
|
There are three predefined value encodings: `int`, `string`, and `bool`. The language
|
|
78
78
|
supports `code`-expressions:
|
|
79
79
|
|
|
80
|
-
* product, e.g., `{x: int, y: int, flag: bool}`
|
|
81
|
-
* disjoint union, e.g., `<
|
|
80
|
+
* product, e.g., `{int x, int y, bool flag}` (in JSON-like syntax `{x: int, y: int, flag: bool}`)
|
|
81
|
+
* disjoint union, e.g., `<{} true, {} false>` (in JSON-like syntax `<true: {}, false: {}>`)
|
|
82
82
|
* vector, e.g., `[ int ]` (all elements of the vector use the same encoding)
|
|
83
83
|
|
|
84
|
-
One can define recursive codes. E.g
|
|
84
|
+
One can define recursive codes. E.g.:
|
|
85
|
+
|
|
86
|
+
$ tree = <string leaf, {tree left, tree right} tree>;
|
|
87
|
+
|
|
88
|
+
or, the same in JSON-like notation:
|
|
85
89
|
|
|
86
90
|
$ tree = <leaf: string, tree: {left: tree, right: tree}>;
|
|
87
91
|
|
|
@@ -91,7 +95,7 @@ The above example defines new code called _tree_.
|
|
|
91
95
|
The code can be then used in a `k`-expression as a filter. A `code`-expression
|
|
92
96
|
within `k`-expression is again prefixed by `$`.
|
|
93
97
|
|
|
94
|
-
$tree = <leaf
|
|
98
|
+
$tree = <string leaf, {tree left, tree right} tree>;
|
|
95
99
|
inc = [(),1] PLUS;
|
|
96
100
|
height = $ tree <
|
|
97
101
|
.leaf 0,
|
|
@@ -107,7 +111,7 @@ run the language from command line.
|
|
|
107
111
|
|
|
108
112
|
$ ./node_modules/.bin/k
|
|
109
113
|
... errors ...
|
|
110
|
-
Usage: ./node_modules/.bin/k ( k-expr | -k k-file) [ json-file ]
|
|
114
|
+
Usage: ./node_modules/.bin/k ( k-expr | -k k-file) [ -1 ] [ json-file ]
|
|
111
115
|
E.g., cat '{"a": 10}' | ./node_modules/.bin/k '[(),()]'
|
|
112
116
|
|
|
113
117
|
### Examples
|
package/bnat.k
CHANGED
|
@@ -71,7 +71,7 @@ _reverse_bnat =
|
|
|
71
71
|
_add2wc =
|
|
72
72
|
-- least significant bit first addition with carry
|
|
73
73
|
--- :{ :bnat x, :bnat y, :[0,1] c}
|
|
74
|
-
--
|
|
74
|
+
-- _log!
|
|
75
75
|
<
|
|
76
76
|
{.x."0" x, .y."0" y, .c."0" c} {.x x, .y y, _ _0 c} _add2wc _0,
|
|
77
77
|
{.x."0" x, .y."0" y, .c."1" c} {.x x, .y y, _ _0 c} _add2wc _1,
|
package/code.k
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
inc = [(),1] PLUS;
|
|
2
|
-
$tree = <
|
|
2
|
+
$tree = < string leaf, {tree left, tree right} tree>;
|
|
3
3
|
height = $tree <
|
|
4
4
|
.leaf 0,
|
|
5
5
|
.tree [.left height, .right height] <GT .0, .1> inc
|
|
@@ -15,4 +15,4 @@ height = $tree <
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
>
|
|
18
|
+
> _log! height
|
package/codes.coffee
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
|
|
2
|
+
are_different = (classes, representatives, name1, name2, codes) ->
|
|
3
|
+
return false if name1 is name2
|
|
4
|
+
code1 = codes[name1]
|
|
5
|
+
code2 = codes[name2]
|
|
6
|
+
# console.log {name1, code1, name2, code2}
|
|
7
|
+
return true unless code1.code is code2.code
|
|
8
|
+
switch code1.code
|
|
9
|
+
when "union", "product"
|
|
10
|
+
[fields1,fields2] = [code1, code2]. map (code) ->
|
|
11
|
+
Object.keys(code[code.code]).reduce (fields, label) ->
|
|
12
|
+
fields[label] = representatives[code[code.code][label]]
|
|
13
|
+
, {}
|
|
14
|
+
return true unless Object.keys(fields1).length is Object.keys(fields2).length
|
|
15
|
+
for field,rep of fields1
|
|
16
|
+
return true unless fields2[field] is rep
|
|
17
|
+
return false
|
|
18
|
+
when "vector"
|
|
19
|
+
return representatives[code1.vector] isnt representatives[code2.vector]
|
|
20
|
+
false
|
|
21
|
+
|
|
22
|
+
minimize = (codes) ->
|
|
23
|
+
names = Object.keys codes
|
|
24
|
+
classes = {}
|
|
25
|
+
classes["{}"] = names
|
|
26
|
+
representatives = names.reduce (representatives, name) ->
|
|
27
|
+
representatives[name] = "{}"
|
|
28
|
+
representatives
|
|
29
|
+
, {}
|
|
30
|
+
changed = true
|
|
31
|
+
while changed
|
|
32
|
+
changed = false
|
|
33
|
+
for name1, eq_names of classes
|
|
34
|
+
code = codes[name1]
|
|
35
|
+
[eq_names, dif_names] = eq_names.reduce ([eq_names, dif_names], name2) ->
|
|
36
|
+
if are_different(classes, representatives, name1, name2, codes)
|
|
37
|
+
dif_names.push name2
|
|
38
|
+
else
|
|
39
|
+
eq_names.push name2
|
|
40
|
+
[eq_names,dif_names]
|
|
41
|
+
, [[],[]]
|
|
42
|
+
classes[name1] = eq_names
|
|
43
|
+
do (new_rep = dif_names[0]) ->
|
|
44
|
+
if new_rep?
|
|
45
|
+
changed = true
|
|
46
|
+
classes[new_rep] = dif_names
|
|
47
|
+
for x in dif_names
|
|
48
|
+
representatives[x] = new_rep
|
|
49
|
+
{classes,representatives}
|
|
50
|
+
|
|
51
|
+
compareAs = (fn) ->
|
|
52
|
+
(a,b) ->
|
|
53
|
+
[a,b] = [a,b].map fn
|
|
54
|
+
return -1 if a < b
|
|
55
|
+
return 1 if a > b
|
|
56
|
+
0
|
|
57
|
+
|
|
58
|
+
pretty_labels = (label_ref_map, codes, representatives) ->
|
|
59
|
+
labels = Object.keys(label_ref_map)
|
|
60
|
+
.sort compareAs (x) -> x
|
|
61
|
+
.map (label) ->
|
|
62
|
+
"#{pretty {code:"ref",ref:label_ref_map[label]}, codes, representatives} #{label}"
|
|
63
|
+
.join ", "
|
|
64
|
+
|
|
65
|
+
pretty = (codeExp, codes, representatives) ->
|
|
66
|
+
switch codeExp.code
|
|
67
|
+
when "ref"
|
|
68
|
+
name = representatives[codeExp.ref] ? codeExp.ref
|
|
69
|
+
if name.startsWith ":"
|
|
70
|
+
pretty codes[name], codes, representatives
|
|
71
|
+
else
|
|
72
|
+
name
|
|
73
|
+
when "product"
|
|
74
|
+
"{#{pretty_labels codeExp.product, codes, representatives}}"
|
|
75
|
+
when "union"
|
|
76
|
+
"<#{pretty_labels codeExp.union, codes, representatives}>"
|
|
77
|
+
when "vector"
|
|
78
|
+
"[#{representatives[codeExp.ref] ? codeExp.ref}]"
|
|
79
|
+
else
|
|
80
|
+
":error"
|
|
81
|
+
|
|
82
|
+
normalize = (label_ref_map, representatives) ->
|
|
83
|
+
# console.log {label_ref_map, representatives}
|
|
84
|
+
Object.keys(label_ref_map).reduce (result, label) ->
|
|
85
|
+
result[label] = do (name = label_ref_map[label]) ->
|
|
86
|
+
representatives[name] ? name
|
|
87
|
+
result
|
|
88
|
+
, {}
|
|
89
|
+
|
|
90
|
+
normalizeAll = (codes,representatives) ->
|
|
91
|
+
names = Object.keys codes
|
|
92
|
+
normalized = names.reduce (normalized, name) ->
|
|
93
|
+
if name is representatives[name]
|
|
94
|
+
do (code = codes[name]) ->
|
|
95
|
+
switch code.code
|
|
96
|
+
when "union", "product"
|
|
97
|
+
normalized[name] = { code: code.code }
|
|
98
|
+
normalized[name][code.code] = normalize code[code.code], representatives
|
|
99
|
+
when "vector"
|
|
100
|
+
normalized[name] = {code:"vector", vector: representatives[code.vector]}
|
|
101
|
+
|
|
102
|
+
normalized
|
|
103
|
+
, {}
|
|
104
|
+
|
|
105
|
+
module.exports = {minimize,pretty,normalize,normalizeAll}
|
|
106
|
+
|
|
107
|
+
|
package/codes.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
(function() {
|
|
3
|
+
var are_different, compareAs, minimize, normalize, normalizeAll, pretty, pretty_labels;
|
|
4
|
+
|
|
5
|
+
are_different = function(classes, representatives, name1, name2, codes) {
|
|
6
|
+
var code1, code2, field, fields1, fields2, rep;
|
|
7
|
+
if (name1 === name2) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
code1 = codes[name1];
|
|
11
|
+
code2 = codes[name2];
|
|
12
|
+
if (code1.code !== code2.code) {
|
|
13
|
+
// console.log {name1, code1, name2, code2}
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
switch (code1.code) {
|
|
17
|
+
case "union":
|
|
18
|
+
case "product":
|
|
19
|
+
[fields1, fields2] = [code1, code2].map(function(code) {
|
|
20
|
+
return Object.keys(code[code.code]).reduce(function(fields, label) {
|
|
21
|
+
return fields[label] = representatives[code[code.code][label]];
|
|
22
|
+
}, {});
|
|
23
|
+
});
|
|
24
|
+
if (Object.keys(fields1).length !== Object.keys(fields2).length) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
for (field in fields1) {
|
|
28
|
+
rep = fields1[field];
|
|
29
|
+
if (fields2[field] !== rep) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
case "vector":
|
|
35
|
+
return representatives[code1.vector] !== representatives[code2.vector];
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
minimize = function(codes) {
|
|
41
|
+
var changed, classes, code, dif_names, eq_names, name1, names, representatives;
|
|
42
|
+
names = Object.keys(codes);
|
|
43
|
+
classes = {};
|
|
44
|
+
classes["{}"] = names;
|
|
45
|
+
representatives = names.reduce(function(representatives, name) {
|
|
46
|
+
representatives[name] = "{}";
|
|
47
|
+
return representatives;
|
|
48
|
+
}, {});
|
|
49
|
+
changed = true;
|
|
50
|
+
while (changed) {
|
|
51
|
+
changed = false;
|
|
52
|
+
for (name1 in classes) {
|
|
53
|
+
eq_names = classes[name1];
|
|
54
|
+
code = codes[name1];
|
|
55
|
+
[eq_names, dif_names] = eq_names.reduce(function([eq_names, dif_names], name2) {
|
|
56
|
+
if (are_different(classes, representatives, name1, name2, codes)) {
|
|
57
|
+
dif_names.push(name2);
|
|
58
|
+
} else {
|
|
59
|
+
eq_names.push(name2);
|
|
60
|
+
}
|
|
61
|
+
return [eq_names, dif_names];
|
|
62
|
+
}, [[], []]);
|
|
63
|
+
classes[name1] = eq_names;
|
|
64
|
+
(function(new_rep) {
|
|
65
|
+
var i, len, results, x;
|
|
66
|
+
if (new_rep != null) {
|
|
67
|
+
changed = true;
|
|
68
|
+
classes[new_rep] = dif_names;
|
|
69
|
+
results = [];
|
|
70
|
+
for (i = 0, len = dif_names.length; i < len; i++) {
|
|
71
|
+
x = dif_names[i];
|
|
72
|
+
results.push(representatives[x] = new_rep);
|
|
73
|
+
}
|
|
74
|
+
return results;
|
|
75
|
+
}
|
|
76
|
+
})(dif_names[0]);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {classes, representatives};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
compareAs = function(fn) {
|
|
83
|
+
return function(a, b) {
|
|
84
|
+
[a, b] = [a, b].map(fn);
|
|
85
|
+
if (a < b) {
|
|
86
|
+
return -1;
|
|
87
|
+
}
|
|
88
|
+
if (a > b) {
|
|
89
|
+
return 1;
|
|
90
|
+
}
|
|
91
|
+
return 0;
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
pretty_labels = function(label_ref_map, codes, representatives) {
|
|
96
|
+
var labels;
|
|
97
|
+
return labels = Object.keys(label_ref_map).sort(compareAs(function(x) {
|
|
98
|
+
return x;
|
|
99
|
+
})).map(function(label) {
|
|
100
|
+
return `${pretty({
|
|
101
|
+
code: "ref",
|
|
102
|
+
ref: label_ref_map[label]
|
|
103
|
+
}, codes, representatives)} ${label}`;
|
|
104
|
+
}).join(", ");
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
pretty = function(codeExp, codes, representatives) {
|
|
108
|
+
var name, ref, ref1;
|
|
109
|
+
switch (codeExp.code) {
|
|
110
|
+
case "ref":
|
|
111
|
+
name = (ref = representatives[codeExp.ref]) != null ? ref : codeExp.ref;
|
|
112
|
+
if (name.startsWith(":")) {
|
|
113
|
+
return pretty(codes[name], codes, representatives);
|
|
114
|
+
} else {
|
|
115
|
+
return name;
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
case "product":
|
|
119
|
+
return `{${pretty_labels(codeExp.product, codes, representatives)}}`;
|
|
120
|
+
case "union":
|
|
121
|
+
return `<${pretty_labels(codeExp.union, codes, representatives)}>`;
|
|
122
|
+
case "vector":
|
|
123
|
+
return `[${(ref1 = representatives[codeExp.ref]) != null ? ref1 : codeExp.ref}]`;
|
|
124
|
+
default:
|
|
125
|
+
return ":error";
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
normalize = function(label_ref_map, representatives) {
|
|
130
|
+
// console.log {label_ref_map, representatives}
|
|
131
|
+
return Object.keys(label_ref_map).reduce(function(result, label) {
|
|
132
|
+
result[label] = (function(name) {
|
|
133
|
+
var ref;
|
|
134
|
+
return (ref = representatives[name]) != null ? ref : name;
|
|
135
|
+
})(label_ref_map[label]);
|
|
136
|
+
return result;
|
|
137
|
+
}, {});
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
normalizeAll = function(codes, representatives) {
|
|
141
|
+
var names, normalized;
|
|
142
|
+
names = Object.keys(codes);
|
|
143
|
+
return normalized = names.reduce(function(normalized, name) {
|
|
144
|
+
if (name === representatives[name]) {
|
|
145
|
+
(function(code) {
|
|
146
|
+
switch (code.code) {
|
|
147
|
+
case "union":
|
|
148
|
+
case "product":
|
|
149
|
+
normalized[name] = {
|
|
150
|
+
code: code.code
|
|
151
|
+
};
|
|
152
|
+
return normalized[name][code.code] = normalize(code[code.code], representatives);
|
|
153
|
+
case "vector":
|
|
154
|
+
return normalized[name] = {
|
|
155
|
+
code: "vector",
|
|
156
|
+
vector: representatives[code.vector]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
})(codes[name]);
|
|
160
|
+
}
|
|
161
|
+
return normalized;
|
|
162
|
+
}, {});
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
module.exports = {minimize, pretty, normalize, normalizeAll};
|
|
166
|
+
|
|
167
|
+
}).call(this);
|
package/fib.k
CHANGED
package/index.coffee
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
fs = require "fs"
|
|
2
2
|
{parse} = require "./parser.js"
|
|
3
3
|
run = require "./run"
|
|
4
|
+
t = require "./codes"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
finalize = (codes) ->
|
|
8
|
+
representatives = t.minimize(codes).representatives
|
|
9
|
+
codes = t.normalizeAll codes, representatives
|
|
10
|
+
|
|
11
|
+
{codes, representatives}
|
|
12
|
+
|
|
4
13
|
|
|
5
14
|
compile = (script) ->
|
|
6
15
|
do ({defs,exp} = parse script) ->
|
|
7
|
-
|
|
16
|
+
# console.log defs
|
|
17
|
+
{codes, representatives} = finalize defs.codes
|
|
18
|
+
# console.log {codes, representatives}
|
|
19
|
+
run.defs = {codes, representatives, rels: defs.rels}
|
|
20
|
+
|
|
8
21
|
(data) -> run exp, data
|
|
22
|
+
|
|
9
23
|
compile.doc = "Transforms k-script (string) into a function"
|
|
10
24
|
|
|
11
25
|
compile_file = (fileName) ->
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by CoffeeScript 2.7.0
|
|
2
2
|
(function() {
|
|
3
|
-
var compile, compile_file, fs, parse, run, runScriptOnData;
|
|
3
|
+
var compile, compile_file, finalize, fs, parse, run, runScriptOnData, t;
|
|
4
4
|
|
|
5
5
|
fs = require("fs");
|
|
6
6
|
|
|
@@ -8,9 +8,26 @@
|
|
|
8
8
|
|
|
9
9
|
run = require("./run");
|
|
10
10
|
|
|
11
|
+
t = require("./codes");
|
|
12
|
+
|
|
13
|
+
finalize = function(codes) {
|
|
14
|
+
var representatives;
|
|
15
|
+
representatives = t.minimize(codes).representatives;
|
|
16
|
+
codes = t.normalizeAll(codes, representatives);
|
|
17
|
+
return {codes, representatives};
|
|
18
|
+
};
|
|
19
|
+
|
|
11
20
|
compile = function(script) {
|
|
12
21
|
return (function({defs, exp}) {
|
|
13
|
-
|
|
22
|
+
var codes, representatives;
|
|
23
|
+
// console.log defs
|
|
24
|
+
({codes, representatives} = finalize(defs.codes));
|
|
25
|
+
// console.log {codes, representatives}
|
|
26
|
+
run.defs = {
|
|
27
|
+
codes,
|
|
28
|
+
representatives,
|
|
29
|
+
rels: defs.rels
|
|
30
|
+
};
|
|
14
31
|
return function(data) {
|
|
15
32
|
return run(exp, data);
|
|
16
33
|
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fraczak/k",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "k-language for JSON-like data transformation",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"prepare": "coffee -c symbol-table.coffee; jison parser.jison",
|
|
8
8
|
"prepublishOnly": "coffee -c *.coffee; echo '#!/usr/bin/env node' | cat - k.js > k.sh",
|
|
9
|
+
"all": "npm run prepublishOnly; npm run prepare; npm run prepublishOnly",
|
|
9
10
|
"test": "coffee -c symbol-table.coffee; jison parser.jison; coffee test.coffee"
|
|
10
11
|
},
|
|
11
12
|
"author": "Wojciech Fraczak",
|
package/parser.jison
CHANGED
|
@@ -44,27 +44,27 @@ str: STRING { $$ = String(yytext).slice(1,-1); };
|
|
|
44
44
|
int: INT { $$ = parseInt(String(yytext)); };
|
|
45
45
|
|
|
46
46
|
input_with_eof: defs comp EOF {
|
|
47
|
-
result = {defs:
|
|
47
|
+
result = {defs: {rels: s.rels, codes: s.codes}, exp: $2};
|
|
48
48
|
// console.log(JSON.stringify(result, "", 2));
|
|
49
49
|
return result;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
defs: {
|
|
53
|
-
| defs name EQ comp SC {
|
|
54
|
-
| defs DOLLAR name EQ code SC {
|
|
52
|
+
defs: { }
|
|
53
|
+
| defs name EQ comp SC { s.add_rel($2,$4); }
|
|
54
|
+
| defs DOLLAR name EQ code SC { s.add_code($3,$5); }
|
|
55
55
|
;
|
|
56
56
|
|
|
57
57
|
code
|
|
58
58
|
: name { $$ = {code: "ref", ref: $1}; }
|
|
59
59
|
| LC labelled_codes RC { $$ = {code: "product",
|
|
60
60
|
product: $2.reduce((r, lc) => {
|
|
61
|
-
r[lc.label] = lc.code;
|
|
61
|
+
r[lc.label] = s.as_ref(lc.code);
|
|
62
62
|
return r }
|
|
63
63
|
, {})}; }
|
|
64
|
-
| LB code RB { $$ = {code: "vector", vector: $2}; }
|
|
64
|
+
| LB code RB { $$ = {code: "vector", vector: s.as_ref($2)}; }
|
|
65
65
|
| LA labelled_codes RA { $$ = {code: "union",
|
|
66
66
|
union: $2.reduce((r, lc) => {
|
|
67
|
-
r[lc.label] = lc.code;
|
|
67
|
+
r[lc.label] = s.as_ref(lc.code);
|
|
68
68
|
return r }
|
|
69
69
|
, {})}; }
|
|
70
70
|
;
|
|
@@ -95,7 +95,7 @@ comp
|
|
|
95
95
|
exp
|
|
96
96
|
: LC labelled RC { $$ = $2; }
|
|
97
97
|
| LB list RB { $$ = {op: "vector", vector: $2}; }
|
|
98
|
-
| LA list RA { $$ =
|
|
98
|
+
| LA list RA { $$ = s.union($2); }
|
|
99
99
|
| name { $$ = {op: "ref", ref: $1}; }
|
|
100
100
|
| LP RP { $$ = s.identity; }
|
|
101
101
|
| LP comp RP { $$ = $2; }
|
|
@@ -104,7 +104,7 @@ exp
|
|
|
104
104
|
| DOT int { $$ = {op: "dot", dot: $2}; }
|
|
105
105
|
| DOT str { $$ = {op: "dot", dot: $2}; }
|
|
106
106
|
| DOT name { $$ = {op: "dot", dot: $2}; }
|
|
107
|
-
| DOLLAR code { $$ = {op: "code", code: $2}; }
|
|
107
|
+
| DOLLAR code { $$ = {op: "code", code: s.as_ref($2)}; }
|
|
108
108
|
;
|
|
109
109
|
|
|
110
110
|
labelled
|
package/parser.js
CHANGED
|
@@ -94,19 +94,19 @@ case 3:
|
|
|
94
94
|
break;
|
|
95
95
|
case 4:
|
|
96
96
|
|
|
97
|
-
result = {defs:
|
|
97
|
+
result = {defs: {rels: s.rels, codes: s.codes}, exp: $$[$0-1]};
|
|
98
98
|
// console.log(JSON.stringify(result, "", 2));
|
|
99
99
|
return result;
|
|
100
100
|
|
|
101
101
|
break;
|
|
102
102
|
case 5:
|
|
103
|
-
|
|
103
|
+
|
|
104
104
|
break;
|
|
105
105
|
case 6:
|
|
106
|
-
|
|
106
|
+
s.add_rel($$[$0-3],$$[$0-1]);
|
|
107
107
|
break;
|
|
108
108
|
case 7:
|
|
109
|
-
|
|
109
|
+
s.add_code($$[$0-3],$$[$0-1]);
|
|
110
110
|
break;
|
|
111
111
|
case 8:
|
|
112
112
|
this.$ = {code: "ref", ref: $$[$0]};
|
|
@@ -114,17 +114,17 @@ break;
|
|
|
114
114
|
case 9:
|
|
115
115
|
this.$ = {code: "product",
|
|
116
116
|
product: $$[$0-1].reduce((r, lc) => {
|
|
117
|
-
r[lc.label] = lc.code;
|
|
117
|
+
r[lc.label] = s.as_ref(lc.code);
|
|
118
118
|
return r }
|
|
119
119
|
, {})};
|
|
120
120
|
break;
|
|
121
121
|
case 10:
|
|
122
|
-
this.$ = {code: "vector", vector: $$[$0-1]};
|
|
122
|
+
this.$ = {code: "vector", vector: s.as_ref($$[$0-1])};
|
|
123
123
|
break;
|
|
124
124
|
case 11:
|
|
125
125
|
this.$ = {code: "union",
|
|
126
126
|
union: $$[$0-1].reduce((r, lc) => {
|
|
127
|
-
r[lc.label] = lc.code;
|
|
127
|
+
r[lc.label] = s.as_ref(lc.code);
|
|
128
128
|
return r }
|
|
129
129
|
, {})};
|
|
130
130
|
break;
|
|
@@ -156,7 +156,7 @@ case 23:
|
|
|
156
156
|
this.$ = {op: "vector", vector: $$[$0-1]};
|
|
157
157
|
break;
|
|
158
158
|
case 24:
|
|
159
|
-
this.$ =
|
|
159
|
+
this.$ = s.union($$[$0-1]);
|
|
160
160
|
break;
|
|
161
161
|
case 25:
|
|
162
162
|
this.$ = {op: "ref", ref: $$[$0]};
|
|
@@ -177,7 +177,7 @@ case 30: case 31: case 32:
|
|
|
177
177
|
this.$ = {op: "dot", dot: $$[$0]};
|
|
178
178
|
break;
|
|
179
179
|
case 33:
|
|
180
|
-
this.$ = {op: "code", code: $$[$0]};
|
|
180
|
+
this.$ = {op: "code", code: s.as_ref($$[$0])};
|
|
181
181
|
break;
|
|
182
182
|
case 34:
|
|
183
183
|
this.$ = {op: "product", product: []};
|
package/run.coffee
CHANGED
|
@@ -3,8 +3,8 @@ valid = (x) ->
|
|
|
3
3
|
return x if x?
|
|
4
4
|
|
|
5
5
|
builtin =
|
|
6
|
-
"
|
|
7
|
-
console.log "
|
|
6
|
+
"_log!": (arg) ->
|
|
7
|
+
console.log "_log!: #{JSON.stringify arg}"
|
|
8
8
|
arg
|
|
9
9
|
"GT": (args) ->
|
|
10
10
|
[ok,_] = do ([last,args...] = args) ->
|
|
@@ -48,11 +48,8 @@ codes =
|
|
|
48
48
|
x is true or x is false
|
|
49
49
|
|
|
50
50
|
verify = (code, value) ->
|
|
51
|
+
# console.log {code,value}
|
|
51
52
|
switch code.code
|
|
52
|
-
when "ref"
|
|
53
|
-
do (c = run.defs.codes[code.ref]) ->
|
|
54
|
-
return verify c, value if c?
|
|
55
|
-
codes[code.ref] value
|
|
56
53
|
when "vector"
|
|
57
54
|
value.every (x) ->
|
|
58
55
|
verify code.vector, x
|
|
@@ -65,8 +62,13 @@ verify = (code, value) ->
|
|
|
65
62
|
do (fields = Object.keys(value)) ->
|
|
66
63
|
return false unless fields.length is 1
|
|
67
64
|
verify code.union[fields[0]], value[fields[0]]
|
|
65
|
+
else
|
|
66
|
+
do (c = run.defs.codes[run.defs.representatives[code]]) ->
|
|
67
|
+
return verify c, value if c?
|
|
68
|
+
codes[code] value
|
|
68
69
|
|
|
69
70
|
run = (exp, value) ->
|
|
71
|
+
# console.log {exp,value}
|
|
70
72
|
return undefined if value is undefined
|
|
71
73
|
try
|
|
72
74
|
switch exp.op
|
|
@@ -77,7 +79,7 @@ run = (exp, value) ->
|
|
|
77
79
|
when "str", "int"
|
|
78
80
|
return exp[exp.op]
|
|
79
81
|
when "ref"
|
|
80
|
-
do (defn = run.defs.rels[exp.ref]) ->
|
|
82
|
+
do (defn = run.defs.rels[exp.ref]?[0]) ->
|
|
81
83
|
if defn?
|
|
82
84
|
run defn, value
|
|
83
85
|
else
|
package/run.js
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
builtin = {
|
|
16
|
-
"
|
|
17
|
-
console.log(`
|
|
16
|
+
"_log!": function(arg) {
|
|
17
|
+
console.log(`_log!: ${JSON.stringify(arg)}`);
|
|
18
18
|
return arg;
|
|
19
19
|
},
|
|
20
20
|
"GT": function(args) {
|
|
@@ -111,14 +111,8 @@
|
|
|
111
111
|
};
|
|
112
112
|
|
|
113
113
|
verify = function(code, value) {
|
|
114
|
+
// console.log {code,value}
|
|
114
115
|
switch (code.code) {
|
|
115
|
-
case "ref":
|
|
116
|
-
return (function(c) {
|
|
117
|
-
if (c != null) {
|
|
118
|
-
return verify(c, value);
|
|
119
|
-
}
|
|
120
|
-
return codes[code.ref](value);
|
|
121
|
-
})(run.defs.codes[code.ref]);
|
|
122
116
|
case "vector":
|
|
123
117
|
return value.every(function(x) {
|
|
124
118
|
return verify(code.vector, x);
|
|
@@ -139,12 +133,20 @@
|
|
|
139
133
|
}
|
|
140
134
|
return verify(code.union[fields[0]], value[fields[0]]);
|
|
141
135
|
})(Object.keys(value));
|
|
136
|
+
default:
|
|
137
|
+
return (function(c) {
|
|
138
|
+
if (c != null) {
|
|
139
|
+
return verify(c, value);
|
|
140
|
+
}
|
|
141
|
+
return codes[code](value);
|
|
142
|
+
})(run.defs.codes[run.defs.representatives[code]]);
|
|
142
143
|
}
|
|
143
144
|
};
|
|
144
145
|
|
|
145
146
|
run = function(exp, value) {
|
|
146
|
-
var e, i, len, ref, result;
|
|
147
|
+
var e, i, len, ref, ref1, result;
|
|
147
148
|
if (value === void 0) {
|
|
149
|
+
// console.log {exp,value}
|
|
148
150
|
return void 0;
|
|
149
151
|
}
|
|
150
152
|
try {
|
|
@@ -171,7 +173,7 @@
|
|
|
171
173
|
return value;
|
|
172
174
|
})(builtin[exp.ref](value));
|
|
173
175
|
}
|
|
174
|
-
})(run.defs.rels[exp.ref]);
|
|
176
|
+
})((ref = run.defs.rels[exp.ref]) != null ? ref[0] : void 0);
|
|
175
177
|
case "dot":
|
|
176
178
|
return value[exp.dot];
|
|
177
179
|
case "comp":
|
|
@@ -192,9 +194,9 @@
|
|
|
192
194
|
return result;
|
|
193
195
|
});
|
|
194
196
|
case "union":
|
|
195
|
-
|
|
196
|
-
for (i = 0, len =
|
|
197
|
-
e =
|
|
197
|
+
ref1 = exp.union;
|
|
198
|
+
for (i = 0, len = ref1.length; i < len; i++) {
|
|
199
|
+
e = ref1[i];
|
|
198
200
|
result = (function() {
|
|
199
201
|
try {
|
|
200
202
|
return run(e, value);
|
package/symbol-table.coffee
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
|
+
rels = Object.create null
|
|
2
|
+
codes = Object.create null
|
|
3
|
+
codes["{}"] = {code: "product", product: {}}
|
|
4
|
+
|
|
1
5
|
identity = op: "identity"
|
|
2
6
|
|
|
7
|
+
is_identity_rel = (rel) ->
|
|
8
|
+
rel.op is "identity"
|
|
9
|
+
|
|
10
|
+
is_empty_rel = (rel) ->
|
|
11
|
+
rel.op is "union" and rel.union.length is 0
|
|
12
|
+
|
|
13
|
+
is_full_rel = (rel) ->
|
|
14
|
+
switch rel.op
|
|
15
|
+
when "int", "str", "identity"
|
|
16
|
+
true
|
|
17
|
+
when "comp"
|
|
18
|
+
rel.comp.every is_full_rel
|
|
19
|
+
when "product", "vector"
|
|
20
|
+
Object.values(rel[rel.op]).every is_full_rel
|
|
21
|
+
else
|
|
22
|
+
false
|
|
23
|
+
|
|
3
24
|
comp = (e1, e2) ->
|
|
4
|
-
return e2 if e1
|
|
5
|
-
return e1 if e2
|
|
25
|
+
return e2 if is_identity_rel e1
|
|
26
|
+
return e1 if is_identity_rel e2
|
|
27
|
+
return e1 if is_empty_rel e1
|
|
28
|
+
return e2 if is_empty_rel e2
|
|
6
29
|
if e1.op is "comp" and e2.op is "comp"
|
|
7
30
|
return {op: "comp", comp: [].concat(e1.comp,e2.comp)}
|
|
8
31
|
if e1.op is "comp"
|
|
@@ -11,4 +34,31 @@ comp = (e1, e2) ->
|
|
|
11
34
|
return {op: "comp", comp: [].concat([e1],e2.comp)}
|
|
12
35
|
{op: "comp", comp: [e1,e2]}
|
|
13
36
|
|
|
14
|
-
|
|
37
|
+
union = (rels) ->
|
|
38
|
+
list = []
|
|
39
|
+
do ->
|
|
40
|
+
for rel in rels
|
|
41
|
+
new_rels = if rel.op is "union"
|
|
42
|
+
rel.union
|
|
43
|
+
else
|
|
44
|
+
[rel]
|
|
45
|
+
for rel in new_rels
|
|
46
|
+
list.push rel
|
|
47
|
+
return if is_full_rel rel
|
|
48
|
+
return list[0] if list.length is 1
|
|
49
|
+
{op: "union", union: list}
|
|
50
|
+
|
|
51
|
+
as_ref = (codeExp) ->
|
|
52
|
+
return codeExp.ref if codeExp.code is "ref"
|
|
53
|
+
newName = ":#{Object.keys(codes).length}"
|
|
54
|
+
codes[newName] = codeExp
|
|
55
|
+
return newName
|
|
56
|
+
|
|
57
|
+
add_rel = (name, rel) ->
|
|
58
|
+
rels[name] ?= []
|
|
59
|
+
rels[name].push rel
|
|
60
|
+
|
|
61
|
+
add_code = (name, code) ->
|
|
62
|
+
codes[name] = code
|
|
63
|
+
|
|
64
|
+
module.exports = {identity, comp, union, rels, codes, add_rel, add_code, as_ref};
|
package/symbol-table.js
CHANGED
|
@@ -1,18 +1,57 @@
|
|
|
1
1
|
// Generated by CoffeeScript 2.7.0
|
|
2
2
|
(function() {
|
|
3
|
-
var comp, identity;
|
|
3
|
+
var add_code, add_rel, as_ref, codes, comp, identity, is_empty_rel, is_full_rel, is_identity_rel, rels, union;
|
|
4
|
+
|
|
5
|
+
rels = Object.create(null);
|
|
6
|
+
|
|
7
|
+
codes = Object.create(null);
|
|
8
|
+
|
|
9
|
+
codes["{}"] = {
|
|
10
|
+
code: "product",
|
|
11
|
+
product: {}
|
|
12
|
+
};
|
|
4
13
|
|
|
5
14
|
identity = {
|
|
6
15
|
op: "identity"
|
|
7
16
|
};
|
|
8
17
|
|
|
18
|
+
is_identity_rel = function(rel) {
|
|
19
|
+
return rel.op === "identity";
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
is_empty_rel = function(rel) {
|
|
23
|
+
return rel.op === "union" && rel.union.length === 0;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
is_full_rel = function(rel) {
|
|
27
|
+
switch (rel.op) {
|
|
28
|
+
case "int":
|
|
29
|
+
case "str":
|
|
30
|
+
case "identity":
|
|
31
|
+
return true;
|
|
32
|
+
case "comp":
|
|
33
|
+
return rel.comp.every(is_full_rel);
|
|
34
|
+
case "product":
|
|
35
|
+
case "vector":
|
|
36
|
+
return Object.values(rel[rel.op]).every(is_full_rel);
|
|
37
|
+
default:
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
9
42
|
comp = function(e1, e2) {
|
|
10
|
-
if (e1
|
|
43
|
+
if (is_identity_rel(e1)) {
|
|
11
44
|
return e2;
|
|
12
45
|
}
|
|
13
|
-
if (e2
|
|
46
|
+
if (is_identity_rel(e2)) {
|
|
14
47
|
return e1;
|
|
15
48
|
}
|
|
49
|
+
if (is_empty_rel(e1)) {
|
|
50
|
+
return e1;
|
|
51
|
+
}
|
|
52
|
+
if (is_empty_rel(e2)) {
|
|
53
|
+
return e2;
|
|
54
|
+
}
|
|
16
55
|
if (e1.op === "comp" && e2.op === "comp") {
|
|
17
56
|
return {
|
|
18
57
|
op: "comp",
|
|
@@ -37,6 +76,53 @@
|
|
|
37
76
|
};
|
|
38
77
|
};
|
|
39
78
|
|
|
40
|
-
|
|
79
|
+
union = function(rels) {
|
|
80
|
+
var list;
|
|
81
|
+
list = [];
|
|
82
|
+
(function() {
|
|
83
|
+
var i, j, len, len1, new_rels, rel;
|
|
84
|
+
for (i = 0, len = rels.length; i < len; i++) {
|
|
85
|
+
rel = rels[i];
|
|
86
|
+
new_rels = rel.op === "union" ? rel.union : [rel];
|
|
87
|
+
for (j = 0, len1 = new_rels.length; j < len1; j++) {
|
|
88
|
+
rel = new_rels[j];
|
|
89
|
+
list.push(rel);
|
|
90
|
+
if (is_full_rel(rel)) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
})();
|
|
96
|
+
if (list.length === 1) {
|
|
97
|
+
return list[0];
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
op: "union",
|
|
101
|
+
union: list
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
as_ref = function(codeExp) {
|
|
106
|
+
var newName;
|
|
107
|
+
if (codeExp.code === "ref") {
|
|
108
|
+
return codeExp.ref;
|
|
109
|
+
}
|
|
110
|
+
newName = `:${Object.keys(codes).length}`;
|
|
111
|
+
codes[newName] = codeExp;
|
|
112
|
+
return newName;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
add_rel = function(name, rel) {
|
|
116
|
+
if (rels[name] == null) {
|
|
117
|
+
rels[name] = [];
|
|
118
|
+
}
|
|
119
|
+
return rels[name].push(rel);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
add_code = function(name, code) {
|
|
123
|
+
return codes[name] = code;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
module.exports = {identity, comp, union, rels, codes, add_rel, add_code, as_ref};
|
|
41
127
|
|
|
42
128
|
}).call(this);
|