brighterscript 0.41.2 → 1.0.0-alpha.12

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 (170) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/README.md +2 -2
  3. package/dist/DiagnosticCollection.js +2 -2
  4. package/dist/DiagnosticCollection.js.map +1 -1
  5. package/dist/DiagnosticFilterer.js +2 -2
  6. package/dist/DiagnosticFilterer.js.map +1 -1
  7. package/dist/DiagnosticMessages.d.ts +6 -1
  8. package/dist/DiagnosticMessages.js +5 -0
  9. package/dist/DiagnosticMessages.js.map +1 -1
  10. package/dist/LanguageServer.d.ts +8 -2
  11. package/dist/LanguageServer.js +50 -44
  12. package/dist/LanguageServer.js.map +1 -1
  13. package/dist/Program.d.ts +61 -45
  14. package/dist/Program.js +305 -188
  15. package/dist/Program.js.map +1 -1
  16. package/dist/ProgramBuilder.d.ts +7 -7
  17. package/dist/ProgramBuilder.js +60 -51
  18. package/dist/ProgramBuilder.js.map +1 -1
  19. package/dist/Scope.d.ts +42 -19
  20. package/dist/Scope.js +261 -129
  21. package/dist/Scope.js.map +1 -1
  22. package/dist/SymbolTable.d.ts +73 -0
  23. package/dist/SymbolTable.js +157 -0
  24. package/dist/SymbolTable.js.map +1 -0
  25. package/dist/XmlScope.d.ts +5 -0
  26. package/dist/XmlScope.js +66 -28
  27. package/dist/XmlScope.js.map +1 -1
  28. package/dist/astUtils/creators.d.ts +15 -1
  29. package/dist/astUtils/creators.js +39 -9
  30. package/dist/astUtils/creators.js.map +1 -1
  31. package/dist/astUtils/reflection.d.ts +28 -16
  32. package/dist/astUtils/reflection.js +52 -30
  33. package/dist/astUtils/reflection.js.map +1 -1
  34. package/dist/astUtils/reflection.spec.js +3 -3
  35. package/dist/astUtils/reflection.spec.js.map +1 -1
  36. package/dist/astUtils/visitors.spec.js +12 -13
  37. package/dist/astUtils/visitors.spec.js.map +1 -1
  38. package/dist/astUtils/xml.d.ts +3 -3
  39. package/dist/astUtils/xml.js +2 -2
  40. package/dist/astUtils/xml.js.map +1 -1
  41. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +5 -6
  42. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  43. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +24 -22
  44. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  45. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js +2 -2
  46. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js.map +1 -1
  47. package/dist/examples/plugins/removePrint.js +1 -1
  48. package/dist/examples/plugins/removePrint.js.map +1 -1
  49. package/dist/files/BrsFile.Class.spec.js +356 -41
  50. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  51. package/dist/files/BrsFile.d.ts +55 -37
  52. package/dist/files/BrsFile.js +430 -399
  53. package/dist/files/BrsFile.js.map +1 -1
  54. package/dist/files/BrsFile.spec.js +199 -158
  55. package/dist/files/BrsFile.spec.js.map +1 -1
  56. package/dist/files/XmlFile.d.ts +20 -9
  57. package/dist/files/XmlFile.js +36 -31
  58. package/dist/files/XmlFile.js.map +1 -1
  59. package/dist/files/XmlFile.spec.js +113 -113
  60. package/dist/files/XmlFile.spec.js.map +1 -1
  61. package/dist/files/tests/imports.spec.js +32 -32
  62. package/dist/files/tests/imports.spec.js.map +1 -1
  63. package/dist/globalCallables.js +17 -6
  64. package/dist/globalCallables.js.map +1 -1
  65. package/dist/interfaces.d.ts +155 -39
  66. package/dist/parser/BrsTranspileState.d.ts +7 -0
  67. package/dist/parser/BrsTranspileState.js +10 -1
  68. package/dist/parser/BrsTranspileState.js.map +1 -1
  69. package/dist/parser/Expression.d.ts +23 -12
  70. package/dist/parser/Expression.js +45 -30
  71. package/dist/parser/Expression.js.map +1 -1
  72. package/dist/parser/Parser.Class.spec.js +100 -1
  73. package/dist/parser/Parser.Class.spec.js.map +1 -1
  74. package/dist/parser/Parser.d.ts +118 -5
  75. package/dist/parser/Parser.js +398 -37
  76. package/dist/parser/Parser.js.map +1 -1
  77. package/dist/parser/Parser.spec.js +404 -7
  78. package/dist/parser/Parser.spec.js.map +1 -1
  79. package/dist/parser/SGParser.d.ts +41 -4
  80. package/dist/parser/SGParser.js +185 -174
  81. package/dist/parser/SGParser.js.map +1 -1
  82. package/dist/parser/SGParser.spec.js +17 -4
  83. package/dist/parser/SGParser.spec.js.map +1 -1
  84. package/dist/parser/SGTypes.d.ts +203 -38
  85. package/dist/parser/SGTypes.js +464 -160
  86. package/dist/parser/SGTypes.js.map +1 -1
  87. package/dist/parser/SGTypes.spec.d.ts +1 -0
  88. package/dist/parser/SGTypes.spec.js +351 -0
  89. package/dist/parser/SGTypes.spec.js.map +1 -0
  90. package/dist/parser/Statement.d.ts +37 -26
  91. package/dist/parser/Statement.js +81 -20
  92. package/dist/parser/Statement.js.map +1 -1
  93. package/dist/parser/Statement.spec.js +5 -5
  94. package/dist/parser/Statement.spec.js.map +1 -1
  95. package/dist/parser/TranspileState.d.ts +1 -1
  96. package/dist/parser/TranspileState.js +15 -7
  97. package/dist/parser/TranspileState.js.map +1 -1
  98. package/dist/parser/tests/controlFlow/ForEach.spec.js +5 -4
  99. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  100. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +1 -1
  101. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  102. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +1 -1
  103. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  104. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +1 -1
  105. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  106. package/dist/parser/tests/expression/TernaryExpression.spec.js +1 -1
  107. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  108. package/dist/types/ArrayType.d.ts +1 -0
  109. package/dist/types/ArrayType.js +23 -19
  110. package/dist/types/ArrayType.js.map +1 -1
  111. package/dist/types/BooleanType.d.ts +3 -2
  112. package/dist/types/BooleanType.js +6 -3
  113. package/dist/types/BooleanType.js.map +1 -1
  114. package/dist/types/BscType.d.ts +19 -4
  115. package/dist/types/BscType.js +9 -0
  116. package/dist/types/BscType.js.map +1 -1
  117. package/dist/types/CustomType.d.ts +8 -5
  118. package/dist/types/CustomType.js +12 -12
  119. package/dist/types/CustomType.js.map +1 -1
  120. package/dist/types/DoubleType.d.ts +1 -0
  121. package/dist/types/DoubleType.js +11 -11
  122. package/dist/types/DoubleType.js.map +1 -1
  123. package/dist/types/DynamicType.d.ts +1 -0
  124. package/dist/types/DynamicType.js +4 -0
  125. package/dist/types/DynamicType.js.map +1 -1
  126. package/dist/types/FloatType.d.ts +2 -1
  127. package/dist/types/FloatType.js +11 -11
  128. package/dist/types/FloatType.js.map +1 -1
  129. package/dist/types/FunctionType.d.ts +13 -10
  130. package/dist/types/FunctionType.js +34 -18
  131. package/dist/types/FunctionType.js.map +1 -1
  132. package/dist/types/FunctionType.spec.js +8 -2
  133. package/dist/types/FunctionType.spec.js.map +1 -1
  134. package/dist/types/IntegerType.d.ts +2 -1
  135. package/dist/types/IntegerType.js +11 -11
  136. package/dist/types/IntegerType.js.map +1 -1
  137. package/dist/types/InvalidType.d.ts +3 -2
  138. package/dist/types/InvalidType.js +7 -4
  139. package/dist/types/InvalidType.js.map +1 -1
  140. package/dist/types/LazyType.d.ts +17 -0
  141. package/dist/types/LazyType.js +44 -0
  142. package/dist/types/LazyType.js.map +1 -0
  143. package/dist/types/LongIntegerType.d.ts +2 -1
  144. package/dist/types/LongIntegerType.js +11 -11
  145. package/dist/types/LongIntegerType.js.map +1 -1
  146. package/dist/types/ObjectType.d.ts +6 -2
  147. package/dist/types/ObjectType.js +9 -3
  148. package/dist/types/ObjectType.js.map +1 -1
  149. package/dist/types/StringType.d.ts +3 -2
  150. package/dist/types/StringType.js +6 -3
  151. package/dist/types/StringType.js.map +1 -1
  152. package/dist/types/UninitializedType.d.ts +4 -2
  153. package/dist/types/UninitializedType.js +8 -3
  154. package/dist/types/UninitializedType.js.map +1 -1
  155. package/dist/types/VoidType.d.ts +3 -2
  156. package/dist/types/VoidType.js +6 -3
  157. package/dist/types/VoidType.js.map +1 -1
  158. package/dist/types/helpers.d.ts +42 -0
  159. package/dist/types/helpers.js +113 -0
  160. package/dist/types/helpers.js.map +1 -0
  161. package/dist/util.d.ts +68 -15
  162. package/dist/util.js +193 -45
  163. package/dist/util.js.map +1 -1
  164. package/dist/validators/ClassValidator.d.ts +5 -1
  165. package/dist/validators/ClassValidator.js +31 -17
  166. package/dist/validators/ClassValidator.js.map +1 -1
  167. package/package.json +1 -1
  168. package/dist/FunctionScope.d.ts +0 -27
  169. package/dist/FunctionScope.js +0 -49
  170. package/dist/FunctionScope.js.map +0 -1
@@ -8,8 +8,18 @@ const Parser_1 = require("./Parser");
8
8
  const Statement_1 = require("./Statement");
9
9
  const vscode_languageserver_1 = require("vscode-languageserver");
10
10
  const DiagnosticMessages_1 = require("../DiagnosticMessages");
11
- const astUtils_1 = require("../astUtils");
11
+ const reflection_1 = require("../astUtils/reflection");
12
12
  const testHelpers_spec_1 = require("../testHelpers.spec");
13
+ const VoidType_1 = require("../types/VoidType");
14
+ const FunctionType_1 = require("../types/FunctionType");
15
+ const StringType_1 = require("../types/StringType");
16
+ const CustomType_1 = require("../types/CustomType");
17
+ const IntegerType_1 = require("../types/IntegerType");
18
+ const ObjectType_1 = require("../types/ObjectType");
19
+ const SymbolTable_1 = require("../SymbolTable");
20
+ const DynamicType_1 = require("../types/DynamicType");
21
+ const util_1 = require("../util");
22
+ const LazyType_1 = require("../types/LazyType");
13
23
  describe('parser', () => {
14
24
  it('emits empty object when empty token list is provided', () => {
15
25
  (0, chai_1.expect)(Parser_1.Parser.parse([])).to.deep.include({
@@ -18,6 +28,56 @@ describe('parser', () => {
18
28
  });
19
29
  });
20
30
  describe('findReferences', () => {
31
+ it('recomputes localVars', () => {
32
+ const parser = Parser_1.Parser.parse(`
33
+ sub main(herd)
34
+ for each zombie in herd
35
+ isAlive = false
36
+ end for
37
+ for i = 0 to 10 step 1
38
+ j = i
39
+ end for
40
+ humansAreAlive = false
41
+ end sub
42
+ `);
43
+ (0, chai_1.expect)(parser.references.functionExpressions[0].symbolTable.getOwnSymbols().map(x => x.name).sort()).to.eql([
44
+ 'herd',
45
+ 'humansAreAlive',
46
+ 'i',
47
+ 'isAlive',
48
+ 'j',
49
+ 'zombie'
50
+ ]);
51
+ parser.invalidateReferences();
52
+ (0, chai_1.expect)(parser.references.functionExpressions[0].symbolTable.getOwnSymbols().map(x => x.name).sort()).to.eql([
53
+ 'herd',
54
+ 'humansAreAlive',
55
+ 'i',
56
+ 'isAlive',
57
+ 'j',
58
+ 'zombie'
59
+ ]);
60
+ });
61
+ it('assigns localVars to correct function expression bucket', () => {
62
+ const parser = Parser_1.Parser.parse(`
63
+ sub main()
64
+ outerName = "bob"
65
+ speak = sub()
66
+ innerName = "innerBob"
67
+ end sub
68
+ age = 12
69
+ end sub
70
+ `);
71
+ parser.invalidateReferences();
72
+ (0, chai_1.expect)(parser.references.functionExpressions[0].symbolTable.getOwnSymbols().map(x => x.name)).to.eql([
73
+ 'outerName',
74
+ 'speak',
75
+ 'age'
76
+ ]);
77
+ (0, chai_1.expect)(parser.references.functionExpressions[1].symbolTable.getOwnSymbols().map(x => x.name)).to.eql([
78
+ 'innerName'
79
+ ]);
80
+ });
21
81
  it('gets called if references are missing', () => {
22
82
  const parser = Parser_1.Parser.parse(`
23
83
  sub main()
@@ -197,6 +257,41 @@ describe('parser', () => {
197
257
  `);
198
258
  (0, chai_1.expect)((_a = parser.diagnostics[0]) === null || _a === void 0 ? void 0 : _a.message).to.equal(DiagnosticMessages_1.DiagnosticMessages.bsFeatureNotSupportedInBrsFiles('namespace').message);
199
259
  });
260
+ it('declares a symbol table for the namespace', () => {
261
+ let parser = parse(`
262
+ namespace Name.Space
263
+ function funcInt() as integer
264
+ return 3
265
+ end function
266
+
267
+ function funcStr() as string
268
+ return "hello"
269
+ end function
270
+ end namespace
271
+ `, Parser_1.ParseMode.BrighterScript);
272
+ (0, chai_1.expect)(parser.ast.statements[0]).to.be.instanceof(Statement_1.NamespaceStatement);
273
+ const namespaceStmt = parser.ast.statements[0];
274
+ (0, chai_1.expect)(namespaceStmt.symbolTable).to.be.instanceof(SymbolTable_1.SymbolTable);
275
+ (0, chai_1.expect)(namespaceStmt.symbolTable.getSymbolType('funcInt').toString()).to.equal('function funcInt() as integer');
276
+ (0, chai_1.expect)(namespaceStmt.symbolTable.getSymbolType('funcStr')).to.be.instanceof(FunctionType_1.FunctionType);
277
+ const strFunctionType = namespaceStmt.symbolTable.getSymbolType('funcStr');
278
+ (0, chai_1.expect)(strFunctionType.returnType.toString()).to.equal('string');
279
+ });
280
+ it('adds a fully qualified name of a function in a namespace to the parsers symbol table', () => {
281
+ let parser = parse(`
282
+ namespace Name.Space
283
+ function funcInt() as integer
284
+ return 3
285
+ end function
286
+
287
+ function funcStr() as string
288
+ return "hello"
289
+ end function
290
+ end namespace
291
+ `, Parser_1.ParseMode.BrighterScript);
292
+ (0, chai_1.expect)(parser.symbolTable.getSymbolType('Name.Space.funcInt')).to.be.instanceof(FunctionType_1.FunctionType);
293
+ (0, chai_1.expect)(parser.symbolTable.getSymbolType('Name.Space.funcStr')).to.be.instanceof(FunctionType_1.FunctionType);
294
+ });
200
295
  });
201
296
  it('supports << operator', () => {
202
297
  var _a;
@@ -451,19 +546,19 @@ describe('parser', () => {
451
546
  let { diagnostics, statements } = Parser_1.Parser.parse(tokens);
452
547
  (0, chai_1.expect)(diagnostics).to.be.lengthOf(0, 'Should have zero diagnostics');
453
548
  let fnSmt = statements[0];
454
- if ((0, astUtils_1.isFunctionStatement)(fnSmt)) {
549
+ if ((0, reflection_1.isFunctionStatement)(fnSmt)) {
455
550
  let ifStmt = fnSmt.func.body.statements[0];
456
- if ((0, astUtils_1.isIfStatement)(ifStmt)) {
551
+ if ((0, reflection_1.isIfStatement)(ifStmt)) {
457
552
  expectCommentWithText(ifStmt.thenBranch.statements[0], `'comment 1`);
458
553
  expectCommentWithText(ifStmt.thenBranch.statements[1], `'comment 2`);
459
554
  expectCommentWithText(ifStmt.thenBranch.statements[3], `'comment 3`);
460
555
  let elseIfBranch = ifStmt.elseBranch;
461
- if ((0, astUtils_1.isIfStatement)(elseIfBranch)) {
556
+ if ((0, reflection_1.isIfStatement)(elseIfBranch)) {
462
557
  expectCommentWithText(elseIfBranch.thenBranch.statements[0], `'comment 4`);
463
558
  expectCommentWithText(elseIfBranch.thenBranch.statements[1], `'comment 5`);
464
559
  expectCommentWithText(elseIfBranch.thenBranch.statements[3], `'comment 6`);
465
560
  let elseBranch = elseIfBranch.elseBranch;
466
- if ((0, astUtils_1.isBlock)(elseBranch)) {
561
+ if ((0, reflection_1.isBlock)(elseBranch)) {
467
562
  expectCommentWithText(elseBranch.statements[0], `'comment 7`);
468
563
  expectCommentWithText(elseBranch.statements[1], `'comment 8`);
469
564
  expectCommentWithText(elseBranch.statements[3], `'comment 9`);
@@ -605,7 +700,7 @@ describe('parser', () => {
605
700
  (0, chai_1.expect)((_a = diagnostics[0]) === null || _a === void 0 ? void 0 : _a.message).to.eql(DiagnosticMessages_1.DiagnosticMessages.bsFeatureNotSupportedInBrsFiles('import statements').message);
606
701
  (0, chai_1.expect)(statements[0]).to.be.instanceof(Statement_1.ImportStatement);
607
702
  });
608
- it('catchs missing file path', () => {
703
+ it('catches missing file path', () => {
609
704
  var _a;
610
705
  let { statements, diagnostics } = parse(`
611
706
  import
@@ -949,6 +1044,308 @@ describe('parser', () => {
949
1044
  (0, chai_1.expect)(fn.annotations[0].getArguments()).to.deep.equal([-100]);
950
1045
  });
951
1046
  });
1047
+ describe('getBscTypeFromExpression', () => {
1048
+ it('computes void type for sub with no return type', () => {
1049
+ const parser = parse(`
1050
+ sub main()
1051
+ getMessage = sub()
1052
+ print "hello"
1053
+ end sub
1054
+ end sub
1055
+ `);
1056
+ const func = parser.ast.statements[0].func;
1057
+ const type = (0, Parser_1.getBscTypeFromExpression)(func.body.statements[0].value, func);
1058
+ (0, chai_1.expect)(type.returnType).to.be.instanceof(VoidType_1.VoidType);
1059
+ });
1060
+ it('computes return type for sub with explicit return type', () => {
1061
+ const parser = parse(`
1062
+ sub main()
1063
+ getMessage = sub() as string
1064
+ return "hello"
1065
+ end sub
1066
+ end sub
1067
+ `);
1068
+ const func = parser.ast.statements[0].func;
1069
+ const type = (0, Parser_1.getBscTypeFromExpression)(func.body.statements[0].value, func);
1070
+ (0, chai_1.expect)(type.returnType).to.be.instanceof(StringType_1.StringType);
1071
+ });
1072
+ it('supports sub with custom return type', () => {
1073
+ const parser = parse(`
1074
+ sub main()
1075
+ getPerson = sub() as Person
1076
+ return new Person()
1077
+ end sub
1078
+ end sub
1079
+
1080
+ class Person
1081
+ end class
1082
+ `, Parser_1.ParseMode.BrighterScript);
1083
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(parser.diagnostics);
1084
+ const func = parser.ast.statements[0].func;
1085
+ const type = (0, Parser_1.getBscTypeFromExpression)(func.body.statements[0].value, func);
1086
+ // Return type is LazyType, because "Person" is not fully known yet
1087
+ (0, chai_1.expect)(type.returnType).to.be.instanceof(LazyType_1.LazyType);
1088
+ });
1089
+ });
1090
+ describe('symbolTable', () => {
1091
+ it('stores the types', () => {
1092
+ const parser = parse(`
1093
+ sub main()
1094
+ someNum = 123
1095
+ someString = "hello world"
1096
+ someObj = {foo: "bar"}
1097
+ someCustom = new CustomKlass()
1098
+ end sub
1099
+
1100
+ class CustomKlass
1101
+ end class
1102
+ `, Parser_1.ParseMode.BrighterScript);
1103
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(parser.diagnostics);
1104
+ const mainSymbolTable = parser.references.functionExpressions[0].symbolTable;
1105
+ (0, chai_1.expect)(mainSymbolTable.getSymbolType('someNum')).to.be.instanceof(IntegerType_1.IntegerType);
1106
+ (0, chai_1.expect)(mainSymbolTable.getSymbolType('someString')).to.be.instanceof(StringType_1.StringType);
1107
+ (0, chai_1.expect)(mainSymbolTable.getSymbolType('someObj')).to.be.instanceof(ObjectType_1.ObjectType);
1108
+ (0, chai_1.expect)(mainSymbolTable.getSymbolType('someCustom')).to.be.instanceof(CustomType_1.CustomType);
1109
+ });
1110
+ it('stores typed parameters in functions', () => {
1111
+ const parser = parse(`
1112
+ sub someFunc(param1 as string, param2 as integer)
1113
+ temp = param2
1114
+ end sub
1115
+ `, Parser_1.ParseMode.BrighterScript);
1116
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(parser.diagnostics);
1117
+ const someFuncSymbolTable = parser.references.functionExpressions[0].symbolTable;
1118
+ (0, chai_1.expect)(someFuncSymbolTable.getSymbolType('param1')).to.be.instanceof(StringType_1.StringType);
1119
+ (0, chai_1.expect)(someFuncSymbolTable.getSymbolType('param2')).to.be.instanceof(IntegerType_1.IntegerType);
1120
+ (0, chai_1.expect)(someFuncSymbolTable.getSymbolType('temp')).to.be.instanceof(IntegerType_1.IntegerType);
1121
+ });
1122
+ it('properly defers typing lazy types', () => {
1123
+ const parser = parse(`
1124
+ sub someFunc()
1125
+ temp = foo()
1126
+ end sub
1127
+
1128
+ function foo() as string
1129
+ return "foo"
1130
+ end function
1131
+ `, Parser_1.ParseMode.BrighterScript);
1132
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(parser.diagnostics);
1133
+ const someFuncSymbolTable = parser.references.functionExpressions[0].symbolTable;
1134
+ (0, chai_1.expect)((0, reflection_1.isLazyType)(someFuncSymbolTable.getSymbol('temp')[0].type)).to.be.true;
1135
+ (0, chai_1.expect)(someFuncSymbolTable.getSymbolType('temp').toTypeString()).to.eq('string');
1136
+ });
1137
+ it('does not know about symbols declared in parent functions', () => {
1138
+ const parser = parse(`
1139
+ sub main()
1140
+ count = 0
1141
+ addOne = sub()
1142
+ oldVal = count
1143
+ end sub
1144
+ end sub
1145
+ `, Parser_1.ParseMode.BrighterScript);
1146
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(parser.diagnostics);
1147
+ const addOneSymbolTable = parser.references.functionExpressions[0].childFunctionExpressions[0].symbolTable;
1148
+ (0, chai_1.expect)((0, reflection_1.isUninitializedType)(addOneSymbolTable.getSymbolType('oldVal'))).to.be.true;
1149
+ });
1150
+ it('finds params', () => {
1151
+ const parser = parse(`
1152
+ sub alert(p1, p2 as string, p3 = 1)
1153
+ end sub
1154
+ `, Parser_1.ParseMode.BrighterScript);
1155
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(parser.diagnostics);
1156
+ (0, testHelpers_spec_1.expectSymbolTableEquals)(parser.references.functionExpressions[0].symbolTable, [
1157
+ ['p1', new DynamicType_1.DynamicType(), util_1.default.createRange(1, 26, 1, 28)],
1158
+ ['p2', new StringType_1.StringType(), util_1.default.createRange(1, 30, 1, 32)],
1159
+ ['p3', new IntegerType_1.IntegerType(), util_1.default.createRange(1, 44, 1, 46)]
1160
+ ]);
1161
+ });
1162
+ describe('loops', () => {
1163
+ it('stores the loop variable in a for loop', () => {
1164
+ const parser = parse(`
1165
+ sub main()
1166
+ for i = 0 to 10 step 10
1167
+ print i
1168
+ end for
1169
+ end sub
1170
+ `, Parser_1.ParseMode.BrighterScript);
1171
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(parser.diagnostics);
1172
+ const currentSymbolTable = parser.references.functionExpressions[0].symbolTable;
1173
+ (0, chai_1.expect)(currentSymbolTable.getSymbolType('i').toString()).to.eq('integer');
1174
+ });
1175
+ it('stores the loop variable in a for each loop', () => {
1176
+ const parser = parse(`
1177
+ sub doLoop(someData)
1178
+ for each datum in someData
1179
+ print datum
1180
+ end for
1181
+ end sub
1182
+ `, Parser_1.ParseMode.BrighterScript);
1183
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(parser.diagnostics);
1184
+ const currentSymbolTable = parser.references.functionExpressions[0].symbolTable;
1185
+ (0, chai_1.expect)(currentSymbolTable.getSymbolType('datum').toString()).to.eq('dynamic');
1186
+ });
1187
+ });
1188
+ });
1189
+ describe('tokenChain', () => {
1190
+ it('can find a chain of tokens', () => {
1191
+ const parser = parse(`
1192
+ sub someFunc()
1193
+ print m.field.childField
1194
+ end sub
1195
+ `, Parser_1.ParseMode.BrighterScript);
1196
+ const childFieldToken = parser.getTokenAt(vscode_languageserver_1.Position.create(2, 38));
1197
+ const tokenChain = parser.getTokenChain(childFieldToken).chain;
1198
+ const tokenChainTokens = tokenChain.map(tcm => tcm.token);
1199
+ (0, chai_1.expect)(tokenChain.length).to.equal(3);
1200
+ (0, chai_1.expect)(tokenChainTokens.map(token => token.text)).to.eql(['m', 'field', 'childField']);
1201
+ (0, chai_1.expect)(tokenChain.map(tcm => tcm.usage)).to.eql([Parser_1.TokenUsage.Direct, Parser_1.TokenUsage.Direct, Parser_1.TokenUsage.Direct]);
1202
+ });
1203
+ it('can find a chain of tokens with function call with no args in the middle', () => {
1204
+ const parser = parse(`
1205
+ sub someFunc()
1206
+ print var.field.funcCall().childField
1207
+ end sub
1208
+ `, Parser_1.ParseMode.BrighterScript);
1209
+ const childFieldToken = parser.getTokenAt(vscode_languageserver_1.Position.create(2, 49));
1210
+ const tokenChain = parser.getTokenChain(childFieldToken).chain;
1211
+ const tokenChainTokens = tokenChain.map(tcm => tcm.token);
1212
+ (0, chai_1.expect)(tokenChain.length).to.equal(4);
1213
+ (0, chai_1.expect)(tokenChainTokens.map(token => token.text)).to.eql(['var', 'field', 'funcCall', 'childField']);
1214
+ (0, chai_1.expect)(tokenChain[2].usage).to.eql(Parser_1.TokenUsage.Call);
1215
+ });
1216
+ it('can find a chain of tokens with function call with multiple args in the middle', () => {
1217
+ const parser = parse(`
1218
+ sub someFunc()
1219
+ print var.field.funcCall(1, "string", {key: value}).childField
1220
+ end sub
1221
+ `, Parser_1.ParseMode.BrighterScript);
1222
+ const childFieldToken = parser.getTokenAt(vscode_languageserver_1.Position.create(2, 75));
1223
+ const tokenChain = parser.getTokenChain(childFieldToken).chain;
1224
+ const tokenChainTokens = tokenChain.map(tcm => tcm.token);
1225
+ (0, chai_1.expect)(tokenChain.length).to.equal(4);
1226
+ (0, chai_1.expect)(tokenChainTokens.map(token => token.text)).to.eql(['var', 'field', 'funcCall', 'childField']);
1227
+ (0, chai_1.expect)(tokenChain[2].usage).to.eql(Parser_1.TokenUsage.Call);
1228
+ });
1229
+ it('can find a chain of tokens with function call with function call inside', () => {
1230
+ const parser = parse(`
1231
+ sub someFunc()
1232
+ print var.field.funcCall(a(), b(), otherFunc2(c(), {d: func3(e)})).childField
1233
+ end sub
1234
+ `, Parser_1.ParseMode.BrighterScript);
1235
+ const childFieldToken = parser.getTokenAt(vscode_languageserver_1.Position.create(2, 90));
1236
+ const tokenChain = parser.getTokenChain(childFieldToken).chain;
1237
+ const tokenChainTokens = tokenChain.map(tcm => tcm.token);
1238
+ (0, chai_1.expect)(tokenChain.length).to.equal(4);
1239
+ (0, chai_1.expect)(tokenChainTokens.map(token => token.text)).to.eql(['var', 'field', 'funcCall', 'childField']);
1240
+ (0, chai_1.expect)(tokenChain[2].usage).to.eql(Parser_1.TokenUsage.Call);
1241
+ });
1242
+ it('can find a chain of tokens with array references inside', () => {
1243
+ const parser = parse(`
1244
+ sub someFunc()
1245
+ print var.field.myArray[0].childField
1246
+ end sub
1247
+ `, Parser_1.ParseMode.BrighterScript);
1248
+ const childFieldToken = parser.getTokenAt(vscode_languageserver_1.Position.create(2, 50));
1249
+ const tokenChain = parser.getTokenChain(childFieldToken).chain;
1250
+ const tokenChainTokens = tokenChain.map(tcm => tcm.token);
1251
+ (0, chai_1.expect)(tokenChain.length).to.equal(4);
1252
+ (0, chai_1.expect)(tokenChainTokens.map(token => token.text)).to.eql(['var', 'field', 'myArray', 'childField']);
1253
+ (0, chai_1.expect)(tokenChain[2].usage).to.eql(Parser_1.TokenUsage.ArrayReference);
1254
+ });
1255
+ it('includes unknown when an expression in brackets is part of the chain', () => {
1256
+ const parser = parse(`
1257
+ sub someFunc()
1258
+ print (1 + 1).toStr()
1259
+ end sub
1260
+ `, Parser_1.ParseMode.BrighterScript);
1261
+ const toStrToken = parser.getTokenAt(vscode_languageserver_1.Position.create(2, 34));
1262
+ const tokenChainResponse = parser.getTokenChain(toStrToken);
1263
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.true;
1264
+ });
1265
+ it('includes unknown when an expression in double brackets is part of the chain', () => {
1266
+ const parser = parse(`
1267
+ sub someFunc()
1268
+ print ((2 + 1)*3).toStr()
1269
+ end sub
1270
+ `, Parser_1.ParseMode.BrighterScript);
1271
+ const toStrToken = parser.getTokenAt(vscode_languageserver_1.Position.create(2, 38));
1272
+ const tokenChainResponse = parser.getTokenChain(toStrToken);
1273
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.true;
1274
+ });
1275
+ it('includes unknown when a complicated expression in brackets is part of the chain', () => {
1276
+ const parser = parse(`
1277
+ sub someFunc(currentDate, lastUpdate)
1278
+ print (INT((currentDate.asSeconds() - lastUpdate) / 86400)).toStr()
1279
+ end sub
1280
+ `, Parser_1.ParseMode.BrighterScript);
1281
+ const toStrToken = parser.getTokenAt(vscode_languageserver_1.Position.create(2, 81));
1282
+ const tokenChainResponse = parser.getTokenChain(toStrToken);
1283
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.true;
1284
+ });
1285
+ });
1286
+ it('includes unknown when property is referenced via brackets', () => {
1287
+ const parser = parse(`
1288
+ sub someFunc()
1289
+ complexObj = {prop: "hello", subObj: {prop: "foo", grandChildObj:{prop:"bar"}}}
1290
+ print complexObj.subObj.prop
1291
+ print complexObj["subObj"].prop
1292
+ print complexObj["subObj"]["grandChildObj"].prop
1293
+ end sub
1294
+ `, Parser_1.ParseMode.BrighterScript);
1295
+ const propAsChainToken = parser.getTokenAt(vscode_languageserver_1.Position.create(3, 44)); // complexObj.subObj.prop
1296
+ const propAsAsBracketToken = parser.getTokenAt(vscode_languageserver_1.Position.create(4, 47)); // complexObj["subObj"].prop
1297
+ const propAsAsDoubleBracketToken = parser.getTokenAt(vscode_languageserver_1.Position.create(5, 64)); // complexObj["subObj"]["grandChildObj"].prop
1298
+ let tokenChainResponse = parser.getTokenChain(propAsChainToken);
1299
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.false;
1300
+ (0, chai_1.expect)(tokenChainResponse.chain.map(tcm => tcm.token).map(token => token.text)).to.eql(['complexObj', 'subObj', 'prop']);
1301
+ tokenChainResponse = parser.getTokenChain(propAsAsBracketToken);
1302
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.false;
1303
+ (0, chai_1.expect)(tokenChainResponse.chain[0].usage).to.eql(Parser_1.TokenUsage.ArrayReference);
1304
+ tokenChainResponse = parser.getTokenChain(propAsAsDoubleBracketToken);
1305
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.true;
1306
+ });
1307
+ it('allows token kinds from AllowedLocalIdentifiers as start of a chain', () => {
1308
+ const parser = parse(`
1309
+ sub testLocalIdentifiers(override, string, float)
1310
+ override.someProp.someFunc()
1311
+ string.someProp.someFunc()
1312
+ float.someProp.someFunc()
1313
+ end sub
1314
+ `, Parser_1.ParseMode.BrightScript);
1315
+ const overrideFuncToken = parser.getTokenAt(vscode_languageserver_1.Position.create(2, 40)); // override.someProp.someFunc()
1316
+ const stringFuncToken = parser.getTokenAt(vscode_languageserver_1.Position.create(3, 40)); // string.someProp.someFunc()
1317
+ const floatFuncToken = parser.getTokenAt(vscode_languageserver_1.Position.create(4, 38)); // float.someProp.someFunc()
1318
+ let tokenChainResponse = parser.getTokenChain(overrideFuncToken);
1319
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.false;
1320
+ (0, chai_1.expect)(tokenChainResponse.chain.map(tcm => tcm.token).map(token => token.text)).to.eql(['override', 'someProp', 'someFunc']);
1321
+ tokenChainResponse = parser.getTokenChain(stringFuncToken);
1322
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.false;
1323
+ (0, chai_1.expect)(tokenChainResponse.chain.map(tcm => tcm.token).map(token => token.text)).to.eql(['string', 'someProp', 'someFunc']);
1324
+ tokenChainResponse = parser.getTokenChain(floatFuncToken);
1325
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.false;
1326
+ (0, chai_1.expect)(tokenChainResponse.chain.map(tcm => tcm.token).map(token => token.text)).to.eql(['float', 'someProp', 'someFunc']);
1327
+ });
1328
+ it('allows token kinds from AllowedProperties in middle of a chain', () => {
1329
+ const parser = parse(`
1330
+ sub testAllowedProperties(someObj)
1331
+ someObj.override.someFunc()
1332
+ someObj.string.someFunc()
1333
+ someObj.float.someFunc()
1334
+ end sub
1335
+ `, Parser_1.ParseMode.BrightScript);
1336
+ const overrideFuncToken = parser.getTokenAt(vscode_languageserver_1.Position.create(2, 36)); // someObj.override.someFunc()
1337
+ const stringFuncToken = parser.getTokenAt(vscode_languageserver_1.Position.create(3, 36)); // someObj.string.someFunc()
1338
+ const floatFuncToken = parser.getTokenAt(vscode_languageserver_1.Position.create(4, 36)); // someObj.float.someFunc()
1339
+ let tokenChainResponse = parser.getTokenChain(overrideFuncToken);
1340
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.false;
1341
+ (0, chai_1.expect)(tokenChainResponse.chain.map(tcm => tcm.token).map(token => token.text)).to.eql(['someObj', 'override', 'someFunc']);
1342
+ tokenChainResponse = parser.getTokenChain(stringFuncToken);
1343
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.false;
1344
+ (0, chai_1.expect)(tokenChainResponse.chain.map(tcm => tcm.token).map(token => token.text)).to.eql(['someObj', 'string', 'someFunc']);
1345
+ tokenChainResponse = parser.getTokenChain(floatFuncToken);
1346
+ (0, chai_1.expect)(tokenChainResponse.includesUnknowableTokenType).to.be.false;
1347
+ (0, chai_1.expect)(tokenChainResponse.chain.map(tcm => tcm.token).map(token => token.text)).to.eql(['someObj', 'float', 'someFunc']);
1348
+ });
952
1349
  });
953
1350
  function parse(text, mode) {
954
1351
  let { tokens } = lexer_1.Lexer.scan(text);
@@ -966,7 +1363,7 @@ function rangeToArray(range) {
966
1363
  }
967
1364
  exports.rangeToArray = rangeToArray;
968
1365
  function expectCommentWithText(stat, text) {
969
- if ((0, astUtils_1.isCommentStatement)(stat)) {
1366
+ if ((0, reflection_1.isCommentStatement)(stat)) {
970
1367
  (0, chai_1.expect)(stat.text).to.equal(text);
971
1368
  }
972
1369
  else {