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