Simplify fix for #4464

This uses more of the existing machinery for moving class body
expressions into the initializer.
This commit is contained in:
Chris Connelly
2017-09-20 15:58:03 +01:00
parent becdf504ce
commit 1d3af8c432
2 changed files with 35 additions and 58 deletions

View File

@@ -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;

View File

@@ -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