OLD | NEW |
1 #!/usr/bin/python2.4 | 1 #!/usr/bin/python2.4 |
2 | 2 |
3 # Copyright 2012 the V8 project authors. All rights reserved. | 3 # Copyright 2012 the V8 project authors. All rights reserved. |
4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
6 # met: | 6 # met: |
7 # | 7 # |
8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 declarations. (These last two must be on one line including the opening | 93 declarations. (These last two must be on one line including the opening |
94 curly brace of the function for their variables to be renamed). | 94 curly brace of the function for their variables to be renamed). |
95 | 95 |
96 Args: | 96 Args: |
97 m: The match object returned by re.search. | 97 m: The match object returned by re.search. |
98 | 98 |
99 Returns: | 99 Returns: |
100 The string that should replace the match in the rewritten program. | 100 The string that should replace the match in the rewritten program. |
101 """ | 101 """ |
102 matched_text = m.group(0) | 102 matched_text = m.group(0) |
103 | |
104 if matched_text.startswith("`") and matched_text.endswith("`"): | |
105 return re.sub(r"\$\{([\w$%]+)\}", | |
106 lambda m: '${' + self.FindNewName(m.group(1)) + '}', | |
107 matched_text) | |
108 | |
109 if matched_text == "{": | 103 if matched_text == "{": |
110 self.Push() | 104 self.Push() |
111 return matched_text | 105 return matched_text |
112 if matched_text == "}": | 106 if matched_text == "}": |
113 self.Pop() | 107 self.Pop() |
114 return matched_text | 108 return matched_text |
115 if re.match("[\"'/]", matched_text): | 109 if re.match("[\"'/]", matched_text): |
116 return matched_text | 110 return matched_text |
117 m = re.match(r"var ", matched_text) | 111 m = re.match(r"var ", matched_text) |
118 if m: | 112 if m: |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 The new name of the variable. | 145 The new name of the variable. |
152 """ | 146 """ |
153 new_identifier = "" | 147 new_identifier = "" |
154 # Variable names that end in _ are member variables of the global object, | 148 # Variable names that end in _ are member variables of the global object, |
155 # so they can be visible from code in a different scope. We leave them | 149 # so they can be visible from code in a different scope. We leave them |
156 # alone. | 150 # alone. |
157 if var_name in self.map: | 151 if var_name in self.map: |
158 return self.map[var_name] | 152 return self.map[var_name] |
159 if self.nesting == 0: | 153 if self.nesting == 0: |
160 return var_name | 154 return var_name |
161 # Do not rename arguments object. | |
162 if var_name == 'arguments': | |
163 return 'arguments' | |
164 while True: | 155 while True: |
165 identifier_first_char = self.identifier_counter % 52 | 156 identifier_first_char = self.identifier_counter % 52 |
166 identifier_second_char = self.identifier_counter // 52 | 157 identifier_second_char = self.identifier_counter // 52 |
167 new_identifier = self.CharFromNumber(identifier_first_char) | 158 new_identifier = self.CharFromNumber(identifier_first_char) |
168 if identifier_second_char != 0: | 159 if identifier_second_char != 0: |
169 new_identifier = ( | 160 new_identifier = ( |
170 self.CharFromNumber(identifier_second_char - 1) + new_identifier) | 161 self.CharFromNumber(identifier_second_char - 1) + new_identifier) |
171 self.identifier_counter += 1 | 162 self.identifier_counter += 1 |
172 if not new_identifier in self.seen_identifiers: | 163 if not new_identifier in self.seen_identifiers: |
173 break | 164 break |
(...skipping 12 matching lines...) Expand all Loading... |
186 | 177 |
187 Returns: | 178 Returns: |
188 The string that should be inserted instead of the matched text. | 179 The string that should be inserted instead of the matched text. |
189 """ | 180 """ |
190 entire_match = m.group(0) | 181 entire_match = m.group(0) |
191 replacement = m.group(1) | 182 replacement = m.group(1) |
192 if re.match(r"'.*'$", entire_match): | 183 if re.match(r"'.*'$", entire_match): |
193 return entire_match | 184 return entire_match |
194 if re.match(r'".*"$', entire_match): | 185 if re.match(r'".*"$', entire_match): |
195 return entire_match | 186 return entire_match |
196 if re.match(r"`.*`$", entire_match): | |
197 return entire_match | |
198 if re.match(r"/.+/$", entire_match): | 187 if re.match(r"/.+/$", entire_match): |
199 return entire_match | 188 return entire_match |
200 return replacement | 189 return replacement |
201 | 190 |
202 def JSMinify(self, text): | 191 def JSMinify(self, text): |
203 """The main entry point. Takes a text and returns a compressed version. | 192 """The main entry point. Takes a text and returns a compressed version. |
204 | 193 |
205 The compressed version hopefully does the same thing. Line breaks are | 194 The compressed version hopefully does the same thing. Line breaks are |
206 preserved. | 195 preserved. |
207 | 196 |
(...skipping 23 matching lines...) Expand all Loading... |
231 line = line[:m.start()] | 220 line = line[:m.start()] |
232 self.in_comment = True | 221 self.in_comment = True |
233 | 222 |
234 # Strip leading and trailing spaces. | 223 # Strip leading and trailing spaces. |
235 line = re.sub(r"^ +", "", line) | 224 line = re.sub(r"^ +", "", line) |
236 line = re.sub(r" +$", "", line) | 225 line = re.sub(r" +$", "", line) |
237 # A regexp that matches a literal string surrounded by "double quotes". | 226 # A regexp that matches a literal string surrounded by "double quotes". |
238 # This regexp can handle embedded backslash-escaped characters including | 227 # This regexp can handle embedded backslash-escaped characters including |
239 # embedded backslash-escaped double quotes. | 228 # embedded backslash-escaped double quotes. |
240 double_quoted_string = r'"(?:[^"\\]|\\.)*"' | 229 double_quoted_string = r'"(?:[^"\\]|\\.)*"' |
241 # A regexp that matches a literal string surrounded by 'single quotes'. | 230 # A regexp that matches a literal string surrounded by 'double quotes'. |
242 single_quoted_string = r"'(?:[^'\\]|\\.)*'" | 231 single_quoted_string = r"'(?:[^'\\]|\\.)*'" |
243 # A regexp that matches a template string | |
244 template_string = r"`(?:[^'\\]|\\.)*`" | |
245 # A regexp that matches a regexp literal surrounded by /slashes/. | 232 # A regexp that matches a regexp literal surrounded by /slashes/. |
246 # Don't allow a regexp to have a ) before the first ( since that's a | 233 # Don't allow a regexp to have a ) before the first ( since that's a |
247 # syntax error and it's probably just two unrelated slashes. | 234 # syntax error and it's probably just two unrelated slashes. |
248 # Also don't allow it to come after anything that can only be the | 235 # Also don't allow it to come after anything that can only be the |
249 # end of a primary expression. | 236 # end of a primary expression. |
250 slash_quoted_regexp = r"(?<![\w$'\")\]])/(?:(?=\()|(?:[^()/\\]|\\.)+)(?:\(
[^/\\]|\\.)*/" | 237 slash_quoted_regexp = r"(?<![\w$'\")\]])/(?:(?=\()|(?:[^()/\\]|\\.)+)(?:\(
[^/\\]|\\.)*/" |
251 # Replace multiple spaces with a single space. | 238 # Replace multiple spaces with a single space. |
252 line = re.sub("|".join([double_quoted_string, | 239 line = re.sub("|".join([double_quoted_string, |
253 single_quoted_string, | 240 single_quoted_string, |
254 template_string, | |
255 slash_quoted_regexp, | 241 slash_quoted_regexp, |
256 "( )+"]), | 242 "( )+"]), |
257 self.RemoveSpaces, | 243 self.RemoveSpaces, |
258 line) | 244 line) |
259 # Strip single spaces unless they have an identifier character both before | 245 # Strip single spaces unless they have an identifier character both before |
260 # and after the space. % and $ are counted as identifier characters. | 246 # and after the space. % and $ are counted as identifier characters. |
261 line = re.sub("|".join([double_quoted_string, | 247 line = re.sub("|".join([double_quoted_string, |
262 single_quoted_string, | 248 single_quoted_string, |
263 template_string, | |
264 slash_quoted_regexp, | 249 slash_quoted_regexp, |
265 r"(?<![a-zA-Z_0-9$%]) | (?![a-zA-Z_0-9$%])()"]), | 250 r"(?<![a-zA-Z_0-9$%]) | (?![a-zA-Z_0-9$%])()"]), |
266 self.RemoveSpaces, | 251 self.RemoveSpaces, |
267 line) | 252 line) |
268 # Collect keywords and identifiers that are already in use. | 253 # Collect keywords and identifiers that are already in use. |
269 if self.nesting == 0: | 254 if self.nesting == 0: |
270 re.sub(r"([a-zA-Z0-9_$%]+)", self.LookAtIdentifier, line) | 255 re.sub(r"([a-zA-Z0-9_$%]+)", self.LookAtIdentifier, line) |
271 function_declaration_regexp = ( | 256 function_declaration_regexp = ( |
272 r"\bfunction" # Function definition keyword... | 257 r"\bfunction" # Function definition keyword... |
273 r"( [\w$%]+)?" # ...optional function name... | 258 r"( [\w$%]+)?" # ...optional function name... |
274 r"\([\w$%,]+\)\{") # ...argument declarations. | 259 r"\([\w$%,]+\)\{") # ...argument declarations. |
275 # Unfortunately the keyword-value syntax { key:value } makes the key look | 260 # Unfortunately the keyword-value syntax { key:value } makes the key look |
276 # like a variable where in fact it is a literal string. We use the | 261 # like a variable where in fact it is a literal string. We use the |
277 # presence or absence of a question mark to try to distinguish between | 262 # presence or absence of a question mark to try to distinguish between |
278 # this case and the ternary operator: "condition ? iftrue : iffalse". | 263 # this case and the ternary operator: "condition ? iftrue : iffalse". |
279 if re.search(r"\?", line): | 264 if re.search(r"\?", line): |
280 block_trailing_colon = r"" | 265 block_trailing_colon = r"" |
281 else: | 266 else: |
282 block_trailing_colon = r"(?![:\w$%])" | 267 block_trailing_colon = r"(?![:\w$%])" |
283 # Variable use. Cannot follow a period precede a colon. | 268 # Variable use. Cannot follow a period precede a colon. |
284 variable_use_regexp = r"(?<![.\w$%])[\w$%]+" + block_trailing_colon | 269 variable_use_regexp = r"(?<![.\w$%])[\w$%]+" + block_trailing_colon |
285 line = re.sub("|".join([double_quoted_string, | 270 line = re.sub("|".join([double_quoted_string, |
286 single_quoted_string, | 271 single_quoted_string, |
287 template_string, | |
288 slash_quoted_regexp, | 272 slash_quoted_regexp, |
289 r"\{", # Curly braces. | 273 r"\{", # Curly braces. |
290 r"\}", | 274 r"\}", |
291 r"\bvar [\w$%,]+", # var declarations. | 275 r"\bvar [\w$%,]+", # var declarations. |
292 function_declaration_regexp, | 276 function_declaration_regexp, |
293 variable_use_regexp]), | 277 variable_use_regexp]), |
294 self.Declaration, | 278 self.Declaration, |
295 line) | 279 line) |
296 new_lines.append(line) | 280 new_lines.append(line) |
297 | 281 |
298 return "\n".join(new_lines) + "\n" | 282 return "\n".join(new_lines) + "\n" |
OLD | NEW |