Skip to content

Commit f7aaf09

Browse files
Add support for parsing and emitting class expressions.
1 parent a1e18fc commit f7aaf09

48 files changed

Lines changed: 906 additions & 7029 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/compiler/binder.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ module ts {
126126
return (<ExportAssignment>node).isExportEquals ? "export=" : "default";
127127
case SyntaxKind.FunctionDeclaration:
128128
case SyntaxKind.ClassDeclaration:
129+
case SyntaxKind.ClassExpression:
129130
return node.flags & NodeFlags.Default ? "default" : undefined;
130131
}
131132
}
@@ -168,7 +169,7 @@ module ts {
168169
addDeclarationToSymbol(symbol, node, includes);
169170
symbol.parent = parent;
170171

171-
if (node.kind === SyntaxKind.ClassDeclaration && symbol.exports) {
172+
if ((node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) && symbol.exports) {
172173
// TypeScript 1.0 spec (April 2014): 8.4
173174
// Every class automatically contains a static property member named 'prototype',
174175
// the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter.
@@ -286,6 +287,7 @@ module ts {
286287
case SyntaxKind.ArrowFunction:
287288
declareSymbol(container.locals, undefined, node, symbolKind, symbolExcludes);
288289
break;
290+
case SyntaxKind.ClassExpression:
289291
case SyntaxKind.ClassDeclaration:
290292
if (node.flags & NodeFlags.Static) {
291293
declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes);
@@ -485,6 +487,9 @@ module ts {
485487
case SyntaxKind.ArrowFunction:
486488
bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, "__function", /*isBlockScopeContainer*/ true);
487489
break;
490+
case SyntaxKind.ClassExpression:
491+
bindAnonymousDeclaration(<ClassExpression>node, SymbolFlags.Class, "__class", /*isBlockScopeContainer*/ false);
492+
break;
488493
case SyntaxKind.CatchClause:
489494
bindCatchVariableDeclaration(<CatchClause>node);
490495
break;
@@ -584,9 +589,9 @@ module ts {
584589
// containing class.
585590
if (node.flags & NodeFlags.AccessibilityModifier &&
586591
node.parent.kind === SyntaxKind.Constructor &&
587-
node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
592+
(node.parent.parent.kind === SyntaxKind.ClassDeclaration || node.parent.parent.kind === SyntaxKind.ClassExpression)) {
588593

589-
let classDeclaration = <ClassDeclaration>node.parent.parent;
594+
let classDeclaration = <ClassLikeDeclaration>node.parent.parent;
590595
declareSymbol(classDeclaration.symbol.members, classDeclaration.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
591596
}
592597
}

src/compiler/checker.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,15 @@ module ts {
422422
result = argumentsSymbol;
423423
break loop;
424424
}
425-
let id = (<FunctionExpression>location).name;
426-
if (id && name === id.text) {
425+
let functionName = (<FunctionExpression>location).name;
426+
if (functionName && name === functionName.text) {
427+
result = location.symbol;
428+
break loop;
429+
}
430+
break;
431+
case SyntaxKind.ClassExpression:
432+
let className = (<ClassExpression>location).name;
433+
if (className && name === className.text) {
427434
result = location.symbol;
428435
break loop;
429436
}
@@ -7991,6 +7998,8 @@ module ts {
79917998
return checkTypeAssertion(<TypeAssertion>node);
79927999
case SyntaxKind.ParenthesizedExpression:
79938000
return checkExpression((<ParenthesizedExpression>node).expression, contextualMapper);
8001+
case SyntaxKind.ClassExpression:
8002+
return checkClassExpression(<ClassExpression>node);
79948003
case SyntaxKind.FunctionExpression:
79958004
case SyntaxKind.ArrowFunction:
79968005
return checkFunctionExpressionOrObjectLiteralMethod(<FunctionExpression>node, contextualMapper);
@@ -9732,8 +9741,18 @@ module ts {
97329741
}
97339742
}
97349743

9744+
function checkClassExpression(node: ClassExpression): Type {
9745+
grammarErrorOnNode(node, Diagnostics.class_expressions_are_not_currently_supported);
9746+
forEach(node.members, checkSourceElement);
9747+
return unknownType;
9748+
}
9749+
97359750
function checkClassDeclaration(node: ClassDeclaration) {
97369751
// Grammar checking
9752+
if (node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
9753+
grammarErrorOnNode(node, Diagnostics.class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration);
9754+
}
9755+
97379756
checkGrammarClassDeclarationHeritageClauses(node);
97389757
checkDecorators(node);
97399758
if (node.name) {

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,5 +501,7 @@ module ts {
501501
yield_expressions_are_not_currently_supported: { code: 9000, category: DiagnosticCategory.Error, key: "'yield' expressions are not currently supported." },
502502
Generators_are_not_currently_supported: { code: 9001, category: DiagnosticCategory.Error, key: "Generators are not currently supported." },
503503
Only_type_references_are_currently_supported_in_a_class_extends_clauses: { code: 9002, category: DiagnosticCategory.Error, key: "Only type references are currently supported in a class 'extends' clauses." },
504+
class_expressions_are_not_currently_supported: { code: 9003, category: DiagnosticCategory.Error, key: "'class' expressions are not currently supported." },
505+
class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration: { code: 9004, category: DiagnosticCategory.Error, key: "'class' declarations are only supported directly inside a module or as a top level declaration." },
504506
};
505507
}

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,5 +1997,13 @@
19971997
"Only type references are currently supported in a class 'extends' clauses.": {
19981998
"category": "Error",
19991999
"code": 9002
2000+
},
2001+
"'class' expressions are not currently supported.": {
2002+
"category": "Error",
2003+
"code": 9003
2004+
},
2005+
"'class' declarations are only supported directly inside a module or as a top level declaration.": {
2006+
"category": "Error",
2007+
"code": 9004
20002008
}
20012009
}

src/compiler/emitter.ts

Lines changed: 103 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3193,7 +3193,7 @@ module ts {
31933193
}
31943194
}
31953195

3196-
function emitMemberAssignments(node: ClassDeclaration, staticFlag: NodeFlags) {
3196+
function emitMemberAssignments(node: ClassLikeDeclaration, staticFlag: NodeFlags) {
31973197
forEach(node.members, member => {
31983198
if (member.kind === SyntaxKind.PropertyDeclaration && (member.flags & NodeFlags.Static) === staticFlag && (<PropertyDeclaration>member).initializer) {
31993199
writeLine();
@@ -3217,7 +3217,7 @@ module ts {
32173217
});
32183218
}
32193219

3220-
function emitMemberFunctionsForES5AndLower(node: ClassDeclaration) {
3220+
function emitMemberFunctionsForES5AndLower(node: ClassLikeDeclaration) {
32213221
forEach(node.members, member => {
32223222
if (member.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) {
32233223
if (!(<MethodDeclaration>member).body) {
@@ -3287,7 +3287,7 @@ module ts {
32873287
});
32883288
}
32893289

3290-
function emitMemberFunctionsForES6AndHigher(node: ClassDeclaration) {
3290+
function emitMemberFunctionsForES6AndHigher(node: ClassLikeDeclaration) {
32913291
for (let member of node.members) {
32923292
if ((member.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) && !(<MethodDeclaration>member).body) {
32933293
emitOnlyPinnedOrTripleSlashComments(member);
@@ -3314,7 +3314,7 @@ module ts {
33143314
}
33153315
}
33163316

3317-
function emitConstructor(node: ClassDeclaration, baseTypeElement: HeritageClauseElement) {
3317+
function emitConstructor(node: ClassLikeDeclaration, baseTypeElement: HeritageClauseElement) {
33183318
let saveTempFlags = tempFlags;
33193319
let saveTempVariables = tempVariables;
33203320
let saveTempParameters = tempParameters;
@@ -3435,82 +3435,92 @@ module ts {
34353435
tempParameters = saveTempParameters;
34363436
}
34373437

3438+
function emitClassExpression(node: ClassExpression) {
3439+
return emitClassLikeDeclaration(node);
3440+
}
3441+
34383442
function emitClassDeclaration(node: ClassDeclaration) {
3443+
return emitClassLikeDeclaration(node);
3444+
}
3445+
3446+
function emitClassLikeDeclaration(node: ClassLikeDeclaration) {
34393447
if (languageVersion < ScriptTarget.ES6) {
3440-
emitClassDeclarationBelowES6(<ClassDeclaration>node);
3448+
emitClassLikeDeclarationBelowES6(node);
34413449
}
34423450
else {
3443-
emitClassDeclarationForES6AndHigher(<ClassDeclaration>node);
3451+
emitClassLikeDeclarationForES6AndHigher(node);
34443452
}
34453453
}
34463454

3447-
function emitClassDeclarationForES6AndHigher(node: ClassDeclaration) {
3455+
function emitClassLikeDeclarationForES6AndHigher(node: ClassLikeDeclaration) {
34483456
let thisNodeIsDecorated = nodeIsDecorated(node);
3449-
if (thisNodeIsDecorated) {
3450-
// To preserve the correct runtime semantics when decorators are applied to the class,
3451-
// the emit needs to follow one of the following rules:
3452-
//
3453-
// * For a local class declaration:
3454-
//
3455-
// @dec class C {
3456-
// }
3457-
//
3458-
// The emit should be:
3459-
//
3460-
// let C = class {
3461-
// };
3462-
// Object.defineProperty(C, "name", { value: "C", configurable: true });
3463-
// C = __decorate([dec], C);
3464-
//
3465-
// * For an exported class declaration:
3466-
//
3467-
// @dec export class C {
3468-
// }
3469-
//
3470-
// The emit should be:
3471-
//
3472-
// export let C = class {
3473-
// };
3474-
// Object.defineProperty(C, "name", { value: "C", configurable: true });
3475-
// C = __decorate([dec], C);
3476-
//
3477-
// * For a default export of a class declaration with a name:
3478-
//
3479-
// @dec default export class C {
3480-
// }
3481-
//
3482-
// The emit should be:
3483-
//
3484-
// let C = class {
3485-
// }
3486-
// Object.defineProperty(C, "name", { value: "C", configurable: true });
3487-
// C = __decorate([dec], C);
3488-
// export default C;
3489-
//
3490-
// * For a default export of a class declaration without a name:
3491-
//
3492-
// @dec default export class {
3493-
// }
3494-
//
3495-
// The emit should be:
3496-
//
3497-
// let _default = class {
3498-
// }
3499-
// _default = __decorate([dec], _default);
3500-
// export default _default;
3501-
//
3502-
if (isES6ExportedDeclaration(node) && !(node.flags & NodeFlags.Default)) {
3503-
write("export ");
3504-
}
3457+
if (node.kind === SyntaxKind.ClassDeclaration) {
3458+
if (thisNodeIsDecorated) {
3459+
// To preserve the correct runtime semantics when decorators are applied to the class,
3460+
// the emit needs to follow one of the following rules:
3461+
//
3462+
// * For a local class declaration:
3463+
//
3464+
// @dec class C {
3465+
// }
3466+
//
3467+
// The emit should be:
3468+
//
3469+
// let C = class {
3470+
// };
3471+
// Object.defineProperty(C, "name", { value: "C", configurable: true });
3472+
// C = __decorate([dec], C);
3473+
//
3474+
// * For an exported class declaration:
3475+
//
3476+
// @dec export class C {
3477+
// }
3478+
//
3479+
// The emit should be:
3480+
//
3481+
// export let C = class {
3482+
// };
3483+
// Object.defineProperty(C, "name", { value: "C", configurable: true });
3484+
// C = __decorate([dec], C);
3485+
//
3486+
// * For a default export of a class declaration with a name:
3487+
//
3488+
// @dec default export class C {
3489+
// }
3490+
//
3491+
// The emit should be:
3492+
//
3493+
// let C = class {
3494+
// }
3495+
// Object.defineProperty(C, "name", { value: "C", configurable: true });
3496+
// C = __decorate([dec], C);
3497+
// export default C;
3498+
//
3499+
// * For a default export of a class declaration without a name:
3500+
//
3501+
// @dec default export class {
3502+
// }
3503+
//
3504+
// The emit should be:
3505+
//
3506+
// let _default = class {
3507+
// }
3508+
// _default = __decorate([dec], _default);
3509+
// export default _default;
3510+
//
3511+
if (isES6ExportedDeclaration(node) && !(node.flags & NodeFlags.Default)) {
3512+
write("export ");
3513+
}
35053514

3506-
write("let ");
3507-
emitDeclarationName(node);
3508-
write(" = ");
3509-
}
3510-
else if (isES6ExportedDeclaration(node)) {
3511-
write("export ");
3512-
if (node.flags & NodeFlags.Default) {
3513-
write("default ");
3515+
write("let ");
3516+
emitDeclarationName(node);
3517+
write(" = ");
3518+
}
3519+
else if (isES6ExportedDeclaration(node)) {
3520+
write("export ");
3521+
if (node.flags & NodeFlags.Default) {
3522+
write("default ");
3523+
}
35143524
}
35153525
}
35163526

@@ -3588,10 +3598,14 @@ module ts {
35883598
}
35893599
}
35903600

3591-
function emitClassDeclarationBelowES6(node: ClassDeclaration) {
3592-
write("var ");
3593-
emitDeclarationName(node);
3594-
write(" = (function (");
3601+
function emitClassLikeDeclarationBelowES6(node: ClassLikeDeclaration) {
3602+
if (node.kind === SyntaxKind.ClassDeclaration) {
3603+
write("var ");
3604+
emitDeclarationName(node);
3605+
write(" = ");
3606+
}
3607+
3608+
write("(function (");
35953609
let baseTypeNode = getClassBaseTypeNode(node);
35963610
if (baseTypeNode) {
35973611
write("_super");
@@ -3641,30 +3655,35 @@ module ts {
36413655
if (baseTypeNode) {
36423656
emit(baseTypeNode.expression);
36433657
}
3644-
write(");");
3658+
write(")");
3659+
if (node.kind === SyntaxKind.ClassDeclaration) {
3660+
write(";");
3661+
}
36453662
emitEnd(node);
36463663

3647-
emitExportMemberAssignment(node);
3664+
if (node.kind === SyntaxKind.ClassDeclaration) {
3665+
emitExportMemberAssignment(<ClassDeclaration>node);
3666+
}
36483667

36493668
if (languageVersion < ScriptTarget.ES6 && node.parent === currentSourceFile && node.name) {
36503669
emitExportMemberAssignments(node.name);
36513670
}
36523671
}
36533672

3654-
function emitClassMemberPrefix(node: ClassDeclaration, member: Node) {
3673+
function emitClassMemberPrefix(node: ClassLikeDeclaration, member: Node) {
36553674
emitDeclarationName(node);
36563675
if (!(member.flags & NodeFlags.Static)) {
36573676
write(".prototype");
36583677
}
36593678
}
36603679

3661-
function emitDecoratorsOfClass(node: ClassDeclaration) {
3680+
function emitDecoratorsOfClass(node: ClassLikeDeclaration) {
36623681
emitDecoratorsOfMembers(node, /*staticFlag*/ 0);
36633682
emitDecoratorsOfMembers(node, NodeFlags.Static);
36643683
emitDecoratorsOfConstructor(node);
36653684
}
36663685

3667-
function emitDecoratorsOfConstructor(node: ClassDeclaration) {
3686+
function emitDecoratorsOfConstructor(node: ClassLikeDeclaration) {
36683687
let constructor = getFirstConstructorWithBody(node);
36693688
if (constructor) {
36703689
emitDecoratorsOfParameters(node, constructor);
@@ -3696,7 +3715,7 @@ module ts {
36963715
writeLine();
36973716
}
36983717

3699-
function emitDecoratorsOfMembers(node: ClassDeclaration, staticFlag: NodeFlags) {
3718+
function emitDecoratorsOfMembers(node: ClassLikeDeclaration, staticFlag: NodeFlags) {
37003719
forEach(node.members, member => {
37013720
if ((member.flags & NodeFlags.Static) !== staticFlag) {
37023721
return;
@@ -3800,7 +3819,7 @@ module ts {
38003819
});
38013820
}
38023821

3803-
function emitDecoratorsOfParameters(node: ClassDeclaration, member: FunctionLikeDeclaration) {
3822+
function emitDecoratorsOfParameters(node: ClassLikeDeclaration, member: FunctionLikeDeclaration) {
38043823
forEach(member.parameters, (parameter, parameterIndex) => {
38053824
if (!nodeIsDecorated(parameter)) {
38063825
return;
@@ -4768,6 +4787,8 @@ var __decorate = this.__decorate || function (decorators, target, key, value) {
47684787
return emitDebuggerStatement(node);
47694788
case SyntaxKind.VariableDeclaration:
47704789
return emitVariableDeclaration(<VariableDeclaration>node);
4790+
case SyntaxKind.ClassExpression:
4791+
return emitClassExpression(<ClassExpression>node);
47714792
case SyntaxKind.ClassDeclaration:
47724793
return emitClassDeclaration(<ClassDeclaration>node);
47734794
case SyntaxKind.InterfaceDeclaration:

0 commit comments

Comments
 (0)