BackwardIterator.ts212 lines · main
1// Porting from
2// https://github.com/Borvik/vscode-postgres/blob/master/src/common/backwordIterator.ts
3
4const _NL = '\n'.charCodeAt(0)
5const _TAB = '\t'.charCodeAt(0)
6const _WSB = ' '.charCodeAt(0)
7const _LBracket = '['.charCodeAt(0)
8const _RBracket = ']'.charCodeAt(0)
9const _LCurly = '{'.charCodeAt(0)
10const _RCurly = '}'.charCodeAt(0)
11const _LParent = '('.charCodeAt(0)
12const _RParent = ')'.charCodeAt(0)
13const _Comma = ','.charCodeAt(0)
14const _Period = '.'.charCodeAt(0)
15const _Quote = "'".charCodeAt(0)
16const _DQuote = '"'.charCodeAt(0)
17const _USC = '_'.charCodeAt(0)
18// _a will give undefined... so rename to _aCode
19const _aCode = 'a'.charCodeAt(0)
20const _z = 'z'.charCodeAt(0)
21const _A = 'A'.charCodeAt(0)
22const _Z = 'Z'.charCodeAt(0)
23const _0 = '0'.charCodeAt(0)
24const _9 = '9'.charCodeAt(0)
25
26const BOF = 0
27
28class BackwardIterator {
29 _line
30 _text
31 _lines
32
33 model
34 offset
35 lineNumber
36
37 constructor(model: any, offset: number, lineNumber: number) {
38 this.model = model
39 this.offset = offset
40 this.lineNumber = lineNumber
41
42 this._text = model.getValue()
43 this._lines = this._text.split(/\r?\n/g)
44 this._line = this._lines[lineNumber]
45 }
46
47 hasNext() {
48 return this.lineNumber >= 0 || this.offset >= 0
49 }
50
51 isFowardDQuote() {
52 if (!this.hasForward()) return false
53 return this.peekForward() === _DQuote
54 }
55
56 isNextDQuote() {
57 if (!this.hasNext()) return false
58 return this.peekNext() === _DQuote
59 }
60
61 isNextPeriod() {
62 if (!this.hasNext()) return false
63 return this.peekNext() === _Period
64 }
65
66 peekNext() {
67 if (this.offset < 0) {
68 if (this.lineNumber > 0) {
69 return _NL
70 }
71 return BOF
72 }
73 return this._line.charCodeAt(this.offset)
74 }
75
76 hasForward() {
77 return this.lineNumber < this._lines.length || this.offset < this._line.length
78 }
79
80 peekForward() {
81 if (this.offset === this._line.length) {
82 if (this.lineNumber === this._lines.length) return BOF
83 return _NL
84 }
85 return this._line.charCodeAt(this.offset + 1)
86 }
87
88 next() {
89 if (this.offset < 0) {
90 if (this.lineNumber > 0) {
91 this.lineNumber--
92 this._line = this._lines[this.lineNumber]
93 this.offset = this._line.length - 1
94 return _NL
95 }
96 this.lineNumber = -1
97 return BOF
98 }
99 let ch = this._line.charCodeAt(this.offset)
100 this.offset--
101 return ch
102 }
103
104 readArguments() {
105 let parentNesting = 0
106 let bracketNesting = 0
107 let curlyNesting = 0
108 let paramCount = 0
109 while (this.hasNext()) {
110 let ch = this.next()
111 switch (ch) {
112 case _LParent:
113 parentNesting--
114 if (parentNesting < 0) {
115 return paramCount
116 }
117 break
118 case _RParent:
119 parentNesting++
120 break
121 case _LCurly:
122 curlyNesting--
123 break
124 case _RCurly:
125 curlyNesting++
126 break
127 case _LBracket:
128 bracketNesting--
129 break
130 case _RBracket:
131 bracketNesting++
132 break
133 case _DQuote:
134 case _Quote:
135 while (this.hasNext() && ch !== this.next()) {
136 // find the closing quote or double quote
137 }
138 break
139 case _Comma:
140 if (!parentNesting && !bracketNesting && !curlyNesting) {
141 paramCount++
142 }
143 break
144 }
145 }
146 return -1
147 }
148
149 readIdent() {
150 let identStarted = false
151 let isQuotedIdentifier = false
152 let ident = ''
153
154 while (this.hasNext()) {
155 // Peek first and check if is part of identifier
156 let ch = this.peekNext()
157 if (identStarted && !isQuotedIdentifier && !this._isIdentPart(ch)) break
158
159 ch = this.next()
160
161 if (!identStarted && isQuotedIdentifier && ch === _DQuote) {
162 identStarted = true
163 continue
164 }
165 if (!identStarted && (ch === _WSB || ch === _TAB || ch == _NL)) continue
166
167 if (!identStarted && (ch === _DQuote || this._isIdentPart(ch))) {
168 identStarted = true
169 isQuotedIdentifier = ch === _DQuote
170 ident = String.fromCharCode(ch) + ident
171 } else if (identStarted) {
172 if (isQuotedIdentifier) {
173 if (ch === BOF) break
174 ident = String.fromCharCode(ch) + ident
175 if (ch === _DQuote) break
176 } else {
177 ident = String.fromCharCode(ch) + ident
178 }
179 }
180 }
181 return ident
182 }
183
184 readIdents(maxlvl: number) {
185 let idents = []
186 while (maxlvl > 0) {
187 maxlvl--
188 let ident = this.readIdent()
189 if (!ident) {
190 break
191 }
192
193 idents.push(ident)
194
195 if (!this.isNextPeriod()) {
196 break
197 }
198 }
199 return idents.reverse()
200 }
201
202 _isIdentPart(ch: number) {
203 return (
204 ch === _USC || // _
205 (ch >= _aCode && ch <= _z) || // a-z
206 (ch >= _A && ch <= _Z) || // A-Z
207 (ch >= _0 && ch <= _9)
208 ) // 0-9
209 }
210}
211
212export default BackwardIterator