diff options
Diffstat (limited to 'resources/mediawiki.libs/CLDRPluralRuleParser.js')
-rw-r--r-- | resources/mediawiki.libs/CLDRPluralRuleParser.js | 475 |
1 files changed, 0 insertions, 475 deletions
diff --git a/resources/mediawiki.libs/CLDRPluralRuleParser.js b/resources/mediawiki.libs/CLDRPluralRuleParser.js deleted file mode 100644 index 3def37c5..00000000 --- a/resources/mediawiki.libs/CLDRPluralRuleParser.js +++ /dev/null @@ -1,475 +0,0 @@ -/* This is CLDRPluralRuleParser v1.1, ported to MediaWiki ResourceLoader */ - -/** -* CLDRPluralRuleParser.js -* A parser engine for CLDR plural rules. -* -* Copyright 2012 GPLV3+, Santhosh Thottingal -* -* @version 0.1.0-alpha -* @source https://github.com/santhoshtr/CLDRPluralRuleParser -* @author Santhosh Thottingal <santhosh.thottingal@gmail.com> -* @author Timo Tijhof -* @author Amir Aharoni -*/ - -( function ( mw ) { -/** - * Evaluates a plural rule in CLDR syntax for a number - * @param {string} rule - * @param {integer} number - * @return {boolean} true if evaluation passed, false if evaluation failed. - */ - -function pluralRuleParser(rule, number) { - /* - Syntax: see http://unicode.org/reports/tr35/#Language_Plural_Rules - ----------------------------------------------------------------- - condition = and_condition ('or' and_condition)* - ('@integer' samples)? - ('@decimal' samples)? - and_condition = relation ('and' relation)* - relation = is_relation | in_relation | within_relation - is_relation = expr 'is' ('not')? value - in_relation = expr (('not')? 'in' | '=' | '!=') range_list - within_relation = expr ('not')? 'within' range_list - expr = operand (('mod' | '%') value)? - operand = 'n' | 'i' | 'f' | 't' | 'v' | 'w' - range_list = (range | value) (',' range_list)* - value = digit+ - digit = 0|1|2|3|4|5|6|7|8|9 - range = value'..'value - samples = sampleRange (',' sampleRange)* (',' ('…'|'...'))? - sampleRange = decimalValue '~' decimalValue - decimalValue = value ('.' value)? - */ - - // we don't evaluate the samples section of the rule. Ignore it. - rule = rule.split('@')[0].trim(); - - if (!rule.length) { - // empty rule or 'other' rule. - return true; - } - // Indicates current position in the rule as we parse through it. - // Shared among all parsing functions below. - var pos = 0, - operand, - expression, - relation, - result, - whitespace = makeRegexParser(/^\s+/), - value = makeRegexParser(/^\d+/), - _n_ = makeStringParser('n'), - _i_ = makeStringParser('i'), - _f_ = makeStringParser('f'), - _t_ = makeStringParser('t'), - _v_ = makeStringParser('v'), - _w_ = makeStringParser('w'), - _is_ = makeStringParser('is'), - _isnot_ = makeStringParser('is not'), - _isnot_sign_ = makeStringParser('!='), - _equal_ = makeStringParser('='), - _mod_ = makeStringParser('mod'), - _percent_ = makeStringParser('%'), - _not_ = makeStringParser('not'), - _in_ = makeStringParser('in'), - _within_ = makeStringParser('within'), - _range_ = makeStringParser('..'), - _comma_ = makeStringParser(','), - _or_ = makeStringParser('or'), - _and_ = makeStringParser('and'); - - function debug() { - // console.log.apply(console, arguments); - } - - debug('pluralRuleParser', rule, number); - - // Try parsers until one works, if none work return null - - function choice(parserSyntax) { - return function() { - for (var i = 0; i < parserSyntax.length; i++) { - var result = parserSyntax[i](); - if (result !== null) { - return result; - } - } - return null; - }; - } - - // Try several parserSyntax-es in a row. - // All must succeed; otherwise, return null. - // This is the only eager one. - - function sequence(parserSyntax) { - var originalPos = pos; - var result = []; - for (var i = 0; i < parserSyntax.length; i++) { - var res = parserSyntax[i](); - if (res === null) { - pos = originalPos; - return null; - } - result.push(res); - } - return result; - } - - // Run the same parser over and over until it fails. - // Must succeed a minimum of n times; otherwise, return null. - - function nOrMore(n, p) { - return function() { - var originalPos = pos; - var result = []; - var parsed = p(); - while (parsed !== null) { - result.push(parsed); - parsed = p(); - } - if (result.length < n) { - pos = originalPos; - return null; - } - return result; - }; - } - - // Helpers -- just make parserSyntax out of simpler JS builtin types - function makeStringParser(s) { - var len = s.length; - return function() { - var result = null; - if (rule.substr(pos, len) === s) { - result = s; - pos += len; - } - - return result; - }; - } - - function makeRegexParser(regex) { - return function() { - var matches = rule.substr(pos).match(regex); - if (matches === null) { - return null; - } - pos += matches[0].length; - return matches[0]; - }; - } - - /* - * integer digits of n. - */ - function i() { - var result = _i_(); - if (result === null) { - debug(' -- failed i', parseInt(number, 10)); - return result; - } - result = parseInt(number, 10); - debug(' -- passed i ', result); - return result; - } - - /* - * absolute value of the source number (integer and decimals). - */ - function n() { - var result = _n_(); - if (result === null) { - debug(' -- failed n ', number); - return result; - } - result = parseFloat(number, 10); - debug(' -- passed n ', result); - return result; - } - - /* - * visible fractional digits in n, with trailing zeros. - */ - function f() { - var result = _f_(); - if (result === null) { - debug(' -- failed f ', number); - return result; - } - result = (number + '.').split('.')[1] || 0; - debug(' -- passed f ', result); - return result; - } - - /* - * visible fractional digits in n, without trailing zeros. - */ - function t() { - var result = _t_(); - if (result === null) { - debug(' -- failed t ', number); - return result; - } - result = (number + '.').split('.')[1].replace(/0$/, '') || 0; - debug(' -- passed t ', result); - return result; - } - - /* - * number of visible fraction digits in n, with trailing zeros. - */ - function v() { - var result = _v_(); - if (result === null) { - debug(' -- failed v ', number); - return result; - } - result = (number + '.').split('.')[1].length || 0; - debug(' -- passed v ', result); - return result; - } - - /* - * number of visible fraction digits in n, without trailing zeros. - */ - function w() { - var result = _w_(); - if (result === null) { - debug(' -- failed w ', number); - return result; - } - result = (number + '.').split('.')[1].replace(/0$/, '').length || 0; - debug(' -- passed w ', result); - return result; - } - - // operand = 'n' | 'i' | 'f' | 't' | 'v' | 'w' - operand = choice([n, i, f, t, v, w]); - - // expr = operand (('mod' | '%') value)? - expression = choice([mod, operand]); - - function mod() { - var result = sequence([operand, whitespace, choice([_mod_, _percent_]), whitespace, value]); - if (result === null) { - debug(' -- failed mod'); - return null; - } - debug(' -- passed ' + parseInt(result[0], 10) + ' ' + result[2] + ' ' + parseInt(result[4], 10)); - return parseInt(result[0], 10) % parseInt(result[4], 10); - } - - function not() { - var result = sequence([whitespace, _not_]); - if (result === null) { - debug(' -- failed not'); - return null; - } - - return result[1]; - } - - // is_relation = expr 'is' ('not')? value - function is() { - var result = sequence([expression, whitespace, choice([_is_]), whitespace, value]); - if (result !== null) { - debug(' -- passed is : ' + result[0] + ' == ' + parseInt(result[4], 10)); - return result[0] === parseInt(result[4], 10); - } - debug(' -- failed is'); - return null; - } - - // is_relation = expr 'is' ('not')? value - function isnot() { - var result = sequence([expression, whitespace, choice([_isnot_, _isnot_sign_]), whitespace, value]); - if (result !== null) { - debug(' -- passed isnot: ' + result[0] + ' != ' + parseInt(result[4], 10)); - return result[0] !== parseInt(result[4], 10); - } - debug(' -- failed isnot'); - return null; - } - - function not_in() { - var result = sequence([expression, whitespace, _isnot_sign_, whitespace, rangeList]); - if (result !== null) { - debug(' -- passed not_in: ' + result[0] + ' != ' + result[4]); - var range_list = result[4]; - for (var i = 0; i < range_list.length; i++) { - if (parseInt(range_list[i], 10) === parseInt(result[0], 10)) { - return false; - } - } - return true; - } - debug(' -- failed not_in'); - return null; - } - - // range_list = (range | value) (',' range_list)* - function rangeList() { - var result = sequence([choice([range, value]), nOrMore(0, rangeTail)]); - var resultList = []; - if (result !== null) { - resultList = resultList.concat(result[0]); - if (result[1][0]) { - resultList = resultList.concat(result[1][0]); - } - return resultList; - } - debug(' -- failed rangeList'); - return null; - } - - function rangeTail() { - // ',' range_list - var result = sequence([_comma_, rangeList]); - if (result !== null) { - return result[1]; - } - debug(' -- failed rangeTail'); - return null; - } - - // range = value'..'value - - function range() { - var i; - var result = sequence([value, _range_, value]); - if (result !== null) { - debug(' -- passed range'); - var array = []; - var left = parseInt(result[0], 10); - var right = parseInt(result[2], 10); - for (i = left; i <= right; i++) { - array.push(i); - } - return array; - } - debug(' -- failed range'); - return null; - } - - function _in() { - // in_relation = expr ('not')? 'in' range_list - var result = sequence([expression, nOrMore(0, not), whitespace, choice([_in_, _equal_]), whitespace, rangeList]); - if (result !== null) { - debug(' -- passed _in:' + result); - var range_list = result[5]; - for (var i = 0; i < range_list.length; i++) { - if (parseInt(range_list[i], 10) === parseInt(result[0], 10)) { - return (result[1][0] !== 'not'); - } - } - return (result[1][0] === 'not'); - } - debug(' -- failed _in '); - return null; - } - - /* - * The difference between in and within is that in only includes integers in the specified range, - * while within includes all values. - */ - - function within() { - // within_relation = expr ('not')? 'within' range_list - var result = sequence([expression, nOrMore(0, not), whitespace, _within_, whitespace, rangeList]); - if (result !== null) { - debug(' -- passed within'); - var range_list = result[5]; - if ((result[0] >= parseInt(range_list[0], 10)) && - (result[0] < parseInt(range_list[range_list.length - 1], 10))) { - return (result[1][0] !== 'not'); - } - return (result[1][0] === 'not'); - } - debug(' -- failed within '); - return null; - } - - // relation = is_relation | in_relation | within_relation - relation = choice([is, not_in, isnot, _in, within]); - - // and_condition = relation ('and' relation)* - function and() { - var result = sequence([relation, nOrMore(0, andTail)]); - if (result) { - if (!result[0]) { - return false; - } - for (var i = 0; i < result[1].length; i++) { - if (!result[1][i]) { - return false; - } - } - return true; - } - debug(' -- failed and'); - return null; - } - - // ('and' relation)* - function andTail() { - var result = sequence([whitespace, _and_, whitespace, relation]); - if (result !== null) { - debug(' -- passed andTail' + result); - return result[3]; - } - debug(' -- failed andTail'); - return null; - - } - // ('or' and_condition)* - function orTail() { - var result = sequence([whitespace, _or_, whitespace, and]); - if (result !== null) { - debug(' -- passed orTail: ' + result[3]); - return result[3]; - } - debug(' -- failed orTail'); - return null; - - } - - // condition = and_condition ('or' and_condition)* - function condition() { - var result = sequence([and, nOrMore(0, orTail)]); - if (result) { - for (var i = 0; i < result[1].length; i++) { - if (result[1][i]) { - return true; - } - } - return result[0]; - - } - return false; - } - - result = condition(); - /* - * For success, the pos must have gotten to the end of the rule - * and returned a non-null. - * n.b. This is part of language infrastructure, so we do not throw an internationalizable message. - */ - if (result === null) { - throw new Error('Parse error at position ' + pos.toString() + ' for rule: ' + rule); - } - - if (pos !== rule.length) { - debug('Warning: Rule not parsed completely. Parser stopped at ' + rule.substr(0, pos) + ' for rule: ' + rule); - } - - return result; -} - -/* pluralRuleParser ends here */ -mw.libs.pluralRuleParser = pluralRuleParser; - -} )( mediaWiki ); |