makeStructureConstructor
This commit is contained in:
parent
f675f91719
commit
21fd0f574a
|
@ -2,6 +2,20 @@
|
|||
|
||||
var Immutable = require("immutable");
|
||||
|
||||
function makeStructureConstructor(label, argumentNames) {
|
||||
var $SyndicateMeta$ = {
|
||||
label: label,
|
||||
arguments: argumentNames
|
||||
};
|
||||
return function() {
|
||||
var result = {"$SyndicateMeta$": $SyndicateMeta$};
|
||||
for (var i = 0; i < argumentNames.length; i++) {
|
||||
result[argumentNames[i]] = arguments[i];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
function $Special(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
@ -111,6 +125,16 @@ function compilePattern(v, p) {
|
|||
return rseq(SOA, acc);
|
||||
}
|
||||
|
||||
if (p.$SyndicateMeta$) {
|
||||
var args = p.$SyndicateMeta$.arguments;
|
||||
acc = rseq(EOA, acc);
|
||||
for (var i = args.length - 1; i >= 0; i--) {
|
||||
acc = walk(p[args[i]], acc);
|
||||
}
|
||||
acc = rseq(p.$SyndicateMeta$.label, acc);
|
||||
return rseq(SOA, acc);
|
||||
}
|
||||
|
||||
if (p instanceof $Embedded) {
|
||||
return appendTrie(p.trie, function (v) { return acc; });
|
||||
} else {
|
||||
|
@ -119,45 +143,6 @@ function compilePattern(v, p) {
|
|||
}
|
||||
}
|
||||
|
||||
function matchPattern(v, p) {
|
||||
var captureCount = 0;
|
||||
var result = {};
|
||||
try {
|
||||
walk(v, p);
|
||||
} catch (e) {
|
||||
if (e.matchPatternFailed) return null;
|
||||
throw e;
|
||||
}
|
||||
result.length = captureCount;
|
||||
return result;
|
||||
|
||||
function walk(v, p) {
|
||||
if (p === v) return;
|
||||
|
||||
if (p === __) return;
|
||||
|
||||
if (Array.isArray(p) && Array.isArray(v) && p.length === v.length) {
|
||||
for (var i = 0; i < p.length; i++) {
|
||||
walk(v[i], p[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCapture(p)) {
|
||||
var thisCapture = captureCount++;
|
||||
walk(v, capturePattern(p));
|
||||
result[captureName(p) || ('$' + thisCapture)] = v;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p instanceof $Embedded) {
|
||||
die("$Embedded patterns not supported in matchPattern()");
|
||||
}
|
||||
|
||||
throw {matchPatternFailed: true};
|
||||
}
|
||||
}
|
||||
|
||||
function rupdate(r, key, k) {
|
||||
var oldWild = r.get(__, emptyTrie);
|
||||
if (Immutable.is(k, oldWild)) {
|
||||
|
@ -498,6 +483,18 @@ function matchValue(r, v) {
|
|||
} else {
|
||||
r = rlookup(r, __);
|
||||
}
|
||||
} else if (v.$SyndicateMeta$) {
|
||||
if (r.has(SOA)) {
|
||||
r = rlookup(r, SOA);
|
||||
stack.push(vs);
|
||||
vs = Immutable.List.of(v.$SyndicateMeta$.label);
|
||||
var args = v.$SyndicateMeta$.arguments;
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
vs = vs.push(v[args[i]]);
|
||||
}
|
||||
} else {
|
||||
r = rlookup(r, __);
|
||||
}
|
||||
} else {
|
||||
if (r.has(v)) {
|
||||
r = rlookup(r, v);
|
||||
|
@ -683,6 +680,17 @@ function compileProjection(/* projection, projection, ... */) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (p.$SyndicateMeta$) {
|
||||
acc.push(SOA);
|
||||
acc.push(p.$SyndicateMeta$.label);
|
||||
var args = p.$SyndicateMeta$.arguments;
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
walk(p[args[i]]);
|
||||
}
|
||||
acc.push(EOA);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p instanceof $Embedded) {
|
||||
die("Cannot embed trie in projection");
|
||||
} else {
|
||||
|
@ -705,6 +713,15 @@ function projectionToPattern(p) {
|
|||
return result;
|
||||
}
|
||||
|
||||
if (p.$SyndicateMeta$) {
|
||||
var result = {"$SyndicateMeta$": p.$SyndicateMeta$};
|
||||
var args = p.$SyndicateMeta$.arguments;
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
result[args[i]] = walk(p[args[i]]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (p instanceof $Embedded) {
|
||||
return p.trie;
|
||||
} else {
|
||||
|
@ -1010,12 +1027,12 @@ module.exports.SOA = SOA;
|
|||
module.exports.EOA = EOA;
|
||||
module.exports.$Capture = $Capture;
|
||||
module.exports.$Special = $Special;
|
||||
module.exports.makeStructureConstructor = makeStructureConstructor;
|
||||
module.exports._$ = _$;
|
||||
module.exports.is_emptyTrie = is_emptyTrie;
|
||||
module.exports.emptyTrie = emptyTrie;
|
||||
module.exports.embeddedTrie = embeddedTrie;
|
||||
module.exports.compilePattern = compilePattern;
|
||||
module.exports.matchPattern = matchPattern;
|
||||
module.exports._union = union;
|
||||
module.exports.union = unionN;
|
||||
module.exports.intersect = intersect;
|
||||
|
|
|
@ -351,45 +351,6 @@ describe("embedding tries in patterns", function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe("calls to matchPattern", function () {
|
||||
it("should yield appropriately-named/-numbered fields", function () {
|
||||
expect(r.matchPattern([1, 2, 3], [r.__, 2, r._$])).to.eql({'$0': 3, 'length': 1});
|
||||
expect(r.matchPattern([1, 2, 3], [r.__, 2, r._$("three")])).to.eql({'three': 3, 'length': 1});
|
||||
expect(r.matchPattern([1, 2, 3], [r._$, 2, r._$("three")]))
|
||||
.to.eql({'$0': 1, 'three': 3, 'length': 2});
|
||||
expect(r.matchPattern([1, 2, 3], [r._$("one"), 2, r._$]))
|
||||
.to.eql({'one': 1, '$1': 3, 'length': 2});
|
||||
expect(r.matchPattern([1, 2, 3], [r._$("one"), 2, r._$("three")]))
|
||||
.to.eql({'one': 1, 'three': 3, 'length': 2});
|
||||
});
|
||||
|
||||
it("should fail on value mismatch", function () {
|
||||
expect(r.matchPattern([1, 2, 3], [r.__, 999, r._$("three")])).to.be(null);
|
||||
});
|
||||
|
||||
it("should fail on array length mismatch", function () {
|
||||
expect(r.matchPattern([1, 2, 3], [r.__, 2, r._$("three"), 4])).to.be(null);
|
||||
});
|
||||
|
||||
it("matches substructure", function () {
|
||||
expect(r.matchPattern([1, [2, 999], 3], [r._$("one"), r._$(null, [2, r.__]), r._$("three")]))
|
||||
.to.eql({ one: 1, '$1': [ 2, 999 ], three: 3, length: 3 });
|
||||
expect(r.matchPattern([1, [2, 999], 3], [r._$("one"), r._$("two", [2, r.__]), r._$("three")]))
|
||||
.to.eql({ one: 1, two: [ 2, 999 ], three: 3, length: 3 });
|
||||
expect(r.matchPattern([1, [999, 2], 3], [r._$("one"), r._$(null, [2, r.__]), r._$("three")]))
|
||||
.to.be(null);
|
||||
expect(r.matchPattern([1, [999, 2], 3], [r._$("one"), r._$("two", [2, r.__]), r._$("three")]))
|
||||
.to.be(null);
|
||||
});
|
||||
|
||||
it("matches nested captures", function () {
|
||||
expect(r.matchPattern([1, [2, 999], 3], [r._$("one"), r._$(null, [2, r._$]), r._$("three")]))
|
||||
.to.eql({ one: 1, '$2': 999, '$1': [ 2, 999 ], three: 3, length: 4 });
|
||||
expect(r.matchPattern([1, [2, 999], 3], [r._$("one"), r._$("two", [2, r._$]), r._$("three")]))
|
||||
.to.eql({ one: 1, '$2': 999, two: [ 2, 999 ], three: 3, length: 4 });
|
||||
});
|
||||
});
|
||||
|
||||
describe("Projection with no captures", function () {
|
||||
it("should yield the empty sequence when there's a match", function () {
|
||||
var emptySequence = [' >{["A"]}'];
|
||||
|
@ -489,3 +450,29 @@ describe('triePruneBranch', function () {
|
|||
' "z" >{true}']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('makeStructureConstructor', function () {
|
||||
it('should produce the right metadata', function () {
|
||||
var ctor = r.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 inst = ctor(123, 234);
|
||||
expect(inst.bar).to.equal(123);
|
||||
expect(inst.zot).to.equal(234);
|
||||
});
|
||||
|
||||
it('should work with compilePattern and matchValue', function () {
|
||||
var sA = Immutable.Set(["A"]);
|
||||
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"]}']);
|
||||
expect(r.matchValue(x, ctor(123, 234))).to.eql(sA);
|
||||
expect(r.matchValue(x, ctor(234, 123))).to.eql(null);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue