diff --git a/lib/coffeescript/nodes.js b/lib/coffeescript/nodes.js index e22ee0e1..9e718296 100644 --- a/lib/coffeescript/nodes.js +++ b/lib/coffeescript/nodes.js @@ -1769,28 +1769,27 @@ } compileNode(o) { - var assign, executableBody, parentName, result; + var executableBody, node, parentName; this.name = this.determineName(); executableBody = this.walkBody(); if (this.parent instanceof Value && !this.parent.hasProperties()) { parentName = this.parent.base.value; } this.hasNameClash = (this.name != null) && this.name === parentName; + node = this; if (executableBody || this.hasNameClash) { - this.compileNode = this.compileClassDeclaration; - result = new ExecutableClassBody(this, executableBody).compileToFragments(o); - this.compileNode = this.constructor.prototype.compileNode; - } else { - result = this.compileClassDeclaration(o); - if ((this.name == null) && o.level === LEVEL_TOP) { - result = this.wrapInParentheses(result); - } + node = new ExecutableClassBody(node, executableBody); + } else if ((this.name == null) && o.level === LEVEL_TOP) { + node = new Parens(node); } if (this.variable) { - assign = new Assign(this.variable, new Literal(''), null, {moduleDeclaration: this.moduleDeclaration}); - return [...assign.compileToFragments(o), ...result]; - } else { - return result; + node = new Assign(this.variable, node, null, {moduleDeclaration: this.moduleDeclaration}); + } + this.compileNode = this.compileClassDeclaration; + try { + return node.compileToFragments(o); + } finally { + delete this.compileNode; } } diff --git a/src/nodes.coffee b/src/nodes.coffee index ed507058..18ef86ea 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -1300,21 +1300,22 @@ exports.Class = class Class extends Base parentName = @parent.base.value if @parent instanceof Value and not @parent.hasProperties() @hasNameClash = @name? and @name is parentName - if executableBody or @hasNameClash - @compileNode = @compileClassDeclaration - result = new ExecutableClassBody(@, executableBody).compileToFragments o - @compileNode = @constructor::compileNode - else - result = @compileClassDeclaration o + node = @ + if executableBody or @hasNameClash + node = new ExecutableClassBody node, executableBody + else if not @name? and o.level is LEVEL_TOP # Anonymous classes are only valid in expressions - result = @wrapInParentheses result if not @name? and o.level is LEVEL_TOP + node = new Parens node if @variable - assign = new Assign @variable, new Literal(''), null, { @moduleDeclaration } - [ assign.compileToFragments(o)..., result... ] - else - result + node = new Assign @variable, node, null, { @moduleDeclaration } + + @compileNode = @compileClassDeclaration + try + return node.compileToFragments o + finally + delete @compileNode compileClassDeclaration: (o) -> @ctor ?= @makeDefaultConstructor() if @externalCtor diff --git a/test/classes.coffee b/test/classes.coffee index fbd399e1..eeee2c00 100644 --- a/test/classes.coffee +++ b/test/classes.coffee @@ -734,6 +734,10 @@ test "#1392 calling `super` in methods defined on namespaced classes", -> eq 5, (new C.a).m() +test "#4436 immediately instantiated named class", -> + ok new class Foo + + test "dynamic method names", -> class A "#{name = 'm'}": -> 1