@fraczak/k 1.1.0 → 1.1.2
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 +80 -52
- package/bnat.k +1 -1
- package/code.k +5 -4
- package/codes.coffee +109 -0
- package/codes.js +176 -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/typed-fib.k +19 -0
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# k-language
|
|
2
2
|
|
|
3
|
+
npm install @fraczak/k
|
|
4
|
+
|
|
3
5
|
Another JSON transformation notation. A `k`-expression
|
|
4
6
|
(script) defines a __partial function__, i.e., a function which, in
|
|
5
7
|
general, is not defined for every input. `k`-expressions can be
|
|
@@ -48,18 +50,18 @@ Elementary partial functions are:
|
|
|
48
50
|
3. There is a number of built-in functions: `GT`, `EQ`, `PLUS`,
|
|
49
51
|
`TIMES`, `MINUS`, `DIV`, `CONCAT`, `toJSON`, `fromJSON`, `CONS`, `SNOC`. For example
|
|
50
52
|
|
|
51
|
-
[1, 2, 3] PLUS --> integer constant 6
|
|
52
|
-
[4, 4] TIMES toJSON --> string constant "16"
|
|
53
|
-
[3, 2] GT --> vector constant [3, 2]
|
|
53
|
+
[1, 2, 3] PLUS --> integer constant function 6
|
|
54
|
+
[4, 4] TIMES toJSON --> string constant function "16"
|
|
55
|
+
[3, 2] GT --> vector constant function [3, 2]
|
|
54
56
|
[3, 4] GT --> is not defined!
|
|
55
57
|
|
|
56
58
|
A more interesting example could be:
|
|
57
59
|
|
|
58
|
-
<
|
|
60
|
+
< GT .0, .1>
|
|
59
61
|
|
|
60
|
-
which selects the
|
|
62
|
+
which selects the maximum element in two element vector, i.e.,
|
|
61
63
|
|
|
62
|
-
[3,8] <
|
|
64
|
+
[3,8] < GT .0, .1 > --> 8
|
|
63
65
|
|
|
64
66
|
## User defined functions
|
|
65
67
|
|
|
@@ -70,18 +72,33 @@ Elementary partial functions are:
|
|
|
70
72
|
[1,()] GT 1,
|
|
71
73
|
[dec factorial, ()] TIMES
|
|
72
74
|
>;
|
|
73
|
-
{
|
|
75
|
+
{ () x, factorial "x!" }
|
|
76
|
+
|
|
77
|
+
Another example could be finding the biggest (max) value in a vector:
|
|
74
78
|
|
|
75
|
-
|
|
79
|
+
max = <
|
|
80
|
+
SNOC -- [x0, x1, x2, ...] -> [x0, [x1, x2, ...]]
|
|
81
|
+
[.0, .1 max] -- [x0, [x1, x2, ...]] -> [x0, max(x1,x2,...)], i.e., recursive call
|
|
82
|
+
<GT.0,.1>, -- if x0 > max(x1,x2,...) then x0 else max(x1,x2,...)
|
|
83
|
+
-- when SNOC is not defined, e.g. the argument is a singleton vector [x0]
|
|
84
|
+
.0 -- [x0] -> x0,
|
|
85
|
+
>;
|
|
86
|
+
max
|
|
87
|
+
|
|
88
|
+
## Value encodings (also called _codes_)
|
|
76
89
|
|
|
77
90
|
There are three predefined value encodings: `int`, `string`, and `bool`. The language
|
|
78
91
|
supports `code`-expressions:
|
|
79
92
|
|
|
80
|
-
* product, e.g., `{x: int, y: int, flag: bool}`
|
|
81
|
-
* disjoint union, e.g., `<
|
|
93
|
+
* product, e.g., `{int x, int y, bool flag}` (in JSON-like syntax `{x: int, y: int, flag: bool}`)
|
|
94
|
+
* disjoint union, e.g., `<{} true, {} false>` (in JSON-like syntax `<true: {}, false: {}>`)
|
|
82
95
|
* vector, e.g., `[ int ]` (all elements of the vector use the same encoding)
|
|
83
96
|
|
|
84
|
-
One can define recursive codes. E.g
|
|
97
|
+
One can define recursive codes. E.g.:
|
|
98
|
+
|
|
99
|
+
$ tree = <string leaf, {tree left, tree right} tree>;
|
|
100
|
+
|
|
101
|
+
or, the same in JSON-like notation:
|
|
85
102
|
|
|
86
103
|
$ tree = <leaf: string, tree: {left: tree, right: tree}>;
|
|
87
104
|
|
|
@@ -91,11 +108,12 @@ The above example defines new code called _tree_.
|
|
|
91
108
|
The code can be then used in a `k`-expression as a filter. A `code`-expression
|
|
92
109
|
within `k`-expression is again prefixed by `$`.
|
|
93
110
|
|
|
94
|
-
$tree = <leaf
|
|
111
|
+
$ tree = <string leaf, {tree left, tree right} tree>;
|
|
95
112
|
inc = [(),1] PLUS;
|
|
113
|
+
max = <GT .0, .1>;
|
|
96
114
|
height = $ tree <
|
|
97
115
|
.leaf 0,
|
|
98
|
-
.tree [.left height, .right height]
|
|
116
|
+
.tree [.left height, .right height] max inc
|
|
99
117
|
> $ int;
|
|
100
118
|
height
|
|
101
119
|
|
|
@@ -107,7 +125,7 @@ run the language from command line.
|
|
|
107
125
|
|
|
108
126
|
$ ./node_modules/.bin/k
|
|
109
127
|
... errors ...
|
|
110
|
-
Usage: ./node_modules/.bin/k ( k-expr | -k k-file) [ json-file ]
|
|
128
|
+
Usage: ./node_modules/.bin/k ( k-expr | -k k-file) [ -1 ] [ json-file ]
|
|
111
129
|
E.g., cat '{"a": 10}' | ./node_modules/.bin/k '[(),()]'
|
|
112
130
|
|
|
113
131
|
### Examples
|
|
@@ -120,7 +138,7 @@ run the language from command line.
|
|
|
120
138
|
2. By providing only `k`-expression, the script will compile the
|
|
121
139
|
`k`-expression and apply the generated function to the `stdin`, line by line:
|
|
122
140
|
|
|
123
|
-
$ ./k
|
|
141
|
+
$ ./node_modules/.bin/k '<["x=",.x," & y=",.y],["only x=",.x],["only y=",.y],["no x nor y"]>{CONCAT "x&y"}'
|
|
124
142
|
|
|
125
143
|
{"y": 123, "x": 432,"others": "..."} --> {"x&y":"x=432 & y=123"}
|
|
126
144
|
{"x":987} --> {"x&y":"only x=987"}
|
|
@@ -146,11 +164,11 @@ run the language from command line.
|
|
|
146
164
|
|
|
147
165
|
We can use it by:
|
|
148
166
|
|
|
149
|
-
$ ./k
|
|
167
|
+
$ ./node_modules/.bin/k -k test.k
|
|
150
168
|
|
|
151
169
|
If we want to read `json` objects from a file, e.g., `my-objects.json`, we do
|
|
152
170
|
|
|
153
|
-
$ ./k
|
|
171
|
+
$ ./node_modules/.bin/k -k test.k my-objects.json
|
|
154
172
|
{"x&y":"x=432 & y=123"}
|
|
155
173
|
{"x&y":"onlyx=987"}
|
|
156
174
|
{"x&y":"no x nor y"}
|
|
@@ -166,52 +184,62 @@ run the language from command line.
|
|
|
166
184
|
####################################################
|
|
167
185
|
|
|
168
186
|
# Using from `javascript`
|
|
169
|
-
|
|
170
|
-
|
|
187
|
+
|
|
188
|
+
var k = require("k");
|
|
189
|
+
|
|
190
|
+
k_expression = '()';
|
|
191
|
+
k.run(k_expression,"ANYTHING...");
|
|
192
|
+
// RETURNS: "ANYTHING..."
|
|
193
|
+
|
|
194
|
+
k_expression = '{"ala" name, 23 age}';
|
|
195
|
+
k.run(k_expression,"ANYTHING...");
|
|
196
|
+
// RETURNS: {"name":"ala","age":23}
|
|
197
|
+
|
|
198
|
+
k_expression = '[.year, .age]';
|
|
199
|
+
k.run(k_expression,{"year":2002,"age":19});
|
|
200
|
+
// RETURNS: [2002,19]
|
|
171
201
|
|
|
172
|
-
|
|
202
|
+
k_expression = '[(), ()]';
|
|
203
|
+
k.run(k_expression,"duplicate me");
|
|
204
|
+
// RETURNS: ["duplicate me","duplicate me"]
|
|
173
205
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
206
|
+
k_expression = '[[[()]]]';
|
|
207
|
+
k.run(k_expression,"nesting");
|
|
208
|
+
// RETURNS: [[["nesting"]]]
|
|
177
209
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
210
|
+
k_expression = '[[()]] {() nested, .0.0 val}';
|
|
211
|
+
k.run(k_expression,"nesting and accessing");
|
|
212
|
+
// RETURNS: {"nested":[["nesting and accessing"]],"val":"nesting and accessing"}
|
|
181
213
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
214
|
+
k_expression = '0000';
|
|
215
|
+
k.run(k_expression,{"test":"parse integer"});
|
|
216
|
+
// RETURNS: 0
|
|
185
217
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
218
|
+
k_expression = '[.y,.x] PLUS';
|
|
219
|
+
k.run(k_expression,{"x":3,"y":4});
|
|
220
|
+
// RETURNS: 7
|
|
189
221
|
|
|
190
|
-
|
|
191
|
-
k.run(k_expression,"nesting");
|
|
192
|
-
// RETURNS: [[["nesting"]]]
|
|
222
|
+
var k_fn = k.compile('{.name nom, <[.age, 18] GT .0, [.age, 12] GT "ado", "enfant"> age}');
|
|
193
223
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
// RETURNS: {"nested":[["nesting and accessing"]],"val":"nesting and accessing"}
|
|
224
|
+
k_fn({"age":23,"name":"Emily"});
|
|
225
|
+
// RETURNS: {"nom":"Emily","age":23}
|
|
197
226
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
// RETURNS: 0
|
|
227
|
+
k_fn({"age":16,"name":"Katrina"});
|
|
228
|
+
// RETURNS: {"nom":"Katrina","age":"ado"}
|
|
201
229
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
// RETURNS: 7
|
|
230
|
+
k_fn({"age":2,"name":"Mark"});
|
|
231
|
+
// RETURNS: {"nom":"Mark","age":"enfant"}
|
|
205
232
|
|
|
206
|
-
|
|
233
|
+
var k_fn = k.compile('$t = < i: int, t: [ t ] > ; <$t, $int>');
|
|
207
234
|
|
|
208
|
-
|
|
235
|
+
k_fn(1);
|
|
236
|
+
// RETURNS: 1
|
|
209
237
|
|
|
210
|
-
|
|
211
|
-
|
|
238
|
+
k_fn({"i":1});
|
|
239
|
+
// RETURNS: {"i":1}
|
|
212
240
|
|
|
213
|
-
|
|
214
|
-
|
|
241
|
+
k_fn([{"i":2},{"i":3},{"t":[]}]);
|
|
242
|
+
// RETURNS: undefined
|
|
215
243
|
|
|
216
|
-
|
|
217
|
-
|
|
244
|
+
k_fn({"t":[{"i":2},{"i":3},{"t":[]}]});
|
|
245
|
+
// RETURNS: {"t":[{"i":2},{"i":3},{"t":[]}]}
|
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,8 +1,9 @@
|
|
|
1
1
|
inc = [(),1] PLUS;
|
|
2
|
-
|
|
2
|
+
max = <GT .0, .1>; -- max = < SNOC [.0, .1 max] <GT .0, .1>, .0 >;
|
|
3
|
+
$tree = < string leaf, {tree left, tree right} tree>;
|
|
3
4
|
height = $tree <
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
.leaf 0,
|
|
6
|
+
.tree [.left height, .right height] max inc
|
|
6
7
|
> $int;
|
|
7
8
|
|
|
8
9
|
<$tree,
|
|
@@ -15,4 +16,4 @@ height = $tree <
|
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
|
-
>
|
|
19
|
+
> _log! height
|
package/codes.coffee
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
do (arg = code[code.code]) ->
|
|
12
|
+
Object.keys(arg).reduce (fields, label) ->
|
|
13
|
+
fields[label] = representatives[arg[label]] ? arg[label]
|
|
14
|
+
, {}
|
|
15
|
+
return true unless Object.keys(fields1).length is Object.keys(fields2).length
|
|
16
|
+
for field,rep of fields1
|
|
17
|
+
return true unless fields2[field] is rep
|
|
18
|
+
when "vector"
|
|
19
|
+
[arg1,arg2] = [code1, code2]. map ({vector}) ->
|
|
20
|
+
representatives[vector] ? vector
|
|
21
|
+
return true unless arg1 is arg2
|
|
22
|
+
false
|
|
23
|
+
|
|
24
|
+
minimize = (codes) ->
|
|
25
|
+
names = Object.keys codes
|
|
26
|
+
classes = {}
|
|
27
|
+
classes["{}"] = names
|
|
28
|
+
representatives = names.reduce (representatives, name) ->
|
|
29
|
+
representatives[name] = "{}"
|
|
30
|
+
representatives
|
|
31
|
+
, {}
|
|
32
|
+
changed = true
|
|
33
|
+
while changed
|
|
34
|
+
changed = false
|
|
35
|
+
for name1, eq_names of classes
|
|
36
|
+
code = codes[name1]
|
|
37
|
+
[eq_names, dif_names] = eq_names.reduce ([eq_names, dif_names], name2) ->
|
|
38
|
+
if are_different(classes, representatives, name1, name2, codes)
|
|
39
|
+
dif_names.push name2
|
|
40
|
+
else
|
|
41
|
+
eq_names.push name2
|
|
42
|
+
[eq_names,dif_names]
|
|
43
|
+
, [[],[]]
|
|
44
|
+
classes[name1] = eq_names
|
|
45
|
+
do (new_rep = dif_names[0]) ->
|
|
46
|
+
if new_rep?
|
|
47
|
+
changed = true
|
|
48
|
+
classes[new_rep] = dif_names
|
|
49
|
+
for x in dif_names
|
|
50
|
+
representatives[x] = new_rep
|
|
51
|
+
{classes,representatives}
|
|
52
|
+
|
|
53
|
+
compareAs = (fn) ->
|
|
54
|
+
(a,b) ->
|
|
55
|
+
[a,b] = [a,b].map fn
|
|
56
|
+
return -1 if a < b
|
|
57
|
+
return 1 if a > b
|
|
58
|
+
0
|
|
59
|
+
|
|
60
|
+
pretty_labels = (label_ref_map, codes, representatives) ->
|
|
61
|
+
labels = Object.keys(label_ref_map)
|
|
62
|
+
.sort compareAs (x) -> x
|
|
63
|
+
.map (label) ->
|
|
64
|
+
"#{pretty {code:"ref",ref:label_ref_map[label]}, codes, representatives} #{label}"
|
|
65
|
+
.join ", "
|
|
66
|
+
|
|
67
|
+
pretty = (codeExp, codes, representatives) ->
|
|
68
|
+
switch codeExp.code
|
|
69
|
+
when "ref"
|
|
70
|
+
name = representatives[codeExp.ref] ? codeExp.ref
|
|
71
|
+
if name.startsWith ":"
|
|
72
|
+
pretty codes[name], codes, representatives
|
|
73
|
+
else
|
|
74
|
+
name
|
|
75
|
+
when "product"
|
|
76
|
+
"{#{pretty_labels codeExp.product, codes, representatives}}"
|
|
77
|
+
when "union"
|
|
78
|
+
"<#{pretty_labels codeExp.union, codes, representatives}>"
|
|
79
|
+
when "vector"
|
|
80
|
+
"[#{representatives[codeExp.ref] ? codeExp.ref}]"
|
|
81
|
+
else
|
|
82
|
+
":error"
|
|
83
|
+
|
|
84
|
+
normalize = (label_ref_map, representatives) ->
|
|
85
|
+
# console.log {label_ref_map, representatives}
|
|
86
|
+
Object.keys(label_ref_map).reduce (result, label) ->
|
|
87
|
+
result[label] = do (name = label_ref_map[label]) ->
|
|
88
|
+
representatives[name] ? name
|
|
89
|
+
result
|
|
90
|
+
, {}
|
|
91
|
+
|
|
92
|
+
normalizeAll = (codes,representatives) ->
|
|
93
|
+
names = Object.keys codes
|
|
94
|
+
normalized = names.reduce (normalized, name) ->
|
|
95
|
+
if name is representatives[name]
|
|
96
|
+
do (code = codes[name]) ->
|
|
97
|
+
switch code.code
|
|
98
|
+
when "union", "product"
|
|
99
|
+
normalized[name] = { code: code.code }
|
|
100
|
+
normalized[name][code.code] = normalize code[code.code], representatives
|
|
101
|
+
when "vector"
|
|
102
|
+
normalized[name] = {code:"vector", vector: representatives[code.vector]}
|
|
103
|
+
|
|
104
|
+
normalized
|
|
105
|
+
, {}
|
|
106
|
+
|
|
107
|
+
module.exports = {minimize,pretty,normalize,normalizeAll}
|
|
108
|
+
|
|
109
|
+
|
package/codes.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
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 arg1, arg2, 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 (function(arg) {
|
|
21
|
+
return Object.keys(arg).reduce(function(fields, label) {
|
|
22
|
+
var ref;
|
|
23
|
+
return fields[label] = (ref = representatives[arg[label]]) != null ? ref : arg[label];
|
|
24
|
+
}, {});
|
|
25
|
+
})(code[code.code]);
|
|
26
|
+
});
|
|
27
|
+
if (Object.keys(fields1).length !== Object.keys(fields2).length) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
for (field in fields1) {
|
|
31
|
+
rep = fields1[field];
|
|
32
|
+
if (fields2[field] !== rep) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
break;
|
|
37
|
+
case "vector":
|
|
38
|
+
[arg1, arg2] = [code1, code2].map(function({vector}) {
|
|
39
|
+
var ref;
|
|
40
|
+
return (ref = representatives[vector]) != null ? ref : vector;
|
|
41
|
+
});
|
|
42
|
+
if (arg1 !== arg2) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
minimize = function(codes) {
|
|
50
|
+
var changed, classes, code, dif_names, eq_names, name1, names, representatives;
|
|
51
|
+
names = Object.keys(codes);
|
|
52
|
+
classes = {};
|
|
53
|
+
classes["{}"] = names;
|
|
54
|
+
representatives = names.reduce(function(representatives, name) {
|
|
55
|
+
representatives[name] = "{}";
|
|
56
|
+
return representatives;
|
|
57
|
+
}, {});
|
|
58
|
+
changed = true;
|
|
59
|
+
while (changed) {
|
|
60
|
+
changed = false;
|
|
61
|
+
for (name1 in classes) {
|
|
62
|
+
eq_names = classes[name1];
|
|
63
|
+
code = codes[name1];
|
|
64
|
+
[eq_names, dif_names] = eq_names.reduce(function([eq_names, dif_names], name2) {
|
|
65
|
+
if (are_different(classes, representatives, name1, name2, codes)) {
|
|
66
|
+
dif_names.push(name2);
|
|
67
|
+
} else {
|
|
68
|
+
eq_names.push(name2);
|
|
69
|
+
}
|
|
70
|
+
return [eq_names, dif_names];
|
|
71
|
+
}, [[], []]);
|
|
72
|
+
classes[name1] = eq_names;
|
|
73
|
+
(function(new_rep) {
|
|
74
|
+
var i, len, results, x;
|
|
75
|
+
if (new_rep != null) {
|
|
76
|
+
changed = true;
|
|
77
|
+
classes[new_rep] = dif_names;
|
|
78
|
+
results = [];
|
|
79
|
+
for (i = 0, len = dif_names.length; i < len; i++) {
|
|
80
|
+
x = dif_names[i];
|
|
81
|
+
results.push(representatives[x] = new_rep);
|
|
82
|
+
}
|
|
83
|
+
return results;
|
|
84
|
+
}
|
|
85
|
+
})(dif_names[0]);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return {classes, representatives};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
compareAs = function(fn) {
|
|
92
|
+
return function(a, b) {
|
|
93
|
+
[a, b] = [a, b].map(fn);
|
|
94
|
+
if (a < b) {
|
|
95
|
+
return -1;
|
|
96
|
+
}
|
|
97
|
+
if (a > b) {
|
|
98
|
+
return 1;
|
|
99
|
+
}
|
|
100
|
+
return 0;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
pretty_labels = function(label_ref_map, codes, representatives) {
|
|
105
|
+
var labels;
|
|
106
|
+
return labels = Object.keys(label_ref_map).sort(compareAs(function(x) {
|
|
107
|
+
return x;
|
|
108
|
+
})).map(function(label) {
|
|
109
|
+
return `${pretty({
|
|
110
|
+
code: "ref",
|
|
111
|
+
ref: label_ref_map[label]
|
|
112
|
+
}, codes, representatives)} ${label}`;
|
|
113
|
+
}).join(", ");
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
pretty = function(codeExp, codes, representatives) {
|
|
117
|
+
var name, ref, ref1;
|
|
118
|
+
switch (codeExp.code) {
|
|
119
|
+
case "ref":
|
|
120
|
+
name = (ref = representatives[codeExp.ref]) != null ? ref : codeExp.ref;
|
|
121
|
+
if (name.startsWith(":")) {
|
|
122
|
+
return pretty(codes[name], codes, representatives);
|
|
123
|
+
} else {
|
|
124
|
+
return name;
|
|
125
|
+
}
|
|
126
|
+
break;
|
|
127
|
+
case "product":
|
|
128
|
+
return `{${pretty_labels(codeExp.product, codes, representatives)}}`;
|
|
129
|
+
case "union":
|
|
130
|
+
return `<${pretty_labels(codeExp.union, codes, representatives)}>`;
|
|
131
|
+
case "vector":
|
|
132
|
+
return `[${(ref1 = representatives[codeExp.ref]) != null ? ref1 : codeExp.ref}]`;
|
|
133
|
+
default:
|
|
134
|
+
return ":error";
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
normalize = function(label_ref_map, representatives) {
|
|
139
|
+
// console.log {label_ref_map, representatives}
|
|
140
|
+
return Object.keys(label_ref_map).reduce(function(result, label) {
|
|
141
|
+
result[label] = (function(name) {
|
|
142
|
+
var ref;
|
|
143
|
+
return (ref = representatives[name]) != null ? ref : name;
|
|
144
|
+
})(label_ref_map[label]);
|
|
145
|
+
return result;
|
|
146
|
+
}, {});
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
normalizeAll = function(codes, representatives) {
|
|
150
|
+
var names, normalized;
|
|
151
|
+
names = Object.keys(codes);
|
|
152
|
+
return normalized = names.reduce(function(normalized, name) {
|
|
153
|
+
if (name === representatives[name]) {
|
|
154
|
+
(function(code) {
|
|
155
|
+
switch (code.code) {
|
|
156
|
+
case "union":
|
|
157
|
+
case "product":
|
|
158
|
+
normalized[name] = {
|
|
159
|
+
code: code.code
|
|
160
|
+
};
|
|
161
|
+
return normalized[name][code.code] = normalize(code[code.code], representatives);
|
|
162
|
+
case "vector":
|
|
163
|
+
return normalized[name] = {
|
|
164
|
+
code: "vector",
|
|
165
|
+
vector: representatives[code.vector]
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
})(codes[name]);
|
|
169
|
+
}
|
|
170
|
+
return normalized;
|
|
171
|
+
}, {});
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
module.exports = {minimize, pretty, normalize, normalizeAll};
|
|
175
|
+
|
|
176
|
+
}).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.2",
|
|
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);
|
package/typed-fib.k
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
inc = [(),1] PLUS;
|
|
2
|
+
fib2 =
|
|
3
|
+
$ { int target, int x, int "fib(x)", int "fib(x-1)" }
|
|
4
|
+
_log!
|
|
5
|
+
<
|
|
6
|
+
{[.target,.x] GT guard, () input}
|
|
7
|
+
.input
|
|
8
|
+
{.target target,
|
|
9
|
+
.x inc x,
|
|
10
|
+
[."fib(x)", ."fib(x-1)"] PLUS "fib(x)",
|
|
11
|
+
."fib(x)" "fib(x-1)" }
|
|
12
|
+
fib2,
|
|
13
|
+
."fib(x)"
|
|
14
|
+
>
|
|
15
|
+
$ int;
|
|
16
|
+
|
|
17
|
+
{() target, 0 x, 1 "fib(x)", 0 "fib(x-1)"} fib2
|
|
18
|
+
|
|
19
|
+
|