yumaikas ревизій цього gist 10 months ago. До ревизії
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 ревизій цього gist 10 months ago. До ревизії
1 file changed, 102 insertions
query_compiler.js(файл створено)
| @@ -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 ревизій цього gist 10 months ago. До ревизії
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 ревизій цього gist 10 months ago. До ревизії
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 ревизій цього gist 10 months ago. До ревизії
1 file changed, 109 insertions
compiled_query.js(файл створено)
| @@ -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 | + | } | |