StringStream.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import { countColumn } from "./misc.js"
  2. // STRING STREAM
  3. // Fed to the mode parsers, provides helper functions to make
  4. // parsers more succinct.
  5. class StringStream {
  6. constructor(string, tabSize, lineOracle) {
  7. this.pos = this.start = 0
  8. this.string = string
  9. this.tabSize = tabSize || 8
  10. this.lastColumnPos = this.lastColumnValue = 0
  11. this.lineStart = 0
  12. this.lineOracle = lineOracle
  13. }
  14. eol() {return this.pos >= this.string.length}
  15. sol() {return this.pos == this.lineStart}
  16. peek() {return this.string.charAt(this.pos) || undefined}
  17. next() {
  18. if (this.pos < this.string.length)
  19. return this.string.charAt(this.pos++)
  20. }
  21. eat(match) {
  22. let ch = this.string.charAt(this.pos)
  23. let ok
  24. if (typeof match == "string") ok = ch == match
  25. else ok = ch && (match.test ? match.test(ch) : match(ch))
  26. if (ok) {++this.pos; return ch}
  27. }
  28. eatWhile(match) {
  29. let start = this.pos
  30. while (this.eat(match)){}
  31. return this.pos > start
  32. }
  33. eatSpace() {
  34. let start = this.pos
  35. while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos
  36. return this.pos > start
  37. }
  38. skipToEnd() {this.pos = this.string.length}
  39. skipTo(ch) {
  40. let found = this.string.indexOf(ch, this.pos)
  41. if (found > -1) {this.pos = found; return true}
  42. }
  43. backUp(n) {this.pos -= n}
  44. column() {
  45. if (this.lastColumnPos < this.start) {
  46. this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue)
  47. this.lastColumnPos = this.start
  48. }
  49. return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
  50. }
  51. indentation() {
  52. return countColumn(this.string, null, this.tabSize) -
  53. (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
  54. }
  55. match(pattern, consume, caseInsensitive) {
  56. if (typeof pattern == "string") {
  57. let cased = str => caseInsensitive ? str.toLowerCase() : str
  58. let substr = this.string.substr(this.pos, pattern.length)
  59. if (cased(substr) == cased(pattern)) {
  60. if (consume !== false) this.pos += pattern.length
  61. return true
  62. }
  63. } else {
  64. let match = this.string.slice(this.pos).match(pattern)
  65. if (match && match.index > 0) return null
  66. if (match && consume !== false) this.pos += match[0].length
  67. return match
  68. }
  69. }
  70. current(){return this.string.slice(this.start, this.pos)}
  71. hideFirstChars(n, inner) {
  72. this.lineStart += n
  73. try { return inner() }
  74. finally { this.lineStart -= n }
  75. }
  76. lookAhead(n) {
  77. let oracle = this.lineOracle
  78. return oracle && oracle.lookAhead(n)
  79. }
  80. baseToken() {
  81. let oracle = this.lineOracle
  82. return oracle && oracle.baseToken(this.pos)
  83. }
  84. }
  85. export default StringStream