Skeleton.match

This commit is contained in:
Tony Garnock-Jones 2018-12-14 12:37:32 +00:00
parent 14bb7f3d6f
commit 0f4a572393
2 changed files with 94 additions and 0 deletions

View File

@ -423,6 +423,32 @@ function unpackScoped(a, k) {
///////////////////////////////////////////////////////////////////////////
function match(p, v) {
let captures = Immutable.List();
function walk(p, v) {
if (Capture.isClassOf(p)) {
if (!walk(p.get(0), v)) return false;
captures = captures.push(v);
return true;
}
if (Discard.isClassOf(p)) return true;
const pcls = classOf(p);
const vcls = classOf(v);
if (!Immutable.is(pcls, vcls)) return false;
if (pcls === null) return Immutable.is(p, v);
if (typeof pcls === 'number') return p.every((pv, i) => walk(pv, v.get(i)));
return p.fields.every((pv, i) => walk(pv, v.fields.get(i)));
}
return walk(p, v) ? captures : false;
}
///////////////////////////////////////////////////////////////////////////
module.exports.EVENT_ADDED = EVENT_ADDED;
module.exports.EVENT_REMOVED = EVENT_REMOVED;
module.exports.EVENT_MESSAGE = EVENT_MESSAGE;
@ -430,3 +456,4 @@ module.exports.Index = Index;
module.exports.analyzeAssertion = analyzeAssertion;
module.exports.instantiateAssertion = instantiateAssertion;
module.exports.match = match;

View File

@ -266,4 +266,71 @@ describe('skeleton', () => {
});
});
describe('matching a single pattern against a value', () => {
it('should accept matching simple records', () => {
expect(Skeleton.match(Immutable.fromJS(A(1, 2)),
Immutable.fromJS(A(1, 2))))
.to.equal(Immutable.List());
});
it('should capture from matching simple records', () => {
expect(Skeleton.match(Immutable.fromJS(A(1, _$)),
Immutable.fromJS(A(1, 2))))
.to.equal(Immutable.List([2]));
});
it('should reject mismatching simple records', () => {
expect(Skeleton.match(Immutable.fromJS(A(1, 2)),
Immutable.fromJS(A(1, "hi"))))
.to.equal(false);
});
it('should accept matching simple lists', () => {
expect(Skeleton.match(Immutable.fromJS([1, 2, 3]),
Immutable.fromJS([1, 2, 3])))
.to.equal(Immutable.List());
});
it('should accept matching nested lists', () => {
expect(Skeleton.match(Immutable.fromJS([1, [2, 4], 3]),
Immutable.fromJS([1, [2, 4], 3])))
.to.equal(Immutable.List());
});
it('should capture matches from simple lists', () => {
expect(Skeleton.match(Immutable.fromJS([1, Capture(2), 3]),
Immutable.fromJS([1, 2, 3])))
.to.equal(Immutable.List([2]));
});
it('should capture discards from simple lists', () => {
expect(Skeleton.match(Immutable.fromJS([1, Capture(__), 3]),
Immutable.fromJS([1, 2, 3])))
.to.equal(Immutable.List([2]));
});
it('should capture discards from nested lists', () => {
expect(Skeleton.match(Immutable.fromJS([1, Capture(__), 3]),
Immutable.fromJS([1, [2, 4], 3])))
.to.equal(Immutable.fromJS([[2, 4]]));
});
it('should capture nested discards from nested lists', () => {
expect(Skeleton.match(Immutable.fromJS([1, Capture([__, 4]), 3]),
Immutable.fromJS([1, [2, 4], 3])))
.to.equal(Immutable.fromJS([[2, 4]]));
});
it('should reject nested mismatches from nested lists', () => {
expect(Skeleton.match(Immutable.fromJS([1, Capture([__, 5]), 3]),
Immutable.fromJS([1, [2, 4], 3])))
.to.equal(false);
});
it('should reject mismatching captures from simple lists', () => {
expect(Skeleton.match(Immutable.fromJS([1, Capture(9), 3]),
Immutable.fromJS([1, 2, 3])))
.to.equal(false);
});
it('should reject simple lists varying in arity', () => {
expect(Skeleton.match(Immutable.fromJS([1, 2, 3, 4]),
Immutable.fromJS([1, 2, 3])))
.to.equal(false);
});
it('should reject simple lists varying in order', () => {
expect(Skeleton.match(Immutable.fromJS([1, 3, 2]),
Immutable.fromJS([1, 2, 3])))
.to.equal(false);
});
});
});