@fraczak/k 1.3.1 → 1.3.3

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/INTRO.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # k - the way of building and manipulating JSON-like data
2
2
 
3
- Technically: notation for defining __first-order partial functions__.
3
+ Technically, `k` is a notation for defining __first-order partial functions__.
4
4
 
5
- An example of a _partial function_ is "`.toto`", which maps an object
6
- to its property named `toto`, or it is not defined if the property
7
- doesn't exist. E.g.,
5
+ An example of a _partial function_ is the _projection_, e.g., "`.toto`",
6
+ which maps an object to its property named `toto`, or it is not defined if
7
+ the property doesn't exist. E.g.,
8
8
 
9
9
  .toto :
10
10
  {"toto": 5, "titi": 10} --> 5
@@ -51,6 +51,14 @@ __QUIZ__: What is:
51
51
 
52
52
  ---
53
53
 
54
+ #### Syntactic sugar:
55
+
56
+ - parenthesis can be omitted, except for the empty composition `()`,
57
+ - dot (`.`) in "projection" acts as a separator so the space around it can be omitted.
58
+
59
+ For example, `[(.toto .titi (.0 .1))]` can be written as `[.toto.titi.0.1]`.
60
+
61
+
54
62
  ## Basic extensions
55
63
 
56
64
  ### Constants, i.e., literals for `strings`, `integers`, `booleans`, and `null`
@@ -77,19 +85,25 @@ names are integers starting from zero. E.g., `{.toto "0", .titi "1",
77
85
 
78
86
  ## Pragmatic extensions, aka "standard library"
79
87
 
80
- - `GT` :
88
+ - `GT` : -- identity for lists of decreasing elements; undefined otherwise
81
89
 
90
+ [4,3] --> [4,3]
91
+ [3,4] ... undefined
92
+ [] --> []
82
93
  [4,3,0] --> [4,3,0]
83
- [5,8] - undefined
84
94
 
85
- - `EQ` :
95
+ - `EQ` : -- identity for lists of equal elements; undefined otherwise
86
96
 
97
+ [4,4] --> [4,4]
98
+ [4,5] ... undefined
87
99
  [4,4,4] --> [4,4,4]
88
- [5,8] - undefined
100
+ [] --> []
89
101
 
90
- - `[PLUS, TIMES, MINUS]` :
102
+ - `{PLUS plus, TIMES times}` :
91
103
 
92
- [2,2,2] --> [6,8,-2]
104
+ [1,2] --> {"plus":3,"times":2}
105
+ [2,2,2] --> {"plus":6,"times":8}
106
+ [] --> {"plus":0,"times":1}
93
107
 
94
108
  - `CONCAT` :
95
109
 
@@ -97,24 +111,25 @@ names are integers starting from zero. E.g., `{.toto "0", .titi "1",
97
111
 
98
112
  - `toJSON` :
99
113
 
100
- {a: 12} --> "{\"a\":12}"
114
+ {"a": 12} --> "{\"a\":12}"
101
115
 
102
116
  - `fromJSON` :
103
117
 
104
- "{\"a\":12}" --> {a: 12}
118
+ "{\"a\":12}" --> {"a":12}
105
119
 
106
- - `DIV`, `FDIV`, `CONS`, `SNOC`, `_log!`
120
+ - other predefined parial functions are: `DIV`, `FDIV`, `CONS`, `SNOC`, `toDateMsec`,
121
+ `toDateStr`, and `_log!`.
107
122
 
108
123
  ---
109
124
 
110
125
  ## Recursive definitions
111
126
 
112
127
  -- factorial.k
113
- dec = ([(),-1] PLUS);
114
- zero? = ([(),0] EQ 0);
128
+ dec = [(),-1] PLUS;
129
+ zero? = [(),0] EQ 0;
115
130
  factorial = <
116
- (zero? 1),
117
- ([(dec factorial), ()] TIMES)
131
+ zero? 1,
132
+ [(dec factorial), ()] TIMES
118
133
  >;
119
134
  { () x, factorial "x!" }
120
135
 
@@ -122,10 +137,10 @@ names are integers starting from zero. E.g., `{.toto "0", .titi "1",
122
137
 
123
138
  _Codes_ (prefixed by `$`) can be defined by taged union and product. E.g.:
124
139
 
125
- $nat = <nat s, {} z>; -- e.g., {{{{} z} s} s}
126
- $pair = {nat x, nat y}; -- e.g., {{{} z} x, {{{{} z} s} s} y}
140
+ $nat = <nat 1, {} 0>; -- e.g., {{{{} 0} 1} 1}
141
+ $pair = {nat x, nat y}; -- e.g., {{{} 0} x, {{{{} 0} 1} 1} y}
127
142
 
128
- s = ($nat {() s} $nat);
129
- add = ($pair <{(.x .s) x, (.y s) y} add, .y> $nat);
143
+ suc = $nat {() 1} $nat;
144
+ add = $pair <{.x.1 x, .y suc y} add, .y> $nat;
130
145
 
131
146
 
package/README.md CHANGED
@@ -51,14 +51,14 @@ the field (or a vector with the index).
51
51
  false
52
52
  null
53
53
 
54
- 6. There is a number of built-in functions: `GT`, `EQ`, `PLUS`,
55
- `TIMES`, `MINUS`, `DIV`, `CONCAT`, `toJSON`, `fromJSON`, `CONS`,
56
- `SNOC`, `_log!`, ... For example:
54
+ 6. The other "built-in" functions: `GT`, `EQ`, `PLUS`,
55
+ `TIMES`, `DIV`, `CONCAT`, `toJSON`, `fromJSON`, `CONS`,
56
+ `SNOC`, `toDateMsec`, `toDateStr`, and `_log!`. For example:
57
57
 
58
58
  [1, 2, 3] PLUS --> integer constant function 6
59
59
  [4, 4] TIMES toJSON --> string constant function "16"
60
60
  [3, 2] GT --> vector constant function [3, 2]
61
- [3, 4] GT --> is not defined!
61
+ [3, 4] GT ... is not defined!
62
62
 
63
63
  A more interesting example could be:
64
64
 
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "k-language for JSON-like data transformation",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "prepare": "coffee -c symbol-table.coffee; jison parser.jison",
7
+ "prepare": "coffee -c symbol-table.coffee; jiwson parser.jison",
8
8
  "prepublishOnly": "coffee -c *.coffee; echo '#!/usr/bin/env node' | cat - k.js > k.sh; echo '#!/usr/bin/env node' | cat - repl.js > repl.sh;",
9
9
  "all": "coffee -c *.coffee; npm run prepare; npm run prepublishOnly",
10
- "test": "coffee -c symbol-table.coffee; jison parser.jison; coffee test.coffee"
10
+ "test": "coffee -c symbol-table.coffee; jiwson parser.jison; coffee test.coffee"
11
11
  },
12
12
  "repository": {
13
13
  "type": "git",
@@ -21,6 +21,6 @@
21
21
  },
22
22
  "devDependencies": {
23
23
  "coffeescript": "^2.7.0",
24
- "jison": "^0.4.18"
24
+ "jiwson": "^0.1.1"
25
25
  }
26
26
  }
package/parser.js CHANGED
@@ -1,4 +1,4 @@
1
- /* parser generated by jison 0.4.18 */
1
+ /* parser generated by jison 0.1.1 */
2
2
  /*
3
3
  Returns a Parser object of the following structure:
4
4
 
@@ -71,6 +71,13 @@
71
71
  recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
72
72
  }
73
73
  */
74
+
75
+
76
+
77
+ var s = require("./symbol-table");
78
+
79
+
80
+
74
81
  var parser = (function(){
75
82
  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];
76
83
  var parser = {trace: function trace () { },
@@ -344,13 +351,7 @@ parse: function parse(input) {
344
351
  }
345
352
  }
346
353
  return true;
347
- }};
348
-
349
-
350
- var s = require("./symbol-table");
351
-
352
-
353
- /* generated by jison-lex 0.3.4 */
354
+ }};/* generated by jison-lex */
354
355
  var lexer = (function(){
355
356
  var lexer = ({
356
357
 
package/repl.coffee CHANGED
@@ -2,6 +2,7 @@
2
2
  k = require "./"
3
3
  run = require "./run"
4
4
  {prettyCode, prettyRel} = require "./pretty"
5
+ fs = require "fs"
5
6
 
6
7
  console.log "Very! experimental repl shell for 'k-language'..."
7
8
 
@@ -33,7 +34,8 @@ do (val = {}, buffer = []) ->
33
34
  else if line.match re
34
35
  file = line.match(re)[1]
35
36
  console.log "-- loading file: #{file} ..."
36
- val = k.compile_file(file) val
37
+ kScript = fs.readFileSync(file).toString();
38
+ val = k.compile(kScript) val
37
39
  console.log "=> #{JSON.stringify val}"
38
40
  else if line.match /^[ \n\t]*(?:--a)?$/
39
41
  console.log JSON.stringify run.defs, " ", 2
package/repl.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Generated by CoffeeScript 2.7.0
2
2
  (function() {
3
3
  //!/usr/bin/env coffee
4
- var help, k, prettyCode, prettyRel, re, run,
4
+ var fs, help, k, prettyCode, prettyRel, re, run,
5
5
  splice = [].splice;
6
6
 
7
7
  k = require("./");
@@ -10,6 +10,8 @@
10
10
 
11
11
  ({prettyCode, prettyRel} = require("./pretty"));
12
12
 
13
+ fs = require("fs");
14
+
13
15
  console.log("Very! experimental repl shell for 'k-language'...");
14
16
 
15
17
  help = function() {
@@ -26,7 +28,7 @@
26
28
 
27
29
  (function(val, buffer) {
28
30
  return process.stdin.on('data', function(data) {
29
- var e, file, first, i, last, len, line, ref, rest, results, todo;
31
+ var e, file, first, i, kScript, last, len, line, ref, rest, results, todo;
30
32
  [first, ...rest] = data.toString("utf8").split("\n");
31
33
  buffer.push(first);
32
34
  if (rest.length > 0) {
@@ -45,7 +47,8 @@
45
47
  } else if (line.match(re)) {
46
48
  file = line.match(re)[1];
47
49
  console.log(`-- loading file: ${file} ...`);
48
- val = k.compile_file(file)(val);
50
+ kScript = fs.readFileSync(file).toString();
51
+ val = k.compile(kScript)(val);
49
52
  results.push(console.log(`=> ${JSON.stringify(val)}`));
50
53
  } else if (line.match(/^[ \n\t]*(?:--a)?$/)) {
51
54
  results.push(console.log(JSON.stringify(run.defs, " ", 2)));
package/repl.sh CHANGED
@@ -2,7 +2,7 @@
2
2
  // Generated by CoffeeScript 2.7.0
3
3
  (function() {
4
4
  //!/usr/bin/env coffee
5
- var help, k, prettyCode, prettyRel, re, run,
5
+ var fs, help, k, prettyCode, prettyRel, re, run,
6
6
  splice = [].splice;
7
7
 
8
8
  k = require("./");
@@ -11,6 +11,8 @@
11
11
 
12
12
  ({prettyCode, prettyRel} = require("./pretty"));
13
13
 
14
+ fs = require("fs");
15
+
14
16
  console.log("Very! experimental repl shell for 'k-language'...");
15
17
 
16
18
  help = function() {
@@ -27,7 +29,7 @@
27
29
 
28
30
  (function(val, buffer) {
29
31
  return process.stdin.on('data', function(data) {
30
- var e, file, first, i, last, len, line, ref, rest, results, todo;
32
+ var e, file, first, i, kScript, last, len, line, ref, rest, results, todo;
31
33
  [first, ...rest] = data.toString("utf8").split("\n");
32
34
  buffer.push(first);
33
35
  if (rest.length > 0) {
@@ -46,7 +48,8 @@
46
48
  } else if (line.match(re)) {
47
49
  file = line.match(re)[1];
48
50
  console.log(`-- loading file: ${file} ...`);
49
- val = k.compile_file(file)(val);
51
+ kScript = fs.readFileSync(file).toString();
52
+ val = k.compile(kScript)(val);
50
53
  results.push(console.log(`=> ${JSON.stringify(val)}`));
51
54
  } else if (line.match(/^[ \n\t]*(?:--a)?$/)) {
52
55
  results.push(console.log(JSON.stringify(run.defs, " ", 2)));
package/run.coffee CHANGED
@@ -20,11 +20,6 @@ builtin =
20
20
  return args if ok
21
21
  "PLUS": (args) -> valid args.reduce ((res, x) -> res + x), 0
22
22
  "TIMES": (args) -> valid args.reduce ((res, x) -> res * x), 1
23
- "MINUS": (args) ->
24
- return valid(- args) if 'number' is typeof args
25
- do ([res,args...] = args) ->
26
- return valid (- res) if args.length is 0
27
- valid args.reduce ((res, x) -> res - x), res
28
23
  "DIV": ([x,y]) ->
29
24
  div = x // y
30
25
  rem = x %% y
package/run.js CHANGED
@@ -49,19 +49,6 @@
49
49
  return res * x;
50
50
  }), 1));
51
51
  },
52
- "MINUS": function(args) {
53
- if ('number' === typeof args) {
54
- return valid(-args);
55
- }
56
- return (function([res, ...args]) {
57
- if (args.length === 0) {
58
- return valid(-res);
59
- }
60
- return valid(args.reduce((function(res, x) {
61
- return res - x;
62
- }), res));
63
- })(args);
64
- },
65
52
  "DIV": function([x, y]) {
66
53
  var div, rem;
67
54
  div = Math.floor(x / y);
@@ -7,21 +7,37 @@ identity = op: "identity"
7
7
  is_identity_rel = (rel) ->
8
8
  rel.op is "identity"
9
9
 
10
+ is_constant_rel = (rel) ->
11
+ switch rel?.op
12
+ when "int", "str"
13
+ true
14
+ when "vector"
15
+ Object.values(rel[rel.op]).every is_constant_rel
16
+ when "product"
17
+ Object.values(rel[rel.op]).every ({exp}) ->
18
+ is_constant_rel exp
19
+ else
20
+ false
21
+
10
22
  is_empty_rel = (rel) ->
11
23
  rel.op is "union" and rel.union.length is 0
12
24
 
13
25
  is_full_rel = (rel) ->
26
+ return true if is_constant_rel rel
14
27
  switch rel.op
15
28
  when "int", "str", "identity"
16
29
  true
17
30
  when "comp"
18
31
  rel.comp.every is_full_rel
19
- when "product", "vector"
32
+ when "vector"
20
33
  Object.values(rel[rel.op]).every is_full_rel
34
+ when "product"
35
+ Object.values(rel[rel.op]).every ({exp}) ->
36
+ is_full_rel exp
21
37
  else
22
38
  false
23
39
 
24
- comp = (e1, e2) ->
40
+ comp_first = (e1, e2) ->
25
41
  return e2 if is_identity_rel e1
26
42
  return e1 if is_identity_rel e2
27
43
  return e1 if is_empty_rel e1
@@ -34,6 +50,16 @@ comp = (e1, e2) ->
34
50
  return {op: "comp", comp: [].concat([e1],e2.comp)}
35
51
  {op: "comp", comp: [e1,e2]}
36
52
 
53
+ comp = (e1, e2) ->
54
+ result = comp_first e1, e2
55
+ return result unless result.op is "comp"
56
+ result.comp = result.comp.reduceRight (c, e) ->
57
+ if is_constant_rel(c[0]) and is_full_rel e
58
+ return c
59
+ return [e, c...]
60
+ , []
61
+ result
62
+
37
63
  union = (rels) ->
38
64
  list = []
39
65
  do ->
package/symbol-table.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // Generated by CoffeeScript 2.7.0
2
2
  (function() {
3
- var add_code, add_rel, as_ref, codes, comp, identity, is_empty_rel, is_full_rel, is_identity_rel, rels, union;
3
+ var add_code, add_rel, as_ref, codes, comp, comp_first, identity, is_constant_rel, is_empty_rel, is_full_rel, is_identity_rel, rels, union;
4
4
 
5
5
  rels = Object.create(null);
6
6
 
@@ -19,11 +19,30 @@
19
19
  return rel.op === "identity";
20
20
  };
21
21
 
22
+ is_constant_rel = function(rel) {
23
+ switch (rel != null ? rel.op : void 0) {
24
+ case "int":
25
+ case "str":
26
+ return true;
27
+ case "vector":
28
+ return Object.values(rel[rel.op]).every(is_constant_rel);
29
+ case "product":
30
+ return Object.values(rel[rel.op]).every(function({exp}) {
31
+ return is_constant_rel(exp);
32
+ });
33
+ default:
34
+ return false;
35
+ }
36
+ };
37
+
22
38
  is_empty_rel = function(rel) {
23
39
  return rel.op === "union" && rel.union.length === 0;
24
40
  };
25
41
 
26
42
  is_full_rel = function(rel) {
43
+ if (is_constant_rel(rel)) {
44
+ return true;
45
+ }
27
46
  switch (rel.op) {
28
47
  case "int":
29
48
  case "str":
@@ -31,15 +50,18 @@
31
50
  return true;
32
51
  case "comp":
33
52
  return rel.comp.every(is_full_rel);
34
- case "product":
35
53
  case "vector":
36
54
  return Object.values(rel[rel.op]).every(is_full_rel);
55
+ case "product":
56
+ return Object.values(rel[rel.op]).every(function({exp}) {
57
+ return is_full_rel(exp);
58
+ });
37
59
  default:
38
60
  return false;
39
61
  }
40
62
  };
41
63
 
42
- comp = function(e1, e2) {
64
+ comp_first = function(e1, e2) {
43
65
  if (is_identity_rel(e1)) {
44
66
  return e2;
45
67
  }
@@ -76,6 +98,21 @@
76
98
  };
77
99
  };
78
100
 
101
+ comp = function(e1, e2) {
102
+ var result;
103
+ result = comp_first(e1, e2);
104
+ if (result.op !== "comp") {
105
+ return result;
106
+ }
107
+ result.comp = result.comp.reduceRight(function(c, e) {
108
+ if (is_constant_rel(c[0]) && is_full_rel(e)) {
109
+ return c;
110
+ }
111
+ return [e, ...c];
112
+ }, []);
113
+ return result;
114
+ };
115
+
79
116
  union = function(rels) {
80
117
  var list;
81
118
  list = [];