@fraczak/k 2.1.6 → 3.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/BIG_PICTURE.md +211 -0
- package/Code-derivation-tests/bnat.mjs +10 -0
- package/Code-derivation-tests/built-in.mjs +19 -0
- package/Code-derivation-tests/dot.mjs +15 -0
- package/Code-derivation-tests/index.mjs +20 -0
- package/Code-derivation-tests/loop.mjs +11 -0
- package/Code-derivation-tests/nat.mjs +10 -0
- package/Code-derivation-tests/not-not.mjs +14 -0
- package/Code-derivation-tests/product.mjs +21 -0
- package/Code-derivation-tests/rlz.mjs +14 -0
- package/Code-derivation-tests/vector.mjs +28 -0
- package/INTRO.md +88 -0
- package/README.md +68 -14
- package/TODO.md +54 -0
- package/TYPES.md +32 -0
- package/bug.json +419 -0
- package/chatGPT.md +235 -0
- package/chatGPT.md~ +119 -0
- package/code-resolution.md +121 -0
- package/code-resolution.mjs +51 -0
- package/codes.mjs +59 -4
- package/filters.mjs +59 -0
- package/hash.mjs +39 -0
- package/index.mjs +55 -12
- package/package.json +2 -2
- package/parser.jison +111 -44
- package/parser.mjs +146 -88
- package/patterns.mjs +601 -0
- package/pretty.mjs +27 -0
- package/repl.mjs +35 -6
- package/run.mjs +4 -1
- package/symbol-table.mjs +1 -1
- package/test-filters.mjs +45 -0
- package/test-fingerprint.mjs +38 -0
- package/test.mjs +1 -43
package/chatGPT.md~
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Thank you for the clarification. Let's revise the explanation to correctly describe the projection from union types as a check.
|
|
2
|
+
|
|
3
|
+
### Key Concepts and Constructs of Kernel/Core
|
|
4
|
+
|
|
5
|
+
1. **Program Structure**:
|
|
6
|
+
- Consists of a possibly empty list of statements, each ending with a semicolon (`;`), followed by an expression.
|
|
7
|
+
- Statements can be:
|
|
8
|
+
- **Code Definitions**: Define data types and start with a dollar sign (`$`).
|
|
9
|
+
- **Relation Definitions**: Define partial functions for data transformations.
|
|
10
|
+
|
|
11
|
+
2. **Code Definitions (Data Types)**:
|
|
12
|
+
- **Union Types**: Defined using angle brackets (`<...>`).
|
|
13
|
+
```kernelcore
|
|
14
|
+
$ bool = <{} true, {} false>;
|
|
15
|
+
```
|
|
16
|
+
- **Product Types**: Defined using curly braces (`{...}`).
|
|
17
|
+
```kernelcore
|
|
18
|
+
$ pair_of_bools = {bool x, bool y};
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
3. **Relation Definitions (Partial Functions)**:
|
|
22
|
+
- **Projection (Field Extraction)**: Partial functions that extract fields from product types or check for specific variants in union types.
|
|
23
|
+
```kernelcore
|
|
24
|
+
// Extract the `x` field from a pair_of_bools (product type)
|
|
25
|
+
extract_x = $pair_of_bools .x;
|
|
26
|
+
|
|
27
|
+
// Extract the `y` field from a pair_of_bools (product type)
|
|
28
|
+
extract_y = $pair_of_bools .y;
|
|
29
|
+
|
|
30
|
+
// Check if a bool is the `true` variant (union type)
|
|
31
|
+
check_true = $bool .true;
|
|
32
|
+
|
|
33
|
+
// Check if a bool is the `false` variant (union type)
|
|
34
|
+
check_false = $bool .false;
|
|
35
|
+
```
|
|
36
|
+
- **Functional Composition**: Sequential application of partial functions.
|
|
37
|
+
```kernelcore
|
|
38
|
+
is_x_true = $pair_of_bools .x .true;
|
|
39
|
+
```
|
|
40
|
+
- **Parallel (Product) Composition**: Combine multiple partial functions to construct a new product type.
|
|
41
|
+
```kernelcore
|
|
42
|
+
extract_both = $pair_of_bools {.x x_value, .y y_value};
|
|
43
|
+
```
|
|
44
|
+
- **Concurrent (Union) Composition**: Try different functions in sequence, returning the first successful result.
|
|
45
|
+
```kernelcore
|
|
46
|
+
is_any_true = $pair_of_bools <.x .true true_bool, .y .true true_bool, false_bool>;
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
4. **Constants**:
|
|
50
|
+
- Constants are partial functions that ignore their input.
|
|
51
|
+
```kernelcore
|
|
52
|
+
true_bool = {{} true};
|
|
53
|
+
false_bool = {{} false};
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
5. **Names and Labels**:
|
|
57
|
+
- Names and labels are alphanumerical sequences of ASCII characters, following the convention `[a-zA-Z_][a-zA-Z0-9_]*`.
|
|
58
|
+
|
|
59
|
+
6. **Final Expression**:
|
|
60
|
+
- A final expression evaluates usage examples and collects results in a single product.
|
|
61
|
+
```kernelcore
|
|
62
|
+
{pair1 is_x_true result1,
|
|
63
|
+
pair2 is_x_true result2,
|
|
64
|
+
pair1 extract_both both_values,
|
|
65
|
+
pair1 is_any_true any_true1,
|
|
66
|
+
pair2 is_any_true any_true2,
|
|
67
|
+
pair3 is_any_true any_true3}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Complete Example Program
|
|
71
|
+
|
|
72
|
+
```kernelcore
|
|
73
|
+
// Define a boolean type as a union of true and false
|
|
74
|
+
$ bool = <{} true, {} false>;
|
|
75
|
+
|
|
76
|
+
// Define a pair of booleans as a product of two booleans
|
|
77
|
+
$ pair_of_bools = {bool x, bool y};
|
|
78
|
+
|
|
79
|
+
// Projection (Field Extraction)
|
|
80
|
+
// Extract the `x` field from a pair_of_bools (product type)
|
|
81
|
+
extract_x = $pair_of_bools .x;
|
|
82
|
+
|
|
83
|
+
// Extract the `y` field from a pair_of_bools (product type)
|
|
84
|
+
extract_y = $pair_of_bools .y;
|
|
85
|
+
|
|
86
|
+
// Check if a bool is the `true` variant (union type)
|
|
87
|
+
check_true = $bool .true;
|
|
88
|
+
|
|
89
|
+
// Check if a bool is the `false` variant (union type)
|
|
90
|
+
check_false = $bool .false;
|
|
91
|
+
|
|
92
|
+
// Check if the `x` field is `true`
|
|
93
|
+
is_x_true = $pair_of_bools .x .true;
|
|
94
|
+
|
|
95
|
+
// Extract both `x` and `y` fields into a new product
|
|
96
|
+
extract_both = $pair_of_bools {.x x_value, .y y_value};
|
|
97
|
+
|
|
98
|
+
// Check if either `x` or `y` is `true`
|
|
99
|
+
is_any_true = $pair_of_bools <.x .true true_bool, .y .true true_bool, false_bool>;
|
|
100
|
+
|
|
101
|
+
// Define constants
|
|
102
|
+
true_bool = {{} true};
|
|
103
|
+
false_bool = {{} false};
|
|
104
|
+
|
|
105
|
+
// Create instances of `pair_of_bools`
|
|
106
|
+
pair1 = {true_bool x, true_bool y};
|
|
107
|
+
pair2 = {true_bool x, false_bool y};
|
|
108
|
+
pair3 = {false_bool x, false_bool y};
|
|
109
|
+
|
|
110
|
+
// Final expression to evaluate usage examples
|
|
111
|
+
{pair1 is_x_true result1,
|
|
112
|
+
pair2 is_x_true result2,
|
|
113
|
+
pair1 extract_both both_values,
|
|
114
|
+
pair1 is_any_true any_true1,
|
|
115
|
+
pair2 is_any_true any_true2,
|
|
116
|
+
pair3 is_any_true any_true3}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
This updated introduction and complete example program now correctly describe the projection from union types as checks, providing a comprehensive overview of kernel/core. If there are any further questions or a
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Pattern and its graph representation
|
|
2
|
+
|
|
3
|
+
Intuitively, a _pattern_ is an adhock description of a set of codes
|
|
4
|
+
by providing some characteristics of the codes. Those characteristics are:
|
|
5
|
+
|
|
6
|
+
1. Is this product vs union?
|
|
7
|
+
2. The code has to have field (label) leading to a type or another parretn
|
|
8
|
+
|
|
9
|
+
Code patterns is a graph with:
|
|
10
|
+
|
|
11
|
+
1. edges labeled by `fields`
|
|
12
|
+
2. nodes labeled by one of the:
|
|
13
|
+
|
|
14
|
+
1. `/*/` - open unkown
|
|
15
|
+
2. `{*}` - open product
|
|
16
|
+
3. `<*>` - open union
|
|
17
|
+
4. `//` - close uknown
|
|
18
|
+
5. `{}` - close product
|
|
19
|
+
6. `<>` - close union
|
|
20
|
+
|
|
21
|
+
A graph without "open" and "unknown" nodes is "code".
|
|
22
|
+
|
|
23
|
+
Actually every node in such a graph corresponds to a code pattern.
|
|
24
|
+
|
|
25
|
+
## Pattern Graph
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
|
|
29
|
+
$nat = < {} _, nat 0, nat 1>;
|
|
30
|
+
rlz = $nat <.0._ {{{} _} 0}, .0 rlz, ()>;
|
|
31
|
+
|
|
32
|
+
We get `codes`:
|
|
33
|
+
|
|
34
|
+
id | code
|
|
35
|
+
------|----------------------
|
|
36
|
+
'{}' | {}
|
|
37
|
+
'nat' | <nat 0, nat 1, {} _>
|
|
38
|
+
|
|
39
|
+
and the (singleton) forest of expressons:
|
|
40
|
+
|
|
41
|
+
id | ref-name | rel
|
|
42
|
+
------|----------|--------------
|
|
43
|
+
0 | 'rlz' | ($nat < (.0 ._ {{{} _} 0}), (.0 rlz), ()>)
|
|
44
|
+
|
|
45
|
+
### Initialize pattern graph
|
|
46
|
+
|
|
47
|
+
1. We annotate the expression forest by unique pattern ids, all initialized as `*`, e.g.:
|
|
48
|
+
|
|
49
|
+
id | name | rel*
|
|
50
|
+
---|-------|-----------------
|
|
51
|
+
0 | 'rlz' | ( $nat < ( .0 ._ { { {} _} 0} ) , ( .0 rlz ) , () > )
|
|
52
|
+
| | %0 ( %1 $nat %2 < %3 ( %4 .0 %5 ._ %6 { %7 { %8 {} %9 _} %10 0} %11 ) %12, %13 ( %14 .0 %15 rlz %16 ) %17 , %18 () %19 > %20 ) %21
|
|
53
|
+
|
|
54
|
+
2. The pattern graph (with 22 nodes) has no edges.
|
|
55
|
+
|
|
56
|
+
### Pattern graph folding
|
|
57
|
+
|
|
58
|
+
Given a pattern graph, `(V,E)`, and an expression forest, `F`, we calculate a `folding` of the pattern graph,
|
|
59
|
+
which consists of:
|
|
60
|
+
|
|
61
|
+
1. equivalence classes `eq` over `V + C`
|
|
62
|
+
- `%x $t $y` implies `%x ~ %y ~ $t`
|
|
63
|
+
- `%x ( %y ...)` implies `%x ~ %y`
|
|
64
|
+
- `(... %x ) %y` implies `%x ~ %y`
|
|
65
|
+
- `%x () %y` implies `%x ~ %y`
|
|
66
|
+
- `%x { %y1 ..., %y2 ..., ..., %yn ...}` implies `%x ~ %y1 ~ %y2 ~ ... ~ %yn`
|
|
67
|
+
- `%x < %y1 ..., %y2 ..., ..., %yn ...>` implies `%x ~ %y1 ~ %y2 ~ ... ~ %yn`
|
|
68
|
+
- `<... %y1, ... %y2, ..., ... %yn > %x` implies `%x ~ %y1 ~ %y2 ~ ... ~ %yn`
|
|
69
|
+
- if `%x ~ $t` and `%x .field %y` implies `%y ~ $t.field`
|
|
70
|
+
2. new edges, `E'`
|
|
71
|
+
- `%x .field %y` implies `%x -[field]-> %y`
|
|
72
|
+
- `{..., ... %x field, ...} %y` implies `%y -[field]-> %x`
|
|
73
|
+
3. pattern refinements, `R`
|
|
74
|
+
- `{... field} %x` implies `%x: <*>`
|
|
75
|
+
- `{... field, ...} %y` implies `%y: {}`
|
|
76
|
+
|
|
77
|
+
In our example:
|
|
78
|
+
|
|
79
|
+
`eq: {0,1,nat,2,3,4,11,12,13,14,15,16,17,18,19,20,21}, {5}, {6,7,8}, {9}, {10}`
|
|
80
|
+
|
|
81
|
+
`E': (4 -[0]-> 5), (5 -[_]-> 6), (10 -[_]-> 9), (11 -[0]-> 10), (14 -[0]-> 15)`
|
|
82
|
+
|
|
83
|
+
`R: 9:{}, 10:<*>`
|
|
84
|
+
|
|
85
|
+
By folding the pattern graph with those information we get:
|
|
86
|
+
|
|
87
|
+
%n ( %n $nat %n < %n ( %n .0 %n ._ %{} { %{} { %{} {} %{} _} %n 0} %n ) %n, %n ( %n .0 %n rlz %n ) %n , %n () %n > %n ) %n
|
|
88
|
+
|
|
89
|
+
### Another example
|
|
90
|
+
|
|
91
|
+
dec = [(),-1] PLUS;
|
|
92
|
+
zero? = [(),0] EQ 0;
|
|
93
|
+
factorial = < zero? 1, [dec factorial, ()] TIMES >;
|
|
94
|
+
{ () x, factorial "x!" }
|
|
95
|
+
|
|
96
|
+
name | rel*
|
|
97
|
+
-------|-----------------
|
|
98
|
+
PLUS | %1 $[int] %2 PLUS %3 $int %4
|
|
99
|
+
-1 | %5 {} %6 -1 %7 $int %8
|
|
100
|
+
EQ | %9 $[int] %10
|
|
101
|
+
dec | %11 [ %12 () %13, %14 -1 %15 ] %16 PLUS %17
|
|
102
|
+
zero? | %18 [ %19 () %20, %21 0 %22 ] %23 EQ %24 .0 %25
|
|
103
|
+
|
|
104
|
+
----
|
|
105
|
+
Other observations:
|
|
106
|
+
|
|
107
|
+
Product like {.x ..., .y ...} implies the input is a product (not really valid)
|
|
108
|
+
Pattern `p = <{ p x, ... }>` implies, it is a union!, i.e., `p = < p x, ... >`, e.g, in `< .x, () >`.
|
|
109
|
+
|
|
110
|
+
## To do
|
|
111
|
+
|
|
112
|
+
0. rewrite the algo to be layered:
|
|
113
|
+
1. pure algebraic (no vectors)
|
|
114
|
+
2. with support for homogenous vectors
|
|
115
|
+
3. native support for bytes, integers (`int64` only), booleans, and strings (`UTF8` only)
|
|
116
|
+
1. incremental pattern graph construction
|
|
117
|
+
2. folding pattern graph nodes corresponding to a code (e.g., parts of
|
|
118
|
+
the pattern graph whose nodes are all closed), adding codes into code graph and,
|
|
119
|
+
finally, re-minimizing it.
|
|
120
|
+
3. support for 'built-in' types via plugins.
|
|
121
|
+
4. do not simplify merge for code derivation sake.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
function resolveCode(rel, inCode, outCode) {
|
|
2
|
+
const annotatedRel = {inCode, outCode, rel};
|
|
3
|
+
return annotatedRel;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// pat: { kind: [null, 'product', 'union'],
|
|
7
|
+
// closed: [true, false],
|
|
8
|
+
// fields: [{f: string, pat: pat}, ...]}
|
|
9
|
+
const emptyPat = { kind: 'union', closed: true, fields: [] };
|
|
10
|
+
const starPat = { kind: null, closed: false, fields: [] };
|
|
11
|
+
function isEmptyPat(pat) {
|
|
12
|
+
const {kind, closed, fields} = pat;
|
|
13
|
+
return kind === 'union' && closed && fields.length === 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function cap(pat1, pat2) {
|
|
17
|
+
if (pat1 === pat2) return pat1;
|
|
18
|
+
const {kind:kind1, closed:closed1, fields:fields1} = pat1;
|
|
19
|
+
const {kind:kind2, closed:closed2, fields:fields2} = pat2;
|
|
20
|
+
let kind, fields;
|
|
21
|
+
if (kind1 === null) {
|
|
22
|
+
kind = kind2;
|
|
23
|
+
} else if (kind2 === null) {
|
|
24
|
+
kind = kind1;
|
|
25
|
+
} else if (kind1 === kind2) {
|
|
26
|
+
kind = kind1;
|
|
27
|
+
} else
|
|
28
|
+
return emptyPat;
|
|
29
|
+
|
|
30
|
+
const map1 = new Map(fields1.map(({f, pat}) => [f, pat]));
|
|
31
|
+
const map2 = new Map(fields2.map(({f, pat}) => [f, pat]));
|
|
32
|
+
const fieldNames = new Set([...map1.keys(), ...map2.keys()]);
|
|
33
|
+
fields = [...fieldNames].map(f => {
|
|
34
|
+
const pat1 = map1.get(f) || starPat;
|
|
35
|
+
const pat2 = map2.get(f) || starPat;
|
|
36
|
+
const pat = cap(pat1, pat2);
|
|
37
|
+
return {f, pat};
|
|
38
|
+
});
|
|
39
|
+
if (fields.some(({pat}) => isEmptyPat(pat))) {
|
|
40
|
+
return emptyPat;
|
|
41
|
+
}
|
|
42
|
+
if ((closed1 && fields1.length !== fields.length) || (closed2 && fields2.length !== fields.length)) {
|
|
43
|
+
return emptyPat;
|
|
44
|
+
}
|
|
45
|
+
return {kind, closed: closed1 || closed2, fields};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
export default { cap, starPat, emptyPat, isEmptyPat, resolveCode };
|
|
50
|
+
export { cap, starPat, emptyPat, isEmptyPat, resolveCode };
|
|
51
|
+
|
package/codes.mjs
CHANGED
|
@@ -1,3 +1,56 @@
|
|
|
1
|
+
function isBuiltIn(code) {
|
|
2
|
+
return code.match(/^(int|string|bool)$/);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function logCeiling(n, base = 2) {
|
|
6
|
+
return Math.ceil(Math.log(n) / Math.log(base));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function encodeCodeToString(code, codes) {
|
|
10
|
+
if (isBuiltIn(code)) return code;
|
|
11
|
+
var i = 0;
|
|
12
|
+
const Q = [[code,i]];
|
|
13
|
+
const D = {[code]: i++};
|
|
14
|
+
var result=[];
|
|
15
|
+
while (Q.length > 0) {
|
|
16
|
+
const [x,c] = Q.shift();
|
|
17
|
+
const c_code = codes[x];
|
|
18
|
+
if (c_code.code == "vector") {
|
|
19
|
+
const u_arg = c_code.vector;
|
|
20
|
+
if (isBuiltIn(u_arg)) {
|
|
21
|
+
result.push(`$C${result.length}=[${u_arg}];`);
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (D[u_arg] === undefined) {
|
|
25
|
+
Q.push([u_arg,i]);
|
|
26
|
+
D[u_arg] = i++;
|
|
27
|
+
}
|
|
28
|
+
result.push(`$C${result.length}=[C${D[u_arg]}];`);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const u_args = Object.keys(c_code[c_code.code]).sort().map((k) => {
|
|
32
|
+
const u_arg = c_code[c_code.code][k];
|
|
33
|
+
if (isBuiltIn(u_arg))
|
|
34
|
+
return `${u_arg}${JSON.stringify(k)}`;
|
|
35
|
+
if (D[u_arg] === undefined) {
|
|
36
|
+
Q.push([u_arg,i]);
|
|
37
|
+
D[u_arg] = i++;
|
|
38
|
+
}
|
|
39
|
+
return `C${D[u_arg]}${JSON.stringify(k)}`;
|
|
40
|
+
});
|
|
41
|
+
if (c_code.code == "union") {
|
|
42
|
+
//result += `$${c}=<${u_args.join(",")}>;`;
|
|
43
|
+
result.push(`$C${result.length}=<${u_args.join(",")}>;`);
|
|
44
|
+
} else if (c_code.code == "product") {
|
|
45
|
+
//result += `$${c}={${u_args.join(",")}};`;
|
|
46
|
+
result.push(`$C${result.length}={${u_args.join(",")}};`);
|
|
47
|
+
} else {
|
|
48
|
+
throw new Error(`Unexpected code ${c_code.code}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return result.join("");
|
|
52
|
+
};
|
|
53
|
+
|
|
1
54
|
function are_different(classes, representatives, name1, name2, codes) {
|
|
2
55
|
if (name1 === name2) return false;
|
|
3
56
|
const code1 = codes[name1];
|
|
@@ -63,6 +116,7 @@ function minimize(codes) {
|
|
|
63
116
|
}
|
|
64
117
|
}
|
|
65
118
|
}
|
|
119
|
+
|
|
66
120
|
return { classes, representatives };
|
|
67
121
|
}
|
|
68
122
|
|
|
@@ -81,7 +135,7 @@ function normalizeAll(codes, representatives) {
|
|
|
81
135
|
switch (code.code) {
|
|
82
136
|
case "union":
|
|
83
137
|
case "product":
|
|
84
|
-
normalized[name] = { code
|
|
138
|
+
normalized[name] = { ...code };
|
|
85
139
|
normalized[name][code.code] = normalize(
|
|
86
140
|
code[code.code],
|
|
87
141
|
representatives
|
|
@@ -89,7 +143,7 @@ function normalizeAll(codes, representatives) {
|
|
|
89
143
|
break;
|
|
90
144
|
case "vector":
|
|
91
145
|
normalized[name] = {
|
|
92
|
-
code
|
|
146
|
+
...code,
|
|
93
147
|
vector: representatives[code.vector] || code.vector,
|
|
94
148
|
};
|
|
95
149
|
}
|
|
@@ -99,5 +153,6 @@ function normalizeAll(codes, representatives) {
|
|
|
99
153
|
}, {});
|
|
100
154
|
}
|
|
101
155
|
|
|
102
|
-
|
|
103
|
-
export { minimize, normalize, normalizeAll };
|
|
156
|
+
|
|
157
|
+
export default { minimize, normalize, normalizeAll, encodeCodeToString };
|
|
158
|
+
export { minimize, normalize, normalizeAll, encodeCodeToString };
|
package/filters.mjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// filter is of type: [name|code|null|union|product|vector],
|
|
2
|
+
// null|union|product have fields, and can be open
|
|
3
|
+
|
|
4
|
+
function unify_with_code(codes, code, filter, context){
|
|
5
|
+
// console.log({code, filter, context});
|
|
6
|
+
if (context == undefined) return undefined;
|
|
7
|
+
if (code == undefined) return undefined;
|
|
8
|
+
switch (filter.type) {
|
|
9
|
+
case "code": {
|
|
10
|
+
if (filter.code == code)
|
|
11
|
+
return context;
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
case "name": {
|
|
15
|
+
const code_filter = {type: 'code', code: code};
|
|
16
|
+
if (filter.name in context) {
|
|
17
|
+
const new_filter = context[filter.name];
|
|
18
|
+
const new_context = {... context, [filter.name]: code_filter};
|
|
19
|
+
return unify_with_code(codes, code, new_filter, new_context);
|
|
20
|
+
}
|
|
21
|
+
return {...context, [filter.name]: {type: 'code', code: code}}
|
|
22
|
+
}
|
|
23
|
+
case "product":
|
|
24
|
+
case "union":
|
|
25
|
+
case null: {
|
|
26
|
+
const ctype = codes[code]?.code;
|
|
27
|
+
if (ctype != 'product' && ctype != 'union') return undefined;
|
|
28
|
+
const code_fields = codes[code][ctype];
|
|
29
|
+
const new_context = Object.keys(filter.fields).reduce((new_context, field) =>
|
|
30
|
+
unify_with_code(codes, code_fields[field], filter.fields[field], new_context)
|
|
31
|
+
, {...context});
|
|
32
|
+
if (filter.open !== true && Object.keys(code_fields).length != Object.keys(filter.fields).length)
|
|
33
|
+
return undefined;
|
|
34
|
+
return new_context;
|
|
35
|
+
}
|
|
36
|
+
case "vector": {
|
|
37
|
+
const ctype = codes[code]?.code;
|
|
38
|
+
if (ctype != 'vector') return undefined;
|
|
39
|
+
const code_vector = codes[code].vector;
|
|
40
|
+
return unify_with_code(codes, code_vector, filter.vector, context);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// we assume the names occurring in both filters are disjoint
|
|
46
|
+
function unify(codes, filter1, filter2, context ) {
|
|
47
|
+
if (context == undefined) return undefined;
|
|
48
|
+
if (filter1 == undefined || filter2 == undefined) return undefined;
|
|
49
|
+
|
|
50
|
+
switch (filter1.type) {
|
|
51
|
+
case "code":
|
|
52
|
+
return unify_with_code(codes, filter1.code, filter2, context);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default { unify_with_code };
|
|
57
|
+
export { unify_with_code };
|
|
58
|
+
|
|
59
|
+
|
package/hash.mjs
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const baseToShifted = {
|
|
2
|
+
'0': 'A', '1': 'B', '2': 'C', '3': 'D',
|
|
3
|
+
'4': 'E', '5': 'F', '6': 'G', '7': 'H',
|
|
4
|
+
'8': 'I', '9': 'J', 'a': 'K', 'b': 'L',
|
|
5
|
+
'c': 'M', 'd': 'N', 'e': 'O', 'f': 'P',
|
|
6
|
+
'g': 'Q', 'h': 'R', 'i': 'S', 'j': 'T',
|
|
7
|
+
'k': 'U', 'l': 'V', 'm': 'W', 'n': 'X',
|
|
8
|
+
'o': 'Y', 'p': 'Z', 'q': 'q', 'r': 'r',
|
|
9
|
+
's': 's', 't': 't', 'u': 'u', 'v': 'v',
|
|
10
|
+
'w': 'w', 'x': 'x', 'y': 'y', 'z': 'z'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const base = Object.keys(baseToShifted).length;
|
|
14
|
+
|
|
15
|
+
function shifString(baseString) {
|
|
16
|
+
let shiftedString = '';
|
|
17
|
+
for (let i = 0; i < baseString.length; i++) {
|
|
18
|
+
shiftedString += baseToShifted[baseString[i]];
|
|
19
|
+
}
|
|
20
|
+
return shiftedString;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function hash(inputString) {
|
|
24
|
+
if (inputString.match(/^\$C0=.*;$/))
|
|
25
|
+
inputString = inputString.slice(4,-1);
|
|
26
|
+
let hashValue = 0;
|
|
27
|
+
const prime = 31;
|
|
28
|
+
const mod = 1000000000039;
|
|
29
|
+
|
|
30
|
+
for (let i = 0; i < inputString.length; i++) {
|
|
31
|
+
let charCode = inputString.charCodeAt(i);
|
|
32
|
+
hashValue = (hashValue * prime + charCode) % mod;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return shifString(hashValue.toString(base));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default hash;
|
|
39
|
+
export { hash };
|
package/index.mjs
CHANGED
|
@@ -1,24 +1,54 @@
|
|
|
1
1
|
import { parse } from "./parser.mjs";
|
|
2
|
+
import { patterns } from "./patterns.mjs";
|
|
2
3
|
import run from "./run.mjs";
|
|
3
4
|
import t from "./codes.mjs";
|
|
5
|
+
import hash from "./hash.mjs";
|
|
4
6
|
|
|
5
7
|
function finalize(codes) {
|
|
6
8
|
const representatives = t.minimize(codes).representatives;
|
|
9
|
+
const normalizedCodes = t.normalizeAll(codes, representatives);
|
|
10
|
+
const globalNames = Object.keys(normalizedCodes).reduce((globalNames, name) => {
|
|
11
|
+
const globalDef = t.encodeCodeToString(name, normalizedCodes);
|
|
12
|
+
normalizedCodes[name].def = globalDef;
|
|
13
|
+
globalNames[name] = hash(globalDef);
|
|
14
|
+
return globalNames;
|
|
15
|
+
}, {});
|
|
16
|
+
const globalCodes = Object.keys(normalizedCodes).reduce((globalCodes, name) => {
|
|
17
|
+
globalCodes[globalNames[name]] = normalizedCodes[name];
|
|
18
|
+
return globalCodes;
|
|
19
|
+
},{});
|
|
20
|
+
// console.log("globalCodes",globalCodes);
|
|
21
|
+
|
|
22
|
+
const extendedRepresentatives = Object.keys(representatives).reduce((result, name) => {
|
|
23
|
+
result[name] = globalNames[representatives[name]] || name;
|
|
24
|
+
return result;
|
|
25
|
+
}, Object.values(globalNames).reduce((result, name) => ({[name]: name, ...result}),{}));
|
|
26
|
+
// console.log("extendedRepresentatives",extendedRepresentatives);
|
|
27
|
+
|
|
28
|
+
const normalizedGlobalCodes = t.normalizeAll(globalCodes, extendedRepresentatives);
|
|
29
|
+
// console.log("normalizedGlobalCodes",normalizedGlobalCodes);
|
|
30
|
+
|
|
31
|
+
|
|
7
32
|
return {
|
|
8
|
-
codes:
|
|
9
|
-
representatives
|
|
33
|
+
codes: normalizedGlobalCodes,
|
|
34
|
+
representatives: extendedRepresentatives
|
|
10
35
|
};
|
|
11
36
|
}
|
|
12
37
|
|
|
13
38
|
function compile(script) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
39
|
+
try {
|
|
40
|
+
run.defs = annotate(script);
|
|
41
|
+
} catch (e) {
|
|
42
|
+
console.error(e);
|
|
43
|
+
const { defs, exp } = parse(script);
|
|
44
|
+
const { codes, representatives } = finalize(defs.codes);
|
|
45
|
+
run.defs = {
|
|
46
|
+
rels: {...defs.rels, "__main__": [exp]},
|
|
47
|
+
codes, representatives
|
|
48
|
+
};
|
|
49
|
+
console.error("WARN: Recompiled without type reconciliation due to the type error above.");
|
|
50
|
+
}
|
|
51
|
+
return run.bind(null, run.defs.rels.__main__[0]);
|
|
22
52
|
}
|
|
23
53
|
|
|
24
54
|
compile.doc = "Transforms k-script (string) into a function";
|
|
@@ -28,5 +58,18 @@ function runScriptOnData(script, data) {
|
|
|
28
58
|
}
|
|
29
59
|
runScriptOnData.doc = "Run 'script' (string) on 'data': (script,data) -> data";
|
|
30
60
|
|
|
31
|
-
|
|
32
|
-
|
|
61
|
+
|
|
62
|
+
function annotate(script) {
|
|
63
|
+
const { defs, exp } = parse(script);
|
|
64
|
+
const { codes, representatives } = finalize(defs.codes);
|
|
65
|
+
|
|
66
|
+
const rels = {...defs.rels, "__main__": [exp]};
|
|
67
|
+
|
|
68
|
+
const pats = patterns(codes, representatives, rels);
|
|
69
|
+
|
|
70
|
+
return {rels,codes,representatives, ...pats}
|
|
71
|
+
}
|
|
72
|
+
annotate.doc = "Annotate all the script expressions with patterns";
|
|
73
|
+
|
|
74
|
+
export default { compile, run: runScriptOnData, parse, annotate };
|
|
75
|
+
export { compile, runScriptOnData as run, parse, annotate };
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fraczak/k",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "k-language for JSON-like data transformation",
|
|
5
5
|
"main": "index.mjs",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"prepare": "jiwson -m es6 parser.jison -o parser.mjs",
|
|
8
|
-
"test": "node test.mjs"
|
|
8
|
+
"test": "node test.mjs; for f in Code-derivation-tests/*.mjs; do echo $f; node $f; done; node test-fingerprint.mjs"
|
|
9
9
|
},
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|