mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
Simplify fix for #4464
This uses more of the existing machinery for moving class body expressions into the initializer.
This commit is contained in:
@@ -2466,17 +2466,17 @@
|
||||
}
|
||||
|
||||
compileNode(o) {
|
||||
var node, parentName;
|
||||
var executableBody, node, parentName;
|
||||
this.name = this.determineName();
|
||||
this.walkBody();
|
||||
executableBody = this.walkBody();
|
||||
if (this.parent instanceof Value && !this.parent.hasProperties()) {
|
||||
// Special handling to allow `class expr.A extends A` declarations
|
||||
parentName = this.parent.base.value;
|
||||
}
|
||||
this.hasNameClash = (this.name != null) && this.name === parentName;
|
||||
node = this;
|
||||
if (this.executableBody || this.hasNameClash) {
|
||||
node = new ExecutableClassBody(node, this.executableBody);
|
||||
if (executableBody || this.hasNameClash) {
|
||||
node = new ExecutableClassBody(node, executableBody);
|
||||
} else if ((this.name == null) && o.level === LEVEL_TOP) {
|
||||
// Anonymous classes are only valid in expressions
|
||||
node = new Parens(node);
|
||||
@@ -2523,18 +2523,10 @@
|
||||
result.push(this.makeCode('extends '), ...this.parent.compileToFragments(o), this.makeCode(' '));
|
||||
}
|
||||
result.push(this.makeCode('{'));
|
||||
if (!(this.passthroughBody.isEmpty() && this.body.isEmpty())) {
|
||||
if (!this.body.isEmpty()) {
|
||||
this.body.spaced = true;
|
||||
result.push(this.makeCode('\n'));
|
||||
if (!this.passthroughBody.isEmpty()) {
|
||||
result.push(...this.passthroughBody.compileToFragments(o, LEVEL_TOP));
|
||||
if (!this.body.isEmpty()) {
|
||||
result.push(this.makeCode('\n\n'));
|
||||
}
|
||||
}
|
||||
if (!this.body.isEmpty()) {
|
||||
result.push(...this.body.compileToFragments(o, LEVEL_TOP));
|
||||
}
|
||||
result.push(...this.body.compileToFragments(o, LEVEL_TOP));
|
||||
result.push(this.makeCode(`\n${this.tab}`));
|
||||
}
|
||||
result.push(this.makeCode('}'));
|
||||
@@ -2567,16 +2559,16 @@
|
||||
}
|
||||
|
||||
walkBody() {
|
||||
var assign, end, expression, expressionIndex, expressions, exprs, i, initializer, initializerExpression, j, k, len1, len2, method, passthroughBodyExpressions, properties, pushSlice, ref1, start;
|
||||
var assign, end, executableBody, expression, expressions, exprs, i, initializer, initializerExpression, j, k, len1, len2, method, properties, pushSlice, ref1, start;
|
||||
this.ctor = null;
|
||||
this.boundMethods = [];
|
||||
executableBody = null;
|
||||
initializer = [];
|
||||
passthroughBodyExpressions = [];
|
||||
({expressions} = this.body);
|
||||
i = 0;
|
||||
ref1 = expressions.slice();
|
||||
for (expressionIndex = j = 0, len1 = ref1.length; j < len1; expressionIndex = ++j) {
|
||||
expression = ref1[expressionIndex];
|
||||
for (j = 0, len1 = ref1.length; j < len1; j++) {
|
||||
expression = ref1[j];
|
||||
if (expression instanceof Value && expression.isObject(true)) {
|
||||
({properties} = expression.base);
|
||||
exprs = [];
|
||||
@@ -2599,9 +2591,6 @@
|
||||
pushSlice();
|
||||
splice.apply(expressions, [i, i - i + 1].concat(exprs)), exprs;
|
||||
i += exprs.length;
|
||||
} else if (expression instanceof Value && expression.base instanceof PassthroughLiteral) {
|
||||
passthroughBodyExpressions.push(expression);
|
||||
expressions.splice(expressionIndex, 1);
|
||||
} else {
|
||||
if (initializerExpression = this.addInitializerExpression(expression)) {
|
||||
initializer.push(initializerExpression);
|
||||
@@ -2625,7 +2614,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
this.passthroughBody = new Block(passthroughBodyExpressions);
|
||||
if (initializer.length !== expressions.length) {
|
||||
this.body.expressions = (function() {
|
||||
var l, len3, results;
|
||||
@@ -2636,16 +2624,15 @@
|
||||
}
|
||||
return results;
|
||||
})();
|
||||
return this.executableBody = new Block(expressions);
|
||||
return new Block(expressions);
|
||||
}
|
||||
}
|
||||
|
||||
// Add an expression to the class initializer
|
||||
|
||||
// NOTE Currently, only methods and static methods are valid in ES class initializers.
|
||||
// When additional expressions become valid, this method should be updated to handle them.
|
||||
addInitializerExpression(node) {
|
||||
if (this.validInitializerMethod(node)) {
|
||||
if (node.unwrapAll() instanceof PassthroughLiteral) {
|
||||
return node;
|
||||
} else if (this.validInitializerMethod(node)) {
|
||||
return this.addInitializerMethod(node);
|
||||
} else {
|
||||
return null;
|
||||
|
||||
@@ -1636,16 +1636,17 @@ exports.Class = class Class extends Base
|
||||
super()
|
||||
|
||||
compileNode: (o) ->
|
||||
@name = @determineName()
|
||||
@walkBody()
|
||||
@name = @determineName()
|
||||
executableBody = @walkBody()
|
||||
|
||||
# Special handling to allow `class expr.A extends A` declarations
|
||||
parentName = @parent.base.value if @parent instanceof Value and not @parent.hasProperties()
|
||||
@hasNameClash = @name? and @name is parentName
|
||||
|
||||
node = @
|
||||
if @executableBody or @hasNameClash
|
||||
node = new ExecutableClassBody node, @executableBody
|
||||
|
||||
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
|
||||
node = new Parens node
|
||||
@@ -1665,7 +1666,7 @@ exports.Class = class Class extends Base
|
||||
|
||||
compileClassDeclaration: (o) ->
|
||||
@ctor ?= @makeDefaultConstructor() if @externalCtor or @boundMethods.length
|
||||
@ctor?.noReturn = yes
|
||||
@ctor?.noReturn = true
|
||||
|
||||
@proxyBoundMethods() if @boundMethods.length
|
||||
|
||||
@@ -1677,14 +1678,10 @@ exports.Class = class Class extends Base
|
||||
result.push @makeCode('extends '), @parent.compileToFragments(o)..., @makeCode ' ' if @parent
|
||||
|
||||
result.push @makeCode '{'
|
||||
unless @passthroughBody.isEmpty() and @body.isEmpty()
|
||||
@body.spaced = yes
|
||||
unless @body.isEmpty()
|
||||
@body.spaced = true
|
||||
result.push @makeCode '\n'
|
||||
unless @passthroughBody.isEmpty()
|
||||
result.push @passthroughBody.compileToFragments(o, LEVEL_TOP)...
|
||||
result.push @makeCode '\n\n' unless @body.isEmpty()
|
||||
unless @body.isEmpty()
|
||||
result.push @body.compileToFragments(o, LEVEL_TOP)...
|
||||
result.push @body.compileToFragments(o, LEVEL_TOP)...
|
||||
result.push @makeCode "\n#{@tab}"
|
||||
result.push @makeCode '}'
|
||||
|
||||
@@ -1707,21 +1704,21 @@ exports.Class = class Class extends Base
|
||||
if name in JS_FORBIDDEN then "_#{name}" else name
|
||||
|
||||
walkBody: ->
|
||||
@ctor = null
|
||||
@boundMethods = []
|
||||
@ctor = null
|
||||
@boundMethods = []
|
||||
executableBody = null
|
||||
|
||||
initializer = []
|
||||
passthroughBodyExpressions = []
|
||||
{ expressions } = @body
|
||||
initializer = []
|
||||
{ expressions } = @body
|
||||
|
||||
i = 0
|
||||
for expression, expressionIndex in expressions.slice()
|
||||
if expression instanceof Value and expression.isObject yes
|
||||
for expression in expressions.slice()
|
||||
if expression instanceof Value and expression.isObject true
|
||||
{ properties } = expression.base
|
||||
exprs = []
|
||||
end = 0
|
||||
start = 0
|
||||
pushSlice = -> exprs.push new Value new Obj properties[start...end], yes if end > start
|
||||
pushSlice = -> exprs.push new Value new Obj properties[start...end], true if end > start
|
||||
|
||||
while assign = properties[end]
|
||||
if initializerExpression = @addInitializerExpression assign
|
||||
@@ -1734,9 +1731,6 @@ exports.Class = class Class extends Base
|
||||
|
||||
expressions[i..i] = exprs
|
||||
i += exprs.length
|
||||
else if expression instanceof Value and expression.base instanceof PassthroughLiteral
|
||||
passthroughBodyExpressions.push expression
|
||||
expressions.splice expressionIndex, 1
|
||||
else
|
||||
if initializerExpression = @addInitializerExpression expression
|
||||
initializer.push initializerExpression
|
||||
@@ -1752,19 +1746,15 @@ exports.Class = class Class extends Base
|
||||
else if method.bound
|
||||
@boundMethods.push method
|
||||
|
||||
@passthroughBody = new Block passthroughBodyExpressions
|
||||
|
||||
if initializer.length isnt expressions.length
|
||||
@body.expressions = (expression.hoist() for expression in initializer)
|
||||
@executableBody = new Block expressions
|
||||
|
||||
new Block expressions
|
||||
|
||||
# Add an expression to the class initializer
|
||||
#
|
||||
# NOTE Currently, only methods and static methods are valid in ES class initializers.
|
||||
# When additional expressions become valid, this method should be updated to handle them.
|
||||
addInitializerExpression: (node) ->
|
||||
if @validInitializerMethod node
|
||||
if node.unwrapAll() instanceof PassthroughLiteral
|
||||
node
|
||||
else if @validInitializerMethod node
|
||||
@addInitializerMethod node
|
||||
else
|
||||
null
|
||||
|
||||
Reference in New Issue
Block a user