@fraczak/k 1.1.0 → 1.1.1

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
@@ -48,9 +48,9 @@ Elementary partial functions are:
48
48
  3. There is a number of built-in functions: `GT`, `EQ`, `PLUS`,
49
49
  `TIMES`, `MINUS`, `DIV`, `CONCAT`, `toJSON`, `fromJSON`, `CONS`, `SNOC`. For example
50
50
 
51
- [1, 2, 3] PLUS --> integer constant 6
52
- [4, 4] TIMES toJSON --> string constant "16"
53
- [3, 2] GT --> vector constant [3, 2]
51
+ [1, 2, 3] PLUS --> integer constant function 6
52
+ [4, 4] TIMES toJSON --> string constant function "16"
53
+ [3, 2] GT --> vector constant function [3, 2]
54
54
  [3, 4] GT --> is not defined!
55
55
 
56
56
  A more interesting example could be:
@@ -70,18 +70,22 @@ Elementary partial functions are:
70
70
  [1,()] GT 1,
71
71
  [dec factorial, ()] TIMES
72
72
  >;
73
- { x: (), "x!": factorial }
73
+ { () x, factorial "x!" }
74
74
 
75
75
  ## Value encodings (also called _types_ or _codes_)
76
76
 
77
77
  There are three predefined value encodings: `int`, `string`, and `bool`. The language
78
78
  supports `code`-expressions:
79
79
 
80
- * product, e.g., `{x: int, y: int, flag: bool}`
81
- * disjoint union, e.g., `<x: string, y: bool>`
80
+ * product, e.g., `{int x, int y, bool flag}` (in JSON-like syntax `{x: int, y: int, flag: bool}`)
81
+ * disjoint union, e.g., `<{} true, {} false>` (in JSON-like syntax `<true: {}, false: {}>`)
82
82
  * vector, e.g., `[ int ]` (all elements of the vector use the same encoding)
83
83
 
84
- One can define recursive codes. E.g.,
84
+ One can define recursive codes. E.g.:
85
+
86
+ $ tree = <string leaf, {tree left, tree right} tree>;
87
+
88
+ or, the same in JSON-like notation:
85
89
 
86
90
  $ tree = <leaf: string, tree: {left: tree, right: tree}>;
87
91
 
@@ -91,7 +95,7 @@ The above example defines new code called _tree_.
91
95
  The code can be then used in a `k`-expression as a filter. A `code`-expression
92
96
  within `k`-expression is again prefixed by `$`.
93
97
 
94
- $tree = <leaf: string, tree: {left: tree, right: tree}>;
98
+ $tree = <string leaf, {tree left, tree right} tree>;
95
99
  inc = [(),1] PLUS;
96
100
  height = $ tree <
97
101
  .leaf 0,
@@ -107,7 +111,7 @@ run the language from command line.
107
111
 
108
112
  $ ./node_modules/.bin/k
109
113
  ... errors ...
110
- Usage: ./node_modules/.bin/k ( k-expr | -k k-file) [ json-file ]
114
+ Usage: ./node_modules/.bin/k ( k-expr | -k k-file) [ -1 ] [ json-file ]
111
115
  E.g., cat '{"a": 10}' | ./node_modules/.bin/k '[(),()]'
112
116
 
113
117
  ### Examples
package/bnat.k CHANGED
@@ -71,7 +71,7 @@ _reverse_bnat =
71
71
  _add2wc =
72
72
  -- least significant bit first addition with carry
73
73
  --- :{ :bnat x, :bnat y, :[0,1] c}
74
- -- _log_
74
+ -- _log!
75
75
  <
76
76
  {.x."0" x, .y."0" y, .c."0" c} {.x x, .y y, _ _0 c} _add2wc _0,
77
77
  {.x."0" x, .y."0" y, .c."1" c} {.x x, .y y, _ _0 c} _add2wc _1,
package/code.k CHANGED
@@ -1,5 +1,5 @@
1
1
  inc = [(),1] PLUS;
2
- $tree = <leaf: string, tree: {left: tree, right: tree}>;
2
+ $tree = < string leaf, {tree left, tree right} tree>;
3
3
  height = $tree <
4
4
  .leaf 0,
5
5
  .tree [.left height, .right height] <GT .0, .1> inc
@@ -15,4 +15,4 @@ height = $tree <
15
15
  }
16
16
  }
17
17
  }
18
- > _log_ height
18
+ > _log! height
package/codes.coffee ADDED
@@ -0,0 +1,107 @@
1
+
2
+ are_different = (classes, representatives, name1, name2, codes) ->
3
+ return false if name1 is name2
4
+ code1 = codes[name1]
5
+ code2 = codes[name2]
6
+ # console.log {name1, code1, name2, code2}
7
+ return true unless code1.code is code2.code
8
+ switch code1.code
9
+ when "union", "product"
10
+ [fields1,fields2] = [code1, code2]. map (code) ->
11
+ Object.keys(code[code.code]).reduce (fields, label) ->
12
+ fields[label] = representatives[code[code.code][label]]
13
+ , {}
14
+ return true unless Object.keys(fields1).length is Object.keys(fields2).length
15
+ for field,rep of fields1
16
+ return true unless fields2[field] is rep
17
+ return false
18
+ when "vector"
19
+ return representatives[code1.vector] isnt representatives[code2.vector]
20
+ false
21
+
22
+ minimize = (codes) ->
23
+ names = Object.keys codes
24
+ classes = {}
25
+ classes["{}"] = names
26
+ representatives = names.reduce (representatives, name) ->
27
+ representatives[name] = "{}"
28
+ representatives
29
+ , {}
30
+ changed = true
31
+ while changed
32
+ changed = false
33
+ for name1, eq_names of classes
34
+ code = codes[name1]
35
+ [eq_names, dif_names] = eq_names.reduce ([eq_names, dif_names], name2) ->
36
+ if are_different(classes, representatives, name1, name2, codes)
37
+ dif_names.push name2
38
+ else
39
+ eq_names.push name2
40
+ [eq_names,dif_names]
41
+ , [[],[]]
42
+ classes[name1] = eq_names
43
+ do (new_rep = dif_names[0]) ->
44
+ if new_rep?
45
+ changed = true
46
+ classes[new_rep] = dif_names
47
+ for x in dif_names
48
+ representatives[x] = new_rep
49
+ {classes,representatives}
50
+
51
+ compareAs = (fn) ->
52
+ (a,b) ->
53
+ [a,b] = [a,b].map fn
54
+ return -1 if a < b
55
+ return 1 if a > b
56
+ 0
57
+
58
+ pretty_labels = (label_ref_map, codes, representatives) ->
59
+ labels = Object.keys(label_ref_map)
60
+ .sort compareAs (x) -> x
61
+ .map (label) ->
62
+ "#{pretty {code:"ref",ref:label_ref_map[label]}, codes, representatives} #{label}"
63
+ .join ", "
64
+
65
+ pretty = (codeExp, codes, representatives) ->
66
+ switch codeExp.code
67
+ when "ref"
68
+ name = representatives[codeExp.ref] ? codeExp.ref
69
+ if name.startsWith ":"
70
+ pretty codes[name], codes, representatives
71
+ else
72
+ name
73
+ when "product"
74
+ "{#{pretty_labels codeExp.product, codes, representatives}}"
75
+ when "union"
76
+ "<#{pretty_labels codeExp.union, codes, representatives}>"
77
+ when "vector"
78
+ "[#{representatives[codeExp.ref] ? codeExp.ref}]"
79
+ else
80
+ ":error"
81
+
82
+ normalize = (label_ref_map, representatives) ->
83
+ # console.log {label_ref_map, representatives}
84
+ Object.keys(label_ref_map).reduce (result, label) ->
85
+ result[label] = do (name = label_ref_map[label]) ->
86
+ representatives[name] ? name
87
+ result
88
+ , {}
89
+
90
+ normalizeAll = (codes,representatives) ->
91
+ names = Object.keys codes
92
+ normalized = names.reduce (normalized, name) ->
93
+ if name is representatives[name]
94
+ do (code = codes[name]) ->
95
+ switch code.code
96
+ when "union", "product"
97
+ normalized[name] = { code: code.code }
98
+ normalized[name][code.code] = normalize code[code.code], representatives
99
+ when "vector"
100
+ normalized[name] = {code:"vector", vector: representatives[code.vector]}
101
+
102
+ normalized
103
+ , {}
104
+
105
+ module.exports = {minimize,pretty,normalize,normalizeAll}
106
+
107
+
package/codes.js ADDED
@@ -0,0 +1,167 @@
1
+ // Generated by CoffeeScript 2.7.0
2
+ (function() {
3
+ var are_different, compareAs, minimize, normalize, normalizeAll, pretty, pretty_labels;
4
+
5
+ are_different = function(classes, representatives, name1, name2, codes) {
6
+ var code1, code2, field, fields1, fields2, rep;
7
+ if (name1 === name2) {
8
+ return false;
9
+ }
10
+ code1 = codes[name1];
11
+ code2 = codes[name2];
12
+ if (code1.code !== code2.code) {
13
+ // console.log {name1, code1, name2, code2}
14
+ return true;
15
+ }
16
+ switch (code1.code) {
17
+ case "union":
18
+ case "product":
19
+ [fields1, fields2] = [code1, code2].map(function(code) {
20
+ return Object.keys(code[code.code]).reduce(function(fields, label) {
21
+ return fields[label] = representatives[code[code.code][label]];
22
+ }, {});
23
+ });
24
+ if (Object.keys(fields1).length !== Object.keys(fields2).length) {
25
+ return true;
26
+ }
27
+ for (field in fields1) {
28
+ rep = fields1[field];
29
+ if (fields2[field] !== rep) {
30
+ return true;
31
+ }
32
+ }
33
+ return false;
34
+ case "vector":
35
+ return representatives[code1.vector] !== representatives[code2.vector];
36
+ }
37
+ return false;
38
+ };
39
+
40
+ minimize = function(codes) {
41
+ var changed, classes, code, dif_names, eq_names, name1, names, representatives;
42
+ names = Object.keys(codes);
43
+ classes = {};
44
+ classes["{}"] = names;
45
+ representatives = names.reduce(function(representatives, name) {
46
+ representatives[name] = "{}";
47
+ return representatives;
48
+ }, {});
49
+ changed = true;
50
+ while (changed) {
51
+ changed = false;
52
+ for (name1 in classes) {
53
+ eq_names = classes[name1];
54
+ code = codes[name1];
55
+ [eq_names, dif_names] = eq_names.reduce(function([eq_names, dif_names], name2) {
56
+ if (are_different(classes, representatives, name1, name2, codes)) {
57
+ dif_names.push(name2);
58
+ } else {
59
+ eq_names.push(name2);
60
+ }
61
+ return [eq_names, dif_names];
62
+ }, [[], []]);
63
+ classes[name1] = eq_names;
64
+ (function(new_rep) {
65
+ var i, len, results, x;
66
+ if (new_rep != null) {
67
+ changed = true;
68
+ classes[new_rep] = dif_names;
69
+ results = [];
70
+ for (i = 0, len = dif_names.length; i < len; i++) {
71
+ x = dif_names[i];
72
+ results.push(representatives[x] = new_rep);
73
+ }
74
+ return results;
75
+ }
76
+ })(dif_names[0]);
77
+ }
78
+ }
79
+ return {classes, representatives};
80
+ };
81
+
82
+ compareAs = function(fn) {
83
+ return function(a, b) {
84
+ [a, b] = [a, b].map(fn);
85
+ if (a < b) {
86
+ return -1;
87
+ }
88
+ if (a > b) {
89
+ return 1;
90
+ }
91
+ return 0;
92
+ };
93
+ };
94
+
95
+ pretty_labels = function(label_ref_map, codes, representatives) {
96
+ var labels;
97
+ return labels = Object.keys(label_ref_map).sort(compareAs(function(x) {
98
+ return x;
99
+ })).map(function(label) {
100
+ return `${pretty({
101
+ code: "ref",
102
+ ref: label_ref_map[label]
103
+ }, codes, representatives)} ${label}`;
104
+ }).join(", ");
105
+ };
106
+
107
+ pretty = function(codeExp, codes, representatives) {
108
+ var name, ref, ref1;
109
+ switch (codeExp.code) {
110
+ case "ref":
111
+ name = (ref = representatives[codeExp.ref]) != null ? ref : codeExp.ref;
112
+ if (name.startsWith(":")) {
113
+ return pretty(codes[name], codes, representatives);
114
+ } else {
115
+ return name;
116
+ }
117
+ break;
118
+ case "product":
119
+ return `{${pretty_labels(codeExp.product, codes, representatives)}}`;
120
+ case "union":
121
+ return `<${pretty_labels(codeExp.union, codes, representatives)}>`;
122
+ case "vector":
123
+ return `[${(ref1 = representatives[codeExp.ref]) != null ? ref1 : codeExp.ref}]`;
124
+ default:
125
+ return ":error";
126
+ }
127
+ };
128
+
129
+ normalize = function(label_ref_map, representatives) {
130
+ // console.log {label_ref_map, representatives}
131
+ return Object.keys(label_ref_map).reduce(function(result, label) {
132
+ result[label] = (function(name) {
133
+ var ref;
134
+ return (ref = representatives[name]) != null ? ref : name;
135
+ })(label_ref_map[label]);
136
+ return result;
137
+ }, {});
138
+ };
139
+
140
+ normalizeAll = function(codes, representatives) {
141
+ var names, normalized;
142
+ names = Object.keys(codes);
143
+ return normalized = names.reduce(function(normalized, name) {
144
+ if (name === representatives[name]) {
145
+ (function(code) {
146
+ switch (code.code) {
147
+ case "union":
148
+ case "product":
149
+ normalized[name] = {
150
+ code: code.code
151
+ };
152
+ return normalized[name][code.code] = normalize(code[code.code], representatives);
153
+ case "vector":
154
+ return normalized[name] = {
155
+ code: "vector",
156
+ vector: representatives[code.vector]
157
+ };
158
+ }
159
+ })(codes[name]);
160
+ }
161
+ return normalized;
162
+ }, {});
163
+ };
164
+
165
+ module.exports = {minimize, pretty, normalize, normalizeAll};
166
+
167
+ }).call(this);
package/fib.k CHANGED
@@ -1,4 +1,4 @@
1
- fib_aux =
1
+ fib_aux = _log!
2
2
  <
3
3
  { [.n, 1] GT [.0,-1] PLUS n,
4
4
  ."[fib(n),fib(n-1)" [[.0,.1] PLUS, .0] "[fib(n),fib(n-1)"
package/index.coffee CHANGED
@@ -1,11 +1,25 @@
1
1
  fs = require "fs"
2
2
  {parse} = require "./parser.js"
3
3
  run = require "./run"
4
+ t = require "./codes"
5
+
6
+
7
+ finalize = (codes) ->
8
+ representatives = t.minimize(codes).representatives
9
+ codes = t.normalizeAll codes, representatives
10
+
11
+ {codes, representatives}
12
+
4
13
 
5
14
  compile = (script) ->
6
15
  do ({defs,exp} = parse script) ->
7
- run.defs = defs
16
+ # console.log defs
17
+ {codes, representatives} = finalize defs.codes
18
+ # console.log {codes, representatives}
19
+ run.defs = {codes, representatives, rels: defs.rels}
20
+
8
21
  (data) -> run exp, data
22
+
9
23
  compile.doc = "Transforms k-script (string) into a function"
10
24
 
11
25
  compile_file = (fileName) ->
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // Generated by CoffeeScript 2.7.0
2
2
  (function() {
3
- var compile, compile_file, fs, parse, run, runScriptOnData;
3
+ var compile, compile_file, finalize, fs, parse, run, runScriptOnData, t;
4
4
 
5
5
  fs = require("fs");
6
6
 
@@ -8,9 +8,26 @@
8
8
 
9
9
  run = require("./run");
10
10
 
11
+ t = require("./codes");
12
+
13
+ finalize = function(codes) {
14
+ var representatives;
15
+ representatives = t.minimize(codes).representatives;
16
+ codes = t.normalizeAll(codes, representatives);
17
+ return {codes, representatives};
18
+ };
19
+
11
20
  compile = function(script) {
12
21
  return (function({defs, exp}) {
13
- run.defs = defs;
22
+ var codes, representatives;
23
+ // console.log defs
24
+ ({codes, representatives} = finalize(defs.codes));
25
+ // console.log {codes, representatives}
26
+ run.defs = {
27
+ codes,
28
+ representatives,
29
+ rels: defs.rels
30
+ };
14
31
  return function(data) {
15
32
  return run(exp, data);
16
33
  };
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "k-language for JSON-like data transformation",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "prepare": "coffee -c symbol-table.coffee; jison parser.jison",
8
8
  "prepublishOnly": "coffee -c *.coffee; echo '#!/usr/bin/env node' | cat - k.js > k.sh",
9
+ "all": "npm run prepublishOnly; npm run prepare; npm run prepublishOnly",
9
10
  "test": "coffee -c symbol-table.coffee; jison parser.jison; coffee test.coffee"
10
11
  },
11
12
  "author": "Wojciech Fraczak",
package/parser.jison CHANGED
@@ -44,27 +44,27 @@ str: STRING { $$ = String(yytext).slice(1,-1); };
44
44
  int: INT { $$ = parseInt(String(yytext)); };
45
45
 
46
46
  input_with_eof: defs comp EOF {
47
- result = {defs: $1, exp: $2};
47
+ result = {defs: {rels: s.rels, codes: s.codes}, exp: $2};
48
48
  // console.log(JSON.stringify(result, "", 2));
49
49
  return result;
50
50
  };
51
51
 
52
- defs: { $$ = {codes: {}, rels: {}}; }
53
- | defs name EQ comp SC { $1.rels[$2] = $4; $$ = $1; }
54
- | defs DOLLAR name EQ code SC { $1.codes[$3] = $5; $$ = $1; }
52
+ defs: { }
53
+ | defs name EQ comp SC { s.add_rel($2,$4); }
54
+ | defs DOLLAR name EQ code SC { s.add_code($3,$5); }
55
55
  ;
56
56
 
57
57
  code
58
58
  : name { $$ = {code: "ref", ref: $1}; }
59
59
  | LC labelled_codes RC { $$ = {code: "product",
60
60
  product: $2.reduce((r, lc) => {
61
- r[lc.label] = lc.code;
61
+ r[lc.label] = s.as_ref(lc.code);
62
62
  return r }
63
63
  , {})}; }
64
- | LB code RB { $$ = {code: "vector", vector: $2}; }
64
+ | LB code RB { $$ = {code: "vector", vector: s.as_ref($2)}; }
65
65
  | LA labelled_codes RA { $$ = {code: "union",
66
66
  union: $2.reduce((r, lc) => {
67
- r[lc.label] = lc.code;
67
+ r[lc.label] = s.as_ref(lc.code);
68
68
  return r }
69
69
  , {})}; }
70
70
  ;
@@ -95,7 +95,7 @@ comp
95
95
  exp
96
96
  : LC labelled RC { $$ = $2; }
97
97
  | LB list RB { $$ = {op: "vector", vector: $2}; }
98
- | LA list RA { $$ = {op: "union", union: $2}; }
98
+ | LA list RA { $$ = s.union($2); }
99
99
  | name { $$ = {op: "ref", ref: $1}; }
100
100
  | LP RP { $$ = s.identity; }
101
101
  | LP comp RP { $$ = $2; }
@@ -104,7 +104,7 @@ exp
104
104
  | DOT int { $$ = {op: "dot", dot: $2}; }
105
105
  | DOT str { $$ = {op: "dot", dot: $2}; }
106
106
  | DOT name { $$ = {op: "dot", dot: $2}; }
107
- | DOLLAR code { $$ = {op: "code", code: $2}; }
107
+ | DOLLAR code { $$ = {op: "code", code: s.as_ref($2)}; }
108
108
  ;
109
109
 
110
110
  labelled
package/parser.js CHANGED
@@ -94,19 +94,19 @@ case 3:
94
94
  break;
95
95
  case 4:
96
96
 
97
- result = {defs: $$[$0-2], exp: $$[$0-1]};
97
+ result = {defs: {rels: s.rels, codes: s.codes}, exp: $$[$0-1]};
98
98
  // console.log(JSON.stringify(result, "", 2));
99
99
  return result;
100
100
 
101
101
  break;
102
102
  case 5:
103
- this.$ = {codes: {}, rels: {}};
103
+
104
104
  break;
105
105
  case 6:
106
- $$[$0-4].rels[$$[$0-3]] = $$[$0-1]; this.$ = $$[$0-4];
106
+ s.add_rel($$[$0-3],$$[$0-1]);
107
107
  break;
108
108
  case 7:
109
- $$[$0-5].codes[$$[$0-3]] = $$[$0-1]; this.$ = $$[$0-5];
109
+ s.add_code($$[$0-3],$$[$0-1]);
110
110
  break;
111
111
  case 8:
112
112
  this.$ = {code: "ref", ref: $$[$0]};
@@ -114,17 +114,17 @@ break;
114
114
  case 9:
115
115
  this.$ = {code: "product",
116
116
  product: $$[$0-1].reduce((r, lc) => {
117
- r[lc.label] = lc.code;
117
+ r[lc.label] = s.as_ref(lc.code);
118
118
  return r }
119
119
  , {})};
120
120
  break;
121
121
  case 10:
122
- this.$ = {code: "vector", vector: $$[$0-1]};
122
+ this.$ = {code: "vector", vector: s.as_ref($$[$0-1])};
123
123
  break;
124
124
  case 11:
125
125
  this.$ = {code: "union",
126
126
  union: $$[$0-1].reduce((r, lc) => {
127
- r[lc.label] = lc.code;
127
+ r[lc.label] = s.as_ref(lc.code);
128
128
  return r }
129
129
  , {})};
130
130
  break;
@@ -156,7 +156,7 @@ case 23:
156
156
  this.$ = {op: "vector", vector: $$[$0-1]};
157
157
  break;
158
158
  case 24:
159
- this.$ = {op: "union", union: $$[$0-1]};
159
+ this.$ = s.union($$[$0-1]);
160
160
  break;
161
161
  case 25:
162
162
  this.$ = {op: "ref", ref: $$[$0]};
@@ -177,7 +177,7 @@ case 30: case 31: case 32:
177
177
  this.$ = {op: "dot", dot: $$[$0]};
178
178
  break;
179
179
  case 33:
180
- this.$ = {op: "code", code: $$[$0]};
180
+ this.$ = {op: "code", code: s.as_ref($$[$0])};
181
181
  break;
182
182
  case 34:
183
183
  this.$ = {op: "product", product: []};
package/run.coffee CHANGED
@@ -3,8 +3,8 @@ valid = (x) ->
3
3
  return x if x?
4
4
 
5
5
  builtin =
6
- "_log_": (arg) ->
7
- console.log "_log_: #{JSON.stringify arg}"
6
+ "_log!": (arg) ->
7
+ console.log "_log!: #{JSON.stringify arg}"
8
8
  arg
9
9
  "GT": (args) ->
10
10
  [ok,_] = do ([last,args...] = args) ->
@@ -48,11 +48,8 @@ codes =
48
48
  x is true or x is false
49
49
 
50
50
  verify = (code, value) ->
51
+ # console.log {code,value}
51
52
  switch code.code
52
- when "ref"
53
- do (c = run.defs.codes[code.ref]) ->
54
- return verify c, value if c?
55
- codes[code.ref] value
56
53
  when "vector"
57
54
  value.every (x) ->
58
55
  verify code.vector, x
@@ -65,8 +62,13 @@ verify = (code, value) ->
65
62
  do (fields = Object.keys(value)) ->
66
63
  return false unless fields.length is 1
67
64
  verify code.union[fields[0]], value[fields[0]]
65
+ else
66
+ do (c = run.defs.codes[run.defs.representatives[code]]) ->
67
+ return verify c, value if c?
68
+ codes[code] value
68
69
 
69
70
  run = (exp, value) ->
71
+ # console.log {exp,value}
70
72
  return undefined if value is undefined
71
73
  try
72
74
  switch exp.op
@@ -77,7 +79,7 @@ run = (exp, value) ->
77
79
  when "str", "int"
78
80
  return exp[exp.op]
79
81
  when "ref"
80
- do (defn = run.defs.rels[exp.ref]) ->
82
+ do (defn = run.defs.rels[exp.ref]?[0]) ->
81
83
  if defn?
82
84
  run defn, value
83
85
  else
package/run.js CHANGED
@@ -13,8 +13,8 @@
13
13
  };
14
14
 
15
15
  builtin = {
16
- "_log_": function(arg) {
17
- console.log(`_log_: ${JSON.stringify(arg)}`);
16
+ "_log!": function(arg) {
17
+ console.log(`_log!: ${JSON.stringify(arg)}`);
18
18
  return arg;
19
19
  },
20
20
  "GT": function(args) {
@@ -111,14 +111,8 @@
111
111
  };
112
112
 
113
113
  verify = function(code, value) {
114
+ // console.log {code,value}
114
115
  switch (code.code) {
115
- case "ref":
116
- return (function(c) {
117
- if (c != null) {
118
- return verify(c, value);
119
- }
120
- return codes[code.ref](value);
121
- })(run.defs.codes[code.ref]);
122
116
  case "vector":
123
117
  return value.every(function(x) {
124
118
  return verify(code.vector, x);
@@ -139,12 +133,20 @@
139
133
  }
140
134
  return verify(code.union[fields[0]], value[fields[0]]);
141
135
  })(Object.keys(value));
136
+ default:
137
+ return (function(c) {
138
+ if (c != null) {
139
+ return verify(c, value);
140
+ }
141
+ return codes[code](value);
142
+ })(run.defs.codes[run.defs.representatives[code]]);
142
143
  }
143
144
  };
144
145
 
145
146
  run = function(exp, value) {
146
- var e, i, len, ref, result;
147
+ var e, i, len, ref, ref1, result;
147
148
  if (value === void 0) {
149
+ // console.log {exp,value}
148
150
  return void 0;
149
151
  }
150
152
  try {
@@ -171,7 +173,7 @@
171
173
  return value;
172
174
  })(builtin[exp.ref](value));
173
175
  }
174
- })(run.defs.rels[exp.ref]);
176
+ })((ref = run.defs.rels[exp.ref]) != null ? ref[0] : void 0);
175
177
  case "dot":
176
178
  return value[exp.dot];
177
179
  case "comp":
@@ -192,9 +194,9 @@
192
194
  return result;
193
195
  });
194
196
  case "union":
195
- ref = exp.union;
196
- for (i = 0, len = ref.length; i < len; i++) {
197
- e = ref[i];
197
+ ref1 = exp.union;
198
+ for (i = 0, len = ref1.length; i < len; i++) {
199
+ e = ref1[i];
198
200
  result = (function() {
199
201
  try {
200
202
  return run(e, value);
@@ -1,8 +1,31 @@
1
+ rels = Object.create null
2
+ codes = Object.create null
3
+ codes["{}"] = {code: "product", product: {}}
4
+
1
5
  identity = op: "identity"
2
6
 
7
+ is_identity_rel = (rel) ->
8
+ rel.op is "identity"
9
+
10
+ is_empty_rel = (rel) ->
11
+ rel.op is "union" and rel.union.length is 0
12
+
13
+ is_full_rel = (rel) ->
14
+ switch rel.op
15
+ when "int", "str", "identity"
16
+ true
17
+ when "comp"
18
+ rel.comp.every is_full_rel
19
+ when "product", "vector"
20
+ Object.values(rel[rel.op]).every is_full_rel
21
+ else
22
+ false
23
+
3
24
  comp = (e1, e2) ->
4
- return e2 if e1.op is "identity"
5
- return e1 if e2.op is "identity"
25
+ return e2 if is_identity_rel e1
26
+ return e1 if is_identity_rel e2
27
+ return e1 if is_empty_rel e1
28
+ return e2 if is_empty_rel e2
6
29
  if e1.op is "comp" and e2.op is "comp"
7
30
  return {op: "comp", comp: [].concat(e1.comp,e2.comp)}
8
31
  if e1.op is "comp"
@@ -11,4 +34,31 @@ comp = (e1, e2) ->
11
34
  return {op: "comp", comp: [].concat([e1],e2.comp)}
12
35
  {op: "comp", comp: [e1,e2]}
13
36
 
14
- module.exports = {identity, comp};
37
+ union = (rels) ->
38
+ list = []
39
+ do ->
40
+ for rel in rels
41
+ new_rels = if rel.op is "union"
42
+ rel.union
43
+ else
44
+ [rel]
45
+ for rel in new_rels
46
+ list.push rel
47
+ return if is_full_rel rel
48
+ return list[0] if list.length is 1
49
+ {op: "union", union: list}
50
+
51
+ as_ref = (codeExp) ->
52
+ return codeExp.ref if codeExp.code is "ref"
53
+ newName = ":#{Object.keys(codes).length}"
54
+ codes[newName] = codeExp
55
+ return newName
56
+
57
+ add_rel = (name, rel) ->
58
+ rels[name] ?= []
59
+ rels[name].push rel
60
+
61
+ add_code = (name, code) ->
62
+ codes[name] = code
63
+
64
+ module.exports = {identity, comp, union, rels, codes, add_rel, add_code, as_ref};
package/symbol-table.js CHANGED
@@ -1,18 +1,57 @@
1
1
  // Generated by CoffeeScript 2.7.0
2
2
  (function() {
3
- var comp, identity;
3
+ var add_code, add_rel, as_ref, codes, comp, identity, is_empty_rel, is_full_rel, is_identity_rel, rels, union;
4
+
5
+ rels = Object.create(null);
6
+
7
+ codes = Object.create(null);
8
+
9
+ codes["{}"] = {
10
+ code: "product",
11
+ product: {}
12
+ };
4
13
 
5
14
  identity = {
6
15
  op: "identity"
7
16
  };
8
17
 
18
+ is_identity_rel = function(rel) {
19
+ return rel.op === "identity";
20
+ };
21
+
22
+ is_empty_rel = function(rel) {
23
+ return rel.op === "union" && rel.union.length === 0;
24
+ };
25
+
26
+ is_full_rel = function(rel) {
27
+ switch (rel.op) {
28
+ case "int":
29
+ case "str":
30
+ case "identity":
31
+ return true;
32
+ case "comp":
33
+ return rel.comp.every(is_full_rel);
34
+ case "product":
35
+ case "vector":
36
+ return Object.values(rel[rel.op]).every(is_full_rel);
37
+ default:
38
+ return false;
39
+ }
40
+ };
41
+
9
42
  comp = function(e1, e2) {
10
- if (e1.op === "identity") {
43
+ if (is_identity_rel(e1)) {
11
44
  return e2;
12
45
  }
13
- if (e2.op === "identity") {
46
+ if (is_identity_rel(e2)) {
14
47
  return e1;
15
48
  }
49
+ if (is_empty_rel(e1)) {
50
+ return e1;
51
+ }
52
+ if (is_empty_rel(e2)) {
53
+ return e2;
54
+ }
16
55
  if (e1.op === "comp" && e2.op === "comp") {
17
56
  return {
18
57
  op: "comp",
@@ -37,6 +76,53 @@
37
76
  };
38
77
  };
39
78
 
40
- module.exports = {identity, comp};
79
+ union = function(rels) {
80
+ var list;
81
+ list = [];
82
+ (function() {
83
+ var i, j, len, len1, new_rels, rel;
84
+ for (i = 0, len = rels.length; i < len; i++) {
85
+ rel = rels[i];
86
+ new_rels = rel.op === "union" ? rel.union : [rel];
87
+ for (j = 0, len1 = new_rels.length; j < len1; j++) {
88
+ rel = new_rels[j];
89
+ list.push(rel);
90
+ if (is_full_rel(rel)) {
91
+ return;
92
+ }
93
+ }
94
+ }
95
+ })();
96
+ if (list.length === 1) {
97
+ return list[0];
98
+ }
99
+ return {
100
+ op: "union",
101
+ union: list
102
+ };
103
+ };
104
+
105
+ as_ref = function(codeExp) {
106
+ var newName;
107
+ if (codeExp.code === "ref") {
108
+ return codeExp.ref;
109
+ }
110
+ newName = `:${Object.keys(codes).length}`;
111
+ codes[newName] = codeExp;
112
+ return newName;
113
+ };
114
+
115
+ add_rel = function(name, rel) {
116
+ if (rels[name] == null) {
117
+ rels[name] = [];
118
+ }
119
+ return rels[name].push(rel);
120
+ };
121
+
122
+ add_code = function(name, code) {
123
+ return codes[name] = code;
124
+ };
125
+
126
+ module.exports = {identity, comp, union, rels, codes, add_rel, add_code, as_ref};
41
127
 
42
128
  }).call(this);