Generalize matchValue to permit wildcard messages (not yet used)

This commit is contained in:
Tony Garnock-Jones 2016-05-17 18:16:20 -04:00
parent 1f33039e28
commit 8256b56607
2 changed files with 53 additions and 36 deletions

View File

@ -403,36 +403,53 @@ function subtract(o1, o2, subtractSuccessesOpt) {
///////////////////////////////////////////////////////////////////////////
// Returns failureResult on failed match, otherwise the appropriate success
// value contained in the trie r.
function matchValue(r, v, failureResult) {
var vs = Immutable.List.of(v);
// Returns failureResult on failed match, otherwise the appropriate
// success value contained in the trie r. If wildcardUnionOpt
// non-falsy, allows wildcards in "messages" v.
function matchValue(r, v, failureResult, wildcardUnionOpt) {
return walk(Immutable.List.of(v), r);
while (!is_emptyTrie(r)) {
if (r instanceof $Success) {
return vs.isEmpty() ? r.value : failureResult;
function walk(vs, r) {
while (!is_emptyTrie(r)) {
if (r instanceof $Success) {
return vs.isEmpty() ? r.value : failureResult;
}
if (vs.isEmpty()) return failureResult;
var v = vs.first();
vs = vs.rest();
if (v === __) {
if (!wildcardUnionOpt) {
die("Cannot match wildcard in value unless wildcardUnionOpt non-falsy");
}
var seed = walk(vs, r.wild);
r.edges.forEach(function (keymap, arity) {
keymap.forEach(function (k, key) {
seed = wildcardUnionOpt(walk(Immutable.Repeat(__, arity).concat(vs), k), seed);
});
});
return seed;
}
if (typeof v === 'string' && v.substring(0, 2) === '__') {
die("Cannot match special string starting with __");
}
if (Array.isArray(v)) {
r = rlookup(r, v.length, SOA);
vs = Immutable.List(v).concat(vs);
} else if (Struct.isStructure(v)) {
r = rlookup(r, v.meta.arity, v.meta);
vs = Immutable.List(v.fields).concat(vs);
} else {
r = rlookup(r, 0, v);
}
}
if (vs.isEmpty()) return failureResult;
var v = vs.first();
vs = vs.shift();
if (typeof v === 'string' && v.substring(0, 2) === '__') {
die("Cannot match special string starting with __");
}
if (Array.isArray(v)) {
r = rlookup(r, v.length, SOA);
vs = Immutable.List(v).concat(vs);
} else if (Struct.isStructure(v)) {
r = rlookup(r, v.meta.arity, v.meta);
vs = Immutable.List(v.fields).concat(vs);
} else {
r = rlookup(r, 0, v);
}
return failureResult;
}
return failureResult;
}
function matchTrie(o1, o2, seed, combiner) {

View File

@ -40,19 +40,19 @@ describe("basic pattern compilation", function () {
describe("of wildcard", function () {
it("should match anything", function () {
expect(r.matchValue(mAny, 'hi')).to.eql(sAny);
expect(r.matchValue(mAny, ['A', 'hi'])).to.eql(sAny);
expect(r.matchValue(mAny, ['B', 'hi'])).to.eql(sAny);
expect(r.matchValue(mAny, ['A', [['hi']]])).to.eql(sAny);
expect(r.matchValue(mAny, 'hi', null)).to.eql(sAny);
expect(r.matchValue(mAny, ['A', 'hi'], null)).to.eql(sAny);
expect(r.matchValue(mAny, ['B', 'hi'], null)).to.eql(sAny);
expect(r.matchValue(mAny, ['A', [['hi']]], null)).to.eql(sAny);
});
});
describe("of A followed by wildcard", function () {
it("should match A followed by anything", function () {
expect(r.matchValue(mAAny, 'hi')).to.be(null);
expect(r.matchValue(mAAny, ['A', 'hi'])).to.eql(sAAny);
expect(r.matchValue(mAAny, ['B', 'hi'])).to.be(null);
expect(r.matchValue(mAAny, ['A', [['hi']]])).to.eql(sAAny);
expect(r.matchValue(mAAny, 'hi', null)).to.be(null);
expect(r.matchValue(mAAny, ['A', 'hi'], null)).to.eql(sAAny);
expect(r.matchValue(mAAny, ['B', 'hi'], null)).to.be(null);
expect(r.matchValue(mAAny, ['A', [['hi']]], null)).to.eql(sAAny);
});
});
@ -539,7 +539,7 @@ describe('makeConstructor', function () {
var inst = ctor(123, 234);
var x = r.compilePattern(sA, ctor(123, r.__));
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);
expect(r.matchValue(x, ctor(123, 234), null)).to.eql(sA);
expect(r.matchValue(x, ctor(234, 123), null)).to.eql(null);
});
});