@prisma-next/psl-parser 0.12.0-dev.9 → 0.13.0-dev.1
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.
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/{parser-R7ldFfcr.mjs → parser-Cw_zV0M5.mjs} +176 -10
- package/dist/parser-Cw_zV0M5.mjs.map +1 -0
- package/dist/{parser-Bjdnhl7C.d.mts → parser-Dfi3Wfdq.d.mts} +1 -1
- package/dist/parser-Dfi3Wfdq.d.mts.map +1 -0
- package/dist/parser.d.mts +1 -1
- package/dist/parser.mjs +1 -1
- package/dist/syntax.d.mts +282 -0
- package/dist/syntax.d.mts.map +1 -0
- package/dist/syntax.mjs +708 -0
- package/dist/syntax.mjs.map +1 -0
- package/dist/tokenizer-DcYI0Xrq.d.mts +15 -0
- package/dist/tokenizer-DcYI0Xrq.d.mts.map +1 -0
- package/dist/tokenizer.d.mts +2 -15
- package/package.json +8 -7
- package/src/exports/syntax.ts +41 -0
- package/src/parser.ts +271 -13
- package/src/syntax/ast/attributes.ts +97 -0
- package/src/syntax/ast/declarations.ts +359 -0
- package/src/syntax/ast/expressions.ts +199 -0
- package/src/syntax/ast/identifier.ts +20 -0
- package/src/syntax/ast/type-annotation.ts +82 -0
- package/src/syntax/ast-helpers.ts +36 -0
- package/src/syntax/green-builder.ts +33 -0
- package/src/syntax/green.ts +29 -0
- package/src/syntax/red.ts +154 -0
- package/src/syntax/syntax-kind.ts +23 -0
- package/dist/parser-Bjdnhl7C.d.mts.map +0 -1
- package/dist/parser-R7ldFfcr.mjs.map +0 -1
- package/dist/tokenizer.d.mts.map +0 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { Token } from '../../tokenizer';
|
|
2
|
+
import type { AstNode } from '../ast-helpers';
|
|
3
|
+
import { filterChildren, findChildToken, findFirstChild } from '../ast-helpers';
|
|
4
|
+
import type { SyntaxNode } from '../red';
|
|
5
|
+
import { AttributeArgAst } from './expressions';
|
|
6
|
+
import { IdentifierAst } from './identifier';
|
|
7
|
+
|
|
8
|
+
export class AttributeArgListAst implements AstNode {
|
|
9
|
+
readonly syntax: SyntaxNode;
|
|
10
|
+
|
|
11
|
+
constructor(syntax: SyntaxNode) {
|
|
12
|
+
this.syntax = syntax;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
lparen(): Token | undefined {
|
|
16
|
+
return findChildToken(this.syntax, 'LParen');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
rparen(): Token | undefined {
|
|
20
|
+
return findChildToken(this.syntax, 'RParen');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
*args(): Iterable<AttributeArgAst> {
|
|
24
|
+
yield* filterChildren(this.syntax, AttributeArgAst.cast);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static cast(node: SyntaxNode): AttributeArgListAst | undefined {
|
|
28
|
+
return node.kind === 'AttributeArgList' ? new AttributeArgListAst(node) : undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class FieldAttributeAst implements AstNode {
|
|
33
|
+
readonly syntax: SyntaxNode;
|
|
34
|
+
|
|
35
|
+
constructor(syntax: SyntaxNode) {
|
|
36
|
+
this.syntax = syntax;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
at(): Token | undefined {
|
|
40
|
+
return findChildToken(this.syntax, 'At');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
name(): IdentifierAst | undefined {
|
|
44
|
+
if (this.dot()) {
|
|
45
|
+
let count = 0;
|
|
46
|
+
for (const child of this.syntax.childNodes()) {
|
|
47
|
+
if (child.kind === 'Identifier') {
|
|
48
|
+
count++;
|
|
49
|
+
if (count === 2) return new IdentifierAst(child);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
dot(): Token | undefined {
|
|
58
|
+
return findChildToken(this.syntax, 'Dot');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
namespaceName(): IdentifierAst | undefined {
|
|
62
|
+
if (!this.dot()) return undefined;
|
|
63
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
argList(): AttributeArgListAst | undefined {
|
|
67
|
+
return findFirstChild(this.syntax, AttributeArgListAst.cast);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static cast(node: SyntaxNode): FieldAttributeAst | undefined {
|
|
71
|
+
return node.kind === 'FieldAttribute' ? new FieldAttributeAst(node) : undefined;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export class ModelAttributeAst implements AstNode {
|
|
76
|
+
readonly syntax: SyntaxNode;
|
|
77
|
+
|
|
78
|
+
constructor(syntax: SyntaxNode) {
|
|
79
|
+
this.syntax = syntax;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
doubleAt(): Token | undefined {
|
|
83
|
+
return findChildToken(this.syntax, 'DoubleAt');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
name(): IdentifierAst | undefined {
|
|
87
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
argList(): AttributeArgListAst | undefined {
|
|
91
|
+
return findFirstChild(this.syntax, AttributeArgListAst.cast);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
static cast(node: SyntaxNode): ModelAttributeAst | undefined {
|
|
95
|
+
return node.kind === 'ModelAttribute' ? new ModelAttributeAst(node) : undefined;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import type { Token } from '../../tokenizer';
|
|
2
|
+
import type { AstNode } from '../ast-helpers';
|
|
3
|
+
import { filterChildren, findChildToken, findFirstChild } from '../ast-helpers';
|
|
4
|
+
import { SyntaxNode } from '../red';
|
|
5
|
+
import { FieldAttributeAst, ModelAttributeAst } from './attributes';
|
|
6
|
+
import type { ExpressionAst } from './expressions';
|
|
7
|
+
import { castExpression } from './expressions';
|
|
8
|
+
import { IdentifierAst } from './identifier';
|
|
9
|
+
import { TypeAnnotationAst } from './type-annotation';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* What may appear inside a `namespace` block: models, enums, composite types,
|
|
13
|
+
* and extension (block) declarations. Mirrors what `parsePslDocument` accepts
|
|
14
|
+
* in a namespace body. `types {}` blocks and nested `namespace` blocks are
|
|
15
|
+
* document-only, so they are not namespace members.
|
|
16
|
+
*/
|
|
17
|
+
export type NamespaceMemberAst =
|
|
18
|
+
| ModelDeclarationAst
|
|
19
|
+
| EnumDeclarationAst
|
|
20
|
+
| CompositeTypeDeclarationAst
|
|
21
|
+
| BlockDeclarationAst;
|
|
22
|
+
|
|
23
|
+
function castNamespaceMember(node: SyntaxNode): NamespaceMemberAst | undefined {
|
|
24
|
+
return (
|
|
25
|
+
ModelDeclarationAst.cast(node) ??
|
|
26
|
+
EnumDeclarationAst.cast(node) ??
|
|
27
|
+
CompositeTypeDeclarationAst.cast(node) ??
|
|
28
|
+
BlockDeclarationAst.cast(node)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class DocumentAst implements AstNode {
|
|
33
|
+
readonly syntax: SyntaxNode;
|
|
34
|
+
|
|
35
|
+
constructor(syntax: SyntaxNode) {
|
|
36
|
+
this.syntax = syntax;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
*declarations(): Iterable<NamespaceMemberAst | TypesBlockAst | NamespaceDeclarationAst> {
|
|
40
|
+
yield* filterChildren(
|
|
41
|
+
this.syntax,
|
|
42
|
+
(node) =>
|
|
43
|
+
castNamespaceMember(node) ?? TypesBlockAst.cast(node) ?? NamespaceDeclarationAst.cast(node),
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static cast(node: SyntaxNode): DocumentAst | undefined {
|
|
48
|
+
return node.kind === 'Document' ? new DocumentAst(node) : undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class ModelDeclarationAst implements AstNode {
|
|
53
|
+
readonly syntax: SyntaxNode;
|
|
54
|
+
|
|
55
|
+
constructor(syntax: SyntaxNode) {
|
|
56
|
+
this.syntax = syntax;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
keyword(): Token | undefined {
|
|
60
|
+
return findChildToken(this.syntax, 'Ident');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
name(): IdentifierAst | undefined {
|
|
64
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
lbrace(): Token | undefined {
|
|
68
|
+
return findChildToken(this.syntax, 'LBrace');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
rbrace(): Token | undefined {
|
|
72
|
+
return findChildToken(this.syntax, 'RBrace');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
*fields(): Iterable<FieldDeclarationAst> {
|
|
76
|
+
yield* filterChildren(this.syntax, FieldDeclarationAst.cast);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
*attributes(): Iterable<ModelAttributeAst> {
|
|
80
|
+
yield* filterChildren(this.syntax, ModelAttributeAst.cast);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static cast(node: SyntaxNode): ModelDeclarationAst | undefined {
|
|
84
|
+
return node.kind === 'ModelDeclaration' ? new ModelDeclarationAst(node) : undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export class EnumDeclarationAst implements AstNode {
|
|
89
|
+
readonly syntax: SyntaxNode;
|
|
90
|
+
|
|
91
|
+
constructor(syntax: SyntaxNode) {
|
|
92
|
+
this.syntax = syntax;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
keyword(): Token | undefined {
|
|
96
|
+
return findChildToken(this.syntax, 'Ident');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
name(): IdentifierAst | undefined {
|
|
100
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
lbrace(): Token | undefined {
|
|
104
|
+
return findChildToken(this.syntax, 'LBrace');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
rbrace(): Token | undefined {
|
|
108
|
+
return findChildToken(this.syntax, 'RBrace');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
*values(): Iterable<EnumValueDeclarationAst> {
|
|
112
|
+
yield* filterChildren(this.syntax, EnumValueDeclarationAst.cast);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
*attributes(): Iterable<ModelAttributeAst> {
|
|
116
|
+
yield* filterChildren(this.syntax, ModelAttributeAst.cast);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static cast(node: SyntaxNode): EnumDeclarationAst | undefined {
|
|
120
|
+
return node.kind === 'EnumDeclaration' ? new EnumDeclarationAst(node) : undefined;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export class CompositeTypeDeclarationAst implements AstNode {
|
|
125
|
+
readonly syntax: SyntaxNode;
|
|
126
|
+
|
|
127
|
+
constructor(syntax: SyntaxNode) {
|
|
128
|
+
this.syntax = syntax;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
keyword(): Token | undefined {
|
|
132
|
+
return findChildToken(this.syntax, 'Ident');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
name(): IdentifierAst | undefined {
|
|
136
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
lbrace(): Token | undefined {
|
|
140
|
+
return findChildToken(this.syntax, 'LBrace');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
rbrace(): Token | undefined {
|
|
144
|
+
return findChildToken(this.syntax, 'RBrace');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
*fields(): Iterable<FieldDeclarationAst> {
|
|
148
|
+
yield* filterChildren(this.syntax, FieldDeclarationAst.cast);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
*attributes(): Iterable<ModelAttributeAst> {
|
|
152
|
+
yield* filterChildren(this.syntax, ModelAttributeAst.cast);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
static cast(node: SyntaxNode): CompositeTypeDeclarationAst | undefined {
|
|
156
|
+
return node.kind === 'CompositeTypeDeclaration'
|
|
157
|
+
? new CompositeTypeDeclarationAst(node)
|
|
158
|
+
: undefined;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export class NamespaceDeclarationAst implements AstNode {
|
|
163
|
+
readonly syntax: SyntaxNode;
|
|
164
|
+
|
|
165
|
+
constructor(syntax: SyntaxNode) {
|
|
166
|
+
this.syntax = syntax;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
keyword(): Token | undefined {
|
|
170
|
+
return findChildToken(this.syntax, 'Ident');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
name(): IdentifierAst | undefined {
|
|
174
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
lbrace(): Token | undefined {
|
|
178
|
+
return findChildToken(this.syntax, 'LBrace');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
rbrace(): Token | undefined {
|
|
182
|
+
return findChildToken(this.syntax, 'RBrace');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
*declarations(): Iterable<NamespaceMemberAst> {
|
|
186
|
+
yield* filterChildren(this.syntax, castNamespaceMember);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
static cast(node: SyntaxNode): NamespaceDeclarationAst | undefined {
|
|
190
|
+
return node.kind === 'Namespace' ? new NamespaceDeclarationAst(node) : undefined;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export class TypesBlockAst implements AstNode {
|
|
195
|
+
readonly syntax: SyntaxNode;
|
|
196
|
+
|
|
197
|
+
constructor(syntax: SyntaxNode) {
|
|
198
|
+
this.syntax = syntax;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
keyword(): Token | undefined {
|
|
202
|
+
return findChildToken(this.syntax, 'Ident');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
lbrace(): Token | undefined {
|
|
206
|
+
return findChildToken(this.syntax, 'LBrace');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
rbrace(): Token | undefined {
|
|
210
|
+
return findChildToken(this.syntax, 'RBrace');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
*declarations(): Iterable<NamedTypeDeclarationAst> {
|
|
214
|
+
yield* filterChildren(this.syntax, NamedTypeDeclarationAst.cast);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
static cast(node: SyntaxNode): TypesBlockAst | undefined {
|
|
218
|
+
return node.kind === 'TypesBlock' ? new TypesBlockAst(node) : undefined;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export class BlockDeclarationAst implements AstNode {
|
|
223
|
+
readonly syntax: SyntaxNode;
|
|
224
|
+
|
|
225
|
+
constructor(syntax: SyntaxNode) {
|
|
226
|
+
this.syntax = syntax;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
keyword(): Token | undefined {
|
|
230
|
+
return findChildToken(this.syntax, 'Ident');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
name(): IdentifierAst | undefined {
|
|
234
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
lbrace(): Token | undefined {
|
|
238
|
+
return findChildToken(this.syntax, 'LBrace');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
rbrace(): Token | undefined {
|
|
242
|
+
return findChildToken(this.syntax, 'RBrace');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
*entries(): Iterable<KeyValuePairAst> {
|
|
246
|
+
yield* filterChildren(this.syntax, KeyValuePairAst.cast);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
static cast(node: SyntaxNode): BlockDeclarationAst | undefined {
|
|
250
|
+
return node.kind === 'BlockDeclaration' ? new BlockDeclarationAst(node) : undefined;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export class KeyValuePairAst implements AstNode {
|
|
255
|
+
readonly syntax: SyntaxNode;
|
|
256
|
+
|
|
257
|
+
constructor(syntax: SyntaxNode) {
|
|
258
|
+
this.syntax = syntax;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
key(): IdentifierAst | undefined {
|
|
262
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
equals(): Token | undefined {
|
|
266
|
+
return findChildToken(this.syntax, 'Equals');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
value(): ExpressionAst | undefined {
|
|
270
|
+
let pastEquals = false;
|
|
271
|
+
for (const child of this.syntax.children()) {
|
|
272
|
+
if (!(child instanceof SyntaxNode)) {
|
|
273
|
+
if (child.kind === 'Equals') pastEquals = true;
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (pastEquals) {
|
|
277
|
+
const expr = castExpression(child);
|
|
278
|
+
if (expr) return expr;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return undefined;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
static cast(node: SyntaxNode): KeyValuePairAst | undefined {
|
|
285
|
+
return node.kind === 'KeyValuePair' ? new KeyValuePairAst(node) : undefined;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export class FieldDeclarationAst implements AstNode {
|
|
290
|
+
readonly syntax: SyntaxNode;
|
|
291
|
+
|
|
292
|
+
constructor(syntax: SyntaxNode) {
|
|
293
|
+
this.syntax = syntax;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
name(): IdentifierAst | undefined {
|
|
297
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
typeAnnotation(): TypeAnnotationAst | undefined {
|
|
301
|
+
return findFirstChild(this.syntax, TypeAnnotationAst.cast);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
*attributes(): Iterable<FieldAttributeAst> {
|
|
305
|
+
yield* filterChildren(this.syntax, FieldAttributeAst.cast);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
static cast(node: SyntaxNode): FieldDeclarationAst | undefined {
|
|
309
|
+
return node.kind === 'FieldDeclaration' ? new FieldDeclarationAst(node) : undefined;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export class EnumValueDeclarationAst implements AstNode {
|
|
314
|
+
readonly syntax: SyntaxNode;
|
|
315
|
+
|
|
316
|
+
constructor(syntax: SyntaxNode) {
|
|
317
|
+
this.syntax = syntax;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
name(): IdentifierAst | undefined {
|
|
321
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
*attributes(): Iterable<FieldAttributeAst> {
|
|
325
|
+
yield* filterChildren(this.syntax, FieldAttributeAst.cast);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
static cast(node: SyntaxNode): EnumValueDeclarationAst | undefined {
|
|
329
|
+
return node.kind === 'EnumValueDeclaration' ? new EnumValueDeclarationAst(node) : undefined;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export class NamedTypeDeclarationAst implements AstNode {
|
|
334
|
+
readonly syntax: SyntaxNode;
|
|
335
|
+
|
|
336
|
+
constructor(syntax: SyntaxNode) {
|
|
337
|
+
this.syntax = syntax;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
name(): IdentifierAst | undefined {
|
|
341
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
equals(): Token | undefined {
|
|
345
|
+
return findChildToken(this.syntax, 'Equals');
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
typeAnnotation(): TypeAnnotationAst | undefined {
|
|
349
|
+
return findFirstChild(this.syntax, TypeAnnotationAst.cast);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
*attributes(): Iterable<FieldAttributeAst> {
|
|
353
|
+
yield* filterChildren(this.syntax, FieldAttributeAst.cast);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
static cast(node: SyntaxNode): NamedTypeDeclarationAst | undefined {
|
|
357
|
+
return node.kind === 'NamedTypeDeclaration' ? new NamedTypeDeclarationAst(node) : undefined;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import type { Token } from '../../tokenizer';
|
|
2
|
+
import type { AstNode } from '../ast-helpers';
|
|
3
|
+
import { filterChildren, findChildToken, findFirstChild } from '../ast-helpers';
|
|
4
|
+
import { SyntaxNode } from '../red';
|
|
5
|
+
import { IdentifierAst } from './identifier';
|
|
6
|
+
|
|
7
|
+
export class FunctionCallAst implements AstNode {
|
|
8
|
+
readonly syntax: SyntaxNode;
|
|
9
|
+
|
|
10
|
+
constructor(syntax: SyntaxNode) {
|
|
11
|
+
this.syntax = syntax;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
name(): IdentifierAst | undefined {
|
|
15
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
lparen(): Token | undefined {
|
|
19
|
+
return findChildToken(this.syntax, 'LParen');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
rparen(): Token | undefined {
|
|
23
|
+
return findChildToken(this.syntax, 'RParen');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
*args(): Iterable<AttributeArgAst> {
|
|
27
|
+
yield* filterChildren(this.syntax, AttributeArgAst.cast);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static cast(node: SyntaxNode): FunctionCallAst | undefined {
|
|
31
|
+
return node.kind === 'FunctionCall' ? new FunctionCallAst(node) : undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class ArrayLiteralAst implements AstNode {
|
|
36
|
+
readonly syntax: SyntaxNode;
|
|
37
|
+
|
|
38
|
+
constructor(syntax: SyntaxNode) {
|
|
39
|
+
this.syntax = syntax;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
lbracket(): Token | undefined {
|
|
43
|
+
return findChildToken(this.syntax, 'LBracket');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
rbracket(): Token | undefined {
|
|
47
|
+
return findChildToken(this.syntax, 'RBracket');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
*elements(): Iterable<ExpressionAst> {
|
|
51
|
+
yield* filterChildren(this.syntax, castExpression);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static cast(node: SyntaxNode): ArrayLiteralAst | undefined {
|
|
55
|
+
return node.kind === 'ArrayLiteral' ? new ArrayLiteralAst(node) : undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export class StringLiteralExprAst implements AstNode {
|
|
60
|
+
readonly syntax: SyntaxNode;
|
|
61
|
+
|
|
62
|
+
constructor(syntax: SyntaxNode) {
|
|
63
|
+
this.syntax = syntax;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
token(): Token | undefined {
|
|
67
|
+
return findChildToken(this.syntax, 'StringLiteral');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
value(): string | undefined {
|
|
71
|
+
const tok = this.token();
|
|
72
|
+
if (!tok) return undefined;
|
|
73
|
+
const raw = tok.text.slice(1, -1);
|
|
74
|
+
return raw.replace(/\\(.)/g, (_match, char: string) => {
|
|
75
|
+
switch (char) {
|
|
76
|
+
case 'n':
|
|
77
|
+
return '\n';
|
|
78
|
+
case 'r':
|
|
79
|
+
return '\r';
|
|
80
|
+
case 't':
|
|
81
|
+
return '\t';
|
|
82
|
+
case '"':
|
|
83
|
+
return '"';
|
|
84
|
+
case '\\':
|
|
85
|
+
return '\\';
|
|
86
|
+
default:
|
|
87
|
+
return `\\${char}`;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static cast(node: SyntaxNode): StringLiteralExprAst | undefined {
|
|
93
|
+
return node.kind === 'StringLiteralExpr' ? new StringLiteralExprAst(node) : undefined;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export class NumberLiteralExprAst implements AstNode {
|
|
98
|
+
readonly syntax: SyntaxNode;
|
|
99
|
+
|
|
100
|
+
constructor(syntax: SyntaxNode) {
|
|
101
|
+
this.syntax = syntax;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
token(): Token | undefined {
|
|
105
|
+
return findChildToken(this.syntax, 'NumberLiteral');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
value(): number | undefined {
|
|
109
|
+
const tok = this.token();
|
|
110
|
+
if (!tok) return undefined;
|
|
111
|
+
return Number(tok.text);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static cast(node: SyntaxNode): NumberLiteralExprAst | undefined {
|
|
115
|
+
return node.kind === 'NumberLiteralExpr' ? new NumberLiteralExprAst(node) : undefined;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export class BooleanLiteralExprAst implements AstNode {
|
|
120
|
+
readonly syntax: SyntaxNode;
|
|
121
|
+
|
|
122
|
+
constructor(syntax: SyntaxNode) {
|
|
123
|
+
this.syntax = syntax;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
token(): Token | undefined {
|
|
127
|
+
return findChildToken(this.syntax, 'Ident');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
value(): boolean | undefined {
|
|
131
|
+
const tok = this.token();
|
|
132
|
+
if (!tok) return undefined;
|
|
133
|
+
if (tok.text === 'true') return true;
|
|
134
|
+
if (tok.text === 'false') return false;
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static cast(node: SyntaxNode): BooleanLiteralExprAst | undefined {
|
|
139
|
+
return node.kind === 'BooleanLiteralExpr' ? new BooleanLiteralExprAst(node) : undefined;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export type ExpressionAst =
|
|
144
|
+
| FunctionCallAst
|
|
145
|
+
| ArrayLiteralAst
|
|
146
|
+
| StringLiteralExprAst
|
|
147
|
+
| NumberLiteralExprAst
|
|
148
|
+
| BooleanLiteralExprAst
|
|
149
|
+
| IdentifierAst;
|
|
150
|
+
|
|
151
|
+
export function castExpression(node: SyntaxNode): ExpressionAst | undefined {
|
|
152
|
+
return (
|
|
153
|
+
FunctionCallAst.cast(node) ??
|
|
154
|
+
ArrayLiteralAst.cast(node) ??
|
|
155
|
+
StringLiteralExprAst.cast(node) ??
|
|
156
|
+
NumberLiteralExprAst.cast(node) ??
|
|
157
|
+
BooleanLiteralExprAst.cast(node) ??
|
|
158
|
+
IdentifierAst.cast(node)
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export class AttributeArgAst implements AstNode {
|
|
163
|
+
readonly syntax: SyntaxNode;
|
|
164
|
+
|
|
165
|
+
constructor(syntax: SyntaxNode) {
|
|
166
|
+
this.syntax = syntax;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
name(): IdentifierAst | undefined {
|
|
170
|
+
if (!this.colon()) return undefined;
|
|
171
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
colon(): Token | undefined {
|
|
175
|
+
return findChildToken(this.syntax, 'Colon');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
value(): ExpressionAst | undefined {
|
|
179
|
+
if (this.colon()) {
|
|
180
|
+
let pastColon = false;
|
|
181
|
+
for (const child of this.syntax.children()) {
|
|
182
|
+
if (!(child instanceof SyntaxNode)) {
|
|
183
|
+
if (child.kind === 'Colon') pastColon = true;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (pastColon) {
|
|
187
|
+
const expr = castExpression(child);
|
|
188
|
+
if (expr) return expr;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
return findFirstChild(this.syntax, castExpression);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
static cast(node: SyntaxNode): AttributeArgAst | undefined {
|
|
197
|
+
return node.kind === 'AttributeArg' ? new AttributeArgAst(node) : undefined;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Token } from '../../tokenizer';
|
|
2
|
+
import type { AstNode } from '../ast-helpers';
|
|
3
|
+
import { findChildToken } from '../ast-helpers';
|
|
4
|
+
import type { SyntaxNode } from '../red';
|
|
5
|
+
|
|
6
|
+
export class IdentifierAst implements AstNode {
|
|
7
|
+
readonly syntax: SyntaxNode;
|
|
8
|
+
|
|
9
|
+
constructor(syntax: SyntaxNode) {
|
|
10
|
+
this.syntax = syntax;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
token(): Token | undefined {
|
|
14
|
+
return findChildToken(this.syntax, 'Ident');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static cast(node: SyntaxNode): IdentifierAst | undefined {
|
|
18
|
+
return node.kind === 'Identifier' ? new IdentifierAst(node) : undefined;
|
|
19
|
+
}
|
|
20
|
+
}
|