For example, let us define the usual mathematical notation for the following simple type of complex numbers.
function Complex(re, im) {
this.re = re;
this.im = im;
}
The usual notation for complex numbers is "a + bi" for a complex
number with an imaginary part, and simply "a" for complex numbers
whith a no imaginary part. However, in myPatterns, all notations must
start with an open parenthesis (one of "([{") and end with the
corresponding closing parenthesis (")]}"). (This restriction ensures
that arbitrary notations designed by different people can always be
composed unambiguosly.) Thus, the implemented notation will be in fact
"(a + bi)" and "(a)", respectively.
Defining this notation for Complex objects is simply done by redefining the Complex.matches() method, with some code implementing the new notation.
Complex.prototype.matches = function(pat, off, sub) {
off = matchChar("(", pat, off);
off = matchData(this.re, pat, off, sub);
if(pat.charAt(off) == "+") {
off = matchChar("+", pat, off);
off = matchData(this.im, pat, off, sub);
off = matchChar("i", pat, off);
} else if(this.im == 0) ; // already done
else throw "fail";
off = matchChar(")", pat, off);
return off;
}
This method matches in fact a sub-pattern at a given offset with the
current Complex. The third argument is the substitution already
accumulated while matching the portion of the pattern that appears
before the current sub-pattern (i.e. between the beginning of the
pattern and the given offset). This substitution must simply be passed
to all the worker functions that require it. There are predefined
worker function for matching a character (matchChar()), a token
(matchToken()), and a sub-data (matchData()). If the match is
successful, the method must return an updated offset, reflecting the
sub-pattern that has been consumed. If the match is unsuccessful, the
method must throw a "fail" exception.
Using this notation, match(new Complex(1, 2), "(%x+%yi)") returns {x:1, y:2}; match(new Complex(3, 0), "(%x+%yi)") returns {x:3, y:0}, and match(new Complex(3, 0), "(%x)") returns {x:3}.
For more convenience, the predefined function pmatch() automatically adds the outermost pair of parentheses around a pattern before calling match(). Thus, one may write pmatch(new Complex(3, 0), "%x+%yi") instead of match(new Complex(3, 0), "(%x+%yi)"). However, when the complex notation is used as a sub-pattern, parentheses remain mandatory: match(new Complex(3, 0), "[(%x+%yi),(%a+%bi)]")
That's all about defining custom notations. More examples are available in the distribution.