Messed around with API document: Improved layout, removed animation, added <Content...
[jquery.git] / build / js / ParseMaster.js
1 /*
2     ParseMaster, version 1.0.2 (2005-08-19)
3     Copyright 2005, Dean Edwards
4     License: http://creativecommons.org/licenses/LGPL/2.1/
5 */
6
7 /* a multi-pattern parser */
8
9 // KNOWN BUG: erroneous behavior when using escapeChar with a replacement value that is a function
10
11 function ParseMaster() {
12     // constants
13     var $EXPRESSION = 0, $REPLACEMENT = 1, $LENGTH = 2;
14     // used to determine nesting levels
15     var $GROUPS = /\(/g, $SUB_REPLACE = /\$\d/, $INDEXED = /^\$\d+$/,
16         $TRIM = /(['"])\1\+(.*)\+\1\1$/, $$ESCAPE = /\\./g, $QUOTE = /'/,
17         $$DELETED = /\x01[^\x01]*\x01/g;
18     var self = this;
19     // public
20     this.add = function($expression, $replacement) {
21         if (!$replacement) $replacement = "";
22         // count the number of sub-expressions
23         //  - add one because each pattern is itself a sub-expression
24         var $length = (_internalEscape(String($expression)).match($GROUPS) || "").length + 1;
25         // does the pattern deal with sub-expressions?
26         if ($SUB_REPLACE.test($replacement)) {
27             // a simple lookup? (e.g. "$2")
28             if ($INDEXED.test($replacement)) {
29                 // store the index (used for fast retrieval of matched strings)
30                 $replacement = parseInt($replacement.slice(1)) - 1;
31             } else { // a complicated lookup (e.g. "Hello $2 $1")
32                 // build a function to do the lookup
33                 var i = $length;
34                 var $quote = $QUOTE.test(_internalEscape($replacement)) ? '"' : "'";
35                 while (i) $replacement = $replacement.split("$" + i--).join($quote + "+a[o+" + i + "]+" + $quote);
36                 $replacement = new Function("a,o", "return" + $quote + $replacement.replace($TRIM, "$1") + $quote);
37             }
38         }
39         // pass the modified arguments
40         _add($expression || "/^$/", $replacement, $length);
41     };
42     // execute the global replacement
43     this.exec = function($string) {
44         _escaped.length = 0;
45         return _unescape(_escape($string, this.escapeChar).replace(
46             new RegExp(_patterns, this.ignoreCase ? "gi" : "g"), _replacement), this.escapeChar).replace($$DELETED, "");
47     };
48     // clear the patterns collection so that this object may be re-used
49     this.reset = function() {
50         _patterns.length = 0;
51     };
52
53     // private
54     var _escaped = [];  // escaped characters
55     var _patterns = []; // patterns stored by index
56     var _toString = function(){return "(" + String(this[$EXPRESSION]).slice(1, -1) + ")"};
57     _patterns.toString = function(){return this.join("|")};
58     // create and add a new pattern to the patterns collection
59     function _add() {
60         arguments.toString = _toString;
61         // store the pattern - as an arguments object (i think this is quicker..?)
62         _patterns[_patterns.length] = arguments;
63     }
64     // this is the global replace function (it's quite complicated)
65     function _replacement() {
66         if (!arguments[0]) return "";
67         var i = 1, j = 0, $pattern;
68         // loop through the patterns
69         while ($pattern = _patterns[j++]) {
70             // do we have a result?
71             if (arguments[i]) {
72                 var $replacement = $pattern[$REPLACEMENT];
73                 switch (typeof $replacement) {
74                     case "function": return $replacement(arguments, i);
75                     case "number": return arguments[$replacement + i];
76                 }
77                 var $delete = (arguments[i].indexOf(self.escapeChar) == -1) ? "" :
78                     "\x01" + arguments[i] + "\x01";
79                 return $delete + $replacement;
80             // skip over references to sub-expressions
81             } else i += $pattern[$LENGTH];
82         }
83     };
84     // encode escaped characters
85     function _escape($string, $escapeChar) {
86         return $escapeChar ? $string.replace(new RegExp("\\" + $escapeChar + "(.)", "g"), function($match, $char) {
87             _escaped[_escaped.length] = $char;
88             return $escapeChar;
89         }) : $string;
90     };
91     // decode escaped characters
92     function _unescape($string, $escapeChar) {
93         var i = 0;
94         return $escapeChar ? $string.replace(new RegExp("\\" + $escapeChar, "g"), function() {
95             return $escapeChar + (_escaped[i++] || "");
96         }) : $string;
97     };
98     function _internalEscape($string) {
99         return $string.replace($$ESCAPE, "");
100     };
101 };
102 ParseMaster.prototype = {
103     constructor: ParseMaster,
104     ignoreCase: false,
105     escapeChar: ""
106 };