source: branches/2.4/prototype/plugins/datejs/parser-debug.js @ 7151

Revision 7151, 37.1 KB checked in by eduardow, 12 years ago (diff)

Ticket #3085 - Corrigida inconsistencia com o formato de hora no Expresso Calendar.

Line 
1/**
2 * @version: 1.0 Alpha-1
3 * @author: Coolite Inc. http://www.coolite.com/
4 * @date: 2008-04-13
5 * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
6 * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
7 * @website: http://www.datejs.com/
8 */
9 
10(function () {
11    Date.Parsing = {
12        Exception: function (s) {
13            this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
14        }
15    };
16   
17    var $P = Date.Parsing;
18    var _ = $P.Operators = {
19        //
20        // Tokenizers
21        //
22        rtoken: function (r) { // regex token
23            return function (s) {
24                var mx = s.match(r);
25                if (mx) {
26                    return ([ mx[0], s.substring(mx[0].length) ]);
27                } else {
28                    throw new $P.Exception(s);
29                }
30            };
31        },
32        token: function (s) { // whitespace-eating token
33            return function (s) {
34                return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s);
35                // Removed .strip()
36                // return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s).strip();
37            };
38        },
39        stoken: function (s) { // string token
40            return _.rtoken(new RegExp("^" + s));
41        },
42
43        //
44        // Atomic Operators
45        //
46
47        until: function (p) {
48            return function (s) {
49                var qx = [], rx = null;
50                while (s.length) {
51                    try {
52                        rx = p.call(this, s);
53                    } catch (e) {
54                        qx.push(rx[0]);
55                        s = rx[1];
56                        continue;
57                    }
58                    break;
59                }
60                return [ qx, s ];
61            };
62        },
63        many: function (p) {
64            return function (s) {
65                var rx = [], r = null;
66                while (s.length) {
67                    try {
68                        r = p.call(this, s);
69                    } catch (e) {
70                        return [ rx, s ];
71                    }
72                    rx.push(r[0]);
73                    s = r[1];
74                }
75                return [ rx, s ];
76            };
77        },
78
79        // generator operators -- see below
80        optional: function (p) {
81            return function (s) {
82                var r = null;
83                try {
84                    r = p.call(this, s);
85                } catch (e) {
86                    return [ null, s ];
87                }
88                return [ r[0], r[1] ];
89            };
90        },
91        not: function (p) {
92            return function (s) {
93                try {
94                    p.call(this, s);
95                } catch (e) {
96                    return [null, s];
97                }
98                throw new $P.Exception(s);
99            };
100        },
101        ignore: function (p) {
102            return p ?
103            function (s) {
104                var r = null;
105                r = p.call(this, s);
106                return [null, r[1]];
107            } : null;
108        },
109        product: function () {
110            var px = arguments[0],
111            qx = Array.prototype.slice.call(arguments, 1), rx = [];
112            for (var i = 0 ; i < px.length ; i++) {
113                rx.push(_.each(px[i], qx));
114            }
115            return rx;
116        },
117        cache: function (rule) {
118            var cache = {}, r = null;
119            return function (s) {
120                try {
121                    r = cache[s] = (cache[s] || rule.call(this, s));
122                } catch (e) {
123                    r = cache[s] = e;
124                }
125                if (r instanceof $P.Exception) {
126                    throw r;
127                } else {
128                    return r;
129                }
130            };
131        },
132         
133        // vector operators -- see below
134        any: function () {
135            var px = arguments;
136            return function (s) {
137                var r = null;
138                for (var i = 0; i < px.length; i++) {
139                    if (px[i] == null) {
140                        continue;
141                    }
142                    try {
143                        r = (px[i].call(this, s));
144                    } catch (e) {
145                        r = null;
146                    }
147                    if (r) {
148                        return r;
149                    }
150                }
151                throw new $P.Exception(s);
152            };
153        },
154        each: function () {
155            var px = arguments;
156            return function (s) {
157                var rx = [], r = null;
158                for (var i = 0; i < px.length ; i++) {
159                    if (px[i] == null) {
160                        continue;
161                    }
162                    try {
163                        r = (px[i].call(this, s));
164                    } catch (e) {
165                        throw new $P.Exception(s);
166                    }
167                    rx.push(r[0]);
168                    s = r[1];
169                }
170                return [ rx, s];
171            };
172        },
173        all: function () {
174            var px = arguments, _ = _;
175            return _.each(_.optional(px));
176        },
177
178        // delimited operators
179        sequence: function (px, d, c) {
180            d = d || _.rtoken(/^\s*/); 
181            c = c || null;
182           
183            if (px.length == 1) {
184                return px[0];
185            }
186            return function (s) {
187                var r = null, q = null;
188                var rx = [];
189                for (var i = 0; i < px.length ; i++) {
190                    try {
191                        r = px[i].call(this, s);
192                    } catch (e) {
193                        break;
194                    }
195                    rx.push(r[0]);
196                    try {
197                        q = d.call(this, r[1]);
198                    } catch (ex) {
199                        q = null;
200                        break;
201                    }
202                    s = q[1];
203                }
204                if (!r) {
205                    throw new $P.Exception(s);
206                }
207                if (q) {
208                    throw new $P.Exception(q[1]);
209                }
210                if (c) {
211                    try {
212                        r = c.call(this, r[1]);
213                    } catch (ey) {
214                        throw new $P.Exception(r[1]);
215                    }
216                }
217                return [ rx, (r?r[1]:s) ];
218            };
219        },
220               
221            //
222            // Composite Operators
223            //
224               
225        between: function (d1, p, d2) {
226            d2 = d2 || d1;
227            var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
228            return function (s) {
229                var rx = _fn.call(this, s);
230                return [[rx[0][0], r[0][2]], rx[1]];
231            };
232        },
233        list: function (p, d, c) {
234            d = d || _.rtoken(/^\s*/); 
235            c = c || null;
236            return (p instanceof Array ?
237                _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
238                _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
239        },
240        set: function (px, d, c) {
241            d = d || _.rtoken(/^\s*/);
242            c = c || null;
243            return function (s) {
244                // r is the current match, best the current 'best' match
245                // which means it parsed the most amount of input
246                var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
247
248                // go through the rules in the given set
249                for (var i = 0; i < px.length ; i++) {
250
251                    // last is a flag indicating whether this must be the last element
252                    // if there is only 1 element, then it MUST be the last one
253                    q = null;
254                    p = null;
255                    r = null;
256                    last = (px.length == 1);
257
258                    // first, we try simply to match the current pattern
259                    // if not, try the next pattern
260                    try {
261                        r = px[i].call(this, s);
262                    } catch (e) {
263                        continue;
264                    }
265
266                    // since we are matching against a set of elements, the first
267                    // thing to do is to add r[0] to matched elements
268                    rx = [[r[0]], r[1]];
269
270                    // if we matched and there is still input to parse and
271                    // we don't already know this is the last element,
272                    // we're going to next check for the delimiter ...
273                    // if there's none, or if there's no input left to parse
274                    // than this must be the last element after all ...
275                    if (r[1].length > 0 && ! last) {
276                        try {
277                            q = d.call(this, r[1]);
278                        } catch (ex) {
279                            last = true;
280                        }
281                    } else {
282                        last = true;
283                    }
284
285                                    // if we parsed the delimiter and now there's no more input,
286                                    // that means we shouldn't have parsed the delimiter at all
287                                    // so don't update r and mark this as the last element ...
288                    if (!last && q[1].length === 0) {
289                        last = true;
290                    }
291
292
293                                    // so, if this isn't the last element, we're going to see if
294                                    // we can get any more matches from the remaining (unmatched)
295                                    // elements ...
296                    if (!last) {
297
298                        // build a list of the remaining rules we can match against,
299                        // i.e., all but the one we just matched against
300                        var qx = [];
301                        for (var j = 0; j < px.length ; j++) {
302                            if (i != j) {
303                                qx.push(px[j]);
304                            }
305                        }
306
307                        // now invoke recursively set with the remaining input
308                        // note that we don't include the closing delimiter ...
309                        // we'll check for that ourselves at the end
310                        p = _.set(qx, d).call(this, q[1]);
311
312                        // if we got a non-empty set as a result ...
313                        // (otw rx already contains everything we want to match)
314                        if (p[0].length > 0) {
315                            // update current result, which is stored in rx ...
316                            // basically, pick up the remaining text from p[1]
317                            // and concat the result from p[0] so that we don't
318                            // get endless nesting ...
319                            rx[0] = rx[0].concat(p[0]);
320                            rx[1] = p[1];
321                        }
322                    }
323
324                                    // at this point, rx either contains the last matched element
325                                    // or the entire matched set that starts with this element.
326
327                                    // now we just check to see if this variation is better than
328                                    // our best so far, in terms of how much of the input is parsed
329                    if (rx[1].length < best[1].length) {
330                        best = rx;
331                    }
332
333                                    // if we've parsed all the input, then we're finished
334                    if (best[1].length === 0) {
335                        break;
336                    }
337                }
338
339                            // so now we've either gone through all the patterns trying them
340                            // as the initial match; or we found one that parsed the entire
341                            // input string ...
342
343                            // if best has no matches, just return empty set ...
344                if (best[0].length === 0) {
345                    return best;
346                }
347
348                            // if a closing delimiter is provided, then we have to check it also
349                if (c) {
350                    // we try this even if there is no remaining input because the pattern
351                    // may well be optional or match empty input ...
352                    try {
353                        q = c.call(this, best[1]);
354                    } catch (ey) {
355                        throw new $P.Exception(best[1]);
356                    }
357
358                    // it parsed ... be sure to update the best match remaining input
359                    best[1] = q[1];
360                }
361
362                            // if we're here, either there was no closing delimiter or we parsed it
363                            // so now we have the best match; just return it!
364                return best;
365            };
366        },
367        forward: function (gr, fname) {
368            return function (s) {
369                return gr[fname].call(this, s);
370            };
371        },
372
373        //
374        // Translation Operators
375        //
376        replace: function (rule, repl) {
377            return function (s) {
378                var r = rule.call(this, s);
379                return [repl, r[1]];
380            };
381        },
382        process: function (rule, fn) {
383            return function (s) { 
384                var r = rule.call(this, s);
385                return [fn.call(this, r[0]), r[1]];
386            };
387        },
388        min: function (min, rule) {
389            return function (s) {
390                var rx = rule.call(this, s);
391                if (rx[0].length < min) {
392                    throw new $P.Exception(s);
393                }
394                return rx;
395            };
396        }
397    };
398       
399
400        // Generator Operators And Vector Operators
401
402        // Generators are operators that have a signature of F(R) => R,
403        // taking a given rule and returning another rule, such as
404        // ignore, which parses a given rule and throws away the result.
405
406        // Vector operators are those that have a signature of F(R1,R2,...) => R,
407        // take a list of rules and returning a new rule, such as each.
408
409        // Generator operators are converted (via the following _generator
410        // function) into functions that can also take a list or array of rules
411        // and return an array of new rules as though the function had been
412        // called on each rule in turn (which is what actually happens).
413
414        // This allows generators to be used with vector operators more easily.
415        // Example:
416        // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
417
418        // This also turns generators into vector operators, which allows
419        // constructs like:
420        // not(cache(foo, bar))
421       
422    var _generator = function (op) {
423        return function () {
424            var args = null, rx = [];
425            if (arguments.length > 1) {
426                args = Array.prototype.slice.call(arguments);
427            } else if (arguments[0] instanceof Array) {
428                args = arguments[0];
429            }
430            if (args) {
431                for (var i = 0, px = args.shift() ; i < px.length ; i++) {
432                    args.unshift(px[i]);
433                    rx.push(op.apply(null, args));
434                    args.shift();
435                    return rx;
436                }
437            } else {
438                return op.apply(null, arguments);
439            }
440        };
441    };
442   
443    var gx = "optional not ignore cache".split(/\s/);
444   
445    for (var i = 0 ; i < gx.length ; i++) {
446        _[gx[i]] = _generator(_[gx[i]]);
447    }
448
449    var _vector = function (op) {
450        return function () {
451            if (arguments[0] instanceof Array) {
452                return op.apply(null, arguments[0]);
453            } else {
454                return op.apply(null, arguments);
455            }
456        };
457    };
458   
459    var vx = "each any all".split(/\s/);
460   
461    for (var j = 0 ; j < vx.length ; j++) {
462        _[vx[j]] = _vector(_[vx[j]]);
463    }
464       
465}());
466
467(function () {
468    var $D = Date, $P = $D.prototype, $C = $D.CultureInfo;
469
470    var flattenAndCompact = function (ax) {
471        var rx = [];
472        for (var i = 0; i < ax.length; i++) {
473            if (ax[i] instanceof Array) {
474                rx = rx.concat(flattenAndCompact(ax[i]));
475            } else {
476                if (ax[i]) {
477                    rx.push(ax[i]);
478                }
479            }
480        }
481        return rx;
482    };
483   
484    $D.Grammar = {};
485       
486    $D.Translator = {
487        hour: function (s) {
488            return function () {
489                this.hour = Number(s);
490            };
491        },
492        minute: function (s) {
493            return function () {
494                this.minute = Number(s);
495            };
496        },
497        second: function (s) {
498            return function () {
499                this.second = Number(s);
500            };
501        },
502        meridian: function (s) {
503            return function () {
504                this.meridian = s.slice(0, 1).toLowerCase();
505            };
506        },
507        timezone: function (s) {
508            return function () {
509                var n = s.replace(/[^\d\+\-]/g, "");
510                if (n.length) {
511                    this.timezoneOffset = Number(n);
512                } else {
513                    this.timezone = s.toLowerCase();
514                }
515            };
516        },
517        day: function (x) {
518            var s = x[0];
519            return function () {
520                this.day = Number(s.match(/\d+/)[0]);
521            };
522        },
523        month: function (s) {
524            return function () {
525                this.month = (s.length == 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
526            };
527        },
528        year: function (s) {
529            return function () {
530                var n = Number(s);
531                this.year = ((s.length > 2) ? n :
532                    (n + (((n + 2000) < $C.twoDigitYearMax) ? 2000 : 1900)));
533            };
534        },
535        rday: function (s) {
536            return function () {
537                switch (s) {
538                case "yesterday":
539                    this.days = -1;
540                    break;
541                case "tomorrow": 
542                    this.days = 1;
543                    break;
544                case "today":
545                    this.days = 0;
546                    break;
547                case "now":
548                    this.days = 0;
549                    this.now = true;
550                    break;
551                }
552            };
553        },
554        finishExact: function (x) { 
555            x = (x instanceof Array) ? x : [ x ];
556
557            for (var i = 0 ; i < x.length ; i++) {
558                if (x[i]) {
559                    x[i].call(this);
560                }
561            }
562           
563            var now = new Date();
564           
565            if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
566                this.day = now.getDate();
567            }
568
569            if (!this.year) {
570                this.year = now.getFullYear();
571            }
572           
573            if (!this.month && this.month !== 0) {
574                this.month = now.getMonth();
575            }
576           
577            if (!this.day) {
578                this.day = 1;
579            }
580           
581            if (!this.hour) {
582                this.hour = 0;
583            }
584           
585            if (!this.minute) {
586                this.minute = 0;
587            }
588
589            if (!this.second) {
590                this.second = 0;
591            }
592
593            if (this.meridian && this.hour) {
594                if (this.meridian == "p" && this.hour < 12) {
595                    this.hour = this.hour + 12;
596                } else if (this.meridian == "a" && this.hour == 12) {
597                    this.hour = 0;
598                }
599            }
600           
601            if (this.day > $D.getDaysInMonth(this.year, this.month)) {
602                throw new RangeError(this.day + " is not a valid value for days.");
603            }
604
605            var r = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second);
606
607            if (this.timezone) {
608                r.set({ timezone: this.timezone });
609            } else if (this.timezoneOffset) {
610                r.set({ timezoneOffset: this.timezoneOffset });
611            }
612           
613            return r;
614        },                     
615        finish: function (x) {
616            x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
617
618            if (x.length === 0) {
619                return null;
620            }
621
622            for (var i = 0 ; i < x.length ; i++) {
623                if (typeof x[i] == "function") {
624                    x[i].call(this);
625                }
626            }
627           
628            var today = $D.today();
629           
630            if (this.now && !this.unit && !this.operator) {
631                return new Date();
632            } else if (this.now) {
633                today = new Date();
634            }
635           
636            var expression = !!(this.days && this.days !== null || this.orient || this.operator);
637           
638            var gap, mod, orient;
639            orient = ((this.orient == "past" || this.operator == "subtract") ? -1 : 1);
640           
641            if(!this.now && "hour minute second".indexOf(this.unit) != -1) {
642                today.setTimeToNow();
643            }
644
645            if (this.month || this.month === 0) {
646                if ("year day hour minute second".indexOf(this.unit) != -1) {
647                    this.value = this.month + 1;
648                    this.month = null;
649                    expression = true;
650                }
651            }
652           
653            if (!expression && this.weekday && !this.day && !this.days) {
654                var temp = Date[this.weekday]();
655                this.day = temp.getDate();
656                if (!this.month) {
657                    this.month = temp.getMonth();
658                }
659                this.year = temp.getFullYear();
660            }
661           
662            if (expression && this.weekday && this.unit != "month") {
663                this.unit = "day";
664                gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
665                mod = 7;
666                this.days = gap ? ((gap + (orient * mod)) % mod) : (orient * mod);
667            }
668           
669            if (this.month && this.unit == "day" && this.operator) {
670                this.value = (this.month + 1);
671                this.month = null;
672            }
673       
674            if (this.value != null && this.month != null && this.year != null) {
675                this.day = this.value * 1;
676            }
677     
678            if (this.month && !this.day && this.value) {
679                today.set({ day: this.value * 1 });
680                if (!expression) {
681                    this.day = this.value * 1;
682                }
683            }
684
685            if (!this.month && this.value && this.unit == "month" && !this.now) {
686                this.month = this.value;
687                expression = true;
688            }
689
690            if (expression && (this.month || this.month === 0) && this.unit != "year") {
691                this.unit = "month";
692                gap = (this.month - today.getMonth());
693                mod = 12;
694                this.months = gap ? ((gap + (orient * mod)) % mod) : (orient * mod);
695                this.month = null;
696            }
697
698            if (!this.unit) {
699                this.unit = "day";
700            }
701           
702            if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
703                this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator == "add") ? 1 : -1) + (this.value||0) * orient;
704            } else if (this[this.unit + "s"] == null || this.operator != null) {
705                if (!this.value) {
706                    this.value = 1;
707                }
708                this[this.unit + "s"] = this.value * orient;
709            }
710
711            if (this.meridian && this.hour) {
712                if (this.meridian == "p" && this.hour < 12) {
713                    this.hour = this.hour + 12;
714                } else if (this.meridian == "a" && this.hour == 12) {
715                    this.hour = 0;
716                }
717            }
718           
719            if (this.weekday && !this.day && !this.days) {
720                var temp = Date[this.weekday]();
721                this.day = temp.getDate();
722                if (temp.getMonth() !== today.getMonth()) {
723                    this.month = temp.getMonth();
724                }
725            }
726           
727            if ((this.month || this.month === 0) && !this.day) {
728                this.day = 1;
729            }
730           
731            if (!this.orient && !this.operator && this.unit == "week" && this.value && !this.day && !this.month) {
732                return Date.today().setWeek(this.value);
733            }
734
735            if (expression && this.timezone && this.day && this.days) {
736                this.day = this.days;
737            }
738           
739            return (expression) ? today.add(this) : today.set(this);
740        }
741    };
742
743    var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
744
745    g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
746    g.timePartDelimiter = _.stoken(":");
747    g.whiteSpace = _.rtoken(/^\s*/);
748    g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
749 
750    var _C = {};
751    g.ctoken = function (keys) {
752        var fn = _C[keys];
753        if (! fn) {
754            var c = $C.regexPatterns;
755            var kx = keys.split(/\s+/), px = [];
756            for (var i = 0; i < kx.length ; i++) {
757                px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
758            }
759            fn = _C[keys] = _.any.apply(null, px);
760        }
761        return fn;
762    };
763    g.ctoken2 = function (key) {
764        return _.rtoken($C.regexPatterns[key]);
765    };
766
767    // hour, minute, second, meridian, timezone
768    g.h = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/), t.hour));
769    g.hh = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/), t.hour));
770    g.H = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/), t.hour));
771    g.HH = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/), t.hour));
772    g.m = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.minute));
773    g.mm = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.minute));
774    g.s = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.second));
775    g.ss = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.second));
776    g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
777 
778    // _.min(1, _.set([ g.H, g.m, g.s ], g._t));
779    g.t = _.cache(_.process(g.ctoken2("shortMeridian"), t.meridian));
780    g.tt = _.cache(_.process(g.ctoken2("longMeridian"), t.meridian));
781    g.z = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone));
782    g.zz = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone));
783   
784    g.zzz = _.cache(_.process(g.ctoken2("timezone"), t.timezone));
785    g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
786    g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
787         
788    // days, months, years
789    g.d = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),
790        _.optional(g.ctoken2("ordinalSuffix"))), t.day));
791    g.dd = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),
792        _.optional(g.ctoken2("ordinalSuffix"))), t.day));
793    g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
794        function (s) {
795            return function () {
796                this.weekday = s;
797            };
798        }
799    ));
800    g.M = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/), t.month));
801    g.MM = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/), t.month));
802    g.MMM = g.MMMM = _.cache(_.process(
803        g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
804    g.y = _.cache(_.process(_.rtoken(/^(\d\d?)/), t.year));
805    g.yy = _.cache(_.process(_.rtoken(/^(\d\d)/), t.year));
806    g.yyy = _.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/), t.year));
807    g.yyyy = _.cache(_.process(_.rtoken(/^(\d\d\d\d)/), t.year));
808       
809        // rolling these up into general purpose rules
810    _fn = function () {
811        return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
812    };
813   
814    g.day = _fn(g.d, g.dd);
815    g.month = _fn(g.M, g.MMM);
816    g.year = _fn(g.yyyy, g.yy);
817
818    // relative date / time expressions
819    g.orientation = _.process(g.ctoken("past future"),
820        function (s) {
821            return function () {
822                this.orient = s;
823            };
824        }
825    );
826    g.operator = _.process(g.ctoken("add subtract"),
827        function (s) {
828            return function () {
829                this.operator = s;
830            };
831        }
832    ); 
833    g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
834    g.unit = _.process(g.ctoken("second minute hour day week month year"),
835        function (s) {
836            return function () {
837                this.unit = s;
838            };
839        }
840    );
841    g.value = _.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),
842        function (s) {
843            return function () {
844                this.value = s.replace(/\D/g, "");
845            };
846        }
847    );
848    g.expression = _.set([ g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
849
850    // pre-loaded rules for different date part order preferences
851    _fn = function () {
852        return  _.set(arguments, g.datePartDelimiter);
853    };
854    g.mdy = _fn(g.ddd, g.month, g.day, g.year);
855    g.ymd = _fn(g.ddd, g.year, g.month, g.day);
856    g.dmy = _fn(g.ddd, g.day, g.month, g.year);
857    g.date = function (s) {
858        return ((g[$C.dateElementOrder] || g.mdy).call(this, s));
859    };
860
861    // parsing date format specifiers - ex: "h:m:s tt"
862    // this little guy will generate a custom parser based
863    // on the format string, ex: g.format("h:m:s tt")
864    g.format = _.process(_.many(
865        _.any(
866        // translate format specifiers into grammar rules
867        _.process(
868        _.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
869        function (fmt) {
870        if (g[fmt]) {
871            return g[fmt];
872        } else {
873            throw $D.Parsing.Exception(fmt);
874        }
875    }
876    ),
877    // translate separator tokens into token rules
878    _.process(
879    _.rtoken(/^[^dMyhHmstz]+/), // all legal separators
880        function (s) {
881            return _.ignore(_.stoken(s));
882        }
883    )
884    )),
885        // construct the parser ...
886        function (rules) {
887            return _.process(_.each.apply(null, rules), t.finishExact);
888        }
889    );
890   
891    var _F = {
892                //"M/d/yyyy": function (s) {
893                //      var m = s.match(/^([0-2]\d|3[0-1]|\d)\/(1[0-2]|0\d|\d)\/(\d\d\d\d)/);
894                //      if (m!=null) {
895                //              var r =  [ t.month.call(this,m[1]), t.day.call(this,m[2]), t.year.call(this,m[3]) ];
896                //              r = t.finishExact.call(this,r);
897                //              return [ r, "" ];
898                //      } else {
899                //              throw new Date.Parsing.Exception(s);
900                //      }
901                //}
902                //"M/d/yyyy": function (s) { return [ new Date(Date._parse(s)), ""]; }
903        };
904    var _get = function (f) {
905        return _F[f] = (_F[f] || g.format(f)[0]);     
906    };
907 
908    g.formats = function (fx) {
909        if (fx instanceof Array) {
910            var rx = [];
911            for (var i = 0 ; i < fx.length ; i++) {
912                rx.push(_get(fx[i]));
913            }
914            return _.any.apply(null, rx);
915        } else {
916            return _get(fx);
917        }
918    };
919
920        // check for these formats first
921    g._formats = g.formats([
922        "\"yyyy-MM-ddTHH:mm:ssZ\"",
923        "yyyy-MM-ddTHH:mm:ssZ",
924        "yyyy-MM-ddTHH:mm:ssz",
925        "yyyy-MM-ddTHH:mm:ss",
926        "yyyy-MM-ddTHH:mmZ",
927        "yyyy-MM-ddTHH:mmz",
928        "yyyy-MM-ddTHH:mm",
929        "ddd, MMM dd, yyyy H:mm:ss tt",
930        "ddd MMM d yyyy HH:mm:ss zzz",
931        "MMddyyyy",
932        "ddMMyyyy",
933        "Mddyyyy",
934        "ddMyyyy",
935        "Mdyyyy",
936        "dMyyyy",
937        "yyyy",
938        "Mdyy",
939        "dMyy",
940        "d"
941    ]);
942
943        // starting rule for general purpose grammar
944    g._start = _.process(_.set([ g.date, g.time, g.expression ],
945        g.generalDelimiter, g.whiteSpace), t.finish);
946       
947        // real starting rule: tries selected formats first,
948        // then general purpose rule
949    g.start = function (s) {
950        try {
951            var r = g._formats.call({}, s);
952            if (r[1].length === 0) {
953                return r;
954            }
955        } catch (e) {}
956        return g._start.call({}, s);
957    };
958       
959        $D._parse = $D.parse;
960
961    /**
962     * Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
963     *
964     * Example
965    <pre><code>
966    ///////////
967    // Dates //
968    ///////////
969
970    // 15-Oct-2004
971    var d1 = Date.parse("10/15/2004");
972
973    // 15-Oct-2004
974    var d1 = Date.parse("15-Oct-2004");
975
976    // 15-Oct-2004
977    var d1 = Date.parse("2004.10.15");
978
979    //Fri Oct 15, 2004
980    var d1 = Date.parse("Fri Oct 15, 2004");
981
982    ///////////
983    // Times //
984    ///////////
985
986    // Today at 10 PM.
987    var d1 = Date.parse("10 PM");
988
989    // Today at 10:30 PM.
990    var d1 = Date.parse("10:30 P.M.");
991
992    // Today at 6 AM.
993    var d1 = Date.parse("06am");
994
995    /////////////////////
996    // Dates and Times //
997    /////////////////////
998
999    // 8-July-2004 @ 10:30 PM
1000    var d1 = Date.parse("July 8th, 2004, 10:30 PM");
1001
1002    // 1-July-2004 @ 10:30 PM
1003    var d1 = Date.parse("2004-07-01T22:30:00");
1004
1005    ////////////////////
1006    // Relative Dates //
1007    ////////////////////
1008
1009    // Returns today's date. The string "today" is culture specific.
1010    var d1 = Date.parse("today");
1011
1012    // Returns yesterday's date. The string "yesterday" is culture specific.
1013    var d1 = Date.parse("yesterday");
1014
1015    // Returns the date of the next thursday.
1016    var d1 = Date.parse("Next thursday");
1017
1018    // Returns the date of the most previous monday.
1019    var d1 = Date.parse("last monday");
1020
1021    // Returns today's day + one year.
1022    var d1 = Date.parse("next year");
1023
1024    ///////////////
1025    // Date Math //
1026    ///////////////
1027
1028    // Today + 2 days
1029    var d1 = Date.parse("t+2");
1030
1031    // Today + 2 days
1032    var d1 = Date.parse("today + 2 days");
1033
1034    // Today + 3 months
1035    var d1 = Date.parse("t+3m");
1036
1037    // Today - 1 year
1038    var d1 = Date.parse("today - 1 year");
1039
1040    // Today - 1 year
1041    var d1 = Date.parse("t-1y");
1042
1043
1044    /////////////////////////////
1045    // Partial Dates and Times //
1046    /////////////////////////////
1047
1048    // July 15th of this year.
1049    var d1 = Date.parse("July 15");
1050
1051    // 15th day of current day and year.
1052    var d1 = Date.parse("15");
1053
1054    // July 1st of current year at 10pm.
1055    var d1 = Date.parse("7/1 10pm");
1056    </code></pre>
1057     *
1058     * @param {String}   The string value to convert into a Date object [Required]
1059     * @return {Date}    A Date object or null if the string cannot be converted into a Date.
1060     */
1061    $D.parse = function (s) {
1062        var r = null;
1063        if (!s) {
1064            return null;
1065        }
1066        if (s instanceof Date) {
1067            return s;
1068        }
1069        try {
1070            r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
1071        } catch (e) {
1072            return null;
1073        }
1074        return ((r[1].length === 0) ? r[0] : null);
1075    };
1076
1077    $D.getParseFunction = function (fx) {
1078        var fn = $D.Grammar.formats(fx);
1079        return function (s) {
1080            var r = null;
1081            try {
1082                r = fn.call({}, s);
1083            } catch (e) {
1084                return null;
1085            }
1086            return ((r[1].length === 0) ? r[0] : null);
1087        };
1088    };
1089   
1090    /**
1091     * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
1092     * The format of the string value must match one of the supplied formats exactly.
1093     *
1094     * Example
1095    <pre><code>
1096    // 15-Oct-2004
1097    var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
1098
1099    // 15-Oct-2004
1100    var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
1101
1102    // 15-Oct-2004
1103    var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
1104
1105    // Multiple formats
1106    var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
1107    </code></pre>
1108     *
1109     * @param {String}   The string value to convert into a Date object [Required].
1110     * @param {Object}   The expected format {String} or an array of expected formats {Array} of the date string [Required].
1111     * @return {Date}    A Date object or null if the string cannot be converted into a Date.
1112     */
1113    $D.parseExact = function (s, fx) {
1114        return $D.getParseFunction(fx)(s);
1115    }; 
1116}());
Note: See TracBrowser for help on using the repository browser.