brighterscript 1.0.0-alpha.18 → 1.0.0-alpha.20

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 (83) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +2 -0
  3. package/bsconfig.schema.json +12 -0
  4. package/dist/BsConfig.d.ts +4 -0
  5. package/dist/DiagnosticMessages.d.ts +21 -1
  6. package/dist/DiagnosticMessages.js +27 -4
  7. package/dist/DiagnosticMessages.js.map +1 -1
  8. package/dist/PluginInterface.d.ts +4 -0
  9. package/dist/PluginInterface.js +6 -0
  10. package/dist/PluginInterface.js.map +1 -1
  11. package/dist/Program.d.ts +1 -2
  12. package/dist/Program.js +6 -2
  13. package/dist/Program.js.map +1 -1
  14. package/dist/ProgramBuilder.d.ts +4 -0
  15. package/dist/ProgramBuilder.js +13 -3
  16. package/dist/ProgramBuilder.js.map +1 -1
  17. package/dist/Scope.d.ts +5 -5
  18. package/dist/astUtils/visitors.d.ts +15 -5
  19. package/dist/astUtils/visitors.js +1 -1
  20. package/dist/astUtils/visitors.js.map +1 -1
  21. package/dist/bscPlugin/BscPlugin.d.ts +3 -1
  22. package/dist/bscPlugin/BscPlugin.js +6 -1
  23. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  24. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +25 -13
  25. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -1
  26. package/dist/bscPlugin/validation/ScopeValidator.d.ts +22 -4
  27. package/dist/bscPlugin/validation/ScopeValidator.js +102 -13
  28. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  29. package/dist/cli.js +9 -3
  30. package/dist/cli.js.map +1 -1
  31. package/dist/files/BrsFile.js +3 -1
  32. package/dist/files/BrsFile.js.map +1 -1
  33. package/dist/files/BrsFile.spec.js +45 -12
  34. package/dist/files/BrsFile.spec.js.map +1 -1
  35. package/dist/files/XmlFile.spec.js +21 -3
  36. package/dist/files/XmlFile.spec.js.map +1 -1
  37. package/dist/files/tests/optionalChaning.spec.d.ts +1 -0
  38. package/dist/files/tests/optionalChaning.spec.js +88 -0
  39. package/dist/files/tests/optionalChaning.spec.js.map +1 -0
  40. package/dist/index.d.ts +1 -0
  41. package/dist/index.js +1 -0
  42. package/dist/index.js.map +1 -1
  43. package/dist/interfaces.d.ts +4 -0
  44. package/dist/lexer/Lexer.d.ts +5 -0
  45. package/dist/lexer/Lexer.js +37 -0
  46. package/dist/lexer/Lexer.js.map +1 -1
  47. package/dist/lexer/Lexer.spec.js +62 -4
  48. package/dist/lexer/Lexer.spec.js.map +1 -1
  49. package/dist/lexer/TokenKind.d.ts +4 -0
  50. package/dist/lexer/TokenKind.js +4 -0
  51. package/dist/lexer/TokenKind.js.map +1 -1
  52. package/dist/parser/Expression.d.ts +37 -8
  53. package/dist/parser/Expression.js +26 -28
  54. package/dist/parser/Expression.js.map +1 -1
  55. package/dist/parser/Parser.d.ts +17 -0
  56. package/dist/parser/Parser.js +141 -107
  57. package/dist/parser/Parser.js.map +1 -1
  58. package/dist/parser/Parser.spec.js +83 -0
  59. package/dist/parser/Parser.spec.js.map +1 -1
  60. package/dist/parser/SGParser.js.map +1 -1
  61. package/dist/parser/SGParser.spec.js +1 -1
  62. package/dist/parser/SGParser.spec.js.map +1 -1
  63. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +1 -1
  64. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  65. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +9 -9
  66. package/dist/parser/tests/expression/TernaryExpression.spec.js +1 -1
  67. package/dist/parser/tests/statement/Enum.spec.js +66 -0
  68. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  69. package/dist/parser/tests/statement/PrintStatement.spec.js +6 -6
  70. package/dist/preprocessor/Manifest.d.ts +5 -5
  71. package/dist/preprocessor/Manifest.js +14 -35
  72. package/dist/preprocessor/Manifest.js.map +1 -1
  73. package/dist/preprocessor/Manifest.spec.d.ts +1 -0
  74. package/dist/preprocessor/Manifest.spec.js +78 -103
  75. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  76. package/dist/roku-types/data.json +21891 -0
  77. package/dist/roku-types/index.d.ts +6776 -0
  78. package/dist/roku-types/index.js +11 -0
  79. package/dist/roku-types/index.js.map +1 -0
  80. package/dist/util.d.ts +8 -5
  81. package/dist/util.js +24 -18
  82. package/dist/util.js.map +1 -1
  83. package/package.json +14 -3
@@ -1668,17 +1668,18 @@ class Parser {
1668
1668
  }
1669
1669
  indexedGet(expr) {
1670
1670
  let openingSquare = this.previous();
1671
+ let questionDotToken = this.getMatchingTokenAtOffset(-2, TokenKind_1.TokenKind.QuestionDot);
1671
1672
  while (this.match(TokenKind_1.TokenKind.Newline)) { }
1672
1673
  let index = this.expression();
1673
1674
  while (this.match(TokenKind_1.TokenKind.Newline)) { }
1674
1675
  let closingSquare = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightSquareBraceAfterArrayOrObjectIndex(), TokenKind_1.TokenKind.RightSquareBracket);
1675
- return new Expression_1.IndexedGetExpression(expr, index, openingSquare, closingSquare);
1676
+ return new Expression_1.IndexedGetExpression(expr, index, openingSquare, closingSquare, questionDotToken);
1676
1677
  }
1677
1678
  newExpression() {
1678
1679
  this.warnIfNotBrighterScriptMode(`using 'new' keyword to construct a class`);
1679
1680
  let newToken = this.advance();
1680
1681
  let nameExpr = this.getNamespacedVariableNameExpression();
1681
- let leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.LeftParen);
1682
+ let leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.QuestionLeftParen);
1682
1683
  let call = this.finishCall(leftParen, nameExpr);
1683
1684
  //pop the call from the callExpressions list because this is technically something else
1684
1685
  this.callExpressions.pop();
@@ -1707,12 +1708,12 @@ class Parser {
1707
1708
  //an expression to keep for _references
1708
1709
  let referenceCallExpression;
1709
1710
  while (true) {
1710
- if (this.match(TokenKind_1.TokenKind.LeftParen)) {
1711
+ if (this.matchAny(TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.QuestionLeftParen)) {
1711
1712
  expr = this.finishCall(this.previous(), expr);
1712
1713
  //store this call expression in references
1713
1714
  referenceCallExpression = expr;
1714
1715
  }
1715
- else if (this.match(TokenKind_1.TokenKind.LeftSquareBracket)) {
1716
+ else if (this.matchAny(TokenKind_1.TokenKind.LeftSquareBracket, TokenKind_1.TokenKind.QuestionLeftSquare) || this.matchSequence(TokenKind_1.TokenKind.QuestionDot, TokenKind_1.TokenKind.LeftSquareBracket)) {
1716
1717
  expr = this.indexedGet(expr);
1717
1718
  }
1718
1719
  else if (this.match(TokenKind_1.TokenKind.Callfunc)) {
@@ -1720,7 +1721,7 @@ class Parser {
1720
1721
  //store this callfunc expression in references
1721
1722
  referenceCallExpression = expr;
1722
1723
  }
1723
- else if (this.match(TokenKind_1.TokenKind.Dot)) {
1724
+ else if (this.matchAny(TokenKind_1.TokenKind.Dot, TokenKind_1.TokenKind.QuestionDot)) {
1724
1725
  if (this.match(TokenKind_1.TokenKind.LeftSquareBracket)) {
1725
1726
  expr = this.indexedGet(expr);
1726
1727
  }
@@ -1733,7 +1734,7 @@ class Parser {
1733
1734
  this.addPropertyHints(name);
1734
1735
  }
1735
1736
  }
1736
- else if (this.check(TokenKind_1.TokenKind.At)) {
1737
+ else if (this.checkAny(TokenKind_1.TokenKind.At, TokenKind_1.TokenKind.QuestionAt)) {
1737
1738
  let dot = this.advance();
1738
1739
  let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedAttributeNameAfterAtSymbol(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
1739
1740
  // force it into an identifier so the AST makes some sense
@@ -1754,8 +1755,7 @@ class Parser {
1754
1755
  }
1755
1756
  finishCall(openingParen, callee, addToCallExpressionList = true) {
1756
1757
  let args = [];
1757
- while (this.match(TokenKind_1.TokenKind.Newline)) {
1758
- }
1758
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
1759
1759
  if (!this.check(TokenKind_1.TokenKind.RightParen)) {
1760
1760
  do {
1761
1761
  while (this.match(TokenKind_1.TokenKind.Newline)) { }
@@ -1838,106 +1838,10 @@ class Parser {
1838
1838
  let expr = this.expression();
1839
1839
  let right = this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftParenAfterExpression(), TokenKind_1.TokenKind.RightParen);
1840
1840
  return new Expression_1.GroupingExpression({ left: left, right: right }, expr);
1841
- case this.match(TokenKind_1.TokenKind.LeftSquareBracket):
1842
- let elements = [];
1843
- let openingSquare = this.previous();
1844
- //add any comment found right after the opening square
1845
- if (this.check(TokenKind_1.TokenKind.Comment)) {
1846
- elements.push(new Statement_1.CommentStatement([this.advance()]));
1847
- }
1848
- while (this.match(TokenKind_1.TokenKind.Newline)) {
1849
- }
1850
- if (!this.match(TokenKind_1.TokenKind.RightSquareBracket)) {
1851
- elements.push(this.expression());
1852
- while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
1853
- if (this.checkPrevious(TokenKind_1.TokenKind.Comment) || this.check(TokenKind_1.TokenKind.Comment)) {
1854
- let comment = this.check(TokenKind_1.TokenKind.Comment) ? this.advance() : this.previous();
1855
- elements.push(new Statement_1.CommentStatement([comment]));
1856
- }
1857
- while (this.match(TokenKind_1.TokenKind.Newline)) {
1858
- }
1859
- if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
1860
- break;
1861
- }
1862
- elements.push(this.expression());
1863
- }
1864
- this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftSquareBraceAfterArrayLiteral(), TokenKind_1.TokenKind.RightSquareBracket);
1865
- }
1866
- let closingSquare = this.previous();
1867
- //this.consume("Expected newline or ':' after array literal", TokenKind.Newline, TokenKind.Colon, TokenKind.Eof);
1868
- return new Expression_1.ArrayLiteralExpression(elements, openingSquare, closingSquare);
1841
+ case this.matchAny(TokenKind_1.TokenKind.LeftSquareBracket):
1842
+ return this.arrayLiteral();
1869
1843
  case this.match(TokenKind_1.TokenKind.LeftCurlyBrace):
1870
- let openingBrace = this.previous();
1871
- let members = [];
1872
- let key = () => {
1873
- let result = {
1874
- colonToken: null,
1875
- keyToken: null,
1876
- range: null
1877
- };
1878
- if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
1879
- result.keyToken = this.advance();
1880
- }
1881
- else if (this.check(TokenKind_1.TokenKind.StringLiteral)) {
1882
- result.keyToken = this.advance();
1883
- }
1884
- else {
1885
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedAAKey()), { range: this.peek().range }));
1886
- throw this.lastDiagnosticAsError();
1887
- }
1888
- result.colonToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedColonBetweenAAKeyAndvalue(), TokenKind_1.TokenKind.Colon);
1889
- result.range = util_1.util.getRange(result.keyToken, result.colonToken);
1890
- return result;
1891
- };
1892
- while (this.match(TokenKind_1.TokenKind.Newline)) {
1893
- }
1894
- if (!this.match(TokenKind_1.TokenKind.RightCurlyBrace)) {
1895
- let lastAAMember;
1896
- if (this.check(TokenKind_1.TokenKind.Comment)) {
1897
- lastAAMember = null;
1898
- members.push(new Statement_1.CommentStatement([this.advance()]));
1899
- }
1900
- else {
1901
- let k = key();
1902
- let expr = this.expression();
1903
- lastAAMember = new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr, getBscTypeFromExpression(expr, this.currentFunctionExpression));
1904
- members.push(lastAAMember);
1905
- }
1906
- while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
1907
- // collect comma at end of expression
1908
- if (lastAAMember && this.checkPrevious(TokenKind_1.TokenKind.Comma)) {
1909
- lastAAMember.commaToken = this.previous();
1910
- }
1911
- //check for comment at the end of the current line
1912
- if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
1913
- let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
1914
- members.push(new Statement_1.CommentStatement([token]));
1915
- }
1916
- else {
1917
- this.consumeStatementSeparators(true);
1918
- //check for a comment on its own line
1919
- if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
1920
- let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
1921
- lastAAMember = null;
1922
- members.push(new Statement_1.CommentStatement([token]));
1923
- continue;
1924
- }
1925
- if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
1926
- break;
1927
- }
1928
- let k = key();
1929
- let expr = this.expression();
1930
- lastAAMember = new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr, getBscTypeFromExpression(expr, this.currentFunctionExpression));
1931
- members.push(lastAAMember);
1932
- }
1933
- }
1934
- this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftCurlyAfterAALiteral(), TokenKind_1.TokenKind.RightCurlyBrace);
1935
- }
1936
- let closingBrace = this.previous();
1937
- const aaExpr = new Expression_1.AALiteralExpression(members, openingBrace, closingBrace, this.currentFunctionExpression);
1938
- this._references.aaLiterals.push(aaExpr);
1939
- this.addPropertyHints(aaExpr);
1940
- return aaExpr;
1844
+ return this.aaLiteral();
1941
1845
  case this.matchAny(TokenKind_1.TokenKind.Pos, TokenKind_1.TokenKind.Tab):
1942
1846
  let token = Object.assign(this.previous(), {
1943
1847
  kind: TokenKind_1.TokenKind.Identifier
@@ -1961,6 +1865,106 @@ class Parser {
1961
1865
  }
1962
1866
  }
1963
1867
  }
1868
+ arrayLiteral() {
1869
+ let elements = [];
1870
+ let openingSquare = this.previous();
1871
+ //add any comment found right after the opening square
1872
+ if (this.check(TokenKind_1.TokenKind.Comment)) {
1873
+ elements.push(new Statement_1.CommentStatement([this.advance()]));
1874
+ }
1875
+ while (this.match(TokenKind_1.TokenKind.Newline)) {
1876
+ }
1877
+ if (!this.match(TokenKind_1.TokenKind.RightSquareBracket)) {
1878
+ elements.push(this.expression());
1879
+ while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
1880
+ if (this.checkPrevious(TokenKind_1.TokenKind.Comment) || this.check(TokenKind_1.TokenKind.Comment)) {
1881
+ let comment = this.check(TokenKind_1.TokenKind.Comment) ? this.advance() : this.previous();
1882
+ elements.push(new Statement_1.CommentStatement([comment]));
1883
+ }
1884
+ while (this.match(TokenKind_1.TokenKind.Newline)) {
1885
+ }
1886
+ if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
1887
+ break;
1888
+ }
1889
+ elements.push(this.expression());
1890
+ }
1891
+ this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftSquareBraceAfterArrayLiteral(), TokenKind_1.TokenKind.RightSquareBracket);
1892
+ }
1893
+ let closingSquare = this.previous();
1894
+ //this.consume("Expected newline or ':' after array literal", TokenKind.Newline, TokenKind.Colon, TokenKind.Eof);
1895
+ return new Expression_1.ArrayLiteralExpression(elements, openingSquare, closingSquare);
1896
+ }
1897
+ aaLiteral() {
1898
+ let openingBrace = this.previous();
1899
+ let members = [];
1900
+ let key = () => {
1901
+ let result = {
1902
+ colonToken: null,
1903
+ keyToken: null,
1904
+ range: null
1905
+ };
1906
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
1907
+ result.keyToken = this.advance();
1908
+ }
1909
+ else if (this.check(TokenKind_1.TokenKind.StringLiteral)) {
1910
+ result.keyToken = this.advance();
1911
+ }
1912
+ else {
1913
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedAAKey()), { range: this.peek().range }));
1914
+ throw this.lastDiagnosticAsError();
1915
+ }
1916
+ result.colonToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedColonBetweenAAKeyAndvalue(), TokenKind_1.TokenKind.Colon);
1917
+ result.range = util_1.util.getRange(result.keyToken, result.colonToken);
1918
+ return result;
1919
+ };
1920
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
1921
+ if (!this.match(TokenKind_1.TokenKind.RightCurlyBrace)) {
1922
+ let lastAAMember;
1923
+ if (this.check(TokenKind_1.TokenKind.Comment)) {
1924
+ lastAAMember = null;
1925
+ members.push(new Statement_1.CommentStatement([this.advance()]));
1926
+ }
1927
+ else {
1928
+ let k = key();
1929
+ let expr = this.expression();
1930
+ lastAAMember = new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr, getBscTypeFromExpression(expr, this.currentFunctionExpression));
1931
+ members.push(lastAAMember);
1932
+ }
1933
+ while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
1934
+ // collect comma at end of expression
1935
+ if (lastAAMember && this.checkPrevious(TokenKind_1.TokenKind.Comma)) {
1936
+ lastAAMember.commaToken = this.previous();
1937
+ }
1938
+ //check for comment at the end of the current line
1939
+ if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
1940
+ let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
1941
+ members.push(new Statement_1.CommentStatement([token]));
1942
+ }
1943
+ else {
1944
+ this.consumeStatementSeparators(true);
1945
+ //check for a comment on its own line
1946
+ if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
1947
+ let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
1948
+ lastAAMember = null;
1949
+ members.push(new Statement_1.CommentStatement([token]));
1950
+ continue;
1951
+ }
1952
+ if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
1953
+ break;
1954
+ }
1955
+ let k = key();
1956
+ let expr = this.expression();
1957
+ lastAAMember = new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr, getBscTypeFromExpression(expr, this.currentFunctionExpression));
1958
+ members.push(lastAAMember);
1959
+ }
1960
+ }
1961
+ this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftCurlyAfterAALiteral(), TokenKind_1.TokenKind.RightCurlyBrace);
1962
+ }
1963
+ let closingBrace = this.previous();
1964
+ const aaExpr = new Expression_1.AALiteralExpression(members, openingBrace, closingBrace, this.currentFunctionExpression);
1965
+ this.addPropertyHints(aaExpr);
1966
+ return aaExpr;
1967
+ }
1964
1968
  /**
1965
1969
  * Pop token if we encounter specified token
1966
1970
  */
@@ -1984,6 +1988,21 @@ class Parser {
1984
1988
  }
1985
1989
  return false;
1986
1990
  }
1991
+ /**
1992
+ * If the next series of tokens matches the given set of tokens, pop them all
1993
+ * @param tokenKinds
1994
+ */
1995
+ matchSequence(...tokenKinds) {
1996
+ var _a;
1997
+ const endIndex = this.current + tokenKinds.length;
1998
+ for (let i = 0; i < tokenKinds.length; i++) {
1999
+ if (tokenKinds[i] !== ((_a = this.tokens[this.current + i]) === null || _a === void 0 ? void 0 : _a.kind)) {
2000
+ return false;
2001
+ }
2002
+ }
2003
+ this.current = endIndex;
2004
+ return true;
2005
+ }
1987
2006
  /**
1988
2007
  * Get next token matching a specified list, or fail with an error
1989
2008
  */
@@ -2086,6 +2105,21 @@ class Parser {
2086
2105
  previous() {
2087
2106
  return this.tokens[this.current - 1];
2088
2107
  }
2108
+ /**
2109
+ * Get the token that is {offset} indexes away from {this.current}
2110
+ * @param offset the number of index steps away from current index to fetch
2111
+ * @param tokenKinds the desired token must match one of these
2112
+ * @example
2113
+ * getToken(-1); //returns the previous token.
2114
+ * getToken(0); //returns current token.
2115
+ * getToken(1); //returns next token
2116
+ */
2117
+ getMatchingTokenAtOffset(offset, ...tokenKinds) {
2118
+ const token = this.tokens[this.current + offset];
2119
+ if (tokenKinds.includes(token.kind)) {
2120
+ return token;
2121
+ }
2122
+ }
2089
2123
  synchronize() {
2090
2124
  this.advance(); // skip the erroneous token
2091
2125
  while (!this.isAtEnd()) {