Matching is implemented by a global function called match() taking two
arguments: a value and a pattern. The value may be any JavaScript
value of any predefined type or user-defined type. The pattern is a
string used to recognize some form of data and decompose it into
smaller pieces, and may contain pattern variables (prefixed by "%"),
for isolating sub-data. A pattern may (currently) not contain any whitespace.
A failed match always returns the null value. A successful match
returns an object having a field for each variable.
1. Match a value in the standard notation
A pattern in the standard notation is simply written in
the native notation for data in JavaScript, sligthly extended to
support variable-length arrays:
The pattern "[p1, ... pn]" matches any array having exactly n
elements matching the n patterns. In particular, the pattern "[]"
matches any empty array. The pattern "[p1, ... pn | p]" matches
any array having at least n initial elements matching the first n
patterns, and whose tail matches the last pattern. For
example, match([1, 2, 3], "[%x|%l]") successfully binds x
to 1 and l to the array [2, 3].
The pattern "{f1:p1, ..., fn:pn}" matches any object
having at least the given fields (either owned or
inherited), provided that the corresponding values match the given
patterns. In particular, the pattern "{}" matches any object.
For example, match({re:2, im:-1}, "{im:%i}") successfully
binds i to -1.
Try it yourself:
Note: the "unnamed" option means that pattern variables are anonymous,
i.e. are represented by a single "%", not followed by any name. For
unnamed patterns, the result of a match is an array having an
element for each variable, in textual order.
2. Define your own notation for some datatype
You can very easily override the default notation above with a custom
notation for any object type.
This is done by overriding the method "matches" (inherited from
Object). The method matches(pat, off, acc) takes as arguments a
pattern, given as a string plus an offset, and an accumulator, which
is a partial result for the match. In case of a successful match, it
has to return the new offset into the pattern, after the notation for
this object has been consumed. In case of match failure, it has to
throw a "fail" exception. The method is free to implement any kind of
matching notation for the object, but which must always start with an
opening parenthesis (one of "([{") and end with the corresponding
closing parenthesis (one of ")]}"):
Now you can match any values containing your datatype, matched in
your own notation: