vba-runner 0.1.1-alpha.1 → 0.1.1-alpha.3

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.
@@ -114,7 +114,7 @@ var Lexer = class _Lexer {
114
114
  const startLine = this.line;
115
115
  const startColumn = this.column;
116
116
  if (this.pos >= this.input.length) {
117
- return { type: 136 /* EOF */, value: "", line: startLine, column: startColumn };
117
+ return { type: 137 /* EOF */, value: "", line: startLine, column: startColumn };
118
118
  }
119
119
  const char = this.peek();
120
120
  if (char === "#") {
@@ -143,12 +143,12 @@ var Lexer = class _Lexer {
143
143
  }
144
144
  if (this.peek() === "#") {
145
145
  this.advance();
146
- return { type: 134 /* Date */, value: dateValue, line: startLine, column: startColumn };
146
+ return { type: 135 /* Date */, value: dateValue, line: startLine, column: startColumn };
147
147
  }
148
148
  }
149
149
  }
150
150
  this.advance();
151
- return { type: 111 /* OperatorHash */, value: "#", line: startLine, column: startColumn };
151
+ return { type: 112 /* OperatorHash */, value: "#", line: startLine, column: startColumn };
152
152
  }
153
153
  if (char === "_") {
154
154
  const next = this.pos + 1 < this.input.length ? this.input[this.pos + 1] : "\0";
@@ -186,7 +186,7 @@ var Lexer = class _Lexer {
186
186
  }
187
187
  if (char === "\n") {
188
188
  this.advance();
189
- return { type: 135 /* Newline */, value: "\n", line: startLine, column: startColumn };
189
+ return { type: 136 /* Newline */, value: "\n", line: startLine, column: startColumn };
190
190
  }
191
191
  if (char === '"') {
192
192
  this.advance();
@@ -208,39 +208,39 @@ var Lexer = class _Lexer {
208
208
  }
209
209
  if (char === "=") {
210
210
  this.advance();
211
- return { type: 120 /* OperatorEquals */, value: "=", line: startLine, column: startColumn };
211
+ return { type: 121 /* OperatorEquals */, value: "=", line: startLine, column: startColumn };
212
212
  }
213
213
  if (char === "<") {
214
214
  this.advance();
215
215
  if (this.peek() === ">") {
216
216
  this.advance();
217
- return { type: 121 /* OperatorNotEquals */, value: "<>", line: startLine, column: startColumn };
217
+ return { type: 122 /* OperatorNotEquals */, value: "<>", line: startLine, column: startColumn };
218
218
  }
219
219
  if (this.peek() === "=") {
220
220
  this.advance();
221
- return { type: 124 /* OperatorLessThanOrEqual */, value: "<=", line: startLine, column: startColumn };
221
+ return { type: 125 /* OperatorLessThanOrEqual */, value: "<=", line: startLine, column: startColumn };
222
222
  }
223
- return { type: 122 /* OperatorLessThan */, value: "<", line: startLine, column: startColumn };
223
+ return { type: 123 /* OperatorLessThan */, value: "<", line: startLine, column: startColumn };
224
224
  }
225
225
  if (char === ">") {
226
226
  this.advance();
227
227
  if (this.peek() === "=") {
228
228
  this.advance();
229
- return { type: 125 /* OperatorGreaterThanOrEqual */, value: ">=", line: startLine, column: startColumn };
229
+ return { type: 126 /* OperatorGreaterThanOrEqual */, value: ">=", line: startLine, column: startColumn };
230
230
  }
231
- return { type: 123 /* OperatorGreaterThan */, value: ">", line: startLine, column: startColumn };
231
+ return { type: 124 /* OperatorGreaterThan */, value: ">", line: startLine, column: startColumn };
232
232
  }
233
233
  if (char === "+") {
234
234
  this.advance();
235
- return { type: 112 /* OperatorPlus */, value: "+", line: startLine, column: startColumn };
235
+ return { type: 113 /* OperatorPlus */, value: "+", line: startLine, column: startColumn };
236
236
  }
237
237
  if (char === "-") {
238
238
  this.advance();
239
- return { type: 113 /* OperatorMinus */, value: "-", line: startLine, column: startColumn };
239
+ return { type: 114 /* OperatorMinus */, value: "-", line: startLine, column: startColumn };
240
240
  }
241
241
  if (char === "!") {
242
242
  this.advance();
243
- return { type: 132 /* OperatorExclamation */, value: "!", line: startLine, column: startColumn };
243
+ return { type: 133 /* OperatorExclamation */, value: "!", line: startLine, column: startColumn };
244
244
  }
245
245
  if (char === "&") {
246
246
  this.advance();
@@ -262,23 +262,23 @@ var Lexer = class _Lexer {
262
262
  if (NUMERIC_TYPE_SUFFIXES.has(this.peek())) this.advance();
263
263
  return { type: 1 /* Number */, value: "0o" + octStr, line: startLine, column: startColumn };
264
264
  }
265
- return { type: 117 /* OperatorAmpersand */, value: "&", line: startLine, column: startColumn };
265
+ return { type: 118 /* OperatorAmpersand */, value: "&", line: startLine, column: startColumn };
266
266
  }
267
267
  if (char === ",") {
268
268
  this.advance();
269
- return { type: 126 /* OperatorComma */, value: ",", line: startLine, column: startColumn };
269
+ return { type: 127 /* OperatorComma */, value: ",", line: startLine, column: startColumn };
270
270
  }
271
271
  if (char === "#") {
272
272
  this.advance();
273
- return { type: 111 /* OperatorHash */, value: "#", line: startLine, column: startColumn };
273
+ return { type: 112 /* OperatorHash */, value: "#", line: startLine, column: startColumn };
274
274
  }
275
275
  if (char === "(") {
276
276
  this.advance();
277
- return { type: 127 /* OperatorLParen */, value: "(", line: startLine, column: startColumn };
277
+ return { type: 128 /* OperatorLParen */, value: "(", line: startLine, column: startColumn };
278
278
  }
279
279
  if (char === ")") {
280
280
  this.advance();
281
- return { type: 128 /* OperatorRParen */, value: ")", line: startLine, column: startColumn };
281
+ return { type: 129 /* OperatorRParen */, value: ")", line: startLine, column: startColumn };
282
282
  }
283
283
  if (char === "[") {
284
284
  this.advance();
@@ -287,23 +287,23 @@ var Lexer = class _Lexer {
287
287
  foreignStr += this.advance();
288
288
  }
289
289
  if (this.peek() === "]") this.advance();
290
- return { type: 138 /* ForeignName */, value: foreignStr, line: startLine, column: startColumn };
290
+ return { type: 139 /* ForeignName */, value: foreignStr, line: startLine, column: startColumn };
291
291
  }
292
292
  if (char === ".") {
293
293
  this.advance();
294
- return { type: 129 /* OperatorDot */, value: ".", line: startLine, column: startColumn };
294
+ return { type: 130 /* OperatorDot */, value: ".", line: startLine, column: startColumn };
295
295
  }
296
296
  if (char === ":") {
297
297
  this.advance();
298
298
  if (this.peek() === "=") {
299
299
  this.advance();
300
- return { type: 131 /* OperatorColonEquals */, value: ":=", line: startLine, column: startColumn };
300
+ return { type: 132 /* OperatorColonEquals */, value: ":=", line: startLine, column: startColumn };
301
301
  }
302
- return { type: 130 /* OperatorColon */, value: ":", line: startLine, column: startColumn };
302
+ return { type: 131 /* OperatorColon */, value: ":", line: startLine, column: startColumn };
303
303
  }
304
304
  if (char === ";") {
305
305
  this.advance();
306
- return { type: 133 /* OperatorSemicolon */, value: ";", line: startLine, column: startColumn };
306
+ return { type: 134 /* OperatorSemicolon */, value: ";", line: startLine, column: startColumn };
307
307
  }
308
308
  if (this.isDigit(char)) {
309
309
  let numStr = "";
@@ -400,7 +400,7 @@ var Lexer = class _Lexer {
400
400
  if (lowerBase === "exit") return { type: 45 /* KeywordExit */, value: idStr, line: startLine, column: startColumn };
401
401
  if (lowerBase === "byref") return { type: 46 /* KeywordByRef */, value: idStr, line: startLine, column: startColumn };
402
402
  if (lowerBase === "byval") return { type: 47 /* KeywordByVal */, value: idStr, line: startLine, column: startColumn };
403
- if (lowerBase === "mod") return { type: 118 /* KeywordMod */, value: idStr, line: startLine, column: startColumn };
403
+ if (lowerBase === "mod") return { type: 119 /* KeywordMod */, value: idStr, line: startLine, column: startColumn };
404
404
  if (lowerBase === "type") return { type: 48 /* KeywordType */, value: idStr, line: startLine, column: startColumn };
405
405
  if (lowerBase === "nothing") return { type: 49 /* KeywordNothing */, value: idStr, line: startLine, column: startColumn };
406
406
  if (lowerBase === "optional") return { type: 50 /* KeywordOptional */, value: idStr, line: startLine, column: startColumn };
@@ -461,26 +461,42 @@ var Lexer = class _Lexer {
461
461
  if (lowerBase === "midb") return { type: 108 /* KeywordMid */, value: idStr, line: startLine, column: startColumn };
462
462
  if (lowerBase === "width") return { type: 109 /* KeywordWidth */, value: idStr, line: startLine, column: startColumn };
463
463
  if (lowerBase === "addressof") return { type: 110 /* KeywordAddressOf */, value: idStr, line: startLine, column: startColumn };
464
+ if ([
465
+ "defbool",
466
+ "defbyte",
467
+ "defint",
468
+ "deflng",
469
+ "deflnglng",
470
+ "deflngptr",
471
+ "defsng",
472
+ "defdbl",
473
+ "defcur",
474
+ "defdate",
475
+ "defstr",
476
+ "defobj",
477
+ "defvar"
478
+ ].includes(lowerBase))
479
+ return { type: 111 /* KeywordDef */, value: idStr, line: startLine, column: startColumn };
464
480
  return { type: 0 /* Identifier */, value: idStr, line: startLine, column: startColumn };
465
481
  }
466
482
  if (char === "*") {
467
483
  this.advance();
468
- return { type: 114 /* OperatorMultiply */, value: "*", line: startLine, column: startColumn };
484
+ return { type: 115 /* OperatorMultiply */, value: "*", line: startLine, column: startColumn };
469
485
  }
470
486
  if (char === "/") {
471
487
  this.advance();
472
- return { type: 115 /* OperatorDivide */, value: "/", line: startLine, column: startColumn };
488
+ return { type: 116 /* OperatorDivide */, value: "/", line: startLine, column: startColumn };
473
489
  }
474
490
  if (char === "\\") {
475
491
  this.advance();
476
- return { type: 116 /* OperatorIntDivide */, value: "\\", line: startLine, column: startColumn };
492
+ return { type: 117 /* OperatorIntDivide */, value: "\\", line: startLine, column: startColumn };
477
493
  }
478
494
  if (char === "^") {
479
495
  this.advance();
480
- return { type: 119 /* OperatorPower */, value: "^", line: startLine, column: startColumn };
496
+ return { type: 120 /* OperatorPower */, value: "^", line: startLine, column: startColumn };
481
497
  }
482
498
  const unknownChar = this.advance();
483
- return { type: 137 /* Unknown */, value: unknownChar, line: startLine, column: startColumn };
499
+ return { type: 138 /* Unknown */, value: unknownChar, line: startLine, column: startColumn };
484
500
  }
485
501
  }
486
502
  tokenize() {
@@ -489,7 +505,7 @@ var Lexer = class _Lexer {
489
505
  do {
490
506
  token = this.getNextToken();
491
507
  tokens.push(token);
492
- } while (token.type !== 136 /* EOF */);
508
+ } while (token.type !== 137 /* EOF */);
493
509
  return tokens;
494
510
  }
495
511
  };
@@ -637,7 +653,7 @@ var Parser = class _Parser {
637
653
  /** Returns true if token is a valid IDENTIFIER per §3.3.5.2:
638
654
  * either a plain lex-identifier or a contextual keyword that is not reserved. */
639
655
  isIdentifier(token) {
640
- return token.type === 0 /* Identifier */ || token.type === 138 /* ForeignName */ || _Parser.CONTEXTUAL_KW.has(token.type);
656
+ return token.type === 0 /* Identifier */ || token.type === 139 /* ForeignName */ || _Parser.CONTEXTUAL_KW.has(token.type);
641
657
  }
642
658
  constructor(tokens, options = {}) {
643
659
  this.tokens = tokens;
@@ -646,7 +662,7 @@ var Parser = class _Parser {
646
662
  }
647
663
  // Keywords can appear as property/class names in VBA (e.g. obj.Property, New Collection)
648
664
  isNameToken(token) {
649
- return token.type === 0 /* Identifier */ || token.type === 138 /* ForeignName */ || token.type >= 3 /* KeywordFor */ && token.type <= 110 /* KeywordAddressOf */;
665
+ return token.type === 0 /* Identifier */ || token.type === 139 /* ForeignName */ || token.type >= 3 /* KeywordFor */ && token.type <= 110 /* KeywordAddressOf */;
650
666
  }
651
667
  /**
652
668
  * Returns true if the current token stream contains a file-I/O Open statement pattern
@@ -663,7 +679,7 @@ var Parser = class _Parser {
663
679
  }
664
680
  throwMissingRParen() {
665
681
  const peek = this.peek();
666
- if (peek.type === 135 /* Newline */) {
682
+ if (peek.type === 136 /* Newline */) {
667
683
  const prevToken = this.tokens[Math.max(0, this.pos - 1)];
668
684
  if (prevToken && this.isContinuationEndToken(prevToken.type)) {
669
685
  this.throwError(
@@ -675,24 +691,24 @@ var Parser = class _Parser {
675
691
  this.throwError(`Parse error: Expected ')' at line ${peek.line} `);
676
692
  }
677
693
  isContinuationEndToken(type) {
678
- return type === 112 /* OperatorPlus */ || type === 113 /* OperatorMinus */ || type === 114 /* OperatorMultiply */ || type === 115 /* OperatorDivide */ || type === 116 /* OperatorIntDivide */ || type === 119 /* OperatorPower */ || type === 117 /* OperatorAmpersand */ || type === 120 /* OperatorEquals */ || type === 121 /* OperatorNotEquals */ || type === 122 /* OperatorLessThan */ || type === 123 /* OperatorGreaterThan */ || type === 124 /* OperatorLessThanOrEqual */ || type === 125 /* OperatorGreaterThanOrEqual */ || type === 126 /* OperatorComma */ || type === 127 /* OperatorLParen */ || type === 26 /* KeywordAnd */ || type === 27 /* KeywordOr */ || type === 64 /* KeywordXor */ || type === 65 /* KeywordEqv */ || type === 66 /* KeywordImp */ || type === 118 /* KeywordMod */ || type === 63 /* KeywordLike */ || type === 51 /* KeywordIs */ || type === 28 /* KeywordNot */;
694
+ return type === 113 /* OperatorPlus */ || type === 114 /* OperatorMinus */ || type === 115 /* OperatorMultiply */ || type === 116 /* OperatorDivide */ || type === 117 /* OperatorIntDivide */ || type === 120 /* OperatorPower */ || type === 118 /* OperatorAmpersand */ || type === 121 /* OperatorEquals */ || type === 122 /* OperatorNotEquals */ || type === 123 /* OperatorLessThan */ || type === 124 /* OperatorGreaterThan */ || type === 125 /* OperatorLessThanOrEqual */ || type === 126 /* OperatorGreaterThanOrEqual */ || type === 127 /* OperatorComma */ || type === 128 /* OperatorLParen */ || type === 26 /* KeywordAnd */ || type === 27 /* KeywordOr */ || type === 64 /* KeywordXor */ || type === 65 /* KeywordEqv */ || type === 66 /* KeywordImp */ || type === 119 /* KeywordMod */ || type === 63 /* KeywordLike */ || type === 51 /* KeywordIs */ || type === 28 /* KeywordNot */;
679
695
  }
680
696
  tokenDisplay(value) {
681
697
  return value.replace(/\n/g, "<\u6539\u884C>").replace(/\r/g, "<CR>").replace(/\t/g, "<\u30BF\u30D6>");
682
698
  }
683
699
  throwError(message, token) {
684
700
  const peek = this.peek();
685
- const t = token ?? (peek.type !== 136 /* EOF */ ? peek : this.tokens[Math.max(0, this.pos - 1)]);
701
+ const t = token ?? (peek.type !== 137 /* EOF */ ? peek : this.tokens[Math.max(0, this.pos - 1)]);
686
702
  throw new ParseError(message, t.line, t.column);
687
703
  }
688
704
  syncToNextTopLevelStatement() {
689
- while (this.peek().type !== 136 /* EOF */ && this.peek().type !== 135 /* Newline */) {
705
+ while (this.peek().type !== 137 /* EOF */ && this.peek().type !== 136 /* Newline */) {
690
706
  this.advance();
691
707
  }
692
708
  while (this.isAtEndTerminator()) {
693
709
  this.advance();
694
710
  this.advance();
695
- while (this.peek().type !== 136 /* EOF */ && this.peek().type !== 135 /* Newline */) {
711
+ while (this.peek().type !== 137 /* EOF */ && this.peek().type !== 136 /* Newline */) {
696
712
  this.advance();
697
713
  }
698
714
  }
@@ -720,6 +736,18 @@ var Parser = class _Parser {
720
736
  }
721
737
  return { type: "OptionCompareStatement", mode };
722
738
  }
739
+ validateParameterOrder(params) {
740
+ let seenOptional = false;
741
+ for (const p of params) {
742
+ if (p.isParamArray) break;
743
+ if (p.isOptional) {
744
+ seenOptional = true;
745
+ } else if (seenOptional) {
746
+ const line = p.loc?.start?.line ?? this.peek().line;
747
+ this.throwError(`Compile error at line ${line}: Non-optional parameter '${p.name}' cannot follow an Optional parameter`);
748
+ }
749
+ }
750
+ }
723
751
  parseParameter() {
724
752
  let isByVal = false;
725
753
  let isOptional = false;
@@ -741,20 +769,20 @@ var Parser = class _Parser {
741
769
  }
742
770
  const nameToken = this.advance();
743
771
  let isArray = false;
744
- if (this.match(127 /* OperatorLParen */)) {
745
- this.consume(128 /* OperatorRParen */, "Expected ')' after parameter name");
772
+ if (this.match(128 /* OperatorLParen */)) {
773
+ this.consume(129 /* OperatorRParen */, "Expected ')' after parameter name");
746
774
  isArray = true;
747
775
  }
748
776
  let paramType;
749
777
  if (this.match(23 /* KeywordAs */)) {
750
778
  paramType = this.advance().value;
751
- if (this.peek().type === 129 /* OperatorDot */) {
779
+ if (this.peek().type === 130 /* OperatorDot */) {
752
780
  this.advance();
753
781
  paramType += "." + this.advance().value;
754
782
  }
755
783
  }
756
784
  let defaultValue;
757
- if (this.match(120 /* OperatorEquals */)) {
785
+ if (this.match(121 /* OperatorEquals */)) {
758
786
  defaultValue = this.parseExpression();
759
787
  }
760
788
  return {
@@ -770,10 +798,43 @@ var Parser = class _Parser {
770
798
  loc: { start: { line: nameToken.line, column: nameToken.column }, end: { line: nameToken.line, column: nameToken.column + nameToken.value.length } }
771
799
  };
772
800
  }
801
+ parseDefDirective() {
802
+ const defToken = this.advance();
803
+ const keyword = defToken.value.toLowerCase().replace(/[$%&#@!^]$/, "");
804
+ const typeMap = {
805
+ defbool: "Boolean",
806
+ defbyte: "Byte",
807
+ defint: "Integer",
808
+ deflng: "Long",
809
+ deflnglng: "LongLong",
810
+ deflngptr: "LongPtr",
811
+ defsng: "Single",
812
+ defdbl: "Double",
813
+ defcur: "Currency",
814
+ defdate: "Date",
815
+ defstr: "String",
816
+ defobj: "Object",
817
+ defvar: "Variant"
818
+ };
819
+ const vbaType = typeMap[keyword] ?? "Variant";
820
+ const ranges = [];
821
+ do {
822
+ const fromTok = this.advance();
823
+ const from = fromTok.value.charAt(0).toLowerCase();
824
+ let to = from;
825
+ if (this.peek().type === 114 /* OperatorMinus */) {
826
+ this.advance();
827
+ const toTok = this.advance();
828
+ to = toTok.value.charAt(0).toLowerCase();
829
+ }
830
+ ranges.push({ from, to });
831
+ } while (this.match(127 /* OperatorComma */));
832
+ return { type: "DefDirective", vbaType, ranges };
833
+ }
773
834
  parseAttributeStatement() {
774
835
  this.advance();
775
836
  const name = this.advance().value;
776
- this.consume(120 /* OperatorEquals */, "Expected '=' after Attribute name");
837
+ this.consume(121 /* OperatorEquals */, "Expected '=' after Attribute name");
777
838
  const value = this.parseExpression();
778
839
  return { type: "AttributeStatement", name, value };
779
840
  }
@@ -831,7 +892,7 @@ var Parser = class _Parser {
831
892
  }
832
893
  }
833
894
  this.consume(23 /* KeywordAs */, "Expected 'As' in Open statement");
834
- this.match(111 /* OperatorHash */);
895
+ this.match(112 /* OperatorHash */);
835
896
  const fileNumber = this.parseExpression();
836
897
  return { type: "OpenStatement", path: path2, mode, access, lock, fileNumber };
837
898
  }
@@ -839,34 +900,34 @@ var Parser = class _Parser {
839
900
  this.advance();
840
901
  const fileNumbers = [];
841
902
  while (!this.isAtTerminator()) {
842
- this.match(111 /* OperatorHash */);
903
+ this.match(112 /* OperatorHash */);
843
904
  fileNumbers.push(this.parseExpression());
844
- if (!this.match(126 /* OperatorComma */)) break;
905
+ if (!this.match(127 /* OperatorComma */)) break;
845
906
  }
846
907
  return { type: "CloseStatement", fileNumbers };
847
908
  }
848
909
  parsePrintStatement() {
849
910
  this.advance();
850
- this.consume(111 /* OperatorHash */, "Expected '#' in Print statement");
911
+ this.consume(112 /* OperatorHash */, "Expected '#' in Print statement");
851
912
  const fileNumber = this.parseExpression();
852
- this.consume(126 /* OperatorComma */, "Expected ',' after file number in Print statement");
913
+ this.consume(127 /* OperatorComma */, "Expected ',' after file number in Print statement");
853
914
  const expressions = [];
854
915
  while (!this.isAtTerminator()) {
855
916
  if (this.match(95 /* KeywordSpc */)) {
856
- this.consume(127 /* OperatorLParen */, "Expected '(' after Spc");
917
+ this.consume(128 /* OperatorLParen */, "Expected '(' after Spc");
857
918
  expressions.push({ type: "Spc", val: this.parseExpression() });
858
- this.consume(128 /* OperatorRParen */, "Expected ')' after Spc");
919
+ this.consume(129 /* OperatorRParen */, "Expected ')' after Spc");
859
920
  } else if (this.match(96 /* KeywordTab */)) {
860
- if (this.match(127 /* OperatorLParen */)) {
921
+ if (this.match(128 /* OperatorLParen */)) {
861
922
  expressions.push({ type: "Tab", val: this.parseExpression() });
862
- this.consume(128 /* OperatorRParen */, "Expected ')' after Tab");
923
+ this.consume(129 /* OperatorRParen */, "Expected ')' after Tab");
863
924
  } else {
864
925
  expressions.push("Tab");
865
926
  }
866
- } else if (this.peek().type === 126 /* OperatorComma */) {
927
+ } else if (this.peek().type === 127 /* OperatorComma */) {
867
928
  this.advance();
868
929
  expressions.push("Comma");
869
- } else if (this.peek().type === 133 /* OperatorSemicolon */) {
930
+ } else if (this.peek().type === 134 /* OperatorSemicolon */) {
870
931
  this.advance();
871
932
  expressions.push("Semicolon");
872
933
  } else {
@@ -879,9 +940,9 @@ var Parser = class _Parser {
879
940
  parseLineInputStatement() {
880
941
  this.advance();
881
942
  this.consume(84 /* KeywordInput */, "Expected 'Input' after 'Line'");
882
- this.consume(111 /* OperatorHash */, "Expected '#' in Line Input statement");
943
+ this.consume(112 /* OperatorHash */, "Expected '#' in Line Input statement");
883
944
  const fileNumber = this.parseExpression();
884
- this.consume(126 /* OperatorComma */, "Expected ',' after file number");
945
+ this.consume(127 /* OperatorComma */, "Expected ',' after file number");
885
946
  const variable = this.parsePrimary();
886
947
  if (variable.type !== "Identifier") {
887
948
  this.throwError(`Parse error: Expected variable name in Line Input at line ${this.peek().line}`);
@@ -890,14 +951,14 @@ var Parser = class _Parser {
890
951
  }
891
952
  parsePutStatement() {
892
953
  this.advance();
893
- this.consume(111 /* OperatorHash */, "Expected '#' in Put statement");
954
+ this.consume(112 /* OperatorHash */, "Expected '#' in Put statement");
894
955
  const fileNumber = this.parseExpression();
895
- this.consume(126 /* OperatorComma */, "Expected ',' after file number");
956
+ this.consume(127 /* OperatorComma */, "Expected ',' after file number");
896
957
  let recordNumber = void 0;
897
- if (this.peek().type !== 126 /* OperatorComma */) {
958
+ if (this.peek().type !== 127 /* OperatorComma */) {
898
959
  recordNumber = this.parseExpression();
899
960
  }
900
- this.consume(126 /* OperatorComma */, "Expected second ',' in Put statement");
961
+ this.consume(127 /* OperatorComma */, "Expected second ',' in Put statement");
901
962
  const data = this.parseExpression();
902
963
  return { type: "PutStatement", fileNumber, recordNumber, data };
903
964
  }
@@ -908,47 +969,47 @@ var Parser = class _Parser {
908
969
  }
909
970
  parseWriteStatement() {
910
971
  this.advance();
911
- this.consume(111 /* OperatorHash */, "Expected '#' in Write statement");
972
+ this.consume(112 /* OperatorHash */, "Expected '#' in Write statement");
912
973
  const fileNumber = this.parseExpression();
913
974
  const items = [];
914
- if (this.match(126 /* OperatorComma */)) {
975
+ if (this.match(127 /* OperatorComma */)) {
915
976
  while (!this.isAtTerminator()) {
916
977
  items.push(this.parseExpression());
917
- if (!this.match(126 /* OperatorComma */)) break;
978
+ if (!this.match(127 /* OperatorComma */)) break;
918
979
  }
919
980
  }
920
981
  return { type: "WriteStatement", fileNumber, items };
921
982
  }
922
983
  parseInputStatement() {
923
984
  this.advance();
924
- this.consume(111 /* OperatorHash */, "Expected '#' in Input statement");
985
+ this.consume(112 /* OperatorHash */, "Expected '#' in Input statement");
925
986
  const fileNumber = this.parseExpression();
926
- this.consume(126 /* OperatorComma */, "Expected ',' in Input statement");
987
+ this.consume(127 /* OperatorComma */, "Expected ',' in Input statement");
927
988
  const variables = [];
928
989
  while (!this.isAtTerminator()) {
929
990
  variables.push(this.parseExpression());
930
- if (!this.match(126 /* OperatorComma */)) break;
991
+ if (!this.match(127 /* OperatorComma */)) break;
931
992
  }
932
993
  return { type: "InputStatement", fileNumber, variables };
933
994
  }
934
995
  parseGetStatement() {
935
996
  this.advance();
936
- this.consume(111 /* OperatorHash */, "Expected '#' in Get statement");
997
+ this.consume(112 /* OperatorHash */, "Expected '#' in Get statement");
937
998
  const fileNumber = this.parseExpression();
938
- this.consume(126 /* OperatorComma */, "Expected ',' in Get statement");
999
+ this.consume(127 /* OperatorComma */, "Expected ',' in Get statement");
939
1000
  let recordNumber = void 0;
940
- if (this.peek().type !== 126 /* OperatorComma */) {
1001
+ if (this.peek().type !== 127 /* OperatorComma */) {
941
1002
  recordNumber = this.parseExpression();
942
1003
  }
943
- this.consume(126 /* OperatorComma */, "Expected ',' in Get statement");
1004
+ this.consume(127 /* OperatorComma */, "Expected ',' in Get statement");
944
1005
  const variable = this.parseExpression();
945
1006
  return { type: "GetStatement", fileNumber, recordNumber, variable };
946
1007
  }
947
1008
  parseSeekStatement() {
948
1009
  this.advance();
949
- this.consume(111 /* OperatorHash */, "Expected '#' in Seek statement");
1010
+ this.consume(112 /* OperatorHash */, "Expected '#' in Seek statement");
950
1011
  const fileNumber = this.parseExpression();
951
- this.consume(126 /* OperatorComma */, "Expected ',' in Seek statement");
1012
+ this.consume(127 /* OperatorComma */, "Expected ',' in Seek statement");
952
1013
  const position = this.parseExpression();
953
1014
  return { type: "SeekStatement", fileNumber, position };
954
1015
  }
@@ -985,15 +1046,16 @@ var Parser = class _Parser {
985
1046
  aliasName = this.advance().value.replace(/^"|"$/g, "");
986
1047
  }
987
1048
  let parameters = [];
988
- if (this.peek().type === 127 /* OperatorLParen */) {
1049
+ if (this.peek().type === 128 /* OperatorLParen */) {
989
1050
  this.advance();
990
- while (this.peek().type !== 128 /* OperatorRParen */ && this.peek().type !== 136 /* EOF */) {
1051
+ while (this.peek().type !== 129 /* OperatorRParen */ && this.peek().type !== 137 /* EOF */) {
991
1052
  parameters.push(this.parseParameter());
992
- if (this.peek().type === 126 /* OperatorComma */) {
1053
+ if (this.peek().type === 127 /* OperatorComma */) {
993
1054
  this.advance();
994
1055
  }
995
1056
  }
996
- this.consume(128 /* OperatorRParen */, "Expected ')' after declare parameters");
1057
+ this.consume(129 /* OperatorRParen */, "Expected ')' after declare parameters");
1058
+ this.validateParameterOrder(parameters);
997
1059
  }
998
1060
  let returnType;
999
1061
  if (!isSub) {
@@ -1030,7 +1092,7 @@ var Parser = class _Parser {
1030
1092
  // argument starters). When one of these follows a greedily-parsed CallExpression in a
1031
1093
  // statement context, it signals that the `(args)` was actually part of the argument expression.
1032
1094
  isBinaryOnlyOperator(type) {
1033
- return type === 114 /* OperatorMultiply */ || type === 115 /* OperatorDivide */ || type === 116 /* OperatorIntDivide */ || type === 119 /* OperatorPower */ || type === 112 /* OperatorPlus */ || type === 113 /* OperatorMinus */ || type === 117 /* OperatorAmpersand */ || type === 121 /* OperatorNotEquals */ || type === 122 /* OperatorLessThan */ || type === 123 /* OperatorGreaterThan */ || type === 124 /* OperatorLessThanOrEqual */ || type === 125 /* OperatorGreaterThanOrEqual */ || type === 118 /* KeywordMod */;
1095
+ return type === 115 /* OperatorMultiply */ || type === 116 /* OperatorDivide */ || type === 117 /* OperatorIntDivide */ || type === 120 /* OperatorPower */ || type === 113 /* OperatorPlus */ || type === 114 /* OperatorMinus */ || type === 118 /* OperatorAmpersand */ || type === 122 /* OperatorNotEquals */ || type === 123 /* OperatorLessThan */ || type === 124 /* OperatorGreaterThan */ || type === 125 /* OperatorLessThanOrEqual */ || type === 126 /* OperatorGreaterThanOrEqual */ || type === 119 /* KeywordMod */;
1034
1096
  }
1035
1097
  // Returns true if there is whitespace between the previous token and the current token (same line).
1036
1098
  // Used to distinguish `Foo(arg)` (no space = function-call postfix) from
@@ -1044,7 +1106,7 @@ var Parser = class _Parser {
1044
1106
  }
1045
1107
  isAtTerminator() {
1046
1108
  const type = this.peek().type;
1047
- return type === 135 /* Newline */ || type === 136 /* EOF */ || type === 130 /* OperatorColon */;
1109
+ return type === 136 /* Newline */ || type === 137 /* EOF */ || type === 131 /* OperatorColon */;
1048
1110
  }
1049
1111
  consume(expectedType, message) {
1050
1112
  if (this.peek().type === expectedType) {
@@ -1053,7 +1115,7 @@ var Parser = class _Parser {
1053
1115
  this.throwError(`Parse error at line ${this.peek().line}: ${message}`);
1054
1116
  }
1055
1117
  skipNewlines() {
1056
- while (this.match(135 /* Newline */)) {
1118
+ while (this.match(136 /* Newline */)) {
1057
1119
  }
1058
1120
  }
1059
1121
  // Build a SourceLocation spanning from start token to end token (inclusive).
@@ -1091,7 +1153,7 @@ var Parser = class _Parser {
1091
1153
  diagnostics: this._diagnostics
1092
1154
  };
1093
1155
  this.skipNewlines();
1094
- while (this.peek().type !== 136 /* EOF */) {
1156
+ while (this.peek().type !== 137 /* EOF */) {
1095
1157
  const startPos = this.pos;
1096
1158
  const startToken = this.peek();
1097
1159
  try {
@@ -1110,7 +1172,7 @@ var Parser = class _Parser {
1110
1172
  }
1111
1173
  this.syncToNextTopLevelStatement();
1112
1174
  }
1113
- if (this.pos === startPos && this.peek().type !== 136 /* EOF */) {
1175
+ if (this.pos === startPos && this.peek().type !== 137 /* EOF */) {
1114
1176
  if (this.isAtEndTerminator()) {
1115
1177
  this.advance();
1116
1178
  this.advance();
@@ -1154,7 +1216,7 @@ var Parser = class _Parser {
1154
1216
  */
1155
1217
  parseIdentifierOrCallStatement() {
1156
1218
  const token = this.peek();
1157
- if ((token.type === 0 /* Identifier */ || _Parser.CONTEXTUAL_KW.has(token.type)) && this.pos + 1 < this.tokens.length && this.tokens[this.pos + 1].type === 130 /* OperatorColon */) {
1219
+ if ((token.type === 0 /* Identifier */ || _Parser.CONTEXTUAL_KW.has(token.type)) && this.pos + 1 < this.tokens.length && this.tokens[this.pos + 1].type === 131 /* OperatorColon */) {
1158
1220
  const labelName = token.value;
1159
1221
  this.advance();
1160
1222
  this.advance();
@@ -1163,12 +1225,12 @@ var Parser = class _Parser {
1163
1225
  if (token.type === 1 /* Number */) {
1164
1226
  const labelName = token.value;
1165
1227
  this.advance();
1166
- this.match(130 /* OperatorColon */);
1228
+ this.match(131 /* OperatorColon */);
1167
1229
  return { type: "LabelStatement", label: labelName };
1168
1230
  }
1169
1231
  const savedPos = this.pos;
1170
1232
  const expr = this.parsePrimary();
1171
- if (this.match(120 /* OperatorEquals */)) {
1233
+ if (this.match(121 /* OperatorEquals */)) {
1172
1234
  return {
1173
1235
  type: "AssignmentStatement",
1174
1236
  left: expr,
@@ -1182,15 +1244,15 @@ var Parser = class _Parser {
1182
1244
  true
1183
1245
  );
1184
1246
  const args2 = [this.parseCallArgument()];
1185
- while (this.match(126 /* OperatorComma */)) {
1247
+ while (this.match(127 /* OperatorComma */)) {
1186
1248
  args2.push(this.parseCallArgument());
1187
1249
  }
1188
1250
  return { type: "CallStatement", expression: { type: "CallExpression", callee, args: args2 } };
1189
1251
  }
1190
1252
  const args = [];
1191
- if (this.peek().type !== 135 /* Newline */ && this.peek().type !== 136 /* EOF */ && this.peek().type !== 9 /* KeywordElse */ && this.peek().type !== 8 /* KeywordElseIf */ && this.peek().type !== 10 /* KeywordEnd */ && this.peek().type !== 5 /* KeywordNext */ && this.peek().type !== 14 /* KeywordLoop */) {
1253
+ if (this.peek().type !== 136 /* Newline */ && this.peek().type !== 137 /* EOF */ && this.peek().type !== 9 /* KeywordElse */ && this.peek().type !== 8 /* KeywordElseIf */ && this.peek().type !== 10 /* KeywordEnd */ && this.peek().type !== 5 /* KeywordNext */ && this.peek().type !== 14 /* KeywordLoop */) {
1192
1254
  args.push(this.parseCallArgument());
1193
- while (this.match(126 /* OperatorComma */)) {
1255
+ while (this.match(127 /* OperatorComma */)) {
1194
1256
  args.push(this.parseCallArgument());
1195
1257
  }
1196
1258
  }
@@ -1210,7 +1272,7 @@ var Parser = class _Parser {
1210
1272
  }
1211
1273
  parseStatementInner() {
1212
1274
  const token = this.peek();
1213
- if (_Parser.CONTEXTUAL_KW.has(token.type) && this.pos + 1 < this.tokens.length && this.tokens[this.pos + 1].type === 130 /* OperatorColon */) {
1275
+ if (_Parser.CONTEXTUAL_KW.has(token.type) && this.pos + 1 < this.tokens.length && this.tokens[this.pos + 1].type === 131 /* OperatorColon */) {
1214
1276
  const labelName = token.value;
1215
1277
  this.advance();
1216
1278
  this.advance();
@@ -1259,7 +1321,7 @@ var Parser = class _Parser {
1259
1321
  return this.parseDoWhileStatement();
1260
1322
  } else if (token.type === 12 /* KeywordWhile */) {
1261
1323
  return this.parseWhileStatement();
1262
- } else if (token.type === 17 /* KeywordSub */ || token.type === 18 /* KeywordFunction */ || token.type === 19 /* KeywordProperty */ && this.peek(1).type !== 120 /* OperatorEquals */) {
1324
+ } else if (token.type === 17 /* KeywordSub */ || token.type === 18 /* KeywordFunction */ || token.type === 19 /* KeywordProperty */ && this.peek(1).type !== 121 /* OperatorEquals */) {
1263
1325
  return this.parseProcedureDeclaration();
1264
1326
  } else if (token.type === 68 /* KeywordStatic */) {
1265
1327
  this.advance();
@@ -1298,13 +1360,15 @@ var Parser = class _Parser {
1298
1360
  } else {
1299
1361
  return this.parseOnGoToSubStatement();
1300
1362
  }
1301
- } else if (token.type === 35 /* KeywordError */ && this.peek(1).type !== 120 /* OperatorEquals */) {
1363
+ } else if (token.type === 35 /* KeywordError */ && this.peek(1).type !== 121 /* OperatorEquals */) {
1302
1364
  return this.parseErrorStatement();
1303
1365
  } else if (token.type === 37 /* KeywordGoSub */) {
1304
1366
  return this.parseGoSubStatement();
1305
1367
  } else if (token.type === 38 /* KeywordReturn */) {
1306
1368
  this.advance();
1307
1369
  return { type: "ReturnStatement" };
1370
+ } else if (token.type === 108 /* KeywordMid */ && this.hasMidAssignmentAhead()) {
1371
+ return this.parseMidStatement();
1308
1372
  } else if (token.type === 39 /* KeywordLSet */) {
1309
1373
  return this.parseLSetStatement();
1310
1374
  } else if (token.type === 40 /* KeywordRSet */) {
@@ -1319,9 +1383,9 @@ var Parser = class _Parser {
1319
1383
  return this.parseResumeStatement();
1320
1384
  } else if (token.type === 105 /* KeywordImplements */) {
1321
1385
  return this.parseImplementsDirective();
1322
- } else if (token.type === 106 /* KeywordAppActivate */ && this.peek(1).type !== 120 /* OperatorEquals */) {
1386
+ } else if (token.type === 106 /* KeywordAppActivate */ && this.peek(1).type !== 121 /* OperatorEquals */) {
1323
1387
  return this.parseAppActivateStatement();
1324
- } else if (token.type === 107 /* KeywordSendKeys */ && this.peek(1).type !== 120 /* OperatorEquals */) {
1388
+ } else if (token.type === 107 /* KeywordSendKeys */ && this.peek(1).type !== 121 /* OperatorEquals */) {
1325
1389
  return this.parseSendKeysStatement();
1326
1390
  } else if (token.type === 29 /* KeywordOption */) {
1327
1391
  this.advance();
@@ -1344,6 +1408,8 @@ var Parser = class _Parser {
1344
1408
  return { type: "OptionPrivateModuleStatement" };
1345
1409
  }
1346
1410
  return null;
1411
+ } else if (token.type === 111 /* KeywordDef */) {
1412
+ return this.parseDefDirective();
1347
1413
  } else if (token.type === 74 /* KeywordAttribute */) {
1348
1414
  return this.parseAttributeStatement();
1349
1415
  } else if (token.type === 75 /* KeywordDeclare */) {
@@ -1360,13 +1426,13 @@ var Parser = class _Parser {
1360
1426
  return this.parseOpenStatement();
1361
1427
  } else if (token.type === 82 /* KeywordClose */) {
1362
1428
  return this.parseCloseStatement();
1363
- } else if (token.type === 83 /* KeywordLine */ && this.peek(1).type !== 120 /* OperatorEquals */) {
1429
+ } else if (token.type === 83 /* KeywordLine */ && this.peek(1).type !== 121 /* OperatorEquals */) {
1364
1430
  return this.parseLineInputStatement();
1365
1431
  } else if (token.type === 85 /* KeywordPrint */) {
1366
1432
  return this.parsePrintStatement();
1367
1433
  } else if (token.type === 86 /* KeywordPut */) {
1368
1434
  return this.parsePutStatement();
1369
- } else if (token.type === 20 /* KeywordGet */ && this.peek(1).type === 111 /* OperatorHash */) {
1435
+ } else if (token.type === 20 /* KeywordGet */ && this.peek(1).type === 112 /* OperatorHash */) {
1370
1436
  return this.parseGetStatement();
1371
1437
  } else if (token.type === 84 /* KeywordInput */) {
1372
1438
  return this.parseInputStatement();
@@ -1374,9 +1440,9 @@ var Parser = class _Parser {
1374
1440
  return this.parseWriteStatement();
1375
1441
  } else if (token.type === 98 /* KeywordSeek */) {
1376
1442
  return this.parseSeekStatement();
1377
- } else if (token.type === 99 /* KeywordReset */ && this.peek(1).type !== 120 /* OperatorEquals */) {
1443
+ } else if (token.type === 99 /* KeywordReset */ && this.peek(1).type !== 121 /* OperatorEquals */) {
1378
1444
  return this.parseResetStatement();
1379
- } else if (token.type === 97 /* KeywordKill */ && this.peek(1).type !== 120 /* OperatorEquals */) {
1445
+ } else if (token.type === 97 /* KeywordKill */ && this.peek(1).type !== 121 /* OperatorEquals */) {
1380
1446
  return this.parseKillStatement();
1381
1447
  } else if (token.type === 102 /* KeywordEvent */) {
1382
1448
  return this.parseEventDeclaration();
@@ -1386,9 +1452,9 @@ var Parser = class _Parser {
1386
1452
  return this.parseLockStatement();
1387
1453
  } else if (token.type === 100 /* KeywordUnlock */) {
1388
1454
  return this.parseUnlockStatement();
1389
- } else if (token.type === 109 /* KeywordWidth */ && this.peek(1).type === 111 /* OperatorHash */) {
1455
+ } else if (token.type === 109 /* KeywordWidth */ && this.peek(1).type === 112 /* OperatorHash */) {
1390
1456
  return this.parseWidthStatement();
1391
- } else if (token.type === 69 /* KeywordClass */ && this.peek(1).type !== 120 /* OperatorEquals */) {
1457
+ } else if (token.type === 69 /* KeywordClass */ && this.peek(1).type !== 121 /* OperatorEquals */) {
1392
1458
  return this.parseClassDeclaration();
1393
1459
  } else if (token.type === 33 /* KeywordCall */) {
1394
1460
  this.advance();
@@ -1399,9 +1465,9 @@ var Parser = class _Parser {
1399
1465
  return { type: "CallStatement", expression: { type: "CallExpression", callee: expr, args: [] } };
1400
1466
  }
1401
1467
  this.throwError(`Parse error: Expected procedure call after 'Call'`);
1402
- } else if (token.type === 0 /* Identifier */ || token.type === 138 /* ForeignName */ || token.type === 129 /* OperatorDot */ || token.type === 70 /* KeywordMe */ || token.type === 1 /* Number */ || _Parser.CONTEXTUAL_KW.has(token.type) || _Parser.COMPAT_KW_EXPR.has(token.type)) {
1468
+ } else if (token.type === 0 /* Identifier */ || token.type === 139 /* ForeignName */ || token.type === 130 /* OperatorDot */ || token.type === 70 /* KeywordMe */ || token.type === 1 /* Number */ || _Parser.CONTEXTUAL_KW.has(token.type) || _Parser.COMPAT_KW_EXPR.has(token.type)) {
1403
1469
  return this.parseIdentifierOrCallStatement();
1404
- } else if (token.type === 137 /* Unknown */) {
1470
+ } else if (token.type === 138 /* Unknown */) {
1405
1471
  this.throwError(`Parse error: Unknown token '${this.tokenDisplay(token.value)}' at line ${token.line}`);
1406
1472
  } else {
1407
1473
  this.advance();
@@ -1432,20 +1498,21 @@ var Parser = class _Parser {
1432
1498
  const name = this.makeIdentifier(idToken);
1433
1499
  const parameters = [];
1434
1500
  let paramsEndColumn;
1435
- if (this.match(127 /* OperatorLParen */)) {
1436
- if (this.peek().type !== 128 /* OperatorRParen */) {
1501
+ if (this.match(128 /* OperatorLParen */)) {
1502
+ if (this.peek().type !== 129 /* OperatorRParen */) {
1437
1503
  parameters.push(this.parseParameter());
1438
- while (this.match(126 /* OperatorComma */)) {
1504
+ while (this.match(127 /* OperatorComma */)) {
1439
1505
  parameters.push(this.parseParameter());
1440
1506
  }
1441
1507
  }
1442
- const rParen = this.consume(128 /* OperatorRParen */, "Expected ')' after procedure parameters");
1508
+ const rParen = this.consume(129 /* OperatorRParen */, "Expected ')' after procedure parameters");
1443
1509
  paramsEndColumn = rParen.column + 1;
1510
+ this.validateParameterOrder(parameters);
1444
1511
  }
1445
1512
  let returnType;
1446
1513
  if (this.match(23 /* KeywordAs */)) {
1447
1514
  returnType = this.advance().value;
1448
- if (this.peek().type === 129 /* OperatorDot */) {
1515
+ if (this.peek().type === 130 /* OperatorDot */) {
1449
1516
  this.advance();
1450
1517
  returnType += "." + this.advance().value;
1451
1518
  }
@@ -1457,7 +1524,7 @@ var Parser = class _Parser {
1457
1524
  this.skipNewlines();
1458
1525
  const body = [];
1459
1526
  const expectedEndStr = isFunction ? "Function" : isProperty ? "Property" : "Sub";
1460
- while (!this.isAtEndTerminator() && this.peek().type !== 136 /* EOF */) {
1527
+ while (!this.isAtEndTerminator() && this.peek().type !== 137 /* EOF */) {
1461
1528
  const stmt = this.parseStatement();
1462
1529
  if (stmt) body.push(stmt);
1463
1530
  this.skipNewlines();
@@ -1468,7 +1535,7 @@ var Parser = class _Parser {
1468
1535
  if (endToken.value.toLowerCase() !== expectedEndStr.toLowerCase()) {
1469
1536
  this.throwError(`Parse error: Expected '${expectedEndStr}' after 'End' at line ${endToken.line}`);
1470
1537
  }
1471
- } else if (this.peek().type === 136 /* EOF */) {
1538
+ } else if (this.peek().type === 137 /* EOF */) {
1472
1539
  this.throwError(`Parse error: Expected 'End ${expectedEndStr}'`);
1473
1540
  }
1474
1541
  return { type: "ProcedureDeclaration", isFunction, isProperty, propertyType, name, parameters, returnType, body, scope: scope || "public", isStatic, paramsEndColumn };
@@ -1491,9 +1558,9 @@ var Parser = class _Parser {
1491
1558
  let isNew = false;
1492
1559
  let objectType;
1493
1560
  let arrayEndColumn;
1494
- if (this.match(127 /* OperatorLParen */)) {
1561
+ if (this.match(128 /* OperatorLParen */)) {
1495
1562
  isArray = true;
1496
- if (this.peek().type !== 128 /* OperatorRParen */) {
1563
+ if (this.peek().type !== 129 /* OperatorRParen */) {
1497
1564
  arrayBounds = [];
1498
1565
  while (true) {
1499
1566
  let lower;
@@ -1503,13 +1570,13 @@ var Parser = class _Parser {
1503
1570
  upper = this.parseExpression();
1504
1571
  }
1505
1572
  arrayBounds.push({ lower, upper });
1506
- if (!this.match(126 /* OperatorComma */)) {
1573
+ if (!this.match(127 /* OperatorComma */)) {
1507
1574
  break;
1508
1575
  }
1509
1576
  }
1510
1577
  }
1511
1578
  const rParenTok = this.peek();
1512
- if (this.match(128 /* OperatorRParen */)) {
1579
+ if (this.match(129 /* OperatorRParen */)) {
1513
1580
  arrayEndColumn = rParenTok.column + 1;
1514
1581
  }
1515
1582
  }
@@ -1520,14 +1587,14 @@ var Parser = class _Parser {
1520
1587
  const typeToken = this.peek();
1521
1588
  if (this.isNameToken(typeToken)) {
1522
1589
  objectType = this.advance().value;
1523
- if (this.peek().type === 129 /* OperatorDot */) {
1590
+ if (this.peek().type === 130 /* OperatorDot */) {
1524
1591
  this.advance();
1525
1592
  objectType += "." + this.advance().value;
1526
1593
  }
1527
1594
  }
1528
1595
  }
1529
1596
  declarations.push({ name, isArray, arrayBounds, isNew, isWithEvents, objectType, arrayEndColumn });
1530
- if (this.match(126 /* OperatorComma */)) {
1597
+ if (this.match(127 /* OperatorComma */)) {
1531
1598
  continue;
1532
1599
  } else {
1533
1600
  break;
@@ -1543,14 +1610,14 @@ var Parser = class _Parser {
1543
1610
  if (this.match(23 /* KeywordAs */)) {
1544
1611
  this.advance();
1545
1612
  }
1546
- if (!this.match(120 /* OperatorEquals */)) this.throwError(`Parse error: Expected '=' in Const at line ${this.peek().line}`);
1613
+ if (!this.match(121 /* OperatorEquals */)) this.throwError(`Parse error: Expected '=' in Const at line ${this.peek().line}`);
1547
1614
  const value = this.parseExpression();
1548
1615
  return { type: "ConstDeclaration", name, value };
1549
1616
  }
1550
1617
  parseSetStatement() {
1551
1618
  this.advance();
1552
1619
  const left = this.parsePrimary();
1553
- if (!this.match(120 /* OperatorEquals */)) this.throwError(`Parse error: Expected '=' in Set statement at line ${this.peek().line}`);
1620
+ if (!this.match(121 /* OperatorEquals */)) this.throwError(`Parse error: Expected '=' in Set statement at line ${this.peek().line}`);
1554
1621
  const right = this.parseExpression();
1555
1622
  return { type: "SetStatement", left, right };
1556
1623
  }
@@ -1562,7 +1629,7 @@ var Parser = class _Parser {
1562
1629
  const labelToken = this.advance();
1563
1630
  label = labelToken.value;
1564
1631
  } else {
1565
- while (this.peek().type !== 135 /* Newline */ && this.peek().type !== 136 /* EOF */) {
1632
+ while (this.peek().type !== 136 /* Newline */ && this.peek().type !== 137 /* EOF */) {
1566
1633
  label += this.advance().value + " ";
1567
1634
  }
1568
1635
  label = label.trim();
@@ -1599,7 +1666,7 @@ var Parser = class _Parser {
1599
1666
  parseResumeStatement() {
1600
1667
  this.advance();
1601
1668
  let target = "";
1602
- while (this.peek().type !== 135 /* Newline */ && this.peek().type !== 136 /* EOF */) {
1669
+ while (this.peek().type !== 136 /* Newline */ && this.peek().type !== 137 /* EOF */) {
1603
1670
  target += this.advance().value;
1604
1671
  }
1605
1672
  return { type: "ResumeStatement", target: target.trim() };
@@ -1620,8 +1687,8 @@ var Parser = class _Parser {
1620
1687
  const idToken = this.advance();
1621
1688
  const name = this.makeIdentifier(idToken);
1622
1689
  const bounds = [];
1623
- if (this.match(127 /* OperatorLParen */)) {
1624
- if (this.peek().type !== 128 /* OperatorRParen */) {
1690
+ if (this.match(128 /* OperatorLParen */)) {
1691
+ if (this.peek().type !== 129 /* OperatorRParen */) {
1625
1692
  while (true) {
1626
1693
  let lower;
1627
1694
  let upper = this.parseExpression();
@@ -1630,12 +1697,12 @@ var Parser = class _Parser {
1630
1697
  upper = this.parseExpression();
1631
1698
  }
1632
1699
  bounds.push({ lower, upper });
1633
- if (!this.match(126 /* OperatorComma */)) {
1700
+ if (!this.match(127 /* OperatorComma */)) {
1634
1701
  break;
1635
1702
  }
1636
1703
  }
1637
1704
  }
1638
- this.match(128 /* OperatorRParen */);
1705
+ this.match(129 /* OperatorRParen */);
1639
1706
  }
1640
1707
  let objectType;
1641
1708
  if (this.match(23 /* KeywordAs */)) {
@@ -1652,18 +1719,18 @@ var Parser = class _Parser {
1652
1719
  const typeName = nameToken.value;
1653
1720
  const members = [];
1654
1721
  this.skipNewlines();
1655
- while (this.peek().type !== 10 /* KeywordEnd */ && this.peek().type !== 136 /* EOF */) {
1722
+ while (this.peek().type !== 10 /* KeywordEnd */ && this.peek().type !== 137 /* EOF */) {
1656
1723
  const memberNameToken = this.advance();
1657
1724
  if (!this.isWordToken(memberNameToken)) {
1658
1725
  this.throwError(`Parse error: Expected member name in Type at line ${memberNameToken.line}`);
1659
1726
  }
1660
- if (this.peek().type === 127 /* OperatorLParen */) {
1727
+ if (this.peek().type === 128 /* OperatorLParen */) {
1661
1728
  this.advance();
1662
1729
  let depth = 1;
1663
- while (depth > 0 && this.peek().type !== 136 /* EOF */ && this.peek().type !== 135 /* Newline */) {
1730
+ while (depth > 0 && this.peek().type !== 137 /* EOF */ && this.peek().type !== 136 /* Newline */) {
1664
1731
  const t = this.advance();
1665
- if (t.type === 127 /* OperatorLParen */) depth++;
1666
- else if (t.type === 128 /* OperatorRParen */) depth--;
1732
+ if (t.type === 128 /* OperatorLParen */) depth++;
1733
+ else if (t.type === 129 /* OperatorRParen */) depth--;
1667
1734
  }
1668
1735
  }
1669
1736
  if (!this.match(23 /* KeywordAs */)) {
@@ -1690,14 +1757,14 @@ var Parser = class _Parser {
1690
1757
  const name = this.makeIdentifier(nameToken);
1691
1758
  const members = [];
1692
1759
  this.skipNewlines();
1693
- while (this.peek().type !== 10 /* KeywordEnd */ && this.peek().type !== 136 /* EOF */) {
1760
+ while (this.peek().type !== 10 /* KeywordEnd */ && this.peek().type !== 137 /* EOF */) {
1694
1761
  const memberNameToken = this.advance();
1695
1762
  if (!this.isWordToken(memberNameToken)) {
1696
1763
  this.throwError(`Parse error: Expected member name in Enum at line ${memberNameToken.line}`);
1697
1764
  }
1698
1765
  const memberName = this.makeIdentifier(memberNameToken);
1699
1766
  let value;
1700
- if (this.match(120 /* OperatorEquals */)) {
1767
+ if (this.match(121 /* OperatorEquals */)) {
1701
1768
  value = this.parseExpression();
1702
1769
  }
1703
1770
  members.push({ name: memberName, value });
@@ -1724,12 +1791,12 @@ var Parser = class _Parser {
1724
1791
  const procedures = [];
1725
1792
  const body = [];
1726
1793
  this.skipNewlines();
1727
- while (this.peek().type !== 136 /* EOF */) {
1794
+ while (this.peek().type !== 137 /* EOF */) {
1728
1795
  if (untilEndClass && this.peek().type === 10 /* KeywordEnd */ && this.peek(1).type === 69 /* KeywordClass */) {
1729
1796
  break;
1730
1797
  }
1731
1798
  const tok = this.peek();
1732
- if (tok.type === 135 /* Newline */) {
1799
+ if (tok.type === 136 /* Newline */) {
1733
1800
  this.skipNewlines();
1734
1801
  continue;
1735
1802
  }
@@ -1793,7 +1860,7 @@ var Parser = class _Parser {
1793
1860
  this.throwError(`Parse error: Expected identifier after 'For' at line ${idToken.line} `);
1794
1861
  }
1795
1862
  const identifier = this.makeIdentifier(idToken);
1796
- if (!this.match(120 /* OperatorEquals */)) {
1863
+ if (!this.match(121 /* OperatorEquals */)) {
1797
1864
  this.throwError(`Parse error: Expected '=' in For statement at line ${this.peek().line} `);
1798
1865
  }
1799
1866
  const startExpr = this.parseExpression();
@@ -1807,7 +1874,7 @@ var Parser = class _Parser {
1807
1874
  }
1808
1875
  this.skipNewlines();
1809
1876
  const body = [];
1810
- while (this.peek().type !== 5 /* KeywordNext */ && this.peek().type !== 136 /* EOF */ && !this.isAtEndTerminator()) {
1877
+ while (this.peek().type !== 5 /* KeywordNext */ && this.peek().type !== 137 /* EOF */ && !this.isAtEndTerminator()) {
1811
1878
  const stmt = this.parseStatement();
1812
1879
  if (stmt) body.push(stmt);
1813
1880
  this.skipNewlines();
@@ -1849,7 +1916,7 @@ var Parser = class _Parser {
1849
1916
  const collection = this.parseExpression();
1850
1917
  this.skipNewlines();
1851
1918
  const body = [];
1852
- while (this.peek().type !== 5 /* KeywordNext */ && this.peek().type !== 136 /* EOF */ && !this.isAtEndTerminator()) {
1919
+ while (this.peek().type !== 5 /* KeywordNext */ && this.peek().type !== 137 /* EOF */ && !this.isAtEndTerminator()) {
1853
1920
  const stmt = this.parseStatement();
1854
1921
  if (stmt) body.push(stmt);
1855
1922
  this.skipNewlines();
@@ -1882,18 +1949,18 @@ var Parser = class _Parser {
1882
1949
  if (!this.match(7 /* KeywordThen */)) {
1883
1950
  this.throwError(`Parse error: Expected 'Then' after condition at line ${this.peek().line}`);
1884
1951
  }
1885
- const isMultiLine = this.peek().type === 135 /* Newline */;
1952
+ const isMultiLine = this.peek().type === 136 /* Newline */;
1886
1953
  const consequent = [];
1887
1954
  let alternate = null;
1888
1955
  if (!isMultiLine) {
1889
- while (this.peek().type !== 135 /* Newline */ && this.peek().type !== 136 /* EOF */ && this.peek().type !== 9 /* KeywordElse */) {
1956
+ while (this.peek().type !== 136 /* Newline */ && this.peek().type !== 137 /* EOF */ && this.peek().type !== 9 /* KeywordElse */) {
1890
1957
  const stmt = this.parseStatement(false);
1891
1958
  if (stmt) consequent.push(stmt);
1892
1959
  }
1893
1960
  if (this.peek().type === 9 /* KeywordElse */) {
1894
1961
  this.advance();
1895
1962
  alternate = [];
1896
- while (this.peek().type !== 135 /* Newline */ && this.peek().type !== 136 /* EOF */) {
1963
+ while (this.peek().type !== 136 /* Newline */ && this.peek().type !== 137 /* EOF */) {
1897
1964
  const stmt = this.parseStatement(false);
1898
1965
  if (stmt) alternate.push(stmt);
1899
1966
  }
@@ -1906,7 +1973,7 @@ var Parser = class _Parser {
1906
1973
  };
1907
1974
  }
1908
1975
  this.skipNewlines();
1909
- while (!this.isAtEndTerminator() && this.peek().type !== 9 /* KeywordElse */ && this.peek().type !== 8 /* KeywordElseIf */ && this.peek().type !== 136 /* EOF */) {
1976
+ while (!this.isAtEndTerminator() && this.peek().type !== 9 /* KeywordElse */ && this.peek().type !== 8 /* KeywordElseIf */ && this.peek().type !== 137 /* EOF */) {
1910
1977
  const stmt = this.parseStatement();
1911
1978
  if (stmt) consequent.push(stmt);
1912
1979
  this.skipNewlines();
@@ -1916,7 +1983,7 @@ var Parser = class _Parser {
1916
1983
  } else if (this.match(9 /* KeywordElse */)) {
1917
1984
  this.skipNewlines();
1918
1985
  alternate = [];
1919
- while (!this.isAtEndTerminator() && this.peek().type !== 136 /* EOF */) {
1986
+ while (!this.isAtEndTerminator() && this.peek().type !== 137 /* EOF */) {
1920
1987
  const stmt = this.parseStatement();
1921
1988
  if (stmt) alternate.push(stmt);
1922
1989
  this.skipNewlines();
@@ -1953,7 +2020,7 @@ var Parser = class _Parser {
1953
2020
  }
1954
2021
  this.skipNewlines();
1955
2022
  const body = [];
1956
- while (this.peek().type !== 14 /* KeywordLoop */ && this.peek().type !== 136 /* EOF */ && !this.isAtEndTerminator()) {
2023
+ while (this.peek().type !== 14 /* KeywordLoop */ && this.peek().type !== 137 /* EOF */ && !this.isAtEndTerminator()) {
1957
2024
  const stmt = this.parseStatement();
1958
2025
  if (stmt) body.push(stmt);
1959
2026
  this.skipNewlines();
@@ -1985,7 +2052,7 @@ var Parser = class _Parser {
1985
2052
  const condition = this.parseExpression();
1986
2053
  this.skipNewlines();
1987
2054
  const body = [];
1988
- while (this.peek().type !== 13 /* KeywordWend */ && this.peek().type !== 136 /* EOF */ && !this.isAtEndTerminator()) {
2055
+ while (this.peek().type !== 13 /* KeywordWend */ && this.peek().type !== 137 /* EOF */ && !this.isAtEndTerminator()) {
1989
2056
  const stmt = this.parseStatement();
1990
2057
  if (stmt) body.push(stmt);
1991
2058
  this.skipNewlines();
@@ -2004,7 +2071,7 @@ var Parser = class _Parser {
2004
2071
  this.skipNewlines();
2005
2072
  const cases = [];
2006
2073
  let elseBody = null;
2007
- while (!this.isAtEndTerminator() && this.peek().type !== 136 /* EOF */) {
2074
+ while (!this.isAtEndTerminator() && this.peek().type !== 137 /* EOF */) {
2008
2075
  if (this.peek().type !== 54 /* KeywordCase */) {
2009
2076
  this.throwError(`Parse error: Expected 'Case' in Select Case at line ${this.peek().line}`);
2010
2077
  }
@@ -2013,7 +2080,7 @@ var Parser = class _Parser {
2013
2080
  this.advance();
2014
2081
  this.skipNewlines();
2015
2082
  elseBody = [];
2016
- while (!this.isAtEndTerminator() && this.peek().type !== 54 /* KeywordCase */ && this.peek().type !== 136 /* EOF */) {
2083
+ while (!this.isAtEndTerminator() && this.peek().type !== 54 /* KeywordCase */ && this.peek().type !== 137 /* EOF */) {
2017
2084
  const stmt = this.parseStatement();
2018
2085
  if (stmt) elseBody.push(stmt);
2019
2086
  this.skipNewlines();
@@ -2022,12 +2089,12 @@ var Parser = class _Parser {
2022
2089
  }
2023
2090
  const ranges = [];
2024
2091
  ranges.push(this.parseRangeClause());
2025
- while (this.match(126 /* OperatorComma */)) {
2092
+ while (this.match(127 /* OperatorComma */)) {
2026
2093
  ranges.push(this.parseRangeClause());
2027
2094
  }
2028
2095
  this.skipNewlines();
2029
2096
  const body = [];
2030
- while (!this.isAtEndTerminator() && this.peek().type !== 54 /* KeywordCase */ && this.peek().type !== 136 /* EOF */) {
2097
+ while (!this.isAtEndTerminator() && this.peek().type !== 54 /* KeywordCase */ && this.peek().type !== 137 /* EOF */) {
2031
2098
  const stmt = this.parseStatement();
2032
2099
  if (stmt) body.push(stmt);
2033
2100
  this.skipNewlines();
@@ -2047,7 +2114,7 @@ var Parser = class _Parser {
2047
2114
  const expression = this.parseExpression();
2048
2115
  this.skipNewlines();
2049
2116
  const body = [];
2050
- while (!this.isAtEndTerminator() && this.peek().type !== 136 /* EOF */) {
2117
+ while (!this.isAtEndTerminator() && this.peek().type !== 137 /* EOF */) {
2051
2118
  const stmt = this.parseStatement();
2052
2119
  if (stmt) body.push(stmt);
2053
2120
  this.skipNewlines();
@@ -2064,7 +2131,7 @@ var Parser = class _Parser {
2064
2131
  const isKeyword = this.peek().type === 51 /* KeywordIs */;
2065
2132
  if (isKeyword) this.advance();
2066
2133
  const compOp = this.peek();
2067
- if (compOp.type === 120 /* OperatorEquals */ || compOp.type === 121 /* OperatorNotEquals */ || compOp.type === 122 /* OperatorLessThan */ || compOp.type === 123 /* OperatorGreaterThan */ || compOp.type === 124 /* OperatorLessThanOrEqual */ || compOp.type === 125 /* OperatorGreaterThanOrEqual */) {
2134
+ if (compOp.type === 121 /* OperatorEquals */ || compOp.type === 122 /* OperatorNotEquals */ || compOp.type === 123 /* OperatorLessThan */ || compOp.type === 124 /* OperatorGreaterThan */ || compOp.type === 125 /* OperatorLessThanOrEqual */ || compOp.type === 126 /* OperatorGreaterThanOrEqual */) {
2068
2135
  this.advance();
2069
2136
  const value = this.parseExpression();
2070
2137
  return { kind: "comparison", operator: compOp.value, value };
@@ -2144,7 +2211,7 @@ var Parser = class _Parser {
2144
2211
  }
2145
2212
  parseEquality() {
2146
2213
  let left = this.parseRelational();
2147
- while (this.peek().type === 120 /* OperatorEquals */ || this.peek().type === 121 /* OperatorNotEquals */ || this.peek().type === 51 /* KeywordIs */ || this.peek().type === 63 /* KeywordLike */) {
2214
+ while (this.peek().type === 121 /* OperatorEquals */ || this.peek().type === 122 /* OperatorNotEquals */ || this.peek().type === 51 /* KeywordIs */ || this.peek().type === 63 /* KeywordLike */) {
2148
2215
  const operator = this.advance().value;
2149
2216
  const right = this.parseRelational();
2150
2217
  left = { type: "BinaryExpression", operator, left, right, loc: this.makeBinaryLoc(left, right) };
@@ -2153,7 +2220,7 @@ var Parser = class _Parser {
2153
2220
  }
2154
2221
  parseRelational() {
2155
2222
  let left = this.parseConcatenation();
2156
- while (this.peek().type === 122 /* OperatorLessThan */ || this.peek().type === 123 /* OperatorGreaterThan */ || this.peek().type === 124 /* OperatorLessThanOrEqual */ || this.peek().type === 125 /* OperatorGreaterThanOrEqual */) {
2223
+ while (this.peek().type === 123 /* OperatorLessThan */ || this.peek().type === 124 /* OperatorGreaterThan */ || this.peek().type === 125 /* OperatorLessThanOrEqual */ || this.peek().type === 126 /* OperatorGreaterThanOrEqual */) {
2157
2224
  const operator = this.advance().value;
2158
2225
  const right = this.parseConcatenation();
2159
2226
  left = { type: "BinaryExpression", operator, left, right, loc: this.makeBinaryLoc(left, right) };
@@ -2162,7 +2229,7 @@ var Parser = class _Parser {
2162
2229
  }
2163
2230
  parseConcatenation() {
2164
2231
  let left = this.parseAdditive();
2165
- while (this.peek().type === 117 /* OperatorAmpersand */) {
2232
+ while (this.peek().type === 118 /* OperatorAmpersand */) {
2166
2233
  const operator = this.advance().value;
2167
2234
  const right = this.parseAdditive();
2168
2235
  left = { type: "BinaryExpression", operator, left, right, loc: this.makeBinaryLoc(left, right) };
@@ -2171,7 +2238,7 @@ var Parser = class _Parser {
2171
2238
  }
2172
2239
  parseAdditive() {
2173
2240
  let left = this.parseModulo();
2174
- while (this.peek().type === 112 /* OperatorPlus */ || this.peek().type === 113 /* OperatorMinus */) {
2241
+ while (this.peek().type === 113 /* OperatorPlus */ || this.peek().type === 114 /* OperatorMinus */) {
2175
2242
  const operator = this.advance().value;
2176
2243
  const right = this.parseModulo();
2177
2244
  left = { type: "BinaryExpression", operator, left, right, loc: this.makeBinaryLoc(left, right) };
@@ -2180,7 +2247,7 @@ var Parser = class _Parser {
2180
2247
  }
2181
2248
  parseModulo() {
2182
2249
  let left = this.parseIntDivision();
2183
- while (this.peek().type === 118 /* KeywordMod */) {
2250
+ while (this.peek().type === 119 /* KeywordMod */) {
2184
2251
  const operator = this.advance().value;
2185
2252
  const right = this.parseIntDivision();
2186
2253
  left = { type: "BinaryExpression", operator, left, right, loc: this.makeBinaryLoc(left, right) };
@@ -2189,7 +2256,7 @@ var Parser = class _Parser {
2189
2256
  }
2190
2257
  parseIntDivision() {
2191
2258
  let left = this.parseMultiplicative();
2192
- while (this.peek().type === 116 /* OperatorIntDivide */) {
2259
+ while (this.peek().type === 117 /* OperatorIntDivide */) {
2193
2260
  const operator = this.advance().value;
2194
2261
  const right = this.parseMultiplicative();
2195
2262
  left = { type: "BinaryExpression", operator, left, right, loc: this.makeBinaryLoc(left, right) };
@@ -2198,7 +2265,7 @@ var Parser = class _Parser {
2198
2265
  }
2199
2266
  parseMultiplicative() {
2200
2267
  let left = this.parseUnary();
2201
- while (this.peek().type === 114 /* OperatorMultiply */ || this.peek().type === 115 /* OperatorDivide */) {
2268
+ while (this.peek().type === 115 /* OperatorMultiply */ || this.peek().type === 116 /* OperatorDivide */) {
2202
2269
  const operator = this.advance().value;
2203
2270
  const right = this.parseUnary();
2204
2271
  left = { type: "BinaryExpression", operator, left, right, loc: this.makeBinaryLoc(left, right) };
@@ -2206,7 +2273,7 @@ var Parser = class _Parser {
2206
2273
  return left;
2207
2274
  }
2208
2275
  parseUnary() {
2209
- if (this.peek().type === 113 /* OperatorMinus */ || this.peek().type === 112 /* OperatorPlus */) {
2276
+ if (this.peek().type === 114 /* OperatorMinus */ || this.peek().type === 113 /* OperatorPlus */) {
2210
2277
  const opTok = this.tokens[this.pos];
2211
2278
  const operator = this.advance().value;
2212
2279
  const argument = this.parseUnary();
@@ -2218,7 +2285,7 @@ var Parser = class _Parser {
2218
2285
  }
2219
2286
  parseExponentiation() {
2220
2287
  let left = this.parsePrimary();
2221
- while (this.peek().type === 119 /* OperatorPower */) {
2288
+ while (this.peek().type === 120 /* OperatorPower */) {
2222
2289
  const operator = this.advance().value;
2223
2290
  const right = this.parsePrimary();
2224
2291
  left = { type: "BinaryExpression", operator, left, right, loc: this.makeBinaryLoc(left, right) };
@@ -2237,16 +2304,24 @@ var Parser = class _Parser {
2237
2304
  expr = { type: "NumberLiteral", value: Number(cleanVal), typeSuffix, isFloat };
2238
2305
  } else if (token.type === 2 /* String */) {
2239
2306
  expr = { type: "StringLiteral", value: token.value };
2240
- } else if (token.type === 134 /* Date */) {
2307
+ } else if (token.type === 135 /* Date */) {
2241
2308
  expr = { type: "DateLiteral", value: token.value };
2242
- } else if (token.type === 138 /* ForeignName */) {
2309
+ } else if (token.type === 139 /* ForeignName */) {
2243
2310
  expr = { type: "Identifier", name: token.value, foreign: true };
2244
2311
  } else if (token.type === 0 /* Identifier */ || _Parser.CONTEXTUAL_KW.has(token.type) || _Parser.COMPAT_KW_EXPR.has(token.type)) {
2245
2312
  expr = { type: "Identifier", name: token.value };
2246
2313
  } else if (token.type === 110 /* KeywordAddressOf */) {
2247
- const procName = this.advance();
2248
- if (!this.isIdentifier(procName)) this.throwError(`Parse error at line ${procName.line}: Expected procedure name after 'AddressOf'`);
2249
- expr = { type: "AddressOfExpression", procedureName: { type: "Identifier", name: procName.value } };
2314
+ const firstTok = this.advance();
2315
+ if (!this.isIdentifier(firstTok)) this.throwError(`Parse error at line ${firstTok.line}: Expected procedure name after 'AddressOf'`);
2316
+ let moduleName;
2317
+ let procTok = firstTok;
2318
+ if (this.peek().type === 130 /* OperatorDot */) {
2319
+ this.advance();
2320
+ moduleName = firstTok.value;
2321
+ procTok = this.advance();
2322
+ if (!this.isIdentifier(procTok)) this.throwError(`Parse error at line ${procTok.line}: Expected procedure name after 'AddressOf ${moduleName}.'`);
2323
+ }
2324
+ expr = { type: "AddressOfExpression", procedureName: { type: "Identifier", name: procTok.value }, moduleName };
2250
2325
  } else if (token.type === 44 /* KeywordEmpty */) {
2251
2326
  expr = { type: "Identifier", name: token.value };
2252
2327
  } else if (token.type === 49 /* KeywordNothing */) {
@@ -2263,14 +2338,14 @@ var Parser = class _Parser {
2263
2338
  this.throwError(`Parse error: Expected class name after 'New' at line ${classNameToken.line}`);
2264
2339
  }
2265
2340
  let className = classNameToken.value;
2266
- if (this.peek().type === 129 /* OperatorDot */) {
2341
+ if (this.peek().type === 130 /* OperatorDot */) {
2267
2342
  this.advance();
2268
2343
  className += "." + this.advance().value;
2269
2344
  }
2270
2345
  expr = { type: "NewExpression", className };
2271
- } else if (token.type === 127 /* OperatorLParen */) {
2346
+ } else if (token.type === 128 /* OperatorLParen */) {
2272
2347
  const innerExpr = this.parseExpression();
2273
- if (!this.match(128 /* OperatorRParen */)) {
2348
+ if (!this.match(129 /* OperatorRParen */)) {
2274
2349
  this.throwMissingRParen();
2275
2350
  }
2276
2351
  expr = { type: "ParenthesizedExpression", expression: innerExpr };
@@ -2284,14 +2359,14 @@ var Parser = class _Parser {
2284
2359
  this.throwError(`Parse error: Expected type name after 'Is' at line ${typeToken.line}`);
2285
2360
  }
2286
2361
  expr = { type: "TypeOfIsExpression", expression: expr, typeName: typeToken.value };
2287
- } else if (token.type === 129 /* OperatorDot */) {
2362
+ } else if (token.type === 130 /* OperatorDot */) {
2288
2363
  const propToken = this.advance();
2289
2364
  if (!this.isNameToken(propToken)) {
2290
2365
  this.throwError(`Parse error: Expected identifier after '.' at line ${propToken.line}`);
2291
2366
  }
2292
2367
  const property = { type: "Identifier", name: propToken.value };
2293
2368
  expr = { type: "ImplicitWithObjectExpression", property };
2294
- } else if (token.type === 135 /* Newline */) {
2369
+ } else if (token.type === 136 /* Newline */) {
2295
2370
  const prevToken = this.tokens[Math.max(0, this.pos - 2)];
2296
2371
  if (prevToken && this.isContinuationEndToken(prevToken.type)) {
2297
2372
  this.throwError(
@@ -2306,31 +2381,31 @@ var Parser = class _Parser {
2306
2381
  }
2307
2382
  expr.loc = this.exprLoc(startTok, this.tokens[this.pos - 1]);
2308
2383
  while (true) {
2309
- if (this.match(129 /* OperatorDot */)) {
2310
- if (this.peek().type === 136 /* EOF */) this.throwError("Expected property name after '.'");
2384
+ if (this.match(130 /* OperatorDot */)) {
2385
+ if (this.peek().type === 137 /* EOF */) this.throwError("Expected property name after '.'");
2311
2386
  const propToken = this.advance();
2312
2387
  const property = { type: "Identifier", name: propToken.value };
2313
2388
  expr = { type: "MemberExpression", object: expr, property };
2314
2389
  expr.loc = this.exprLoc(startTok, this.tokens[this.pos - 1]);
2315
- } else if (this.match(132 /* OperatorExclamation */)) {
2316
- if (this.peek().type === 136 /* EOF */) this.throwError("Expected identifier after '!'");
2390
+ } else if (this.match(133 /* OperatorExclamation */)) {
2391
+ if (this.peek().type === 137 /* EOF */) this.throwError("Expected identifier after '!'");
2317
2392
  const propToken = this.advance();
2318
2393
  const property = { type: "Identifier", name: propToken.value };
2319
2394
  expr = { type: "DictionaryAccessExpression", object: expr, property };
2320
2395
  expr.loc = this.exprLoc(startTok, this.tokens[this.pos - 1]);
2321
- } else if (this.peek().type === 127 /* OperatorLParen */) {
2396
+ } else if (this.peek().type === 128 /* OperatorLParen */) {
2322
2397
  if (stopBeforeSpacedLParen && this.hasSpaceBeforeCurrentToken()) {
2323
2398
  break;
2324
2399
  }
2325
2400
  this.advance();
2326
2401
  const args = [];
2327
- if (this.peek().type !== 128 /* OperatorRParen */) {
2402
+ if (this.peek().type !== 129 /* OperatorRParen */) {
2328
2403
  args.push(this.parseCallArgument());
2329
- while (this.match(126 /* OperatorComma */)) {
2404
+ while (this.match(127 /* OperatorComma */)) {
2330
2405
  args.push(this.parseCallArgument());
2331
2406
  }
2332
2407
  }
2333
- if (!this.match(128 /* OperatorRParen */)) {
2408
+ if (!this.match(129 /* OperatorRParen */)) {
2334
2409
  this.throwMissingRParen();
2335
2410
  }
2336
2411
  expr = { type: "CallExpression", callee: expr, args };
@@ -2344,10 +2419,10 @@ var Parser = class _Parser {
2344
2419
  // Parse a call argument, handling named arguments (e.g., shift:=xlUp)
2345
2420
  parseCallArgument() {
2346
2421
  const next = this.peek().type;
2347
- if (next === 126 /* OperatorComma */ || next === 128 /* OperatorRParen */ || this.isAtTerminator()) {
2422
+ if (next === 127 /* OperatorComma */ || next === 129 /* OperatorRParen */ || this.isAtTerminator()) {
2348
2423
  return { type: "MissingArgument" };
2349
2424
  }
2350
- if (this.pos + 1 < this.tokens.length && this.tokens[this.pos + 1].type === 131 /* OperatorColonEquals */ && typeof this.peek().value === "string" && /^[A-Za-z_]\w*$/.test(this.peek().value)) {
2425
+ if (this.pos + 1 < this.tokens.length && this.tokens[this.pos + 1].type === 132 /* OperatorColonEquals */ && typeof this.peek().value === "string" && /^[A-Za-z_]\w*$/.test(this.peek().value)) {
2351
2426
  const nameToken = this.advance();
2352
2427
  this.advance();
2353
2428
  const value = this.parseExpression();
@@ -2373,7 +2448,7 @@ var Parser = class _Parser {
2373
2448
  this.throwError(`Parse error: Expected label (identifier or number) in On...GoTo/GoSub at line ${labelToken.line}`);
2374
2449
  }
2375
2450
  labels.push(labelToken.value);
2376
- if (!this.match(126 /* OperatorComma */)) {
2451
+ if (!this.match(127 /* OperatorComma */)) {
2377
2452
  break;
2378
2453
  }
2379
2454
  }
@@ -2390,7 +2465,7 @@ var Parser = class _Parser {
2390
2465
  parseLSetStatement() {
2391
2466
  this.advance();
2392
2467
  const left = this.parsePrimary();
2393
- if (!this.match(120 /* OperatorEquals */)) {
2468
+ if (!this.match(121 /* OperatorEquals */)) {
2394
2469
  this.throwError(`Parse error: Expected '=' in LSet statement at line ${this.peek().line}`);
2395
2470
  }
2396
2471
  const right = this.parseExpression();
@@ -2399,12 +2474,45 @@ var Parser = class _Parser {
2399
2474
  parseRSetStatement() {
2400
2475
  this.advance();
2401
2476
  const left = this.parsePrimary();
2402
- if (!this.match(120 /* OperatorEquals */)) {
2477
+ if (!this.match(121 /* OperatorEquals */)) {
2403
2478
  this.throwError(`Parse error: Expected '=' in RSet statement at line ${this.peek().line}`);
2404
2479
  }
2405
2480
  const right = this.parseExpression();
2406
2481
  return { type: "RSetStatement", left, right };
2407
2482
  }
2483
+ hasMidAssignmentAhead() {
2484
+ if (this.peek(1).type !== 128 /* OperatorLParen */) return false;
2485
+ let depth = 0;
2486
+ let i = 1;
2487
+ while (this.pos + i < this.tokens.length) {
2488
+ const t = this.tokens[this.pos + i];
2489
+ if (t.type === 128 /* OperatorLParen */) depth++;
2490
+ else if (t.type === 129 /* OperatorRParen */) {
2491
+ depth--;
2492
+ if (depth === 0) {
2493
+ return this.tokens[this.pos + i + 1]?.type === 121 /* OperatorEquals */;
2494
+ }
2495
+ } else if (t.type === 136 /* Newline */ || t.type === 137 /* EOF */) break;
2496
+ i++;
2497
+ }
2498
+ return false;
2499
+ }
2500
+ parseMidStatement() {
2501
+ const midToken = this.advance();
2502
+ const isByte = midToken.value.toLowerCase().startsWith("midb");
2503
+ this.consume(128 /* OperatorLParen */, "Expected '(' after Mid");
2504
+ const target = this.parseExpression();
2505
+ this.consume(127 /* OperatorComma */, "Expected ',' after Mid target");
2506
+ const start = this.parseExpression();
2507
+ let length = null;
2508
+ if (this.match(127 /* OperatorComma */)) {
2509
+ length = this.parseExpression();
2510
+ }
2511
+ this.consume(129 /* OperatorRParen */, "Expected ')' after Mid arguments");
2512
+ this.consume(121 /* OperatorEquals */, "Expected '=' in Mid statement");
2513
+ const value = this.parseExpression();
2514
+ return { type: "MidStatement", target, start, length, value, isByte };
2515
+ }
2408
2516
  parseErrorStatement() {
2409
2517
  this.advance();
2410
2518
  const errorNumber = this.parseExpression();
@@ -2413,34 +2521,35 @@ var Parser = class _Parser {
2413
2521
  parseEventDeclaration(scope) {
2414
2522
  this.advance();
2415
2523
  const idToken = this.advance();
2416
- if (!this.isIdentifier(idToken) && !this.isNameToken(idToken)) this.throwError(`Expected identifier after 'Event' at line ${idToken.line}`);
2524
+ if (!this.isIdentifier(idToken)) this.throwError(`Expected identifier after 'Event' at line ${idToken.line}`);
2417
2525
  const name = { type: "Identifier", name: idToken.value };
2418
2526
  const parameters = [];
2419
- if (this.match(127 /* OperatorLParen */)) {
2420
- if (this.peek().type !== 128 /* OperatorRParen */) {
2527
+ if (this.match(128 /* OperatorLParen */)) {
2528
+ if (this.peek().type !== 129 /* OperatorRParen */) {
2421
2529
  parameters.push(this.parseParameter());
2422
- while (this.match(126 /* OperatorComma */)) {
2530
+ while (this.match(127 /* OperatorComma */)) {
2423
2531
  parameters.push(this.parseParameter());
2424
2532
  }
2425
2533
  }
2426
- this.consume(128 /* OperatorRParen */, "Expected ')' after event parameters");
2534
+ this.consume(129 /* OperatorRParen */, "Expected ')' after event parameters");
2535
+ this.validateParameterOrder(parameters);
2427
2536
  }
2428
2537
  return { type: "EventDeclaration", name, parameters, scope };
2429
2538
  }
2430
2539
  parseRaiseEventStatement() {
2431
2540
  this.advance();
2432
2541
  const idToken = this.advance();
2433
- if (!this.isIdentifier(idToken) && !this.isNameToken(idToken)) this.throwError(`Expected identifier after 'RaiseEvent' at line ${idToken.line}`);
2542
+ if (!this.isIdentifier(idToken)) this.throwError(`Expected identifier after 'RaiseEvent' at line ${idToken.line}`);
2434
2543
  const eventName = { type: "Identifier", name: idToken.value };
2435
2544
  const args = [];
2436
- if (this.match(127 /* OperatorLParen */)) {
2437
- if (this.peek().type !== 128 /* OperatorRParen */) {
2545
+ if (this.match(128 /* OperatorLParen */)) {
2546
+ if (this.peek().type !== 129 /* OperatorRParen */) {
2438
2547
  args.push(this.parseExpression());
2439
- while (this.match(126 /* OperatorComma */)) {
2548
+ while (this.match(127 /* OperatorComma */)) {
2440
2549
  args.push(this.parseExpression());
2441
2550
  }
2442
2551
  }
2443
- this.consume(128 /* OperatorRParen */, "Expected ')' after RaiseEvent arguments");
2552
+ this.consume(129 /* OperatorRParen */, "Expected ')' after RaiseEvent arguments");
2444
2553
  }
2445
2554
  return { type: "RaiseEventStatement", eventName, args };
2446
2555
  }
@@ -2454,7 +2563,7 @@ var Parser = class _Parser {
2454
2563
  this.advance();
2455
2564
  const title = this.parseExpression();
2456
2565
  let wait;
2457
- if (this.match(126 /* OperatorComma */)) {
2566
+ if (this.match(127 /* OperatorComma */)) {
2458
2567
  wait = this.parseExpression();
2459
2568
  }
2460
2569
  return { type: "AppActivateStatement", title, wait };
@@ -2463,17 +2572,17 @@ var Parser = class _Parser {
2463
2572
  this.advance();
2464
2573
  const keys = this.parseExpression();
2465
2574
  let wait;
2466
- if (this.match(126 /* OperatorComma */)) {
2575
+ if (this.match(127 /* OperatorComma */)) {
2467
2576
  wait = this.parseExpression();
2468
2577
  }
2469
2578
  return { type: "SendKeysStatement", keys, wait };
2470
2579
  }
2471
2580
  parseLockStatement() {
2472
2581
  this.advance();
2473
- this.match(111 /* OperatorHash */);
2582
+ this.match(112 /* OperatorHash */);
2474
2583
  const fileNumber = this.parseExpression();
2475
2584
  let recordRange;
2476
- if (this.match(126 /* OperatorComma */)) {
2585
+ if (this.match(127 /* OperatorComma */)) {
2477
2586
  const start = this.parseExpression();
2478
2587
  let end;
2479
2588
  if (this.match(4 /* KeywordTo */)) {
@@ -2485,10 +2594,10 @@ var Parser = class _Parser {
2485
2594
  }
2486
2595
  parseUnlockStatement() {
2487
2596
  this.advance();
2488
- this.match(111 /* OperatorHash */);
2597
+ this.match(112 /* OperatorHash */);
2489
2598
  const fileNumber = this.parseExpression();
2490
2599
  let recordRange;
2491
- if (this.match(126 /* OperatorComma */)) {
2600
+ if (this.match(127 /* OperatorComma */)) {
2492
2601
  const start = this.parseExpression();
2493
2602
  let end;
2494
2603
  if (this.match(4 /* KeywordTo */)) {
@@ -2500,9 +2609,9 @@ var Parser = class _Parser {
2500
2609
  }
2501
2610
  parseWidthStatement() {
2502
2611
  this.advance();
2503
- this.consume(111 /* OperatorHash */, "Expected '#' after Width");
2612
+ this.consume(112 /* OperatorHash */, "Expected '#' after Width");
2504
2613
  const fileNumber = this.parseExpression();
2505
- this.consume(126 /* OperatorComma */, "Expected ',' after file number");
2614
+ this.consume(127 /* OperatorComma */, "Expected ',' after file number");
2506
2615
  const width = this.parseExpression();
2507
2616
  return { type: "WidthStatement", fileNumber, width };
2508
2617
  }
@@ -2755,6 +2864,21 @@ function evaluateCCExpr(expr, resolve) {
2755
2864
  }
2756
2865
  return parseOr();
2757
2866
  }
2867
+ function stripVBAFileHeader(source) {
2868
+ const lines = source.split("\n");
2869
+ if (!lines[0]?.trimEnd().toUpperCase().startsWith("VERSION")) return source;
2870
+ const result = [...lines];
2871
+ let i = 0;
2872
+ result[i] = "";
2873
+ i++;
2874
+ while (i < result.length) {
2875
+ const trimmed = result[i].trimEnd().toUpperCase();
2876
+ result[i] = "";
2877
+ i++;
2878
+ if (trimmed === "END") break;
2879
+ }
2880
+ return result.join("\n");
2881
+ }
2758
2882
 
2759
2883
  // ../../test-libs/vba-analyzer.ts
2760
2884
  var fs = __toESM(require("fs"), 1);
@@ -3787,6 +3911,18 @@ function collectVarRefsInBody(stmts, writes, reads, skipVars) {
3787
3911
  collectReadsInExpr(stmt.right, reads);
3788
3912
  break;
3789
3913
  }
3914
+ case "MidStatement": {
3915
+ const w = extractWriteName(stmt.target);
3916
+ if (w && !skipVars.has(w)) {
3917
+ if (!writes.has(w)) writes.set(w, []);
3918
+ writes.get(w).push(line);
3919
+ }
3920
+ collectReadsInExpr(stmt.target, reads);
3921
+ collectReadsInExpr(stmt.start, reads);
3922
+ if (stmt.length) collectReadsInExpr(stmt.length, reads);
3923
+ collectReadsInExpr(stmt.value, reads);
3924
+ break;
3925
+ }
3790
3926
  case "ReDimStatement": {
3791
3927
  const w = stmt.name?.name?.toLowerCase() ?? null;
3792
3928
  if (w && !skipVars.has(w)) {
@@ -3959,6 +4095,12 @@ function collectWriteAttrs(stmts, targets, selfRefs, boolOnly, arrayWrites) {
3959
4095
  if (stmt.left?.type === "CallExpression") arrayWrites.add(w);
3960
4096
  }
3961
4097
  }
4098
+ if (stmt.type === "MidStatement") {
4099
+ const w = extractWriteName(stmt.target);
4100
+ if (w && targets.has(w)) {
4101
+ selfRefs.add(w);
4102
+ }
4103
+ }
3962
4104
  const sub = (s) => collectWriteAttrs(Array.isArray(s) ? s : [s], targets, selfRefs, boolOnly, arrayWrites);
3963
4105
  if (stmt.body) sub(stmt.body);
3964
4106
  if (stmt.consequent) sub(stmt.consequent);
@@ -4252,7 +4394,9 @@ function analyzeGotoInProc(proc) {
4252
4394
  };
4253
4395
  }
4254
4396
  function analyzeFile(filePath) {
4255
- const src = fs.readFileSync(filePath, "utf-8");
4397
+ const ext = path.extname(filePath).toLowerCase();
4398
+ const raw = fs.readFileSync(filePath, "utf-8");
4399
+ const src = stripVBAFileHeader(raw);
4256
4400
  const lines = src.split("\n");
4257
4401
  const warnings = [];
4258
4402
  let ast;