jashkenas--coffeescript/test/regex.coffee

329 lines
6.4 KiB
CoffeeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Regular Expression Literals
# ---------------------------
# TODO: add method invocation tests: /regex/.toString()
# * Regexen
# * Heregexen
test "basic regular expression literals", ->
ok 'a'.match(/a/)
ok 'a'.match /a/
ok 'a'.match(/a/g)
ok 'a'.match /a/g
test "division is not confused for a regular expression", ->
# Any spacing around the slash is allowed when it cannot be a regex.
eq 2, 4 / 2 / 1
eq 2, 4/2/1
eq 2, 4/ 2 / 1
eq 2, 4 /2 / 1
eq 2, 4 / 2/ 1
eq 2, 4 / 2 /1
eq 2, 4 /2/ 1
a = (regex) -> regex.test 'a b c'
a.valueOf = -> 4
b = 2
g = 1
eq 2, a / b/g
eq 2, a/ b/g
eq 2, a / b/ g
eq 2, a / b/g # Tabs.
eq 2, a / b/g # Non-breaking spaces.
eq true, a /b/g
# Use parentheses to disambiguate.
eq true, a(/ b/g)
eq true, a(/ b/)
eq true, a (/ b/)
# Escape to disambiguate.
eq true, a /\ b/g
eq false, a /\ b/g
eq true, a /\ b/
obj = method: -> 2
two = 2
eq 2, (obj.method()/two + obj.method()/two)
i = 1
eq 2, (4)/2/i
eq 1, i/i/i
a = ''
a += ' ' until / /.test a
eq a, ' '
a = if /=/.test '=' then yes else no
eq a, yes
a = if !/=/.test '=' then yes else no
eq a, no
#3182:
match = 'foo=bar'.match /=/
eq match[0], '='
#3410:
ok ' '.match(/ /)[0] is ' '
test "division vs regex after a callable token", ->
b = 2
g = 1
r = (r) -> r.test 'b'
a = 4
eq 2, a / b/g
eq 2, a/b/g
eq 2, a/ b/g
eq true, r /b/g
eq 2, (1 + 3) / b/g
eq 2, (1 + 3)/b/g
eq 2, (1 + 3)/ b/g
eq true, (r) /b/g
eq 2, [4][0] / b/g
eq 2, [4][0]/b/g
eq 2, [4][0]/ b/g
eq true, [r][0] /b/g
eq 0.5, 4? / b/g
eq 0.5, 4?/b/g
eq 0.5, 4?/ b/g
eq true, r? /b/g
(->
eq 2, @ / b/g
eq 2, @/b/g
eq 2, @/ b/g
).call 4
(->
eq true, @ /b/g
).call r
(->
eq 2, this / b/g
eq 2, this/b/g
eq 2, this/ b/g
).call 4
(->
eq true, this /b/g
).call r
class A
p: (regex) -> if regex then r regex else 4
class B extends A
p: ->
eq 2, super() / b/g
eq 2, super()/b/g
eq 2, super()/ b/g
eq true, super /b/g
new B().p()
test "always division and never regex after some tokens", ->
b = 2
g = 1
eq 2, 4 / b/g
eq 2, 4/b/g
eq 2, 4/ b/g
eq 2, 4 /b/g
eq 2, "4" / b/g
eq 2, "4"/b/g
eq 2, "4"/ b/g
eq 2, "4" /b/g
eq 20, "4#{0}" / b/g
eq 20, "4#{0}"/b/g
eq 20, "4#{0}"/ b/g
eq 20, "4#{0}" /b/g
ok isNaN /a/ / b/g
ok isNaN /a/i / b/g
ok isNaN /a//b/g
ok isNaN /a/i/b/g
ok isNaN /a// b/g
ok isNaN /a/i/ b/g
ok isNaN /a/ /b/g
ok isNaN /a/i /b/g
eq 0.5, true / b/g
eq 0.5, true/b/g
eq 0.5, true/ b/g
eq 0.5, true /b/g
eq 0, false / b/g
eq 0, false/b/g
eq 0, false/ b/g
eq 0, false /b/g
eq 0, null / b/g
eq 0, null/b/g
eq 0, null/ b/g
eq 0, null /b/g
ok isNaN undefined / b/g
ok isNaN undefined/b/g
ok isNaN undefined/ b/g
ok isNaN undefined /b/g
ok isNaN {a: 4} / b/g
ok isNaN {a: 4}/b/g
ok isNaN {a: 4}/ b/g
ok isNaN {a: 4} /b/g
o = prototype: 4
eq 2, o:: / b/g
eq 2, o::/b/g
eq 2, o::/ b/g
eq 2, o:: /b/g
i = 4
eq 2.0, i++ / b/g
eq 2.5, i++/b/g
eq 3.0, i++/ b/g
eq 3.5, i++ /b/g
eq 4.0, i-- / b/g
eq 3.5, i--/b/g
eq 3.0, i--/ b/g
eq 2.5, i-- /b/g
test "compound division vs regex", ->
c = 4
i = 2
a = 10
b = a /= c / i
eq a, 5
a = 10
b = a /= c /i
eq a, 5
a = 10
b = a /= c /i # Tabs.
eq a, 5
a = 10
b = a /= c /i # Non-breaking spaces.
eq a, 5
a = 10
b = a/= c /i
eq a, 5
a = 10
b = a/=c/i
eq a, 5
a = (regex) -> regex.test '=C '
b = a /=c /i
eq b, true
a = (regex) -> regex.test '= C '
# Use parentheses to disambiguate.
b = a(/= c /i)
eq b, true
b = a(/= c /)
eq b, false
b = a (/= c /)
eq b, false
# Escape to disambiguate.
b = a /\= c /i
eq b, true
b = a /\= c /
eq b, false
test "#764: regular expressions should be indexable", ->
eq /0/['source'], ///#{0}///['source']
test "#584: slashes are allowed unescaped in character classes", ->
ok /^a\/[/]b$/.test 'a//b'
test "does not allow to escape newlines", ->
throws -> CoffeeScript.compile '/a\\\nb/'
# Heregexe(n|s)
test "a heregex will ignore whitespace and comments", ->
eq /^I'm\x20+[a]\s+Heregex?\/\/\//gim + '', ///
^ I'm \x20+ [a] \s+
Heregex? / // # or not
///gim + ''
test "an empty heregex will compile to an empty, non-capturing group", ->
eq /(?:)/ + '', /// /// + ''
eq /(?:)/ + '', ////// + ''
test "heregex starting with slashes", ->
ok /////a/\////.test ' //a// '
test '#2388: `///` in heregex interpolations', ->
ok ///a#{///b///}c///.test ' /a/b/c/ '
ws = ' \t'
scan = (regex) -> regex.exec('\t foo')[0]
eq '/\t /', /// #{scan /// [#{ws}]* ///} /// + ''
test "regexes are not callable", ->
throws -> CoffeeScript.compile '/a/()'
throws -> CoffeeScript.compile '///a#{b}///()'
throws -> CoffeeScript.compile '/a/ 1'
throws -> CoffeeScript.compile '///a#{b}/// 1'
throws -> CoffeeScript.compile '''
/a/
k: v
'''
throws -> CoffeeScript.compile '''
///a#{b}///
k: v
'''
test "backreferences", ->
ok /(a)(b)\2\1/.test 'abba'
test "#3795: Escape otherwise invalid characters", ->
ok (//).test '\u2028'
ok (//).test '\u2029'
ok ///\///.test '\u2028'
ok ///\///.test '\u2029'
ok ///ab///.test 'ab' # The space is U+2028.
ok ///ab///.test 'ab' # The space is U+2029.
ok ///\0
1///.test '\x001'
a = 'a'
ok ///#{a}b///.test 'ab' # The space is U+2028.
ok ///#{a}b///.test 'ab' # The space is U+2029.
ok ///#{a}\///.test 'a\u2028'
ok ///#{a}\///.test 'a\u2029'
ok ///#{a}\0
1///.test 'a\x001'
test "#4248: Unicode code point escapes", ->
ok /a\u{1ab}c/u.test 'a\u01abc'
ok ///#{ 'a' }\u{000001ab}c///u.test 'a\u{1ab}c'
ok ///a\u{000001ab}c///u.test 'a\u{1ab}c'
ok /a\u{12345}c/u.test 'a\ud808\udf45c'
# and now without u flag
ok /a\u{1ab}c/.test 'a\u01abc'
ok ///#{ 'a' }\u{000001ab}c///.test 'a\u{1ab}c'
ok ///a\u{000001ab}c///.test 'a\u{1ab}c'
ok /a\u{12345}c/.test 'a\ud808\udf45c'
# rewrite code point escapes unless u flag is set
eqJS """
/\\u{bcdef}\\u{abc}/u
""",
"""
/\\u{bcdef}\\u{abc}/u;
"""
eqJS """
///#{ 'a' }\\u{bcdef}///
""",
"""
/a\\udab3\\uddef/;
"""
test "#4811, heregex comments with ///", ->
eqJS """
///
a | # comment with ///
b # /// 'heregex' in comment will be consumed
///
""",
"""
// comment with ///
// /// 'heregex' in comment will be consumed
/a|b/;
"""