@fraczak/k 2.0.1 → 2.1.0
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 +89 -29
- package/package.json +1 -1
- package/parser.jison +5 -1
- package/parser.mjs +30 -20
- package/pretty.mjs +3 -2
- package/run.mjs +103 -22
package/README.md
CHANGED
|
@@ -94,6 +94,27 @@ the constant value. E.g.:
|
|
|
94
94
|
{123 int, "kScript" str, true bool, null null} :
|
|
95
95
|
"any" --> {"int":123,"str":"kScript","bool":true,"null":null}
|
|
96
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
|
+
|
|
97
118
|
#### Vector product
|
|
98
119
|
|
|
99
120
|
Vector product can be seen as an abbreviation for product whose field
|
|
@@ -111,51 +132,57 @@ can be written as `[.toto, .titi, 123]`.
|
|
|
111
132
|
|
|
112
133
|
### Pragmatic extensions, aka "standard library"
|
|
113
134
|
|
|
114
|
-
- `GT`
|
|
135
|
+
- `GT` -- identity for lists of decreasing elements; undefined otherwise
|
|
115
136
|
|
|
137
|
+
GT:
|
|
116
138
|
[4,3] --> [4,3]
|
|
117
139
|
[3,4] ... undefined
|
|
118
140
|
[] --> []
|
|
119
141
|
[4,3,0] --> [4,3,0]
|
|
120
142
|
|
|
121
|
-
- `EQ`
|
|
143
|
+
- `EQ` -- identity for lists of equal elements; undefined otherwise
|
|
122
144
|
|
|
145
|
+
EQ:
|
|
123
146
|
[4,4] --> [4,4]
|
|
124
147
|
[4,5] ... undefined
|
|
125
148
|
[4,4,4] --> [4,4,4]
|
|
126
149
|
[] --> []
|
|
127
150
|
|
|
128
|
-
- `
|
|
151
|
+
- `PLUS` and `TIMES` -- sum and product of lists of numbers
|
|
129
152
|
|
|
153
|
+
{PLUS plus, TIMES times} :
|
|
130
154
|
[1,2] --> {"plus":3,"times":2}
|
|
131
155
|
[2,2,2] --> {"plus":6,"times":8}
|
|
132
156
|
[] --> {"plus":0,"times":1}
|
|
133
157
|
|
|
134
|
-
- `CONCAT`
|
|
158
|
+
- `CONCAT` -- concatenation of lists of strings
|
|
135
159
|
|
|
160
|
+
CONCAT:
|
|
161
|
+
["a","bc","d"] --> "abcd"
|
|
136
162
|
["a","bc","d"] --> "abcd"
|
|
137
163
|
|
|
138
|
-
- `toJSON`
|
|
164
|
+
- `toJSON` and `fromJSON` -- conversion to and from JSON strings
|
|
139
165
|
|
|
166
|
+
toJSON:
|
|
140
167
|
{"a": 12} --> "{\"a\":12}"
|
|
141
168
|
|
|
142
|
-
|
|
169
|
+
fromJSON:
|
|
170
|
+
"{\"a\":12}" --> {"a":12}
|
|
171
|
+
"2.12" --> 2.12
|
|
172
|
+
"[1,2.11,0.3e-32]" --> [1,2.11,3e-33]
|
|
143
173
|
|
|
144
|
-
"{\"a\":12}" --> {"a":12}
|
|
145
174
|
|
|
146
175
|
- other predefined parial functions are: `DIV`, `FDIV`, `CONS`, `SNOC`, `toDateMsec`,
|
|
147
176
|
`toDateStr`, and `_log!`.
|
|
148
177
|
|
|
149
178
|
---
|
|
150
179
|
|
|
151
|
-
### Function definitions
|
|
180
|
+
### Function and code (i.e., _type_) definitions
|
|
152
181
|
|
|
153
182
|
dec = [(),-1] PLUS;
|
|
154
183
|
max = <SNOC [.0, .1 max] <GT.0, .1>, .0> ;
|
|
155
184
|
factorial = < [(),0] GT .0 [dec factorial, ()] TIMES, 1 >;
|
|
156
185
|
|
|
157
|
-
### Codes (_types_)
|
|
158
|
-
|
|
159
186
|
_Codes_ (prefixed by `$`) can be defined by taged union and product. E.g.:
|
|
160
187
|
|
|
161
188
|
$nat = <nat 1, {} 0>;
|
|
@@ -178,6 +205,44 @@ by `[ codeExp ]`. All members of the vector are the same code. E.g.,
|
|
|
178
205
|
-- of integers and a vector of strings
|
|
179
206
|
---
|
|
180
207
|
|
|
208
|
+
### List comprehension on vectors
|
|
209
|
+
|
|
210
|
+
A vector can be "open" by PIPE (`|`) operator so the following partial function is applied to
|
|
211
|
+
each element of the vector one by one, yielding another open value. An open value can be "closed",
|
|
212
|
+
i.e., turn into a regular vector using `CARET` (`^`) operator. E.g.:
|
|
213
|
+
|
|
214
|
+
```k
|
|
215
|
+
| .x ^ :
|
|
216
|
+
[{x:12}, {x:8,y:10}, {y:98}] --> [12,8]
|
|
217
|
+
[1,2,3] --> []
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The PIPE operator can be used, e.g., to define a Cartesian product:
|
|
221
|
+
|
|
222
|
+
```k
|
|
223
|
+
[.0 |, .1 |] ^ :
|
|
224
|
+
[[1,2], [3,4]] --> [[1,3],[1,4],[2,3],[2,4]]
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
or
|
|
228
|
+
|
|
229
|
+
```k
|
|
230
|
+
{ | x, | y } ^ :
|
|
231
|
+
[1,2] --> [{"x":1,"y":1},{"x":2,"y":1},{"x":1,"y":2},{"x":2,"y":2}]
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**QUIZ**: Write a function which will take a list of integers and an integer `x`, and count how many
|
|
235
|
+
times value `x` appears in the list. (see `Examples/list-comprehension.k` for a solution)
|
|
236
|
+
|
|
237
|
+
```k
|
|
238
|
+
count_occurrences =
|
|
239
|
+
$ { [int] list, int x }
|
|
240
|
+
-- ???
|
|
241
|
+
$ int;
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
181
246
|
## Examples
|
|
182
247
|
|
|
183
248
|
1. projection:
|
|
@@ -269,11 +334,11 @@ within `k`-expression is again prefixed by `$`.
|
|
|
269
334
|
|
|
270
335
|
## `k` (a command-line JSON processor using `k` syntax)
|
|
271
336
|
|
|
272
|
-
There is a wrapper, `./node_modules/.bin/k`
|
|
337
|
+
There is a wrapper, `k` (`./node_modules/.bin/k`), which makes it easy to
|
|
273
338
|
run the language from command line.
|
|
274
339
|
|
|
275
|
-
>
|
|
276
|
-
|
|
340
|
+
> k
|
|
341
|
+
... errors ...
|
|
277
342
|
Usage: ./node_modules/.bin/k ( k-expr | -k k-file) [ -1 ] [ json-file ]
|
|
278
343
|
E.g., cat '{"a": 10}' | ./node_modules/.bin/k '[(),()]'
|
|
279
344
|
|
|
@@ -281,14 +346,14 @@ For example:
|
|
|
281
346
|
|
|
282
347
|
1. One `k`-expression with one `json`-object:
|
|
283
348
|
|
|
284
|
-
> echo '{"x": 12, "y": 13}' |
|
|
349
|
+
> echo '{"x": 12, "y": 13}' | k '{ <.x, "no x"> x, () input}'
|
|
285
350
|
{"x":12,"input":{"x":12,"y":13}}
|
|
286
351
|
|
|
287
352
|
2. By providing only `k`-expression, the script will compile the
|
|
288
353
|
`k`-expression and apply the generated function to the `stdin`,
|
|
289
354
|
line by line:
|
|
290
355
|
|
|
291
|
-
>
|
|
356
|
+
> k '<["x=",.x," & y=",.y],["only x=",.x],["only y=",.y],["no x nor y"]>{CONCAT "x&y"}'
|
|
292
357
|
|
|
293
358
|
{"y": 123, "x": 432,"others": "..."} --> {"x&y":"x=432 & y=123"}
|
|
294
359
|
{"x": 987} --> {"x&y":"only x=987"}
|
|
@@ -316,11 +381,11 @@ For example:
|
|
|
316
381
|
|
|
317
382
|
We can use it by:
|
|
318
383
|
|
|
319
|
-
>
|
|
384
|
+
> k -k test.k
|
|
320
385
|
|
|
321
386
|
If we want to read `json` objects from a file, e.g., `my-objects.json`, we do
|
|
322
387
|
|
|
323
|
-
>
|
|
388
|
+
> k -k test.k my-objects.json
|
|
324
389
|
{"x&y":"x=432 & y=123"}
|
|
325
390
|
{"x&y":"only x=987"}
|
|
326
391
|
{"x&y":"no x nor y"}
|
|
@@ -340,11 +405,11 @@ For example:
|
|
|
340
405
|
### Short comparaison with `jq` tutorial examples: <https://stedolan.github.io/jq/tutorial/>
|
|
341
406
|
|
|
342
407
|
1.
|
|
343
|
-
curl 'https://api.github.com/
|
|
344
|
-
curl 'https://api.github.com/
|
|
408
|
+
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq '.'
|
|
409
|
+
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k '()' -1
|
|
345
410
|
2.
|
|
346
|
-
curl 'https://api.github.com/
|
|
347
|
-
curl 'https://api.github.com/
|
|
411
|
+
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq '.[0]'
|
|
412
|
+
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k '.0' -1
|
|
348
413
|
3.
|
|
349
414
|
jq '.[0] | {message: .commit.message, name: .commit.committer.name}'
|
|
350
415
|
k '.0 {.commit.message message, .commit.committer.name name}' -1
|
|
@@ -352,21 +417,16 @@ For example:
|
|
|
352
417
|
examples 4 and 5 of the `jq` tutorial are equivalent.
|
|
353
418
|
5.
|
|
354
419
|
jq '[.[] | {message: .commit.message, name: .commit.committer.name}]'
|
|
355
|
-
k '
|
|
356
|
-
map_f = <SNOC [.0 f,.1 map_f] CONS, [.0 f], []>; %\
|
|
357
|
-
map_f' -1
|
|
420
|
+
k '| .commit {.message message, .committer.name name} ^' -1
|
|
358
421
|
6.
|
|
359
422
|
jq '[.[] | {message: .commit.message, name: .commit.committer.name, parents: [.parents[].html_url]}]'
|
|
360
|
-
k '
|
|
361
|
-
f = {.commit.message message, .commit.committer.name name, .parents map_html_url parents}; %\
|
|
362
|
-
map_f = <SNOC [.0 f, .1 map_f] CONS, [.0 f] , []>; %\
|
|
363
|
-
map_f' -1
|
|
423
|
+
k '| {.commit.message message, .commit.committer.name name, .parents | .html_url ^ parents} ^' -1
|
|
364
424
|
|
|
365
425
|
---
|
|
366
426
|
|
|
367
427
|
## k-REPL (Read-Evaluate-Print Loop)
|
|
368
428
|
|
|
369
|
-
Also there is a REPL, `./node_modules/.bin/k-repl
|
|
429
|
+
Also there is a REPL, `k-repl` (`./node_modules/.bin/k-repl`), which acts like a toy
|
|
370
430
|
shell for the language. E.g.:
|
|
371
431
|
|
|
372
432
|
> ./node_modules/.bin/k-repl
|
package/package.json
CHANGED
package/parser.jison
CHANGED
|
@@ -44,6 +44,8 @@ function fromEscString(escString) {
|
|
|
44
44
|
";" return 'SC';
|
|
45
45
|
":" return 'COL';
|
|
46
46
|
"$" return 'DOLLAR';
|
|
47
|
+
"|" return 'PIPE';
|
|
48
|
+
"^" return 'CARET';
|
|
47
49
|
\"([^"\\]|\\(.|\n))*\"|\'([^'\\]|\\(.|\n))*\' return 'STRING';
|
|
48
50
|
[a-zA-Z_][a-zA-Z0-9_?!]* return 'NAME';
|
|
49
51
|
0|[-]?[1-9][0-9]* return 'INT';
|
|
@@ -52,7 +54,7 @@ function fromEscString(escString) {
|
|
|
52
54
|
/lex
|
|
53
55
|
|
|
54
56
|
%token NAME STRING INT
|
|
55
|
-
%token LA LC LB LP RA RP RB RC EQ DOT COMMA SC COL DOLLAR
|
|
57
|
+
%token LA LC LB LP RA RP RB RC EQ DOT COMMA SC COL DOLLAR PIPE CARET
|
|
56
58
|
%token EOF
|
|
57
59
|
|
|
58
60
|
%start input_with_eof
|
|
@@ -126,6 +128,8 @@ exp
|
|
|
126
128
|
| DOT str { $$ = {op: "dot", dot: $2}; }
|
|
127
129
|
| DOT name { $$ = {op: "dot", dot: $2}; }
|
|
128
130
|
| DOLLAR code { $$ = {op: "code", code: s.as_ref($2)}; }
|
|
131
|
+
| PIPE { $$ = {op: "pipe"}; }
|
|
132
|
+
| CARET { $$ = {op: "caret"}; }
|
|
129
133
|
;
|
|
130
134
|
|
|
131
135
|
labelled
|
package/parser.mjs
CHANGED
|
@@ -100,12 +100,12 @@ function fromEscString(escString) {
|
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
var parser = (function(){
|
|
103
|
-
var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[4,6,8,15,18,21,23,32,34],$V1=[1,7],$V2=[1,
|
|
103
|
+
var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[4,6,8,15,18,21,23,32,34,35,36],$V1=[1,7],$V2=[1,17],$V3=[1,18],$V4=[1,8],$V5=[1,9],$V6=[1,10],$V7=[1,11],$V8=[1,14],$V9=[1,15],$Va=[1,16],$Vb=[1,22],$Vc=[4,6,8,12,15,18,21,23,32,34,35,36],$Vd=[2,28],$Ve=[1,27],$Vf=[1,28],$Vg=[1,29],$Vh=[4,6,8,12,14,15,18,20,21,22,23,24,27,32,33,34,35,36],$Vi=[2,49],$Vj=[2,31],$Vk=[2,32],$Vl=[4,6,8,12,14,15,18,20,21,22,23,24,27,28,32,33,34,35,36],$Vm=[2,8],$Vn=[2,13],$Vo=[20,27],$Vp=[22,24,27],$Vq=[20,24,27],$Vr=[2,43],$Vs=[2,44],$Vt=[2,45];
|
|
104
104
|
var parser = {trace: function trace () { },
|
|
105
105
|
yy: {},
|
|
106
|
-
symbols_: {"error":2,"name":3,"NAME":4,"str":5,"STRING":6,"int":7,"INT":8,"input_with_eof":9,"defs":10,"comp":11,"EOF":12,"EQ":13,"SC":14,"DOLLAR":15,"codeDef":16,"code":17,"LC":18,"labelled_codes":19,"RC":20,"LB":21,"RB":22,"LA":23,"RA":24,"non_empty_labelled_codes":25,"code_label":26,"COMMA":27,"COL":28,"exp":29,"labelled":30,"list":31,"LP":32,"RP":33,"DOT":34,"
|
|
107
|
-
terminals_: {2:"error",4:"NAME",6:"STRING",8:"INT",12:"EOF",13:"EQ",14:"SC",15:"DOLLAR",18:"LC",20:"RC",21:"LB",22:"RB",23:"LA",24:"RA",27:"COMMA",28:"COL",32:"LP",33:"RP",34:"DOT"},
|
|
108
|
-
productions_: [0,[3,1],[5,1],[7,1],[9,3],[10,0],[10,5],[10,6],[17,1],[17,1],[16,3],[16,3],[16,3],[19,0],[19,1],[25,1],[25,3],[26,2],[26,2],[26,2],[26,3],[26,3],[26,3],[11,1],[11,2],[29,3],[29,3],[29,3],[29,1],[29,2],[29,3],[29,1],[29,1],[29,2],[29,2],[29,2],[29,2],[30,0],[30,1],[
|
|
106
|
+
symbols_: {"error":2,"name":3,"NAME":4,"str":5,"STRING":6,"int":7,"INT":8,"input_with_eof":9,"defs":10,"comp":11,"EOF":12,"EQ":13,"SC":14,"DOLLAR":15,"codeDef":16,"code":17,"LC":18,"labelled_codes":19,"RC":20,"LB":21,"RB":22,"LA":23,"RA":24,"non_empty_labelled_codes":25,"code_label":26,"COMMA":27,"COL":28,"exp":29,"labelled":30,"list":31,"LP":32,"RP":33,"DOT":34,"PIPE":35,"CARET":36,"non_empty_labelled":37,"comp_label":38,"non_empty_list":39,"$accept":0,"$end":1},
|
|
107
|
+
terminals_: {2:"error",4:"NAME",6:"STRING",8:"INT",12:"EOF",13:"EQ",14:"SC",15:"DOLLAR",18:"LC",20:"RC",21:"LB",22:"RB",23:"LA",24:"RA",27:"COMMA",28:"COL",32:"LP",33:"RP",34:"DOT",35:"PIPE",36:"CARET"},
|
|
108
|
+
productions_: [0,[3,1],[5,1],[7,1],[9,3],[10,0],[10,5],[10,6],[17,1],[17,1],[16,3],[16,3],[16,3],[19,0],[19,1],[25,1],[25,3],[26,2],[26,2],[26,2],[26,3],[26,3],[26,3],[11,1],[11,2],[29,3],[29,3],[29,3],[29,1],[29,2],[29,3],[29,1],[29,1],[29,2],[29,2],[29,2],[29,2],[29,1],[29,1],[30,0],[30,1],[37,1],[37,3],[38,2],[38,2],[38,2],[38,3],[38,3],[38,3],[31,0],[31,1],[39,1],[39,3]],
|
|
109
109
|
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
|
|
110
110
|
/* this == yyval */
|
|
111
111
|
|
|
@@ -139,7 +139,7 @@ break;
|
|
|
139
139
|
case 8:
|
|
140
140
|
this.$ = {code: "ref", ref: $$[$0]};
|
|
141
141
|
break;
|
|
142
|
-
case 9: case 23: case
|
|
142
|
+
case 9: case 23: case 40: case 50:
|
|
143
143
|
this.$ = $$[$0];
|
|
144
144
|
break;
|
|
145
145
|
case 10:
|
|
@@ -160,10 +160,10 @@ case 14:
|
|
|
160
160
|
return r }
|
|
161
161
|
, {});
|
|
162
162
|
break;
|
|
163
|
-
case 15: case
|
|
163
|
+
case 15: case 51:
|
|
164
164
|
this.$ = [$$[$0]];
|
|
165
165
|
break;
|
|
166
|
-
case 16: case
|
|
166
|
+
case 16: case 52:
|
|
167
167
|
this.$ = [].concat($$[$0-2],$$[$0]);
|
|
168
168
|
break;
|
|
169
169
|
case 17: case 18: case 19:
|
|
@@ -206,27 +206,33 @@ case 36:
|
|
|
206
206
|
this.$ = {op: "code", code: s.as_ref($$[$0])};
|
|
207
207
|
break;
|
|
208
208
|
case 37:
|
|
209
|
-
this.$ = {op: "
|
|
209
|
+
this.$ = {op: "pipe"};
|
|
210
|
+
break;
|
|
211
|
+
case 38:
|
|
212
|
+
this.$ = {op: "caret"};
|
|
210
213
|
break;
|
|
211
214
|
case 39:
|
|
215
|
+
this.$ = {op: "product", product: []};
|
|
216
|
+
break;
|
|
217
|
+
case 41:
|
|
212
218
|
this.$ = {op: "product", product: [$$[$0]]};
|
|
213
219
|
break;
|
|
214
|
-
case
|
|
220
|
+
case 42:
|
|
215
221
|
$$[$0-2].product = [].concat($$[$0-2].product,$$[$0]); this.$ = $$[$0-2];
|
|
216
222
|
break;
|
|
217
|
-
case
|
|
223
|
+
case 43: case 44: case 45:
|
|
218
224
|
this.$ = {label: $$[$0], exp: $$[$0-1]};
|
|
219
225
|
break;
|
|
220
|
-
case
|
|
226
|
+
case 46: case 47: case 48:
|
|
221
227
|
this.$ = {label: $$[$0-2], exp: $$[$0]};
|
|
222
228
|
break;
|
|
223
|
-
case
|
|
229
|
+
case 49:
|
|
224
230
|
this.$ = [];
|
|
225
231
|
break;
|
|
226
232
|
}
|
|
227
233
|
},
|
|
228
|
-
table: [o($V0,[2,5],{9:1,10:2}),{1:[3]},{3:4,4:$V1,5:12,6:$V2,7:13,8:$V3,11:3,15:[1,5],18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8},{3:
|
|
229
|
-
defaultActions: {
|
|
234
|
+
table: [o($V0,[2,5],{9:1,10:2}),{1:[3]},{3:4,4:$V1,5:12,6:$V2,7:13,8:$V3,11:3,15:[1,5],18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8,35:$V9,36:$Va},{3:21,4:$V1,5:12,6:$V2,7:13,8:$V3,12:[1,19],15:$Vb,18:$V4,21:$V5,23:$V6,29:20,32:$V7,34:$V8,35:$V9,36:$Va},o($Vc,$Vd,{13:[1,23]}),{3:24,4:$V1,16:26,17:25,18:$Ve,21:$Vf,23:$Vg},o($Vh,[2,23]),o([4,6,8,12,13,14,15,18,20,21,22,23,24,27,28,32,33,34,35,36],[2,1]),{3:34,4:$V1,5:35,6:$V2,7:36,8:$V3,11:33,15:$Vb,18:$V4,20:[2,39],21:$V5,23:$V6,29:6,30:30,32:$V7,34:$V8,35:$V9,36:$Va,37:31,38:32},{3:21,4:$V1,5:12,6:$V2,7:13,8:$V3,11:39,15:$Vb,18:$V4,21:$V5,22:$Vi,23:$V6,29:6,31:37,32:$V7,34:$V8,35:$V9,36:$Va,39:38},{3:21,4:$V1,5:12,6:$V2,7:13,8:$V3,11:39,15:$Vb,18:$V4,21:$V5,23:$V6,24:$Vi,29:6,31:40,32:$V7,34:$V8,35:$V9,36:$Va,39:38},{3:21,4:$V1,5:12,6:$V2,7:13,8:$V3,11:42,15:$Vb,18:$V4,21:$V5,23:$V6,29:6,32:$V7,33:[1,41],34:$V8,35:$V9,36:$Va},o($Vh,$Vj),o($Vh,$Vk),{3:45,4:$V1,5:44,6:$V2,7:43,8:$V3},o($Vh,[2,37]),o($Vh,[2,38]),o($Vl,[2,2]),o($Vl,[2,3]),{1:[2,4]},o($Vh,[2,24]),o($Vh,$Vd),{3:46,4:$V1,16:26,17:25,18:$Ve,21:$Vf,23:$Vg},{3:21,4:$V1,5:12,6:$V2,7:13,8:$V3,11:47,15:$Vb,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8,35:$V9,36:$Va},o($Vc,$Vm,{13:[1,48]}),o($Vh,[2,36]),o($Vh,[2,9]),{3:53,4:$V1,5:54,6:$V2,7:55,8:$V3,16:26,17:52,18:$Ve,19:49,20:$Vn,21:$Vf,23:$Vg,25:50,26:51},{3:46,4:$V1,16:26,17:56,18:$Ve,21:$Vf,23:$Vg},{3:53,4:$V1,5:54,6:$V2,7:55,8:$V3,16:26,17:52,18:$Ve,19:57,21:$Vf,23:$Vg,24:$Vn,25:50,26:51},{20:[1,58]},{20:[2,40],27:[1,59]},o($Vo,[2,41]),{3:60,4:$V1,5:61,6:$V2,7:62,8:$V3,15:$Vb,18:$V4,21:$V5,23:$V6,29:20,32:$V7,34:$V8,35:$V9,36:$Va},o($V0,$Vd,{28:[1,63]}),o($V0,$Vj,{28:[1,64]}),o($V0,$Vk,{28:[1,65]}),{22:[1,66]},o([22,24],[2,50],{27:[1,67]}),o($Vp,[2,51],{5:12,7:13,29:20,3:21,4:$V1,6:$V2,8:$V3,15:$Vb,18:$V4,21:$V5,23:$V6,32:$V7,34:$V8,35:$V9,36:$Va}),{24:[1,68]},o($Vh,[2,29]),{3:21,4:$V1,5:12,6:$V2,7:13,8:$V3,15:$Vb,18:$V4,21:$V5,23:$V6,29:20,32:$V7,33:[1,69],34:$V8,35:$V9,36:$Va},o($Vh,[2,33]),o($Vh,[2,34]),o($Vh,[2,35]),o($Vh,$Vm),{3:21,4:$V1,5:12,6:$V2,7:13,8:$V3,14:[1,70],15:$Vb,18:$V4,21:$V5,23:$V6,29:20,32:$V7,34:$V8,35:$V9,36:$Va},{16:71,18:$Ve,21:$Vf,23:$Vg},{20:[1,72]},o([20,24],[2,14],{27:[1,73]}),o($Vq,[2,15]),{3:74,4:$V1,5:75,6:$V2,7:76,8:$V3},o([4,6,8],$Vm,{28:[1,77]}),{28:[1,78]},{28:[1,79]},{22:[1,80]},{24:[1,81]},o($Vh,[2,25]),{3:34,4:$V1,5:35,6:$V2,7:36,8:$V3,11:33,15:$Vb,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8,35:$V9,36:$Va,38:82},o($V0,$Vd,{20:$Vr,27:$Vr}),o($V0,$Vj,{20:$Vs,27:$Vs}),o($V0,$Vk,{20:$Vt,27:$Vt}),{3:21,4:$V1,5:12,6:$V2,7:13,8:$V3,11:83,15:$Vb,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8,35:$V9,36:$Va},{3:21,4:$V1,5:12,6:$V2,7:13,8:$V3,11:84,15:$Vb,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8,35:$V9,36:$Va},{3:21,4:$V1,5:12,6:$V2,7:13,8:$V3,11:85,15:$Vb,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8,35:$V9,36:$Va},o($Vh,[2,26]),{3:21,4:$V1,5:12,6:$V2,7:13,8:$V3,11:86,15:$Vb,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8,35:$V9,36:$Va},o($Vh,[2,27]),o($Vh,[2,30]),o($V0,[2,6]),{14:[1,87]},o($Vh,[2,10]),{3:53,4:$V1,5:54,6:$V2,7:55,8:$V3,16:26,17:52,18:$Ve,21:$Vf,23:$Vg,26:88},o($Vq,[2,17]),o($Vq,[2,18]),o($Vq,[2,19]),{3:46,4:$V1,16:26,17:89,18:$Ve,21:$Vf,23:$Vg},{3:46,4:$V1,16:26,17:90,18:$Ve,21:$Vf,23:$Vg},{3:46,4:$V1,16:26,17:91,18:$Ve,21:$Vf,23:$Vg},o($Vh,[2,11]),o($Vh,[2,12]),o($Vo,[2,42]),o($Vo,[2,46],{5:12,7:13,29:20,3:21,4:$V1,6:$V2,8:$V3,15:$Vb,18:$V4,21:$V5,23:$V6,32:$V7,34:$V8,35:$V9,36:$Va}),o($Vo,[2,47],{5:12,7:13,29:20,3:21,4:$V1,6:$V2,8:$V3,15:$Vb,18:$V4,21:$V5,23:$V6,32:$V7,34:$V8,35:$V9,36:$Va}),o($Vo,[2,48],{5:12,7:13,29:20,3:21,4:$V1,6:$V2,8:$V3,15:$Vb,18:$V4,21:$V5,23:$V6,32:$V7,34:$V8,35:$V9,36:$Va}),o($Vp,[2,52],{5:12,7:13,29:20,3:21,4:$V1,6:$V2,8:$V3,15:$Vb,18:$V4,21:$V5,23:$V6,32:$V7,34:$V8,35:$V9,36:$Va}),o($V0,[2,7]),o($Vq,[2,16]),o($Vq,[2,20]),o($Vq,[2,21]),o($Vq,[2,22])],
|
|
235
|
+
defaultActions: {19:[2,4]},
|
|
230
236
|
parseError: function parseError (str, hash) {
|
|
231
237
|
if (hash.recoverable) {
|
|
232
238
|
this.trace(str);
|
|
@@ -734,18 +740,22 @@ case 15:return 28;
|
|
|
734
740
|
break;
|
|
735
741
|
case 16:return 15;
|
|
736
742
|
break;
|
|
737
|
-
case 17:return
|
|
743
|
+
case 17:return 35;
|
|
744
|
+
break;
|
|
745
|
+
case 18:return 36;
|
|
746
|
+
break;
|
|
747
|
+
case 19:return 6;
|
|
738
748
|
break;
|
|
739
|
-
case
|
|
749
|
+
case 20:return 4;
|
|
740
750
|
break;
|
|
741
|
-
case
|
|
751
|
+
case 21:return 8;
|
|
742
752
|
break;
|
|
743
|
-
case
|
|
753
|
+
case 22:return 12;
|
|
744
754
|
break;
|
|
745
755
|
}
|
|
746
756
|
},
|
|
747
|
-
rules: [/^(?:[/][*]([*][^/]|[^*])*[*][/])/,/^(?:(\/\/|#|%|--)[^\n]*)/,/^(?:\s+)/,/^(?:<)/,/^(?:\{)/,/^(?:\[)/,/^(?:\()/,/^(?:>)/,/^(?:\})/,/^(?:\])/,/^(?:\))/,/^(?:=)/,/^(?:\.)/,/^(?:,)/,/^(?:;)/,/^(?::)/,/^(?:\$)/,/^(?:"([^"\\]|\\(.|\n))*"|'([^'\\]|\\(.|\n))*')/,/^(?:[a-zA-Z_][a-zA-Z0-9_?!]*)/,/^(?:0|[-]?[1-9][0-9]*)/,/^(?:$)/],
|
|
748
|
-
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"inclusive":true}}
|
|
757
|
+
rules: [/^(?:[/][*]([*][^/]|[^*])*[*][/])/,/^(?:(\/\/|#|%|--)[^\n]*)/,/^(?:\s+)/,/^(?:<)/,/^(?:\{)/,/^(?:\[)/,/^(?:\()/,/^(?:>)/,/^(?:\})/,/^(?:\])/,/^(?:\))/,/^(?:=)/,/^(?:\.)/,/^(?:,)/,/^(?:;)/,/^(?::)/,/^(?:\$)/,/^(?:\|)/,/^(?:\^)/,/^(?:"([^"\\]|\\(.|\n))*"|'([^'\\]|\\(.|\n))*')/,/^(?:[a-zA-Z_][a-zA-Z0-9_?!]*)/,/^(?:0|[-]?[1-9][0-9]*)/,/^(?:$)/],
|
|
758
|
+
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22],"inclusive":true}}
|
|
749
759
|
});
|
|
750
760
|
return lexer;
|
|
751
761
|
})();
|
package/pretty.mjs
CHANGED
|
@@ -34,9 +34,10 @@ function prettyCode (codes, representatives, codeExp) {
|
|
|
34
34
|
case "product":
|
|
35
35
|
return `{${prettyCode_labels(codes, representatives, codeExp.product)}}`;
|
|
36
36
|
case "union":
|
|
37
|
-
return
|
|
37
|
+
return `< ${prettyCode_labels(codes, representatives, codeExp.union)} >`;
|
|
38
38
|
case "vector":
|
|
39
|
-
return `[${representatives
|
|
39
|
+
return `[${prettyCode(codes,representatives, {code:'ref', ref:codeExp.vector})}]`;
|
|
40
|
+
// return `[${representatives[codeExp.vector] || codeExp.vector}]`;
|
|
40
41
|
default:
|
|
41
42
|
return ":error";
|
|
42
43
|
}
|
package/run.mjs
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
|
|
1
3
|
const modulo = (a, b) => ((+a % (b = +b)) + b) % b;
|
|
2
4
|
const valid = (x) => (isNaN(x) ? undefined : x);
|
|
3
5
|
|
|
6
|
+
function isOpen(x) {
|
|
7
|
+
return (Array.isArray(x) && x.open);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function isClosed(x) {
|
|
11
|
+
return (Array.isArray(x) && !x.open);
|
|
12
|
+
}
|
|
13
|
+
|
|
4
14
|
const builtin = {
|
|
5
15
|
"_log!": (arg) => {
|
|
6
16
|
console.error(`_log!: ${JSON.stringify(arg)}`);
|
|
@@ -83,12 +93,25 @@ function verify(code, value) {
|
|
|
83
93
|
function run(exp, value) {
|
|
84
94
|
"use strict";
|
|
85
95
|
if (value === undefined) return;
|
|
96
|
+
if (isOpen(value)) {
|
|
97
|
+
if (exp.op === "caret") {
|
|
98
|
+
return [...value];
|
|
99
|
+
} else {
|
|
100
|
+
const result = [];
|
|
101
|
+
result.open = true
|
|
102
|
+
for (const v of value) {
|
|
103
|
+
const r = run(exp, v);
|
|
104
|
+
if (r !== undefined) result.push(r);
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
86
109
|
switch (exp.op) {
|
|
87
110
|
case "code":
|
|
88
111
|
if (verify(exp.code, value)) {
|
|
89
112
|
return value;
|
|
90
113
|
}
|
|
91
|
-
|
|
114
|
+
return;
|
|
92
115
|
case "identity":
|
|
93
116
|
return value;
|
|
94
117
|
case "str":
|
|
@@ -99,25 +122,24 @@ function run(exp, value) {
|
|
|
99
122
|
if (defn != null) {
|
|
100
123
|
return run(defn[defn.length - 1], value);
|
|
101
124
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (value == exp.dot) return {};
|
|
106
|
-
return;
|
|
125
|
+
const builtin_func = builtin[exp.ref];
|
|
126
|
+
if (builtin_func != null) {
|
|
127
|
+
return builtin_func(value);
|
|
107
128
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (exp.dot == "true") return {};
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
if (value === false) {
|
|
117
|
-
if (exp.dot == "false") return {};
|
|
129
|
+
throw(`Unknown ref: '${exp.ref}'`);
|
|
130
|
+
case "dot":
|
|
131
|
+
// a hack to allow something like 'null . null' or '0 . 0' to work by returning unit
|
|
132
|
+
if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
133
|
+
if (`${value}` === `${exp.dot}`) return {};
|
|
118
134
|
return;
|
|
119
135
|
}
|
|
120
136
|
return value[exp.dot];
|
|
137
|
+
case "pipe": {
|
|
138
|
+
assert(isClosed(value), `PIPE (|): Only a regular vector value can be "open".`);
|
|
139
|
+
const result = [...value];
|
|
140
|
+
result.open = true;
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
121
143
|
case "comp":
|
|
122
144
|
return exp.comp.reduce((value, exp) => {
|
|
123
145
|
if (value !== undefined) return run(exp, value);
|
|
@@ -131,26 +153,85 @@ function run(exp, value) {
|
|
|
131
153
|
}
|
|
132
154
|
return;
|
|
133
155
|
case "vector": {
|
|
134
|
-
|
|
156
|
+
let result = [];
|
|
157
|
+
let open = false;
|
|
135
158
|
for (let i = 0, len = exp.vector.length; i < len; i++) {
|
|
136
159
|
const r = run(exp.vector[i], value);
|
|
137
160
|
if (r === undefined) return;
|
|
138
|
-
|
|
161
|
+
if (open) {
|
|
162
|
+
if (isOpen(r)) {
|
|
163
|
+
const newResult = [];
|
|
164
|
+
newResult.open = true;
|
|
165
|
+
for (const x of result) {
|
|
166
|
+
for (const y of r) {
|
|
167
|
+
newResult.push([...x, y]);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
result = newResult;
|
|
171
|
+
} else {
|
|
172
|
+
for (const x of result) x.push(r);
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
if (isOpen(r)) {
|
|
176
|
+
open = true;
|
|
177
|
+
const newResult = [];
|
|
178
|
+
newResult.open = true;
|
|
179
|
+
for (const x of r) {
|
|
180
|
+
newResult.push([...result, x]);
|
|
181
|
+
}
|
|
182
|
+
result = newResult;
|
|
183
|
+
} else {
|
|
184
|
+
result.push(r);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
139
187
|
}
|
|
140
188
|
return result;
|
|
141
189
|
}
|
|
142
190
|
case "product": {
|
|
143
|
-
|
|
191
|
+
let result = {};
|
|
192
|
+
let open = false;
|
|
144
193
|
for (let i = 0, len = exp.product.length; i < len; i++) {
|
|
145
194
|
const { label, exp: e } = exp.product[i];
|
|
146
195
|
const r = run(e, value);
|
|
147
196
|
if (r === undefined) return;
|
|
148
|
-
|
|
197
|
+
if (open) {
|
|
198
|
+
if (isOpen(r)) {
|
|
199
|
+
let newResult = [];
|
|
200
|
+
newResult.open = true;
|
|
201
|
+
for (const v of r) {
|
|
202
|
+
for (const x of result) {
|
|
203
|
+
newResult.push({...x, [label]: v});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
result = newResult;
|
|
207
|
+
} else {
|
|
208
|
+
let newResult = [];
|
|
209
|
+
newResult.open = true;
|
|
210
|
+
for (const x of result) {
|
|
211
|
+
newResult.push({...x, [label]: r});
|
|
212
|
+
}
|
|
213
|
+
result = newResult;
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
if (isOpen(r)) {
|
|
217
|
+
open = true;
|
|
218
|
+
let newResult = [];
|
|
219
|
+
newResult.open = true;
|
|
220
|
+
for (const v of r.values()) {
|
|
221
|
+
newResult.push({...result, [label]: v});
|
|
222
|
+
}
|
|
223
|
+
result = newResult;
|
|
224
|
+
} else {
|
|
225
|
+
result[label] = r;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
149
228
|
}
|
|
150
|
-
return result
|
|
229
|
+
return result
|
|
151
230
|
}
|
|
231
|
+
case "caret":
|
|
232
|
+
assert(false, "CARET (^): Only an 'open' vector can be closed.");
|
|
152
233
|
default:
|
|
153
|
-
|
|
234
|
+
assert(false,`Unknown operation: '${exp.op}'`);
|
|
154
235
|
}
|
|
155
236
|
}
|
|
156
237
|
|