compiled_query.js
· 3.7 KiB · JavaScript
Originalformat
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
Originalformat
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 |