@fraczak/k 2.1.1 → 2.1.4
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/.vscode/launch.json +18 -0
- package/README.md +5 -6
- package/README.md.orig +527 -0
- package/package.json +1 -1
- package/parser.jison +2 -2
- package/parser.mjs +24 -24
- package/repl.mjs +46 -53
- package/run.mjs +135 -119
- package/symbol-table.mjs +17 -30
- package/vscode-profile-2023-12-12-23-11-48.cpuprofile +1 -0
- package/vscode-profile-2023-12-12-23-12-19.cpuprofile +1 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
|
|
8
|
+
{
|
|
9
|
+
"type": "node",
|
|
10
|
+
"request": "launch",
|
|
11
|
+
"name": "Launch Program",
|
|
12
|
+
"skipFiles": [
|
|
13
|
+
"<node_internals>/**"
|
|
14
|
+
],
|
|
15
|
+
"program": "${workspaceFolder}/repl.mjs"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
package/README.md
CHANGED
|
@@ -185,6 +185,7 @@ can be written as `[.toto, .titi, 123]`.
|
|
|
185
185
|
|
|
186
186
|
_Codes_ (prefixed by `$`) can be defined by taged union and product. E.g.:
|
|
187
187
|
|
|
188
|
+
|
|
188
189
|
$nat = <nat 1, {} 0>;
|
|
189
190
|
$pair = {nat x, nat y};
|
|
190
191
|
|
|
@@ -217,7 +218,7 @@ i.e., turn into a regular vector using `CARET` (`^`) operator. E.g.:
|
|
|
217
218
|
[1,2,3] --> []
|
|
218
219
|
```
|
|
219
220
|
|
|
220
|
-
The PIPE operator can be used
|
|
221
|
+
The PIPE operator can be used for defining the Cartesian product:
|
|
221
222
|
|
|
222
223
|
```k
|
|
223
224
|
[.0 |, .1 |] ^ :
|
|
@@ -241,13 +242,11 @@ times value `x` appears in the list. (see `Examples/list-comprehension.k` for a
|
|
|
241
242
|
$ int;
|
|
242
243
|
```
|
|
243
244
|
|
|
244
|
-
**WARNING**:
|
|
245
|
-
nested _list comprehension_ you cannot drop paranthesis anymore.
|
|
246
|
-
E.g., `| (| PLUS ^ .0) ^` and `| | PLUS ^ .0 ^` are two different functions:
|
|
245
|
+
**WARNING**: When using `CARET` operator paranthesis may be required, e.g., like in:
|
|
247
246
|
|
|
248
247
|
```k
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
| ( [|,|] ^ ) ^ :
|
|
249
|
+
[[1,2],[3,4]] --> [[[1,1],[1,2],[2,1],[2,2]],[[3,3],[3,4],[4,3],[4,4]]]
|
|
251
250
|
```
|
|
252
251
|
|
|
253
252
|
---
|
package/README.md.orig
ADDED
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
# k-language
|
|
2
|
+
|
|
3
|
+
npm install '@fraczak/k'
|
|
4
|
+
|
|
5
|
+
From javascript:
|
|
6
|
+
|
|
7
|
+
import k from "@fraczak/k";
|
|
8
|
+
|
|
9
|
+
const fn = k.compile("<.name,.nom,'?'>");
|
|
10
|
+
console.log([{name:"x"},{nom:"y"},{}].map(fn));
|
|
11
|
+
// returns: [ "x", "y", "?" ]
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## k - the way of building and manipulating JSON-like data
|
|
16
|
+
|
|
17
|
+
Technically, `k` is a notation for defining **first-order partial functions**.
|
|
18
|
+
|
|
19
|
+
An example of a _partial function_ is the _projection_, e.g., "`.toto`",
|
|
20
|
+
which maps an object to its property named `toto`, or it is not defined if
|
|
21
|
+
the property doesn't exist. E.g.,
|
|
22
|
+
|
|
23
|
+
1 .toto :
|
|
24
|
+
2 {"toto": 5, "titi": 10} --> 5
|
|
25
|
+
3 {"titi": 10} ... undefined // it is not a value!
|
|
26
|
+
|
|
27
|
+
> Note: The above 3 lines should be read as follows. A `k`-expression
|
|
28
|
+
> is printed in the first line (before "`:`"). The following lines
|
|
29
|
+
> are examples of the function defined by the `k`-expression applayed
|
|
30
|
+
> to JSON values (first part of each line). If the function for the
|
|
31
|
+
> value is defined, then the result is printed after "`-->`" (line 2 in
|
|
32
|
+
> the above example). If the function is not defined for the value,
|
|
33
|
+
> then "`... undefined`" is printed (line 3).
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
### Combining "partial functions"
|
|
38
|
+
|
|
39
|
+
There are three ways of combining functions:
|
|
40
|
+
|
|
41
|
+
1. **composition**: `(f1 f2 ...)`, e.g. `(.toto .titi)` extracts
|
|
42
|
+
nested field.
|
|
43
|
+
|
|
44
|
+
(.toto .titi) :
|
|
45
|
+
{"toto": {"titi": 10}} --> 10
|
|
46
|
+
{"toto": 10 } ... undefined
|
|
47
|
+
{} ... undefined
|
|
48
|
+
|
|
49
|
+
2. **merge**: `< f1, f2,... >`, e.g., `<.toto, .titi>` extracts field
|
|
50
|
+
`toto` if present; otherwise extracts `titi`.
|
|
51
|
+
|
|
52
|
+
<.toto, .titi> :
|
|
53
|
+
{"toto": 5, "titi": 10} --> 5
|
|
54
|
+
{"titi": 10 } --> 10
|
|
55
|
+
{} ... undefined
|
|
56
|
+
|
|
57
|
+
3. **product**: `{ f1 label1, f2 label2, ...}`, e.g., `{.toto TOTO,
|
|
58
|
+
.titi TITI}` extracts two fields and builds a record out of them.
|
|
59
|
+
|
|
60
|
+
{.toto TOTO, .titi TITI} :
|
|
61
|
+
{"toto": 5, "titi": 10, "x": 3} --> {"TOTO": 5, "TITI": 10}
|
|
62
|
+
{"titi": 10 } ... undefined
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
**QUIZ**: What is:
|
|
67
|
+
|
|
68
|
+
- empty composition: `()` ?
|
|
69
|
+
- empty merge: `<>` ?
|
|
70
|
+
- empty product: `{}` ?
|
|
71
|
+
- `{{{{} s} s} s}` ?
|
|
72
|
+
- `({{{() a} b} c} .c .b .a)` ?
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### Syntactic sugar
|
|
77
|
+
|
|
78
|
+
- parenthesis can be omitted, except for the empty composition `()`,
|
|
79
|
+
- dot (`.`) in "projection" acts as a separator so the space around it can be omitted.
|
|
80
|
+
|
|
81
|
+
For example, `[(.toto .titi (.0 .1))]` can be written as `[.toto.titi.0.1]`.
|
|
82
|
+
|
|
83
|
+
Comments can be introduced by `//`, `--`, `%`, or `#` and extends to
|
|
84
|
+
the end of line. Multiline `C`-like comments, `/* ... */`, are also
|
|
85
|
+
supported.
|
|
86
|
+
|
|
87
|
+
### Basic extensions
|
|
88
|
+
|
|
89
|
+
#### Constants, i.e., literals for `strings`, `integers`, `booleans`, and `null`
|
|
90
|
+
|
|
91
|
+
A constant defines a function which ignores its argument and produces
|
|
92
|
+
the constant value. E.g.:
|
|
93
|
+
|
|
94
|
+
{123 int, "kScript" str, true bool, null null} :
|
|
95
|
+
"any" --> {"int":123,"str":"kScript","bool":true,"null":null}
|
|
96
|
+
|
|
97
|
+
Those values, i.e., `strings`, `integers`, `booleans`, and `null`, admit the
|
|
98
|
+
projection to the canonicat string representation of the value, e.g.:
|
|
99
|
+
|
|
100
|
+
.2 :
|
|
101
|
+
2 --> {}
|
|
102
|
+
"2" --> {}
|
|
103
|
+
4 ... undefined
|
|
104
|
+
true ... undefined
|
|
105
|
+
|
|
106
|
+
.true :
|
|
107
|
+
true --> {}
|
|
108
|
+
"true" --> {}
|
|
109
|
+
4 ... undefined
|
|
110
|
+
"toto" ... undefined
|
|
111
|
+
|
|
112
|
+
.null :
|
|
113
|
+
null --> {}
|
|
114
|
+
"null" --> {}
|
|
115
|
+
4 ... undefined
|
|
116
|
+
false ... undefined
|
|
117
|
+
|
|
118
|
+
#### Vector product
|
|
119
|
+
|
|
120
|
+
Vector product can be seen as an abbreviation for product whose field
|
|
121
|
+
names are integers starting from zero. E.g., `{.toto 0, .titi 1, 123 2}`
|
|
122
|
+
can be written as `[.toto, .titi, 123]`.
|
|
123
|
+
|
|
124
|
+
[.toto, .titi, 12] :
|
|
125
|
+
{"toto": 5, "titi": 10 } --> [5, 10, 12]
|
|
126
|
+
|
|
127
|
+
.1 :
|
|
128
|
+
["A","B","C"] --> "B"
|
|
129
|
+
["a"] ... undefined
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
### Pragmatic extensions, aka "standard library"
|
|
134
|
+
|
|
135
|
+
- `GT` -- identity for lists of decreasing elements; undefined otherwise
|
|
136
|
+
|
|
137
|
+
GT:
|
|
138
|
+
[4,3] --> [4,3]
|
|
139
|
+
[3,4] ... undefined
|
|
140
|
+
[] --> []
|
|
141
|
+
[4,3,0] --> [4,3,0]
|
|
142
|
+
|
|
143
|
+
- `EQ` -- identity for lists of equal elements; undefined otherwise
|
|
144
|
+
|
|
145
|
+
EQ:
|
|
146
|
+
[4,4] --> [4,4]
|
|
147
|
+
[4,5] ... undefined
|
|
148
|
+
[4,4,4] --> [4,4,4]
|
|
149
|
+
[] --> []
|
|
150
|
+
|
|
151
|
+
- `PLUS` and `TIMES` -- sum and product of lists of numbers
|
|
152
|
+
|
|
153
|
+
{PLUS plus, TIMES times} :
|
|
154
|
+
[1,2] --> {"plus":3,"times":2}
|
|
155
|
+
[2,2,2] --> {"plus":6,"times":8}
|
|
156
|
+
[] --> {"plus":0,"times":1}
|
|
157
|
+
|
|
158
|
+
- `CONCAT` -- concatenation of lists of strings
|
|
159
|
+
|
|
160
|
+
CONCAT:
|
|
161
|
+
["a","bc","d"] --> "abcd"
|
|
162
|
+
["a","bc","d"] --> "abcd"
|
|
163
|
+
|
|
164
|
+
- `toJSON` and `fromJSON` -- conversion to and from JSON strings
|
|
165
|
+
|
|
166
|
+
toJSON:
|
|
167
|
+
{"a": 12} --> "{\"a\":12}"
|
|
168
|
+
|
|
169
|
+
fromJSON:
|
|
170
|
+
"{\"a\":12}" --> {"a":12}
|
|
171
|
+
"2.12" --> 2.12
|
|
172
|
+
"[1,2.11,0.3e-32]" --> [1,2.11,3e-33]
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
- other predefined parial functions are: `DIV`, `FDIV`, `CONS`, `SNOC`, `toDateMsec`,
|
|
176
|
+
`toDateStr`, and `_log!`.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
### Function and code (i.e., _type_) definitions
|
|
181
|
+
|
|
182
|
+
dec = [(),-1] PLUS;
|
|
183
|
+
max = <SNOC [.0, .1 max] <GT.0, .1>, .0> ;
|
|
184
|
+
factorial = < [(),0] GT .0 [dec factorial, ()] TIMES, 1 >;
|
|
185
|
+
|
|
186
|
+
<<<<<<< HEAD
|
|
187
|
+
_Codes_ (prefixed by `$`) can be defined by taged union and product. E.g.:
|
|
188
|
+
=======
|
|
189
|
+
### Codes (schemas, i.e., _non-functional types_)
|
|
190
|
+
|
|
191
|
+
_Codes_ (prefixed by `$`) can be defined by tagged union and product. E.g.:
|
|
192
|
+
>>>>>>> b8f6bd5 (Minor doc changes)
|
|
193
|
+
|
|
194
|
+
$nat = <nat 1, {} 0>;
|
|
195
|
+
$pair = {nat x, nat y};
|
|
196
|
+
|
|
197
|
+
suc = {$nat 1};
|
|
198
|
+
add = $pair <{.x.1 x, .y suc y} add, .y>;
|
|
199
|
+
|
|
200
|
+
#### Basic extension codes
|
|
201
|
+
|
|
202
|
+
Since _basic extension_ introduces integers, booleans, and strings, there are three
|
|
203
|
+
predefined types: `int`, `bool`, and `string`. A vector product code can also be defined
|
|
204
|
+
by `[ codeExp ]`. All members of the vector are the same code. E.g.,
|
|
205
|
+
|
|
206
|
+
$intVector = [ int ];
|
|
207
|
+
$boolVector = [ bool ];
|
|
208
|
+
$tree = [ tree ];
|
|
209
|
+
|
|
210
|
+
emptyList? = $intVector $[ string ]; -- as only an empty vector can be a vector
|
|
211
|
+
-- of integers and a vector of strings
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
### List comprehension on vectors (experimental!)
|
|
215
|
+
|
|
216
|
+
A vector can be "open" by PIPE (`|`) operator so the following partial function is applied to
|
|
217
|
+
each element of the vector one by one, yielding another open value. An open value can be "closed",
|
|
218
|
+
i.e., turn into a regular vector using `CARET` (`^`) operator. E.g.:
|
|
219
|
+
|
|
220
|
+
```k
|
|
221
|
+
| .x ^ :
|
|
222
|
+
[{x:12}, {x:8,y:10}, {y:98}] --> [12,8]
|
|
223
|
+
[1,2,3] --> []
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The PIPE operator can be used for defining the Cartesian product:
|
|
227
|
+
|
|
228
|
+
```k
|
|
229
|
+
[.0 |, .1 |] ^ :
|
|
230
|
+
[[1,2], [3,4]] --> [[1,3],[1,4],[2,3],[2,4]]
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
or
|
|
234
|
+
|
|
235
|
+
```k
|
|
236
|
+
{ | x, | y } ^ :
|
|
237
|
+
[1,2] --> [{"x":1,"y":1},{"x":2,"y":1},{"x":1,"y":2},{"x":2,"y":2}]
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**QUIZ**: Write a function which will take a list of integers and an integer `x`, and count how many
|
|
241
|
+
times value `x` appears in the list. (see `Examples/list-comprehension.k` for a solution)
|
|
242
|
+
|
|
243
|
+
```k
|
|
244
|
+
count_occurrences =
|
|
245
|
+
$ { [int] list, int x }
|
|
246
|
+
-- ???
|
|
247
|
+
$ int;
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**WARNING**: When using `CARET` operator paranthesis may be required, e.g., like in:
|
|
251
|
+
|
|
252
|
+
```k
|
|
253
|
+
| ( [|,|] ^ ) ^ :
|
|
254
|
+
[[1,2],[3,4]] --> [[[1,1],[1,2],[2,1],[2,2]],[[3,3],[3,4],[4,3],[4,4]]]
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Examples
|
|
260
|
+
|
|
261
|
+
1. projection:
|
|
262
|
+
|
|
263
|
+
.x
|
|
264
|
+
."field name"
|
|
265
|
+
.4
|
|
266
|
+
|
|
267
|
+
The function is defined only if its argument is a structure with
|
|
268
|
+
the field (or a vector with the index).
|
|
269
|
+
|
|
270
|
+
2. _constants_, literals for Strings, Booleans, and
|
|
271
|
+
Integers. Examples:
|
|
272
|
+
|
|
273
|
+
"a string"
|
|
274
|
+
'another "String"'
|
|
275
|
+
123
|
|
276
|
+
false
|
|
277
|
+
null
|
|
278
|
+
|
|
279
|
+
3. "built-in" functions:
|
|
280
|
+
|
|
281
|
+
[1, 2, 3] PLUS -- integer constant function 6
|
|
282
|
+
[4, 4] TIMES toJSON -- string constant function "16"
|
|
283
|
+
[3, 2] GT -- vector constant function [3, 2]
|
|
284
|
+
[3, 4] GT -- ... undefined
|
|
285
|
+
|
|
286
|
+
A more interesting example could be:
|
|
287
|
+
|
|
288
|
+
< GT .0, .1>
|
|
289
|
+
|
|
290
|
+
which selects the maximum element in two element vector, i.e.,
|
|
291
|
+
|
|
292
|
+
[3,8] < GT .0, .1 > --> 8
|
|
293
|
+
|
|
294
|
+
### User defined functions
|
|
295
|
+
|
|
296
|
+
`k`-expression can be prefixed by function definitions. E.g.:
|
|
297
|
+
|
|
298
|
+
dec = [(),-1] PLUS;
|
|
299
|
+
zero? = [(),0] EQ 0;
|
|
300
|
+
factorial = <
|
|
301
|
+
zero? 1,
|
|
302
|
+
[dec factorial, ()] TIMES
|
|
303
|
+
>;
|
|
304
|
+
{ () x, factorial "x!" }
|
|
305
|
+
|
|
306
|
+
Another example could be finding the biggest (max) value in a vector:
|
|
307
|
+
|
|
308
|
+
max = <
|
|
309
|
+
SNOC # [x0, x1, x2, ...] --> [x0, [x1, x2, ...]]
|
|
310
|
+
[.0, .1 max] # [x0, [x1, x2, ...]] --> [x0, max(x1,x2,...)], i.e., recursive call
|
|
311
|
+
<GT .0, .1> # if x0 > max(x1,x2,...) then x0 else max(x1,x2,...)
|
|
312
|
+
, # when SNOC is not defined, i.e., if the input vector has one element:
|
|
313
|
+
.0 # [x0] --> x0
|
|
314
|
+
>;
|
|
315
|
+
max
|
|
316
|
+
|
|
317
|
+
### Value encodings (_codes_)
|
|
318
|
+
|
|
319
|
+
There are three predefined value encodings: `int`, `string`, and
|
|
320
|
+
`bool`. The language supports `code`-expressions:
|
|
321
|
+
|
|
322
|
+
- product, e.g., `{int x, int y, bool flag}`
|
|
323
|
+
- disjoint union, e.g., `<{} true, {} false>`
|
|
324
|
+
- vector, e.g., `[ int ]` (all elements of the vector use the same
|
|
325
|
+
encoding)
|
|
326
|
+
|
|
327
|
+
One can define recursive codes. E.g.:
|
|
328
|
+
|
|
329
|
+
$tree = <string leaf, {tree left, tree right} tree>;
|
|
330
|
+
|
|
331
|
+
Each _code_ definition starts with a `$`.
|
|
332
|
+
The above example defines new code called _tree_.
|
|
333
|
+
|
|
334
|
+
The code can be then used in a `k`-expression as a filter. A `code`-expression
|
|
335
|
+
within `k`-expression is again prefixed by `$`.
|
|
336
|
+
|
|
337
|
+
$ tree = <string leaf, {tree left, tree right} tree>;
|
|
338
|
+
inc = [(),1] PLUS;
|
|
339
|
+
max = <GT .0, .1>;
|
|
340
|
+
height = $ tree <
|
|
341
|
+
.leaf 0,
|
|
342
|
+
.tree [.left height, .right height] max inc
|
|
343
|
+
> $ int;
|
|
344
|
+
height
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## `k` (a command-line JSON processor using `k` syntax)
|
|
349
|
+
|
|
350
|
+
There is a wrapper, `k` (`./node_modules/.bin/k`), which makes it easy to
|
|
351
|
+
run the language from command line.
|
|
352
|
+
|
|
353
|
+
> k
|
|
354
|
+
... errors ...
|
|
355
|
+
Usage: ./node_modules/.bin/k ( k-expr | -k k-file) [ -1 ] [ json-file ]
|
|
356
|
+
E.g., cat '{"a": 10}' | ./node_modules/.bin/k '[(),()]'
|
|
357
|
+
|
|
358
|
+
For example:
|
|
359
|
+
|
|
360
|
+
1. One `k`-expression with one `json`-object:
|
|
361
|
+
|
|
362
|
+
> echo '{"x": 12, "y": 13}' | k '{ <.x, "no x"> x, () input}'
|
|
363
|
+
{"x":12,"input":{"x":12,"y":13}}
|
|
364
|
+
|
|
365
|
+
2. By providing only `k`-expression, the script will compile the
|
|
366
|
+
`k`-expression and apply the generated function to the `stdin`,
|
|
367
|
+
line by line:
|
|
368
|
+
|
|
369
|
+
> k '<["x=",.x," & y=",.y],["only x=",.x],["only y=",.y],["no x nor y"]>{CONCAT "x&y"}'
|
|
370
|
+
|
|
371
|
+
{"y": 123, "x": 432,"others": "..."} --> {"x&y":"x=432 & y=123"}
|
|
372
|
+
{"x": 987} --> {"x&y":"only x=987"}
|
|
373
|
+
{"z": 123} --> {"x&y":"no x nor y"}
|
|
374
|
+
^D - to interrupt
|
|
375
|
+
|
|
376
|
+
If the input is a multiline json object, we need to add `-1` to the command-line options.
|
|
377
|
+
|
|
378
|
+
3. If the `k`-expression is long, it can be put in a file, e.g.:
|
|
379
|
+
|
|
380
|
+
> cat test.k
|
|
381
|
+
--------- comments start by #, --, or // ----------------------------------
|
|
382
|
+
< -- merge of 4 partial functions...
|
|
383
|
+
["x=", .x, " & y=", .y], -- produces a vector of 4 values, if fields 'x' and 'y' are present
|
|
384
|
+
["only x=", .x], -- produces a pair '["only x=", "value-of-x"]', for input like {"x":"value-of-x"}
|
|
385
|
+
-- it is defined only if field 'x' is present
|
|
386
|
+
["only y=", .y],
|
|
387
|
+
["no x nor y"] -- defined for all input, returns always the same one element vector
|
|
388
|
+
>
|
|
389
|
+
-- one of the string vectors is passed to the following partial function,
|
|
390
|
+
-- which produces a record (map) with one field "x&y", whose value is the
|
|
391
|
+
-- result of concatenating elements of the passed in vector
|
|
392
|
+
{ CONCAT "x&y" }
|
|
393
|
+
------------------------------------------------------------------------------
|
|
394
|
+
|
|
395
|
+
We can use it by:
|
|
396
|
+
|
|
397
|
+
> k -k test.k
|
|
398
|
+
|
|
399
|
+
If we want to read `json` objects from a file, e.g., `my-objects.json`, we do
|
|
400
|
+
|
|
401
|
+
> k -k test.k my-objects.json
|
|
402
|
+
{"x&y":"x=432 & y=123"}
|
|
403
|
+
{"x&y":"only x=987"}
|
|
404
|
+
{"x&y":"no x nor y"}
|
|
405
|
+
|
|
406
|
+
where:
|
|
407
|
+
|
|
408
|
+
> cat my-objects.json
|
|
409
|
+
####################################################
|
|
410
|
+
# empty lines and lines starting with # are ignored
|
|
411
|
+
{"y": 123, "x": 432,"others": "..."}
|
|
412
|
+
{"x": 987}
|
|
413
|
+
{"z": 123}
|
|
414
|
+
####################################################
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
### Short comparaison with `jq` tutorial examples: <https://stedolan.github.io/jq/tutorial/>
|
|
419
|
+
|
|
420
|
+
1.
|
|
421
|
+
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq '.'
|
|
422
|
+
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k '()' -1
|
|
423
|
+
2.
|
|
424
|
+
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq '.[0]'
|
|
425
|
+
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k '.0' -1
|
|
426
|
+
3.
|
|
427
|
+
jq '.[0] | {message: .commit.message, name: .commit.committer.name}'
|
|
428
|
+
k '.0 {.commit.message message, .commit.committer.name name}' -1
|
|
429
|
+
4. note: `k`-expression defines a partial function yielding a single json object, i.e., as far as `k` is concerned,
|
|
430
|
+
examples 4 and 5 of the `jq` tutorial are equivalent.
|
|
431
|
+
5.
|
|
432
|
+
jq '[.[] | {message: .commit.message, name: .commit.committer.name}]'
|
|
433
|
+
k '| .commit {.message message, .committer.name name} ^' -1
|
|
434
|
+
6.
|
|
435
|
+
jq '[.[] | {message: .commit.message, name: .commit.committer.name, parents: [.parents[].html_url]}]'
|
|
436
|
+
k '| {.commit.message message, .commit.committer.name name, .parents | .html_url ^ parents} ^' -1
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## k-REPL (Read-Evaluate-Print Loop)
|
|
441
|
+
|
|
442
|
+
Also there is a REPL, `k-repl` (`./node_modules/.bin/k-repl`), which acts like a toy
|
|
443
|
+
shell for the language. E.g.:
|
|
444
|
+
|
|
445
|
+
> ./node_modules/.bin/k-repl
|
|
446
|
+
{'a' a, 'b' b} toJSON
|
|
447
|
+
=> "{\"a\":\"a\",\"b\":\"b\"}"
|
|
448
|
+
{"a" a} toJSON fromJSON
|
|
449
|
+
=> {"a": "a"}
|
|
450
|
+
inc = [(),1] PLUS; 1 inc inc
|
|
451
|
+
=> 3
|
|
452
|
+
inc inc inc inc
|
|
453
|
+
=> 7
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## Using `k` from `javascript`
|
|
458
|
+
|
|
459
|
+
import k from "@fraczak/k";
|
|
460
|
+
|
|
461
|
+
let k_expression = '()';
|
|
462
|
+
k.run(k_expression,"ANYTHING...");
|
|
463
|
+
// RETURNS: "ANYTHING..."
|
|
464
|
+
|
|
465
|
+
k_expression = '{"ala" name, 23 age}';
|
|
466
|
+
k.run(k_expression,"ANYTHING...");
|
|
467
|
+
// RETURNS: {"name":"ala","age":23}
|
|
468
|
+
|
|
469
|
+
k_expression = '[.year, .age]';
|
|
470
|
+
k.run(k_expression,{"year":2002,"age":19});
|
|
471
|
+
// RETURNS: [2002,19]
|
|
472
|
+
|
|
473
|
+
k_expression = '[(), ()]';
|
|
474
|
+
k.run(k_expression,"duplicate me");
|
|
475
|
+
// RETURNS: ["duplicate me","duplicate me"]
|
|
476
|
+
|
|
477
|
+
k_expression = '[[[()]]]';
|
|
478
|
+
k.run(k_expression,"nesting");
|
|
479
|
+
// RETURNS: [[["nesting"]]]
|
|
480
|
+
|
|
481
|
+
k_expression = '[[()]] {() nested, .0.0 val}';
|
|
482
|
+
k.run(k_expression,"nesting and accessing");
|
|
483
|
+
// RETURNS: {"nested":[["nesting and accessing"]],"val":"nesting and accessing"}
|
|
484
|
+
|
|
485
|
+
k_expression = '0000';
|
|
486
|
+
k.run(k_expression,{"test":"parse integer"});
|
|
487
|
+
// RETURNS: 0
|
|
488
|
+
|
|
489
|
+
k_expression = '[.y,.x] PLUS';
|
|
490
|
+
k.run(k_expression,{"x":3,"y":4});
|
|
491
|
+
// RETURNS: 7
|
|
492
|
+
|
|
493
|
+
var k_fn = k.compile('{.name nom, <[.age, 18] GT .0, [.age, 12] GT "ado", "enfant"> age}');
|
|
494
|
+
|
|
495
|
+
k_fn({"age":23,"name":"Emily"});
|
|
496
|
+
// RETURNS: {"nom":"Emily","age":23}
|
|
497
|
+
|
|
498
|
+
k_fn({"age":16,"name":"Katrina"});
|
|
499
|
+
// RETURNS: {"nom":"Katrina","age":"ado"}
|
|
500
|
+
|
|
501
|
+
k_fn({"age":2,"name":"Mark"});
|
|
502
|
+
// RETURNS: {"nom":"Mark","age":"enfant"}
|
|
503
|
+
|
|
504
|
+
k_fn = k.compile('$t = < i: int, t: [ t ] > ; <$t, $int>');
|
|
505
|
+
|
|
506
|
+
k_fn(1);
|
|
507
|
+
// RETURNS: 1
|
|
508
|
+
|
|
509
|
+
k_fn({"i":1});
|
|
510
|
+
// RETURNS: {"i":1}
|
|
511
|
+
|
|
512
|
+
k_fn([{"i":2},{"i":3},{"t":[]}]);
|
|
513
|
+
// RETURNS: undefined
|
|
514
|
+
|
|
515
|
+
k_fn({"t":[{"i":2},{"i":3},{"t":[]}]});
|
|
516
|
+
// RETURNS: {"t":[{"i":2},{"i":3},{"t":[]}]}
|
|
517
|
+
|
|
518
|
+
k_fn = k.compile('$ < < [ int ] ints, [ bool ] bools > list, string None>');
|
|
519
|
+
|
|
520
|
+
k_fn({"None":"None"});
|
|
521
|
+
// RETURNS: {"None":"None"}
|
|
522
|
+
|
|
523
|
+
k_fn({"list":{"ints":[]}});
|
|
524
|
+
// RETURNS: {"list":{"ints":[]}}
|
|
525
|
+
|
|
526
|
+
k_fn({"list":{"ints":[1,2,3]}});
|
|
527
|
+
// RETURNS: {"list":{"ints":[1,2,3]}}
|
package/package.json
CHANGED
package/parser.jison
CHANGED
|
@@ -54,7 +54,7 @@ function fromEscString(escString) {
|
|
|
54
54
|
/lex
|
|
55
55
|
|
|
56
56
|
%token NAME STRING INT
|
|
57
|
-
%token LA LC LB LP RA RP RB RC EQ DOT COMMA SC COL DOLLAR PIPE CARET
|
|
57
|
+
%token LA LC LB LP RA RP RB RC EQ DOT COMMA SC COL DOLLAR PIPE CARET
|
|
58
58
|
%token EOF
|
|
59
59
|
|
|
60
60
|
%start input_with_eof
|
|
@@ -113,6 +113,7 @@ code_label
|
|
|
113
113
|
comp
|
|
114
114
|
: exp { $$ = $1; }
|
|
115
115
|
| comp exp { $$ = s.comp($1, $2); }
|
|
116
|
+
| comp CARET { $$ = {op: 'caret', caret: $1}; }
|
|
116
117
|
;
|
|
117
118
|
|
|
118
119
|
exp
|
|
@@ -129,7 +130,6 @@ exp
|
|
|
129
130
|
| DOT name { $$ = {op: "dot", dot: $2}; }
|
|
130
131
|
| DOLLAR code { $$ = {op: "code", code: s.as_ref($2)}; }
|
|
131
132
|
| PIPE { $$ = {op: "pipe"}; }
|
|
132
|
-
| CARET { $$ = {op: "caret"}; }
|
|
133
133
|
;
|
|
134
134
|
|
|
135
135
|
labelled
|