@fraczak/k 1.0.1 → 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 +54 -14
- package/bnat.k +121 -0
- package/code.k +18 -0
- package/codes.coffee +107 -0
- package/codes.js +167 -0
- package/factorial.k +11 -0
- package/fib.k +15 -0
- package/index.coffee +16 -1
- package/index.js +20 -2
- package/k.coffee +34 -20
- package/k.js +51 -30
- package/k.sh +51 -30
- package/package.json +4 -3
- package/parser.jison +54 -8
- package/parser.js +99 -46
- package/pow.k +7 -0
- package/run.coffee +46 -4
- package/run.js +81 -10
- package/symbol-table.coffee +53 -3
- package/symbol-table.js +90 -4
- package/test.coffee +16 -0
- package/test.js +43 -0
- package/{test.t → test.k} +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# k-language
|
|
2
2
|
|
|
3
|
-
Another JSON
|
|
3
|
+
Another JSON transformation notation. A `k`-expression
|
|
4
4
|
(script) defines a __partial function__, i.e., a function which, in
|
|
5
5
|
general, is not defined for every input. `k`-expressions can be
|
|
6
6
|
combined to build other `k`-expressions in three ways:
|
|
@@ -11,14 +11,15 @@ combined to build other `k`-expressions in three ways:
|
|
|
11
11
|
|
|
12
12
|
Apart from empty composition, `()`, which defines _identity_, the paranthesis can be omitted.
|
|
13
13
|
|
|
14
|
-
2. product, e.g., vector:
|
|
14
|
+
2. product, e.g., vector or structure:
|
|
15
15
|
|
|
16
16
|
[ E1, E2, E3, ... ]
|
|
17
|
-
|
|
18
|
-
or structure:
|
|
19
|
-
|
|
20
17
|
{ E1 "e1", E2 "e2", E3 "e3", ... }
|
|
21
18
|
|
|
19
|
+
Now, structure can also be written similarly to JSON, ie.,
|
|
20
|
+
|
|
21
|
+
{ e1: E1, e2: E2, e3: E3, ... }
|
|
22
|
+
|
|
22
23
|
3. union (merge), e.g.:
|
|
23
24
|
|
|
24
25
|
< E1, E2, E3, ... >
|
|
@@ -42,15 +43,14 @@ Elementary partial functions are:
|
|
|
42
43
|
'another "String"'
|
|
43
44
|
123
|
|
44
45
|
false
|
|
45
|
-
|
|
46
|
-
Those functions are always defined, i.e., they ignore their argument.
|
|
46
|
+
null
|
|
47
47
|
|
|
48
48
|
3. There is a number of built-in functions: `GT`, `EQ`, `PLUS`,
|
|
49
|
-
`TIMES`, `MINUS`, `DIV`, `CONCAT`, `toJSON`, `fromJSON`. For example
|
|
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:
|
|
@@ -61,6 +61,47 @@ Elementary partial functions are:
|
|
|
61
61
|
|
|
62
62
|
[3,8] < [.0, .1] GT, [.1, .0] GT > .0 --> 8
|
|
63
63
|
|
|
64
|
+
## User defined functions
|
|
65
|
+
|
|
66
|
+
`k`-expression can be prefixed by function definitions. E.g.:
|
|
67
|
+
|
|
68
|
+
dec = [(),1] MINUS;
|
|
69
|
+
factorial = <
|
|
70
|
+
[1,()] GT 1,
|
|
71
|
+
[dec factorial, ()] TIMES
|
|
72
|
+
>;
|
|
73
|
+
{ () x, factorial "x!" }
|
|
74
|
+
|
|
75
|
+
## Value encodings (also called _types_ or _codes_)
|
|
76
|
+
|
|
77
|
+
There are three predefined value encodings: `int`, `string`, and `bool`. The language
|
|
78
|
+
supports `code`-expressions:
|
|
79
|
+
|
|
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
|
+
* vector, e.g., `[ int ]` (all elements of the vector use the same encoding)
|
|
83
|
+
|
|
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:
|
|
89
|
+
|
|
90
|
+
$ tree = <leaf: string, tree: {left: tree, right: tree}>;
|
|
91
|
+
|
|
92
|
+
Each _code_ definition starts with a `$`.
|
|
93
|
+
The above example defines new code called _tree_.
|
|
94
|
+
|
|
95
|
+
The code can be then used in a `k`-expression as a filter. A `code`-expression
|
|
96
|
+
within `k`-expression is again prefixed by `$`.
|
|
97
|
+
|
|
98
|
+
$tree = <string leaf, {tree left, tree right} tree>;
|
|
99
|
+
inc = [(),1] PLUS;
|
|
100
|
+
height = $ tree <
|
|
101
|
+
.leaf 0,
|
|
102
|
+
.tree [.left height, .right height] <GT .0, .1> inc
|
|
103
|
+
> $ int;
|
|
104
|
+
height
|
|
64
105
|
|
|
65
106
|
|
|
66
107
|
## Command line script
|
|
@@ -70,7 +111,7 @@ run the language from command line.
|
|
|
70
111
|
|
|
71
112
|
$ ./node_modules/.bin/k
|
|
72
113
|
... errors ...
|
|
73
|
-
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 ]
|
|
74
115
|
E.g., cat '{"a": 10}' | ./node_modules/.bin/k '[(),()]'
|
|
75
116
|
|
|
76
117
|
### Examples
|
|
@@ -113,7 +154,7 @@ run the language from command line.
|
|
|
113
154
|
|
|
114
155
|
If we want to read `json` objects from a file, e.g., `my-objects.json`, we do
|
|
115
156
|
|
|
116
|
-
$ ./k.coffee -k test.k
|
|
157
|
+
$ ./k.coffee -k test.k my-objects.json
|
|
117
158
|
{"x&y":"x=432 & y=123"}
|
|
118
159
|
{"x&y":"onlyx=987"}
|
|
119
160
|
{"x&y":"no x nor y"}
|
|
@@ -178,4 +219,3 @@ run the language from command line.
|
|
|
178
219
|
|
|
179
220
|
k_fn({"age":2,"name":"Mark"})
|
|
180
221
|
// RETURNS: {"nom":"Mark","age":"enfant"}
|
|
181
|
-
|
package/bnat.k
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
-- Standard binary encoding of natural
|
|
2
|
+
-- numbers with addition (+).
|
|
3
|
+
|
|
4
|
+
_ = {{} _};
|
|
5
|
+
_1 = {() "1"};
|
|
6
|
+
_0 = {() "0"};
|
|
7
|
+
|
|
8
|
+
n0 = _ ;
|
|
9
|
+
n1 = _ _1;
|
|
10
|
+
|
|
11
|
+
from_digit = <
|
|
12
|
+
[0, ()] EQ _, -- {_: {}}
|
|
13
|
+
[1, ()] EQ n1, -- {"1": {_: {}}}
|
|
14
|
+
[2, ()] EQ _ _0 _1, -- {"1": {"0": {_: {}}}}
|
|
15
|
+
[3, ()] EQ _ _1 _1, -- {"1": {"1": {_: {}}}}
|
|
16
|
+
[4, ()] EQ _ _0 _0 _1, -- {"1": {"0": {"0": {_: {}}}}}
|
|
17
|
+
[5, ()] EQ _ _1 _0 _1,
|
|
18
|
+
[6, ()] EQ _ _0 _1 _1,
|
|
19
|
+
[7, ()] EQ _ _1 _1 _1,
|
|
20
|
+
[8, ()] EQ _ _0 _0 _0 _1,
|
|
21
|
+
[9, ()] EQ _ _1 _0 _0 _1,
|
|
22
|
+
[10, ()] EQ _ _0 _1 _0 _1
|
|
23
|
+
>;
|
|
24
|
+
|
|
25
|
+
to_digit = <
|
|
26
|
+
._ 0,
|
|
27
|
+
."1"._ 1,
|
|
28
|
+
."1"."0"._ 2,
|
|
29
|
+
."1"."1"._ 3,
|
|
30
|
+
."1"."0"."0"._ 4,
|
|
31
|
+
."1"."0"."1"._ 5,
|
|
32
|
+
."1"."1"."0"._ 6,
|
|
33
|
+
."1"."1"."1"._ 7,
|
|
34
|
+
."1"."0"."0"."0"._ 8,
|
|
35
|
+
."1"."0"."0"."1"._ 9,
|
|
36
|
+
."1"."0"."1"."0"._ 10,
|
|
37
|
+
."1"."0"."1"."1"._ 11,
|
|
38
|
+
."1"."1"."0"."0"._ 12,
|
|
39
|
+
."1"."1"."0"."1"._ 13,
|
|
40
|
+
."1"."1"."1"."0"._ 14,
|
|
41
|
+
."1"."1"."1"."1"._ 15
|
|
42
|
+
> ;
|
|
43
|
+
|
|
44
|
+
remove_leading_zeros =
|
|
45
|
+
< ."0" remove_leading_zeros, () >;
|
|
46
|
+
|
|
47
|
+
_append_zero =
|
|
48
|
+
< ._ _ _0, -- ( _ -> 0 _)
|
|
49
|
+
."1" _append_zero _1, -- ('1 ... -> '1 [$.1 | _append_zero]),
|
|
50
|
+
."0" _append_zero _0 -- ('0 ... -> '0 [$.0 | _append_zero]),
|
|
51
|
+
>
|
|
52
|
+
;
|
|
53
|
+
|
|
54
|
+
_append_one =
|
|
55
|
+
<
|
|
56
|
+
._ _ _1,
|
|
57
|
+
."1" _append_one _1,
|
|
58
|
+
."0" _append_one _0
|
|
59
|
+
>
|
|
60
|
+
;
|
|
61
|
+
|
|
62
|
+
reverse_bnat = {() x, _ y} _reverse_bnat;
|
|
63
|
+
|
|
64
|
+
_reverse_bnat =
|
|
65
|
+
<
|
|
66
|
+
{.x._ x, .y y} .y,
|
|
67
|
+
{.x."0" x, .y _0 y} _reverse_bnat,
|
|
68
|
+
{.x."1" x, .y _1 y} _reverse_bnat
|
|
69
|
+
>;
|
|
70
|
+
|
|
71
|
+
_add2wc =
|
|
72
|
+
-- least significant bit first addition with carry
|
|
73
|
+
--- :{ :bnat x, :bnat y, :[0,1] c}
|
|
74
|
+
-- _log!
|
|
75
|
+
<
|
|
76
|
+
{.x."0" x, .y."0" y, .c."0" c} {.x x, .y y, _ _0 c} _add2wc _0,
|
|
77
|
+
{.x."0" x, .y."0" y, .c."1" c} {.x x, .y y, _ _0 c} _add2wc _1,
|
|
78
|
+
|
|
79
|
+
{.x."0" x, .y."1" y, .c."0" c} {.x x, .y y, _ _0 c} _add2wc _1,
|
|
80
|
+
{.x."0" x, .y."1" y, .c."1" c} {.x x, .y y, _ _1 c} _add2wc _0,
|
|
81
|
+
|
|
82
|
+
{.x."1" x, .y."0" y, .c."0" c} {.x x, .y y, _ _0 c} _add2wc _1,
|
|
83
|
+
{.x."1" x, .y."0" y, .c."1" c} {.x x, .y y, _ _1 c} _add2wc _0,
|
|
84
|
+
|
|
85
|
+
{.x."1" x, .y."1" y, .c."0" c} {.x x, .y y, _ _1 c} _add2wc _0,
|
|
86
|
+
{.x."1" x, .y."1" y, .c."1" c} {.x x, .y y, _ _1 c} _add2wc _1,
|
|
87
|
+
{.x._ x, .c."0" c, .y y} .y,
|
|
88
|
+
{.y._ y, .c."0" c, .x x} .x,
|
|
89
|
+
{.x._ x, .c."1" c, .y._ y} n1,
|
|
90
|
+
{.x._ x, .y."0" y, .c."1" c} .y _1,
|
|
91
|
+
{.x."0" x, .y._ y, .c."1" c} .x _1,
|
|
92
|
+
{.x._ x, .y."1" y, .c."1" c} {_ x, .y y, {} _1 c} _add2wc _0,
|
|
93
|
+
{.x."1" x, .y._ y, .c."1" c} {.x x, _ y, {} _1 c} _add2wc _0
|
|
94
|
+
>;
|
|
95
|
+
|
|
96
|
+
plus = <
|
|
97
|
+
SNOC {
|
|
98
|
+
x: .0 from_digit remove_leading_zeros reverse_bnat,
|
|
99
|
+
y: .1 plus remove_leading_zeros reverse_bnat,
|
|
100
|
+
c: {} _0 } _add2wc reverse_bnat,
|
|
101
|
+
.0 from_digit
|
|
102
|
+
>;
|
|
103
|
+
|
|
104
|
+
to_string = <
|
|
105
|
+
._ "0",
|
|
106
|
+
toString
|
|
107
|
+
>;
|
|
108
|
+
|
|
109
|
+
toString = <
|
|
110
|
+
._ "",
|
|
111
|
+
["0", ."0" toString] CONCAT,
|
|
112
|
+
["1", ."1" toString] CONCAT
|
|
113
|
+
>;
|
|
114
|
+
|
|
115
|
+
[(), plus]
|
|
116
|
+
{
|
|
117
|
+
input: .0,
|
|
118
|
+
sum: {raw: .1, digits: .1 <to_digit,"...too big...">, binary: .1 to_string}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
-- example: > echo '[9,9,9,8]' | ./k.sh -k ./bnat.k
|
package/code.k
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
inc = [(),1] PLUS;
|
|
2
|
+
$tree = < string leaf, {tree left, tree right} tree>;
|
|
3
|
+
height = $tree <
|
|
4
|
+
.leaf 0,
|
|
5
|
+
.tree [.left height, .right height] <GT .0, .1> inc
|
|
6
|
+
> $int;
|
|
7
|
+
|
|
8
|
+
<$tree,
|
|
9
|
+
{tree:
|
|
10
|
+
{ left: { leaf: "a"},
|
|
11
|
+
right: { tree:
|
|
12
|
+
{ left: {leaf: "b"},
|
|
13
|
+
right: {leaf: "c"}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
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/factorial.k
ADDED
package/fib.k
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
fib_aux = _log!
|
|
2
|
+
<
|
|
3
|
+
{ [.n, 1] GT [.0,-1] PLUS n,
|
|
4
|
+
."[fib(n),fib(n-1)" [[.0,.1] PLUS, .0] "[fib(n),fib(n-1)"
|
|
5
|
+
} fib_aux,
|
|
6
|
+
."[fib(n),fib(n-1)"
|
|
7
|
+
>
|
|
8
|
+
;
|
|
9
|
+
|
|
10
|
+
fib = {() n, [1,1] "[fib(n),fib(n-1)"}
|
|
11
|
+
fib_aux .0;
|
|
12
|
+
|
|
13
|
+
----------------------
|
|
14
|
+
|
|
15
|
+
fib
|
package/index.coffee
CHANGED
|
@@ -1,10 +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
|
-
do (exp = parse script) ->
|
|
15
|
+
do ({defs,exp} = parse script) ->
|
|
16
|
+
# console.log defs
|
|
17
|
+
{codes, representatives} = finalize defs.codes
|
|
18
|
+
# console.log {codes, representatives}
|
|
19
|
+
run.defs = {codes, representatives, rels: defs.rels}
|
|
20
|
+
|
|
7
21
|
(data) -> run exp, data
|
|
22
|
+
|
|
8
23
|
compile.doc = "Transforms k-script (string) into a function"
|
|
9
24
|
|
|
10
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,8 +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
|
-
return (function(exp) {
|
|
21
|
+
return (function({defs, exp}) {
|
|
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
|
+
};
|
|
13
31
|
return function(data) {
|
|
14
32
|
return run(exp, data);
|
|
15
33
|
};
|
package/k.coffee
CHANGED
|
@@ -4,7 +4,8 @@ k = require "./"
|
|
|
4
4
|
|
|
5
5
|
prog = process.argv[1]
|
|
6
6
|
|
|
7
|
-
{kScript,jsonStream} =
|
|
7
|
+
{kScript,jsonStream,oneJson} =
|
|
8
|
+
do (oneJson = false, args = process.argv.slice(2)) ->
|
|
8
9
|
try
|
|
9
10
|
kScript = do (arg = args.shift()) ->
|
|
10
11
|
throw new Error() unless arg?
|
|
@@ -16,30 +17,43 @@ prog = process.argv[1]
|
|
|
16
17
|
kScript = k.compile kScript
|
|
17
18
|
|
|
18
19
|
jsonStream = do (arg = args.shift()) ->
|
|
20
|
+
if arg is "-1"
|
|
21
|
+
oneJson = true
|
|
22
|
+
arg = args.shift()
|
|
19
23
|
return process.stdin unless arg?
|
|
20
24
|
fs.createReadStream arg
|
|
21
25
|
|
|
22
|
-
{kScript, jsonStream}
|
|
26
|
+
{kScript, jsonStream, oneJson}
|
|
23
27
|
catch e
|
|
24
28
|
console.error e
|
|
25
|
-
console.error "Usage: #{prog} ( k-expr | -k k-file ) [ json-file ]"
|
|
29
|
+
console.error "Usage: #{prog} ( k-expr | -k k-file ) [ -1 ] [ json-file ]"
|
|
26
30
|
console.error " E.g., echo '{\"a\": 12}' | #{prog} '[(),()]'"
|
|
27
31
|
process.exit -1
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
33
|
+
if oneJson
|
|
34
|
+
do (buffer = []) ->
|
|
35
|
+
jsonStream.on 'data', (data) ->
|
|
36
|
+
buffer.push data
|
|
37
|
+
jsonStream.on 'end', ->
|
|
38
|
+
try
|
|
39
|
+
console.log JSON.stringify kScript JSON.parse buffer.join('')
|
|
40
|
+
catch e
|
|
41
|
+
console.error e
|
|
42
|
+
else
|
|
43
|
+
do (buffer = [], line = 0) ->
|
|
44
|
+
jsonStream.on 'data', (data) ->
|
|
45
|
+
[first, rest...] = data.toString("utf8").split "\n"
|
|
46
|
+
buffer.push first
|
|
47
|
+
if rest.length > 0
|
|
48
|
+
todo = buffer.join ""
|
|
49
|
+
[rest..., last] = rest
|
|
50
|
+
buffer = [last]
|
|
51
|
+
todo = [todo, rest...]
|
|
52
|
+
for json in todo
|
|
53
|
+
if not json.match /^[ \n\t]*(?:#.*)?$/
|
|
54
|
+
try
|
|
55
|
+
console.log JSON.stringify kScript JSON.parse json
|
|
56
|
+
catch e
|
|
57
|
+
console.error "Problem [line #{line}]: '#{json}'"
|
|
58
|
+
console.error e
|
|
59
|
+
line = line + 1
|