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