Created
July 25, 2011 16:32
-
-
Save geraldalewis/1104521 to your computer and use it in GitHub Desktop.
1002_identical_params..1002_identical_params_revised
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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