| // 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); |