Browse files

Issue #1547 'use strict' eval and arguments use restricted

  • Loading branch information...
1 parent 0b7cfba commit 8b179fb391e948c9de9475bf3cfa4ca118c562d3 @geraldalewis geraldalewis committed Jan 9, 2012
Showing with 62 additions and 33 deletions.
  1. +6 −3 src/lexer.coffee
  2. +12 −4 src/nodes.coffee
  3. +44 −26 test/strict.coffee
View
9 src/lexer.coffee
@@ -106,7 +106,7 @@ exports.Lexer = class Lexer
@tokens.pop()
id = '!' + id
- if id in ['eval', 'arguments'].concat JS_FORBIDDEN
+ if id in JS_FORBIDDEN
if forcedIdentifier
tag = 'IDENTIFIER'
id = new String id
@@ -576,11 +576,14 @@ RESERVED = [
'private', 'protected', 'public', 'static', 'yield'
]
+STRICT_PROSCRIBED = ['arguments', 'eval']
+
# The superset of both JavaScript keywords and reserved words, none of which may
# be used as identifiers or properties.
-JS_FORBIDDEN = JS_KEYWORDS.concat RESERVED
+JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED)
-exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS)
+exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED)
+exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED
# Token matching regexes.
IDENTIFIER = /// ^
View
16 src/nodes.coffee
@@ -4,7 +4,7 @@
# the syntax tree into a string of JavaScript code, call `compile()` on the root.
{Scope} = require './scope'
-{RESERVED} = require './lexer'
+{RESERVED, STRICT_PROSCRIBED} = require './lexer'
# Import the helpers we plan to use.
{compact, flatten, extend, merge, del, starts, ends, last} = require './helpers'
@@ -329,7 +329,7 @@ exports.Literal = class Literal extends Base
if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0'
else if @value is 'this'
if o.scope.method?.bound then o.scope.method.context else @value
- else if @value.reserved and "#{@value}" not in ['eval', 'arguments']
+ else if @value.reserved
"\"#{@value}\""
else
@value
@@ -862,6 +862,8 @@ exports.Class = class Class extends Base
tail instanceof Access and tail.name.value
else
@variable.base.value
+ if decl in STRICT_PROSCRIBED
+ throw SyntaxError 'variable name may not be eval or arguments'
decl and= IDENTIFIER.test(decl) and decl
# For all `this`-references and bound functions in the class definition,
@@ -990,6 +992,8 @@ exports.Assign = class Assign extends Base
constructor: (@variable, @value, @context, options) ->
@param = options and options.param
@subpattern = options and options.subpattern
+ if @variable.unwrapAll().value in STRICT_PROSCRIBED
+ throw SyntaxError 'variable name may not be "eval" or "arguments"'
children: ['variable', 'value']
@@ -1055,7 +1059,7 @@ exports.Assign = class Assign extends Base
acc = IDENTIFIER.test idx.unwrap().value or 0
value = new Value value
value.properties.push new (if acc then Access else Index) idx
- if obj.unwrap().value in ['arguments','eval'].concat RESERVED
+ if obj.unwrap().value in RESERVED
throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{value.compile o}"
return new Assign(obj, value, null, param: @param).compile o, LEVEL_TOP
vvar = value.compile o, LEVEL_LIST
@@ -1100,7 +1104,7 @@ exports.Assign = class Assign extends Base
else
acc = isObject and IDENTIFIER.test idx.unwrap().value or 0
val = new Value new Literal(vvar), [new (if acc then Access else Index) idx]
- if name? and name in ['arguments','eval'].concat RESERVED
+ if name? and name in RESERVED
throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{val.compile o}"
assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compile o, LEVEL_LIST
assigns.push vvar unless top or @subpattern
@@ -1224,6 +1228,8 @@ exports.Code = class Code extends Base
# as well as be a splat, gathering up a group of parameters into an array.
exports.Param = class Param extends Base
constructor: (@name, @value, @splat) ->
+ if @name.unwrapAll().value in STRICT_PROSCRIBED
+ throw SyntaxError 'parameter name eval or arguments is not allowed'
children: ['name', 'value']
@@ -1575,6 +1581,8 @@ exports.Try = class Try extends Base
tryPart = @attempt.compile o, LEVEL_TOP
catchPart = if @recovery
+ if @error.value in STRICT_PROSCRIBED
+ throw SyntaxError "catch variable may not be eval or arguments"
o.scope.add @error.value, 'param' unless o.scope.check @error.value
" catch#{errorPart}{\n#{ @recovery.compile o, LEVEL_TOP }\n#{@tab}}"
else unless @ensure or @recovery
View
70 test/strict.coffee
@@ -100,32 +100,50 @@ test "`delete` operand restrictions", ->
strict '([a]) -> delete a'
strict '({a}) -> delete a'
-test "`Future Reserved Word`s as identifiers prohibited", ->
- futures = 'implements interface let package private protected public static yield'.split ' '
- for keyword in futures
- strict "#{keyword} = 1"
- strict "class #{keyword}"
- strict "try new Error catch #{keyword}"
- strict "(#{keyword}) ->"
- strict "{keyword}++"
- strict "++{keyword}"
- strict "{keyword}--"
- strict "--{keyword}"
+test "`Future Reserved Word`s, `eval` and `arguments` restrictions", ->
-test "`eval` and `arguments` use restricted", ->
- proscribeds = 'eval arguments'.split ' '
- for proscribed in proscribeds
- strict "#{proscribed} = 1"
- strict "class #{proscribed}"
- strict "try new Error catch #{proscribed}"
- strict "(#{proscribed}) ->"
- strict "{proscribed}++"
- strict "++{proscribed}"
- strict "{proscribed}--"
- strict "--{proscribed}"
- strictOk "eval 'true'"
- strictOk "-> arguments[0]"
+ 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}"
+ 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 yield'.split ' '
+ for keyword in future
+ access keyword
+ assign keyword
+ invoke keyword
+ fnDecl keyword
+ param keyword
+ prop keyword, strictOk
+ tryCatch keyword
-
-
+ for keyword in ['eval', 'arguments']
+ access keyword, strictOk
+ assign keyword
+ invoke keyword, strictOk
+ fnDecl keyword
+ param keyword
+ prop keyword, strictOk
+ tryCatch keyword

0 comments on commit 8b179fb

Please sign in to comment.