• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rokucommunity / brighterscript / #12930

13 Aug 2024 05:02PM UTC coverage: 86.193% (-1.7%) from 87.933%
#12930

push

web-flow
Merge 58ad447a2 into 0e968f1c3

10630 of 13125 branches covered (80.99%)

Branch coverage included in aggregate %.

6675 of 7284 new or added lines in 99 files covered. (91.64%)

84 existing lines in 18 files now uncovered.

12312 of 13492 relevant lines covered (91.25%)

26865.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.32
/src/parser/AstNode.ts
1
import type { WalkVisitor, WalkOptions } from '../astUtils/visitors';
2
import { WalkMode } from '../astUtils/visitors';
1✔
3
import type { Location, Position } from 'vscode-languageserver';
4
import { CancellationTokenSource } from 'vscode-languageserver';
1✔
5
import { InternalWalkMode } from '../astUtils/visitors';
1✔
6
import type { SymbolTable } from '../SymbolTable';
7
import type { BrsTranspileState } from './BrsTranspileState';
8
import type { GetTypeOptions, TranspileResult } from '../interfaces';
9
import type { AnnotationExpression } from './Expression';
10
import util from '../util';
1✔
11
import { DynamicType } from '../types/DynamicType';
1✔
12
import type { BscType } from '../types/BscType';
13
import type { Token } from '../lexer/Token';
14

15
/**
16
 * A BrightScript AST node
17
 */
18
export abstract class AstNode {
1✔
19
    public abstract kind: AstNodeKind;
20
    /**
21
     *  The starting and ending location of the node.
22
     */
23
    public abstract location?: Location | undefined;
24

25
    public abstract transpile(state: BrsTranspileState): TranspileResult;
26

27
    /**
28
     * Optional property, set at the top level with a map of conditional compile consts and their values
29
     */
30
    public bsConsts?: Map<string, boolean>;
31

32
    /**
33
     * When being considered by the walk visitor, this describes what type of element the current class is.
34
     */
35
    public visitMode = InternalWalkMode.visitStatements;
60,732✔
36

37
    public abstract walk(visitor: WalkVisitor, options: WalkOptions);
38

39
    /**
40
     * The parent node for this statement. This is set dynamically during `onFileValidate`, and should not be set directly.
41
     */
42
    public parent?: AstNode;
43

44
    /**
45
     * Certain expressions or statements can have a symbol table (such as blocks, functions, namespace bodies, etc).
46
     * If you're interested in getting the closest SymbolTable, use `getSymbolTable` instead.
47
     */
48
    public symbolTable?: SymbolTable;
49

50
    /**
51
     * Get the closest symbol table for this node
52
     */
53
    public getSymbolTable(): SymbolTable {
54
        let node: AstNode = this;
75,167✔
55
        while (node) {
75,167✔
56
            if (node.symbolTable) {
213,892✔
57
                return node.symbolTable;
75,167✔
58
            }
59
            node = node.parent!;
138,725✔
60
        }
61

62
        //justification: we are following a chain of nodes until we get to one with a SymbolTable,
63
        //and the top-level node will always have a SymbolTable. So we'll never hit this undefined,
64
        //but it is not so easy to convince the typechecker of this.
65
        return undefined as any;
×
66
    }
67

68
    /**
69
     * Walk upward and return the first node that results in `true` from the matcher.
70
     * @param matcher a function called for each node. If you return true, this function returns the specified node. If you return a node, that node is returned. all other return values continue the loop
71
     *                The function's second parameter is a cancellation token. If you'd like to short-circuit the walk, call `cancellationToken.cancel()`, then this function will return `undefined`
72
     */
73
    public findAncestor<TNode extends AstNode = AstNode>(matcher: (node: AstNode, cancellationToken: CancellationTokenSource) => boolean | AstNode | undefined | void): TNode | undefined {
74
        let node = this.parent;
46,453✔
75

76
        const cancel = new CancellationTokenSource();
46,453✔
77
        while (node) {
46,453✔
78
            let matcherValue = matcher(node, cancel);
177,264✔
79
            if (cancel.token.isCancellationRequested) {
177,264✔
80
                return;
1✔
81
            }
82
            if (matcherValue) {
177,263✔
83
                cancel.cancel();
8,979✔
84
                return (matcherValue === true ? node : matcherValue) as TNode;
8,979✔
85

86
            }
87
            node = node.parent;
168,284✔
88
        }
89
    }
90

91
    /**
92
     * Find the first child where the matcher evaluates to true.
93
     * @param matcher a function called for each node. If you return true, this function returns the specified node. If you return a node, that node is returned. all other return values continue the loop
94
     */
95
    public findChild<TNode extends AstNode = AstNode>(matcher: (node: AstNode, cancellationSource) => boolean | AstNode | undefined | void, options?: WalkOptions): TNode | undefined {
96
        const cancel = new CancellationTokenSource();
1,501✔
97
        let result: AstNode | undefined;
98
        this.walk((node) => {
1,501✔
99
            const matcherValue = matcher(node, cancel);
3,228✔
100
            if (matcherValue) {
3,228✔
101
                cancel.cancel();
1,314✔
102
                result = matcherValue === true ? node : matcherValue;
1,314✔
103
            }
104
        }, {
105
            walkMode: WalkMode.visitAllRecursive,
106
            ...options ?? {},
4,503✔
107
            cancel: cancel.token
108
        });
109
        return result as TNode;
1,501✔
110
    }
111

112
    /**
113
     * Find a list of all children first child where the matcher evaluates to true.
114
     * @param matcher a function called for each node. If you return true, the specified node is included in the results. If you return a node,
115
     * that node is returned. all other return values exclude that value and continue the loop
116
     */
117
    public findChildren<TNode extends AstNode = AstNode>(matcher: (node: AstNode, cancellationSource: CancellationTokenSource) => boolean | AstNode | undefined | void, options?: WalkOptions): Array<TNode> {
118
        const cancel = new CancellationTokenSource();
25✔
119
        let result: Array<AstNode> = [];
25✔
120
        this.walk((node) => {
25✔
121
            const matcherValue = matcher(node, cancel);
300✔
122
            if (matcherValue) {
300✔
123
                result.push(matcherValue === true ? node : matcherValue);
50!
124
            }
125
        }, {
126
            walkMode: WalkMode.visitAllRecursive,
127
            ...options ?? {},
75✔
128
            cancel: cancel.token
129
        });
130
        return result as TNode[];
25✔
131
    }
132

133
    /**
134
     * FInd the deepest child that includes the given position
135
     */
136
    public findChildAtPosition<TNodeType extends AstNode = AstNode>(position: Position, options?: WalkOptions): TNodeType | undefined {
137
        return this.findChild<TNodeType>((node) => {
1,456✔
138
            //if the current node includes this range, keep that node
139
            if (util.rangeContains(node?.location.range, position)) {
3,034!
140
                return node.findChildAtPosition(position, options) ?? node;
1,272✔
141
            }
142
        }, options);
143
    }
144

145
    /**
146
     * Get the BscType of this node.
147
     */
148
    public getType(options: GetTypeOptions): BscType {
149
        return DynamicType.instance;
498✔
150
    }
151

152
    /**
153
     * Links all child nodes to their parent AstNode, and the same with symbol tables. This performs a full AST walk, so you should use this sparingly
154
     */
155
    public link() {
156
        //the act of walking causes the nodes to be linked
157
        this.walk(() => { }, {
3,011✔
158
            // eslint-disable-next-line no-bitwise
159
            walkMode: WalkMode.visitAllRecursive | InternalWalkMode.visitFalseConditionalCompilationBlocks
160
        });
161
    }
162

163
    /**
164
     * Walk upward and return the root node
165
     */
166
    public getRoot() {
NEW
167
        let node = this as AstNode;
×
168

NEW
169
        while (node) {
×
NEW
170
            if (!node.parent) {
×
NEW
171
                return node;
×
172
            }
NEW
173
            node = node.parent;
×
174
        }
175
    }
176

177

178
    /**
179
     * Gets all the trivia (comments, whitespace) that is directly before the start of this node
180
     * Note: this includes all trivia that might start on the line of the previous node
181
     */
182
    public get leadingTrivia(): Token[] {
183
        return [];
5✔
184
    }
185

186
    /**
187
     * Gets any trivia that is directly before the end of the node
188
     * For example, this would return all trivia before a `end function` token of a FunctionExpression
189
     */
190
    public get endTrivia(): Token[] {
191
        return [];
35✔
192
    }
193

194
    public getBsConsts() {
195
        return this.bsConsts ?? this.parent?.getBsConsts();
73,225✔
196
    }
197
}
198

199
export abstract class Statement extends AstNode {
1✔
200
    /**
201
     * When being considered by the walk visitor, this describes what type of element the current class is.
202
     */
203
    public visitMode = InternalWalkMode.visitStatements;
27,515✔
204
    /**
205
     * Annotations for this statement
206
     */
207
    public annotations?: AnnotationExpression[] | undefined;
208
}
209

210

211
/** A BrightScript expression */
212
export abstract class Expression extends AstNode {
1✔
213
    /**
214
     * When being considered by the walk visitor, this describes what type of element the current class is.
215
     */
216
    public visitMode = InternalWalkMode.visitExpressions;
33,217✔
217
}
218

219
export enum AstNodeKind {
1✔
220
    Body = 'Body',
1✔
221
    BinaryExpression = 'BinaryExpression',
1✔
222
    CallExpression = 'CallExpression',
1✔
223
    FunctionExpression = 'FunctionExpression',
1✔
224
    FunctionParameterExpression = 'FunctionParameterExpression',
1✔
225
    NamespacedVariableNameExpression = 'NamespacedVariableNameExpression',
1✔
226
    DottedGetExpression = 'DottedGetExpression',
1✔
227
    XmlAttributeGetExpression = 'XmlAttributeGetExpression',
1✔
228
    IndexedGetExpression = 'IndexedGetExpression',
1✔
229
    GroupingExpression = 'GroupingExpression',
1✔
230
    LiteralExpression = 'LiteralExpression',
1✔
231
    EscapedCharCodeLiteralExpression = 'EscapedCharCodeLiteralExpression',
1✔
232
    ArrayLiteralExpression = 'ArrayLiteralExpression',
1✔
233
    AAMemberExpression = 'AAMemberExpression',
1✔
234
    AALiteralExpression = 'AALiteralExpression',
1✔
235
    UnaryExpression = 'UnaryExpression',
1✔
236
    VariableExpression = 'VariableExpression',
1✔
237
    SourceLiteralExpression = 'SourceLiteralExpression',
1✔
238
    NewExpression = 'NewExpression',
1✔
239
    CallfuncExpression = 'CallfuncExpression',
1✔
240
    TemplateStringQuasiExpression = 'TemplateStringQuasiExpression',
1✔
241
    TemplateStringExpression = 'TemplateStringExpression',
1✔
242
    TaggedTemplateStringExpression = 'TaggedTemplateStringExpression',
1✔
243
    AnnotationExpression = 'AnnotationExpression',
1✔
244
    TernaryExpression = 'TernaryExpression',
1✔
245
    NullCoalescingExpression = 'NullCoalescingExpression',
1✔
246
    RegexLiteralExpression = 'RegexLiteralExpression',
1✔
247
    EmptyStatement = 'EmptyStatement',
1✔
248
    AssignmentStatement = 'AssignmentStatement',
1✔
249
    ExpressionStatement = 'ExpressionStatement',
1✔
250
    ExitForStatement = 'ExitForStatement',
1✔
251
    ExitWhileStatement = 'ExitWhileStatement',
1✔
252
    FunctionStatement = 'FunctionStatement',
1✔
253
    IfStatement = 'IfStatement',
1✔
254
    IncrementStatement = 'IncrementStatement',
1✔
255
    PrintStatement = 'PrintStatement',
1✔
256
    DimStatement = 'DimStatement',
1✔
257
    GotoStatement = 'GotoStatement',
1✔
258
    LabelStatement = 'LabelStatement',
1✔
259
    ReturnStatement = 'ReturnStatement',
1✔
260
    EndStatement = 'EndStatement',
1✔
261
    StopStatement = 'StopStatement',
1✔
262
    ForStatement = 'ForStatement',
1✔
263
    ForEachStatement = 'ForEachStatement',
1✔
264
    WhileStatement = 'WhileStatement',
1✔
265
    DottedSetStatement = 'DottedSetStatement',
1✔
266
    IndexedSetStatement = 'IndexedSetStatement',
1✔
267
    LibraryStatement = 'LibraryStatement',
1✔
268
    NamespaceStatement = 'NamespaceStatement',
1✔
269
    ImportStatement = 'ImportStatement',
1✔
270
    InterfaceStatement = 'InterfaceStatement',
1✔
271
    InterfaceFieldStatement = 'InterfaceFieldStatement',
1✔
272
    InterfaceMethodStatement = 'InterfaceMethodStatement',
1✔
273
    ClassStatement = 'ClassStatement',
1✔
274
    MethodStatement = 'MethodStatement',
1✔
275
    ClassMethodStatement = 'ClassMethodStatement',
1✔
276
    FieldStatement = 'FieldStatement',
1✔
277
    ClassFieldStatement = 'ClassFieldStatement',
1✔
278
    TryCatchStatement = 'TryCatchStatement',
1✔
279
    CatchStatement = 'CatchStatement',
1✔
280
    ThrowStatement = 'ThrowStatement',
1✔
281
    EnumStatement = 'EnumStatement',
1✔
282
    EnumMemberStatement = 'EnumMemberStatement',
1✔
283
    ConstStatement = 'ConstStatement',
1✔
284
    ContinueStatement = 'ContinueStatement',
1✔
285
    Block = 'Block',
1✔
286
    TypeExpression = 'TypeExpression',
1✔
287
    TypecastExpression = 'TypecastExpression',
1✔
288
    TypedArrayExpression = 'TypedArrayExpression',
1✔
289
    TypecastStatement = 'TypecastStatement',
1✔
290
    AliasStatement = 'AliasStatement',
1✔
291
    ConditionalCompileStatement = 'ConditionalCompileStatement',
1✔
292
    ConditionalCompileConstStatement = 'ConditionalCompileConstStatement',
1✔
293
    ConditionalCompileErrorStatement = 'ConditionalCompileErrorStatement',
1✔
294
    AugmentedAssignmentStatement = 'AugmentedAssignmentStatement'
1✔
295
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc