Convert Syndicate/js to use prefix-style trie

This commit is contained in:
Tony Garnock-Jones 2016-05-08 11:11:16 -04:00
parent 7b8b6c5da7
commit 062e4603af
25 changed files with 972 additions and 1211 deletions

View File

@ -122,24 +122,8 @@ var modifiedSourceActions = {
var label = maybeLabel.numChildren === 1
? maybeLabel.children[0].interval.contents
: JSON.stringify(typeName.interval.contents);
var fragments = [];
fragments.push(
'var ' + typeName.asES5 + ' = (function() {',
' var $SyndicateMeta$ = {',
' label: ' + label + ',',
' arguments: ' + JSON.stringify(formals),
' };',
' return function ' + typeName.asES5 + '(' + formalsRaw.asES5 + ') {',
' return {');
formals.forEach(function(f) {
fragments.push(' ' + JSON.stringify(f) + ': ' + f + ',');
});
fragments.push(
' "$SyndicateMeta$": $SyndicateMeta$',
' };',
' };',
'})();');
return fragments.join('\n');
return 'var ' + typeName.asES5 + ' = Syndicate.Route.makeStructureConstructor(' +
label + ', ' + JSON.stringify(formals) + ');';
},
SendMessageStatement: function(_colons, expr, sc) {

View File

@ -1,32 +1,6 @@
"use strict";
var DOM = (function() {
var $SyndicateMeta$ = {
label: "DOM",
arguments: ["containerSelector","fragmentClass","spec"]
};
return function DOM(containerSelector, fragmentClass, spec) {
return {
"containerSelector": containerSelector,
"fragmentClass": fragmentClass,
"spec": spec,
"$SyndicateMeta$": $SyndicateMeta$
};
};
})();
var jQuery = (function() {
var $SyndicateMeta$ = {
label: "jQuery",
arguments: ["selector","eventType","event"]
};
return function jQuery(selector, eventType, event) {
return {
"selector": selector,
"eventType": eventType,
"event": event,
"$SyndicateMeta$": $SyndicateMeta$
};
};
})();
var DOM = Syndicate.DOM.DOM;
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
$(document).ready(function() {
new Syndicate.Ground(function () {
@ -37,7 +11,7 @@ $(document).ready(function() {
this.counter = 0;
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(DOM('#button-label','',Syndicate.seal(this.counter)), 0); }))
.onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(jQuery('#counter','click',_), 0); }), (function() { var _ = Syndicate.__; return { assertion: jQuery('#counter','click',_), metalevel: 0 }; }), (function() {
.onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(jQueryEvent('#counter','click',_), 0); }), (function() { var _ = Syndicate.__; return { assertion: jQueryEvent('#counter','click',_), metalevel: 0 }; }), (function() {
this.counter++;
})).completeBuild();
});

View File

@ -3,7 +3,6 @@
<head>
<title>Syndicate: Button Example</title>
<meta charset="utf-8">
<link href="style.css" rel="stylesheet">
<script src="../../third-party/jquery-2.2.0.min.js"></script>
<script src="../../dist/syndicatecompiler.js"></script>
<script src="../../dist/syndicate.js"></script>

View File

@ -1,5 +1,5 @@
assertion type DOM(containerSelector, fragmentClass, spec);
assertion type jQuery(selector, eventType, event);
var DOM = Syndicate.DOM.DOM;
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
$(document).ready(function() {
ground dataspace {
@ -10,7 +10,7 @@ $(document).ready(function() {
this.counter = 0;
forever {
assert DOM('#button-label', '', Syndicate.seal(this.counter));
on message jQuery('#counter', 'click', _) {
on message jQueryEvent('#counter', 'click', _) {
this.counter++;
}
}

View File

@ -12,15 +12,18 @@ $(document).ready(function () {
console.log('starting ground boot');
Syndicate.DOM.spawnDOMDriver();
var DOM = Syndicate.DOM.DOM;
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
Dataspace.spawn({
boot: function () {
return assert(["DOM", "#clicker-holder", "clicker",
seal(["button", ["span", [["style", "font-style: italic"]], "Click me!"]])])
.andThen(sub(["jQuery", "button.clicker", "click", __]));
return assert(DOM("#clicker-holder", "clicker",
seal(["button", ["span", [["style", "font-style: italic"]],
"Click me!"]])))
.andThen(sub(jQueryEvent("button.clicker", "click", __)));
},
handleEvent: function (e) {
if (e.type === "message" && e.message[0] === "jQuery") {
if (e.type === "message" && jQueryEvent.isClassOf(e.message)) {
Dataspace.send("bump_count");
}
}
@ -33,11 +36,11 @@ $(document).ready(function () {
return sub("bump_count");
},
updateState: function () {
Dataspace.stateChange(retract(["DOM", __, __, __])
.andThen(assert(["DOM", "#counter-holder", "counter",
seal(["div",
["p", "The current count is: ",
this.counter]])])));
Dataspace.stateChange(retract(DOM.pattern)
.andThen(assert(DOM("#counter-holder", "counter",
seal(["div",
["p", "The current count is: ",
this.counter]])))));
},
handleEvent: function (e) {
if (e.type === "message" && e.message === "bump_count") {

View File

@ -6,8 +6,8 @@ assertion type tvAlert(text);
assertion type switchAction(on);
assertion type componentPresent(name);
assertion type DOM(containerSelector, fragmentClass, spec);
assertion type jQuery(selector, eventType, event);
var DOM = Syndicate.DOM.DOM;
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
///////////////////////////////////////////////////////////////////////////
// TV
@ -48,7 +48,7 @@ function spawnRemoteControl() {
actor {
forever {
assert componentPresent('remote control');
on message jQuery('#remote-control', 'click', _) {
on message jQueryEvent('#remote-control', 'click', _) {
:: remoteClick();
}
}
@ -92,14 +92,14 @@ function spawnStoveSwitch() {
"img/stove-coil-element-" +
(this.powerOn ? "hot" : "cold") + ".jpg"]]]));
on message jQuery('#stove-switch-on', 'click', _) { this.powerOn = true; }
on message jQuery('#stove-switch-off', 'click', _) { this.powerOn = false; }
on message jQueryEvent('#stove-switch-on', 'click', _) { this.powerOn = true; }
on message jQueryEvent('#stove-switch-off', 'click', _) { this.powerOn = false; }
on message switchAction($newState) {
this.powerOn = newState;
}
} until {
case message jQuery('#kill-stove-switch', 'click', _);
case message jQueryEvent('#kill-stove-switch', 'click', _);
}
}
}
@ -120,7 +120,7 @@ function spawnPowerDrawMonitor() {
this.watts = on ? 1500 : 0;
}
} until {
case message jQuery('#kill-power-draw-monitor', 'click', _);
case message jQueryEvent('#kill-power-draw-monitor', 'click', _);
}
}
}
@ -187,10 +187,10 @@ function spawnFailureMonitor() {
function spawnChaosMonkey() {
actor {
forever {
on message jQuery('#spawn-power-draw-monitor', 'click', _) {
on message jQueryEvent('#spawn-power-draw-monitor', 'click', _) {
spawnPowerDrawMonitor();
}
on message jQuery('#spawn-stove-switch', 'click', _) {
on message jQueryEvent('#spawn-stove-switch', 'click', _) {
spawnStoveSwitch();
}
}

View File

@ -14,10 +14,13 @@ $(document).ready(function () {
Dataspace.spawn({
boot: function () {
return sub(['jQuery', '#clicker', 'click', __]);
return sub(Syndicate.JQuery.jQueryEvent('#clicker', 'click', __));
},
handleEvent: function (e) {
if (e.type === 'message' && e.message[0] === 'jQuery' && e.message[1] === '#clicker') {
if (e.type === 'message'
&& Syndicate.JQuery.jQueryEvent.isClassOf(e.message)
&& e.message.selector === '#clicker')
{
var r = $('#result');
r.html(Number(r.html()) + 1);
}

View File

@ -23,8 +23,8 @@ ground dataspace {
actor {
forever {
on message $m {
console.log("Got message:", m);
on message beep($counter) {
console.log("beep!", counter);
}
}
}

View File

@ -1,5 +1,7 @@
"use strict";
var beep = Syndicate.Route.makeStructureConstructor('beep', ['counter']);
var G;
$(document).ready(function () {
var Dataspace = Syndicate.Dataspace;
@ -15,16 +17,16 @@ $(document).ready(function () {
boot: function () {},
handleEvent: function (e) {},
step: function () {
Dataspace.send(["beep", this.counter++]);
Dataspace.send(beep(this.counter++));
return this.counter <= 10;
}
});
Dataspace.spawn({
boot: function () { return sub(["beep", __]); },
boot: function () { return sub(beep.pattern); },
handleEvent: function (e) {
if (e.type === 'message') {
console.log("beep!", e.message[1]);
console.log("beep!", e.message.counter);
}
}
});

View File

@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////
// GUI
assertion type jQuery(selector, eventType, event);
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
assertion type fieldCommand(detail);
assertion type fieldContents(text, pos);
assertion type highlight(state);
@ -34,8 +34,8 @@ function spawnGui() {
var text = this.text;
var pos = this.pos;
var highlight = this.highlightState;
var hLeft = highlight ? highlight.get(0) : 0;
var hRight = highlight ? highlight.get(1) : 0;
var hLeft = highlight ? highlight[0] : 0;
var hRight = highlight ? highlight[1] : 0;
$("#fieldContents")[0].innerHTML = highlight
? piece(text, pos, 0, hLeft, "normal") +
piece(text, pos, hLeft, hRight, "highlight") +
@ -44,7 +44,7 @@ function spawnGui() {
};
forever {
on message jQuery("#inputRow", "+keypress", $event) {
on message jQueryEvent("#inputRow", "+keypress", $event) {
var keycode = event.keyCode;
var character = String.fromCharCode(event.charCode);
if (keycode === 37 /* left */) {
@ -79,11 +79,11 @@ function spawnGui() {
function spawnModel() {
actor {
this.fieldContents = "initial";
this.cursorPos = this.fieldContents.length; /* positions address gaps between characters */
this.fieldValue = "initial";
this.cursorPos = this.fieldValue.length; /* positions address gaps between characters */
forever {
assert fieldContents(this.fieldContents, this.cursorPos);
assert fieldContents(this.fieldValue, this.cursorPos);
on message fieldCommand("cursorLeft") {
this.cursorPos--;
@ -93,24 +93,24 @@ function spawnModel() {
on message fieldCommand("cursorRight") {
this.cursorPos++;
if (this.cursorPos > this.fieldContents.length)
this.cursorPos = this.fieldContents.length;
if (this.cursorPos > this.fieldValue.length)
this.cursorPos = this.fieldValue.length;
}
on message fieldCommand("backspace") {
if (this.cursorPos > 0) {
this.fieldContents =
this.fieldContents.substring(0, this.cursorPos - 1) +
this.fieldContents.substring(this.cursorPos);
this.fieldValue =
this.fieldValue.substring(0, this.cursorPos - 1) +
this.fieldValue.substring(this.cursorPos);
this.cursorPos--;
}
}
on message fieldCommand(["insert", $newText]) {
this.fieldContents =
this.fieldContents.substring(0, this.cursorPos) +
this.fieldValue =
this.fieldValue.substring(0, this.cursorPos) +
newText +
this.fieldContents.substring(this.cursorPos);
this.fieldValue.substring(this.cursorPos);
this.cursorPos += newText.length;
}
}
@ -122,13 +122,13 @@ function spawnModel() {
function spawnSearch() {
actor {
this.fieldContents = "";
this.fieldValue = "";
this.highlight = false;
this.search = function () {
var searchtext = $("#searchBox")[0].value;
if (searchtext) {
var pos = this.fieldContents.indexOf(searchtext);
var pos = this.fieldValue.indexOf(searchtext);
this.highlight = (pos !== -1) && [pos, pos + searchtext.length];
} else {
this.highlight = false;
@ -138,12 +138,12 @@ function spawnSearch() {
forever {
assert highlight(this.highlight);
on message jQuery("#searchBox", "input", $event) {
on message jQueryEvent("#searchBox", "input", $event) {
this.search();
}
on asserted fieldContents($text, _) {
this.fieldContents = text;
this.fieldValue = text;
this.search();
}
}

View File

@ -7,6 +7,11 @@ var Patch = Syndicate.Patch;
var __ = Syndicate.__;
var _$ = Syndicate._$;
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
var fieldContents = Route.makeStructureConstructor('fieldContents', ['text', 'pos']);
var highlight = Route.makeStructureConstructor('highlight', ['state']);
var fieldCommand = Route.makeStructureConstructor('fieldCommand', ['detail']);
function escapeText(text) {
text = text.replace(/&/g, '&amp;');
text = text.replace(/</g, '&lt;');
@ -31,30 +36,30 @@ function spawnGui() {
highlight: { state: false },
boot: function () {
return Patch.sub(["jQuery", "#inputRow", "+keypress", __])
.andThen(Patch.sub(["fieldContents", __, __]))
.andThen(Patch.sub(["highlight", __]));
return Patch.sub(jQueryEvent("#inputRow", "+keypress", __))
.andThen(Patch.sub(fieldContents.pattern))
.andThen(Patch.sub(highlight.pattern));
},
fieldContentsProjection: Route.compileProjection(["fieldContents", _$("text"), _$("pos")]),
highlightProjection: Route.compileProjection(["highlight", _$("state")]),
fieldContentsProjection: fieldContents(_$("text"), _$("pos")),
highlightProjection: highlight(_$("state")),
handleEvent: function (e) {
var self = this;
switch (e.type) {
case "message":
var event = e.message[3];
var event = e.message.eventValue;
var keycode = event.keyCode;
var character = String.fromCharCode(event.charCode);
if (keycode === 37 /* left */) {
Dataspace.send(["fieldCommand", "cursorLeft"]);
Dataspace.send(fieldCommand("cursorLeft"));
} else if (keycode === 39 /* right */) {
Dataspace.send(["fieldCommand", "cursorRight"]);
Dataspace.send(fieldCommand("cursorRight"));
} else if (keycode === 9 /* tab */) {
// ignore
} else if (keycode === 8 /* backspace */) {
Dataspace.send(["fieldCommand", "backspace"]);
Dataspace.send(fieldCommand("backspace"));
} else if (character) {
Dataspace.send(["fieldCommand", ["insert", character]]);
Dataspace.send(fieldCommand(["insert", character]));
}
break;
case "stateChange":
@ -73,8 +78,8 @@ function spawnGui() {
var text = this.field ? this.field.text : "";
var pos = this.field ? this.field.pos : 0;
var highlight = this.highlight ? this.highlight.state : false;
var hLeft = highlight ? highlight.get(0) : 0;
var hRight = highlight ? highlight.get(1) : 0;
var hLeft = highlight ? highlight[0] : 0;
var hRight = highlight ? highlight[1] : 0;
$("#fieldContents")[0].innerHTML = highlight
? piece(text, pos, 0, hLeft, "normal") +
piece(text, pos, hLeft, hRight, "highlight") +
@ -90,36 +95,36 @@ function spawnGui() {
function spawnModel() {
var initialContents = "initial";
Dataspace.spawn({
fieldContents: initialContents,
fieldValue: initialContents,
cursorPos: initialContents.length, /* positions address gaps between characters */
boot: function () {
this.publishState();
return Patch.sub(["fieldCommand", __]);
return Patch.sub(fieldCommand.pattern);
},
handleEvent: function (e) {
if (e.type === "message" && e.message[0] === "fieldCommand") {
var command = e.message[1];
if (e.type === "message" && fieldCommand.isClassOf(e.message)) {
var command = e.message.detail;
if (command === "cursorLeft") {
this.cursorPos--;
if (this.cursorPos < 0)
this.cursorPos = 0;
} else if (command === "cursorRight") {
this.cursorPos++;
if (this.cursorPos > this.fieldContents.length)
this.cursorPos = this.fieldContents.length;
if (this.cursorPos > this.fieldValue.length)
this.cursorPos = this.fieldValue.length;
} else if (command === "backspace" && this.cursorPos > 0) {
this.fieldContents =
this.fieldContents.substring(0, this.cursorPos - 1) +
this.fieldContents.substring(this.cursorPos);
this.fieldValue =
this.fieldValue.substring(0, this.cursorPos - 1) +
this.fieldValue.substring(this.cursorPos);
this.cursorPos--;
} else if (command.constructor === Array && command[0] === "insert") {
var newText = command[1];
this.fieldContents =
this.fieldContents.substring(0, this.cursorPos) +
this.fieldValue =
this.fieldValue.substring(0, this.cursorPos) +
newText +
this.fieldContents.substring(this.cursorPos);
this.fieldValue.substring(this.cursorPos);
this.cursorPos += newText.length;
}
this.publishState();
@ -128,8 +133,8 @@ function spawnModel() {
publishState: function () {
Dataspace.stateChange(
Patch.retract(["fieldContents", __, __])
.andThen(Patch.assert(["fieldContents", this.fieldContents, this.cursorPos])));
Patch.retract(fieldContents.pattern)
.andThen(Patch.assert(fieldContents(this.fieldValue, this.cursorPos))));
}
});
}
@ -139,24 +144,24 @@ function spawnModel() {
function spawnSearch() {
Dataspace.spawn({
fieldContents: "",
fieldValue: "",
highlight: false,
boot: function () {
this.publishState();
return Patch.sub(["jQuery", "#searchBox", "input", __])
.andThen(Patch.sub(["fieldContents", __, __]));
return Patch.sub(jQueryEvent("#searchBox", "input", __))
.andThen(Patch.sub(fieldContents.pattern));
},
fieldContentsProjection: Route.compileProjection(["fieldContents", _$("text"), _$("pos")]),
fieldContentsProjection: fieldContents(_$("text"), _$("pos")),
handleEvent: function (e) {
var self = this;
if (e.type === "message" && e.message[0] === "jQuery") {
if (jQueryEvent.isClassOf(e.message)) {
this.search();
}
if (e.type === "stateChange") {
Route.projectObjects(e.patch.added, this.fieldContentsProjection).forEach(function (c) {
self.fieldContents = c.text;
self.fieldValue = c.text;
});
this.search();
}
@ -164,15 +169,15 @@ function spawnSearch() {
publishState: function () {
Dataspace.stateChange(
Patch.retract(["highlight", __])
.andThen(Patch.assert(["highlight", this.highlight])));
Patch.retract(highlight.pattern)
.andThen(Patch.assert(highlight(this.highlight))));
},
search: function () {
var searchtext = $("#searchBox")[0].value;
var oldHighlight = this.highlight;
if (searchtext) {
var pos = this.fieldContents.indexOf(searchtext);
var pos = this.fieldValue.indexOf(searchtext);
this.highlight = (pos !== -1) && [pos, pos + searchtext.length];
} else {
this.highlight = false;

View File

@ -5,7 +5,7 @@ var Dataspace = require('./dataspace.js').Dataspace;
var Route = require('./route.js');
var Patch = require('./patch.js');
var $Ack = new Route.$Special('ack');
var ack = Route.makeStructureConstructor('ack', ['id']);
function Ack(metaLevel, id) {
this.metaLevel = metaLevel || 0;
@ -14,19 +14,19 @@ function Ack(metaLevel, id) {
}
Ack.prototype.arm = function () {
Dataspace.stateChange(Patch.sub([$Ack, this.id], this.metaLevel));
Dataspace.send([$Ack, this.id], this.metaLevel);
Dataspace.stateChange(Patch.sub(ack(this.id), this.metaLevel));
Dataspace.send(ack(this.id), this.metaLevel);
};
Ack.prototype.disarm = function () {
Dataspace.stateChange(Patch.unsub([$Ack, this.id], this.metaLevel));
Dataspace.stateChange(Patch.unsub(ack(this.id), this.metaLevel));
};
Ack.prototype.check = function (e) {
if (!this.done) {
if (e.type === 'message') {
var m = Patch.stripAtMeta(e.message, this.metaLevel);
if (m && m[0] === $Ack && m[1] === this.id) {
if (ack.isClassOf(m) && m.id === this.id) {
this.disarm();
this.done = true;
}
@ -37,5 +37,5 @@ Ack.prototype.check = function (e) {
///////////////////////////////////////////////////////////////////////////
module.exports.$Ack = $Ack;
module.exports.ack = ack;
module.exports.Ack = Ack;

View File

@ -94,11 +94,10 @@ Facet.prototype.onEvent = function(isTerminal, eventType, subscriptionFn, projec
if (e.type === 'stateChange') {
var proj = projectionFn.call(facet.actor.state);
var spec = Patch.prependAtMeta(proj.assertion, proj.metalevel);
var compiledSpec = Route.compileProjection(spec);
var objects = Route.projectObjects(eventType === 'asserted'
? e.patch.added
: e.patch.removed,
compiledSpec);
spec);
if (objects && objects.size > 0) {
// console.log(objects.toArray());
if (isTerminal) { facet.terminate(); }

View File

@ -229,11 +229,11 @@ Dataspace.prototype.interpretAction = function (pid, action) {
return true;
case 'message':
if (Patch.isObserve(action.message)) {
if (Patch.observe.isClassOf(action.message)) {
console.warn('Process ' + pid + ' send message containing query', action.message);
}
if (pid !== 'meta' && Patch.isAtMeta(action.message)) {
Dataspace.send(action.message[1]);
if (pid !== 'meta' && Patch.atMeta.isClassOf(action.message)) {
Dataspace.send(action.message.assertion);
} else {
this.mux.routeMessage(action.message).forEach(function (pid) {
self.deliverEvent(pid, action);

View File

@ -20,8 +20,10 @@ function DemandMatcher(demandSpec, supplySpec, options) {
this.supplySpec = supplySpec;
this.demandPattern = Route.projectionToPattern(demandSpec);
this.supplyPattern = Route.projectionToPattern(supplySpec);
this.demandProjection = Route.compileProjection(Patch.prependAtMeta(demandSpec, this.metaLevel));
this.supplyProjection = Route.compileProjection(Patch.prependAtMeta(supplySpec, this.metaLevel));
this.demandProjection = Patch.prependAtMeta(demandSpec, this.metaLevel);
this.supplyProjection = Patch.prependAtMeta(supplySpec, this.metaLevel);
this.demandProjectionNames = Route.projectionNames(this.demandProjection);
this.supplyProjectionNames = Route.projectionNames(this.supplyProjection);
this.currentDemand = Immutable.Set();
this.currentSupply = Immutable.Set();
}
@ -40,10 +42,12 @@ DemandMatcher.prototype.handleEvent = function (e) {
DemandMatcher.prototype.handlePatch = function (p) {
var self = this;
var addedDemand = Route.trieKeys(Route.project(p.added, self.demandProjection));
var removedDemand = Route.trieKeys(Route.project(p.removed, self.demandProjection));
var addedSupply = Route.trieKeys(Route.project(p.added, self.supplyProjection));
var removedSupply = Route.trieKeys(Route.project(p.removed, self.supplyProjection));
var dN = self.demandProjectionNames.length;
var sN = self.supplyProjectionNames.length;
var addedDemand = Route.trieKeys(Route.project(p.added, self.demandProjection), dN);
var removedDemand = Route.trieKeys(Route.project(p.removed, self.demandProjection), dN);
var addedSupply = Route.trieKeys(Route.project(p.added, self.supplyProjection), sN);
var removedSupply = Route.trieKeys(Route.project(p.removed, self.supplyProjection), sN);
if (addedDemand === null) {
throw new Error("Syndicate: wildcard demand detected:\n" +
@ -61,12 +65,12 @@ DemandMatcher.prototype.handlePatch = function (p) {
removedSupply.forEach(function (captures) {
if (self.currentDemand.has(captures)) {
self.onSupplyDecrease(Route.captureToObject(captures, self.supplyProjection));
self.onSupplyDecrease(Route.captureToObject(captures, self.supplyProjectionNames));
}
});
addedDemand.forEach(function (captures) {
if (!self.currentSupply.has(captures)) {
self.onDemandIncrease(Route.captureToObject(captures, self.demandProjection));
self.onDemandIncrease(Route.captureToObject(captures, self.demandProjectionNames));
}
});

View File

@ -1,6 +1,7 @@
// DOM fragment display driver
var Patch = require("./patch.js");
var DemandMatcher = require('./demand-matcher.js').DemandMatcher;
var Route = require('./route.js');
var Ack = require('./ack.js').Ack;
var Seal = require('./seal.js').Seal;
@ -9,27 +10,25 @@ var Dataspace = Dataspace_.Dataspace;
var __ = Dataspace_.__;
var _$ = Dataspace_._$;
var DOM = Route.makeStructureConstructor('DOM', ['selector', 'fragmentClass', 'fragmentSpec']);
function spawnDOMDriver(domWrapFunction, jQueryWrapFunction) {
domWrapFunction = domWrapFunction || defaultWrapFunction;
domWrapFunction = domWrapFunction || DOM;
var spec = domWrapFunction(_$('selector'), _$('fragmentClass'), _$('fragmentSpec'));
Dataspace.spawn(
new DemandMatcher(spec,
Patch.advertise(spec),
Patch.advertise(spec), // TODO: are the embedded captures problematic here? If not, why not?
{
onDemandIncrease: function (c) {
Dataspace.spawn(new DOMFragment(c.selector,
c.fragmentClass,
c.fragmentSpec,
domWrapFunction,
jQueryWrapFunction));
c.fragmentClass,
c.fragmentSpec,
domWrapFunction,
jQueryWrapFunction));
}
}));
}
function defaultWrapFunction(selector, fragmentClass, fragmentSpec) {
return ["DOM", selector, fragmentClass, fragmentSpec];
}
function DOMFragment(selector, fragmentClass, fragmentSpec, domWrapFunction, jQueryWrapFunction) {
this.selector = selector;
this.fragmentClass = fragmentClass;
@ -138,4 +137,4 @@ DOMFragment.prototype.buildNodes = function () {
///////////////////////////////////////////////////////////////////////////
module.exports.spawnDOMDriver = spawnDOMDriver;
module.exports.defaultWrapFunction = defaultWrapFunction;
module.exports.DOM = DOM;

View File

@ -1,15 +1,18 @@
// JQuery event driver
var Patch = require("./patch.js");
var DemandMatcher = require('./demand-matcher.js').DemandMatcher;
var Route = require('./route.js');
var Dataspace_ = require("./dataspace.js");
var Dataspace = Dataspace_.Dataspace;
var __ = Dataspace_.__;
var _$ = Dataspace_._$;
var jQueryEvent = Route.makeStructureConstructor('jQueryEvent', ['selector', 'eventName', 'eventValue']);
function spawnJQueryDriver(baseSelector, metaLevel, wrapFunction) {
metaLevel = metaLevel || 0;
wrapFunction = wrapFunction || defaultWrapFunction;
wrapFunction = wrapFunction || jQueryEvent;
Dataspace.spawn(
new DemandMatcher(Patch.observe(wrapFunction(_$('selector'), _$('eventName'), __)),
Patch.advertise(wrapFunction(_$('selector'), _$('eventName'), __)),
@ -17,25 +20,21 @@ function spawnJQueryDriver(baseSelector, metaLevel, wrapFunction) {
metaLevel: metaLevel,
onDemandIncrease: function (c) {
Dataspace.spawn(new JQueryEventRouter(baseSelector,
c.selector,
c.eventName,
metaLevel,
wrapFunction));
c.selector,
c.eventName,
metaLevel,
wrapFunction));
}
}));
}
function defaultWrapFunction(selector, eventName, eventValue) {
return ["jQuery", selector, eventName, eventValue];
}
function JQueryEventRouter(baseSelector, selector, eventName, metaLevel, wrapFunction) {
var self = this;
this.baseSelector = baseSelector || null;
this.selector = selector;
this.eventName = eventName;
this.metaLevel = metaLevel || 0;
this.wrapFunction = wrapFunction || defaultWrapFunction;
this.wrapFunction = wrapFunction || jQueryEvent;
this.preventDefault = (this.eventName.charAt(0) !== "+");
this.handler =
Dataspace.wrap(function (e) {
@ -88,4 +87,4 @@ function simplifyDOMEvent(e) {
module.exports.spawnJQueryDriver = spawnJQueryDriver;
module.exports.simplifyDOMEvent = simplifyDOMEvent;
module.exports.defaultWrapFunction = defaultWrapFunction;
module.exports.jQueryEvent = jQueryEvent;

View File

@ -12,7 +12,7 @@ module.exports.Route = require("./route.js");
copyKeys(['__', '_$', '$Capture', '$Special',
'is_emptyTrie', 'emptyTrie',
'embeddedTrie', 'compilePattern',
'compileProjection', 'project', 'projectObjects',
'project', 'projectObjects',
'prettyTrie'],
module.exports,
module.exports.Route);
@ -35,7 +35,6 @@ module.exports.Reflect = require("./reflect.js");
module.exports.Patch = require("./patch.js");
copyKeys(['emptyPatch',
'observe', 'atMeta', 'advertise',
'isObserve', 'isAtMeta', 'isAdvertise',
'assert', 'retract', 'sub', 'unsub', 'pub', 'unpub',
'patchSeq'],
module.exports,

View File

@ -45,12 +45,12 @@ Mux.prototype.updateStream = function (pid, unclampedPatch) {
};
var atMetaEverything = Route.compilePattern(true, Patch.atMeta(Route.__));
var atMetaBranchKeys = Immutable.List([Route.SOA, Patch.$AtMeta]);
var onlyMeta = Immutable.Set.of("meta");
var atMetaBranchKeys = Immutable.List([[Patch.atMeta.meta.arguments.length, Patch.atMeta.meta]]);
var onlyMeta = Route.trieSuccess(Immutable.Set.of("meta"));
function echoCancelledTrie(t) {
return Route.subtract(t, atMetaEverything, function (v1, v2) {
return v1.has("meta") ? onlyMeta : null;
return v1.has("meta") ? onlyMeta : Route.emptyTrie;
});
}
@ -95,12 +95,10 @@ function computeEvents(oldMux, newMux, updateStreamResult) {
function computeAffectedPids(routingTable, delta) {
var cover = Route._union(delta.added, delta.removed);
routingTable = Route.trieStep(routingTable, Route.SOA);
routingTable = Route.trieStep(routingTable, Patch.$Observe);
routingTable =
Route.trieStep(routingTable, Patch.observe.meta.arguments.length, Patch.observe.meta);
return Route.matchTrie(cover, routingTable, Immutable.Set(),
function (v, r, acc) {
return acc.union(Route.trieStep(r, Route.EOA).value);
});
function (v1, v2, acc) { return acc.union(v2); });
}
Mux.prototype.routeMessage = function (body) {

View File

@ -13,18 +13,11 @@ function Patch(added, removed) {
var emptyPatch = new Patch(Route.emptyTrie, Route.emptyTrie);
var removeEverythingPatch = new Patch(Route.emptyTrie, Route.compilePattern(true, __));
var trueLabel = Route.trieSuccess(true);
var $Observe = new Route.$Special("$Observe");
var $AtMeta = new Route.$Special("$AtMeta");
var $Advertise = new Route.$Special("$Advertise");
function observe(p) { return [$Observe, p]; }
function atMeta(p) { return [$AtMeta, p]; }
function advertise(p) { return [$Advertise, p]; }
function isObserve(p) { return p[0] === $Observe; }
function isAtMeta(p) { return p[0] === $AtMeta; }
function isAdvertise(p) { return p[0] === $Advertise; }
var observe = Route.makeStructureConstructor('observe', ['assertion']);
var atMeta = Route.makeStructureConstructor('atMeta', ['assertion']);
var advertise = Route.makeStructureConstructor('advertise', ['assertion']);
function prependAtMeta(p, level) {
while (level--) {
@ -35,8 +28,8 @@ function prependAtMeta(p, level) {
function stripAtMeta(p, level) {
while (level--) {
if (p.length === 2 && p[0] === $AtMeta) {
p = p[1];
if (atMeta.isClassOf(p)) {
p = p.assertion;
} else {
return null;
}
@ -115,7 +108,7 @@ Patch.prototype.lift = function () {
Route.compilePattern(true, atMeta(Route.embeddedTrie(this.removed))));
};
var atMetaProj = Route.compileProjection(atMeta(_$));
var atMetaProj = atMeta(_$);
Patch.prototype.drop = function () {
return new Patch(Route.project(this.added, atMetaProj),
Route.project(this.removed, atMetaProj));
@ -132,8 +125,9 @@ Patch.prototype.label = function (labelValue) {
};
Patch.prototype.limit = function (bound) {
return new Patch(Route.subtract(this.added, bound, function (v1, v2) { return null; }),
Route.intersect(this.removed, bound, function (v1, v2) { return v1; }));
return new Patch(Route.subtract(this.added, bound, function (v1, v2) { return Route.emptyTrie; }),
Route.intersect(this.removed, bound,
function (v1, v2) { return Route.trieSuccess(v1); }));
};
var metaLabelSet = Immutable.Set(["meta"]);
@ -143,20 +137,20 @@ Patch.prototype.computeAggregate = function (label, base, removeMeta /* optional
function addCombiner(v1, v2) {
if (removeMeta && Immutable.is(v2, metaLabelSet)) {
return v1;
return Route.trieSuccess(v1);
} else {
return null;
return Route.emptyTrie;
}
}
function removeCombiner(v1, v2) {
if (v2.size === 1) {
return v1;
return Route.trieSuccess(v1);
} else {
if (removeMeta && v2.size === 2 && v2.has("meta")) {
return v1;
return Route.trieSuccess(v1);
} else {
return null;
return Route.emptyTrie;
}
}
}
@ -167,9 +161,11 @@ Patch.prototype.applyTo = function (base) {
};
Patch.prototype.updateInterests = function (base) {
return Route._union(Route.subtract(base, this.removed, function (v1, v2) { return null; }),
return Route._union(Route.subtract(base,
this.removed,
function (v1, v2) { return Route.emptyTrie; }),
this.added,
function (v1, v2) { return true; });
function (v1, v2) { return trueLabel; });
};
Patch.prototype.unapplyTo = function (base) {
@ -180,9 +176,9 @@ Patch.prototype.andThen = function (nextPatch) {
return new Patch(nextPatch.updateInterests(this.added),
Route._union(Route.subtract(this.removed,
nextPatch.added,
function (v1, v2) { return null; }),
function (v1, v2) { return Route.emptyTrie; }),
nextPatch.removed,
function (v1, v2) { return true; }));
function (v1, v2) { return trueLabel; }));
};
function patchSeq(/* patch, patch, ... */) {
@ -199,11 +195,8 @@ function computePatch(oldBase, newBase) {
}
function biasedIntersection(object, subject) {
subject = Route.trieStep(subject, Route.SOA);
subject = Route.trieStep(subject, $Observe);
return Route.intersect(object, subject,
function (v1, v2) { return true; },
function (v, r) { return Route.trieStep(r, Route.EOA); });
subject = Route.trieStep(subject, observe.meta.arguments.length, observe.meta);
return Route.intersect(object, subject, function (v1, v2) { return Route.trieSuccess(v1); });
}
Patch.prototype.viewFrom = function (interests) {
@ -240,15 +233,9 @@ module.exports.Patch = Patch;
module.exports.emptyPatch = emptyPatch;
module.exports.removeEverythingPatch = removeEverythingPatch;
module.exports.$Observe = $Observe;
module.exports.$AtMeta = $AtMeta;
module.exports.$Advertise = $Advertise;
module.exports.observe = observe;
module.exports.atMeta = atMeta;
module.exports.advertise = advertise;
module.exports.isObserve = isObserve;
module.exports.isAtMeta = isAtMeta;
module.exports.isAdvertise = isAdvertise;
module.exports.prependAtMeta = prependAtMeta;
module.exports.stripAtMeta = stripAtMeta;

File diff suppressed because it is too large Load Diff

View File

@ -32,13 +32,13 @@ describe('mux stream', function () {
describe('addition', function () {
it('should union interests appropriately', function () {
var m = getM();
checkPrettyTrie(m.routingTable, [' 1 >{[0]}',
' 2 >{[0,1]}',
' 3 >{[1]}']);
checkPrettyTrie(m.interestsOf(0), [' 1 >{[0]}',
' 2 >{[0]}']);
checkPrettyTrie(m.interestsOf(1), [' 2 >{[1]}',
' 3 >{[1]}']);
checkPrettyTrie(m.routingTable, [' 1 {[0]}',
' 2 {[0,1]}',
' 3 {[1]}']);
checkPrettyTrie(m.interestsOf(0), [' 1 {[0]}',
' 2 {[0]}']);
checkPrettyTrie(m.interestsOf(1), [' 2 {[1]}',
' 3 {[1]}']);
});
});
@ -51,30 +51,30 @@ describe('mux stream', function () {
.andThen(Patch.assert(4))
.andThen(Patch.retract(99));
checkPrettyPatch(rawPatch,
[' 1 >{true}',
' 4 >{true}'],
[' 2 >{true}',
' 3 >{true}',
' 99 >{true}']);
[' 1 {true}',
' 4 {true}'],
[' 2 {true}',
' 3 {true}',
' 99 {true}']);
var m = getM();
var updateStreamResult = m.updateStream(1, rawPatch);
expect(updateStreamResult.pid).to.equal(1);
checkPrettyPatch(updateStreamResult.delta,
[' 1 >{[1]}',
' 4 >{[1]}'],
[' 2 >{[1]}',
' 3 >{[1]}']);
checkPrettyTrie(m.routingTable, [' 1 >{[0,1]}',
' 2 >{[0]}',
' 4 >{[1]}']);
checkPrettyTrie(m.interestsOf(0), [' 1 >{[0]}',
' 2 >{[0]}']);
checkPrettyTrie(m.interestsOf(1), [' 1 >{[1]}',
' 4 >{[1]}']);
[' 1 {[1]}',
' 4 {[1]}'],
[' 2 {[1]}',
' 3 {[1]}']);
checkPrettyTrie(m.routingTable, [' 1 {[0,1]}',
' 2 {[0]}',
' 4 {[1]}']);
checkPrettyTrie(m.interestsOf(0), [' 1 {[0]}',
' 2 {[0]}']);
checkPrettyTrie(m.interestsOf(1), [' 1 {[1]}',
' 4 {[1]}']);
checkPrettyPatch(updateStreamResult.deltaAggregate,
[' 4 >{[1]}'],
[' 3 >{[1]}']);
[' 4 {[1]}'],
[' 3 {[1]}']);
});
});
@ -84,17 +84,17 @@ describe('mux stream', function () {
var updateStreamResult = m.removeStream(1);
expect(updateStreamResult.pid).to.equal(1);
checkPrettyPatch(updateStreamResult.delta,
['::: nothing'],
[' 2 >{[1]}',
' 3 >{[1]}']);
checkPrettyTrie(m.routingTable, [' 1 >{[0]}',
' 2 >{[0]}']);
checkPrettyTrie(m.interestsOf(0), [' 1 >{[0]}',
' 2 >{[0]}']);
checkPrettyTrie(m.interestsOf(1), ['::: nothing']);
[' ::: nothing'],
[' 2 {[1]}',
' 3 {[1]}']);
checkPrettyTrie(m.routingTable, [' 1 {[0]}',
' 2 {[0]}']);
checkPrettyTrie(m.interestsOf(0), [' 1 {[0]}',
' 2 {[0]}']);
checkPrettyTrie(m.interestsOf(1), [' ::: nothing']);
checkPrettyPatch(updateStreamResult.deltaAggregate,
['::: nothing'],
[' 3 >{[1]}']);
[' ::: nothing'],
[' 3 {[1]}']);
});
});
});

View File

@ -19,76 +19,76 @@ function checkPrettyPatch(p, expectedAdded, expectedRemoved) {
describe('basic patch compilation', function () {
it('should print as expected', function () {
checkPrettyPatch(Patch.assert([1, 2]),
[' < 1 2 > >{true}'],
['::: nothing']);
[' <2> 1 2 {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.assert(__),
[' ★ >{true}'],
['::: nothing']);
[' ★ {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.sub(__),
[' < $Observe ★ > >{true}'],
['::: nothing']);
[' observe<1> ★ {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.sub([1, 2]),
[' < $Observe < 1 2 > > >{true}'],
['::: nothing']);
[' observe<1> <2> 1 2 {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.pub('x'),
[' < $Advertise "x" > >{true}'],
['::: nothing']);
[' advertise<1> "x" {true}'],
[' ::: nothing']);
});
it('should work at nonzero metalevel', function () {
checkPrettyPatch(Patch.assert([1, 2], 0),
[' < 1 2 > >{true}'],
['::: nothing']);
[' <2> 1 2 {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.assert([1, 2], 1),
[' < $AtMeta < 1 2 > > >{true}'],
['::: nothing']);
[' atMeta<1> <2> 1 2 {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.assert([1, 2], 2),
[' < $AtMeta < $AtMeta < 1 2 > > > >{true}'],
['::: nothing']);
[' atMeta<1> atMeta<1> <2> 1 2 {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.sub([1, 2], 0),
[' < $Observe < 1 2 > > >{true}'],
['::: nothing']);
[' observe<1> <2> 1 2 {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.sub([1, 2], 1),
[' < $AtMeta < $Observe < 1 2 > > > >{true}',
' $Observe < $AtMeta < 1 2 > > > >{true}'],
['::: nothing']);
[' atMeta<1> observe<1> <2> 1 2 {true}',
' observe<1> atMeta<1> <2> 1 2 {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.sub([1, 2], 2),
[' < $AtMeta < $AtMeta < $Observe < 1 2 > > > > >{true}',
' $Observe < $AtMeta < 1 2 > > > > >{true}',
' $Observe < $AtMeta < $AtMeta < 1 2 > > > > >{true}'],
['::: nothing']);
[' atMeta<1> atMeta<1> observe<1> <2> 1 2 {true}',
' observe<1> atMeta<1> <2> 1 2 {true}',
' observe<1> atMeta<1> atMeta<1> <2> 1 2 {true}'],
[' ::: nothing']);
});
});
describe('patch sequencing', function () {
it('should do the right thing in simple cases', function () {
checkPrettyPatch(Patch.assert(__).andThen(Patch.retract(3)),
[' ★ >{true}',
' 3::: nothing'],
[' 3 >{true}']);
[' ★ {true}',
' 3 ::: nothing'],
[' 3 {true}']);
checkPrettyPatch(Patch.assert(3).andThen(Patch.retract(__)),
['::: nothing'],
[' ★ >{true}']);
[' ::: nothing'],
[' ★ {true}']);
checkPrettyPatch(Patch.assert(__).andThen(Patch.retract(__)),
['::: nothing'],
[' ★ >{true}']);
[' ::: nothing'],
[' ★ {true}']);
checkPrettyPatch(Patch.assert(3).andThen(Patch.retract(3)),
['::: nothing'],
[' 3 >{true}']);
[' ::: nothing'],
[' 3 {true}']);
checkPrettyPatch(Patch.sub([1, __]).andThen(Patch.unsub([1, 2])),
[' < $Observe < 1 ★ > > >{true}',
' 2::: nothing'],
[' < $Observe < 1 2 > > >{true}']);
[' observe<1> <2> 1 ★ {true}',
' 2 ::: nothing'],
[' observe<1> <2> 1 2 {true}']);
checkPrettyPatch(Patch.sub([__, 2]).andThen(Patch.unsub([1, 2])),
[' < $Observe < ★ 2 > > >{true}',
' 1::: nothing'],
[' < $Observe < 1 2 > > >{true}']);
[' observe<1> <2> ★ 2 {true}',
' 1 ::: nothing'],
[' observe<1> <2> 1 2 {true}']);
checkPrettyPatch(Patch.sub([__, __]).andThen(Patch.unsub([1, 2])),
[' < $Observe < ★ ★ > > >{true}',
' 1 ★ > > >{true}',
' 2::: nothing'],
[' < $Observe < 1 2 > > >{true}']);
[' observe<1> <2> ★ ★ {true}',
' 1 ★ {true}',
' 2 ::: nothing'],
[' observe<1> <2> 1 2 {true}']);
});
it('works for longer chains of asserts and retracts', function () {
@ -99,11 +99,11 @@ describe('patch sequencing', function () {
.andThen(Patch.assert(4))
.andThen(Patch.retract(99));
checkPrettyPatch(rawPatch,
[' 1 >{true}',
' 4 >{true}'],
[' 2 >{true}',
' 3 >{true}',
' 99 >{true}']);
[' 1 {true}',
' 4 {true}'],
[' 2 {true}',
' 3 {true}',
' 99 {true}']);
});
});
@ -111,31 +111,31 @@ describe('patch sequencing', function () {
describe('patch lifting', function () {
it('should basically work', function () {
checkPrettyPatch(Patch.assert([1, 2]).lift(),
[' < $AtMeta < 1 2 > > >{true}'],
['::: nothing']);
[' atMeta<1> <2> 1 2 {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.sub([1, 2]).lift(),
[' < $AtMeta < $Observe < 1 2 > > > >{true}'],
['::: nothing']);
[' atMeta<1> observe<1> <2> 1 2 {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.assert([1, 2]).andThen(Patch.assert(Patch.atMeta([1, 2]))).lift(),
[' < $AtMeta < $AtMeta < 1 2 > > > >{true}',
' 1 2 > > >{true}'],
['::: nothing']);
[' atMeta<1> atMeta<1> <2> 1 2 {true}',
' <2> 1 2 {true}'],
[' ::: nothing']);
});
});
describe('patch dropping', function () {
it('should basically work', function () {
checkPrettyPatch(Patch.assert([1, 2]).drop(),
['::: nothing'],
['::: nothing']);
[' ::: nothing'],
[' ::: nothing']);
checkPrettyPatch(Patch.sub([1, 2]).drop(),
['::: nothing'],
['::: nothing']);
[' ::: nothing'],
[' ::: nothing']);
checkPrettyPatch(Patch.sub([1, 2], 1).drop(),
[' < $Observe < 1 2 > > >{true}'],
['::: nothing']);
[' observe<1> <2> 1 2 {true}'],
[' ::: nothing']);
checkPrettyPatch(Patch.assert([1, 2]).andThen(Patch.assert(Patch.atMeta([1, 2]))).drop(),
[' < 1 2 > >{true}'],
['::: nothing']);
[' <2> 1 2 {true}'],
[' ::: nothing']);
});
});

View File

@ -10,7 +10,20 @@ function checkPrettyTrie(m, expected) {
}
function checkTrieKeys(actual, expected) {
expect(actual.equals(Immutable.Set(expected).map(Immutable.List))).to.be(true);
expect(Immutable.is(actual, Immutable.Set(expected).map(Immutable.List))).to.be(true);
}
function checkProjectedObjects(actual, expected) {
actual = Immutable.Set(actual);
expected = Immutable.Set(expected);
actual.forEach(function (e) { c(expected, e) });
expected.forEach(function (e) { c(actual, e) });
function c(s, e1) {
if (!s.find(function (e2) { return expect.eql(e1, e2) })) {
throw new Error("Comparison failed: actual " + JSON.stringify(actual.toArray()) +
"; expected " + JSON.stringify(expected.toArray()));
}
}
}
describe("basic pattern compilation", function () {
@ -20,8 +33,8 @@ describe("basic pattern compilation", function () {
var mAAny = r.compilePattern(sAAny, ['A', r.__]);
it("should print as expected", function () {
checkPrettyTrie(mAny, [' ★ >{["mAny"]}']);
checkPrettyTrie(mAAny, [' < "A" ★ > >{["mAAny"]}']);
checkPrettyTrie(mAny, [' ★ {["mAny"]}']);
checkPrettyTrie(mAAny, [' <2> "A" ★ {["mAAny"]}']);
});
describe("of wildcard", function () {
@ -53,81 +66,78 @@ describe("unions", function () {
it("should collapse common prefix wildcard", function () {
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 'A']),
r.compilePattern(Immutable.Set(['B']), [r.__, 'B'])),
[' < ★ "A" > >{["A"]}',
' "B" > >{["B"]}']);
[' <2> ★ "A" {["A"]}',
' "B" {["B"]}']);
});
it("should unroll wildcard unioned with nonwildcard", function () {
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 'A']),
r.compilePattern(Immutable.Set(['W']), r.__)),
[' ★ >{["W"]}',
' < ★ "A" ★...> >{["W"]}',
' > >{["W","A"]}',
' ★...> >{["W"]}',
' > >{["W"]}',
' > >{["W"]}']);
[' ★ {["W"]}',
' <2> ★ ★ {["W"]}',
' "A" {["A","W"]}']);
});
it("should properly multiply out", function () {
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 2]),
r.compilePattern(Immutable.Set(['C']), [1, 3]),
r.compilePattern(Immutable.Set(['B']), [3, 4])),
[' < ★ 2 > >{["A"]}',
' 1 2 > >{["A"]}',
' 3 > >{["C"]}',
' 3 2 > >{["A"]}',
' 4 > >{["B"]}']);
[' <2> ★ 2 {["A"]}',
' 1 2 {["A"]}',
' 3 {["C"]}',
' 3 2 {["A"]}',
' 4 {["B"]}']);
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['C']), [1, 3]),
r.compilePattern(Immutable.Set(['B']), [3, 4])),
[' < 1 3 > >{["C"]}',
' 3 4 > >{["B"]}']);
[' <2> 1 3 {["C"]}',
' 3 4 {["B"]}']);
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 2]),
r.compilePattern(Immutable.Set(['C']), [1, 3])),
[' < ★ 2 > >{["A"]}',
' 1 2 > >{["A"]}',
' 3 > >{["C"]}']);
[' <2> ★ 2 {["A"]}',
' 1 2 {["A"]}',
' 3 {["C"]}']);
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 2]),
r.compilePattern(Immutable.Set(['B']), [3, 4])),
[' < ★ 2 > >{["A"]}',
' 3 2 > >{["A"]}',
' 4 > >{["B"]}']);
[' <2> ★ 2 {["A"]}',
' 3 2 {["A"]}',
' 4 {["B"]}']);
});
it("should correctly construct intermediate values", function () {
var MU = r.emptyTrie;
MU = r.union(MU, r.compilePattern(Immutable.Set(['A']), [r.__, 2]));
checkPrettyTrie(MU, [' < ★ 2 > >{["A"]}']);
checkPrettyTrie(MU, [' <2> ★ 2 {["A"]}']);
MU = r.union(MU, r.compilePattern(Immutable.Set(['C']), [1, 3]));
checkPrettyTrie(MU, [' < ★ 2 > >{["A"]}',
' 1 2 > >{["A"]}',
' 3 > >{["C"]}']);
checkPrettyTrie(MU, [' <2> ★ 2 {["A"]}',
' 1 2 {["A"]}',
' 3 {["C"]}']);
MU = r.union(MU, r.compilePattern(Immutable.Set(['B']), [3, 4]));
checkPrettyTrie(MU, [' < ★ 2 > >{["A"]}',
' 1 2 > >{["A"]}',
' 3 > >{["C"]}',
' 3 2 > >{["A"]}',
' 4 > >{["B"]}']);
checkPrettyTrie(MU, [' <2> ★ 2 {["A"]}',
' 1 2 {["A"]}',
' 3 {["C"]}',
' 3 2 {["A"]}',
' 4 {["B"]}']);
});
it("should handle identical patterns with different pids", function () {
var m = r.union(r.compilePattern(Immutable.Set('B'), [2]),
r.compilePattern(Immutable.Set('C'), [3]));
checkPrettyTrie(m, [' < 2 > >{["B"]}',
' 3 > >{["C"]}']);
checkPrettyTrie(m, [' <1> 2 {["B"]}',
' 3 {["C"]}']);
m = r.union(r.compilePattern(Immutable.Set('A'), [2]), m);
checkPrettyTrie(m, [' < 2 > >{["A","B"]}',
' 3 > >{["C"]}']);
checkPrettyTrie(m, [' <1> 2 {["A","B"]}',
' 3 {["C"]}']);
});
it('should work with subtraction and wildcards', function () {
var x = r.compilePattern(Immutable.Set(["A"]), [r.__]);
var y = r.compilePattern(Immutable.Set(["A"]), ["Y"]);
var z = r.compilePattern(Immutable.Set(["A"]), ["Z"]);
var expected = [' < "Y"::: nothing',
' ★ > >{["A"]}'];
var expected = [' <1> ★ {["A"]}',
' "Y" ::: nothing'];
checkPrettyTrie(r.subtract(r.union(x, z), y), expected);
checkPrettyTrie(r.union(r.subtract(x, y), z), expected);
});
@ -135,42 +145,42 @@ describe("unions", function () {
describe("projections", function () {
describe("with picky structure", function () {
var proj = r.compileProjection(r._$("v", [[r.__]]));
var proj = r._$("v", [[r.__]]);
it("should include things that match as well as wildcards", function () {
checkPrettyTrie(r.project(r.union(r.compilePattern(Immutable.Set(['A']), r.__),
r.compilePattern(Immutable.Set(['B']), [['b']])),
proj),
[' < < ★ > > >{["A"]}',
' "b" > > >{["A","B"]}']);
[' <1> <1> ★ {["A"]}',
' "b" {["A","B"]}']);
});
it("should exclude things that lack the required structure", function () {
checkPrettyTrie(r.project(r.union(r.compilePattern(Immutable.Set(['A']), r.__),
r.compilePattern(Immutable.Set(['B']), ['b'])),
proj),
[' < < ★ > > >{["A"]}']);
[' <1> <1> ★ {["A"]}']);
});
});
describe("simple positional", function () {
var proj = r.compileProjection([r._$, r._$]);
var proj = [r._$, r._$];
it("should collapse common prefixes", function () {
checkPrettyTrie(r.project(r.union(r.compilePattern(Immutable.Set(['A']), [1, 2]),
r.compilePattern(Immutable.Set(['C']), [1, 3]),
r.compilePattern(Immutable.Set(['B']), [3, 4])),
proj),
[' 1 2 >{["A"]}',
' 3 >{["C"]}',
' 3 4 >{["B"]}']);
[' 1 2 {["A"]}',
' 3 {["C"]}',
' 3 4 {["B"]}']);
});
it("should yield a correct set of results", function () {
var u = r.union(r.compilePattern(Immutable.Set(['A']), [1, 2]),
r.compilePattern(Immutable.Set(['C']), [1, 3]),
r.compilePattern(Immutable.Set(['B']), [3, 4]));
checkTrieKeys(r.trieKeys(r.project(u, proj)), [[1, 2], [1, 3], [3, 4]]);
checkTrieKeys(r.trieKeys(r.project(u, proj), 2), [[1, 2], [1, 3], [3, 4]]);
});
});
});
@ -179,29 +189,27 @@ describe("subtraction", function () {
it("should basically work", function () {
checkPrettyTrie(r.subtract(r.compilePattern(true, r.__),
r.compilePattern(true, 3),
function (v1, v2) { return null; }),
[" ★ >{true}",
" 3::: nothing"]);
function (v1, v2) { return r.emptyTrie; }),
[" ★ {true}",
" 3 ::: nothing"]);
checkPrettyTrie(r.subtract(r.compilePattern(true, r.__),
r.compilePattern(true, [3]),
function (v1, v2) { return null; }),
[" ★ >{true}",
" < ★...> >{true}",
" > >{true}",
" 3 ★...> >{true}",
" >::: nothing"]);
function (v1, v2) { return r.emptyTrie; }),
[" ★ {true}",
" <1> ★ {true}",
" 3 ::: nothing"]);
});
it("should be idempotent if the subtrahend doesn't overlap the minuend", function () {
checkPrettyTrie(r.compilePattern(true, 1),
[' 1 >{true}']);
[' 1 {true}']);
checkPrettyTrie(r.subtract(r.compilePattern(true, 1),
r.compilePattern(true, 2)),
[' 1 >{true}']);
[' 1 {true}']);
checkPrettyTrie(r.subtract(r.compilePattern(true, 1),
r.compilePattern(true, 2),
function (v1, v2) { return null; }),
[' 1 >{true}']);
[' 1 {true}']);
});
});
@ -211,11 +219,11 @@ describe("subtract after union", function () {
var R12 = r.union(R1, R2);
it("should have sane preconditions", function () { // Am I doing this right?
checkPrettyTrie(R1, [' < ★ "B" > >{["A"]}']);
checkPrettyTrie(R2, [' < "A" ★ > >{["B"]}']);
checkPrettyTrie(R12, [' < "A" "B" > >{["B","A"]}',
' ★ > >{["B"]}',
' ★ "B" > >{["A"]}']);
checkPrettyTrie(R1, [' <2> ★ "B" {["A"]}']);
checkPrettyTrie(R2, [' <2> "A" ★ {["B"]}']);
checkPrettyTrie(R12, [' <2> ★ "B" {["A"]}',
' "A" ★ {["B"]}',
' "B" {["A","B"]}']);
});
it("should yield the remaining ingredients of the union", function () {
@ -248,28 +256,30 @@ describe("trieKeys on wild tries", function () {
r.compilePattern(Immutable.Set(['C']), [1, 3]),
r.compilePattern(Immutable.Set(['B']), [3, 4]));
it("should yield null to signal an infinite result", function () {
expect(r.trieKeys(r.project(M, r.compileProjection([r._$, r._$])))).to.be(null);
it("should yield false to signal an infinite result", function () {
expect(r.trieKeys(r.project(M, [r._$, r._$]), 1)).to.be(false);
});
it("should extract just the second array element successfully", function () {
checkTrieKeys(r.trieKeys(r.project(M, r.compileProjection([r.__, r._$]))),
checkTrieKeys(r.trieKeys(r.project(M, [r.__, r._$]), 1),
[[2],[3],[4]]);
});
var M2 = r.project(M, r.compileProjection([r._$, r._$]));
var M2 = r.project(M, [r._$, r._$]);
it("should survive double-projection", function () {
checkTrieKeys(r.trieKeys(r.project(M2, r.compileProjection(r.__, r._$))),
checkTrieKeys(r.trieKeys(r.projectMany(M2, [r.__, r._$]), 1),
[[2],[3],[4]]);
});
it("should survive embedding and reprojection", function () {
checkTrieKeys(r.trieKeys(r.project(r.compilePattern(true, [r.embeddedTrie(M2)]),
r.compileProjection([r.__, r._$]))),
checkTrieKeys(r.trieKeys(r.project(r.compilePattern(Immutable.Set(['A']),
r.embeddedTrieArray(M2, 2)),
[r.__, r._$]), 1),
[[2],[3],[4]]);
checkTrieKeys(r.trieKeys(r.project(r.compilePattern(true, [[r.embeddedTrie(M2)]]),
r.compileProjection([[r.__, r._$]]))),
checkTrieKeys(r.trieKeys(r.project(r.compilePattern(Immutable.Set(['A']),
[r.embeddedTrieArray(M2, 2)]),
[[r.__, r._$]]), 1),
[[2],[3],[4]]);
});
});
@ -278,23 +288,24 @@ describe("trieKeys using multiple-values in projections", function () {
var M = r.union(r.compilePattern(Immutable.Set(['A']), [1, 2]),
r.compilePattern(Immutable.Set(['C']), [1, 3]),
r.compilePattern(Immutable.Set(['B']), [3, 4]));
var proj = r.compileProjection([r._$, r._$]);
var proj = [r._$, r._$];
var M2 = r.project(M, proj);
it("should be able to extract ordinary values", function () {
checkTrieKeys(r.trieKeys(M2), [[1,2],[1,3],[3,4]]);
checkTrieKeys(r.trieKeys(M2, 2), [[1,2],[1,3],[3,4]]);
});
it("should be able to be reprojected as a sequence of more than one value", function () {
checkTrieKeys(r.trieKeys(r.project(M2, r.compileProjection(r._$, r._$))),
checkTrieKeys(r.trieKeys(r.projectMany(M2, [r._$, r._$]), 2),
[[1,2],[1,3],[3,4]]);
});
it("should be convertible into objects with $-indexed fields", function () {
expect(r.trieKeysToObjects(r.trieKeys(M2), proj).toArray())
.to.eql([{'$0': 3, '$1': 4}, {'$0': 1, '$1': 2}, {'$0': 1, '$1': 3}]);
expect(r.projectObjects(M, proj).toArray())
.to.eql([{'$0': 3, '$1': 4}, {'$0': 1, '$1': 2}, {'$0': 1, '$1': 3}]);
var names = r.projectionNames(proj);
checkProjectedObjects(r.trieKeysToObjects(r.trieKeys(M2, names.length), names).toArray(),
[{'$0': 3, '$1': 4}, {'$0': 1, '$1': 2}, {'$0': 1, '$1': 3}]);
checkProjectedObjects(r.projectObjects(M, proj).toArray(),
[{'$0': 3, '$1': 4}, {'$0': 1, '$1': 2}, {'$0': 1, '$1': 3}]);
});
});
@ -304,15 +315,15 @@ describe("trieKeys using multiple-values in projections, with names", function (
r.compilePattern(Immutable.Set(['B']), [3, 4]));
it("should yield named fields", function () {
expect(r.projectObjects(M, r.compileProjection([r._$("fst"), r._$("snd")])).toArray())
.to.eql([{'fst': 3, 'snd': 4}, {'fst': 1, 'snd': 2}, {'fst': 1, 'snd': 3}]);
checkProjectedObjects(r.projectObjects(M, [r._$("fst"), r._$("snd")]).toArray(),
[{'fst': 3, 'snd': 4}, {'fst': 1, 'snd': 2}, {'fst': 1, 'snd': 3}]);
});
it("should yield numbered fields where names are missing", function () {
expect(r.projectObjects(M, r.compileProjection([r._$, r._$("snd")])).toArray())
.to.eql([{'$0': 3, 'snd': 4}, {'$0': 1, 'snd': 2}, {'$0': 1, 'snd': 3}]);
expect(r.projectObjects(M, r.compileProjection([r._$("fst"), r._$])).toArray())
.to.eql([{'fst': 3, '$1': 4}, {'fst': 1, '$1': 2}, {'fst': 1, '$1': 3}]);
checkProjectedObjects(r.projectObjects(M, [r._$, r._$("snd")]).toArray(),
[{'$0': 3, 'snd': 4}, {'$0': 1, 'snd': 2}, {'$0': 1, 'snd': 3}]);
checkProjectedObjects(r.projectObjects(M, [r._$("fst"), r._$]).toArray(),
[{'fst': 3, '$1': 4}, {'fst': 1, '$1': 2}, {'fst': 1, '$1': 3}]);
});
});
@ -393,47 +404,51 @@ describe("calls to matchPattern", function () {
var ctor = r.makeStructureConstructor('foo', ['bar', 'zot']);
expect(r.matchPattern(ctor(123, 234), ctor(r._$("bar"), r._$("zot"))))
.to.eql({ bar: 123, zot: 234, length: 2 });
// Previously, structures were roughly the same as arrays:
expect(r.matchPattern(["foo", 123, 234], ctor(r._$("bar"), r._$("zot"))))
.to.eql({ bar: 123, zot: 234, length: 2 });
.to.be(null);
expect(r.matchPattern(ctor(123, 234), ["foo", r._$("bar"), r._$("zot")]))
.to.eql({ bar: 123, zot: 234, length: 2 });
.to.be(null);
});
});
describe("Projection with no captures", function () {
it("should yield the empty sequence when there's a match", function () {
var emptySequence = [' >{["A"]}'];
var emptySequence = [' {["A"]}'];
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
r.compileProjection(r.__)),
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]), r.__),
emptySequence);
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
r.compileProjection([r.__, r.__])),
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]), [r.__, r.__]),
emptySequence);
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
r.compileProjection(["X", r.__])),
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]), ["X", r.__]),
emptySequence);
});
it("should yield the empty trie when there's no match", function () {
expect(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
r.compileProjection(["Y", r.__]))).to.be(r.emptyTrie);
["Y", r.__])).to.be(r.emptyTrie);
});
it("should yield nonempty sequences when there are captures after all", function () {
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
r.compileProjection([r.__, r._$])),
[' ★ >{["A"]}']);
[r.__, r._$]),
[' ★ {["A"]}']);
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
r.compileProjection([r._$, r._$])),
[' "X" ★ >{["A"]}']);
[r._$, r._$]),
[' "X" ★ {["A"]}']);
});
});
describe('trieStep', function () {
it('should expand wildcard when given SOA', function () {
expect(Immutable.is(r.trieStep(r.compilePattern(true, r.__), r.SOA),
r._testing.rwildseq(r._testing.rseq(r.EOA, r._testing.rsuccess(true)))))
expect(Immutable.is(r.trieStep(r.compilePattern(true, r.__), 0, r.SOA),
r._testing.rsuccess(true)))
.to.be(true);
expect(Immutable.is(r.trieStep(r.compilePattern(true, r.__), 1, r.SOA),
r._testing.rwild(r._testing.rsuccess(true))))
.to.be(true);
expect(Immutable.is(r.trieStep(r.compilePattern(true, r.__), 2, r.SOA),
r._testing.rwild(r._testing.rwild(r._testing.rsuccess(true)))))
.to.be(true);
});
});
@ -443,60 +458,61 @@ describe('intersect', function () {
var x = r.compilePattern(Immutable.Set([0]), ["fieldContents", r.__, r.__]);
var y = r.compilePattern(Immutable.Set([0]), ["fieldContents", "initial", 7]);
checkPrettyTrie(r.subtract(x, y), [
' < "fieldContents" ★ ★ > >{[0]}',
' "initial" ★ > >{[0]}',
' 7::: nothing']);
checkPrettyTrie(r.intersect(r.subtract(x, y), y), ['::: nothing']);
' <3> "fieldContents" ★ ★ {[0]}',
' "initial" ★ {[0]}',
' 7 ::: nothing']);
checkPrettyTrie(r.intersect(r.subtract(x, y), y), [' ::: nothing']);
});
});
describe('triePruneBranch', function () {
it('should not affect empty trie', function () {
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([r.SOA])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List(["x"])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([r.SOA, "x"])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([])), [' ::: nothing']);
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([r.SOA])), [' ::: nothing']);
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List(["x"])), [' ::: nothing']);
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([r.SOA, "x"])), [' ::: nothing']);
});
it('should leave a hole in a full trie', function () {
var full = r.compilePattern(true, r.__);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([r.SOA])),
[' ★ >{true}',
' <::: nothing']);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List(["x"])),
[' ★ >{true}',
' "x"::: nothing']);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([r.SOA, "x"])),
[' ★ >{true}',
' < ★...> >{true}',
' > >{true}',
' "x"::: nothing']);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([])), [' ::: nothing']);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([[0, r.SOA]])),
[' ★ {true}',
' <0> ::: nothing']);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([[0, "x"]])),
[' ★ {true}',
' "x" ::: nothing']);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([[2, r.SOA], [0, "x"]])),
[' ★ {true}',
' <2> ★ ★ {true}',
' "x" ::: nothing']);
});
it('should prune in a finite tree and leave the rest alone', function () {
var A = r.compilePattern(true, ["y"])
var B = r.union(r.compilePattern(true, ["x"]), A);
var C = r.union(r.compilePattern(true, "z"), B);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List(["z"])), [' < "y" > >{true}']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List(["z"])), [' < "x" > >{true}',
' "y" > >{true}']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List(["z"])), [' < "x" > >{true}',
' "y" > >{true}']);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([r.SOA])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([r.SOA])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([r.SOA])), [' "z" >{true}']);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([r.SOA, "x"])), [' < "y" > >{true}']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([r.SOA, "x"])), [' < "y" > >{true}']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([r.SOA, "x"])), [' < "y" > >{true}',
' "z" >{true}']);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([r.SOA, "y"])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([r.SOA, "y"])), [' < "x" > >{true}']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([r.SOA, "y"])), [' < "x" > >{true}',
' "z" >{true}']);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([])), [' ::: nothing']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([])), [' ::: nothing']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([])), [' ::: nothing']);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([[0, "z"]])), [' <1> "y" {true}']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([[0, "z"]])), [' <1> "x" {true}',
' "y" {true}']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([[0, "z"]])), [' <1> "x" {true}',
' "y" {true}']);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([[1, r.SOA]])), [' ::: nothing']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([[1, r.SOA]])), [' ::: nothing']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([[1, r.SOA]])), [' "z" {true}']);
var px = [[1, r.SOA], [0, "x"]];
checkPrettyTrie(r.triePruneBranch(A, Immutable.List(px)), [' <1> "y" {true}']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List(px)), [' <1> "y" {true}']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List(px)), [' "z" {true}',
' <1> "y" {true}']);
var py = [[1, r.SOA], [0, "y"]];
checkPrettyTrie(r.triePruneBranch(A, Immutable.List(py)), [' ::: nothing']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List(py)), [' <1> "x" {true}']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List(py)), [' "z" {true}',
' <1> "x" {true}']);
});
});
@ -520,7 +536,7 @@ describe('makeStructureConstructor', function () {
var ctor = r.makeStructureConstructor('foo', ['bar', 'zot']);
var inst = ctor(123, 234);
var x = r.compilePattern(sA, ctor(123, r.__));
checkPrettyTrie(x, [' < "foo" 123 ★ > >{["A"]}']);
checkPrettyTrie(x, [' foo<2> 123 ★ {["A"]}']);
expect(r.matchValue(x, ctor(123, 234))).to.eql(sA);
expect(r.matchValue(x, ctor(234, 123))).to.eql(null);
});

View File

@ -60,10 +60,9 @@ describe("configurationTrace", function() {
Dataspace.send(123);
Dataspace.send(234);
}, ['<<<<<<<< Removed:\n'+
'::: nothing\n'+
' ::: nothing\n'+
'======== Added:\n'+
' < $Observe ★ > >{[0]}\n'
+' >::: nothing\n'+
' observe<1> ★ {[0]}\n'+
'>>>>>>>>',
Syndicate.message(123),
Syndicate.message(234)]);
@ -84,9 +83,9 @@ describe("nonempty initial routes", function () {
handleEvent: traceEvent(trace)
});
}, ['<<<<<<<< Removed:\n'+
'::: nothing\n'+
' ::: nothing\n'+
'======== Added:\n'+
' < "A" ★ > >{[1]}\n'+
' <2> "A" ★ {[0]}\n'+
'>>>>>>>>']);
});
});
@ -104,14 +103,14 @@ describe("nested actor with an echoey protocol", function () {
});
}));
}, ['<<<<<<<< Removed:\n'+
'::: nothing\n'+
' ::: nothing\n'+
'======== Added:\n'+
' < $AtMeta "X" > >{[0]}\n'+
' atMeta<1> "X" {["meta"]}\n'+
'>>>>>>>>',
'<<<<<<<< Removed:\n'+
' < $AtMeta "X" > >{[0]}\n'+
' atMeta<1> "X" {["meta"]}\n'+
'======== Added:\n'+
'::: nothing\n'+
' ::: nothing\n'+
'>>>>>>>>']);
})
it("shouldn't see an echoed message", function () {
@ -120,7 +119,7 @@ describe("nested actor with an echoey protocol", function () {
Dataspace.spawn({
boot: function () {
Dataspace.send("X", 1); // happens after subs on next line!
return Patch.sub("X", 1);
return Patch.sub("X", 1);
},
handleEvent: traceEvent(trace)
});