CrypticSwarm / js-matcher

Provides simple pattern matching over JavaScript objects.
11 stars 1 forks source link

Simple unbound field name matches don't work #2

Open msackman opened 12 years ago

msackman commented 12 years ago

In your examples, you have the rather impressive:

match({ '$v': '$y', '$x': [1,2,'$v'], i: '$x'}, { i: 'd', b: [23, 44], a: 3, c: 3, d: [1,2,'b']})

which works. However, much simpler matches do not work:

isMatch({'$a': '$b'}, {c: 5}); // false
isMatch({'$a': 5}, {c: 5}); // false

whereas

isMatch({c: '$b'}, {c: 5}); // true

But there is a problem - if you make the first two work then you then have some ambiguity issues:

match({'$a': 5}, {x: 5, y: 5, z: 5})

What on earth should '$a' be bound to in the resultant object? Or should you support a /g-like regex flag and be able to reissue the query and get the next result?

CrypticSwarm commented 12 years ago

I was keeping it simple when I made this. Using a variable as a key requires knowing which concrete value it should be.
That is to say it needs to have been bound somewhere else first. It currently doesn't do a search through the object to find a key that would work.

One of the main problems with your proposed /g flag is that there is the lack of a specified order on keys in a {}. If a search was performed and multiple keys matched, and the first (or last) match was bound then the match wouldn't always be the same for all JS engines. (however assuming this is only used in node and not in a browser then it is less or a problem, but I'm not making those assumptions.)

Another option would be to return a list of bindings rather then just bindings. In this case if it didn't match it would return []. This would be making it much more like logic programming.

msackman commented 12 years ago

Ahh, I see - thanks for the clarification. So the variable field name only works if the variable is defined by a value of another field.

Personally I don't see the issue with field order with a /g-type variant - if you're relying on field order anyway you're probably Doing It Wrong. The goal would merely be to provide a means to iterate over all the solutions. I was starting to think along the lines of returning a {match: { /* The vars matched */ }, next: function () { /* run me to yield the next solution */ }} type result so that it behaves a bit like a cursor.