(function () {
var $D = Date;
$D.Grammar = {};
var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
// Allow rolling up into general purpose rules
_fn = function () {
return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
};
g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
g.timePartDelimiter = _.stoken(":");
g.whiteSpace = _.rtoken(/^\s*/);
g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
var _C = {};
g.ctoken = function (keys) {
var fn = _C[keys];
if (! fn) {
var c = Date.CultureInfo.regexPatterns;
var kx = keys.split(/\s+/), px = [];
for (var i = 0; i < kx.length ; i++) {
px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
}
fn = _C[keys] = _.any.apply(null, px);
}
return fn;
};
g.ctoken2 = function (key) {
return _.rtoken(Date.CultureInfo.regexPatterns[key]);
};
var cacheProcessRtoken = function (key, token, type, eachToken) {
if (eachToken) {
g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
} else {
g[key] = _.cache(_.process(_.rtoken(token), type));
}
};
var cacheProcessCtoken = function (token, type) {
return _.cache(_.process(g.ctoken2(token), type));
};
var _F = {}; //function cache
var _get = function (f) {
_F[f] = (_F[f] || g.format(f)[0]);
return _F[f];
};
g.allformats = function (fx) {
var rx = [];
if (fx instanceof Array) {
for (var i = 0; i < fx.length; i++) {
rx.push(_get(fx[i]));
}
} else {
rx.push(_get(fx));
}
return rx;
};
g.formats = function (fx) {
if (fx instanceof Array) {
var rx = [];
for (var i = 0 ; i < fx.length ; i++) {
rx.push(_get(fx[i]));
}
return _.any.apply(null, rx);
} else {
return _get(fx);
}
};
var grammarFormats = {
timeFormats: function(){
var i,
RTokenKeys = [
"h",
"hh",
"H",
"HH",
"m",
"mm",
"s",
"ss",
"ss.s",
"z",
"zz"
],
RToken = [
/^(0[0-9]|1[0-2]|[1-9])/,
/^(0[0-9]|1[0-2])/,
/^([0-1][0-9]|2[0-3]|[0-9])/,
/^([0-1][0-9]|2[0-3])/,
/^([0-5][0-9]|[0-9])/,
/^[0-5][0-9]/,
/^([0-5][0-9]|[0-9])/,
/^[0-5][0-9]/,
/^[0-5][0-9]\.[0-9]{1,3}/,
/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
],
tokens = [
t.hour,
t.hour,
t.hour,
t.minute,
t.minute,
t.second,
t.second,
t.secondAndMillisecond,
t.timezone,
t.timezone,
t.timezone
];
for (i=0; i < RTokenKeys.length; i++) {
cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
}
g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
g.t = cacheProcessCtoken("shortMeridian", t.meridian);
g.tt = cacheProcessCtoken("longMeridian", t.meridian);
g.zzz = cacheProcessCtoken("timezone", t.timezone);
g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
},
dateFormats: function () {
// pre-loaded rules for different date part order preferences
var _setfn = function () {
return _.set(arguments, g.datePartDelimiter);
};
var i,
RTokenKeys = [
"d",
"dd",
"M",
"MM",
"y",
"yy",
"yyy",
"yyyy"
],
RToken = [
/^([0-2]\d|3[0-1]|\d)/,
/^([0-2]\d|3[0-1])/,
/^(1[0-2]|0\d|\d)/,
/^(1[0-2]|0\d)/,
/^(\d+)/,
/^(\d\d)/,
/^(\d\d?\d?\d?)/,
/^(\d\d\d\d)/
],
tokens = [
t.day,
t.day,
t.month,
t.month,
t.year,
t.year,
t.year,
t.year
],
eachToken = [
"ordinalSuffix",
"ordinalSuffix"
];
for (i=0; i < RTokenKeys.length; i++) {
cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
}
g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
function (s) {
return function () {
this.weekday = s;
};
}
));
g.day = _fn(g.d, g.dd);
g.month = _fn(g.M, g.MMM);
g.year = _fn(g.yyyy, g.yy);
g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
g.date = function (s) {
return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
};
},
relative: function () {
// relative date / time expressions
g.orientation = _.process(g.ctoken("past future"),
function (s) {
return function () {
this.orient = s;
};
}
);
g.operator = _.process(g.ctoken("add subtract"),
function (s) {
return function () {
this.operator = s;
};
}
);
g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
g.unit = _.process(g.ctoken("second minute hour day week month year"),
function (s) {
return function () {
this.unit = s;
};
}
);
}
};
g.buildGrammarFormats = function () {
// these need to be rebuilt every time the language changes.
_C = {};
grammarFormats.timeFormats();
grammarFormats.dateFormats();
grammarFormats.relative();
g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
function (s) {
return function () {
this.value = s.replace(/\D/g, "");
};
}
);
g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
g.format = _.process(_.many(
_.any(
// translate format specifiers into grammar rules
_.process(
_.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
function (fmt) {
if (g[fmt]) {
return g[fmt];
} else {
throw $D.Parsing.Exception(fmt);
}
}
),
// translate separator tokens into token rules
_.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
function (s) {
return _.ignore(_.stoken(s));
}
)
)
),
// construct the parser ...
function (rules) {
return _.process(_.each.apply(null, rules), t.finishExact);
}
);
// starting rule for general purpose grammar
g._start = _.process(_.set([ g.date, g.time, g.expression ],
g.generalDelimiter, g.whiteSpace), t.finish);
};
g.buildGrammarFormats();
// parsing date format specifiers - ex: "h:m:s tt"
// this little guy will generate a custom parser based
// on the format string, ex: g.format("h:m:s tt")
// check for these formats first
g._formats = g.formats([
"\"yyyy-MM-ddTHH:mm:ssZ\"",
"yyyy-MM-ddTHH:mm:ss.sz",
"yyyy-MM-ddTHH:mm:ssZ",
"yyyy-MM-ddTHH:mm:ssz",
"yyyy-MM-ddTHH:mm:ss",
"yyyy-MM-ddTHH:mmZ",
"yyyy-MM-ddTHH:mmz",
"yyyy-MM-ddTHH:mm",
"ddd, MMM dd, yyyy H:mm:ss tt",
"ddd MMM d yyyy HH:mm:ss zzz",
"MMddyyyy",
"ddMMyyyy",
"Mddyyyy",
"ddMyyyy",
"Mdyyyy",
"dMyyyy",
"yyyy",
"Mdyy",
"dMyy",
"d"
]);
// real starting rule: tries selected formats first,
// then general purpose rule
g.start = function (s) {
try {
var r = g._formats.call({}, s);
if (r[1].length === 0) {
return r;
}
} catch (e) {}
return g._start.call({}, s);
};
}());
|