@fraczak/k 4.0.1 → 4.0.2

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/codes.mjs CHANGED
@@ -12,7 +12,7 @@ function isBuiltIn(code) {
12
12
  return code.match(/^(int|string|bool)$/);
13
13
  }
14
14
 
15
- function encodeCodeToString(code, codes) {
15
+ function encodeCodeToString(code, codes = theRepository.codes) {
16
16
  if (isBuiltIn(code)) return code;
17
17
  var i = 0;
18
18
  const Q = [[code,i]];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "4.0.1",
3
+ "version": "4.0.2",
4
4
  "description": "k-language for JSON-like data transformation",
5
5
  "main": "index.mjs",
6
6
  "scripts": {
package/parser.jison CHANGED
@@ -3,6 +3,10 @@
3
3
  import { SymbolTable, comp, union, identity } from "./symbol-table.mjs";
4
4
  let s = new SymbolTable();
5
5
 
6
+ function anError(pos,msg) {
7
+ throw new Error(`Parse Error (lines ${pos.first_line}:${pos.first_column}...${pos.last_line}:${pos.last_column}): ${msg}`);
8
+ }
9
+
6
10
  function getToken(yytext,yy,lstack) {
7
11
  const yylloc = yy.lexer.yylloc;
8
12
  const loc = lstack[lstack.length - 1]; // { first_line: 5, last_line: 5, first_column: 2, last_column: 3 };
@@ -38,7 +42,7 @@ function fromEscString(escString) {
38
42
  %lex
39
43
 
40
44
  %%
41
- [/][*]([*][^/]|[^*])*[*][/] /* c-comment */
45
+ [/][*]([^*]*[*]+[^*/])*[^*]*[*]+[/] /* c-comment */
42
46
  ("//"|"#"|"%"|"--")[^\n]* /* one line comment */
43
47
  \s+ /* blanks */
44
48
  "<" return 'LA';
@@ -119,7 +123,10 @@ code
119
123
  ;
120
124
 
121
125
  codeDef
122
- : lc labelled_codes rc { $$ = { code: "product", product: $2, start: $1.start, end: $3.end }; }
126
+ : lc labelled_codes rc { if (Object.keys($2).length == 1)
127
+ $$ = { code: "union", union: $2, start: $1.start, end: $3.end };
128
+ else
129
+ $$ = { code: "product", product: $2, start: $1.start, end: $3.end }; }
123
130
  | lb code rb { $$ = { code: "vector", vector: s.as_ref($2), start: $1.start, end: $3.end }; }
124
131
  | la labelled_codes ra { $$ = { code: "union", union: $2, start: $1.start, end: $3.end }; }
125
132
  ;
@@ -127,9 +134,11 @@ codeDef
127
134
  labelled_codes
128
135
  : { $$ = {}; }
129
136
  | non_empty_labelled_codes { $$ = $1.reduce((r, lc) => {
130
- r[lc.label] = s.as_ref(lc.code);
131
- return r }
132
- , {}); }
137
+ if (r[lc.label])
138
+ anError(@0,`Duplicate label '${lc.label}'.`);
139
+ r[lc.label] = s.as_ref(lc.code);
140
+ return r }
141
+ , {}); }
133
142
  ;
134
143
 
135
144
  non_empty_labelled_codes
@@ -149,9 +158,15 @@ code_label
149
158
 
150
159
  filter_
151
160
  : dollar code { $$ = { type: "code", code: s.as_ref($2), start: $1.start, end: $2.end}; }
152
- | lp labelled_filters rp { $$ = { type: null, open: $2.open, fields: $2.fields, start: $1.start, end: $3.end}; }
161
+ | lp labelled_filters rp { if ( !$2.open && (Object.keys($2.fields).length == 1))
162
+ $$ = { type: "union", open: $2.open, fields: $2.fields, start: $1.start, end: $3.end};
163
+ else
164
+ $$ = { type: null, open: $2.open, fields: $2.fields, start: $1.start, end: $3.end}; }
153
165
  | la labelled_filters ra { $$ = { type: "union", open: $2.open, fields: $2.fields, start: $1.start, end: $3.end}; }
154
- | lc labelled_filters rc { $$ = { type: "product", open: $2.open, fields: $2.fields, start: $1.start, end: $3.end}; }
166
+ | lc labelled_filters rc { if ( !$2.open && (Object.keys($2.fields).length == 1))
167
+ $$ = { type: "union", open: $2.open, fields: $2.fields, start: $1.start, end: $3.end};
168
+ else
169
+ $$ = { type: "product", open: $2.open, fields: $2.fields, start: $1.start, end: $3.end}; }
155
170
  | lb filter rb { $$ = { type: "vector", vector: $2, start: $1.start, end: $3.end }; }
156
171
  ;
157
172
 
@@ -166,6 +181,8 @@ labelled_filters
166
181
  if (lc.dots) {
167
182
  r.open = true;
168
183
  } else {
184
+ if (r.fields[lc.label])
185
+ anError(@0,`Duplicate label '${lc.label}'.`);
169
186
  r.fields[lc.label] = lc.filter;
170
187
  }
171
188
  return r }
@@ -213,7 +230,12 @@ exp
213
230
 
214
231
  labelled
215
232
  : { $$ = {op: "product", product: []}; }
216
- | non_empty_labelled { $$ = $1; }
233
+ | non_empty_labelled { $1.product.reduce( (labels, {label}) =>
234
+ { if (labels[label])
235
+ anError(@0,`Duplicate label '${label}'.`)
236
+ labels[label] = true;
237
+ return labels; }, {});
238
+ $$ = $1; }
217
239
  ;
218
240
 
219
241
  non_empty_labelled
package/parser.mjs CHANGED
@@ -78,6 +78,10 @@
78
78
  import { SymbolTable, comp, union, identity } from "./symbol-table.mjs";
79
79
  let s = new SymbolTable();
80
80
 
81
+ function anError(pos,msg) {
82
+ throw new Error(`Parse Error (lines ${pos.first_line}:${pos.first_column}...${pos.last_line}:${pos.last_column}): ${msg}`);
83
+ }
84
+
81
85
  function getToken(yytext,yy,lstack) {
82
86
  const yylloc = yy.lexer.yylloc;
83
87
  const loc = lstack[lstack.length - 1]; // { first_line: 5, last_line: 5, first_column: 2, last_column: 3 };
@@ -154,11 +158,14 @@ break;
154
158
  case 27:
155
159
  this.$ = { code: "ref", ref: $$[$0].value, start: $$[$0].start, end: $$[$0].end};
156
160
  break;
157
- case 28: case 47: case 61: case 79: case 89:
161
+ case 28: case 47: case 61: case 89:
158
162
  this.$ = $$[$0];
159
163
  break;
160
164
  case 29:
161
- this.$ = { code: "product", product: $$[$0-1], start: $$[$0-2].start, end: $$[$0].end };
165
+ if (Object.keys($$[$0-1]).length == 1)
166
+ this.$ = { code: "union", union: $$[$0-1], start: $$[$0-2].start, end: $$[$0].end };
167
+ else
168
+ this.$ = { code: "product", product: $$[$0-1], start: $$[$0-2].start, end: $$[$0].end };
162
169
  break;
163
170
  case 30:
164
171
  this.$ = { code: "vector", vector: s.as_ref($$[$0-1]), start: $$[$0-2].start, end: $$[$0].end };
@@ -171,9 +178,11 @@ case 32:
171
178
  break;
172
179
  case 33:
173
180
  this.$ = $$[$0].reduce((r, lc) => {
174
- r[lc.label] = s.as_ref(lc.code);
175
- return r }
176
- , {});
181
+ if (r[lc.label])
182
+ anError(this._$,`Duplicate label '${lc.label}'.`);
183
+ r[lc.label] = s.as_ref(lc.code);
184
+ return r }
185
+ , {});
177
186
  break;
178
187
  case 34: case 52: case 90:
179
188
  this.$ = [$$[$0]];
@@ -191,13 +200,19 @@ case 42:
191
200
  this.$ = { type: "code", code: s.as_ref($$[$0]), start: $$[$0-1].start, end: $$[$0].end};
192
201
  break;
193
202
  case 43:
194
- this.$ = { type: null, open: $$[$0-1].open, fields: $$[$0-1].fields, start: $$[$0-2].start, end: $$[$0].end};
203
+ if ( !$$[$0-1].open && (Object.keys($$[$0-1].fields).length == 1))
204
+ this.$ = { type: "union", open: $$[$0-1].open, fields: $$[$0-1].fields, start: $$[$0-2].start, end: $$[$0].end};
205
+ else
206
+ this.$ = { type: null, open: $$[$0-1].open, fields: $$[$0-1].fields, start: $$[$0-2].start, end: $$[$0].end};
195
207
  break;
196
208
  case 44:
197
209
  this.$ = { type: "union", open: $$[$0-1].open, fields: $$[$0-1].fields, start: $$[$0-2].start, end: $$[$0].end};
198
210
  break;
199
211
  case 45:
200
- this.$ = { type: "product", open: $$[$0-1].open, fields: $$[$0-1].fields, start: $$[$0-2].start, end: $$[$0].end};
212
+ if ( !$$[$0-1].open && (Object.keys($$[$0-1].fields).length == 1))
213
+ this.$ = { type: "union", open: $$[$0-1].open, fields: $$[$0-1].fields, start: $$[$0-2].start, end: $$[$0].end};
214
+ else
215
+ this.$ = { type: "product", open: $$[$0-1].open, fields: $$[$0-1].fields, start: $$[$0-2].start, end: $$[$0].end};
201
216
  break;
202
217
  case 46:
203
218
  this.$ = { type: "vector", vector: $$[$0-1], start: $$[$0-2].start, end: $$[$0].end };
@@ -216,6 +231,8 @@ case 51:
216
231
  if (lc.dots) {
217
232
  r.open = true;
218
233
  } else {
234
+ if (r.fields[lc.label])
235
+ anError(this._$,`Duplicate label '${lc.label}'.`);
219
236
  r.fields[lc.label] = lc.filter;
220
237
  }
221
238
  return r }
@@ -275,6 +292,14 @@ break;
275
292
  case 78:
276
293
  this.$ = {op: "product", product: []};
277
294
  break;
295
+ case 79:
296
+ $$[$0].product.reduce( (labels, {label}) =>
297
+ { if (labels[label])
298
+ anError(this._$,`Duplicate label '${label}'.`)
299
+ labels[label] = true;
300
+ return labels; }, {});
301
+ this.$ = $$[$0];
302
+ break;
278
303
  case 80:
279
304
  this.$ = {op: "product", product: [$$[$0]]};
280
305
  break;
@@ -821,7 +846,7 @@ case 25:return 47;
821
846
  break;
822
847
  }
823
848
  },
824
- rules: [/^(?:[/][*]([*][^/]|[^*])*[*][/])/,/^(?:(\/\/|#|%|--)[^\n]*)/,/^(?:\s+)/,/^(?:<)/,/^(?:\{)/,/^(?:\[)/,/^(?:\()/,/^(?:>)/,/^(?:\})/,/^(?:\])/,/^(?:\))/,/^(?:=)/,/^(?:\.\.\.)/,/^(?:\.)/,/^(?:,)/,/^(?:;)/,/^(?::)/,/^(?:\$)/,/^(?:\?)/,/^(?:\|)/,/^(?:\^)/,/^(?:"([^"\\]|\\(.|\n))*"|'([^'\\]|\\(.|\n))*')/,/^(?:[a-zA-Z_][a-zA-Z0-9_?!]*)/,/^(?:0|[-]?[1-9][0-9]*)/,/^(?:\+\+\+)/,/^(?:$)/],
849
+ rules: [/^(?:[/][*]([^*]*[*]+[^*/])*[^*]*[*]+[/])/,/^(?:(\/\/|#|%|--)[^\n]*)/,/^(?:\s+)/,/^(?:<)/,/^(?:\{)/,/^(?:\[)/,/^(?:\()/,/^(?:>)/,/^(?:\})/,/^(?:\])/,/^(?:\))/,/^(?:=)/,/^(?:\.\.\.)/,/^(?:\.)/,/^(?:,)/,/^(?:;)/,/^(?::)/,/^(?:\$)/,/^(?:\?)/,/^(?:\|)/,/^(?:\^)/,/^(?:"([^"\\]|\\(.|\n))*"|'([^'\\]|\\(.|\n))*')/,/^(?:[a-zA-Z_][a-zA-Z0-9_?!]*)/,/^(?:0|[-]?[1-9][0-9]*)/,/^(?:\+\+\+)/,/^(?:$)/],
825
850
  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,23,24,25],"inclusive":true}}
826
851
  });
827
852
  return lexer;
package/patterns.mjs CHANGED
@@ -210,7 +210,7 @@ function patterns(representatives, rels) {
210
210
  newPatternId = context[filter.name];
211
211
  break;
212
212
  case "code":
213
- newPatternId = rootDef.typePatternGraph.getTypeId(filter.code);
213
+ newPatternId = rootDef.typePatternGraph.getTypeId(representatives[filter.code] || filter.code);
214
214
  break;
215
215
  case "union":
216
216
  newPatternId = rootDef.typePatternGraph.addNewNode(
@@ -384,19 +384,24 @@ function patterns(representatives, rels) {
384
384
  rel.patterns[1] = rootDef.typePatternGraph.addNewNode();
385
385
  break;
386
386
  case "CONS": {
387
- let member = rootDef.typePatternGraph.addNewNode();
387
+ const member = rootDef.typePatternGraph.addNewNode();
388
388
  rel.patterns[1] = rootDef.typePatternGraph.addNewNode({pattern: '[]'}, {"vector-member": [member]});
389
389
  rel.patterns[0] = rootDef.typePatternGraph.addNewNode({pattern: '{}'}, {"car": [member], "cdr": [rel.patterns[1]]});
390
390
  }; break;
391
391
  case "SNOC": {
392
- let member = rootDef.typePatternGraph.addNewNode();
392
+ const member = rootDef.typePatternGraph.addNewNode();
393
393
  rel.patterns[0] = rootDef.typePatternGraph.addNewNode({pattern: '[]'}, {"vector-member": [member]});
394
394
  rel.patterns[1] = rootDef.typePatternGraph.addNewNode({pattern: '{}'}, {"car": [member], "cdr": [rel.patterns[0]]});
395
395
  }; break;
396
+ case "DIV": {
397
+ const intId = rootDef.typePatternGraph.getTypeId('int');
398
+ rel.patterns[0] = rootDef.typePatternGraph.addNewNode({pattern: '[]'}, {"vector-member": [intId]});
399
+ rel.patterns[1] = rootDef.typePatternGraph.addNewNode({pattern: '{}'}, {"div": [intId], "rem": [intId]});
400
+ }; break;
401
+ break;
396
402
  // TO DO
397
- case "null":
398
- case "DIV":
399
403
  case "FDIV":
404
+ case "null":
400
405
  rel.patterns = [rootDef.typePatternGraph.addNewNode(), rootDef.typePatternGraph.addNewNode()];
401
406
  break;
402
407
  default:
package/repl.mjs CHANGED
@@ -13,18 +13,15 @@ const splice = [].splice;
13
13
  console.log("Very! experimental repl shell for 'k-language'...");
14
14
 
15
15
  const help = function () {
16
- console.log(" --h print help");
17
- console.log(" --a print codes and relations");
18
- console.log(" --c print aliased codes");
19
- console.log(" --C code print code definition");
20
- console.log(" --r print rels");
21
- console.log(" --p pretty-print last value");
22
- console.log(" --pp print last value via node.js 'console.log'");
23
- console.log(" --s reg store the last value in register 'reg'");
24
- console.log(" --g reg get the value from register 'reg'");
25
- console.log(" --regs print registers names");
26
- console.log(" --l file.k load 'file.k'");
27
- console.log(" --x rel print out the type pattern of 'rel'");
16
+ // console.log(" --debug loads codes and relations as value");
17
+ console.log(" --c print aliased codes");
18
+ console.log(" --C code print code definition");
19
+ console.log(" --r print rels");
20
+ console.log(" --R rel print out the type pattern of 'rel'");
21
+ console.log(" --p (--pp) pretty-print last value");
22
+ console.log(" --s (--g) reg store (get) the last value in register 'reg'");
23
+ console.log(" --regs print register names");
24
+ console.log(" --l file.k load 'file.k'");
28
25
  };
29
26
 
30
27
  help();
@@ -32,19 +29,18 @@ help();
32
29
  const re__l = /^[ \n\t]*(?:--l[ ]+)(.+)[ ]*?$/;
33
30
  const re__s = /^[ \n\t]*(?:--s[ ]+)(.+)[ ]*?$/;
34
31
  const re__g = /^[ \n\t]*(?:--g[ ]+)(.+)[ ]*?$/;
35
- const re__x = /^[ \n\t]*(?:--x[ ]+)(.+)[ ]*?$/;
32
+ const re__R = /^[ \n\t]*(?:--R[ ]+)(.+)[ ]*?$/;
36
33
  const re__C = /^[ \n\t]*(?:--C[ ]+)(.+)[ ]*?$/;
37
34
 
38
35
  const rl = readline.createInterface({
39
36
  input: process.stdin,
40
37
  output: process.stdout,
41
- prompt: ''
38
+ prompt: '> '
42
39
  });
43
40
 
44
41
  rl.prompt();
45
42
 
46
43
  rl.on('line', (line) => {
47
- // console.log(`Received: ${line}`);
48
44
  evaluate(line);
49
45
  rl.prompt();
50
46
  }).on('close', () => {
@@ -52,37 +48,48 @@ rl.on('line', (line) => {
52
48
  process.exit(0);
53
49
  });
54
50
 
51
+ let old_val = {};
55
52
  let val = {};
53
+ const printVal = function (v = val) {
54
+ if (v === undefined)
55
+ console.log("...",v);
56
+ else
57
+ console.log(`=> ${JSON.stringify(v)}`);
58
+ rl.setPrompt('> ');
59
+ }
56
60
  const registers = {};
57
61
  const buffer = [];
58
62
  function evaluate(line) {
59
63
  if (line.trim().endsWith('\\')) {
60
64
  buffer.push(line.slice(0, -1));
65
+ rl.setPrompt(' ');
61
66
  return;
62
67
  }
63
68
  line = [...buffer, line].join('\n');
64
69
  buffer.length = 0;
65
70
  try {
66
- if (val === void 0) {
67
- val = {};
68
- }
71
+ if (val === undefined)
72
+ val = old_val;
73
+ else
74
+ old_val = val;
69
75
  if (line.match(/^[ \n\t]*(?:--h)?$/)) {
70
76
  // --h
71
77
  help();
72
78
  } else if (line.match(/^[ \n\t]*\^$/)) {
73
79
  val = closeVector(val);
74
- console.log(`=> ${JSON.stringify(val)}`);
80
+ printVal();
81
+
75
82
  } else if (line.match(re__l)) {
76
83
  // --l
77
84
  const file = line.match(re__l)[1];
78
- console.log(` -- loading file: ${file} ...`);
85
+ console.log(` ... loading file: ${file} ...`);
79
86
  const kScript = fs.readFileSync(file).toString();
80
- console.log(` ----------------------------- compiling file: ${file} ...`);
87
+ console.log(` Done!`);
81
88
  // console.log(kScript);
82
89
  val = k.compile("+++\n" + kScript + "\n()")(val);
83
- console.log(`=> ${JSON.stringify(val)}`);
84
- } else if (line.match(/^[ \n\t]*(?:--a)?$/)) {
85
- // --a
90
+ printVal();
91
+ } else if (line.match(/^[ \n\t]*--debug$/)) {
92
+ // --debug
86
93
  val = run.defs;
87
94
  console.log(val);
88
95
  // --r
@@ -150,9 +157,9 @@ function evaluate(line) {
150
157
  let reg = line.match(re__g)[1];
151
158
  val = registers[reg];
152
159
  console.log(val);
153
- // --x
154
- } else if (line.match(re__x)) {
155
- const relName = line.match(re__x)[1];
160
+ // --R rel
161
+ } else if (line.match(re__R)) {
162
+ const relName = line.match(re__R)[1];
156
163
  const rel = run.defs?.rels[relName];
157
164
  if (!rel) {
158
165
  console.log(` -- relation '${relName}' not found`);
@@ -171,7 +178,7 @@ function evaluate(line) {
171
178
  } else if (!line.match(/^[ \n\t]*(?:#.*)?$/)) {
172
179
  try {
173
180
  val = k.run(`+++\n${line}\n()`, val);
174
- console.log(`=> ${JSON.stringify(val)}`);
181
+ printVal();
175
182
  } catch (error) {
176
183
  e = error;
177
184
  console.error("ERROR:");
package/run.mjs CHANGED
@@ -62,7 +62,7 @@ const builtin = {
62
62
  toJSON: (x) => JSON.stringify(x),
63
63
  fromJSON: (x) => JSON.parse(x),
64
64
  CONS: ({car, cdr}) => { try { return [car, ...cdr]; } catch (e) { return undefined; } },
65
- SNOC: (x) => (x.length > 1 ? {car: x[0], cdr: x.slice(1)} : undefined),
65
+ SNOC: (x) => (x.length > 0 ? {car: x[0], cdr: x.slice(1)} : undefined),
66
66
  toDateMsec: (x) => new Date(x).getTime(),
67
67
  toDateStr: (x) => new Date(x).toISOString(),
68
68
  };
@@ -1,5 +1,5 @@
1
1
  import k from './index.mjs';
2
- import { encodeCodeToString } from './codes.mjs';
2
+ import { encodeCodeToString, find } from './codes.mjs';
3
3
  import hash from './hash.mjs';
4
4
  [
5
5
  `
@@ -7,7 +7,7 @@ import hash from './hash.mjs';
7
7
  $pair = {nat x, nat y};
8
8
  $b = {int"x", bool y};
9
9
  $vector = [int];
10
- $tree = <{nat value, tree left, tree right} binary, {nat value} leaf, {nat value, tree tree} unary, [tree] list_of_trees>;
10
+ $tree = <{nat value, tree left, tree right} binary, nat leaf, {nat value, tree tree} unary, [tree] list_of_trees>;
11
11
 
12
12
  succ = { $nat succ} $nat;
13
13
  plus = $pair <
@@ -17,22 +17,27 @@ import hash from './hash.mjs';
17
17
  {{} zero} succ succ {() x, () y} plus
18
18
  `
19
19
  ].map(function (script) {
20
- console.log(`k_expression = '${script}';`);
20
+ console.log("test-fingerprint:");
21
+ // console.log(`k_expression = '${script}';`);
21
22
  const annotated = k.annotate(script);
22
- for (const code in annotated.codes) {
23
- console.log(`CODE: ${code}`);
24
- const s = encodeCodeToString(code,annotated.codes);
25
- console.log(` - DEFS: ${s}`);;
23
+ // console.log(annotated);
24
+ let ERRORS = 0;
25
+ for (const code in annotated.representatives) {
26
+ // console.log(`CODE: ${code}`);
27
+ const s = encodeCodeToString(annotated.representatives[code]);
28
+ // console.log(` - DEFS: ${s}`);;
26
29
  const annotated2 = k.annotate(s+" {}");;
27
- const s2 = encodeCodeToString(annotated2.representatives["C0"],annotated2.codes);
28
- console.log(` - reparsed FINGERPRINT: ${hash(s2)}`);
29
- if ((s === s2) && (hash(s) === hash(s2))) {
30
- console.log('--- OK');
31
- } else {
32
- console.log('--- ERROR');
33
- }
34
-
35
- console.log('-------------------');
30
+ const s2 = encodeCodeToString(annotated2.representatives["C0"]);
31
+ // console.log(` - reparsed FINGERPRINT: ${hash(s2)}`);
32
+ if (!((s === s2) && (hash(s) === hash(s2)))) {
33
+ ERRORS++;
34
+ console.log(` ERROR - reparsed FINGERPRINT for ${code} is different`);
35
+ }
36
+ }
37
+ if (ERRORS === 0) {
38
+ console.log("OK");
39
+ } else {
40
+ console.log(" ----- ERRORS");
36
41
  }
37
42
  });
38
43