Skip to content

Commit 7463517

Browse files
authored
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 55a7097 commit 7463517

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

Diff for: src/compiler/binder.ts

+3-1
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

Diff for: src/compiler/checker.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -37928,6 +37928,8 @@ namespace ts {
3792837928
return checkMappedType(<MappedTypeNode>node);
3792937929
case SyntaxKind.FunctionDeclaration:
3793037930
return checkFunctionDeclaration(<FunctionDeclaration>node);
37931+
case SyntaxKind.ClassStaticBlockDeclaration:
37932+
return forEachChild(node, checkSourceElement);
3793137933
case SyntaxKind.Block:
3793237934
case SyntaxKind.ModuleBlock:
3793337935
return checkBlock(<Block>node);
@@ -40948,7 +40950,7 @@ namespace ts {
4094840950
function checkGrammarBreakOrContinueStatement(node: BreakOrContinueStatement): boolean {
4094940951
let current: Node = node;
4095040952
while (current) {
40951-
if (isFunctionLike(current)) {
40953+
if (isFunctionLikeOrClassStaticBlockDeclaration(current)) {
4095240954
return grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary);
4095340955
}
4095440956

Diff for: src/compiler/emitter.ts

+13
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,

Diff for: src/compiler/factory/nodeFactory.ts

+32
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);

Diff for: src/compiler/parser.ts

+32
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);
@@ -6561,6 +6564,28 @@ namespace ts {
65616564
return false;
65626565
}
65636566

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

66496677
const hasJSDoc = hasPrecedingJSDocComment();
66506678
const decorators = parseDecorators();
@@ -6910,6 +6938,10 @@ namespace ts {
69106938
return nextToken() === SyntaxKind.OpenParenToken;
69116939
}
69126940

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

Diff for: src/compiler/transformers/ts.ts

+1
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

Diff for: src/compiler/types.ts

+9
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
}
@@ -6929,6 +6936,8 @@ namespace ts {
69296936
updateIndexSignature(node: IndexSignatureDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration;
69306937
createTemplateLiteralTypeSpan(type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan;
69316938
updateTemplateLiteralTypeSpan(node: TemplateLiteralTypeSpan, type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan;
6939+
createClassStaticBlockDeclaration(staticToken: Token<SyntaxKind.StaticKeyword>, body: Block): ClassStaticBlockDeclaration;
6940+
updateClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration, staticToken: Token<SyntaxKind.StaticKeyword>, body: Block): ClassStaticBlockDeclaration;
69326941

69336942
//
69346943
// Types

Diff for: src/compiler/utilities.ts

+1
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:

Diff for: src/compiler/utilitiesPublic.ts

+9
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,14 @@ namespace ts {
12191219
return !!node && isFunctionLikeKind(node.kind);
12201220
}
12211221

1222+
export function isClassStaticBlockDeclaration(node: Node): node is ClassStaticBlockDeclaration {
1223+
return node.kind === SyntaxKind.ClassStaticBlockDeclaration;
1224+
}
1225+
1226+
export function isFunctionLikeOrClassStaticBlockDeclaration(node: Node | undefined): node is (SignatureDeclaration | ClassStaticBlockDeclaration) {
1227+
return !!node && (isFunctionLikeKind(node.kind) || isClassStaticBlockDeclaration(node));
1228+
}
1229+
12221230
/* @internal */
12231231
export function isFunctionLikeDeclaration(node: Node): node is FunctionLikeDeclaration {
12241232
return node && isFunctionLikeDeclarationKind(node.kind);
@@ -1270,6 +1278,7 @@ namespace ts {
12701278
|| kind === SyntaxKind.GetAccessor
12711279
|| kind === SyntaxKind.SetAccessor
12721280
|| kind === SyntaxKind.IndexSignature
1281+
|| kind === SyntaxKind.ClassStaticBlockDeclaration
12731282
|| kind === SyntaxKind.SemicolonClassElement;
12741283
}
12751284

Diff for: src/compiler/visitorPublic.ts

+8
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,
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+
}
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+
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+
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+
}());
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+
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+
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)