# 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 '(_,{_=true})->', 'param, {param=}' strict '({_,_})->', '{param, param}' strict '({_=true,_})->', '{param=, param}' strict '(_,[_])->', 'param, [param]' strict '(_,[_=true])->', 'param, [param=]' strict '([_,_])->', '[param, param]' strict '([_=true,_])->', '[param=, param]' strict '(_,[_]=true)->', 'param, [param]=' strict '(_,[_=true]=true)->', 'param, [param=]=' strict '(_,[@_,{_}])->', 'param, [@param, {param}]' strict '(_,[_,{@_}])->', 'param, [param, {@param}]' strict '(_,[_,{@_=true}])->', '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 '(a=b=true,a)->', 'param=assignment, param' strict '({a=b=true},a)->', '{param=assignment}, param' # the following function expressions should **not** throw errors strictOk '(_,@_)->' strictOk '(@_,_...)->' strictOk '(_,@_ = true)->' strictOk '(@_,{_})->' strictOk '({_,@_})->' strictOk '({_,@_ = true})->' strictOk '([_,@_])->' strictOk '([_,@_ = true])->' 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