Pattern matching for Javascript data structures (objects / lists / primitives) in a DSLy fashion
by ntoshev
HTML
<script src="https://github.com/documentcloud/underscore/raw/master/underscore-min.js"></script>
<div id='log'/>
JavaScript
//make console.log print to the html panel
var logs=document.getElementById('log');
console.log= function(s){
var e=document.createElement('pre');
e.innerHTML=s;
logs.insertBefore(e);
}
'use strict';
//create variables to be matched
function v(name){
function v(value) {
if (v.bound != undefined && value != undefined && v.bound != value)
throw new ReferenceError('Conflict in ' + name + ' between ' + v.bound + ' and ' + value)
if (value != undefined)
v.bound = value
return v.bound
}
return v
}
// determine if v is a matchable variable
function isVar(v){
var props = []
for (var p in x){
props.push(p)
}
//better typecheck? Make it a real object, instanceof?
return (v instanceof Function) && (_.isEqual(props,[]) || _.isEqual(props,['bound']))
}
function match(first, second) {
if (isVar(first)) {
first(second)
} else if (isVar(second)) {
second(first)
} else if (first instanceof Array) {
if (!(second instanceof Array)) throw ReferenceError("Can't match " + first + " with " + second)
if (first.length != second.length) throw ReferenceError("Array length doesn't match")
for (var i=0; i<second.length; i++)
match(first[i], second[i])
} else if (first instanceof Object) {
for(var p in first) {
if (!(p in second)) throw ReferenceError("Can't match property " + p)
match(first[p], second[p])
}
for(var p in second) {
if (!(p in first)) throw ReferenceError("Can't match property " + p)
}
} else if (first != second) {
throw ReferenceError("Can't match " + first + " with " + second)
}
}
var x = v();
var y = v()
match({name:'john', list:[y,'john', 3, 'john']}, {name:x, list:[1, x, 3, x]});
console.log(x()); // john
console.log(y()); // 1
match(y, 2); // exception printed in console, y is 1 already
console.log(y()); // never reached