@fraczak/k 1.2.0 → 1.2.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.
@@ -0,0 +1,200 @@
1
+ 1
2
+ 2
3
+ 3
4
+ 4
5
+ 5
6
+ 6
7
+ 7
8
+ 8
9
+ 9
10
+ 10
11
+ 11
12
+ 12
13
+ 13
14
+ 14
15
+ 15
16
+ 16
17
+ 17
18
+ 18
19
+ 19
20
+ 20
21
+ 21
22
+ 22
23
+ 23
24
+ 24
25
+ 25
26
+ 26
27
+ 27
28
+ 28
29
+ 29
30
+ 30
31
+ 31
32
+ 32
33
+ 33
34
+ 34
35
+ 35
36
+ 36
37
+ 37
38
+ 38
39
+ 39
40
+ 40
41
+ 41
42
+ 42
43
+ 43
44
+ 44
45
+ 45
46
+ 46
47
+ 47
48
+ 48
49
+ 49
50
+ 50
51
+ 51
52
+ 52
53
+ 53
54
+ 54
55
+ 55
56
+ 56
57
+ 57
58
+ 58
59
+ 59
60
+ 60
61
+ 61
62
+ 62
63
+ 63
64
+ 64
65
+ 65
66
+ 66
67
+ 67
68
+ 68
69
+ 69
70
+ 70
71
+ 71
72
+ 72
73
+ 73
74
+ 74
75
+ 75
76
+ 76
77
+ 77
78
+ 78
79
+ 79
80
+ 80
81
+ 81
82
+ 82
83
+ 83
84
+ 84
85
+ 85
86
+ 86
87
+ 87
88
+ 88
89
+ 89
90
+ 90
91
+ 91
92
+ 92
93
+ 93
94
+ 94
95
+ 95
96
+ 96
97
+ 97
98
+ 98
99
+ 99
100
+ 100
101
+ 101
102
+ 102
103
+ 103
104
+ 104
105
+ 105
106
+ 106
107
+ 107
108
+ 108
109
+ 109
110
+ 110
111
+ 111
112
+ 112
113
+ 113
114
+ 114
115
+ 115
116
+ 116
117
+ 117
118
+ 118
119
+ 119
120
+ 120
121
+ 121
122
+ 122
123
+ 123
124
+ 124
125
+ 125
126
+ 126
127
+ 127
128
+ 128
129
+ 129
130
+ 130
131
+ 131
132
+ 132
133
+ 133
134
+ 134
135
+ 135
136
+ 136
137
+ 137
138
+ 138
139
+ 139
140
+ 140
141
+ 141
142
+ 142
143
+ 143
144
+ 144
145
+ 145
146
+ 146
147
+ 147
148
+ 148
149
+ 149
150
+ 150
151
+ 151
152
+ 152
153
+ 153
154
+ 154
155
+ 155
156
+ 156
157
+ 157
158
+ 158
159
+ 159
160
+ 160
161
+ 161
162
+ 162
163
+ 163
164
+ 164
165
+ 165
166
+ 166
167
+ 167
168
+ 168
169
+ 169
170
+ 170
171
+ 171
172
+ 172
173
+ 173
174
+ 174
175
+ 175
176
+ 176
177
+ 177
178
+ 178
179
+ 179
180
+ 180
181
+ 181
182
+ 182
183
+ 183
184
+ 184
185
+ 185
186
+ 186
187
+ 187
188
+ 188
189
+ 189
190
+ 190
191
+ 191
192
+ 192
193
+ 193
194
+ 194
195
+ 195
196
+ 196
197
+ 197
198
+ 198
199
+ 199
200
+ 200
package/README.md CHANGED
@@ -1,106 +1,108 @@
1
- # k-language
1
+ # k-language
2
2
 
3
- npm install @fraczak/k
3
+ npm install @fraczak/k
4
4
 
5
- Another JSON transformation notation. A `k`-expression
6
- (script) defines a __partial function__, i.e., a function which, in
7
- general, is not defined for every input. `k`-expressions can be
8
- combined to build other `k`-expressions in three ways:
5
+ From javascript:
6
+
7
+ var k = require("@fraczak/k"),
8
+ fn = k.compile("<.name,.nom,'?'>");
9
+ console.log([{name:"x"},{nom:"y"},{}].map(fn));
10
+ // returns: [ "x", "y", "?" ]
11
+
12
+ Another JSON transformation notation. A `k`-expression (script)
13
+ defines a __partial function__, i.e., a function which may fail
14
+ for some input. `k`-expressions can be combined to build
15
+ other `k`-expressions in three ways:
9
16
 
10
17
  1. composition, e.g.:
11
-
18
+
12
19
  (E1 E2 E3 ...)
13
-
14
- Apart from empty composition, `()`, which defines _identity_, the paranthesis can be omitted.
20
+
21
+ Apart from empty composition, `()`, which defines _identity_, the
22
+ paranthesis can be omitted.
15
23
 
16
24
  2. product, e.g., vector or structure:
17
25
 
18
26
  [ E1, E2, E3, ... ]
19
27
  { E1 "e1", E2 "e2", E3 "e3", ... }
20
28
 
21
- Now, structure can also be written similarly to JSON, ie.,
22
-
23
- { e1: E1, e2: E2, e3: E3, ... }
24
-
25
29
  3. union (merge), e.g.:
26
30
 
27
31
  < E1, E2, E3, ... >
28
-
29
- Elementary partial functions are:
30
-
31
- 1. _projection_, i.e., extracting the value of a given field or
32
- index. Examples:
33
-
34
- .x
35
- ."field name"
36
- .4
37
-
38
- The function is defined only if its argument is a structure with
39
- the field (or a vector with the index).
40
-
41
- 2. _constants_, literals for Strings, Booleans, and
32
+
33
+ Elementary partial functions are:
34
+
35
+ 4. _projection_, i.e., extracting the value of a given field or
36
+ index. Examples:
37
+
38
+ .x
39
+ ."field name"
40
+ .4
41
+
42
+ The function is defined only if its argument is a structure with
43
+ the field (or a vector with the index).
44
+
45
+ 5. _constants_, literals for Strings, Booleans, and
42
46
  Integers. Examples:
43
-
44
- "a string"
45
- 'another "String"'
46
- 123
47
- false
48
- null
49
-
50
- 3. There is a number of built-in functions: `GT`, `EQ`, `PLUS`,
51
- `TIMES`, `MINUS`, `DIV`, `CONCAT`, `toJSON`, `fromJSON`, `CONS`, `SNOC`. For example
52
-
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]
56
- [3, 4] GT --> is not defined!
57
-
58
- A more interesting example could be:
59
-
60
- < GT .0, .1>
61
-
62
- which selects the maximum element in two element vector, i.e.,
63
-
64
- [3,8] < GT .0, .1 > --> 8
47
+
48
+ "a string"
49
+ 'another "String"'
50
+ 123
51
+ false
52
+ null
53
+
54
+ 6. There is a number of built-in functions: `GT`, `EQ`, `PLUS`,
55
+ `TIMES`, `MINUS`, `DIV`, `CONCAT`, `toJSON`, `fromJSON`, `CONS`,
56
+ `SNOC`, `_log!`, ... For example:
57
+
58
+ [1, 2, 3] PLUS --> integer constant function 6
59
+ [4, 4] TIMES toJSON --> string constant function "16"
60
+ [3, 2] GT --> vector constant function [3, 2]
61
+ [3, 4] GT --> is not defined!
62
+
63
+ A more interesting example could be:
64
+
65
+ < GT .0, .1>
66
+
67
+ which selects the maximum element in two element vector, i.e.,
68
+
69
+ [3,8] < GT .0, .1 > --> 8
65
70
 
66
71
  ## User defined functions
67
72
 
68
- `k`-expression can be prefixed by function definitions. E.g.:
73
+ `k`-expression can be prefixed by function definitions. E.g.:
69
74
 
70
- dec = [(),1] MINUS;
71
- factorial = <
72
- [1,()] GT 1,
73
- [dec factorial, ()] TIMES
74
- >;
75
- { () x, factorial "x!" }
75
+ dec = [(),1] MINUS;
76
+ factorial = <
77
+ [(),1] EQ 1,
78
+ [dec factorial, ()] TIMES
79
+ >;
80
+ { () x, < factorial, "not defined" > "x!" }
76
81
 
77
82
  Another example could be finding the biggest (max) value in a vector:
78
83
 
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
84
+ max = <
85
+ SNOC -- [x0, x1, x2, ...] -> [x0, [x1, x2, ...]]
86
+ [.0, .1 max] -- [x0, [x1, x2, ...]] -> [x0, max(x1,x2,...)], i.e., recursive call
87
+ <GT.0,.1>, -- if x0 > max(x1,x2,...) then x0 else max(x1,x2,...)
88
+ -- when SNOC is not defined, e.g. the argument is a singleton vector [x0]
89
+ .0 -- [x0] -> x0,
90
+ >;
91
+ max
87
92
 
88
- ## Value encodings (also called _codes_)
93
+ ## Value encodings (_codes_)
89
94
 
90
- There are three predefined value encodings: `int`, `string`, and `bool`. The language
91
- supports `code`-expressions:
95
+ There are three predefined value encodings: `int`, `string`, and
96
+ `bool`. The language supports `code`-expressions:
92
97
 
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: {}>`)
95
- * vector, e.g., `[ int ]` (all elements of the vector use the same encoding)
98
+ * product, e.g., `{int x, int y, bool flag}`
99
+ * disjoint union, e.g., `<{} true, {} false>`
100
+ * vector, e.g., `[ int ]` (all elements of the vector use the same
101
+ encoding)
96
102
 
97
103
  One can define recursive codes. E.g.:
98
104
 
99
- $ tree = <string leaf, {tree left, tree right} tree>;
100
-
101
- or, the same in JSON-like notation:
102
-
103
- $ tree = <leaf: string, tree: {left: tree, right: tree}>;
105
+ tree = <string leaf, {tree left, tree right} tree>;
104
106
 
105
107
  Each _code_ definition starts with a `$`.
106
108
  The above example defines new code called _tree_.
@@ -108,138 +110,164 @@ The above example defines new code called _tree_.
108
110
  The code can be then used in a `k`-expression as a filter. A `code`-expression
109
111
  within `k`-expression is again prefixed by `$`.
110
112
 
111
- $ tree = <string leaf, {tree left, tree right} tree>;
112
- inc = [(),1] PLUS;
113
- max = <GT .0, .1>;
114
- height = $ tree <
115
- .leaf 0,
116
- .tree [.left height, .right height] max inc
117
- > $ int;
118
- height
119
-
113
+ $ tree = <string leaf, {tree left, tree right} tree>;
114
+ inc = [(),1] PLUS;
115
+ max = <GT .0, .1>;
116
+ height = $ tree <
117
+ .leaf 0,
118
+ .tree [.left height, .right height] max inc
119
+ > $ int;
120
+ height
120
121
 
121
122
  ## Command line script
122
123
 
123
124
  There is a wrapper, `./node_modules/.bin/k` , which makes it easy to
124
125
  run the language from command line.
125
126
 
126
- $ ./node_modules/.bin/k
127
- ... errors ...
128
- Usage: ./node_modules/.bin/k ( k-expr | -k k-file) [ -1 ] [ json-file ]
129
- E.g., cat '{"a": 10}' | ./node_modules/.bin/k '[(),()]'
127
+ > ./node_modules/.bin/k
128
+ ... errors ...
129
+ Usage: ./node_modules/.bin/k ( k-expr | -k k-file) [ -1 ] [ json-file ]
130
+ E.g., cat '{"a": 10}' | ./node_modules/.bin/k '[(),()]'
130
131
 
131
132
  ### Examples
132
133
 
133
134
  1. One `k`-expression with one `json`-object:
134
135
 
135
- $ echo '{"x": 12, "y": 13}' | ./k.coffee '{ <.x, "no x"> x, () input}'
136
- {"x":12,"input":{"x":12,"y":13}}
137
-
136
+ > echo '{"x": 12, "y": 13}' | ./k.coffee '{ <.x, "no x"> x, () input}'
137
+ {"x":12,"input":{"x":12,"y":13}}
138
+
138
139
  2. By providing only `k`-expression, the script will compile the
139
- `k`-expression and apply the generated function to the `stdin`, line by line:
140
+ `k`-expression and apply the generated function to the `stdin`,
141
+ line by line:
140
142
 
141
- $ ./node_modules/.bin/k '<["x=",.x," & y=",.y],["only x=",.x],["only y=",.y],["no x nor y"]>{CONCAT "x&y"}'
142
-
143
- {"y": 123, "x": 432,"others": "..."} --> {"x&y":"x=432 & y=123"}
144
- {"x":987} --> {"x&y":"only x=987"}
145
- {"z":123} --> {"x&y":"no x nor y"}
146
- ^D - to interrupt
143
+ > ./node_modules/.bin/k '<["x=",.x," & y=",.y],["only x=",.x],["only y=",.y],["no x nor y"]>{CONCAT "x&y"}'
144
+
145
+ {"y": 123, "x": 432,"others": "..."} --> {"x&y":"x=432 & y=123"}
146
+ {"x":987} --> {"x&y":"only x=987"}
147
+ {"z":123} --> {"x&y":"no x nor y"}
148
+ ^D - to interrupt
147
149
 
148
150
  3. If the `k`-expression is long, it can be put in a file, e.g.:
149
151
 
150
- $ cat test.k
151
- --------- comments start by #, --, or // ----------------------------------
152
- < -- merge of 4 partial functions...
153
- ["x=", .x, " & y=", .y], -- produces a vector of 4 values, if fields 'x' and 'y' are present
154
- ["only x=", .x], -- produces a pair '["only x=", "value-of-x"]', for input like {"x":"value-of-x"}
155
- -- it is defined only if field 'x' is present
156
- ["only y=", .y],
157
- ["no x nor y"] -- defined for all input, returns always the same one element vector
158
- >
159
- -- one of the string vectors is passed to the following partial function,
160
- -- which produces a record (map) with one field "x&y", whose value is the
161
- -- result of concatenating elements of the passed in vector
162
- { CONCAT "x&y" }
163
- ------------------------------------------------------------------------------
164
-
165
- We can use it by:
166
-
167
- $ ./node_modules/.bin/k -k test.k
168
-
169
- If we want to read `json` objects from a file, e.g., `my-objects.json`, we do
170
-
171
- $ ./node_modules/.bin/k -k test.k my-objects.json
172
- {"x&y":"x=432 & y=123"}
173
- {"x&y":"onlyx=987"}
174
- {"x&y":"no x nor y"}
175
-
176
- where:
177
-
178
- $ cat my-objects.json
179
- ####################################################
180
- # empty lines and lines starting with # are ignored
181
- {"y": 123, "x": 432,"others": "..."}
182
- {"x":987}
183
- {"z":123}
184
- ####################################################
185
-
186
- # Using from `javascript`
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]
201
-
202
- k_expression = '[(), ()]';
203
- k.run(k_expression,"duplicate me");
204
- // RETURNS: ["duplicate me","duplicate me"]
205
-
206
- k_expression = '[[[()]]]';
207
- k.run(k_expression,"nesting");
208
- // RETURNS: [[["nesting"]]]
209
-
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"}
213
-
214
- k_expression = '0000';
215
- k.run(k_expression,{"test":"parse integer"});
216
- // RETURNS: 0
217
-
218
- k_expression = '[.y,.x] PLUS';
219
- k.run(k_expression,{"x":3,"y":4});
220
- // RETURNS: 7
221
-
222
- var k_fn = k.compile('{.name nom, <[.age, 18] GT .0, [.age, 12] GT "ado", "enfant"> age}');
223
-
224
- k_fn({"age":23,"name":"Emily"});
225
- // RETURNS: {"nom":"Emily","age":23}
226
-
227
- k_fn({"age":16,"name":"Katrina"});
228
- // RETURNS: {"nom":"Katrina","age":"ado"}
229
-
230
- k_fn({"age":2,"name":"Mark"});
231
- // RETURNS: {"nom":"Mark","age":"enfant"}
232
-
233
- var k_fn = k.compile('$t = < i: int, t: [ t ] > ; <$t, $int>');
234
-
235
- k_fn(1);
236
- // RETURNS: 1
237
-
238
- k_fn({"i":1});
239
- // RETURNS: {"i":1}
240
-
241
- k_fn([{"i":2},{"i":3},{"t":[]}]);
242
- // RETURNS: undefined
243
-
244
- k_fn({"t":[{"i":2},{"i":3},{"t":[]}]});
245
- // RETURNS: {"t":[{"i":2},{"i":3},{"t":[]}]}
152
+ > cat test.k
153
+ --------- comments start by #, --, or // ----------------------------------
154
+ < -- merge of 4 partial functions...
155
+ ["x=", .x, " & y=", .y], -- produces a vector of 4 values, if fields 'x' and 'y' are present
156
+ ["only x=", .x], -- produces a pair '["only x=", "value-of-x"]', for input like {"x":"value-of-x"}
157
+ -- it is defined only if field 'x' is present
158
+ ["only y=", .y],
159
+ ["no x nor y"] -- defined for all input, returns always the same one element vector
160
+ >
161
+ -- one of the string vectors is passed to the following partial function,
162
+ -- which produces a record (map) with one field "x&y", whose value is the
163
+ -- result of concatenating elements of the passed in vector
164
+ { CONCAT "x&y" }
165
+ ------------------------------------------------------------------------------
166
+
167
+ We can use it by:
168
+
169
+ > ./node_modules/.bin/k -k test.k
170
+
171
+ If we want to read `json` objects from a file, e.g., `my-objects.json`, we do
172
+
173
+ > ./node_modules/.bin/k -k test.k my-objects.json
174
+ {"x&y":"x=432 & y=123"}
175
+ {"x&y":"onlyx=987"}
176
+ {"x&y":"no x nor y"}
177
+
178
+ where:
179
+
180
+ > cat my-objects.json
181
+ ####################################################
182
+ # empty lines and lines starting with # are ignored
183
+ {"y": 123, "x": 432,"others": "..."}
184
+ {"x":987}
185
+ {"z":123}
186
+ ####################################################
187
+
188
+ ### k-REPL (Read-Evaluate-Print Loop)
189
+
190
+ Also there is a REPL, `./node_modules/.bin/k-repl`, which acts like a toy
191
+ shell for the language. E.g.:
192
+
193
+ > ./node_modules/.bin/k-repl
194
+ {'a' a, 'b' b} toJSON
195
+ => "{\"a\":\"a\",\"b\":\"b\"}"
196
+ {"a" a} toJSON fromJSON
197
+ => {"a":"a"}
198
+ inc = [(),1] PLUS; 1 inc inc
199
+ => 3
200
+ inc inc inc inc
201
+ => 7
202
+
203
+ ## Using from `javascript`
204
+
205
+ var k = require("k");
206
+
207
+ k_expression = '()';
208
+ k.run(k_expression,"ANYTHING...");
209
+ // RETURNS: "ANYTHING..."
210
+
211
+ k_expression = '{"ala" name, 23 age}';
212
+ k.run(k_expression,"ANYTHING...");
213
+ // RETURNS: {"name":"ala","age":23}
214
+
215
+ k_expression = '[.year, .age]';
216
+ k.run(k_expression,{"year":2002,"age":19});
217
+ // RETURNS: [2002,19]
218
+
219
+ k_expression = '[(), ()]';
220
+ k.run(k_expression,"duplicate me");
221
+ // RETURNS: ["duplicate me","duplicate me"]
222
+
223
+ k_expression = '[[[()]]]';
224
+ k.run(k_expression,"nesting");
225
+ // RETURNS: [[["nesting"]]]
226
+
227
+ k_expression = '[[()]] {() nested, .0.0 val}';
228
+ k.run(k_expression,"nesting and accessing");
229
+ // RETURNS: {"nested":[["nesting and accessing"]],"val":"nesting and accessing"}
230
+
231
+ k_expression = '0000';
232
+ k.run(k_expression,{"test":"parse integer"});
233
+ // RETURNS: 0
234
+
235
+ k_expression = '[.y,.x] PLUS';
236
+ k.run(k_expression,{"x":3,"y":4});
237
+ // RETURNS: 7
238
+
239
+ var k_fn = k.compile('{.name nom, <[.age, 18] GT .0, [.age, 12] GT "ado", "enfant"> age}');
240
+
241
+ k_fn({"age":23,"name":"Emily"});
242
+ // RETURNS: {"nom":"Emily","age":23}
243
+
244
+ k_fn({"age":16,"name":"Katrina"});
245
+ // RETURNS: {"nom":"Katrina","age":"ado"}
246
+
247
+ k_fn({"age":2,"name":"Mark"});
248
+ // RETURNS: {"nom":"Mark","age":"enfant"}
249
+
250
+ var k_fn = k.compile('$t = < i: int, t: [ t ] > ; <$t, $int>');
251
+
252
+ k_fn(1);
253
+ // RETURNS: 1
254
+
255
+ k_fn({"i":1});
256
+ // RETURNS: {"i":1}
257
+
258
+ k_fn([{"i":2},{"i":3},{"t":[]}]);
259
+ // RETURNS: undefined
260
+
261
+ k_fn({"t":[{"i":2},{"i":3},{"t":[]}]});
262
+ // RETURNS: {"t":[{"i":2},{"i":3},{"t":[]}]}
263
+
264
+ var k_fn = k.compile('$ < < [ int ] ints, [ bool ] bools > list, string None>');
265
+
266
+ k_fn({"None":"None"});
267
+ // RETURNS: {"None":"None"}
268
+
269
+ k_fn({"list":{"ints":[]}});
270
+ // RETURNS: {"list":{"ints":[]}}
271
+
272
+ k_fn({"list":{"ints":[1,2,3]}});
273
+ // RETURNS: {"list":{"ints":[1,2,3]}}