174 lines
5.4 KiB
CoffeeScript
174 lines
5.4 KiB
CoffeeScript
# Strict Early Errors
|
|
# -------------------
|
|
|
|
# The following are prohibited under ES5's `strict` mode
|
|
# * `Octal Integer Literals`
|
|
# * `Octal Escape Sequences`
|
|
# * duplicate property definitions in `Object Literal`s
|
|
# * duplicate formal parameter
|
|
# * `delete` operand is a variable
|
|
# * `delete` operand is a parameter
|
|
# * `delete` operand is `undefined`
|
|
# * `Future Reserved Word`s as identifiers: implements, interface, let, package, private, protected, public, static, yield
|
|
# * `eval` or `arguments` as `catch` identifier
|
|
# * `eval` or `arguments` as formal parameter
|
|
# * `eval` or `arguments` as function declaration identifier
|
|
# * `eval` or `arguments` as LHS of assignment
|
|
# * `eval` or `arguments` as the operand of a post/pre-fix inc/dec-rement expression
|
|
|
|
# helper to assert that code complies with strict prohibitions
|
|
strict = (code, msg) ->
|
|
throws (-> CoffeeScript.compile code), null, msg ? code
|
|
strictOk = (code, msg) ->
|
|
doesNotThrow (-> CoffeeScript.compile code), msg ? code
|
|
|
|
|
|
test "octal integer literals prohibited", ->
|
|
strict '01'
|
|
strict '07777'
|
|
# decimals with a leading '0' are also prohibited
|
|
strict '09'
|
|
strict '079'
|
|
strictOk '`01`'
|
|
|
|
test "octal escape sequences prohibited", ->
|
|
strict '"\\1"'
|
|
strict '"\\7"'
|
|
strict '"\\001"'
|
|
strict '"\\777"'
|
|
strict '"_\\1"'
|
|
strict '"\\1_"'
|
|
strict '"_\\1_"'
|
|
strict '"\\\\\\1"'
|
|
strictOk '"\\0"'
|
|
eq "\x00", "\0"
|
|
strictOk '"\\08"'
|
|
eq "\x008", "\08"
|
|
strictOk '"\\0\\8"'
|
|
eq "\x008", "\0\8"
|
|
strictOk '"\\8"'
|
|
eq "8", "\8"
|
|
strictOk '"\\\\1"'
|
|
eq "\\" + "1", "\\1"
|
|
strictOk '"\\\\\\\\1"'
|
|
eq "\\\\" + "1", "\\\\1"
|
|
strictOk "`'\\1'`"
|
|
eq "\\" + "1", `"\\1"`
|
|
|
|
# Also test other string types.
|
|
strict "'\\\\\\1'"
|
|
eq "\x008", '\08'
|
|
eq "\\\\" + "1", '\\\\1'
|
|
strict "'''\\\\\\1'''"
|
|
eq "\x008", '''\08'''
|
|
eq "\\\\" + "1", '''\\\\1'''
|
|
strict '"""\\\\\\1"""'
|
|
eq "\x008", """\08"""
|
|
eq "\\\\" + "1", """\\\\1"""
|
|
|
|
test "duplicate formal parameters are prohibited", ->
|
|
nonce = {}
|
|
# a Param can be an Identifier, ThisProperty( @-param ), Array, or Object
|
|
# a Param can also be a splat (...) or an assignment (param=value)
|
|
# the following function expressions should throw errors
|
|
strict '(_,_)->', 'param, param'
|
|
strict '(_,_...)->', 'param, param...'
|
|
strict '(_,_ = true)->', 'param, param='
|
|
strict '(@_,@_)->', 'two @params'
|
|
strict '(@case,@case)->', 'two @reserved'
|
|
strict '(_,{_})->', 'param, {param}'
|
|
strict '({_,_})->', '{param, param}'
|
|
strict '(_,[_])->', 'param, [param]'
|
|
strict '([_,_])->', '[param, param]'
|
|
strict '(_,[_]=true)->', 'param, [param]='
|
|
strict '(_,[@_,{_}])->', 'param, [@param, {param}]'
|
|
strict '(_,[_,{@_}])->', 'param, [param, {@param}]'
|
|
strict '(_,[_,{_}])->', 'param, [param, {param}]'
|
|
strict '(_,[_,{__}])->', 'param, [param, {param2}]'
|
|
strict '(_,[__,{_}])->', 'param, [param2, {param}]'
|
|
strict '(__,[_,{_}])->', 'param, [param2, {param2}]'
|
|
strict '(0:a,1:a)->', '0:param,1:param'
|
|
strict '({0:a,1:a})->', '{0:param,1:param}'
|
|
# the following function expressions should **not** throw errors
|
|
strictOk '(_,@_)->'
|
|
strictOk '(@_,_...)->'
|
|
strictOk '(_,@_ = true)->'
|
|
strictOk '(@_,{_})->'
|
|
strictOk '({_,@_})->'
|
|
strictOk '([_,@_])->'
|
|
strictOk '({},_arg)->'
|
|
strictOk '({},{})->'
|
|
strictOk '([]...,_arg)->'
|
|
strictOk '({}...,_arg)->'
|
|
strictOk '({}...,[],_arg)->'
|
|
strictOk '([]...,{},_arg)->'
|
|
strictOk '(@case,_case)->'
|
|
strictOk '(@case,_case...)->'
|
|
strictOk '(@case...,_case)->'
|
|
strictOk '(_case,@case)->'
|
|
strictOk '(_case,@case...)->'
|
|
strictOk '(a:a)->'
|
|
strictOk '(a:a,a:b)->'
|
|
|
|
test "`delete` operand restrictions", ->
|
|
strict 'a = 1; delete a'
|
|
strictOk 'delete a' #noop
|
|
strict '(a) -> delete a'
|
|
strict '(a...) -> delete a'
|
|
strict '(a = 1) -> delete a'
|
|
strict '([a]) -> delete a'
|
|
strict '({a}) -> delete a'
|
|
|
|
test "`Future Reserved Word`s, `eval` and `arguments` restrictions", ->
|
|
|
|
access = (keyword, check = strict) ->
|
|
check "#{keyword}.a = 1"
|
|
check "#{keyword}[0] = 1"
|
|
assign = (keyword, check = strict) ->
|
|
check "#{keyword} = 1"
|
|
check "#{keyword} += 1"
|
|
check "#{keyword} -= 1"
|
|
check "#{keyword} *= 1"
|
|
check "#{keyword} /= 1"
|
|
check "#{keyword} ?= 1"
|
|
check "{keyword}++"
|
|
check "++{keyword}"
|
|
check "{keyword}--"
|
|
check "--{keyword}"
|
|
destruct = (keyword, check = strict) ->
|
|
check "{#{keyword}}"
|
|
check "o = {#{keyword}}"
|
|
invoke = (keyword, check = strict) ->
|
|
check "#{keyword} yes"
|
|
check "do #{keyword}"
|
|
fnDecl = (keyword, check = strict) ->
|
|
check "class #{keyword}"
|
|
param = (keyword, check = strict) ->
|
|
check "(#{keyword}) ->"
|
|
check "({#{keyword}}) ->"
|
|
prop = (keyword, check = strict) ->
|
|
check "a.#{keyword} = 1"
|
|
tryCatch = (keyword, check = strict) ->
|
|
check "try new Error catch #{keyword}"
|
|
|
|
future = 'implements interface let package private protected public static'.split ' '
|
|
for keyword in future
|
|
access keyword
|
|
assign keyword
|
|
destruct keyword
|
|
invoke keyword
|
|
fnDecl keyword
|
|
param keyword
|
|
prop keyword, strictOk
|
|
tryCatch keyword
|
|
|
|
for keyword in ['eval', 'arguments']
|
|
access keyword, strictOk
|
|
assign keyword
|
|
destruct keyword, strictOk
|
|
invoke keyword, strictOk
|
|
fnDecl keyword
|
|
param keyword
|
|
prop keyword, strictOk
|
|
tryCatch keyword
|