Add VisibilityRestriction

This commit is contained in:
Tony Garnock-Jones 2018-11-20 14:17:10 +00:00
parent 8964596453
commit 4048ce3ba2
2 changed files with 48 additions and 21 deletions

View File

@ -62,12 +62,12 @@ spawn named "BrokerClientFactory" {
on stop w(Clear(ep)); on stop w(Clear(ep));
on message _BrokerPacket(url, Add(ep, $vs)) { on message _BrokerPacket(url, Add(ep, $vs)) {
react { react {
assert FromBroker(url, Skeleton.instantiateAssertion(spec, vs)); assert Skeleton.instantiateAssertion(FromBroker(url, spec), vs);
stop on message _BrokerPacket(url, Del(ep, vs)); stop on message _BrokerPacket(url, Del(ep, vs));
} }
} }
on message _BrokerPacket(url, Msg(ep, $vs)) { on message _BrokerPacket(url, Msg(ep, $vs)) {
send FromBroker(url, Skeleton.instantiateAssertion(spec, vs)); send Skeleton.instantiateAssertion(FromBroker(url, spec), vs);
} }
} }
} }

View File

@ -105,7 +105,7 @@ Node.prototype.extend = function(skeleton) {
if (!nextNode) { if (!nextNode) {
nextNode = new Node(new Continuation( nextNode = new Node(new Continuation(
node.continuation.cachedAssertions.filter( node.continuation.cachedAssertions.filter(
(a) => Immutable.is(classOf(projectPath(a, path)), cls)))); (a) => Immutable.is(classOf(projectPath(unscope(a), path)), cls))));
table = table.set(cls, nextNode); table = table.set(cls, nextNode);
node.edges = node.edges.set(selector, table); node.edges = node.edges.set(selector, table);
} }
@ -137,7 +137,7 @@ Index.prototype.addHandler = function(analysisResults, callback) {
let leaf = constValMap.get(constVals, false); let leaf = constValMap.get(constVals, false);
if (!leaf) { if (!leaf) {
leaf = new Leaf(continuation.cachedAssertions.filter( leaf = new Leaf(continuation.cachedAssertions.filter(
(a) => projectPaths(a, constPaths).equals(constVals))); (a) => projectPaths(unscope(a), constPaths).equals(constVals)));
constValMap = constValMap.set(constVals, leaf); constValMap = constValMap.set(constVals, leaf);
continuation.leafMap = continuation.leafMap.set(constPaths, constValMap); continuation.leafMap = continuation.leafMap.set(constPaths, constValMap);
} }
@ -145,9 +145,13 @@ Index.prototype.addHandler = function(analysisResults, callback) {
if (!handler) { if (!handler) {
let cachedCaptures = Bag.Bag().withMutations((mutable) => { let cachedCaptures = Bag.Bag().withMutations((mutable) => {
leaf.cachedAssertions.forEach((a) => { leaf.cachedAssertions.forEach((a) => {
let captures = projectPaths(a, capturePaths); return unpackScoped(a, (restrictionPaths, term) => {
mutable.set(captures, mutable.get(captures, 0) + 1); if (restrictionPaths === false || restrictionPaths.equals(capturePaths)) {
return true; let captures = projectPaths(a, capturePaths);
mutable.set(captures, mutable.get(captures, 0) + 1);
}
return true;
});
}) })
}); });
handler = new Handler(cachedCaptures); handler = new Handler(cachedCaptures);
@ -184,6 +188,8 @@ Index.prototype.removeHandler = function(analysisResults, callback) {
}; };
Node.prototype.modify = function(outerValue, m_cont, m_leaf, m_handler) { Node.prototype.modify = function(outerValue, m_cont, m_leaf, m_handler) {
const [restrictionPaths, outerValueTerm] = unpackScoped(outerValue, (p,t) => [p,t]);
function walkNode(node, termStack) { function walkNode(node, termStack) {
walkContinuation(node.continuation); walkContinuation(node.continuation);
node.edges.forEach((table, selector) => { node.edges.forEach((table, selector) => {
@ -203,12 +209,14 @@ Node.prototype.modify = function(outerValue, m_cont, m_leaf, m_handler) {
function walkContinuation(continuation) { function walkContinuation(continuation) {
m_cont(continuation, outerValue); m_cont(continuation, outerValue);
continuation.leafMap.forEach((constValMap, constPaths) => { continuation.leafMap.forEach((constValMap, constPaths) => {
let constVals = projectPaths(outerValue, constPaths); let constVals = projectPaths(outerValueTerm, constPaths);
let leaf = constValMap.get(constVals, false); let leaf = constValMap.get(constVals, false);
if (leaf) { if (leaf) {
m_leaf(leaf, outerValue); m_leaf(leaf, outerValue);
leaf.handlerMap.forEach((handler, capturePaths) => { leaf.handlerMap.forEach((handler, capturePaths) => {
m_handler(handler, projectPaths(outerValue, capturePaths)); if (restrictionPaths === false || restrictionPaths.equals(capturePaths)) {
m_handler(handler, projectPaths(outerValueTerm, capturePaths));
}
return true; return true;
}); });
} }
@ -216,7 +224,7 @@ Node.prototype.modify = function(outerValue, m_cont, m_leaf, m_handler) {
}); });
} }
walkNode(this, Immutable.Stack().push(Immutable.List([outerValue]))); walkNode(this, Immutable.Stack().push(Immutable.List([outerValueTerm])));
}; };
function add_to_cont(c, v) { c.cachedAssertions = c.cachedAssertions.add(v); } function add_to_cont(c, v) { c.cachedAssertions = c.cachedAssertions.add(v); }
@ -308,38 +316,57 @@ function analyzeAssertion(a) {
return { skeleton, constPaths, constVals, capturePaths }; return { skeleton, constPaths, constVals, capturePaths };
} }
function VisibilityRestriction() {} function OpaquePlaceholder() {}
function instantiateAssertion(a, vs) { function instantiateAssertion(a, vs) {
let capturePaths = Immutable.List();
let remaining = vs; let remaining = vs;
function walk(a) {
function walk(path, a) {
if (Capture.isClassOf(a)) { if (Capture.isClassOf(a)) {
capturePaths = capturePaths.push(path);
const v = remaining.first(); const v = remaining.first();
remaining = remaining.shift(); remaining = remaining.shift();
walk(a.get(0)); walk(path, a.get(0));
return v; return v;
} }
if (Discard.isClassOf(a)) { if (Discard.isClassOf(a)) {
return new VisibilityRestriction(); return new OpaquePlaceholder();
// ^ Doesn't match ANYTHING ELSE, even other // ^ Doesn't match ANYTHING ELSE, even other `OpaquePlaceholder`
// VisibilityRestriction instances. This does the equivalent of // instances. This prevents unwanted matching against
// the Racket implementation's `visibility-restriction` stuff, // "don't-care" positions when `VisibilityRestriction`s are in
// to a degree. // play.
} }
let cls = classOf(a); let cls = classOf(a);
if (cls !== null) { if (cls !== null) {
if (typeof cls === 'number') { if (typeof cls === 'number') {
return a.map(walk); return a.map((v, i) => walk(path.push(i), v));
} else { } else {
return new Record(a.label, a.fields.map(walk)); return new Record(a.label, a.fields.map((v, i) => walk(path.push(i), v)));
} }
} }
return a; return a;
} }
return walk(a);
const instantiated = walk(Immutable.List(), a);
// ^ Compute `instantiated` completely before retrieving the imperatively-updated `capturePaths`.
return new VisibilityRestriction(capturePaths, instantiated);
}
function VisibilityRestriction(paths, term) {
this.paths = paths;
this.term = term;
}
function unscope(a) {
return (a instanceof VisibilityRestriction) ? a.term : a;
}
function unpackScoped(a, k) {
return (a instanceof VisibilityRestriction) ? k(a.paths, a.term) : k(false, a);
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////