blob: d9f05e17e99a4a7747cd8d86d71822518dd4959a [file] [log] [blame]
// 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);