xbintsc 0.1.3 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +14 -13
  2. package/dist/src/ast/common.d.ts +33 -0
  3. package/dist/src/ast/common.js +7 -0
  4. package/dist/src/ast/common.js.map +1 -0
  5. package/dist/src/ast/declarations.d.ts +110 -0
  6. package/dist/src/ast/declarations.js +5 -0
  7. package/dist/src/ast/declarations.js.map +1 -0
  8. package/dist/src/ast/expressions.d.ts +219 -0
  9. package/dist/src/ast/expressions.js +6 -0
  10. package/dist/src/ast/expressions.js.map +1 -0
  11. package/dist/src/ast/kinds.d.ts +160 -0
  12. package/dist/src/ast/kinds.js +171 -0
  13. package/dist/src/ast/kinds.js.map +1 -0
  14. package/dist/src/ast/modules.d.ts +61 -0
  15. package/dist/src/ast/modules.js +5 -0
  16. package/dist/src/ast/modules.js.map +1 -0
  17. package/dist/src/ast/nodes.d.ts +11 -839
  18. package/dist/src/ast/nodes.js +11 -237
  19. package/dist/src/ast/nodes.js.map +1 -1
  20. package/dist/src/ast/operators.d.ts +71 -0
  21. package/dist/src/ast/operators.js +77 -0
  22. package/dist/src/ast/operators.js.map +1 -0
  23. package/dist/src/ast/statements.d.ts +120 -0
  24. package/dist/src/ast/statements.js +5 -0
  25. package/dist/src/ast/statements.js.map +1 -0
  26. package/dist/src/ast/types.d.ts +123 -0
  27. package/dist/src/ast/types.js +6 -0
  28. package/dist/src/ast/types.js.map +1 -0
  29. package/dist/src/codegen/generator/calls.d.ts +22 -0
  30. package/dist/src/codegen/generator/calls.js +301 -0
  31. package/dist/src/codegen/generator/calls.js.map +1 -0
  32. package/dist/src/codegen/generator/context.d.ts +45 -0
  33. package/dist/src/codegen/generator/context.js +128 -0
  34. package/dist/src/codegen/generator/context.js.map +1 -0
  35. package/dist/src/codegen/generator/expressions.d.ts +22 -0
  36. package/dist/src/codegen/generator/expressions.js +383 -0
  37. package/dist/src/codegen/generator/expressions.js.map +1 -0
  38. package/dist/src/codegen/generator/generator.d.ts +22 -0
  39. package/dist/src/codegen/generator/generator.js +21 -0
  40. package/dist/src/codegen/generator/generator.js.map +1 -0
  41. package/dist/src/codegen/generator/module.d.ts +15 -0
  42. package/dist/src/codegen/generator/module.js +114 -0
  43. package/dist/src/codegen/generator/module.js.map +1 -0
  44. package/dist/src/codegen/generator/state.d.ts +40 -0
  45. package/dist/src/codegen/generator/state.js +84 -0
  46. package/dist/src/codegen/generator/state.js.map +1 -0
  47. package/dist/src/codegen/generator/statements.d.ts +22 -0
  48. package/dist/src/codegen/generator/statements.js +425 -0
  49. package/dist/src/codegen/generator/statements.js.map +1 -0
  50. package/dist/src/codegen/generator/tables.d.ts +19 -0
  51. package/dist/src/codegen/generator/tables.js +153 -0
  52. package/dist/src/codegen/generator/tables.js.map +1 -0
  53. package/dist/src/codegen/llvm.d.ts +4 -13
  54. package/dist/src/codegen/llvm.js +4 -1159
  55. package/dist/src/codegen/llvm.js.map +1 -1
  56. package/dist/src/driver/compiler.js +13 -4
  57. package/dist/src/driver/compiler.js.map +1 -1
  58. package/dist/src/lexer/char.d.ts +78 -0
  59. package/dist/src/lexer/char.js +106 -0
  60. package/dist/src/lexer/char.js.map +1 -0
  61. package/dist/src/lexer/scanner.js +1 -98
  62. package/dist/src/lexer/scanner.js.map +1 -1
  63. package/dist/src/parser/context.d.ts +58 -0
  64. package/dist/src/parser/context.js +174 -0
  65. package/dist/src/parser/context.js.map +1 -0
  66. package/dist/src/parser/declarations.d.ts +26 -0
  67. package/dist/src/parser/declarations.js +461 -0
  68. package/dist/src/parser/declarations.js.map +1 -0
  69. package/dist/src/parser/expressions.d.ts +27 -0
  70. package/dist/src/parser/expressions.js +437 -0
  71. package/dist/src/parser/expressions.js.map +1 -0
  72. package/dist/src/parser/helpers.d.ts +7 -0
  73. package/dist/src/parser/helpers.js +36 -0
  74. package/dist/src/parser/helpers.js.map +1 -0
  75. package/dist/src/parser/literals.d.ts +16 -0
  76. package/dist/src/parser/literals.js +193 -0
  77. package/dist/src/parser/literals.js.map +1 -0
  78. package/dist/src/parser/modules.d.ts +12 -0
  79. package/dist/src/parser/modules.js +175 -0
  80. package/dist/src/parser/modules.js.map +1 -0
  81. package/dist/src/parser/operators.d.ts +12 -0
  82. package/dist/src/parser/operators.js +172 -0
  83. package/dist/src/parser/operators.js.map +1 -0
  84. package/dist/src/parser/parser.d.ts +17 -122
  85. package/dist/src/parser/parser.js +18 -2307
  86. package/dist/src/parser/parser.js.map +1 -1
  87. package/dist/src/parser/speculation.d.ts +6 -0
  88. package/dist/src/parser/speculation.js +10 -0
  89. package/dist/src/parser/speculation.js.map +1 -0
  90. package/dist/src/parser/statements.d.ts +28 -0
  91. package/dist/src/parser/statements.js +402 -0
  92. package/dist/src/parser/statements.js.map +1 -0
  93. package/dist/src/parser/types.d.ts +21 -0
  94. package/dist/src/parser/types.js +338 -0
  95. package/dist/src/parser/types.js.map +1 -0
  96. package/dist/tests/e2e/compile.test.js +122 -2
  97. package/dist/tests/e2e/compile.test.js.map +1 -1
  98. package/dist/tests/parser/parser.test.js +9 -1
  99. package/dist/tests/parser/parser.test.js.map +1 -1
  100. package/package.json +1 -1
  101. package/runtime/rt.h +32 -0
  102. package/runtime/rt_internal.h +106 -0
  103. package/runtime/xt_alloc.c +38 -0
  104. package/runtime/xt_builtins.c +192 -0
  105. package/runtime/xt_containers.c +225 -0
  106. package/runtime/xt_io.c +133 -0
  107. package/runtime/xt_stdlib.c +502 -0
  108. package/runtime/xt_values.c +291 -0
  109. package/scripts/build-runtime.mjs +8 -1
  110. package/src/ast/common.ts +210 -0
  111. package/src/ast/declarations.ts +130 -0
  112. package/src/ast/expressions.ts +275 -0
  113. package/src/ast/kinds.ts +176 -0
  114. package/src/ast/modules.ts +73 -0
  115. package/src/ast/nodes.ts +11 -1101
  116. package/src/ast/operators.ts +76 -0
  117. package/src/ast/statements.ts +148 -0
  118. package/src/ast/types.ts +173 -0
  119. package/src/codegen/generator/calls.ts +355 -0
  120. package/src/codegen/generator/context.ts +156 -0
  121. package/src/codegen/generator/expressions.ts +431 -0
  122. package/src/codegen/generator/generator.ts +35 -0
  123. package/src/codegen/generator/module.ts +139 -0
  124. package/src/codegen/generator/state.ts +126 -0
  125. package/src/codegen/generator/statements.ts +474 -0
  126. package/src/codegen/generator/tables.ts +171 -0
  127. package/src/codegen/llvm.ts +4 -1305
  128. package/src/driver/compiler.ts +17 -5
  129. package/src/lexer/char.ts +116 -0
  130. package/src/lexer/scanner.ts +9 -109
  131. package/src/parser/context.ts +196 -0
  132. package/src/parser/declarations.ts +502 -0
  133. package/src/parser/expressions.ts +465 -0
  134. package/src/parser/helpers.ts +42 -0
  135. package/src/parser/literals.ts +207 -0
  136. package/src/parser/modules.ts +194 -0
  137. package/src/parser/operators.ts +181 -0
  138. package/src/parser/parser.ts +35 -2369
  139. package/src/parser/speculation.ts +9 -0
  140. package/src/parser/statements.ts +457 -0
  141. package/src/parser/types.ts +365 -0
  142. package/runtime/xt_runtime.c +0 -682
@@ -0,0 +1,365 @@
1
+ /**
2
+ * Type parsing: unions, intersections, operators, references, function/tuple
3
+ * types, type literals and mapped types.
4
+ */
5
+
6
+ import { DiagnosticCode } from "../diagnostics/diagnostic.js";
7
+ import { TokenKind } from "../lexer/token.js";
8
+ import { TypeOperator } from "../ast/operators.js";
9
+ import {
10
+ SyntaxKind,
11
+ type BooleanLiteral,
12
+ type FunctionTypeNode,
13
+ type Identifier,
14
+ type MappedTypeNode,
15
+ type NumericLiteral,
16
+ type QualifiedName,
17
+ type TupleTypeNode,
18
+ type TypeLiteralNode,
19
+ type TypeNode,
20
+ type TypeParameterDeclaration,
21
+ } from "../ast/nodes.js";
22
+ import type { Parser } from "./parser.js";
23
+
24
+ export interface TypeMethods {
25
+ parseTypeArguments(this: Parser): TypeNode[];
26
+ parseType(this: Parser): TypeNode;
27
+ parseUnionType(this: Parser): TypeNode;
28
+ parseIntersectionType(this: Parser): TypeNode;
29
+ parseTypeOperatorOrHigher(this: Parser): TypeNode;
30
+ parsePostfixType(this: Parser): TypeNode;
31
+ parsePrimaryType(this: Parser): TypeNode;
32
+ previousTypeEnd(this: Parser, typeArguments: readonly TypeNode[], fallback: number): number;
33
+ parseEntityName(this: Parser): Identifier | QualifiedName;
34
+ parseFunctionType(this: Parser, explicitStart?: number): FunctionTypeNode;
35
+ parseTupleType(this: Parser): TupleTypeNode;
36
+ parseTypeLiteral(this: Parser): TypeLiteralNode | MappedTypeNode;
37
+ }
38
+
39
+ export const typeMethods: TypeMethods = {
40
+ parseTypeArguments(this: Parser): TypeNode[] {
41
+ this.parseExpected(TokenKind.LessThan);
42
+ const types: TypeNode[] = [];
43
+ while (!this.at(TokenKind.GreaterThan) && !this.at(TokenKind.EndOfFile)) {
44
+ types.push(this.parseType());
45
+ if (this.at(TokenKind.Comma)) this.nextToken();
46
+ else break;
47
+ }
48
+ this.parseGreaterThan();
49
+ return types;
50
+ },
51
+
52
+ // -- types ----------------------------------------------------------------
53
+
54
+ parseType(this: Parser): TypeNode {
55
+ const start = this.token.start;
56
+ const checkType = this.parseUnionType();
57
+ if (this.at(TokenKind.ExtendsKeyword)) {
58
+ this.nextToken();
59
+ const extendsType = this.parseUnionType();
60
+ this.parseExpected(TokenKind.Question);
61
+ const trueType = this.parseType();
62
+ this.parseExpected(TokenKind.Colon);
63
+ const falseType = this.parseType();
64
+ return { kind: SyntaxKind.ConditionalType, checkType, extendsType, trueType, falseType, start, end: falseType.end };
65
+ }
66
+ return checkType;
67
+ },
68
+
69
+ parseUnionType(this: Parser): TypeNode {
70
+ const start = this.token.start;
71
+ const leading = this.at(TokenKind.Bar);
72
+ if (leading) this.nextToken();
73
+ const first = this.parseIntersectionType();
74
+ if (!this.at(TokenKind.Bar)) return first;
75
+ const types: TypeNode[] = [first];
76
+ while (this.at(TokenKind.Bar)) {
77
+ this.nextToken();
78
+ types.push(this.parseIntersectionType());
79
+ }
80
+ return { kind: SyntaxKind.UnionType, types, start, end: types[types.length - 1]!.end };
81
+ },
82
+
83
+ parseIntersectionType(this: Parser): TypeNode {
84
+ const start = this.token.start;
85
+ const leading = this.at(TokenKind.Ampersand);
86
+ if (leading) this.nextToken();
87
+ const first = this.parseTypeOperatorOrHigher();
88
+ if (!this.at(TokenKind.Ampersand)) return first;
89
+ const types: TypeNode[] = [first];
90
+ while (this.at(TokenKind.Ampersand)) {
91
+ this.nextToken();
92
+ types.push(this.parseTypeOperatorOrHigher());
93
+ }
94
+ return { kind: SyntaxKind.IntersectionType, types, start, end: types[types.length - 1]!.end };
95
+ },
96
+
97
+ parseTypeOperatorOrHigher(this: Parser): TypeNode {
98
+ const start = this.token.start;
99
+ if (this.at(TokenKind.KeyOfKeyword)) {
100
+ this.nextToken();
101
+ const type = this.parseTypeOperatorOrHigher();
102
+ return { kind: SyntaxKind.TypeOperator, operator: TypeOperator.KeyOf, type, start, end: type.end };
103
+ }
104
+ if (this.at(TokenKind.UniqueKeyword)) {
105
+ this.nextToken();
106
+ const type = this.parseTypeOperatorOrHigher();
107
+ return { kind: SyntaxKind.TypeOperator, operator: TypeOperator.Unique, type, start, end: type.end };
108
+ }
109
+ if (this.at(TokenKind.ReadonlyKeyword)) {
110
+ this.nextToken();
111
+ const type = this.parseTypeOperatorOrHigher();
112
+ return { kind: SyntaxKind.TypeOperator, operator: TypeOperator.Readonly, type, start, end: type.end };
113
+ }
114
+ if (this.at(TokenKind.InferKeyword)) {
115
+ this.nextToken();
116
+ const name = this.parseIdentifier();
117
+ let constraint: TypeNode | undefined;
118
+ if (this.at(TokenKind.ExtendsKeyword)) {
119
+ this.nextToken();
120
+ constraint = this.parseType();
121
+ }
122
+ const typeParameter: TypeParameterDeclaration = { kind: SyntaxKind.TypeParameterDeclaration, name, constraint, start: name.start, end: constraint?.end ?? name.end };
123
+ return { kind: SyntaxKind.InferType, typeParameter, start, end: typeParameter.end };
124
+ }
125
+ return this.parsePostfixType();
126
+ },
127
+
128
+ parsePostfixType(this: Parser): TypeNode {
129
+ const start = this.token.start;
130
+ let type = this.parsePrimaryType();
131
+ for (;;) {
132
+ if (this.at(TokenKind.OpenBracket)) {
133
+ this.nextToken();
134
+ if (this.at(TokenKind.CloseBracket)) {
135
+ const close = this.nextToken();
136
+ type = { kind: SyntaxKind.ArrayType, elementType: type, start, end: close.end };
137
+ } else {
138
+ const indexType = this.parseType();
139
+ const close = this.parseExpected(TokenKind.CloseBracket);
140
+ type = { kind: SyntaxKind.IndexedAccessType, objectType: type, indexType, start, end: close.end };
141
+ }
142
+ continue;
143
+ }
144
+ if (this.at(TokenKind.Question) && this.atAhead(1, TokenKind.Colon)) {
145
+ // Optional tuple member, handled inside tuples only.
146
+ }
147
+ return type;
148
+ }
149
+ },
150
+
151
+ parsePrimaryType(this: Parser): TypeNode {
152
+ const token = this.token;
153
+ const start = token.start;
154
+ switch (token.kind) {
155
+ case TokenKind.AnyKeyword:
156
+ this.nextToken();
157
+ return { kind: SyntaxKind.AnyKeywordType, start, end: token.end };
158
+ case TokenKind.UnknownKeyword:
159
+ this.nextToken();
160
+ return { kind: SyntaxKind.UnknownKeywordType, start, end: token.end };
161
+ case TokenKind.NumberKeyword:
162
+ this.nextToken();
163
+ return { kind: SyntaxKind.NumberKeywordType, start, end: token.end };
164
+ case TokenKind.BigIntKeyword:
165
+ this.nextToken();
166
+ return { kind: SyntaxKind.BigIntKeywordType, start, end: token.end };
167
+ case TokenKind.StringKeyword:
168
+ this.nextToken();
169
+ return { kind: SyntaxKind.StringKeywordType, start, end: token.end };
170
+ case TokenKind.BooleanKeyword:
171
+ this.nextToken();
172
+ return { kind: SyntaxKind.BooleanKeywordType, start, end: token.end };
173
+ case TokenKind.SymbolKeyword:
174
+ this.nextToken();
175
+ return { kind: SyntaxKind.SymbolKeywordType, start, end: token.end };
176
+ case TokenKind.VoidKeyword:
177
+ this.nextToken();
178
+ return { kind: SyntaxKind.VoidKeywordType, start, end: token.end };
179
+ case TokenKind.UndefinedKeyword:
180
+ this.nextToken();
181
+ return { kind: SyntaxKind.UndefinedKeywordType, start, end: token.end };
182
+ case TokenKind.NullKeyword:
183
+ this.nextToken();
184
+ return { kind: SyntaxKind.NullKeywordType, start, end: token.end };
185
+ case TokenKind.NeverKeyword:
186
+ this.nextToken();
187
+ return { kind: SyntaxKind.NeverKeywordType, start, end: token.end };
188
+ case TokenKind.ObjectKeyword:
189
+ this.nextToken();
190
+ return { kind: SyntaxKind.ObjectKeywordType, start, end: token.end };
191
+ case TokenKind.ThisKeyword:
192
+ this.nextToken();
193
+ return { kind: SyntaxKind.ThisKeywordType, start, end: token.end };
194
+ case TokenKind.TypeOfKeyword: {
195
+ this.nextToken();
196
+ const exprName = this.parseEntityName();
197
+ const typeArguments = this.at(TokenKind.LessThan) ? this.parseTypeArguments() : [];
198
+ return { kind: SyntaxKind.TypeQuery, exprName, typeArguments, start, end: this.token.start };
199
+ }
200
+ case TokenKind.OpenBrace:
201
+ return this.parseTypeLiteral();
202
+ case TokenKind.OpenBracket:
203
+ return this.parseTupleType();
204
+ case TokenKind.OpenParen: {
205
+ const closeIndex = this.findMatchingParen(0);
206
+ if (closeIndex >= 0 && this.lookAhead(closeIndex + 1).kind === TokenKind.EqualsGreaterThan) {
207
+ return this.parseFunctionType();
208
+ }
209
+ this.nextToken();
210
+ const type = this.parseType();
211
+ const close = this.parseExpected(TokenKind.CloseParen);
212
+ return { kind: SyntaxKind.ParenthesizedType, type, start, end: close.end };
213
+ }
214
+ case TokenKind.LessThan:
215
+ return this.parseFunctionType();
216
+ case TokenKind.NewKeyword: {
217
+ this.nextToken();
218
+ return this.parseFunctionType(start);
219
+ }
220
+ case TokenKind.StringLiteral: {
221
+ this.nextToken();
222
+ const literal = this.stringLiteralFromToken(token);
223
+ return { kind: SyntaxKind.LiteralType, literal, start, end: token.end };
224
+ }
225
+ case TokenKind.NumericLiteral: {
226
+ this.nextToken();
227
+ const literal: NumericLiteral = { kind: SyntaxKind.NumericLiteral, text: token.text, value: Number(token.value ?? 0), start, end: token.end };
228
+ return { kind: SyntaxKind.LiteralType, literal, start, end: token.end };
229
+ }
230
+ case TokenKind.TrueKeyword: {
231
+ this.nextToken();
232
+ const literal: BooleanLiteral = { kind: SyntaxKind.TrueKeyword, value: true, start, end: token.end };
233
+ return { kind: SyntaxKind.LiteralType, literal, start, end: token.end };
234
+ }
235
+ case TokenKind.FalseKeyword: {
236
+ this.nextToken();
237
+ const literal: BooleanLiteral = { kind: SyntaxKind.FalseKeyword, value: false, start, end: token.end };
238
+ return { kind: SyntaxKind.LiteralType, literal, start, end: token.end };
239
+ }
240
+ case TokenKind.Minus: {
241
+ this.nextToken();
242
+ const num = this.parseExpected(TokenKind.NumericLiteral);
243
+ const literal: NumericLiteral = { kind: SyntaxKind.NumericLiteral, text: `-${num.text}`, value: -Number(num.value ?? 0), start, end: num.end };
244
+ return { kind: SyntaxKind.LiteralType, literal, start, end: num.end };
245
+ }
246
+ case TokenKind.ImportKeyword: {
247
+ // import("...").T - parse loosely and degrade to `any`.
248
+ this.nextToken();
249
+ if (this.at(TokenKind.OpenParen)) {
250
+ this.nextToken();
251
+ if (this.at(TokenKind.StringLiteral)) this.nextToken();
252
+ this.parseExpected(TokenKind.CloseParen);
253
+ }
254
+ while (this.at(TokenKind.Dot)) {
255
+ this.nextToken();
256
+ this.parseIdentifierName();
257
+ }
258
+ const typeArguments = this.at(TokenKind.LessThan) ? this.parseTypeArguments() : [];
259
+ return { kind: SyntaxKind.AnyKeywordType, start, end: this.token.start, typeArguments } as unknown as TypeNode;
260
+ }
261
+ default:
262
+ break;
263
+ }
264
+ if (this.isIdentifierLike(token)) {
265
+ const typeName = this.parseEntityName();
266
+ const typeArguments = this.at(TokenKind.LessThan) ? this.parseTypeArguments() : [];
267
+ return { kind: SyntaxKind.TypeReference, typeName, typeArguments, start, end: this.previousTypeEnd(typeArguments, typeName.end) };
268
+ }
269
+ this.error(DiagnosticCode.InvalidTypeSyntax, `Expected a type but found '${token.text || token.kind}'`);
270
+ if (token.kind !== TokenKind.EndOfFile) this.nextToken();
271
+ return { kind: SyntaxKind.AnyKeywordType, start, end: token.end };
272
+ },
273
+
274
+ previousTypeEnd(this: Parser, typeArguments: readonly TypeNode[], fallback: number): number {
275
+ return typeArguments[typeArguments.length - 1]?.end ?? fallback;
276
+ },
277
+
278
+ parseEntityName(this: Parser): Identifier | QualifiedName {
279
+ let left: Identifier | QualifiedName = this.parseIdentifierName();
280
+ while (this.at(TokenKind.Dot)) {
281
+ this.nextToken();
282
+ const right = this.parseIdentifierName();
283
+ left = { kind: SyntaxKind.QualifiedName, left, right, start: left.start, end: right.end };
284
+ }
285
+ return left;
286
+ },
287
+
288
+ parseFunctionType(this: Parser, explicitStart?: number): FunctionTypeNode {
289
+ const start = explicitStart ?? this.token.start;
290
+ const typeParameters = this.at(TokenKind.LessThan) ? this.parseTypeParameters() : [];
291
+ const parameters = this.parseParameters();
292
+ this.parseExpected(TokenKind.EqualsGreaterThan);
293
+ const returnType = this.parseReturnType();
294
+ return { kind: SyntaxKind.FunctionType, typeParameters, parameters, returnType, start, end: returnType.end };
295
+ },
296
+
297
+ parseTupleType(this: Parser): TupleTypeNode {
298
+ const open = this.parseExpected(TokenKind.OpenBracket);
299
+ const elements: TypeNode[] = [];
300
+ while (!this.at(TokenKind.CloseBracket) && !this.at(TokenKind.EndOfFile)) {
301
+ let element: TypeNode;
302
+ if (this.at(TokenKind.DotDotDot)) {
303
+ const restStart = this.nextToken().start;
304
+ const type = this.parseType();
305
+ element = { kind: SyntaxKind.RestType, type, start: restStart, end: type.end };
306
+ } else {
307
+ element = this.parseType();
308
+ }
309
+ if (this.at(TokenKind.Question)) {
310
+ const end = this.nextToken().end;
311
+ element = { kind: SyntaxKind.OptionalType, type: element, start: element.start, end };
312
+ }
313
+ elements.push(element);
314
+ if (this.at(TokenKind.Comma)) this.nextToken();
315
+ else break;
316
+ }
317
+ const close = this.parseExpected(TokenKind.CloseBracket);
318
+ return { kind: SyntaxKind.TupleType, elements, start: open.start, end: close.end };
319
+ },
320
+
321
+ parseTypeLiteral(this: Parser): TypeLiteralNode | MappedTypeNode {
322
+ const start = this.token.start;
323
+ // Detect mapped type: { [K in T]: U }
324
+ let cursor = 0;
325
+ if (this.atAhead(1, TokenKind.OpenBracket)) {
326
+ cursor = 1;
327
+ if (this.atAhead(2, TokenKind.Identifier)) {
328
+ let i = 3;
329
+ if (this.lookAhead(i).kind === TokenKind.InKeyword) {
330
+ const open = this.parseExpected(TokenKind.OpenBrace);
331
+ this.parseExpected(TokenKind.OpenBracket);
332
+ const name = this.parseIdentifier();
333
+ this.parseExpected(TokenKind.InKeyword);
334
+ let constraint = this.parseType();
335
+ this.parseExpected(TokenKind.CloseBracket);
336
+ let questionToken: boolean | "+" | "-" = false;
337
+ if (this.at(TokenKind.Question)) {
338
+ this.nextToken();
339
+ questionToken = true;
340
+ } else if (this.at(TokenKind.Plus)) {
341
+ this.nextToken();
342
+ this.nextToken();
343
+ questionToken = "+";
344
+ } else if (this.at(TokenKind.Minus)) {
345
+ this.nextToken();
346
+ this.nextToken();
347
+ questionToken = "-";
348
+ }
349
+ let type: TypeNode | undefined;
350
+ if (this.at(TokenKind.Colon)) {
351
+ this.nextToken();
352
+ type = this.parseType();
353
+ }
354
+ this.parseSemicolonOrComma();
355
+ const close = this.parseExpected(TokenKind.CloseBrace);
356
+ const typeParameter: TypeParameterDeclaration = { kind: SyntaxKind.TypeParameterDeclaration, name, constraint, start: name.start, end: constraint.end };
357
+ return { kind: SyntaxKind.MappedType, readonlyToken: false, typeParameter, questionToken, type, start: open.start, end: close.end };
358
+ }
359
+ }
360
+ }
361
+ void cursor;
362
+ const members = this.parseTypeMembers();
363
+ return { kind: SyntaxKind.TypeLiteral, members, start, end: this.token.start };
364
+ },
365
+ };