def remove_constants(source):
source = '<STR_LIT:U+0020>' + source + '<STR_LIT:\n>'<EOL>comments = []<EOL>inside_comment, single_comment = False, False<EOL>inside_single, inside_double = False, False<EOL>inside_regexp = False<EOL>regexp_class_count = <NUM_LIT:0><EOL>n = <NUM_LIT:0><EOL>while n < len(source):<EOL><INDENT>char = source[n]<EOL>if char == '<STR_LIT:">' and not (inside_comment or inside_single<EOL>or inside_regexp):<EOL><INDENT>if not _is_cancelled(source, n):<EOL><INDENT>if inside_double:<EOL><INDENT>inside_double[<NUM_LIT:1>] = n + <NUM_LIT:1><EOL>comments.append(inside_double)<EOL>inside_double = False<EOL><DEDENT>else:<EOL><INDENT>inside_double = [n, None, <NUM_LIT:0>]<EOL><DEDENT><DEDENT><DEDENT>elif char == "<STR_LIT:'>" and not (inside_comment or inside_double<EOL>or inside_regexp):<EOL><INDENT>if not _is_cancelled(source, n):<EOL><INDENT>if inside_single:<EOL><INDENT>inside_single[<NUM_LIT:1>] = n + <NUM_LIT:1><EOL>comments.append(inside_single)<EOL>inside_single = False<EOL><DEDENT>else:<EOL><INDENT>inside_single = [n, None, <NUM_LIT:0>]<EOL><DEDENT><DEDENT><DEDENT>elif (inside_single or inside_double):<EOL><INDENT>if char in LINE_TERMINATOR:<EOL><INDENT>if _is_cancelled(source, n):<EOL><INDENT>if char == CR and source[n + <NUM_LIT:1>] == LF:<EOL><INDENT>n += <NUM_LIT:1><EOL><DEDENT>n += <NUM_LIT:1><EOL>continue<EOL><DEDENT>else:<EOL><INDENT>raise SyntaxError(<EOL>'<STR_LIT>'<EOL>)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>if inside_comment:<EOL><INDENT>if single_comment:<EOL><INDENT>if char in LINE_TERMINATOR:<EOL><INDENT>inside_comment[<NUM_LIT:1>] = n<EOL>comments.append(inside_comment)<EOL>inside_comment = False<EOL>single_comment = False<EOL><DEDENT><DEDENT>else:  <EOL><INDENT>if char == '<STR_LIT:/>' and source[n - <NUM_LIT:1>] == '<STR_LIT:*>':<EOL><INDENT>inside_comment[<NUM_LIT:1>] = n + <NUM_LIT:1><EOL>comments.append(inside_comment)<EOL>inside_comment = False<EOL><DEDENT><DEDENT><DEDENT>elif inside_regexp:<EOL><INDENT>if not quiting_regexp:<EOL><INDENT>if char in LINE_TERMINATOR:<EOL><INDENT>raise SyntaxError(<EOL>'<STR_LIT>'<EOL>)<EOL><DEDENT>if _is_cancelled(source, n):<EOL><INDENT>n += <NUM_LIT:1><EOL>continue<EOL><DEDENT>if char == '<STR_LIT:[>':<EOL><INDENT>regexp_class_count += <NUM_LIT:1><EOL><DEDENT>elif char == '<STR_LIT:]>':<EOL><INDENT>regexp_class_count = max(regexp_class_count - <NUM_LIT:1>, <NUM_LIT:0>)<EOL><DEDENT>elif char == '<STR_LIT:/>' and not regexp_class_count:<EOL><INDENT>quiting_regexp = True<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if char not in IDENTIFIER_START:<EOL><INDENT>inside_regexp[<NUM_LIT:1>] = n<EOL>comments.append(inside_regexp)<EOL>inside_regexp = False<EOL><DEDENT><DEDENT><DEDENT>elif char == '<STR_LIT:/>' and source[n - <NUM_LIT:1>] == '<STR_LIT:/>':<EOL><INDENT>single_comment = True<EOL>inside_comment = [n - <NUM_LIT:1>, None, <NUM_LIT:1>]<EOL><DEDENT>elif char == '<STR_LIT:*>' and source[n - <NUM_LIT:1>] == '<STR_LIT:/>':<EOL><INDENT>inside_comment = [n - <NUM_LIT:1>, None, <NUM_LIT:1>]<EOL><DEDENT>elif char == '<STR_LIT:/>' and source[n + <NUM_LIT:1>] not in ('<STR_LIT:/>', '<STR_LIT:*>'):<EOL><INDENT>if not _ensure_regexp(source, n):  <EOL><INDENT>n += <NUM_LIT:1><EOL>continue  <EOL><DEDENT>quiting_regexp = False<EOL>inside_regexp = [n, None, <NUM_LIT:2>]<EOL><DEDENT>elif not (inside_comment or inside_regexp):<EOL><INDENT>if (char in NUMS and<EOL>source[n - <NUM_LIT:1>] not in IDENTIFIER_PART) or char == '<STR_LIT:.>':<EOL><INDENT>if char == '<STR_LIT:.>':<EOL><INDENT>k = parse_num(source, n + <NUM_LIT:1>, NUMS)<EOL>if k == n + <NUM_LIT:1>:  <EOL><INDENT>n += <NUM_LIT:1><EOL>continue<EOL><DEDENT>k = parse_exponent(source, k)<EOL><DEDENT>elif char == '<STR_LIT:0>' and source[n + <NUM_LIT:1>] in {<EOL>'<STR_LIT:x>', '<STR_LIT:X>'<EOL>}:  <EOL><INDENT>k = parse_num(source, n + <NUM_LIT:2>, HEX)<EOL>if k == n + <NUM_LIT:2> or source[k] in IDENTIFIER_PART:<EOL><INDENT>raise SyntaxError('<STR_LIT>')<EOL><DEDENT><DEDENT>else:  <EOL><INDENT>k = parse_num(source, n + <NUM_LIT:1>, NUMS)<EOL>if source[k] == '<STR_LIT:.>':<EOL><INDENT>k = parse_num(source, k + <NUM_LIT:1>, NUMS)<EOL><DEDENT>k = parse_exponent(source, k)<EOL><DEDENT>comments.append((n, k, <NUM_LIT:3>))<EOL>n = k<EOL>continue<EOL><DEDENT><DEDENT><DEDENT>n += <NUM_LIT:1><EOL><DEDENT>res = '<STR_LIT>'<EOL>start = <NUM_LIT:0><EOL>count = <NUM_LIT:0><EOL>constants = {}<EOL>for end, next_start, typ in comments:<EOL><INDENT>res += source[start:end]<EOL>start = next_start<EOL>if typ == <NUM_LIT:0>:  <EOL><INDENT>name = StringName<EOL><DEDENT>elif typ == <NUM_LIT:1>:  <EOL><INDENT>continue<EOL><DEDENT>elif typ == <NUM_LIT:2>:  <EOL><INDENT>name = RegExpName<EOL><DEDENT>elif typ == <NUM_LIT:3>:  <EOL><INDENT>name = NumberName<EOL><DEDENT>else:<EOL><INDENT>raise RuntimeError()<EOL><DEDENT>res += '<STR_LIT:U+0020>' + name % count + '<STR_LIT:U+0020>'<EOL>constants[name % count] = source[end:next_start]<EOL>count += <NUM_LIT:1><EOL><DEDENT>res += source[start:]<EOL>for e in WHITE:<EOL><INDENT>res = res.replace(e, '<STR_LIT:U+0020>')<EOL><DEDENT>res = res.replace(CR + LF, '<STR_LIT:\n>')<EOL>for e in LINE_TERMINATOR:<EOL><INDENT>res = res.replace(e, '<STR_LIT:\n>')<EOL><DEDENT>return res.strip(), constants<EOL>
Replaces Strings and Regexp literals in the source code with
       identifiers and *removes comments*. Identifier is of the format:

       PyJsStringConst(String const number)_ - for Strings
       PyJsRegExpConst(RegExp const number)_ - for RegExps

       Returns dict which relates identifier and replaced constant.

       Removes single line and multiline comments from JavaScript source code
       Pseudo comments (inside strings) will not be removed.

       For example this line:
       var x = "/*PSEUDO COMMENT*/ TEXT //ANOTHER PSEUDO COMMENT"
       will be unaltered