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; }