// Copyright 2014 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. (function(scope) { // consume* functions return a 2 value array of [parsed-data, '' or not-yet consumed input] // Regex should be anchored with /^ function consumeToken(regex, string) { var result = regex.exec(string); if (result) { result = regex.ignoreCase ? result[0].toLowerCase() : result[0]; return [result, string.substr(result.length)]; } } function consumeTrimmed(consumer, string) { string = string.replace(/^\s*/, ''); var result = consumer(string); if (result) { return [result[0], result[1].replace(/^\s*/, '')]; } } function consumeRepeated(consumer, separator, string) { consumer = consumeTrimmed.bind(null, consumer); var list = []; while (true) { var result = consumer(string); if (!result) { return [list, string]; } list.push(result[0]); string = result[1]; result = consumeToken(separator, string); if (!result || result[1] == '') { return [list, string]; } string = result[1]; } } // Consumes a token or expression with balanced parentheses function consumeParenthesised(parser, string) { var nesting = 0; for (var n = 0; n < string.length; n++) { if (/\s|,/.test(string[n]) && nesting == 0) { break; } else if (string[n] == '(') { nesting++; } else if (string[n] == ')') { nesting--; if (nesting == 0) n++; if (nesting <= 0) break; } } var parsed = parser(string.substr(0, n)); return parsed == undefined ? undefined : [parsed, string.substr(n)]; } function lcm(a, b) { var c = a; var d = b; while (c && d) c > d ? c %= d : d %= c; c = (a * b) / (c + d); return c; } function ignore(value) { return function(input) { var result = value(input); if (result) result[0] = undefined; return result; } } function optional(value, defaultValue) { return function(input) { var result = value(input); if (result) return result; return [defaultValue, input]; } } function consumeList(list, input) { var output = []; for (var i = 0; i < list.length; i++) { var result = scope.consumeTrimmed(list[i], input); if (!result || result[0] == '') return; if (result[0] !== undefined) output.push(result[0]); input = result[1]; } if (input == '') { return output; } } function mergeWrappedNestedRepeated(wrap, nestedMerge, separator, left, right) { var matchingLeft = []; var matchingRight = []; var reconsititution = []; var length = lcm(left.length, right.length); for (var i = 0; i < length; i++) { var thing = nestedMerge(left[i % left.length], right[i % right.length]); if (!thing) { return; } matchingLeft.push(thing[0]); matchingRight.push(thing[1]); reconsititution.push(thing[2]); } return [matchingLeft, matchingRight, function(positions) { var result = positions.map(function(position, i) { return reconsititution[i](position); }).join(separator); return wrap ? wrap(result) : result; }]; } function mergeList(left, right, list) { var lefts = []; var rights = []; var functions = []; var j = 0; for (var i = 0; i < list.length; i++) { if (typeof list[i] == 'function') { var result = list[i](left[j], right[j++]); lefts.push(result[0]); rights.push(result[1]); functions.push(result[2]); } else { (function(pos) { lefts.push(false); rights.push(false); functions.push(function() { return list[pos]; }); })(i); } } return [lefts, rights, function(results) { var result = ''; for (var i = 0; i < results.length; i++) { result += functions[i](results[i]); } return result; }]; } scope.consumeToken = consumeToken; scope.consumeTrimmed = consumeTrimmed; scope.consumeRepeated = consumeRepeated; scope.consumeParenthesised = consumeParenthesised; scope.ignore = ignore; scope.optional = optional; scope.consumeList = consumeList; scope.mergeNestedRepeated = mergeWrappedNestedRepeated.bind(null, null); scope.mergeWrappedNestedRepeated = mergeWrappedNestedRepeated; scope.mergeList = mergeList; })(webAnimations1);