# -*- coding: utf-8 -*-
"""
Collection of raw lexer test cases and class constructor.
"""

from __future__ import unicode_literals

import textwrap

swapquotes = {
    39: 34, 34: 39,
    # note the follow are interim error messages
    96: 39,
}

# The structure and some test cases are taken
# from https://bitbucket.org/ned/jslex
es5_cases = [
    (
        # Identifiers
        'identifiers_ascii',
        ('i my_variable_name c17 _dummy $str $ _ CamelCase class2type',
         ['ID i', 'ID my_variable_name', 'ID c17', 'ID _dummy',
          'ID $str', 'ID $', 'ID _', 'ID CamelCase', 'ID class2type']
         ),
    ), (
        'identifiers_unicode',
        (u'\u03c0 \u03c0_tail var\ua67c',
         [u'ID \u03c0', u'ID \u03c0_tail', u'ID var\ua67c']),
    ), (
        # https://github.com/rspivak/slimit/issues/2
        'slimit_issue_2',
        ('nullify truelie falsepositive',
         ['ID nullify', 'ID truelie', 'ID falsepositive']),

    ), (
        'keywords_break',
        ('break Break BREAK', ['BREAK break', 'ID Break', 'ID BREAK']),
    ), (
        # Literals
        'literals',
        ('null true false Null True False',
         ['NULL null', 'TRUE true', 'FALSE false',
          'ID Null', 'ID True', 'ID False']
         ),
    ), (
        # Punctuators
        'punctuators_simple',
        ('a /= b', ['ID a', 'DIVEQUAL /=', 'ID b']),
    ), (
        'punctuators_various_equality',
        (('= == != === !== < > <= >= || && ++ -- << >> '
          '>>> += -= *= <<= >>= >>>= &= %= ^= |='),
         ['EQ =', 'EQEQ ==', 'NE !=', 'STREQ ===', 'STRNEQ !==', 'LT <',
          'GT >', 'LE <=', 'GE >=', 'OR ||', 'AND &&', 'PLUSPLUS ++',
          'MINUSMINUS --', 'LSHIFT <<', 'RSHIFT >>', 'URSHIFT >>>',
          'PLUSEQUAL +=', 'MINUSEQUAL -=', 'MULTEQUAL *=', 'LSHIFTEQUAL <<=',
          'RSHIFTEQUAL >>=', 'URSHIFTEQUAL >>>=', 'ANDEQUAL &=', 'MODEQUAL %=',
          'XOREQUAL ^=', 'OREQUAL |=',
          ]
         ),
    ), (
        'punctuators_various_others',
        ('. , ; : + - * % & | ^ ~ ? ! ( ) { } [ ]',
         ['PERIOD .', 'COMMA ,', 'SEMI ;', 'COLON :', 'PLUS +', 'MINUS -',
          'MULT *', 'MOD %', 'BAND &', 'BOR |', 'BXOR ^', 'BNOT ~',
          'CONDOP ?', 'NOT !', 'LPAREN (', 'RPAREN )', 'LBRACE {', 'RBRACE }',
          'LBRACKET [', 'RBRACKET ]']
         ),
    ), (
        'division_simple',
        ('a / b', ['ID a', 'DIV /', 'ID b']),
    ), (
        'numbers',
        (('3 3.3 0 0. 0.0 0.001 010 3.e2 3.e-2 3.e+2 3E2 3E+2 3E-2 '
          '0.5e2 0.5e+2 0.5e-2 33 128.15 0x001 0X12ABCDEF 0xabcdef'),
         ['NUMBER 3', 'NUMBER 3.3', 'NUMBER 0', 'NUMBER 0.', 'NUMBER 0.0',
          'NUMBER 0.001', 'NUMBER 010', 'NUMBER 3.e2', 'NUMBER 3.e-2',
          'NUMBER 3.e+2', 'NUMBER 3E2', 'NUMBER 3E+2', 'NUMBER 3E-2',
          'NUMBER 0.5e2', 'NUMBER 0.5e+2', 'NUMBER 0.5e-2', 'NUMBER 33',
          'NUMBER 128.15', 'NUMBER 0x001', 'NUMBER 0X12ABCDEF',
          'NUMBER 0xabcdef']
         ),
    ), (
        'strings_simple_quote',
        (""" '"' """, ["""STRING '"'"""]),
    ), (
        'strings_escape_quote_tab',
        (r'''"foo" 'foo' "x\";" 'x\';' "foo\tbar"''',
         ['STRING "foo"', """STRING 'foo'""", r'STRING "x\";"',
          r"STRING 'x\';'", r'STRING "foo\tbar"']
         ),
    ), (
        'strings_escape_ascii',
        (r"""'\x55' "\x12ABCDEF" '!@#$%^&*()_+{}[]\";?'""",
         [r"STRING '\x55'", r'STRING "\x12ABCDEF"',
          r"STRING '!@#$%^&*()_+{}[]\";?'"]
         ),
    ), (
        'strings_escape_unicode',
        (r"""'\u0001' "\uFCEF" 'a\\\b\n'""",
         [r"STRING '\u0001'", r'STRING "\uFCEF"', r"STRING 'a\\\b\n'"]
         ),
    ), (
        'strings_unicode',
        (u'"тест строки\\""', [u'STRING "тест строки\\""']),
    ), (
        'strings_escape_octal',
        (r"""'\251'""", [r"""STRING '\251'"""]),
    ), (
        # Bug - https://github.com/rspivak/slimit/issues/5
        'slimit_issue_5',
        (r"var tagRegExp = new RegExp('<(\/*)(FooBar)', 'gi');",
         ['VAR var', 'ID tagRegExp', 'EQ =',
          'NEW new', 'ID RegExp', 'LPAREN (',
          r"STRING '<(\/*)(FooBar)'", 'COMMA ,', "STRING 'gi'",
          'RPAREN )', 'SEMI ;']),
    ), (
        # same as above but inside double quotes
        'slimit_issue_5_double_quote',
        (r'"<(\/*)(FooBar)"', [r'STRING "<(\/*)(FooBar)"']),
    ), (
        # multiline string (string written across multiple lines
        # of code) https://github.com/rspivak/slimit/issues/24
        'slimit_issue_24_multi_line_code_double',
        ("var a = 'hello \\\n world'",
         ['VAR var', 'ID a', 'EQ =', "STRING 'hello \\\n world'"]),
    ), (
        'slimit_issue_24_multi_line_code_single',
        ('var a = "hello \\\r world"',
         ['VAR var', 'ID a', 'EQ =', 'STRING "hello \\\r world"']),
    ), (
        # regex
        'regex_1',
        (r'a=/a*/,1', ['ID a', 'EQ =', 'REGEX /a*/', 'COMMA ,', 'NUMBER 1']),
    ), (
        'regex_2',
        (r'a=/a*[^/]+/,1',
         ['ID a', 'EQ =', 'REGEX /a*[^/]+/', 'COMMA ,', 'NUMBER 1']
         ),
    ), (
        'regex_3',
        (r'a=/a*\[^/,1',
         ['ID a', 'EQ =', r'REGEX /a*\[^/', 'COMMA ,', 'NUMBER 1']
         ),
    ), (
        'regex_4',
        (r'a=/\//,1', ['ID a', 'EQ =', r'REGEX /\//', 'COMMA ,', 'NUMBER 1']),
    ), (
        # not a regex, just a division
        # https://github.com/rspivak/slimit/issues/6
        'slimit_issue_6_not_regex_but_division',
        (r'x = this / y;',
         ['ID x', 'EQ =', 'THIS this', r'DIV /', r'ID y', r'SEMI ;']),
    ), (
        'regex_mozilla_example_1',
        # next two are from
        # http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions
        ('for (var x = a in foo && "</x>" || mot ? z:/x:3;x<5;y</g/i) '
         '{xyz(x++);}',
         ["FOR for", "LPAREN (", "VAR var", "ID x", "EQ =", "ID a", "IN in",
          "ID foo", "AND &&", 'STRING "</x>"', "OR ||", "ID mot", "CONDOP ?",
          "ID z", "COLON :", "REGEX /x:3;x<5;y</g", "DIV /", "ID i",
          "RPAREN )", "LBRACE {", "ID xyz", "LPAREN (", "ID x", "PLUSPLUS ++",
          "RPAREN )", "SEMI ;", "RBRACE }"]
         ),
    ), (
        'regex_mozilla_example_2',
        ('for (var x = a in foo && "</x>" || mot ? z/x:3;x<5;y</g/i) '
         '{xyz(x++);}',
         ["FOR for", "LPAREN (", "VAR var", "ID x", "EQ =", "ID a", "IN in",
          "ID foo", "AND &&", 'STRING "</x>"', "OR ||", "ID mot", "CONDOP ?",
          "ID z", "DIV /", "ID x", "COLON :", "NUMBER 3", "SEMI ;", "ID x",
          "LT <", "NUMBER 5", "SEMI ;", "ID y", "LT <", "REGEX /g/i",
          "RPAREN )", "LBRACE {", "ID xyz", "LPAREN (", "ID x", "PLUSPLUS ++",
          "RPAREN )", "SEMI ;", "RBRACE }"]
         ),

    ), (
        'regex_illegal_1',
        # Various "illegal" regexes that are valid according to the std.
        (r"""/????/, /++++/, /[----]/ """,
         ['REGEX /????/', 'COMMA ,',
          'REGEX /++++/', 'COMMA ,', 'REGEX /[----]/']
         ),

    ), (
        'regex_stress_test_1',
        # Stress cases from
        # http://stackoverflow.com/questions/5533925/
        # what-javascript-constructs-does-jslex-incorrectly-lex/5573409#5573409
        (r"""/\[/""", [r"""REGEX /\[/"""]),
    ), (
        'regex_stress_test_2',
        (r"""/[i]/""", [r"""REGEX /[i]/"""]),
    ), (
        'regex_stress_test_3',
        (r"""/[\]]/""", [r"""REGEX /[\]]/"""]),
    ), (
        'reg
ex_stress_test_4',
        (r"""/a[\]]/""", [r"""REGEX /a[\]]/"""]),
    ), (
        'regex_stress_test_5',
        (r"""/a[\]]b
/""", [r"""REGEX /a[\]]b/"""]),
    ), (
        'regex_stress_test_6',
        (r"""/[\]/]/gi""", [r"""REGEX /[\]/]/gi"""]),
    ), (
        'regex_stress_test_7',
        (r"""/\[[^\]]+\]/gi""", [r"""REGEX /\[[^\]]+\]/gi"""]),
    ), (
        'regex_stress_test_8',
        (r"""
         rexl.re = {
         NAME: /^(?!\d)(?:\w)+|^"(?:[^"]|"")+"/,
         UNQUOTED_LITERAL: /^@(?:(?!\d)(?:\w|\:)+|^"(?:[^"]|"")+")\[[^\]]+\]/,
         QUOTED_LITERAL: /^'(?:[^']|'')*'/,
         NUMERIC_LITERAL: /^[0-9]+(?:\.[0-9]*(?:[eE][-+][0-9]+)?)?/,
         SYMBOL: /^(?:==|=|<>|<=|<|>=