OLD | NEW |
| (Empty) |
1 // Copyright 2014 Google Inc. All rights reserved. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 | |
15 (function(scope) { | |
16 | |
17 // consume* functions return a 2 value array of [parsed-data, '' or not-yet co
nsumed input] | |
18 | |
19 // Regex should be anchored with /^ | |
20 function consumeToken(regex, string) { | |
21 var result = regex.exec(string); | |
22 if (result) { | |
23 result = regex.ignoreCase ? result[0].toLowerCase() : result[0]; | |
24 return [result, string.substr(result.length)]; | |
25 } | |
26 } | |
27 | |
28 function consumeTrimmed(consumer, string) { | |
29 string = string.replace(/^\s*/, ''); | |
30 var result = consumer(string); | |
31 if (result) { | |
32 return [result[0], result[1].replace(/^\s*/, '')]; | |
33 } | |
34 } | |
35 | |
36 function consumeRepeated(consumer, separator, string) { | |
37 consumer = consumeTrimmed.bind(null, consumer); | |
38 var list = []; | |
39 while (true) { | |
40 var result = consumer(string); | |
41 if (!result) { | |
42 return [list, string]; | |
43 } | |
44 list.push(result[0]); | |
45 string = result[1]; | |
46 result = consumeToken(separator, string); | |
47 if (!result || result[1] == '') { | |
48 return [list, string]; | |
49 } | |
50 string = result[1]; | |
51 } | |
52 } | |
53 | |
54 // Consumes a token or expression with balanced parentheses | |
55 function consumeParenthesised(parser, string) { | |
56 var nesting = 0; | |
57 for (var n = 0; n < string.length; n++) { | |
58 if (/\s|,/.test(string[n]) && nesting == 0) { | |
59 break; | |
60 } else if (string[n] == '(') { | |
61 nesting++; | |
62 } else if (string[n] == ')') { | |
63 nesting--; | |
64 if (nesting == 0) | |
65 n++; | |
66 if (nesting <= 0) | |
67 break; | |
68 } | |
69 } | |
70 var parsed = parser(string.substr(0, n)); | |
71 return parsed == undefined ? undefined : [parsed, string.substr(n)]; | |
72 } | |
73 | |
74 function lcm(a, b) { | |
75 var c = a; | |
76 var d = b; | |
77 while (c && d) | |
78 c > d ? c %= d : d %= c; | |
79 c = (a * b) / (c + d); | |
80 return c; | |
81 } | |
82 | |
83 function ignore(value) { | |
84 return function(input) { | |
85 var result = value(input); | |
86 if (result) | |
87 result[0] = undefined; | |
88 return result; | |
89 } | |
90 } | |
91 | |
92 function optional(value, defaultValue) { | |
93 return function(input) { | |
94 var result = value(input); | |
95 if (result) | |
96 return result; | |
97 return [defaultValue, input]; | |
98 } | |
99 } | |
100 | |
101 function consumeList(list, input) { | |
102 var output = []; | |
103 for (var i = 0; i < list.length; i++) { | |
104 var result = scope.consumeTrimmed(list[i], input); | |
105 if (!result || result[0] == '') | |
106 return; | |
107 if (result[0] !== undefined) | |
108 output.push(result[0]); | |
109 input = result[1]; | |
110 } | |
111 if (input == '') { | |
112 return output; | |
113 } | |
114 } | |
115 | |
116 function mergeWrappedNestedRepeated(wrap, nestedMerge, separator, left, right)
{ | |
117 var matchingLeft = []; | |
118 var matchingRight = []; | |
119 var reconsititution = []; | |
120 var length = lcm(left.length, right.length); | |
121 for (var i = 0; i < length; i++) { | |
122 var thing = nestedMerge(left[i % left.length], right[i % right.length]); | |
123 if (!thing) { | |
124 return; | |
125 } | |
126 matchingLeft.push(thing[0]); | |
127 matchingRight.push(thing[1]); | |
128 reconsititution.push(thing[2]); | |
129 } | |
130 return [matchingLeft, matchingRight, function(positions) { | |
131 var result = positions.map(function(position, i) { | |
132 return reconsititution[i](position); | |
133 }).join(separator); | |
134 return wrap ? wrap(result) : result; | |
135 }]; | |
136 } | |
137 | |
138 function mergeList(left, right, list) { | |
139 var lefts = []; | |
140 var rights = []; | |
141 var functions = []; | |
142 var j = 0; | |
143 for (var i = 0; i < list.length; i++) { | |
144 if (typeof list[i] == 'function') { | |
145 var result = list[i](left[j], right[j++]); | |
146 lefts.push(result[0]); | |
147 rights.push(result[1]); | |
148 functions.push(result[2]); | |
149 } else { | |
150 (function(pos) { | |
151 lefts.push(false); | |
152 rights.push(false); | |
153 functions.push(function() { return list[pos]; }); | |
154 })(i); | |
155 } | |
156 } | |
157 return [lefts, rights, function(results) { | |
158 var result = ''; | |
159 for (var i = 0; i < results.length; i++) { | |
160 result += functions[i](results[i]); | |
161 } | |
162 return result; | |
163 }]; | |
164 } | |
165 | |
166 scope.consumeToken = consumeToken; | |
167 scope.consumeTrimmed = consumeTrimmed; | |
168 scope.consumeRepeated = consumeRepeated; | |
169 scope.consumeParenthesised = consumeParenthesised; | |
170 scope.ignore = ignore; | |
171 scope.optional = optional; | |
172 scope.consumeList = consumeList; | |
173 scope.mergeNestedRepeated = mergeWrappedNestedRepeated.bind(null, null); | |
174 scope.mergeWrappedNestedRepeated = mergeWrappedNestedRepeated; | |
175 scope.mergeList = mergeList; | |
176 | |
177 })(webAnimations1); | |
OLD | NEW |