| 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 |