Split and rename route.js into trie.js, struct.js and special.js

This commit is contained in:
Tony Garnock-Jones 2016-05-08 11:33:39 -04:00
parent 062e4603af
commit 9c5f427366
19 changed files with 216 additions and 198 deletions

View File

@ -8,7 +8,7 @@ Source files in `src/`, from most general to most specific:
- `util.js`: Functions `extend` and `kwApply`.
- `randomid.js`: Generation of (cryptographically) random base64 strings.
- `route.js`: Implementation of dataspace trie structure.
- `trie.js`: Implementation of dataspace trie structure.
- `patch.js`: Implementation of patches over dataspace tries.
- `mux.js`: Use of tries plus patches to build a (de)multiplexing routing structure.
- `dataspace.js`: Implementation of core leaf actors and dataspaces.

View File

@ -122,7 +122,7 @@ var modifiedSourceActions = {
var label = maybeLabel.numChildren === 1
? maybeLabel.children[0].interval.contents
: JSON.stringify(typeName.interval.contents);
return 'var ' + typeName.asES5 + ' = Syndicate.Route.makeStructureConstructor(' +
return 'var ' + typeName.asES5 + ' = Syndicate.Struct.makeStructureConstructor(' +
label + ', ' + JSON.stringify(formals) + ');';
},

View File

@ -1,6 +1,6 @@
"use strict";
var beep = Syndicate.Route.makeStructureConstructor('beep', ['counter']);
var beep = Syndicate.Struct.makeStructureConstructor('beep', ['counter']);
var G;
$(document).ready(function () {

View File

@ -2,15 +2,15 @@
// GUI
var Dataspace = Syndicate.Dataspace;
var Route = Syndicate.Route;
var Trie = Syndicate.Trie;
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']);
var fieldContents = Syndicate.Struct.makeStructureConstructor('fieldContents', ['text', 'pos']);
var highlight = Syndicate.Struct.makeStructureConstructor('highlight', ['state']);
var fieldCommand = Syndicate.Struct.makeStructureConstructor('fieldCommand', ['detail']);
function escapeText(text) {
text = text.replace(/&/g, '&');
@ -63,10 +63,10 @@ function spawnGui() {
}
break;
case "stateChange":
Route.projectObjects(e.patch.added, this.fieldContentsProjection).forEach(function (c) {
Trie.projectObjects(e.patch.added, this.fieldContentsProjection).forEach(function (c) {
self.field = c;
});
Route.projectObjects(e.patch.added, this.highlightProjection).forEach(function (c) {
Trie.projectObjects(e.patch.added, this.highlightProjection).forEach(function (c) {
self.highlight = c;
});
this.updateDisplay();
@ -160,7 +160,7 @@ function spawnSearch() {
this.search();
}
if (e.type === "stateChange") {
Route.projectObjects(e.patch.added, this.fieldContentsProjection).forEach(function (c) {
Trie.projectObjects(e.patch.added, this.fieldContentsProjection).forEach(function (c) {
self.fieldValue = c.text;
});
this.search();

View File

@ -2,10 +2,10 @@
var RandomID = require('./randomid.js');
var Dataspace = require('./dataspace.js').Dataspace;
var Route = require('./route.js');
var Struct = require('./struct.js');
var Patch = require('./patch.js');
var ack = Route.makeStructureConstructor('ack', ['id']);
var ack = Struct.makeStructureConstructor('ack', ['id']);
function Ack(metaLevel, id) {
this.metaLevel = metaLevel || 0;

View File

@ -4,7 +4,7 @@ var Immutable = require('immutable');
var Dataspace = require('./dataspace.js').Dataspace;
var Mux = require('./mux.js');
var Patch = require('./patch.js');
var Route = require('./route.js');
var Trie = require('./trie.js');
var Util = require('./util.js');
//---------------------------------------------------------------------------
@ -79,7 +79,7 @@ Facet.prototype.onEvent = function(isTerminal, eventType, subscriptionFn, projec
if (e.type === 'message') {
var proj = projectionFn.call(facet.actor.state);
var spec = Patch.prependAtMeta(proj.assertion, proj.metalevel);
var match = Route.matchPattern(e.message, spec);
var match = Trie.matchPattern(e.message, spec);
// console.log(match);
if (match) {
if (isTerminal) { facet.terminate(); }
@ -94,10 +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 objects = Route.projectObjects(eventType === 'asserted'
? e.patch.added
: e.patch.removed,
spec);
var objects = Trie.projectObjects(eventType === 'asserted'
? e.patch.added
: e.patch.removed,
spec);
if (objects && objects.size > 0) {
// console.log(objects.toArray());
if (isTerminal) { facet.terminate(); }

View File

@ -1,7 +1,6 @@
"use strict";
var Immutable = require('immutable');
var Route = require('./route.js');
var Patch = require('./patch.js');
var Mux = require('./mux.js');

View File

@ -1,5 +1,5 @@
var Immutable = require('immutable');
var Route = require('./route.js');
var Trie = require('./trie.js');
var Patch = require('./patch.js');
var Util = require('./util.js');
@ -18,12 +18,12 @@ function DemandMatcher(demandSpec, supplySpec, options) {
this.onSupplyDecrease = options.onSupplyDecrease;
this.demandSpec = demandSpec;
this.supplySpec = supplySpec;
this.demandPattern = Route.projectionToPattern(demandSpec);
this.supplyPattern = Route.projectionToPattern(supplySpec);
this.demandPattern = Trie.projectionToPattern(demandSpec);
this.supplyPattern = Trie.projectionToPattern(supplySpec);
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.demandProjectionNames = Trie.projectionNames(this.demandProjection);
this.supplyProjectionNames = Trie.projectionNames(this.supplyProjection);
this.currentDemand = Immutable.Set();
this.currentSupply = Immutable.Set();
}
@ -44,10 +44,10 @@ DemandMatcher.prototype.handlePatch = function (p) {
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);
var addedDemand = Trie.trieKeys(Trie.project(p.added, self.demandProjection), dN);
var removedDemand = Trie.trieKeys(Trie.project(p.removed, self.demandProjection), dN);
var addedSupply = Trie.trieKeys(Trie.project(p.added, self.supplyProjection), sN);
var removedSupply = Trie.trieKeys(Trie.project(p.removed, self.supplyProjection), sN);
if (addedDemand === null) {
throw new Error("Syndicate: wildcard demand detected:\n" +
@ -65,12 +65,12 @@ DemandMatcher.prototype.handlePatch = function (p) {
removedSupply.forEach(function (captures) {
if (self.currentDemand.has(captures)) {
self.onSupplyDecrease(Route.captureToObject(captures, self.supplyProjectionNames));
self.onSupplyDecrease(Trie.captureToObject(captures, self.supplyProjectionNames));
}
});
addedDemand.forEach(function (captures) {
if (!self.currentSupply.has(captures)) {
self.onDemandIncrease(Route.captureToObject(captures, self.demandProjectionNames));
self.onDemandIncrease(Trie.captureToObject(captures, self.demandProjectionNames));
}
});

View File

@ -1,7 +1,7 @@
// DOM fragment display driver
var Patch = require("./patch.js");
var DemandMatcher = require('./demand-matcher.js').DemandMatcher;
var Route = require('./route.js');
var Struct = require('./struct.js');
var Ack = require('./ack.js').Ack;
var Seal = require('./seal.js').Seal;
@ -10,7 +10,7 @@ var Dataspace = Dataspace_.Dataspace;
var __ = Dataspace_.__;
var _$ = Dataspace_._$;
var DOM = Route.makeStructureConstructor('DOM', ['selector', 'fragmentClass', 'fragmentSpec']);
var DOM = Struct.makeStructureConstructor('DOM', ['selector', 'fragmentClass', 'fragmentSpec']);
function spawnDOMDriver(domWrapFunction, jQueryWrapFunction) {
domWrapFunction = domWrapFunction || DOM;

View File

@ -1,14 +1,14 @@
// JQuery event driver
var Patch = require("./patch.js");
var DemandMatcher = require('./demand-matcher.js').DemandMatcher;
var Route = require('./route.js');
var Struct = require('./struct.js');
var Dataspace_ = require("./dataspace.js");
var Dataspace = Dataspace_.Dataspace;
var __ = Dataspace_.__;
var _$ = Dataspace_._$;
var jQueryEvent = Route.makeStructureConstructor('jQueryEvent', ['selector', 'eventName', 'eventValue']);
var jQueryEvent = Struct.makeStructureConstructor('jQueryEvent', ['selector', 'eventName', 'eventValue']);
function spawnJQueryDriver(baseSelector, metaLevel, wrapFunction) {
metaLevel = metaLevel || 0;

View File

@ -8,14 +8,15 @@ function copyKeys(keys, to, from) {
module.exports = require("./dataspace.js");
module.exports.Route = require("./route.js");
module.exports.Trie = require("./trie.js");
copyKeys(['__', '_$', '$Capture', '$Special',
'is_emptyTrie', 'emptyTrie',
'embeddedTrie', 'compilePattern',
'project', 'projectObjects',
'prettyTrie'],
module.exports,
module.exports.Route);
module.exports.Trie);
module.exports.Struct = require('./struct.js');
var Seal = require('./seal.js')
copyKeys(['Seal', 'seal'],

View File

@ -1,12 +1,12 @@
"use strict";
var Immutable = require('immutable');
var Route = require('./route.js');
var Trie = require('./trie.js');
var Patch = require('./patch.js');
function Mux(nextPid, routingTable, interestTable) {
this.nextPid = nextPid || 0;
this.routingTable = routingTable || Route.emptyTrie;
this.routingTable = routingTable || Trie.emptyTrie;
this.interestTable = interestTable || Immutable.Map(); // pid -> Trie
}
@ -33,7 +33,7 @@ Mux.prototype.updateStream = function (pid, unclampedPatch) {
this.routingTable = newRoutingTable;
if (Route.is_emptyTrie(newInterests)) {
if (Trie.is_emptyTrie(newInterests)) {
this.interestTable = this.interestTable.remove(pid);
} else {
this.interestTable = this.interestTable.set(pid, newInterests);
@ -44,13 +44,13 @@ Mux.prototype.updateStream = function (pid, unclampedPatch) {
deltaAggregate: deltaAggregate };
};
var atMetaEverything = Route.compilePattern(true, Patch.atMeta(Route.__));
var atMetaEverything = Trie.compilePattern(true, Patch.atMeta(Trie.__));
var atMetaBranchKeys = Immutable.List([[Patch.atMeta.meta.arguments.length, Patch.atMeta.meta]]);
var onlyMeta = Route.trieSuccess(Immutable.Set.of("meta"));
var onlyMeta = Trie.trieSuccess(Immutable.Set.of("meta"));
function echoCancelledTrie(t) {
return Route.subtract(t, atMetaEverything, function (v1, v2) {
return v1.has("meta") ? onlyMeta : Route.emptyTrie;
return Trie.subtract(t, atMetaEverything, function (v1, v2) {
return v1.has("meta") ? onlyMeta : Trie.emptyTrie;
});
}
@ -60,8 +60,8 @@ function computeEvents(oldMux, newMux, updateStreamResult) {
var deltaAggregate = updateStreamResult.deltaAggregate;
var deltaAggregateNoEcho = (actingPid === "meta")
? delta // because echo-cancellation means that meta-SCNs are always new information
: new Patch.Patch(Route.triePruneBranch(deltaAggregate.added, atMetaBranchKeys),
Route.triePruneBranch(deltaAggregate.removed, atMetaBranchKeys));
: new Patch.Patch(Trie.triePruneBranch(deltaAggregate.added, atMetaBranchKeys),
Trie.triePruneBranch(deltaAggregate.removed, atMetaBranchKeys));
var oldRoutingTable = oldMux.routingTable;
var newRoutingTable = newMux.routingTable;
var affectedPids =
@ -94,16 +94,16 @@ function computeEvents(oldMux, newMux, updateStreamResult) {
}
function computeAffectedPids(routingTable, delta) {
var cover = Route._union(delta.added, delta.removed);
var cover = Trie._union(delta.added, delta.removed);
routingTable =
Route.trieStep(routingTable, Patch.observe.meta.arguments.length, Patch.observe.meta);
return Route.matchTrie(cover, routingTable, Immutable.Set(),
function (v1, v2, acc) { return acc.union(v2); });
Trie.trieStep(routingTable, Patch.observe.meta.arguments.length, Patch.observe.meta);
return Trie.matchTrie(cover, routingTable, Immutable.Set(),
function (v1, v2, acc) { return acc.union(v2); });
}
Mux.prototype.routeMessage = function (body) {
if (Route.matchValue(this.routingTable, body) === null) {
return Route.matchValue(this.routingTable, Patch.observe(body)) || Immutable.Set();
if (Trie.matchValue(this.routingTable, body) === null) {
return Trie.matchValue(this.routingTable, Patch.observe(body)) || Immutable.Set();
} else {
// Some other stream has declared body
return Immutable.Set();
@ -111,7 +111,7 @@ Mux.prototype.routeMessage = function (body) {
};
Mux.prototype.interestsOf = function (pid) {
return this.interestTable.get(pid, Route.emptyTrie);
return this.interestTable.get(pid, Trie.emptyTrie);
};
///////////////////////////////////////////////////////////////////////////

View File

@ -1,23 +1,24 @@
"use strict";
var Route = require("./route.js");
var Trie = require("./trie.js");
var Struct = require("./struct.js");
var Immutable = require("immutable");
var __ = Route.__;
var _$ = Route._$;
var __ = Trie.__;
var _$ = Trie._$;
function Patch(added, removed) {
this.added = added;
this.removed = removed;
}
var emptyPatch = new Patch(Route.emptyTrie, Route.emptyTrie);
var removeEverythingPatch = new Patch(Route.emptyTrie, Route.compilePattern(true, __));
var trueLabel = Route.trieSuccess(true);
var emptyPatch = new Patch(Trie.emptyTrie, Trie.emptyTrie);
var removeEverythingPatch = new Patch(Trie.emptyTrie, Trie.compilePattern(true, __));
var trueLabel = Trie.trieSuccess(true);
var observe = Route.makeStructureConstructor('observe', ['assertion']);
var atMeta = Route.makeStructureConstructor('atMeta', ['assertion']);
var advertise = Route.makeStructureConstructor('advertise', ['assertion']);
var observe = Struct.makeStructureConstructor('observe', ['assertion']);
var atMeta = Struct.makeStructureConstructor('atMeta', ['assertion']);
var advertise = Struct.makeStructureConstructor('advertise', ['assertion']);
function prependAtMeta(p, level) {
while (level--) {
@ -39,11 +40,11 @@ function stripAtMeta(p, level) {
function observeAtMeta(p, level) {
if (level === 0) {
return Route.compilePattern(true, observe(p));
return Trie.compilePattern(true, observe(p));
} else {
return Route._union(
Route.compilePattern(true, observe(prependAtMeta(p, level))),
Route.compilePattern(true, atMeta(Route.embeddedTrie(observeAtMeta(p, level - 1)))));
return Trie._union(
Trie.compilePattern(true, observe(prependAtMeta(p, level))),
Trie.compilePattern(true, atMeta(Trie.embeddedTrie(observeAtMeta(p, level - 1)))));
}
}
@ -55,21 +56,21 @@ function _check(p) {
}
function assert(p, metaLevel) {
return new Patch(Route.compilePattern(true, prependAtMeta(_check(p), metaLevel || 0)),
Route.emptyTrie);
return new Patch(Trie.compilePattern(true, prependAtMeta(_check(p), metaLevel || 0)),
Trie.emptyTrie);
}
function retract(p, metaLevel) {
return new Patch(Route.emptyTrie,
Route.compilePattern(true, prependAtMeta(_check(p), metaLevel || 0)));
return new Patch(Trie.emptyTrie,
Trie.compilePattern(true, prependAtMeta(_check(p), metaLevel || 0)));
}
function sub(p, metaLevel) {
return new Patch(observeAtMeta(_check(p), metaLevel || 0), Route.emptyTrie);
return new Patch(observeAtMeta(_check(p), metaLevel || 0), Trie.emptyTrie);
}
function unsub(p, metaLevel) {
return new Patch(Route.emptyTrie, observeAtMeta(_check(p), metaLevel || 0));
return new Patch(Trie.emptyTrie, observeAtMeta(_check(p), metaLevel || 0));
}
function pub(p, metaLevel) {
@ -88,7 +89,7 @@ Patch.prototype.equals = function (other) {
};
Patch.prototype.isEmpty = function () {
return this.added === Route.emptyTrie && this.removed === Route.emptyTrie;
return this.added === Trie.emptyTrie && this.removed === Trie.emptyTrie;
};
Patch.prototype.isNonEmpty = function () {
@ -96,89 +97,89 @@ Patch.prototype.isNonEmpty = function () {
};
Patch.prototype.hasAdded = function () {
return this.added !== Route.emptyTrie;
return this.added !== Trie.emptyTrie;
};
Patch.prototype.hasRemoved = function () {
return this.removed !== Route.emptyTrie;
return this.removed !== Trie.emptyTrie;
};
Patch.prototype.lift = function () {
return new Patch(Route.compilePattern(true, atMeta(Route.embeddedTrie(this.added))),
Route.compilePattern(true, atMeta(Route.embeddedTrie(this.removed))));
return new Patch(Trie.compilePattern(true, atMeta(Trie.embeddedTrie(this.added))),
Trie.compilePattern(true, atMeta(Trie.embeddedTrie(this.removed))));
};
var atMetaProj = atMeta(_$);
Patch.prototype.drop = function () {
return new Patch(Route.project(this.added, atMetaProj),
Route.project(this.removed, atMetaProj));
return new Patch(Trie.project(this.added, atMetaProj),
Trie.project(this.removed, atMetaProj));
};
Patch.prototype.strip = function () {
return new Patch(Route.relabel(this.added, function (v) { return true; }),
Route.relabel(this.removed, function (v) { return true; }));
return new Patch(Trie.relabel(this.added, function (v) { return true; }),
Trie.relabel(this.removed, function (v) { return true; }));
};
Patch.prototype.label = function (labelValue) {
return new Patch(Route.relabel(this.added, function (v) { return labelValue; }),
Route.relabel(this.removed, function (v) { return labelValue; }));
return new Patch(Trie.relabel(this.added, function (v) { return labelValue; }),
Trie.relabel(this.removed, function (v) { return labelValue; }));
};
Patch.prototype.limit = function (bound) {
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); }));
return new Patch(Trie.subtract(this.added, bound, function (v1, v2) { return Trie.emptyTrie; }),
Trie.intersect(this.removed, bound,
function (v1, v2) { return Trie.trieSuccess(v1); }));
};
var metaLabelSet = Immutable.Set(["meta"]);
Patch.prototype.computeAggregate = function (label, base, removeMeta /* optional flag */) {
return new Patch(Route.subtract(this.added, base, addCombiner),
Route.subtract(this.removed, base, removeCombiner));
return new Patch(Trie.subtract(this.added, base, addCombiner),
Trie.subtract(this.removed, base, removeCombiner));
function addCombiner(v1, v2) {
if (removeMeta && Immutable.is(v2, metaLabelSet)) {
return Route.trieSuccess(v1);
return Trie.trieSuccess(v1);
} else {
return Route.emptyTrie;
return Trie.emptyTrie;
}
}
function removeCombiner(v1, v2) {
if (v2.size === 1) {
return Route.trieSuccess(v1);
return Trie.trieSuccess(v1);
} else {
if (removeMeta && v2.size === 2 && v2.has("meta")) {
return Route.trieSuccess(v1);
return Trie.trieSuccess(v1);
} else {
return Route.emptyTrie;
return Trie.emptyTrie;
}
}
}
};
Patch.prototype.applyTo = function (base) {
return Route._union(Route.subtract(base, this.removed), this.added);
return Trie._union(Trie.subtract(base, this.removed), this.added);
};
Patch.prototype.updateInterests = function (base) {
return Route._union(Route.subtract(base,
this.removed,
function (v1, v2) { return Route.emptyTrie; }),
this.added,
function (v1, v2) { return trueLabel; });
return Trie._union(Trie.subtract(base,
this.removed,
function (v1, v2) { return Trie.emptyTrie; }),
this.added,
function (v1, v2) { return trueLabel; });
};
Patch.prototype.unapplyTo = function (base) {
return Route._union(Route.subtract(base, this.added), this.removed);
return Trie._union(Trie.subtract(base, this.added), this.removed);
};
Patch.prototype.andThen = function (nextPatch) {
return new Patch(nextPatch.updateInterests(this.added),
Route._union(Route.subtract(this.removed,
nextPatch.added,
function (v1, v2) { return Route.emptyTrie; }),
nextPatch.removed,
function (v1, v2) { return trueLabel; }));
Trie._union(Trie.subtract(this.removed,
nextPatch.added,
function (v1, v2) { return Trie.emptyTrie; }),
nextPatch.removed,
function (v1, v2) { return trueLabel; }));
};
function patchSeq(/* patch, patch, ... */) {
@ -190,13 +191,13 @@ function patchSeq(/* patch, patch, ... */) {
}
function computePatch(oldBase, newBase) {
return new Patch(Route.subtract(newBase, oldBase),
Route.subtract(oldBase, newBase));
return new Patch(Trie.subtract(newBase, oldBase),
Trie.subtract(oldBase, newBase));
}
function biasedIntersection(object, subject) {
subject = Route.trieStep(subject, observe.meta.arguments.length, observe.meta);
return Route.intersect(object, subject, function (v1, v2) { return Route.trieSuccess(v1); });
subject = Trie.trieStep(subject, observe.meta.arguments.length, observe.meta);
return Trie.intersect(object, subject, function (v1, v2) { return Trie.trieSuccess(v1); });
}
Patch.prototype.viewFrom = function (interests) {
@ -207,23 +208,23 @@ Patch.prototype.viewFrom = function (interests) {
Patch.prototype.unsafeUnion = function (other) {
// Unsafe because does not necessarily preserve invariant that added
// and removed are disjoint.
return new Patch(Route._union(this.added, other.added),
Route._union(this.removed, other.removed));
return new Patch(Trie._union(this.added, other.added),
Trie._union(this.removed, other.removed));
};
Patch.prototype.project = function (compiledProjection) {
return new Patch(Route.project(this.added, compiledProjection),
Route.project(this.removed, compiledProjection));
return new Patch(Trie.project(this.added, compiledProjection),
Trie.project(this.removed, compiledProjection));
};
Patch.prototype.projectObjects = function (compiledProjection) {
return [Route.projectObjects(this.added, compiledProjection),
Route.projectObjects(this.removed, compiledProjection)];
return [Trie.projectObjects(this.added, compiledProjection),
Trie.projectObjects(this.removed, compiledProjection)];
};
Patch.prototype.pretty = function () {
return ("<<<<<<<< Removed:\n" + Route.prettyTrie(this.removed) + "\n" +
"======== Added:\n" + Route.prettyTrie(this.added) + "\n" +
return ("<<<<<<<< Removed:\n" + Trie.prettyTrie(this.removed) + "\n" +
"======== Added:\n" + Trie.prettyTrie(this.added) + "\n" +
">>>>>>>>");
}

8
js/src/special.js Normal file
View File

@ -0,0 +1,8 @@
"use strict";
// $Special: Builder of singleton "atoms".
function $Special(name) {
this.name = name;
}
module.exports = $Special;

60
js/src/struct.js Normal file
View File

@ -0,0 +1,60 @@
"use strict";
// "Structures": Simple named-tuple-like records.
// TODO: shore up $SyndicateMeta$, making it a proper object
var Immutable = require("immutable");
var $Special = require('./special.js');
/* Defined here rather than in trie.js because we need it in makeStructureConstructor. */
var __ = new $Special("wildcard"); /* wildcard marker */
function instantiateStructure($SyndicateMeta$, argvals) {
var result = {"$SyndicateMeta$": $SyndicateMeta$};
var argnames = $SyndicateMeta$.arguments;
for (var i = 0; i < argnames.length; i++) {
result[argnames[i]] = argvals[i];
}
return result;
}
function makeStructureConstructor(label, argumentNames) {
var $SyndicateMeta$ = {
label: label,
arguments: argumentNames
};
var ctor = function() {
return instantiateStructure($SyndicateMeta$, arguments);
};
ctor.meta = $SyndicateMeta$;
ctor.isClassOf = function (v) { return v && v.$SyndicateMeta$ === $SyndicateMeta$; };
ctor.pattern = ctor.apply(null, Immutable.Repeat(__, argumentNames.length).toArray());
return ctor;
}
function isSyndicateMeta(m) {
// TODO: include more structure in $SyndicateMeta$ objects to make
// this judgement less sloppy.
return m && m.label && Array.isArray(m.arguments);
}
function isStructure(s) {
return (s !== null) && (typeof s === 'object') && ("$SyndicateMeta$" in s);
}
function structureToArray(s, excludeLabel) {
var result = excludeLabel ? [] : [s.$SyndicateMeta$.label];
var args = s.$SyndicateMeta$.arguments;
for (var i = 0; i < args.length; i++) {
result.push(s[args[i]]);
}
return result;
}
///////////////////////////////////////////////////////////////////////////
module.exports.__ = __;
module.exports.instantiateStructure = instantiateStructure;
module.exports.makeStructureConstructor = makeStructureConstructor;
module.exports.isSyndicateMeta = isSyndicateMeta;
module.exports.isStructure = isStructure;
module.exports.structureToArray = structureToArray;

View File

@ -1,62 +1,8 @@
"use strict";
var Immutable = require("immutable");
///////////////////////////////////////////////////////////////////////////
// "Structures": Simple named-tuple-like records.
// TODO: shore up $SyndicateMeta$, making it a proper object
function instantiateStructure($SyndicateMeta$, argvals) {
var result = {"$SyndicateMeta$": $SyndicateMeta$};
var argnames = $SyndicateMeta$.arguments;
for (var i = 0; i < argnames.length; i++) {
result[argnames[i]] = argvals[i];
}
return result;
}
function makeStructureConstructor(label, argumentNames) {
var $SyndicateMeta$ = {
label: label,
arguments: argumentNames
};
var ctor = function() {
return instantiateStructure($SyndicateMeta$, arguments);
};
ctor.meta = $SyndicateMeta$;
ctor.isClassOf = function (v) { return v && v.$SyndicateMeta$ === $SyndicateMeta$; };
ctor.pattern = ctor.apply(null, Immutable.Repeat(__, argumentNames.length).toArray());
return ctor;
}
function isSyndicateMeta(m) {
// TODO: include more structure in $SyndicateMeta$ objects to make
// this judgement less sloppy.
return m && m.label && Array.isArray(m.arguments);
}
function isStructure(s) {
return (s !== null) && (typeof s === 'object') && ("$SyndicateMeta$" in s);
}
function structureToArray(s, excludeLabel) {
var result = excludeLabel ? [] : [s.$SyndicateMeta$.label];
var args = s.$SyndicateMeta$.arguments;
for (var i = 0; i < args.length; i++) {
result.push(s[args[i]]);
}
return result;
}
///////////////////////////////////////////////////////////////////////////
// $Special: Builder of singletons.
function $Special(name) {
this.name = name;
}
///////////////////////////////////////////////////////////////////////////
// Misc. utilities
var Struct = require('./struct.js');
var $Special = require('./special.js');
function die(message) {
throw new Error(message);
@ -100,7 +46,7 @@ $Branch.prototype.equals = function (other) {
///////////////////////////////////////////////////////////////////////////
// Patterns, projections and captures
var __ = new $Special("wildcard"); /* wildcard marker */
var __ = Struct.__; /* imported rather than defined here because of cyclic dep in Struct */
var SOA = new $Special("array"); /* key for start-of-array */
function $Embedded(trie, arrayLength) {
@ -239,7 +185,7 @@ function compilePattern(v, p) {
return rseq(p.size, SOA, acc);
}
if (isStructure(p)) {
if (Struct.isStructure(p)) {
var args = p.$SyndicateMeta$.arguments;
for (var i = args.length - 1; i >= 0; i--) {
acc = walk(p[args[i]], acc);
@ -276,7 +222,10 @@ function matchPattern(v, p) {
if (p === __) return;
if (isStructure(p) && isStructure(v) && (p.$SyndicateMeta$ === v.$SyndicateMeta$)) {
if (Struct.isStructure(p)
&& Struct.isStructure(v)
&& (p.$SyndicateMeta$ === v.$SyndicateMeta$))
{
var args = p.$SyndicateMeta$.arguments;
for (var i = 0; i < args.length; i++) {
walk(v[args[i]], p[args[i]]);
@ -481,9 +430,9 @@ function matchValue(r, v, failureResultOpt) {
if (Array.isArray(v)) {
r = rlookup(r, v.length, SOA);
vs = Immutable.List(v).concat(vs);
} else if (isStructure(v)) {
} else if (Struct.isStructure(v)) {
r = rlookup(r, v.$SyndicateMeta$.arguments.length, v.$SyndicateMeta$);
vs = Immutable.List(structureToArray(v, true)).concat(vs);
vs = Immutable.List(Struct.structureToArray(v, true)).concat(vs);
} else {
r = rlookup(r, 0, v);
}
@ -600,7 +549,7 @@ function projectionNames(p) {
return;
}
if (isStructure(p)) {
if (Struct.isStructure(p)) {
var args = p.$SyndicateMeta$.arguments;
for (var i = 0; i < args.length; i++) walk(p[args[i]]);
return;
@ -626,7 +575,7 @@ function projectionToPattern(p) {
return result;
}
if (isStructure(p)) {
if (Struct.isStructure(p)) {
var result = {"$SyndicateMeta$": p.$SyndicateMeta$};
var args = p.$SyndicateMeta$.arguments;
for (var i = 0; i < args.length; i++) {
@ -702,12 +651,12 @@ function projectMany(t, wholeSpecs, projectSuccessOpt, combinerOpt) {
return target;
}
if (isStructure(spec)) {
if (Struct.isStructure(spec)) {
var arity = spec.$SyndicateMeta$.arguments.length;
var key = spec.$SyndicateMeta$;
var intermediate = walk(isCapturing,
rlookup(t, arity, key),
Immutable.List(structureToArray(spec, true)),
Immutable.List(Struct.structureToArray(spec, true)),
function (intermediate) {
return walk(isCapturing, intermediate, specsRest, kont);
});
@ -738,14 +687,14 @@ function reconstructSequence(key, items) {
if (key === SOA) {
return items.toArray();
} else {
return instantiateStructure(key, items);
return Struct.instantiateStructure(key, items);
}
}
function trieKeys(m, takeCount0) {
if (typeof takeCount0 !== 'number') {
// Cope with API change which would otherwise silently cause problems
die("Missing mandatory argument 'takeCount' to Route.trieKeys");
die("Missing mandatory argument 'takeCount' to Trie.trieKeys");
}
if (is_emptyTrie(m)) return Immutable.Set();
@ -773,7 +722,7 @@ function trieKeys(m, takeCount0) {
if (result === false) return false; // break out of iteration
var piece;
if (isSyndicateMeta(key) || key === SOA) { // TODO: this is sloppy
if (Struct.isSyndicateMeta(key) || key === SOA) { // TODO: this is sloppy
piece = walk(k, arity, Immutable.List(), function (items, m1) {
var item = reconstructSequence(key, items);
return walk(m1, takeCount - 1, valsRev.unshift(item), kont);
@ -849,7 +798,7 @@ function prettyTrie(m, initialIndent) {
}
acc.push(" ");
if (key === SOA) key = '<' + arity + '>';
else if (isSyndicateMeta(key)) key = key.label + '<' + arity + '>';
else if (Struct.isSyndicateMeta(key)) key = key.label + '<' + arity + '>';
else if (key instanceof $Special) key = key.name;
else if (typeof key === 'undefined') key = 'undefined';
else key = JSON.stringify(key);
@ -870,7 +819,6 @@ module.exports.__ = __;
module.exports.SOA = SOA;
module.exports.$Capture = $Capture;
module.exports.$Special = $Special;
module.exports.makeStructureConstructor = makeStructureConstructor;
module.exports._$ = _$;
module.exports.is_emptyTrie = is_emptyTrie;
module.exports.emptyTrie = emptyTrie;

View File

@ -3,15 +3,15 @@
var expect = require('expect.js');
var Immutable = require('immutable');
var Route = require('../src/route.js');
var Trie = require('../src/trie.js');
var Patch = require('../src/patch.js');
var Mux = require('../src/mux.js');
var __ = Route.__;
var _$ = Route._$;
var __ = Trie.__;
var _$ = Trie._$;
function checkPrettyTrie(m, expected) {
expect(Route.prettyTrie(m)).to.equal(expected.join('\n'));
expect(Trie.prettyTrie(m)).to.equal(expected.join('\n'));
}
function checkPrettyPatch(p, expectedAdded, expectedRemoved) {

View File

@ -3,11 +3,11 @@
var expect = require('expect.js');
var Immutable = require('immutable');
var Route = require('../src/route.js');
var Trie = require('../src/trie.js');
var Patch = require('../src/patch.js');
var __ = Route.__;
var _$ = Route._$;
var __ = Trie.__;
var _$ = Trie._$;
function checkPrettyPatch(p, expectedAdded, expectedRemoved) {
expect(p.pretty()).to.equal(

View File

@ -3,7 +3,8 @@
var Immutable = require('immutable');
var expect = require('expect.js');
var util = require('util');
var r = require("../src/route.js");
var Struct = require("../src/struct.js");
var r = require("../src/trie.js");
function checkPrettyTrie(m, expected) {
expect(r.prettyTrie(m)).to.equal(expected.join('\n'));
@ -401,7 +402,7 @@ describe("calls to matchPattern", function () {
});
it("matches structures", function () {
var ctor = r.makeStructureConstructor('foo', ['bar', 'zot']);
var ctor = Struct.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:
@ -518,14 +519,14 @@ describe('triePruneBranch', function () {
describe('makeStructureConstructor', function () {
it('should produce the right metadata', function () {
var ctor = r.makeStructureConstructor('foo', ['bar', 'zot']);
var ctor = Struct.makeStructureConstructor('foo', ['bar', 'zot']);
var inst = ctor(123, 234);
expect(inst.$SyndicateMeta$.label).to.equal('foo');
expect(inst.$SyndicateMeta$.arguments).to.eql(['bar', 'zot']);
});
it('should produce the right instance data', function () {
var ctor = r.makeStructureConstructor('foo', ['bar', 'zot']);
var ctor = Struct.makeStructureConstructor('foo', ['bar', 'zot']);
var inst = ctor(123, 234);
expect(inst.bar).to.equal(123);
expect(inst.zot).to.equal(234);
@ -533,7 +534,7 @@ describe('makeStructureConstructor', function () {
it('should work with compilePattern and matchValue', function () {
var sA = Immutable.Set(["A"]);
var ctor = r.makeStructureConstructor('foo', ['bar', 'zot']);
var ctor = Struct.makeStructureConstructor('foo', ['bar', 'zot']);
var inst = ctor(123, 234);
var x = r.compilePattern(sA, ctor(123, r.__));
checkPrettyTrie(x, [' foo<2> 123 ★ {["A"]}']);