Skip to content

Instantly share code, notes, and snippets.

@geraldalewis
Created July 25, 2011 16:32
Show Gist options
  • Save geraldalewis/1104521 to your computer and use it in GitHub Desktop.
Save geraldalewis/1104521 to your computer and use it in GitHub Desktop.
1002_identical_params..1002_identical_params_revised
diff --git a/src/nodes.coffee b/src/nodes.coffee
index 1697c44..cc382d7 100644
--- a/src/nodes.coffee
+++ b/src/nodes.coffee
@@ -1076,19 +1076,23 @@ exports.Code = class Code extends Base
o.scope = new Scope o.scope, @body, this
o.scope.shared = del o, 'sharedScope'
o.indent += TAB
- o.uniqs = {}
delete o.bare
- vars = []
- exprs = []
+ formalParams = []
+ paramNames = []
+ exprs = []
for param in @params when param.splat
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)),
new Value new Literal 'arguments'
break
for param in @params
+ for pname in allNames = param.simpleNames()
+ unless o.scope.check pname then o.scope.parameter pname
+ paramNames.unshift allNames...
+ for param in @params
if param.isComplex()
val = ref = param.asReference o
- o.uniqs[param.refName] = true if param.refName?
+ paramNames.push param.refName if param.refName?
val = new Op '?', ref, param.value if param.value
exprs.push new Assign new Value(param.name), val, '=', param: yes
else
@@ -1097,17 +1101,21 @@ exports.Code = class Code extends Base
lit = new Literal ref.name.value + ' == null'
val = new Assign new Value(param.name), param.value, '='
exprs.push new If lit, val
- param.checkUnique o
- vars.push ref unless splats
+ formalParams.push ref unless splats
wasEmpty = @body.isEmpty()
exprs.unshift splats if splats
@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 formalParams[i] = fp.compile o for fp, i in formalParams
+ uniqs = {}
+ for pname in paramNames
+ if uniqs.hasOwnProperty(pname)
+ throw SyntaxError "parameter names must be unique; a parameter '#{pname}' already exists."
+ uniqs[pname] = true
@body.makeReturn() unless wasEmpty or @noReturn
idt = o.indent
code = 'function'
code += ' ' + @name if @ctor
- code += '(' + vars.join(', ') + ') {'
+ code += '(' + formalParams.join(', ') + ') {'
code += "\n#{ @body.compileWithDeclarations o }\n#{@tab}" unless @body.isEmpty()
code += '}'
return @tab + code if @ctor
@@ -1144,23 +1152,19 @@ exports.Param = class Param extends Base
node = new Splat node if @splat
@reference = node
- checkUnique: (o) ->
- for name in @collectNames()
- throw SyntaxError "parameter names must be unique; a parameter '#{name}' already exists." if o.uniqs.hasOwnProperty name
- o.uniqs[name] = true
-
- # Some parameters may be in the form of object literals or arrays.
- # Collect each parameter name to allow `checkUnique` to ensure they're each unique.
- collectNames: (node = @name)->
+ simpleNames: (node=@name)->
names = []
unless node.objects
- return [node.properties[0].name.value] if node.properties?.length
- return [node.value] if node.value?
+ return [] if node.this and node.properties[0].name.value.reserved
+ return [node.properties[0].name.value] if node.this
+ return [node.value]
for obj in node.objects
- if obj.variable? then names.push obj.variable.base.value
- else if obj.base?.objects?.length then names = names.concat(@collectNames(obj.base))
- else unless obj.properties?.length then names.push(obj.base.value)
- else names.push(obj.properties[0].name.value)
+ if obj instanceof Value
+ continue if obj.this and obj.properties[0].name.value.reserved
+ if obj.isArray() or obj.isObject() then names.unshift @simpleNames(obj.base)...
+ else if obj.this then names.push obj.properties[0].name.value
+ else names.push obj.base.value
+ else names.push obj.variable.base.value
names
isComplex: ->
diff --git a/test/functions.coffee b/test/functions.coffee
index e8c3407..54e7600 100644
--- a/test/functions.coffee
+++ b/test/functions.coffee
@@ -165,21 +165,16 @@ test "arguments vs parameters", ->
eq 5, f (x) -> 5
test "#1002: parameters with identical names", ->
-
- # exercises param.isComplex() branch
- # (tests for false positives)
- doesNotThrow -> ((@prop1002, splat1002...) -> ) 0, 1
-
- # the second @prop had the name `undefined`
- # until I added the check for ref.base?.value
- # (tests for false positives)
- doesNotThrow -> ((@first1002, splat..., @last1002) -> ) 0, 1, 2
-
nonce = {}
- testNames = (code,msg) -> eq nonce, (try CoffeeScript.eval "#{code}", bare: on catch e then nonce), msg
- # a Param can be an Identifier, ThisProperty( @param ), Array, or Object
+ testNames = (code,msg) -> eq nonce,
+ (try CoffeeScript.eval "#{code}", bare: on
+ catch e
+ if e instanceof SyntaxError then nonce else -1), msg
+
+ # 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
testNames '(_,_)->', 'param, param'
testNames '(_,@_)->', 'param, @param'
testNames '(_,_...)->', 'param, param...'
@@ -201,8 +196,16 @@ test "#1002: parameters with identical names", ->
testNames '(_,[_,{__}])->', 'param, [param, {param2}]'
testNames '(_,[__,{_}])->', 'param, [param2, {param}]'
testNames '(__,[_,{_}])->', 'param, [param2, {param2}]'
- testNames '({}, _arg)->', 'object literal, _arg to test compiler renaming of references'
- doesNotThrow -> do ({},{}) -> #compiler should give each {} a unique name
- testNames '(@case, _case)->', '@case, _case to test compiler renaming of reserved keywords'
- testNames '(@case, @case)->', '@case, @case'
-
+ # the following function expressions should **not** throw errors
+ doesNotThrow -> CoffeeScript.eval '({},_arg)->', bare: on
+ doesNotThrow -> CoffeeScript.eval '({},{})->', bare: on
+ doesNotThrow -> CoffeeScript.eval '([]...,_arg)->', bare: on
+ doesNotThrow -> CoffeeScript.eval '({}...,_arg)->', bare: on
+ doesNotThrow -> CoffeeScript.eval '({}...,[],_arg)->', bare: on
+ doesNotThrow -> CoffeeScript.eval '([]...,{},_arg)->', bare: on
+ doesNotThrow -> CoffeeScript.eval '(@case,_case)->', bare: on
+ doesNotThrow -> CoffeeScript.eval '(@case,_case...)->', bare: on
+ doesNotThrow -> CoffeeScript.eval '(@case...,_case)->', bare: on
+ doesNotThrow -> CoffeeScript.eval '(_case,@case)->', bare: on
+ doesNotThrow -> CoffeeScript.eval '(_case,@case...)->', bare: on
+
\ No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment