@fraczak/k 4.0.3 → 5.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "4.0.3",
3
+ "version": "5.0.0",
4
4
  "description": "k-language for JSON-like data transformation",
5
5
  "main": "index.mjs",
6
6
  "scripts": {
package/patterns.mjs CHANGED
@@ -3,6 +3,7 @@ import hash from "./hash.mjs";
3
3
  import { TypePatternGraph } from "./typing.mjs";
4
4
  import { Graph, sccs, topoOrder } from "./Graph.mjs";
5
5
  import codes from "./codes.mjs";
6
+ import { assignCanonicalNames } from "./export.mjs";
6
7
 
7
8
  const unitCode = codes.unitCode;
8
9
 
@@ -101,6 +102,7 @@ function patterns(representatives, rels) {
101
102
  // representatives:{"{}": "BG", ...}
102
103
  // rels: {"rlz": [{op: comp,...}, ...], ...}
103
104
 
105
+ const relAlias = {};
104
106
 
105
107
  // 1 INITIALIZATION
106
108
  // 1.1 initialize patternNodes and rels
@@ -416,7 +418,7 @@ function patterns(representatives, rels) {
416
418
  for (const relName in rels) {
417
419
  const rootDef = rels[relName];
418
420
  rootDef.typePatternGraph = new TypePatternGraph();
419
- rootDef.varRefs = []; // the list of non-built references as pointers to AST nodes
421
+ rootDef.varRefs = []; // the list of references to non-builtin rels as pointers to AST nodes
420
422
  rootDef.patternVars = {};
421
423
  augment(rootDef.def, rootDef);
422
424
  delete rootDef.patternVars;
@@ -453,12 +455,16 @@ function patterns(representatives, rels) {
453
455
 
454
456
  // 3. Topological sort of the DAG
455
457
 
456
- const sccInOrder = topoOrder(DAG);
458
+ const sccInOrder = topoOrder(DAG).reverse();
457
459
 
458
460
  // 4. For each strongly connected component C in a bottom-up order
461
+
462
+ // we will also generate the canonical representation of the relations in C and replace
463
+ // the name to the relation by the hash of the canonical representation
464
+
465
+ // console.log("----- SCC in order", sccInOrder);
459
466
 
460
- for (const scc of sccInOrder.reverse()) {
461
- // console.log(`SCC: { ${DAGnodes[scc].scc} }`);
467
+ for (const scc of sccInOrder) {
462
468
 
463
469
  const maxNumberOfIterations = 10;
464
470
 
@@ -497,9 +503,7 @@ function patterns(representatives, rels) {
497
503
  throw e;
498
504
  }
499
505
  }
500
-
501
506
  rels[relName] = compactRel(relDef,relName);
502
-
503
507
  return relDefToString(rels[relName]);
504
508
  }));
505
509
 
@@ -507,9 +511,19 @@ function patterns(representatives, rels) {
507
511
  // console.log("SUCCESS!");
508
512
  break;
509
513
  }
510
- } // while
511
-
514
+ } // end of iteration loop
515
+
516
+ DAGnodes[scc].scc.forEach( relName => {
517
+ const relDef = rels[relName];
518
+ const canonical = relDefToString(relDef);
519
+ const h = hash(canonical);
520
+ relAlias[relName] = h;
521
+ });
522
+
523
+ assignCanonicalNames(DAGnodes[scc].scc, rels, relAlias);
524
+
512
525
  }
526
+ return relAlias;
513
527
  }
514
528
 
515
529
  export default { patterns };
package/pretty.mjs CHANGED
@@ -1,26 +1,22 @@
1
1
  import { find } from "./codes.mjs";
2
2
  import { TypePatternGraph } from "./typing.mjs";
3
3
 
4
- function compareAs(fn) {
5
- return function (a, b) {
6
- [a, b] = [a, b].map(fn);
7
- if (a < b) return -1;
8
- if (a > b) return 1;
9
- return 0;
10
- };
11
- }
12
-
13
4
  const nameRE = /^[a-zA-Z0-9_][a-zA-Z0-9_?!]*$/;
5
+ function pLabel_(label) {
6
+ return nameRE.test(label) ? ` ${label}` : `${JSON.stringify(label)}`;
7
+ }
8
+ function pLabel(label) {
9
+ return nameRE.test(label) ? `${label}` : `${JSON.stringify(label)}`;
10
+ }
14
11
 
15
12
  function prettyCode_labels (representatives, label_ref_map) {
16
13
  return Object.keys(label_ref_map)
17
- .sort( compareAs((x) => x) )
14
+ .sort()
18
15
  .map( (label) => {
19
- const plabel = nameRE.test(label) ? label : `'${label}'`;
20
16
  return `${prettyCode(representatives, {
21
17
  code: "ref",
22
18
  ref: label_ref_map[label],
23
- })} ${plabel}`;
19
+ })}${pLabel_(label)}`;
24
20
  })
25
21
  .join(", ");
26
22
  };
@@ -46,10 +42,10 @@ function prettyCode (representatives, codeExp) {
46
42
  }
47
43
  };
48
44
 
49
- function prettyFilter (prettyCode, filter) {
45
+ function prettyFilter ( filter ) {
50
46
  const fieldsStr = () => {
51
47
  const fields = Object.keys(filter.fields).map( (key) =>
52
- `${prettyFilter(prettyCode, filter.fields[key])} ${key}`
48
+ `${prettyFilter(filter.fields[key])}${pLabel_(key)}`
53
49
  );
54
50
  if (filter.open) fields.push("...");
55
51
  return fields.join(", ");
@@ -57,11 +53,11 @@ function prettyFilter (prettyCode, filter) {
57
53
  switch (filter.type) {
58
54
 
59
55
  case "code":
60
- return `$${prettyCode({code: "ref",ref: filter.code,})}`;
56
+ return `$${filter.code}`;
61
57
  case "name":
62
58
  return filter.name;
63
59
  case "vector":
64
- return `[${prettyFilter(prettyCode, filter.vector)}]${filter.name ? "=" + filter.name : ""}`;
60
+ return `[${prettyFilter(filter.vector)}]${filter.name ? "=" + filter.name : ""}`;
65
61
  case null:
66
62
  if (filter.name && Object.keys(filter.fields).length == 0)
67
63
  return filter.name;
@@ -74,12 +70,13 @@ function prettyFilter (prettyCode, filter) {
74
70
  throw new Error(`Unknown filter type ${filter.type} in ${JSON.stringify(filter)}`);
75
71
  }
76
72
 
77
- function prettyRel (prettyCode, exp) {
73
+ function prettyRel (exp) {
78
74
  "use strict";
79
75
  const pretty = (exp) => {
80
76
  switch (exp.op) {
81
77
  case "filter":
82
- return `?${prettyFilter(prettyCode, exp.filter)}`;
78
+ if (exp.filter.type == 'code') return `$${exp.filter.code}`;
79
+ return `?${prettyFilter(exp.filter)}`;
83
80
  case "pipe":
84
81
  return `|`;
85
82
  case "caret":
@@ -101,27 +98,16 @@ function prettyRel (prettyCode, exp) {
101
98
  case "dot":
102
99
  if ("number" === typeof exp.dot) {
103
100
  return `.${exp.dot}`;
104
- } else if (nameRE.test(exp.dot)) {
105
- return `.${exp.dot}`;
106
- } else {
107
- return `'${exp.dot}'`;
108
- }
109
- break;
101
+ } else
102
+ return `.${pLabel(exp.dot)}`;
110
103
  case "code":
111
- return `$${prettyCode({
112
- code: "ref",
113
- ref: exp.code,
114
- })}`;
104
+ return `$${exp.code}`;
115
105
  case "product":
116
106
  return (function (labelled) {
117
107
  return `{${labelled.join(", ")}}`;
118
108
  })(
119
109
  exp.product.map(function ({ label, exp }) {
120
- if (nameRE.test(label)) {
121
- return `${pretty(exp)} ${label}`;
122
- } else {
123
- return `${pretty(exp)} '${label}'`;
124
- }
110
+ return `${pretty(exp)}${pLabel_(label)}`;
125
111
  })
126
112
  );
127
113
  }
@@ -148,25 +134,24 @@ function patterns2filters(typePatternGraph, ...patternIds) {
148
134
 
149
135
  // variables - variables which will have to be added as extra filters
150
136
  const variables = inDegree.reduce( (variables, degree, i) => {
151
- if (degree > 1) variables[i] = "fresh";
137
+ if (degree > 1) variables[i] = true;
152
138
  return variables;
153
139
  }, {});
154
140
 
141
+ const filterVars = {};
155
142
  const buildFilter = (path, patternId, i) => {
156
143
  let named_filter = {};
157
144
  const pattern = newTypePatternGraph.get_pattern(patternId);
158
145
  if (variables[patternId] && pattern.pattern != 'type') {
159
- const name = `X${patternId}`;
160
- if (variables[patternId] == "done")
161
- return { type: 'name', name: name };
162
- variables[patternId] = "done";
163
- named_filter = { name: name };
146
+ if (filterVars[patternId])
147
+ return { type: 'name', name: filterVars[patternId] };
148
+ filterVars[patternId] = `X${Object.keys(filterVars).length}`;
149
+ named_filter = { name: filterVars[patternId] };
164
150
  }
165
151
 
166
-
167
152
  const edges = newTypePatternGraph.edges[patternId];
168
153
  const fields = () =>
169
- Object.keys(edges).reduce( (fields, key) =>{
154
+ Object.keys(edges).sort().reduce( (fields, key) =>{
170
155
  fields[key] = buildFilter([...path, key], Object.values(edges[key])[0], i);
171
156
  return fields;
172
157
  }, {});
package/repl.mjs CHANGED
@@ -6,14 +6,17 @@ import k from "./index.mjs";
6
6
  import {run, closeVector } from "./run.mjs";
7
7
  import { prettyCode, prettyRel, patterns2filters } from "./pretty.mjs";
8
8
  import { find } from "./codes.mjs";
9
+ import { exportRelation } from "./export.mjs";
9
10
 
10
11
 
11
- const splice = [].splice;
12
+ let DEBUG_FLAG = false;
12
13
 
13
14
  console.log("Very! experimental repl shell for 'k-language'...");
14
15
 
15
16
  const help = function () {
16
- // console.log(" --debug loads codes and relations as value");
17
+ console.log(` --debug toggle debug flag: [${DEBUG_FLAG?'ON':'OFF'}]`);
18
+ if (DEBUG_FLAG)
19
+ console.log(" --load loads codes and relations as value");
17
20
  console.log(" --c print aliased codes");
18
21
  console.log(" --C code print 'code' definition");
19
22
  console.log(" --r print relations");
@@ -88,40 +91,42 @@ function evaluate(line) {
88
91
  // console.log(kScript);
89
92
  val = k.compile("+++\n" + kScript + "\n()")(val);
90
93
  printVal();
91
- } else if (line.match(/^[ \n\t]*--debug$/)) {
92
94
  // --debug
95
+ } else if (line.match(/^[ \n\t]*--debug$/)) {
96
+ DEBUG_FLAG = ! DEBUG_FLAG;
97
+ // --load
98
+ } else if (line.match(/^[ \n\t]*--load$/)) {
93
99
  val = run.defs;
94
100
  console.log(val);
95
101
  // --r
96
102
  } else if (line.match(/^[ \n\t]*(?:--r)?$/)) {
97
- console.log(
103
+ console.log("BUILT-IN:", run.builtin);
104
+ console.log("USER-DEFINED:",
98
105
  (function (defs, result) {
99
106
  if (defs == null) {
100
107
  return result;
101
108
  }
102
- return (function (prettyRel) {
103
- for (const relName in defs.rels) {
104
- if (relName != "__main__")
105
- result[relName] = prettyRel(defs.rels[relName].def);
106
- }
107
- return result;
108
- })(
109
- prettyRel.bind(
110
- null,
111
- prettyCode.bind(null, defs.representatives)
112
- )
113
- );
109
+
110
+ for (const relName in defs.rels) {
111
+ if (relName != "__main__")
112
+ result[relName] = prettyRel(defs.rels[relName].def);
113
+ }
114
+ return result;
114
115
  })(run.defs, {}));
115
116
  // --c
116
117
  } else if (line.match(/^[ \n\t]*(?:--c)?$/)) {
117
118
  console.log(
118
119
  (function (defs, result) {
119
120
  for (const codeName of Object.keys(defs.representatives || {})) {
120
- const codeExp = find(defs.representatives[codeName] || codeName);
121
- result[codeName] = prettyCode(
122
- defs.representatives,
123
- codeExp
124
- );
121
+ const codeRep = defs.representatives[codeName] || codeName;
122
+ if (codeName == codeRep) {
123
+ result[codeName] = prettyCode(
124
+ defs.representatives,
125
+ find(codeRep)
126
+ );
127
+ } else if (! codeName.startsWith(":")) {
128
+ result[codeName] = codeRep;
129
+ }
125
130
  }
126
131
  return result;
127
132
  })(run.defs || {}, {})
@@ -161,18 +166,33 @@ function evaluate(line) {
161
166
  const relName = line.match(re__R)[1];
162
167
  const rel = run.defs?.rels[relName];
163
168
  if (!rel) {
169
+ if (relName in run.builtin) {
170
+ console.log(` -- builtin relation: ${relName}\n ${relName} = ${run.builtin[relName]}`);
171
+ return;
172
+ }
164
173
  console.log(` -- relation '${relName}' not found`);
165
174
  return;
166
175
  }
176
+ const canonicalRelName = run.defs.relAlias[relName];
167
177
  const filters = patterns2filters(rel.typePatternGraph, ...rel.def.patterns);
168
178
  // console.log(filters);
169
179
  // console.log(" variables:", JSON.stringify(variables));
170
180
  // console.log(JSON.stringify({filters, variables}, null, 2));
171
181
  // for (const filter of filters) {
172
- const pcodef= prettyCode.bind(null, run.defs.representatives);
173
- const filtersStr = filters.map( x => prettyRel(pcodef, {op: "filter", filter: x}));
174
- console.log(` ${relName} : ${filtersStr[0]} --> ${filtersStr[1]}`);
175
- console.log(` ${relName} = ${prettyRel(pcodef,rel.def)};`);
182
+ const filtersStr = filters.map( x => prettyRel( {op: "filter", filter: x}));
183
+ // console.log(` -- canonical relation name: ${canonicalRelName} --`);
184
+ // console.log(` ${relName} : ${filtersStr[0]} --> ${filtersStr[1]}`);
185
+ // console.log(` ${relName} = ${prettyRel(rel.def)};`);
186
+ // console.log(` ${relName} = ${prettyRel(rel.simplified)};`);
187
+ console.log({
188
+ name: canonicalRelName,
189
+ type: `${filtersStr[0]} --> ${filtersStr[1]}`,
190
+ def: prettyRel(rel.simplified)
191
+ });
192
+ if (DEBUG_FLAG) {
193
+ val = exportRelation(run.defs.rels, run.defs.relAlias, relName);
194
+ console.log(val);
195
+ }
176
196
  // }
177
197
  // ------ k code
178
198
  } else if (!line.match(/^[ \n\t]*(?:#.*)?$/)) {
@@ -180,12 +200,11 @@ function evaluate(line) {
180
200
  val = k.run(`+++\n${line}\n()`, val);
181
201
  printVal();
182
202
  } catch (error) {
183
- e = error;
184
- console.error("ERROR:");
185
- console.error(e);
203
+ console.error(error.message);
186
204
  }
187
205
  }
188
206
  } catch (e) {
189
207
  console.error(e.message);
208
+ console.error(e);
190
209
  }
191
210
  }
package/run.mjs CHANGED
@@ -248,7 +248,9 @@ function run(exp, value) {
248
248
  }
249
249
  case "caret": {
250
250
  const result = run(exp.caret, value);
251
- assert(isOpen(result), "CARET (^): Only an 'open' vector can be closed.");
251
+ // assert(isOpen(result), "CARET (^): Only an 'open' vector can be closed.");
252
+ if (! isOpen(result))
253
+ throw new Error(`Type Error (line: ${exp.end?.line}:${exp.end?.column}): CARET (^): Only 'unboxed' values can be 'boxed'.`)
252
254
  return [...result];
253
255
  }
254
256
  case "filter": {
@@ -261,5 +263,7 @@ function run(exp, value) {
261
263
  };
262
264
  }
263
265
 
266
+ run.builtin = builtin;
267
+
264
268
  export default run;
265
269
  export { run , closeVector };
package/TYPES.md DELETED
@@ -1,32 +0,0 @@
1
- # What if we concider partial functions as filter-to-filter mappings?
2
-
3
- ## Examples
4
-
5
- ```k
6
- .x :: ( X x, ... ) -> X
7
- { f1 x1, f2 x2, ..., fn xn } :: X -> { f1(X) x1, f2(X) x2, ..., fn(X) xn }
8
- { f x } :: X -> < f(X) x, ... >
9
- < f1, f2, ..., fn > :: X -> f1(X) // f1 == f2 == ... == fn
10
- [ f1, f2, ..., fn ] :: X -> [f1(X)] // f1 == f2 == ... == fn
11
- $code ::
12
- ```
13
-
14
- Let's consider the following example:
15
-
16
- ```k
17
- $nat = < {} _, nat s >;
18
- z = {{} _}; -- X -> <{} _, ...>
19
- s = {() s}; -- X -> <X s, ...>
20
-
21
- add =
22
- <
23
- {.x ._ if, .y then} .then,
24
- {.x .s x, .y s y } add
25
- >
26
- ;
27
-
28
- double = {() x, () y} add;
29
-
30
- z s s $nat double;
31
- ```
32
-