Skip to content

Commit dde4ca2

Browse files
committed
Class static block (#9)
* Add types factory and parser * Add some case * Make class static block as a container * Update cases * Add visitor * Add emitter and more compile target * Check boundary of break and continue
1 parent 42b0e3c commit dde4ca2

File tree

128 files changed

+4041
-2
lines changed

Some content is hidden

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

128 files changed

+4041
-2
lines changed

src/compiler/binder.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,7 @@ namespace ts {
18291829
case SyntaxKind.ConstructSignature:
18301830
case SyntaxKind.IndexSignature:
18311831
case SyntaxKind.ConstructorType:
1832+
case SyntaxKind.ClassStaticBlockDeclaration:
18321833
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike;
18331834

18341835
case SyntaxKind.FunctionExpression:
@@ -1864,7 +1865,7 @@ namespace ts {
18641865
// By not creating a new block-scoped-container here, we ensure that both 'var x'
18651866
// and 'let x' go into the Function-container's locals, and we do get a collision
18661867
// conflict.
1867-
return isFunctionLike(node.parent) ? ContainerFlags.None : ContainerFlags.IsBlockScopedContainer;
1868+
return isFunctionLike(node.parent) || isClassStaticBlockDeclaration(node.parent) ? ContainerFlags.None : ContainerFlags.IsBlockScopedContainer;
18681869
}
18691870

18701871
return ContainerFlags.None;
@@ -1926,6 +1927,7 @@ namespace ts {
19261927
case SyntaxKind.JSDocFunctionType:
19271928
case SyntaxKind.JSDocTypedefTag:
19281929
case SyntaxKind.JSDocCallbackTag:
1930+
case SyntaxKind.ClassStaticBlockDeclaration:
19291931
case SyntaxKind.TypeAliasDeclaration:
19301932
case SyntaxKind.MappedType:
19311933
// All the children of these container types are never visible through another

src/compiler/checker.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38038,6 +38038,8 @@ namespace ts {
3803838038
return checkMappedType(<MappedTypeNode>node);
3803938039
case SyntaxKind.FunctionDeclaration:
3804038040
return checkFunctionDeclaration(<FunctionDeclaration>node);
38041+
case SyntaxKind.ClassStaticBlockDeclaration:
38042+
return forEachChild(node, checkSourceElement);
3804138043
case SyntaxKind.Block:
3804238044
case SyntaxKind.ModuleBlock:
3804338045
return checkBlock(<Block>node);
@@ -41092,7 +41094,7 @@ namespace ts {
4109241094
function checkGrammarBreakOrContinueStatement(node: BreakOrContinueStatement): boolean {
4109341095
let current: Node = node;
4109441096
while (current) {
41095-
if (isFunctionLike(current)) {
41097+
if (isFunctionLikeOrClassStaticBlockDeclaration(current)) {
4109641098
return grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary);
4109741099
}
4109841100

src/compiler/emitter.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,8 @@ namespace ts {
13411341
return emitMethodSignature(<MethodSignature>node);
13421342
case SyntaxKind.MethodDeclaration:
13431343
return emitMethodDeclaration(<MethodDeclaration>node);
1344+
case SyntaxKind.ClassStaticBlockDeclaration:
1345+
return emitClassStaticBlockDeclaration(<ClassStaticBlockDeclaration>node);
13441346
case SyntaxKind.Constructor:
13451347
return emitConstructor(<ConstructorDeclaration>node);
13461348
case SyntaxKind.GetAccessor:
@@ -2008,6 +2010,11 @@ namespace ts {
20082010
emitSignatureAndBody(node, emitSignatureHead);
20092011
}
20102012

2013+
function emitClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration) {
2014+
emit(node.staticToken);
2015+
emitBlockFunctionBody(node.body);
2016+
}
2017+
20112018
function emitConstructor(node: ConstructorDeclaration) {
20122019
emitModifiers(node, node.modifiers);
20132020
writeKeyword("constructor");
@@ -5770,6 +5777,12 @@ namespace ts {
57705777
visitTypeNode(node.type),
57715778
visitFunctionBody(node.body));
57725779

5780+
case SyntaxKind.ClassStaticBlockDeclaration:
5781+
Debug.type<ClassStaticBlockDeclaration>(node);
5782+
return factory.updateClassStaticBlockDeclaration(node,
5783+
visit(node.staticToken, isStaticModifier),
5784+
visitFunctionBody(node.body));
5785+
57735786
case SyntaxKind.Constructor:
57745787
Debug.type<ConstructorDeclaration>(node);
57755788
return factory.updateConstructorDeclaration(node,

src/compiler/factory/nodeFactory.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ namespace ts {
9494
updateConstructSignature,
9595
createIndexSignature,
9696
updateIndexSignature,
97+
createClassStaticBlockDeclaration,
98+
updateClassStaticBlockDeclaration,
9799
createTemplateLiteralTypeSpan,
98100
updateTemplateLiteralTypeSpan,
99101
createKeywordTypeNode,
@@ -1610,6 +1612,36 @@ namespace ts {
16101612
: node;
16111613
}
16121614

1615+
// @api
1616+
function createClassStaticBlockDeclaration(
1617+
staticToken: Token<SyntaxKind.StaticKeyword>,
1618+
body: Block
1619+
): ClassStaticBlockDeclaration {
1620+
const node = createBaseGenericNamedDeclaration<ClassStaticBlockDeclaration>(
1621+
SyntaxKind.ClassStaticBlockDeclaration,
1622+
/*decorators*/ undefined,
1623+
/*modifiers*/ undefined,
1624+
/*name*/ undefined,
1625+
/*typeParameters*/ undefined
1626+
);
1627+
node.staticToken = staticToken;
1628+
node.body = body;
1629+
node.transformFlags = TransformFlags.ContainsESNext;
1630+
return node;
1631+
}
1632+
1633+
// @api
1634+
function updateClassStaticBlockDeclaration(
1635+
node: ClassStaticBlockDeclaration,
1636+
staticToken: Token<SyntaxKind.StaticKeyword>,
1637+
body: Block
1638+
): ClassStaticBlockDeclaration {
1639+
return node.staticToken !== staticToken
1640+
|| node.body !== body
1641+
? update(createClassStaticBlockDeclaration(staticToken, body), node)
1642+
: node;
1643+
}
1644+
16131645
// @api
16141646
function createTemplateLiteralTypeSpan(type: TypeNode, literal: TemplateMiddle | TemplateTail) {
16151647
const node = createBaseNode<TemplateLiteralTypeSpan>(SyntaxKind.TemplateLiteralTypeSpan);

src/compiler/parser.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ namespace ts {
168168
visitNode(cbNode, (<FunctionLikeDeclaration>node).type) ||
169169
visitNode(cbNode, (<ArrowFunction>node).equalsGreaterThanToken) ||
170170
visitNode(cbNode, (<FunctionLikeDeclaration>node).body);
171+
case SyntaxKind.ClassStaticBlockDeclaration:
172+
return visitNode(cbNode, (<ClassStaticBlockDeclaration>node).staticToken) ||
173+
visitNode(cbNode, (<ClassStaticBlockDeclaration>node).body);
171174
case SyntaxKind.TypeReference:
172175
return visitNode(cbNode, (<TypeReferenceNode>node).typeName) ||
173176
visitNodes(cbNode, cbNodes, (<TypeReferenceNode>node).typeArguments);
@@ -6562,6 +6565,28 @@ namespace ts {
65626565
return false;
65636566
}
65646567

6568+
function parseClassStaticBlockDeclaration(): ClassStaticBlockDeclaration {
6569+
const pos = getNodePos();
6570+
const staticKeyworkd = parseExpectedToken(SyntaxKind.StaticKeyword);
6571+
const body = parseClassStaticBlockBodyBlock();
6572+
return finishNode(factory.createClassStaticBlockDeclaration(staticKeyworkd, body), pos);
6573+
}
6574+
6575+
function parseClassStaticBlockBodyBlock() {
6576+
const savedYieldContext = inYieldContext();
6577+
setYieldContext(false);
6578+
6579+
const savedAwaitContext = inAwaitContext();
6580+
setAwaitContext(false);
6581+
6582+
const block = parseBlock(/*ignoreMissingOpenBrace*/ false);
6583+
6584+
setAwaitContext(savedAwaitContext);
6585+
setYieldContext(savedYieldContext);
6586+
6587+
return block;
6588+
}
6589+
65656590
function parseDecoratorExpression() {
65666591
if (inAwaitContext() && token() === SyntaxKind.AwaitKeyword) {
65676592
// `@await` is is disallowed in an [Await] context, but can cause parsing to go off the rails
@@ -6646,6 +6671,9 @@ namespace ts {
66466671
nextToken();
66476672
return finishNode(factory.createSemicolonClassElement(), pos);
66486673
}
6674+
if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) {
6675+
return parseClassStaticBlockDeclaration();
6676+
}
66496677

66506678
const hasJSDoc = hasPrecedingJSDocComment();
66516679
const decorators = parseDecorators();
@@ -6911,6 +6939,10 @@ namespace ts {
69116939
return nextToken() === SyntaxKind.OpenParenToken;
69126940
}
69136941

6942+
function nextTokenIsOpenBrace() {
6943+
return nextToken() === SyntaxKind.OpenBraceToken;
6944+
}
6945+
69146946
function nextTokenIsSlash() {
69156947
return nextToken() === SyntaxKind.SlashToken;
69166948
}

src/compiler/transformers/ts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ namespace ts {
324324
case SyntaxKind.GetAccessor:
325325
case SyntaxKind.SetAccessor:
326326
case SyntaxKind.MethodDeclaration:
327+
case SyntaxKind.ClassStaticBlockDeclaration:
327328
// Fallback to the default visit behavior.
328329
return visitorWorker(node);
329330

src/compiler/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ namespace ts {
208208
SetAccessor,
209209
CallSignature,
210210
ConstructSignature,
211+
ClassStaticBlockDeclaration,
211212
IndexSignature,
212213
// Type
213214
TypePredicate,
@@ -1502,6 +1503,12 @@ namespace ts {
15021503
readonly type: TypeNode;
15031504
}
15041505

1506+
export interface ClassStaticBlockDeclaration extends ClassElement {
1507+
readonly kind: SyntaxKind.ClassStaticBlockDeclaration;
1508+
readonly staticToken: Token<SyntaxKind.StaticKeyword>;
1509+
readonly body: Block;
1510+
}
1511+
15051512
export interface TypeNode extends Node {
15061513
_typeNodeBrand: any;
15071514
}
@@ -6932,6 +6939,8 @@ namespace ts {
69326939
updateIndexSignature(node: IndexSignatureDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration;
69336940
createTemplateLiteralTypeSpan(type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan;
69346941
updateTemplateLiteralTypeSpan(node: TemplateLiteralTypeSpan, type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan;
6942+
createClassStaticBlockDeclaration(staticToken: Token<SyntaxKind.StaticKeyword>, body: Block): ClassStaticBlockDeclaration;
6943+
updateClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration, staticToken: Token<SyntaxKind.StaticKeyword>, body: Block): ClassStaticBlockDeclaration;
69356944

69366945
//
69376946
// Types

src/compiler/utilities.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,6 +1601,7 @@ namespace ts {
16011601
case SyntaxKind.FunctionDeclaration:
16021602
case SyntaxKind.FunctionExpression:
16031603
case SyntaxKind.ModuleDeclaration:
1604+
case SyntaxKind.ClassStaticBlockDeclaration:
16041605
case SyntaxKind.PropertyDeclaration:
16051606
case SyntaxKind.PropertySignature:
16061607
case SyntaxKind.MethodDeclaration:

src/compiler/utilitiesPublic.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,14 @@ namespace ts {
12211221
return !!node && isFunctionLikeKind(node.kind);
12221222
}
12231223

1224+
export function isClassStaticBlockDeclaration(node: Node): node is ClassStaticBlockDeclaration {
1225+
return node.kind === SyntaxKind.ClassStaticBlockDeclaration;
1226+
}
1227+
1228+
export function isFunctionLikeOrClassStaticBlockDeclaration(node: Node | undefined): node is (SignatureDeclaration | ClassStaticBlockDeclaration) {
1229+
return !!node && (isFunctionLikeKind(node.kind) || isClassStaticBlockDeclaration(node));
1230+
}
1231+
12241232
/* @internal */
12251233
export function isFunctionLikeDeclaration(node: Node): node is FunctionLikeDeclaration {
12261234
return node && isFunctionLikeDeclarationKind(node.kind);
@@ -1272,6 +1280,7 @@ namespace ts {
12721280
|| kind === SyntaxKind.GetAccessor
12731281
|| kind === SyntaxKind.SetAccessor
12741282
|| kind === SyntaxKind.IndexSignature
1283+
|| kind === SyntaxKind.ClassStaticBlockDeclaration
12751284
|| kind === SyntaxKind.SemicolonClassElement;
12761285
}
12771286

src/compiler/visitorPublic.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,14 @@ namespace ts {
475475
visitParameterList(node.parameters, visitor, context, nodesVisitor),
476476
visitFunctionBody(node.body!, visitor, context, nodeVisitor));
477477

478+
case SyntaxKind.ClassStaticBlockDeclaration:
479+
Debug.type<ClassStaticBlockDeclaration>(node);
480+
context.startLexicalEnvironment();
481+
context.suspendLexicalEnvironment();
482+
return factory.updateClassStaticBlockDeclaration(node,
483+
nodeVisitor(node.staticToken, visitor, isStaticModifier),
484+
visitFunctionBody(node.body, visitor, context, nodeVisitor));
485+
478486
case SyntaxKind.CallSignature:
479487
Debug.type<CallSignatureDeclaration>(node);
480488
return factory.updateCallSignature(node,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//// [classStaticBlock1.ts]
2+
const a = 2;
3+
4+
class C {
5+
static {
6+
const a = 1;
7+
8+
a;
9+
}
10+
}
11+
12+
13+
//// [classStaticBlock1.js]
14+
const a = 2;
15+
class C {
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/conformance/classes/classStaticBlock/classStaticBlock1.ts ===
2+
const a = 2;
3+
>a : Symbol(a, Decl(classStaticBlock1.ts, 0, 5))
4+
5+
class C {
6+
>C : Symbol(C, Decl(classStaticBlock1.ts, 0, 12))
7+
8+
static {
9+
const a = 1;
10+
>a : Symbol(a, Decl(classStaticBlock1.ts, 4, 13))
11+
12+
a;
13+
>a : Symbol(a, Decl(classStaticBlock1.ts, 4, 13))
14+
}
15+
}
16+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/conformance/classes/classStaticBlock/classStaticBlock1.ts ===
2+
const a = 2;
3+
>a : 2
4+
>2 : 2
5+
6+
class C {
7+
>C : C
8+
9+
static {
10+
const a = 1;
11+
>a : 1
12+
>1 : 1
13+
14+
a;
15+
>a : 1
16+
}
17+
}
18+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//// [classStaticBlock1.ts]
2+
const a = 2;
3+
4+
class C {
5+
static {
6+
const a = 1;
7+
8+
a;
9+
}
10+
}
11+
12+
13+
//// [classStaticBlock1.js]
14+
var a = 2;
15+
var C = /** @class */ (function () {
16+
function C() {
17+
}
18+
return C;
19+
}());
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/conformance/classes/classStaticBlock/classStaticBlock1.ts ===
2+
const a = 2;
3+
>a : Symbol(a, Decl(classStaticBlock1.ts, 0, 5))
4+
5+
class C {
6+
>C : Symbol(C, Decl(classStaticBlock1.ts, 0, 12))
7+
8+
static {
9+
const a = 1;
10+
>a : Symbol(a, Decl(classStaticBlock1.ts, 4, 13))
11+
12+
a;
13+
>a : Symbol(a, Decl(classStaticBlock1.ts, 4, 13))
14+
}
15+
}
16+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/conformance/classes/classStaticBlock/classStaticBlock1.ts ===
2+
const a = 2;
3+
>a : 2
4+
>2 : 2
5+
6+
class C {
7+
>C : C
8+
9+
static {
10+
const a = 1;
11+
>a : 1
12+
>1 : 1
13+
14+
a;
15+
>a : 1
16+
}
17+
}
18+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [classStaticBlock1.ts]
2+
const a = 2;
3+
4+
class C {
5+
static {
6+
const a = 1;
7+
8+
a;
9+
}
10+
}
11+
12+
13+
//// [classStaticBlock1.js]
14+
const a = 2;
15+
class C {
16+
static {
17+
const a = 1;
18+
a;
19+
}
20+
}

0 commit comments

Comments
 (0)