-
Notifications
You must be signed in to change notification settings - Fork 60
Expand file tree
/
Copy pathreflection.ts
More file actions
325 lines (311 loc) · 16.2 KB
/
reflection.ts
File metadata and controls
325 lines (311 loc) · 16.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
import type { Body, AssignmentStatement, Block, ExpressionStatement, CommentStatement, ExitForStatement, ExitWhileStatement, FunctionStatement, IfStatement, IncrementStatement, PrintStatement, GotoStatement, LabelStatement, ReturnStatement, EndStatement, StopStatement, ForStatement, ForEachStatement, WhileStatement, DottedSetStatement, IndexedSetStatement, LibraryStatement, NamespaceStatement, ImportStatement, ClassFieldStatement, ClassMethodStatement, ClassStatement, InterfaceFieldStatement, InterfaceMethodStatement, InterfaceStatement, EnumStatement, EnumMemberStatement, TryCatchStatement, CatchStatement, MethodStatement, FieldStatement, ConstStatement, ContinueStatement } from '../parser/Statement';
import type { LiteralExpression, BinaryExpression, CallExpression, FunctionExpression, NamespacedVariableNameExpression, DottedGetExpression, XmlAttributeGetExpression, IndexedGetExpression, GroupingExpression, EscapedCharCodeLiteralExpression, ArrayLiteralExpression, AALiteralExpression, UnaryExpression, VariableExpression, SourceLiteralExpression, NewExpression, CallfuncExpression, TemplateStringQuasiExpression, TemplateStringExpression, TaggedTemplateStringExpression, AnnotationExpression, FunctionParameterExpression, AAMemberExpression } from '../parser/Expression';
import type { BrsFile } from '../files/BrsFile';
import type { XmlFile } from '../files/XmlFile';
import type { BscFile, File, TypedefProvider } from '../interfaces';
import { InvalidType } from '../types/InvalidType';
import { VoidType } from '../types/VoidType';
import { InternalWalkMode } from './visitors';
import { FunctionType } from '../types/FunctionType';
import { StringType } from '../types/StringType';
import { BooleanType } from '../types/BooleanType';
import { IntegerType } from '../types/IntegerType';
import { LongIntegerType } from '../types/LongIntegerType';
import { FloatType } from '../types/FloatType';
import { DoubleType } from '../types/DoubleType';
import { CustomType } from '../types/CustomType';
import type { Scope } from '../Scope';
import type { XmlScope } from '../XmlScope';
import { DynamicType } from '../types/DynamicType';
import type { InterfaceType } from '../types/InterfaceType';
import type { ObjectType } from '../types/ObjectType';
import type { AstNode, Expression, Statement } from '../parser/AstNode';
// File reflection
export function isBrsFile(file: (BscFile | File)): file is BrsFile {
return file?.constructor.name === 'BrsFile';
}
export function isXmlFile(file: (BscFile)): file is XmlFile {
return file?.constructor.name === 'XmlFile';
}
export function isXmlScope(scope: (Scope)): scope is XmlScope {
return scope?.constructor.name === 'XmlScope';
}
// Statements reflection
/**
* Determine if the variable is a descendent of the Statement base class.
* Due to performance restrictions, this expects all statements to
* directly extend Statement or FunctionStatement,
* so it only checks the immediate parent's class name.
*/
export function isStatement(element: AstNode | undefined): element is Statement {
// eslint-disable-next-line no-bitwise
return !!(element && element.visitMode & InternalWalkMode.visitStatements);
}
export function isBody(element: AstNode | undefined): element is Body {
return element?.constructor?.name === 'Body';
}
export function isAssignmentStatement(element: AstNode | undefined): element is AssignmentStatement {
return element?.constructor?.name === 'AssignmentStatement';
}
export function isBlock(element: AstNode | undefined): element is Block {
return element?.constructor?.name === 'Block';
}
export function isExpressionStatement(element: AstNode | undefined): element is ExpressionStatement {
return element?.constructor?.name === 'ExpressionStatement';
}
export function isCommentStatement(element: AstNode | undefined): element is CommentStatement {
return element?.constructor?.name === 'CommentStatement';
}
export function isExitForStatement(element: AstNode | undefined): element is ExitForStatement {
return element?.constructor?.name === 'ExitForStatement';
}
export function isExitWhileStatement(element: AstNode | undefined): element is ExitWhileStatement {
return element?.constructor?.name === 'ExitWhileStatement';
}
export function isFunctionStatement(element: AstNode | undefined): element is FunctionStatement {
return element?.constructor?.name === 'FunctionStatement';
}
export function isIfStatement(element: AstNode | undefined): element is IfStatement {
return element?.constructor?.name === 'IfStatement';
}
export function isIncrementStatement(element: AstNode | undefined): element is IncrementStatement {
return element?.constructor?.name === 'IncrementStatement';
}
export function isPrintStatement(element: AstNode | undefined): element is PrintStatement {
return element?.constructor?.name === 'PrintStatement';
}
export function isGotoStatement(element: AstNode | undefined): element is GotoStatement {
return element?.constructor?.name === 'GotoStatement';
}
export function isLabelStatement(element: AstNode | undefined): element is LabelStatement {
return element?.constructor?.name === 'LabelStatement';
}
export function isReturnStatement(element: AstNode | undefined): element is ReturnStatement {
return element?.constructor?.name === 'ReturnStatement';
}
export function isEndStatement(element: AstNode | undefined): element is EndStatement {
return element?.constructor?.name === 'EndStatement';
}
export function isStopStatement(element: AstNode | undefined): element is StopStatement {
return element?.constructor?.name === 'StopStatement';
}
export function isForStatement(element: AstNode | undefined): element is ForStatement {
return element?.constructor?.name === 'ForStatement';
}
export function isForEachStatement(element: AstNode | undefined): element is ForEachStatement {
return element?.constructor?.name === 'ForEachStatement';
}
export function isWhileStatement(element: AstNode | undefined): element is WhileStatement {
return element?.constructor?.name === 'WhileStatement';
}
export function isDottedSetStatement(element: AstNode | undefined): element is DottedSetStatement {
return element?.constructor?.name === 'DottedSetStatement';
}
export function isIndexedSetStatement(element: AstNode | undefined): element is IndexedSetStatement {
return element?.constructor?.name === 'IndexedSetStatement';
}
export function isLibraryStatement(element: AstNode | undefined): element is LibraryStatement {
return element?.constructor?.name === 'LibraryStatement';
}
export function isNamespaceStatement(element: AstNode | undefined): element is NamespaceStatement {
return element?.constructor?.name === 'NamespaceStatement';
}
export function isClassStatement(element: AstNode | undefined): element is ClassStatement {
return element?.constructor?.name === 'ClassStatement';
}
export function isImportStatement(element: AstNode | undefined): element is ImportStatement {
return element?.constructor?.name === 'ImportStatement';
}
export function isMethodStatement(element: AstNode | undefined): element is MethodStatement {
const name = element?.constructor.name;
return name === 'MethodStatement' || name === 'ClassMethodStatement';
}
/**
* @deprecated use `isMethodStatement`
*/
export function isClassMethodStatement(element: AstNode | undefined): element is ClassMethodStatement {
return isMethodStatement(element);
}
export function isFieldStatement(element: AstNode | undefined): element is FieldStatement {
const name = element?.constructor.name;
return name === 'FieldStatement' || name === 'ClassFieldStatement';
}
/**
* @deprecated use `isFieldStatement`
*/
export function isClassFieldStatement(element: AstNode | undefined): element is ClassFieldStatement {
return isFieldStatement(element);
}
export function isInterfaceStatement(element: AstNode | undefined): element is InterfaceStatement {
return element?.constructor.name === 'InterfaceStatement';
}
export function isInterfaceMethodStatement(element: AstNode | undefined): element is InterfaceMethodStatement {
return element?.constructor.name === 'InterfaceMethodStatement';
}
export function isInterfaceFieldStatement(element: AstNode | undefined): element is InterfaceFieldStatement {
return element?.constructor.name === 'InterfaceFieldStatement';
}
export function isEnumStatement(element: AstNode | undefined): element is EnumStatement {
return element?.constructor.name === 'EnumStatement';
}
export function isEnumMemberStatement(element: AstNode | undefined): element is EnumMemberStatement {
return element?.constructor.name === 'EnumMemberStatement';
}
export function isConstStatement(element: AstNode | undefined): element is ConstStatement {
return element?.constructor.name === 'ConstStatement';
}
export function isContinueStatement(element: AstNode | undefined): element is ContinueStatement {
return element?.constructor.name === 'ContinueStatement';
}
export function isTryCatchStatement(element: AstNode | undefined): element is TryCatchStatement {
return element?.constructor.name === 'TryCatchStatement';
}
export function isCatchStatement(element: AstNode | undefined): element is CatchStatement {
return element?.constructor.name === 'CatchStatement';
}
// Expressions reflection
/**
* Determine if the variable is a descendent of the Expression base class.
* Due to performance restrictions, this expects all statements to directly extend Expression,
* so it only checks the immediate parent's class name. For example:
* this will work for StringLiteralExpression -> Expression,
* but will not work CustomStringLiteralExpression -> StringLiteralExpression -> Expression
*/
export function isExpression(element: AstNode | undefined): element is Expression {
// eslint-disable-next-line no-bitwise
return !!(element && element.visitMode & InternalWalkMode.visitExpressions);
}
export function isBinaryExpression(element: AstNode | undefined): element is BinaryExpression {
return element?.constructor.name === 'BinaryExpression';
}
export function isCallExpression(element: AstNode | undefined): element is CallExpression {
return element?.constructor.name === 'CallExpression';
}
export function isFunctionExpression(element: AstNode | undefined): element is FunctionExpression {
return element?.constructor.name === 'FunctionExpression';
}
export function isNamespacedVariableNameExpression(element: AstNode | undefined): element is NamespacedVariableNameExpression {
return element?.constructor.name === 'NamespacedVariableNameExpression';
}
export function isDottedGetExpression(element: AstNode | undefined): element is DottedGetExpression {
return element?.constructor.name === 'DottedGetExpression';
}
export function isXmlAttributeGetExpression(element: AstNode | undefined): element is XmlAttributeGetExpression {
return element?.constructor.name === 'XmlAttributeGetExpression';
}
export function isIndexedGetExpression(element: AstNode | undefined): element is IndexedGetExpression {
return element?.constructor.name === 'IndexedGetExpression';
}
export function isGroupingExpression(element: AstNode | undefined): element is GroupingExpression {
return element?.constructor.name === 'GroupingExpression';
}
export function isLiteralExpression(element: AstNode | undefined): element is LiteralExpression {
return element?.constructor.name === 'LiteralExpression';
}
export function isEscapedCharCodeLiteralExpression(element: AstNode | undefined): element is EscapedCharCodeLiteralExpression {
return element?.constructor.name === 'EscapedCharCodeLiteralExpression';
}
export function isArrayLiteralExpression(element: AstNode | undefined): element is ArrayLiteralExpression {
return element?.constructor.name === 'ArrayLiteralExpression';
}
export function isAALiteralExpression(element: AstNode | undefined): element is AALiteralExpression {
return element?.constructor.name === 'AALiteralExpression';
}
export function isAAMemberExpression(element: AstNode | undefined): element is AAMemberExpression {
return element?.constructor.name === 'AAMemberExpression';
}
export function isUnaryExpression(element: AstNode | undefined): element is UnaryExpression {
return element?.constructor.name === 'UnaryExpression';
}
export function isVariableExpression(element: AstNode | undefined): element is VariableExpression {
return element?.constructor.name === 'VariableExpression';
}
export function isSourceLiteralExpression(element: AstNode | undefined): element is SourceLiteralExpression {
return element?.constructor.name === 'SourceLiteralExpression';
}
export function isNewExpression(element: AstNode | undefined): element is NewExpression {
return element?.constructor.name === 'NewExpression';
}
export function isCallfuncExpression(element: AstNode | undefined): element is CallfuncExpression {
return element?.constructor.name === 'CallfuncExpression';
}
export function isTemplateStringQuasiExpression(element: AstNode | undefined): element is TemplateStringQuasiExpression {
return element?.constructor.name === 'TemplateStringQuasiExpression';
}
export function isTemplateStringExpression(element: AstNode | undefined): element is TemplateStringExpression {
return element?.constructor.name === 'TemplateStringExpression';
}
export function isTaggedTemplateStringExpression(element: AstNode | undefined): element is TaggedTemplateStringExpression {
return element?.constructor.name === 'TaggedTemplateStringExpression';
}
export function isFunctionParameterExpression(element: AstNode | undefined): element is FunctionParameterExpression {
return element?.constructor.name === 'FunctionParameterExpression';
}
export function isAnnotationExpression(element: AstNode | undefined): element is AnnotationExpression {
return element?.constructor.name === 'AnnotationExpression';
}
export function isTypedefProvider(element: any): element is TypedefProvider {
return 'getTypedef' in element;
}
// BscType reflection
export function isStringType(value: any): value is StringType {
return value?.constructor.name === StringType.name;
}
export function isFunctionType(e: any): e is FunctionType {
return e?.constructor.name === FunctionType.name;
}
export function isBooleanType(e: any): e is BooleanType {
return e?.constructor.name === BooleanType.name;
}
export function isIntegerType(e: any): e is IntegerType {
return e?.constructor.name === IntegerType.name;
}
export function isLongIntegerType(e: any): e is LongIntegerType {
return e?.constructor.name === LongIntegerType.name;
}
export function isFloatType(e: any): e is FloatType {
return e?.constructor.name === FloatType.name;
}
export function isDoubleType(e: any): e is DoubleType {
return e?.constructor.name === DoubleType.name;
}
export function isInvalidType(e: any): e is InvalidType {
return e?.constructor.name === InvalidType.name;
}
export function isVoidType(e: any): e is VoidType {
return e?.constructor.name === VoidType.name;
}
export function isCustomType(e: any): e is CustomType {
return e?.constructor.name === CustomType.name;
}
export function isDynamicType(e: any): e is DynamicType {
return e?.constructor.name === DynamicType.name;
}
export function isInterfaceType(e: any): e is InterfaceType {
return e?.constructor.name === 'InterfaceType';
}
export function isObjectType(e: any): e is ObjectType {
return e?.constructor.name === 'ObjectType';
}
const numberConstructorNames = [
IntegerType.name,
LongIntegerType.name,
FloatType.name,
DoubleType.name
];
export function isNumberType(e: any): e is IntegerType | LongIntegerType | FloatType | DoubleType {
return numberConstructorNames.includes(e?.constructor.name);
}
// Literal reflection
export function isLiteralInvalid(e: any): e is LiteralExpression & { type: InvalidType } {
return isLiteralExpression(e) && isInvalidType(e.type);
}
export function isLiteralBoolean(e: any): e is LiteralExpression & { type: BooleanType } {
return isLiteralExpression(e) && isBooleanType(e.type);
}
export function isLiteralString(e: any): e is LiteralExpression & { type: StringType } {
return isLiteralExpression(e) && isStringType(e.type);
}
export function isLiteralNumber(e: any): e is LiteralExpression & { type: IntegerType | LongIntegerType | FloatType | DoubleType } {
return isLiteralExpression(e) && isNumberType(e.type);
}