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

rokucommunity / brighterscript / #12717

14 Jun 2024 08:20PM UTC coverage: 85.629% (-2.3%) from 87.936%
#12717

push

web-flow
Merge 94311dc0a into 42db50190

10808 of 13500 branches covered (80.06%)

Branch coverage included in aggregate %.

6557 of 7163 new or added lines in 96 files covered. (91.54%)

83 existing lines in 17 files now uncovered.

12270 of 13451 relevant lines covered (91.22%)

26531.66 hits per line

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

80.95
/src/astUtils/creators.ts
1
import type { Location } from 'vscode-languageserver';
2
import type { Identifier, Token } from '../lexer/Token';
3
import type { SGToken } from '../parser/SGTypes';
4
import { SGAttribute, SGComponent, SGInterface, SGInterfaceField, SGInterfaceFunction, SGScript } from '../parser/SGTypes';
1✔
5
import { TokenKind } from '../lexer/TokenKind';
1✔
6
import type { Expression } from '../parser/AstNode';
7
import { CallExpression, DottedGetExpression, FunctionExpression, LiteralExpression, VariableExpression } from '../parser/Expression';
1✔
8
import { Block, MethodStatement } from '../parser/Statement';
1✔
9

10
const tokenDefaults = {
1✔
11
    [TokenKind.BackTick]: '`',
12
    [TokenKind.Backslash]: '\\',
13
    [TokenKind.BackslashEqual]: '\\=',
14
    [TokenKind.Callfunc]: '@.',
15
    [TokenKind.Caret]: '^',
16
    [TokenKind.Colon]: ':',
17
    [TokenKind.Comma]: ',',
18
    [TokenKind.Comment]: '\'',
19
    [TokenKind.Dollar]: '$',
20
    [TokenKind.Dot]: '.',
21
    [TokenKind.EndClass]: 'end class',
22
    [TokenKind.EndEnum]: 'end enum',
23
    [TokenKind.EndFor]: 'end for',
24
    [TokenKind.EndFunction]: 'end function',
25
    [TokenKind.EndIf]: 'end if',
26
    [TokenKind.EndInterface]: 'end interface',
27
    [TokenKind.EndNamespace]: 'end namespace',
28
    [TokenKind.EndSub]: 'end sub',
29
    [TokenKind.EndTry]: 'end try',
30
    [TokenKind.EndWhile]: 'end while',
31
    [TokenKind.Equal]: '=',
32
    [TokenKind.Greater]: '>',
33
    [TokenKind.GreaterEqual]: '>=',
34
    [TokenKind.HashConst]: '#const',
35
    [TokenKind.HashElse]: '#else',
36
    [TokenKind.HashElseIf]: '#else if',
37
    [TokenKind.HashEndIf]: '#end if',
38
    [TokenKind.HashError]: '#error',
39
    [TokenKind.HashIf]: '#if',
40
    [TokenKind.LeftCurlyBrace]: '{',
41
    [TokenKind.LeftParen]: '(',
42
    [TokenKind.LeftShift]: '<<',
43
    [TokenKind.LeftShiftEqual]: '<<=',
44
    [TokenKind.LeftSquareBracket]: '[',
45
    [TokenKind.Less]: '<',
46
    [TokenKind.LessEqual]: '<=',
47
    [TokenKind.LessGreater]: '<>',
48
    [TokenKind.LineNumLiteral]: 'LINE_NUM',
49
    [TokenKind.Minus]: '-',
50
    [TokenKind.MinusEqual]: '-=',
51
    [TokenKind.MinusMinus]: '--',
52
    [TokenKind.Newline]: '\n',
53
    [TokenKind.PkgLocationLiteral]: 'PKG_LOCATION',
54
    [TokenKind.PkgPathLiteral]: 'PKG_PATH',
55
    [TokenKind.Plus]: '+',
56
    [TokenKind.PlusEqual]: '+=',
57
    [TokenKind.PlusPlus]: '++',
58
    [TokenKind.Question]: '?',
59
    [TokenKind.QuestionQuestion]: '??',
60
    [TokenKind.RightCurlyBrace]: '}',
61
    [TokenKind.RightParen]: ')',
62
    [TokenKind.RightShift]: '>>',
63
    [TokenKind.RightShiftEqual]: '>>=',
64
    [TokenKind.RightSquareBracket]: ']',
65
    [TokenKind.Semicolon]: ';',
66
    [TokenKind.SourceFilePathLiteral]: 'SOURCE_FILE_PATH',
67
    [TokenKind.SourceFunctionNameLiteral]: 'SOURCE_FUNCTION_NAME',
68
    [TokenKind.SourceLineNumLiteral]: 'SOURCE_LINE_NUM',
69
    [TokenKind.SourceLocationLiteral]: 'SOURCE_LOCATION',
70
    [TokenKind.Star]: '*',
71
    [TokenKind.StarEqual]: '*=',
72
    [TokenKind.Tab]: '\t',
73
    [TokenKind.TemplateStringExpressionBegin]: '${',
74
    [TokenKind.TemplateStringExpressionEnd]: '}',
75
    [TokenKind.Whitespace]: ' '
76
};
77

78
export function createToken<T extends TokenKind>(kind: T, text?: string, location?: Location): Token & { kind: T } {
1✔
79
    return {
1,558,978✔
80
        kind: kind,
81
        text: text ?? tokenDefaults[kind as string] ?? kind.toString().toLowerCase(),
9,353,868✔
82
        isReserved: !text || text === kind.toString(),
3,109,100✔
83
        location: location,
84
        leadingWhitespace: '',
85
        leadingTrivia: []
86
    };
87
}
88

89
export function createIdentifier(name: string, location?: Location): Identifier {
1✔
90
    return {
230✔
91
        kind: TokenKind.Identifier,
92
        text: name,
93
        isReserved: false,
94
        location: location,
95
        leadingWhitespace: '',
96
        leadingTrivia: []
97
    };
98
}
99

100
export function createVariableExpression(ident: string, location?: Location): VariableExpression {
1✔
101
    return new VariableExpression({ name: createToken(TokenKind.Identifier, ident, location) });
20✔
102
}
103

104
export function createDottedIdentifier(path: string[], location?: Location): DottedGetExpression {
1✔
105
    const ident = path.pop();
1✔
106
    const obj = path.length > 1 ? createDottedIdentifier(path, location) : createVariableExpression(path[0], location);
1!
107
    return new DottedGetExpression({
1✔
108
        obj: obj,
109
        name: createToken(TokenKind.Identifier, ident, location),
110
        dot: createToken(TokenKind.Dot, '.', location)
111
    });
112
}
113

114
/**
115
 * Create a StringLiteralExpression. The TokenKind.StringLiteral token value includes the leading and trailing doublequote during lexing.
116
 * Since brightscript doesn't support strings with quotes in them, we can safely auto-detect and wrap the value in quotes in this function.
117
 * @param value - the string value. (value will be wrapped in quotes if they are missing)
118
 */
119
export function createStringLiteral(value: string, location?: Location) {
1✔
120
    //wrap the value in double quotes
121
    if (!value.startsWith('"') && !value.endsWith('"')) {
21✔
122
        value = '"' + value + '"';
18✔
123
    }
124
    return new LiteralExpression({ value: createToken(TokenKind.StringLiteral, value, location) });
21✔
125
}
126
export function createIntegerLiteral(value: string, location?: Location) {
1✔
127
    return new LiteralExpression({ value: createToken(TokenKind.IntegerLiteral, value, location) });
6✔
128
}
129
export function createFloatLiteral(value: string, location?: Location) {
1✔
130
    return new LiteralExpression({ value: createToken(TokenKind.FloatLiteral, value, location) });
3✔
131
}
132
export function createDoubleLiteral(value: string, location?: Location) {
1✔
133
    return new LiteralExpression({ value: createToken(TokenKind.DoubleLiteral, value, location) });
3✔
134
}
135
export function createLongIntegerLiteral(value: string, location?: Location) {
1✔
136
    return new LiteralExpression({ value: createToken(TokenKind.LongIntegerLiteral, value, location) });
3✔
137
}
138
export function createInvalidLiteral(value?: string, location?: Location) {
1✔
139
    return new LiteralExpression({ value: createToken(TokenKind.Invalid, value, location) });
11✔
140
}
141
export function createBooleanLiteral(value: string, location?: Location) {
1✔
142
    return new LiteralExpression({ value: createToken(value === 'true' ? TokenKind.True : TokenKind.False, value, location) });
10✔
143
}
144
export function createFunctionExpression(kind: TokenKind.Sub | TokenKind.Function) {
1✔
145
    return new FunctionExpression({
37✔
146
        parameters: [],
147
        body: new Block({ statements: [] }),
148
        functionType: createToken(kind),
149
        endFunctionType: kind === TokenKind.Sub ? createToken(TokenKind.EndSub) : createToken(TokenKind.EndFunction),
37!
150
        leftParen: createToken(TokenKind.LeftParen),
151
        rightParen: createToken(TokenKind.RightParen)
152
    });
153
}
154

155
export function createMethodStatement(name: string, kind: TokenKind.Sub | TokenKind.Function = TokenKind.Function, modifiers?: Token[]) {
1!
156
    return new MethodStatement({
37✔
157
        modifiers: modifiers,
158
        name: createIdentifier(name),
159
        func: createFunctionExpression(kind)
160
    });
161
}
162

163
export function createCall(callee: Expression, args?: Expression[]) {
1✔
164
    return new CallExpression({
3✔
165
        callee: callee,
166
        openingParen: createToken(TokenKind.LeftParen, '('),
167
        closingParen: createToken(TokenKind.RightParen, ')'),
168
        args: args
169
    });
170
}
171

172
export function createSGToken(text: string, location?: Location) {
1✔
173
    return {
1✔
174
        text: text,
175
        range: location
176
    } as SGToken;
177
}
178

179
/**
180
 * Create an SGAttribute without any ranges
181
 */
182
export function createSGAttribute(keyName: string, value: string) {
1✔
183
    return new SGAttribute({
69✔
184
        key: { text: keyName },
185
        equals: { text: '=' },
186
        openingQuote: { text: '"' },
187
        value: { text: value },
188
        closingQuote: { text: '"' }
189
    });
190
}
191

192
export function createSGInterfaceField(id: string, attributes: { type?: string; alias?: string; value?: string; onChange?: string; alwaysNotify?: string } = {}) {
1!
NEW
193
    const attrs = [
×
194
        createSGAttribute('id', id)
195
    ];
NEW
196
    for (let key in attributes) {
×
NEW
197
        attrs.push(
×
198
            createSGAttribute(key, attributes[key])
199
        );
200
    }
NEW
201
    return new SGInterfaceField({
×
202
        startTagOpen: { text: '<' },
203
        startTagName: { text: 'field' },
204
        attributes: attrs,
205
        startTagClose: { text: '/>' }
206
    });
207
}
208

209
export function createSGComponent(name: string, parentName?: string) {
1✔
NEW
210
    const attributes = [
×
211
        createSGAttribute('name', name)
212
    ];
NEW
213
    if (parentName) {
×
NEW
214
        attributes.push(
×
215
            createSGAttribute('extends', parentName)
216
        );
217
    }
NEW
218
    return new SGComponent({
×
219
        startTagOpen: { text: '<' },
220
        startTagName: { text: 'component' },
221
        attributes: attributes,
222
        startTagClose: { text: '>' },
223
        elements: [],
224
        endTagOpen: { text: '</' },
225
        endTagName: { text: 'component' },
226
        endTagClose: { text: '>' }
227
    });
228
}
229

230
export function createSGInterfaceFunction(functionName: string) {
1✔
NEW
231
    return new SGInterfaceFunction({
×
232
        startTagOpen: { text: '<' },
233
        startTagName: { text: 'function' },
234
        attributes: [createSGAttribute('name', functionName)],
235
        startTagClose: { text: '/>' }
236
    });
237
}
238

239
export function createSGInterface() {
1✔
NEW
240
    return new SGInterface({
×
241
        startTagOpen: { text: '<' },
242
        startTagName: { text: 'interface' },
243
        attributes: [],
244
        startTagClose: { text: '>' },
245
        elements: [],
246
        endTagOpen: { text: '</' },
247
        endTagName: { text: 'interface' },
248
        endTagClose: { text: '>' }
249
    });
250
}
251

252
export function createSGScript(attributes: { type?: string; uri?: string }) {
1✔
253
    const attrs = [] as SGAttribute[];
34✔
254
    for (let key in attributes) {
34✔
255
        attrs.push(
68✔
256
            createSGAttribute(key, attributes[key])
257
        );
258
    }
259
    return new SGScript({
34✔
260
        startTagOpen: { text: '<' },
261
        startTagName: { text: 'script' },
262
        attributes: attrs,
263
        startTagClose: { text: '/>' }
264
    });
265
}
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