@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 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` : -- identity for lists of decreasing elements; undefined otherwise
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` : -- identity for lists of equal elements; undefined otherwise
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
- - `{PLUS plus, TIMES times}` :
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
- - `fromJSON` :
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` , which makes it easy to
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
- > ./node_modules/.bin/k
276
- ... errors ...
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}' | ./k.coffee '{ <.x, "no x"> x, () input}'
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
- > ./node_modules/.bin/k '<["x=",.x," & y=",.y],["only x=",.x],["only y=",.y],["no x nor y"]>{CONCAT "x&y"}'
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
- > ./node_modules/.bin/k -k test.k
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
- > ./node_modules/.bin/k -k test.k my-objects.json
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/repos/stedolan/jq/commits?per_page=5' | jq '.'
344
- curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | k '()' -1
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/repos/stedolan/jq/commits?per_page=5' | jq '.[0]'
347
- curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | k '.0' -1
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 'f = .commit {.message message, .committer.name name}; %\
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 'map_html_url = <SNOC [.0 .html_url, .1 map_html_url] CONS, [.0 .html_url], []>; %\
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`, which acts like a toy
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "k-language for JSON-like data transformation",
5
5
  "main": "index.mjs",
6
6
  "scripts": {
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,15],$V3=[1,16],$V4=[1,8],$V5=[1,9],$V6=[1,10],$V7=[1,11],$V8=[1,14],$V9=[1,20],$Va=[4,6,8,12,15,18,21,23,32,34],$Vb=[2,28],$Vc=[1,25],$Vd=[1,26],$Ve=[1,27],$Vf=[4,6,8,12,14,15,18,20,21,22,23,24,27,32,33,34],$Vg=[2,47],$Vh=[2,31],$Vi=[2,32],$Vj=[4,6,8,12,14,15,18,20,21,22,23,24,27,28,32,33,34],$Vk=[2,8],$Vl=[2,13],$Vm=[20,27],$Vn=[22,24,27],$Vo=[20,24,27],$Vp=[2,41],$Vq=[2,42],$Vr=[2,43];
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,"non_empty_labelled":35,"comp_label":36,"non_empty_list":37,"$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"},
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],[35,1],[35,3],[36,2],[36,2],[36,2],[36,3],[36,3],[36,3],[31,0],[31,1],[37,1],[37,3]],
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 38: case 48:
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 49:
163
+ case 15: case 51:
164
164
  this.$ = [$$[$0]];
165
165
  break;
166
- case 16: case 50:
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: "product", product: []};
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 40:
220
+ case 42:
215
221
  $$[$0-2].product = [].concat($$[$0-2].product,$$[$0]); this.$ = $$[$0-2];
216
222
  break;
217
- case 41: case 42: case 43:
223
+ case 43: case 44: case 45:
218
224
  this.$ = {label: $$[$0], exp: $$[$0-1]};
219
225
  break;
220
- case 44: case 45: case 46:
226
+ case 46: case 47: case 48:
221
227
  this.$ = {label: $$[$0-2], exp: $$[$0]};
222
228
  break;
223
- case 47:
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:19,4:$V1,5:12,6:$V2,7:13,8:$V3,12:[1,17],15:$V9,18:$V4,21:$V5,23:$V6,29:18,32:$V7,34:$V8},o($Va,$Vb,{13:[1,21]}),{3:22,4:$V1,16:24,17:23,18:$Vc,21:$Vd,23:$Ve},o($Vf,[2,23]),o([4,6,8,12,13,14,15,18,20,21,22,23,24,27,28,32,33,34],[2,1]),{3:32,4:$V1,5:33,6:$V2,7:34,8:$V3,11:31,15:$V9,18:$V4,20:[2,37],21:$V5,23:$V6,29:6,30:28,32:$V7,34:$V8,35:29,36:30},{3:19,4:$V1,5:12,6:$V2,7:13,8:$V3,11:37,15:$V9,18:$V4,21:$V5,22:$Vg,23:$V6,29:6,31:35,32:$V7,34:$V8,37:36},{3:19,4:$V1,5:12,6:$V2,7:13,8:$V3,11:37,15:$V9,18:$V4,21:$V5,23:$V6,24:$Vg,29:6,31:38,32:$V7,34:$V8,37:36},{3:19,4:$V1,5:12,6:$V2,7:13,8:$V3,11:40,15:$V9,18:$V4,21:$V5,23:$V6,29:6,32:$V7,33:[1,39],34:$V8},o($Vf,$Vh),o($Vf,$Vi),{3:43,4:$V1,5:42,6:$V2,7:41,8:$V3},o($Vj,[2,2]),o($Vj,[2,3]),{1:[2,4]},o($Vf,[2,24]),o($Vf,$Vb),{3:44,4:$V1,16:24,17:23,18:$Vc,21:$Vd,23:$Ve},{3:19,4:$V1,5:12,6:$V2,7:13,8:$V3,11:45,15:$V9,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8},o($Va,$Vk,{13:[1,46]}),o($Vf,[2,36]),o($Vf,[2,9]),{3:51,4:$V1,5:52,6:$V2,7:53,8:$V3,16:24,17:50,18:$Vc,19:47,20:$Vl,21:$Vd,23:$Ve,25:48,26:49},{3:44,4:$V1,16:24,17:54,18:$Vc,21:$Vd,23:$Ve},{3:51,4:$V1,5:52,6:$V2,7:53,8:$V3,16:24,17:50,18:$Vc,19:55,21:$Vd,23:$Ve,24:$Vl,25:48,26:49},{20:[1,56]},{20:[2,38],27:[1,57]},o($Vm,[2,39]),{3:58,4:$V1,5:59,6:$V2,7:60,8:$V3,15:$V9,18:$V4,21:$V5,23:$V6,29:18,32:$V7,34:$V8},o($V0,$Vb,{28:[1,61]}),o($V0,$Vh,{28:[1,62]}),o($V0,$Vi,{28:[1,63]}),{22:[1,64]},o([22,24],[2,48],{27:[1,65]}),o($Vn,[2,49],{5:12,7:13,29:18,3:19,4:$V1,6:$V2,8:$V3,15:$V9,18:$V4,21:$V5,23:$V6,32:$V7,34:$V8}),{24:[1,66]},o($Vf,[2,29]),{3:19,4:$V1,5:12,6:$V2,7:13,8:$V3,15:$V9,18:$V4,21:$V5,23:$V6,29:18,32:$V7,33:[1,67],34:$V8},o($Vf,[2,33]),o($Vf,[2,34]),o($Vf,[2,35]),o($Vf,$Vk),{3:19,4:$V1,5:12,6:$V2,7:13,8:$V3,14:[1,68],15:$V9,18:$V4,21:$V5,23:$V6,29:18,32:$V7,34:$V8},{16:69,18:$Vc,21:$Vd,23:$Ve},{20:[1,70]},o([20,24],[2,14],{27:[1,71]}),o($Vo,[2,15]),{3:72,4:$V1,5:73,6:$V2,7:74,8:$V3},o([4,6,8],$Vk,{28:[1,75]}),{28:[1,76]},{28:[1,77]},{22:[1,78]},{24:[1,79]},o($Vf,[2,25]),{3:32,4:$V1,5:33,6:$V2,7:34,8:$V3,11:31,15:$V9,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8,36:80},o($V0,$Vb,{20:$Vp,27:$Vp}),o($V0,$Vh,{20:$Vq,27:$Vq}),o($V0,$Vi,{20:$Vr,27:$Vr}),{3:19,4:$V1,5:12,6:$V2,7:13,8:$V3,11:81,15:$V9,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8},{3:19,4:$V1,5:12,6:$V2,7:13,8:$V3,11:82,15:$V9,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8},{3:19,4:$V1,5:12,6:$V2,7:13,8:$V3,11:83,15:$V9,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8},o($Vf,[2,26]),{3:19,4:$V1,5:12,6:$V2,7:13,8:$V3,11:84,15:$V9,18:$V4,21:$V5,23:$V6,29:6,32:$V7,34:$V8},o($Vf,[2,27]),o($Vf,[2,30]),o($V0,[2,6]),{14:[1,85]},o($Vf,[2,10]),{3:51,4:$V1,5:52,6:$V2,7:53,8:$V3,16:24,17:50,18:$Vc,21:$Vd,23:$Ve,26:86},o($Vo,[2,17]),o($Vo,[2,18]),o($Vo,[2,19]),{3:44,4:$V1,16:24,17:87,18:$Vc,21:$Vd,23:$Ve},{3:44,4:$V1,16:24,17:88,18:$Vc,21:$Vd,23:$Ve},{3:44,4:$V1,16:24,17:89,18:$Vc,21:$Vd,23:$Ve},o($Vf,[2,11]),o($Vf,[2,12]),o($Vm,[2,40]),o($Vm,[2,44],{5:12,7:13,29:18,3:19,4:$V1,6:$V2,8:$V3,15:$V9,18:$V4,21:$V5,23:$V6,32:$V7,34:$V8}),o($Vm,[2,45],{5:12,7:13,29:18,3:19,4:$V1,6:$V2,8:$V3,15:$V9,18:$V4,21:$V5,23:$V6,32:$V7,34:$V8}),o($Vm,[2,46],{5:12,7:13,29:18,3:19,4:$V1,6:$V2,8:$V3,15:$V9,18:$V4,21:$V5,23:$V6,32:$V7,34:$V8}),o($Vn,[2,50],{5:12,7:13,29:18,3:19,4:$V1,6:$V2,8:$V3,15:$V9,18:$V4,21:$V5,23:$V6,32:$V7,34:$V8}),o($V0,[2,7]),o($Vo,[2,16]),o($Vo,[2,20]),o($Vo,[2,21]),o($Vo,[2,22])],
229
- defaultActions: {17:[2,4]},
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 6;
743
+ case 17:return 35;
744
+ break;
745
+ case 18:return 36;
746
+ break;
747
+ case 19:return 6;
738
748
  break;
739
- case 18:return 4;
749
+ case 20:return 4;
740
750
  break;
741
- case 19:return 8;
751
+ case 21:return 8;
742
752
  break;
743
- case 20:return 12;
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 `<${prettyCode_labels(codes, representatives, codeExp.union)}>`;
37
+ return `< ${prettyCode_labels(codes, representatives, codeExp.union)} >`;
38
38
  case "vector":
39
- return `[${representatives[codeExp.vector] || codeExp.vector}]`;
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
- break;
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
- return builtin[exp.ref](value);
103
- case "dot":
104
- if (typeof value === "string") {
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
- if (/^(0|([1-9]\d*))$/.test(value)) {
109
- if (value == exp.dot) return {};
110
- return;
111
- }
112
- if (value === true) {
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
- const result = [];
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
- result.push(r);
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
- const result = {};
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
- result[label] = r;
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
- return console.error(exp.op);
234
+ assert(false,`Unknown operation: '${exp.op}'`);
154
235
  }
155
236
  }
156
237