mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Issue #1547 'use strict' duplicate formal parameter are prohibited
updated error message (thanks @davidchambers) code style fixes
This commit is contained in:
parent
a2ef66f197
commit
7521068ba3
2 changed files with 55 additions and 12 deletions
|
@ -1162,8 +1162,10 @@ exports.Code = class Code extends Base
|
||||||
o.scope.shared = del(o, 'sharedScope')
|
o.scope.shared = del(o, 'sharedScope')
|
||||||
o.indent += TAB
|
o.indent += TAB
|
||||||
delete o.bare
|
delete o.bare
|
||||||
vars = []
|
params = []
|
||||||
exprs = []
|
exprs = []
|
||||||
|
for name in @paramNames() # this step must be performed before the others
|
||||||
|
unless o.scope.check name then o.scope.parameter name
|
||||||
for param in @params when param.splat
|
for param in @params when param.splat
|
||||||
o.scope.add p.name.value, 'var', yes for p in @params when p.name.value
|
o.scope.add p.name.value, 'var', yes for p in @params when p.name.value
|
||||||
splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
|
splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
|
||||||
|
@ -1180,11 +1182,15 @@ exports.Code = class Code extends Base
|
||||||
lit = new Literal ref.name.value + ' == null'
|
lit = new Literal ref.name.value + ' == null'
|
||||||
val = new Assign new Value(param.name), param.value, '='
|
val = new Assign new Value(param.name), param.value, '='
|
||||||
exprs.push new If lit, val
|
exprs.push new If lit, val
|
||||||
vars.push ref unless splats
|
params.push ref unless splats
|
||||||
wasEmpty = @body.isEmpty()
|
wasEmpty = @body.isEmpty()
|
||||||
exprs.unshift splats if splats
|
exprs.unshift splats if splats
|
||||||
@body.expressions.unshift exprs... if exprs.length
|
@body.expressions.unshift exprs... if exprs.length
|
||||||
o.scope.parameter vars[i] = v.compile o for v, i in vars unless splats
|
o.scope.parameter params[i] = p.compile o for p, i in params
|
||||||
|
uniqs = []
|
||||||
|
for name in @paramNames()
|
||||||
|
throw SyntaxError "multiple parameters named '#{name}'" if name in uniqs
|
||||||
|
uniqs.push name
|
||||||
@body.makeReturn() unless wasEmpty or @noReturn
|
@body.makeReturn() unless wasEmpty or @noReturn
|
||||||
if @bound
|
if @bound
|
||||||
if o.scope.parent.method?.bound
|
if o.scope.parent.method?.bound
|
||||||
|
@ -1194,12 +1200,18 @@ exports.Code = class Code extends Base
|
||||||
idt = o.indent
|
idt = o.indent
|
||||||
code = 'function'
|
code = 'function'
|
||||||
code += ' ' + @name if @ctor
|
code += ' ' + @name if @ctor
|
||||||
code += '(' + vars.join(', ') + ') {'
|
code += '(' + params.join(', ') + ') {'
|
||||||
code += "\n#{ @body.compileWithDeclarations o }\n#{@tab}" unless @body.isEmpty()
|
code += "\n#{ @body.compileWithDeclarations o }\n#{@tab}" unless @body.isEmpty()
|
||||||
code += '}'
|
code += '}'
|
||||||
return @tab + code if @ctor
|
return @tab + code if @ctor
|
||||||
if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code
|
if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code
|
||||||
|
|
||||||
|
# A list of parameter names, excluding those generated by the compiler.
|
||||||
|
paramNames: ->
|
||||||
|
names = []
|
||||||
|
names.push param.names()... for param in @params
|
||||||
|
names
|
||||||
|
|
||||||
# Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries
|
# Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries
|
||||||
# unless `crossScope` is `true`.
|
# unless `crossScope` is `true`.
|
||||||
traverseChildren: (crossScope, func) ->
|
traverseChildren: (crossScope, func) ->
|
||||||
|
@ -1223,7 +1235,8 @@ exports.Param = class Param extends Base
|
||||||
node = @name
|
node = @name
|
||||||
if node.this
|
if node.this
|
||||||
node = node.properties[0].name
|
node = node.properties[0].name
|
||||||
node = new Literal '_' + node.value if node.value.reserved
|
if node.value.reserved
|
||||||
|
node = new Literal o.scope.freeVariable node.value
|
||||||
else if node.isComplex()
|
else if node.isComplex()
|
||||||
node = new Literal o.scope.freeVariable 'arg'
|
node = new Literal o.scope.freeVariable 'arg'
|
||||||
node = new Value node
|
node = new Value node
|
||||||
|
@ -1233,6 +1246,36 @@ exports.Param = class Param extends Base
|
||||||
isComplex: ->
|
isComplex: ->
|
||||||
@name.isComplex()
|
@name.isComplex()
|
||||||
|
|
||||||
|
# Finds the name or names of a `Param`; useful for detecting duplicates.
|
||||||
|
# In a sense, a destructured parameter represents multiple JS parameters,
|
||||||
|
# thus this method returns an `Array` of names.
|
||||||
|
# Reserved words used as param names, as well as the Object and Array
|
||||||
|
# literals used for destructured params, get a compiler generated name
|
||||||
|
# during the `Code` compilation step, so this is necessarily an incomplete
|
||||||
|
# list of a parameter's names.
|
||||||
|
names: (name = @name)->
|
||||||
|
atParam = (obj) ->
|
||||||
|
{value} = obj.properties[0].name
|
||||||
|
return if value.reserved then [] else [value]
|
||||||
|
# * simple literals `foo`
|
||||||
|
return [name.value] if name instanceof Literal
|
||||||
|
# * at-params `@foo`
|
||||||
|
return atParam(name) if name instanceof Value
|
||||||
|
names = []
|
||||||
|
for obj in name.objects
|
||||||
|
# * assignments within destructured parameters `{foo:bar}`
|
||||||
|
if obj instanceof Assign
|
||||||
|
names.push obj.variable.base.value
|
||||||
|
# * destructured parameters within destructured parameters `[{a}]`
|
||||||
|
else if obj.isArray() or obj.isObject()
|
||||||
|
names.push @names(obj.base)...
|
||||||
|
# * at-params within destructured parameters `{@foo}`
|
||||||
|
else if obj.this
|
||||||
|
names.push atParam(obj)...
|
||||||
|
# * simple destructured parameters {foo}
|
||||||
|
else names.push obj.base.value
|
||||||
|
names
|
||||||
|
|
||||||
#### Splat
|
#### Splat
|
||||||
|
|
||||||
# A splat, either as a parameter to a function, an argument to a call,
|
# A splat, either as a parameter to a function, an argument to a call,
|
||||||
|
|
|
@ -91,9 +91,9 @@ test "self-referencing functions", ->
|
||||||
|
|
||||||
test "splats", ->
|
test "splats", ->
|
||||||
arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
|
arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
|
||||||
arrayEq [2, 3], (((_, _, splat...) -> splat) 0, 1, 2, 3)
|
arrayEq [2, 3], (((_, _1, splat...) -> splat) 0, 1, 2, 3)
|
||||||
arrayEq [0, 1], (((splat..., _, _) -> splat) 0, 1, 2, 3)
|
arrayEq [0, 1], (((splat..., _, _1) -> splat) 0, 1, 2, 3)
|
||||||
arrayEq [2], (((_, _, splat..., _) -> splat) 0, 1, 2, 3)
|
arrayEq [2], (((_, _1, splat..., _2) -> splat) 0, 1, 2, 3)
|
||||||
|
|
||||||
test "@-parameters: automatically assign an argument's value to a property of the context", ->
|
test "@-parameters: automatically assign an argument's value to a property of the context", ->
|
||||||
nonce = {}
|
nonce = {}
|
||||||
|
@ -131,7 +131,7 @@ test "destructuring in function definition", ->
|
||||||
test "default values", ->
|
test "default values", ->
|
||||||
nonceA = {}
|
nonceA = {}
|
||||||
nonceB = {}
|
nonceB = {}
|
||||||
a = (_,_,arg=nonceA) -> arg
|
a = (_,_1,arg=nonceA) -> arg
|
||||||
eq nonceA, a()
|
eq nonceA, a()
|
||||||
eq nonceA, a(0)
|
eq nonceA, a(0)
|
||||||
eq nonceB, a(0,0,nonceB)
|
eq nonceB, a(0,0,nonceB)
|
||||||
|
@ -139,7 +139,7 @@ test "default values", ->
|
||||||
eq nonceA, a(0,0,null)
|
eq nonceA, a(0,0,null)
|
||||||
eq false , a(0,0,false)
|
eq false , a(0,0,false)
|
||||||
eq nonceB, a(undefined,undefined,nonceB,undefined)
|
eq nonceB, a(undefined,undefined,nonceB,undefined)
|
||||||
b = (_,arg=nonceA,_,_) -> arg
|
b = (_,arg=nonceA,_1,_2) -> arg
|
||||||
eq nonceA, b()
|
eq nonceA, b()
|
||||||
eq nonceA, b(0)
|
eq nonceA, b(0)
|
||||||
eq nonceB, b(0,nonceB)
|
eq nonceB, b(0,nonceB)
|
||||||
|
@ -147,7 +147,7 @@ test "default values", ->
|
||||||
eq nonceA, b(0,null)
|
eq nonceA, b(0,null)
|
||||||
eq false , b(0,false)
|
eq false , b(0,false)
|
||||||
eq nonceB, b(undefined,nonceB,undefined)
|
eq nonceB, b(undefined,nonceB,undefined)
|
||||||
c = (arg=nonceA,_,_) -> arg
|
c = (arg=nonceA,_,_1) -> arg
|
||||||
eq nonceA, c()
|
eq nonceA, c()
|
||||||
eq 0, c(0)
|
eq 0, c(0)
|
||||||
eq nonceB, c(nonceB)
|
eq nonceB, c(nonceB)
|
||||||
|
|
Loading…
Add table
Reference in a new issue