yumaikas a révisé ce gist . Aller à la révision
1 file changed, 42 insertions
query_compiler.js
@@ -1,3 +1,45 @@ | |||
1 | + | export class EnsureMap extends Map { | |
2 | + | ensureGet(key, value) { | |
3 | + | if (this.has(key)) { | |
4 | + | return this.get(key); | |
5 | + | } | |
6 | + | this.set(key, value); | |
7 | + | return value; | |
8 | + | } | |
9 | + | ||
10 | + | } | |
11 | + | ||
12 | + | export function PredicateMap() { | |
13 | + | let patIdx = 0; | |
14 | + | let predicateStore = new Map(); | |
15 | + | let idxStore = new Map(); | |
16 | + | return { | |
17 | + | entries() { | |
18 | + | return predicateStore.entries(); | |
19 | + | }, | |
20 | + | lookup(pattern) { | |
21 | + | return predicateStore.get(pattern); | |
22 | + | }, | |
23 | + | indexOf(pattern) { | |
24 | + | return idxStore.get(pattern); | |
25 | + | }, | |
26 | + | store(pattern, predicate) { | |
27 | + | if (!predicateStore.has(pattern)) { | |
28 | + | predicateStore.set(pattern, predicate); | |
29 | + | idxStore.set(pattern, patIdx); | |
30 | + | patIdx++; | |
31 | + | } | |
32 | + | }, | |
33 | + | } | |
34 | + | } | |
35 | + | ||
36 | + | function generalizePattern(pattern) { | |
37 | + | let vars = []; | |
38 | + | let patt = pattern.map(x => /^\$/.test(x) ? (vars.push(x.slice(1)),'*') : x).join(" "); | |
39 | + | vars = vars.map(x => /\?$/.test(x) ? x.slice(0,-1) : x); | |
40 | + | return {vars:vars, patt:patt}; | |
41 | + | } | |
42 | + | ||
1 | 43 | function compileRule(ruleTokens, predicates) { | |
2 | 44 | // TODO: compile condiitions into predicates (if they don't match an existing predicate) | |
3 | 45 | // and check predicates for non-standard cost models |
yumaikas a révisé ce gist . Aller à la révision
1 file changed, 102 insertions
query_compiler.js(fichier créé)
@@ -0,0 +1,102 @@ | |||
1 | + | function compileRule(ruleTokens, predicates) { | |
2 | + | // TODO: compile condiitions into predicates (if they don't match an existing predicate) | |
3 | + | // and check predicates for non-standard cost models | |
4 | + | // (port with custom costs, constant counters, etc) | |
5 | + | let rule = { | |
6 | + | predicateIds: [], | |
7 | + | predicates: [], | |
8 | + | queryPlan: null, | |
9 | + | predicateNames: new Map(), | |
10 | + | consequenceFn: null, | |
11 | + | usedVars: new Set(), | |
12 | + | }; | |
13 | + | ||
14 | + | for (let c of ruleTokens.condition) { | |
15 | + | let { patt: predKey, vars: pattVars } = generalizePattern(c); | |
16 | + | pattVars.forEach((pv) => rule.usedVars.add(pv)); | |
17 | + | ||
18 | + | ||
19 | + | if (predicates.lookup(predKey)) { | |
20 | + | // rule.predicateNames.set(predKey, n); | |
21 | + | rule.predicateIds.push(predicates.indexOf(predKey)); | |
22 | + | } else { | |
23 | + | console.log("NEW"); | |
24 | + | let { name: n, code: predFn } = makeBasicPatternPredicate(c); | |
25 | + | rule.predicateNames.set(predKey, n); | |
26 | + | predicates.store(predKey, { code: predFn, vars: pattVars }); | |
27 | + | rule.predicateIds.push(predicates.indexOf(predKey)); | |
28 | + | } | |
29 | + | rule.predicates.push({ | |
30 | + | idx: predicates.indexOf(predKey), | |
31 | + | name: rule.predicateNames.get(predKey), | |
32 | + | pred: predicates.lookup(predKey), | |
33 | + | varsForPred: pattVars, | |
34 | + | }) | |
35 | + | } | |
36 | + | console.log(["XXX", rule.predicateNames]); | |
37 | + | ||
38 | + | let hyperEdges = new EnsureMap(); | |
39 | + | ||
40 | + | for (let predicate of rule.predicates) { | |
41 | + | for (let v of predicate.varsForPred) { | |
42 | + | hyperEdges.ensureGet(v, new Set()).add(predicate); | |
43 | + | } | |
44 | + | } | |
45 | + | ||
46 | + | // console.log(hyperEdges); | |
47 | + | ||
48 | + | let matchObjParts = ["let match = {\n"]; | |
49 | + | let plan_fns = []; | |
50 | + | for (let predicate of rule.predicates) { | |
51 | + | matchObjParts.push(predicate.name, ": false,\n"); | |
52 | + | ||
53 | + | let plan_fn_parts= ["plans.", slug(predicate.name) ," = function ", "(match, patterns) {\n"]; | |
54 | + | ||
55 | + | plan_fn_parts.push("\tfor(let ");; | |
56 | + | if (predicate.varsForPred.length > 0) { | |
57 | + | plan_fn_parts.push("["); | |
58 | + | for (let v of predicate.varsForPred) { | |
59 | + | plan_fn_parts.push(slug(v), ", "); | |
60 | + | } | |
61 | + | plan_fn_parts.pop(); | |
62 | + | plan_fn_parts.push("] "); | |
63 | + | } else { | |
64 | + | plan_fn_parts.push("_ "); | |
65 | + | } | |
66 | + | plan_fn_parts.push("of patterns.", slug(predicate.name), ") {\n"); | |
67 | + | plan_fn_parts.push("\t\tmatch.state.", slug(predicate.name), " = true;\n"); | |
68 | + | ||
69 | + | for (let v of predicate.varsForPred) { | |
70 | + | plan_fn_parts.push("\t\tmatch.vars.", slug(v), " = ", slug(v), ";\n"); | |
71 | + | } | |
72 | + | ||
73 | + | let seenPredicates = new Set(); | |
74 | + | plan_fn_parts.push("\t\tif (\n"); | |
75 | + | let shouldPop = false; | |
76 | + | for (let v of predicate.varsForPred) { | |
77 | + | for (let otherPred of hyperEdges.get(v)) { | |
78 | + | // console.log({ a: otherPred.idx, b: predicate.idx }); | |
79 | + | if (otherPred.idx !== predicate.idx && !seenPredicates.has(otherPred.idx)) { | |
80 | + | shouldPop = true; | |
81 | + | seenPredicates.add(otherPred.idx); | |
82 | + | // TODO thing | |
83 | + | plan_fn_parts.push( | |
84 | + | "\t\t\tmatch.state.", slug(otherPred.name), | |
85 | + | " || plans.", slug(otherPred.name), "(match, patterns)", " && \n" ); | |
86 | + | } | |
87 | + | } | |
88 | + | // console.log("---"); | |
89 | + | } | |
90 | + | if (shouldPop) { | |
91 | + | plan_fn_parts.pop(); | |
92 | + | plan_fn_parts.push("\n"); | |
93 | + | } | |
94 | + | plan_fn_parts.push("\n\t\t) {\n\t\t\t return true; \n\t\t} else { return false; }\n"); | |
95 | + | plan_fn_parts.push("\t}\n}\n\n\n"); | |
96 | + | ||
97 | + | plan_fns.push(plan_fn_parts.join("")); | |
98 | + | } | |
99 | + | rule.queryPlan = plan_fns; | |
100 | + | ||
101 | + | return rule; | |
102 | + | } |
yumaikas a révisé ce gist . Aller à la révision
1 file changed, 10 insertions, 8 deletions
compiled_query.js
@@ -17,7 +17,7 @@ plans._lightning_struck_x_y = function (match, patterns) { | |||
17 | 17 | match.vars._x = _x; | |
18 | 18 | match.vars._y = _y; | |
19 | 19 | if ( | |
20 | - | match.state._something_is_at_x_y || plans._something_is_at_x_y(match, patterns) && | |
20 | + | match.state._something_is_at_x_y || plans._something_is_at_x_y(match, patterns) | |
21 | 21 | ||
22 | 22 | ) { | |
23 | 23 | return true; | |
@@ -35,8 +35,9 @@ plans._something_is_at_x_y = function (match, patterns) { | |||
35 | 35 | match.vars._x = _x; | |
36 | 36 | match.vars._y = _y; | |
37 | 37 | if ( | |
38 | - | match.state._something_has_inventory_inventory || plans._something_has_inventory_inventory(match, patterns) && | |
39 | - | match.state._lightning_struck_x_y || plans._lightning_struck_x_y(match, patterns) && | |
38 | + | match.state._something_has_inventory_inventory || plans._something_has_inventory_inventory(match, p | |
39 | + | atterns) && | |
40 | + | match.state._lightning_struck_x_y || plans._lightning_struck_x_y(match, patterns) | |
40 | 41 | ||
41 | 42 | ) { | |
42 | 43 | return true; | |
@@ -54,7 +55,7 @@ plans._something_has_inventory_inventory = function (match, patterns) { | |||
54 | 55 | match.vars._inventory = _inventory; | |
55 | 56 | if ( | |
56 | 57 | match.state._something_is_at_x_y || plans._something_is_at_x_y(match, patterns) && | |
57 | - | match.state._inventory_has_item_item || plans._inventory_has_item_item(match, patterns) && | |
58 | + | match.state._inventory_has_item_item || plans._inventory_has_item_item(match, patterns) | |
58 | 59 | ||
59 | 60 | ) { | |
60 | 61 | return true; | |
@@ -71,8 +72,9 @@ plans._inventory_has_item_item = function (match, patterns) { | |||
71 | 72 | match.vars._inventory = _inventory; | |
72 | 73 | match.vars._item = _item; | |
73 | 74 | if ( | |
74 | - | match.state._something_has_inventory_inventory || plans._something_has_inventory_inventory(match, patterns) && | |
75 | - | match.state._item_is_class || plans._item_is_class(match, patterns) && | |
75 | + | match.state._something_has_inventory_inventory || plans._something_has_inventory_inventory(match, p | |
76 | + | atterns) && | |
77 | + | match.state._item_is_class || plans._item_is_class(match, patterns) | |
76 | 78 | ||
77 | 79 | ) { | |
78 | 80 | return true; | |
@@ -90,7 +92,7 @@ plans._item_is_class = function (match, patterns) { | |||
90 | 92 | match.vars._class = _class; | |
91 | 93 | if ( | |
92 | 94 | match.state._inventory_has_item_item || plans._inventory_has_item_item(match, patterns) && | |
93 | - | match.state._class_is_conductive || plans._class_is_conductive(match, patterns) && | |
95 | + | match.state._class_is_conductive || plans._class_is_conductive(match, patterns) | |
94 | 96 | ||
95 | 97 | ) { | |
96 | 98 | return true; | |
@@ -106,7 +108,7 @@ plans._class_is_conductive = function (match, patterns) { | |||
106 | 108 | match.state._class_is_conductive = true; | |
107 | 109 | match.vars._class = _class; | |
108 | 110 | if ( | |
109 | - | match.state._item_is_class || plans._item_is_class(match, patterns) && | |
111 | + | match.state._item_is_class || plans._item_is_class(match, patterns) | |
110 | 112 | ||
111 | 113 | ) { | |
112 | 114 | return true; |
yumaikas a révisé ce gist . Aller à la révision
1 file changed, 7 insertions
compiled_query.js
@@ -22,6 +22,7 @@ plans._lightning_struck_x_y = function (match, patterns) { | |||
22 | 22 | ) { | |
23 | 23 | return true; | |
24 | 24 | } else { return false; } | |
25 | + | } | |
25 | 26 | } | |
26 | 27 | ||
27 | 28 | ||
@@ -40,6 +41,7 @@ plans._something_is_at_x_y = function (match, patterns) { | |||
40 | 41 | ) { | |
41 | 42 | return true; | |
42 | 43 | } else { return false; } | |
44 | + | } | |
43 | 45 | } | |
44 | 46 | ||
45 | 47 | ||
@@ -57,6 +59,7 @@ plans._something_has_inventory_inventory = function (match, patterns) { | |||
57 | 59 | ) { | |
58 | 60 | return true; | |
59 | 61 | } else { return false; } | |
62 | + | } | |
60 | 63 | } | |
61 | 64 | ||
62 | 65 | ||
@@ -74,6 +77,7 @@ plans._inventory_has_item_item = function (match, patterns) { | |||
74 | 77 | ) { | |
75 | 78 | return true; | |
76 | 79 | } else { return false; } | |
80 | + | } | |
77 | 81 | } | |
78 | 82 | ||
79 | 83 | ||
@@ -91,6 +95,7 @@ plans._item_is_class = function (match, patterns) { | |||
91 | 95 | ) { | |
92 | 96 | return true; | |
93 | 97 | } else { return false; } | |
98 | + | } | |
94 | 99 | } | |
95 | 100 | ||
96 | 101 | ||
@@ -106,4 +111,6 @@ plans._class_is_conductive = function (match, patterns) { | |||
106 | 111 | ) { | |
107 | 112 | return true; | |
108 | 113 | } else { return false; } | |
114 | + | } | |
109 | 115 | } | |
116 | + |
yumaikas a révisé ce gist . Aller à la révision
1 file changed, 109 insertions
compiled_query.js(fichier créé)
@@ -0,0 +1,109 @@ | |||
1 | + | /* | |
2 | + | | | |
3 | + | lightning struck $x $y | |
4 | + | , $something is at $x $y? | |
5 | + | , $something has inventory $inventory? | |
6 | + | , $inventory has item $item? | |
7 | + | , $item is $class? | |
8 | + | , $class is conductive? | |
9 | + | | | |
10 | + | $something is struck by lightning | |
11 | + | ||
12 | + | */ | |
13 | + | ||
14 | + | plans._lightning_struck_x_y = function (match, patterns) { | |
15 | + | for(let [_x, _y] of patterns._lightning_struck_x_y) { | |
16 | + | match.state._lightning_struck_x_y = true; | |
17 | + | match.vars._x = _x; | |
18 | + | match.vars._y = _y; | |
19 | + | if ( | |
20 | + | match.state._something_is_at_x_y || plans._something_is_at_x_y(match, patterns) && | |
21 | + | ||
22 | + | ) { | |
23 | + | return true; | |
24 | + | } else { return false; } | |
25 | + | } | |
26 | + | ||
27 | + | ||
28 | + | ||
29 | + | ||
30 | + | plans._something_is_at_x_y = function (match, patterns) { | |
31 | + | for(let [_something, _x, _y] of patterns._something_is_at_x_y) { | |
32 | + | match.state._something_is_at_x_y = true; | |
33 | + | match.vars._something = _something; | |
34 | + | match.vars._x = _x; | |
35 | + | match.vars._y = _y; | |
36 | + | if ( | |
37 | + | match.state._something_has_inventory_inventory || plans._something_has_inventory_inventory(match, patterns) && | |
38 | + | match.state._lightning_struck_x_y || plans._lightning_struck_x_y(match, patterns) && | |
39 | + | ||
40 | + | ) { | |
41 | + | return true; | |
42 | + | } else { return false; } | |
43 | + | } | |
44 | + | ||
45 | + | ||
46 | + | ||
47 | + | ||
48 | + | plans._something_has_inventory_inventory = function (match, patterns) { | |
49 | + | for(let [_something, _inventory] of patterns._something_has_inventory_inventory) { | |
50 | + | match.state._something_has_inventory_inventory = true; | |
51 | + | match.vars._something = _something; | |
52 | + | match.vars._inventory = _inventory; | |
53 | + | if ( | |
54 | + | match.state._something_is_at_x_y || plans._something_is_at_x_y(match, patterns) && | |
55 | + | match.state._inventory_has_item_item || plans._inventory_has_item_item(match, patterns) && | |
56 | + | ||
57 | + | ) { | |
58 | + | return true; | |
59 | + | } else { return false; } | |
60 | + | } | |
61 | + | ||
62 | + | ||
63 | + | ||
64 | + | ||
65 | + | plans._inventory_has_item_item = function (match, patterns) { | |
66 | + | for(let [_inventory, _item] of patterns._inventory_has_item_item) { | |
67 | + | match.state._inventory_has_item_item = true; | |
68 | + | match.vars._inventory = _inventory; | |
69 | + | match.vars._item = _item; | |
70 | + | if ( | |
71 | + | match.state._something_has_inventory_inventory || plans._something_has_inventory_inventory(match, patterns) && | |
72 | + | match.state._item_is_class || plans._item_is_class(match, patterns) && | |
73 | + | ||
74 | + | ) { | |
75 | + | return true; | |
76 | + | } else { return false; } | |
77 | + | } | |
78 | + | ||
79 | + | ||
80 | + | ||
81 | + | ||
82 | + | plans._item_is_class = function (match, patterns) { | |
83 | + | for(let [_item, _class] of patterns._item_is_class) { | |
84 | + | match.state._item_is_class = true; | |
85 | + | match.vars._item = _item; | |
86 | + | match.vars._class = _class; | |
87 | + | if ( | |
88 | + | match.state._inventory_has_item_item || plans._inventory_has_item_item(match, patterns) && | |
89 | + | match.state._class_is_conductive || plans._class_is_conductive(match, patterns) && | |
90 | + | ||
91 | + | ) { | |
92 | + | return true; | |
93 | + | } else { return false; } | |
94 | + | } | |
95 | + | ||
96 | + | ||
97 | + | ||
98 | + | ||
99 | + | plans._class_is_conductive = function (match, patterns) { | |
100 | + | for(let [_class] of patterns._class_is_conductive) { | |
101 | + | match.state._class_is_conductive = true; | |
102 | + | match.vars._class = _class; | |
103 | + | if ( | |
104 | + | match.state._item_is_class || plans._item_is_class(match, patterns) && | |
105 | + | ||
106 | + | ) { | |
107 | + | return true; | |
108 | + | } else { return false; } | |
109 | + | } |