compiled_query.js
· 3.7 KiB · JavaScript
Исходник
Playground
/*
|
lightning struck $x $y
, $something is at $x $y?
, $something has inventory $inventory?
, $inventory has item $item?
, $item is $class?
, $class is conductive?
|
$something is struck by lightning
*/
plans._lightning_struck_x_y = function (match, patterns) {
for(let [_x, _y] of patterns._lightning_struck_x_y) {
match.state._lightning_struck_x_y = true;
match.vars._x = _x;
match.vars._y = _y;
if (
match.state._something_is_at_x_y || plans._something_is_at_x_y(match, patterns)
) {
return true;
} else { return false; }
}
}
plans._something_is_at_x_y = function (match, patterns) {
for(let [_something, _x, _y] of patterns._something_is_at_x_y) {
match.state._something_is_at_x_y = true;
match.vars._something = _something;
match.vars._x = _x;
match.vars._y = _y;
if (
match.state._something_has_inventory_inventory || plans._something_has_inventory_inventory(match, p
atterns) &&
match.state._lightning_struck_x_y || plans._lightning_struck_x_y(match, patterns)
) {
return true;
} else { return false; }
}
}
plans._something_has_inventory_inventory = function (match, patterns) {
for(let [_something, _inventory] of patterns._something_has_inventory_inventory) {
match.state._something_has_inventory_inventory = true;
match.vars._something = _something;
match.vars._inventory = _inventory;
if (
match.state._something_is_at_x_y || plans._something_is_at_x_y(match, patterns) &&
match.state._inventory_has_item_item || plans._inventory_has_item_item(match, patterns)
) {
return true;
} else { return false; }
}
}
plans._inventory_has_item_item = function (match, patterns) {
for(let [_inventory, _item] of patterns._inventory_has_item_item) {
match.state._inventory_has_item_item = true;
match.vars._inventory = _inventory;
match.vars._item = _item;
if (
match.state._something_has_inventory_inventory || plans._something_has_inventory_inventory(match, p
atterns) &&
match.state._item_is_class || plans._item_is_class(match, patterns)
) {
return true;
} else { return false; }
}
}
plans._item_is_class = function (match, patterns) {
for(let [_item, _class] of patterns._item_is_class) {
match.state._item_is_class = true;
match.vars._item = _item;
match.vars._class = _class;
if (
match.state._inventory_has_item_item || plans._inventory_has_item_item(match, patterns) &&
match.state._class_is_conductive || plans._class_is_conductive(match, patterns)
) {
return true;
} else { return false; }
}
}
plans._class_is_conductive = function (match, patterns) {
for(let [_class] of patterns._class_is_conductive) {
match.state._class_is_conductive = true;
match.vars._class = _class;
if (
match.state._item_is_class || plans._item_is_class(match, patterns)
) {
return true;
} else { return false; }
}
}
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 | |
31 | plans._something_is_at_x_y = function (match, patterns) { |
32 | for(let [_something, _x, _y] of patterns._something_is_at_x_y) { |
33 | match.state._something_is_at_x_y = true; |
34 | match.vars._something = _something; |
35 | match.vars._x = _x; |
36 | match.vars._y = _y; |
37 | if ( |
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) |
41 | |
42 | ) { |
43 | return true; |
44 | } else { return false; } |
45 | } |
46 | } |
47 | |
48 | |
49 | |
50 | |
51 | plans._something_has_inventory_inventory = function (match, patterns) { |
52 | for(let [_something, _inventory] of patterns._something_has_inventory_inventory) { |
53 | match.state._something_has_inventory_inventory = true; |
54 | match.vars._something = _something; |
55 | match.vars._inventory = _inventory; |
56 | if ( |
57 | match.state._something_is_at_x_y || plans._something_is_at_x_y(match, patterns) && |
58 | match.state._inventory_has_item_item || plans._inventory_has_item_item(match, patterns) |
59 | |
60 | ) { |
61 | return true; |
62 | } else { return false; } |
63 | } |
64 | } |
65 | |
66 | |
67 | |
68 | |
69 | plans._inventory_has_item_item = function (match, patterns) { |
70 | for(let [_inventory, _item] of patterns._inventory_has_item_item) { |
71 | match.state._inventory_has_item_item = true; |
72 | match.vars._inventory = _inventory; |
73 | match.vars._item = _item; |
74 | if ( |
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) |
78 | |
79 | ) { |
80 | return true; |
81 | } else { return false; } |
82 | } |
83 | } |
84 | |
85 | |
86 | |
87 | |
88 | plans._item_is_class = function (match, patterns) { |
89 | for(let [_item, _class] of patterns._item_is_class) { |
90 | match.state._item_is_class = true; |
91 | match.vars._item = _item; |
92 | match.vars._class = _class; |
93 | if ( |
94 | match.state._inventory_has_item_item || plans._inventory_has_item_item(match, patterns) && |
95 | match.state._class_is_conductive || plans._class_is_conductive(match, patterns) |
96 | |
97 | ) { |
98 | return true; |
99 | } else { return false; } |
100 | } |
101 | } |
102 | |
103 | |
104 | |
105 | |
106 | plans._class_is_conductive = function (match, patterns) { |
107 | for(let [_class] of patterns._class_is_conductive) { |
108 | match.state._class_is_conductive = true; |
109 | match.vars._class = _class; |
110 | if ( |
111 | match.state._item_is_class || plans._item_is_class(match, patterns) |
112 | |
113 | ) { |
114 | return true; |
115 | } else { return false; } |
116 | } |
117 | } |
118 | |
119 |
query_compiler.js
· 4.7 KiB · JavaScript
Исходник
Playground
export class EnsureMap extends Map {
ensureGet(key, value) {
if (this.has(key)) {
return this.get(key);
}
this.set(key, value);
return value;
}
}
export function PredicateMap() {
let patIdx = 0;
let predicateStore = new Map();
let idxStore = new Map();
return {
entries() {
return predicateStore.entries();
},
lookup(pattern) {
return predicateStore.get(pattern);
},
indexOf(pattern) {
return idxStore.get(pattern);
},
store(pattern, predicate) {
if (!predicateStore.has(pattern)) {
predicateStore.set(pattern, predicate);
idxStore.set(pattern, patIdx);
patIdx++;
}
},
}
}
function generalizePattern(pattern) {
let vars = [];
let patt = pattern.map(x => /^\$/.test(x) ? (vars.push(x.slice(1)),'*') : x).join(" ");
vars = vars.map(x => /\?$/.test(x) ? x.slice(0,-1) : x);
return {vars:vars, patt:patt};
}
function compileRule(ruleTokens, predicates) {
// TODO: compile condiitions into predicates (if they don't match an existing predicate)
// and check predicates for non-standard cost models
// (port with custom costs, constant counters, etc)
let rule = {
predicateIds: [],
predicates: [],
queryPlan: null,
predicateNames: new Map(),
consequenceFn: null,
usedVars: new Set(),
};
for (let c of ruleTokens.condition) {
let { patt: predKey, vars: pattVars } = generalizePattern(c);
pattVars.forEach((pv) => rule.usedVars.add(pv));
if (predicates.lookup(predKey)) {
// rule.predicateNames.set(predKey, n);
rule.predicateIds.push(predicates.indexOf(predKey));
} else {
console.log("NEW");
let { name: n, code: predFn } = makeBasicPatternPredicate(c);
rule.predicateNames.set(predKey, n);
predicates.store(predKey, { code: predFn, vars: pattVars });
rule.predicateIds.push(predicates.indexOf(predKey));
}
rule.predicates.push({
idx: predicates.indexOf(predKey),
name: rule.predicateNames.get(predKey),
pred: predicates.lookup(predKey),
varsForPred: pattVars,
})
}
console.log(["XXX", rule.predicateNames]);
let hyperEdges = new EnsureMap();
for (let predicate of rule.predicates) {
for (let v of predicate.varsForPred) {
hyperEdges.ensureGet(v, new Set()).add(predicate);
}
}
// console.log(hyperEdges);
let matchObjParts = ["let match = {\n"];
let plan_fns = [];
for (let predicate of rule.predicates) {
matchObjParts.push(predicate.name, ": false,\n");
let plan_fn_parts= ["plans.", slug(predicate.name) ," = function ", "(match, patterns) {\n"];
plan_fn_parts.push("\tfor(let ");;
if (predicate.varsForPred.length > 0) {
plan_fn_parts.push("[");
for (let v of predicate.varsForPred) {
plan_fn_parts.push(slug(v), ", ");
}
plan_fn_parts.pop();
plan_fn_parts.push("] ");
} else {
plan_fn_parts.push("_ ");
}
plan_fn_parts.push("of patterns.", slug(predicate.name), ") {\n");
plan_fn_parts.push("\t\tmatch.state.", slug(predicate.name), " = true;\n");
for (let v of predicate.varsForPred) {
plan_fn_parts.push("\t\tmatch.vars.", slug(v), " = ", slug(v), ";\n");
}
let seenPredicates = new Set();
plan_fn_parts.push("\t\tif (\n");
let shouldPop = false;
for (let v of predicate.varsForPred) {
for (let otherPred of hyperEdges.get(v)) {
// console.log({ a: otherPred.idx, b: predicate.idx });
if (otherPred.idx !== predicate.idx && !seenPredicates.has(otherPred.idx)) {
shouldPop = true;
seenPredicates.add(otherPred.idx);
// TODO thing
plan_fn_parts.push(
"\t\t\tmatch.state.", slug(otherPred.name),
" || plans.", slug(otherPred.name), "(match, patterns)", " && \n" );
}
}
// console.log("---");
}
if (shouldPop) {
plan_fn_parts.pop();
plan_fn_parts.push("\n");
}
plan_fn_parts.push("\n\t\t) {\n\t\t\t return true; \n\t\t} else { return false; }\n");
plan_fn_parts.push("\t}\n}\n\n\n");
plan_fns.push(plan_fn_parts.join(""));
}
rule.queryPlan = plan_fns;
return rule;
}
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 | |
43 | function compileRule(ruleTokens, predicates) { |
44 | // TODO: compile condiitions into predicates (if they don't match an existing predicate) |
45 | // and check predicates for non-standard cost models |
46 | // (port with custom costs, constant counters, etc) |
47 | let rule = { |
48 | predicateIds: [], |
49 | predicates: [], |
50 | queryPlan: null, |
51 | predicateNames: new Map(), |
52 | consequenceFn: null, |
53 | usedVars: new Set(), |
54 | }; |
55 | |
56 | for (let c of ruleTokens.condition) { |
57 | let { patt: predKey, vars: pattVars } = generalizePattern(c); |
58 | pattVars.forEach((pv) => rule.usedVars.add(pv)); |
59 | |
60 | |
61 | if (predicates.lookup(predKey)) { |
62 | // rule.predicateNames.set(predKey, n); |
63 | rule.predicateIds.push(predicates.indexOf(predKey)); |
64 | } else { |
65 | console.log("NEW"); |
66 | let { name: n, code: predFn } = makeBasicPatternPredicate(c); |
67 | rule.predicateNames.set(predKey, n); |
68 | predicates.store(predKey, { code: predFn, vars: pattVars }); |
69 | rule.predicateIds.push(predicates.indexOf(predKey)); |
70 | } |
71 | rule.predicates.push({ |
72 | idx: predicates.indexOf(predKey), |
73 | name: rule.predicateNames.get(predKey), |
74 | pred: predicates.lookup(predKey), |
75 | varsForPred: pattVars, |
76 | }) |
77 | } |
78 | console.log(["XXX", rule.predicateNames]); |
79 | |
80 | let hyperEdges = new EnsureMap(); |
81 | |
82 | for (let predicate of rule.predicates) { |
83 | for (let v of predicate.varsForPred) { |
84 | hyperEdges.ensureGet(v, new Set()).add(predicate); |
85 | } |
86 | } |
87 | |
88 | // console.log(hyperEdges); |
89 | |
90 | let matchObjParts = ["let match = {\n"]; |
91 | let plan_fns = []; |
92 | for (let predicate of rule.predicates) { |
93 | matchObjParts.push(predicate.name, ": false,\n"); |
94 | |
95 | let plan_fn_parts= ["plans.", slug(predicate.name) ," = function ", "(match, patterns) {\n"]; |
96 | |
97 | plan_fn_parts.push("\tfor(let ");; |
98 | if (predicate.varsForPred.length > 0) { |
99 | plan_fn_parts.push("["); |
100 | for (let v of predicate.varsForPred) { |
101 | plan_fn_parts.push(slug(v), ", "); |
102 | } |
103 | plan_fn_parts.pop(); |
104 | plan_fn_parts.push("] "); |
105 | } else { |
106 | plan_fn_parts.push("_ "); |
107 | } |
108 | plan_fn_parts.push("of patterns.", slug(predicate.name), ") {\n"); |
109 | plan_fn_parts.push("\t\tmatch.state.", slug(predicate.name), " = true;\n"); |
110 | |
111 | for (let v of predicate.varsForPred) { |
112 | plan_fn_parts.push("\t\tmatch.vars.", slug(v), " = ", slug(v), ";\n"); |
113 | } |
114 | |
115 | let seenPredicates = new Set(); |
116 | plan_fn_parts.push("\t\tif (\n"); |
117 | let shouldPop = false; |
118 | for (let v of predicate.varsForPred) { |
119 | for (let otherPred of hyperEdges.get(v)) { |
120 | // console.log({ a: otherPred.idx, b: predicate.idx }); |
121 | if (otherPred.idx !== predicate.idx && !seenPredicates.has(otherPred.idx)) { |
122 | shouldPop = true; |
123 | seenPredicates.add(otherPred.idx); |
124 | // TODO thing |
125 | plan_fn_parts.push( |
126 | "\t\t\tmatch.state.", slug(otherPred.name), |
127 | " || plans.", slug(otherPred.name), "(match, patterns)", " && \n" ); |
128 | } |
129 | } |
130 | // console.log("---"); |
131 | } |
132 | if (shouldPop) { |
133 | plan_fn_parts.pop(); |
134 | plan_fn_parts.push("\n"); |
135 | } |
136 | plan_fn_parts.push("\n\t\t) {\n\t\t\t return true; \n\t\t} else { return false; }\n"); |
137 | plan_fn_parts.push("\t}\n}\n\n\n"); |
138 | |
139 | plan_fns.push(plan_fn_parts.join("")); |
140 | } |
141 | rule.queryPlan = plan_fns; |
142 | |
143 | return rule; |
144 | } |
145 |