|
143 | 143 | // Handle Strings |
144 | 144 | if (stream.match(stringPrefixes)) { |
145 | 145 | var isFmtString = stream.current().toLowerCase().indexOf('f') !== -1; |
146 | | - if (!isFmtString || state.fstr_state !== null) { |
| 146 | + if (!isFmtString) { |
147 | 147 | // if this is a nested format string (e.g. f' { f"{10*10}" + "a" }' ) |
148 | 148 | // we do not format the nested expression and treat the nested format |
149 | 149 | // string as regular string |
150 | 150 | state.tokenize = tokenStringFactory(stream.current()); |
151 | 151 | return state.tokenize(stream, state); |
152 | 152 | } else { |
153 | 153 | // need to do something more sophisticated |
154 | | - state.tokenize = formatStringFactory(stream.current()); |
| 154 | + state.tokenize = formatStringFactory(stream.current(), state.tokenize); |
155 | 155 | return state.tokenize(stream, state); |
156 | 156 | } |
157 | 157 | } |
|
184 | 184 | return ERRORCLASS; |
185 | 185 | } |
186 | 186 |
|
187 | | - function formatStringFactory(delimiter) { |
| 187 | + function formatStringFactory(delimiter, tokenOuter) { |
188 | 188 | while ("rubf".indexOf(delimiter.charAt(0).toLowerCase()) >= 0) |
189 | 189 | delimiter = delimiter.substr(1); |
190 | 190 |
|
191 | 191 | var singleline = delimiter.length == 1; |
192 | 192 | var OUTCLASS = "string"; |
193 | 193 |
|
194 | | - function tokenString(stream, state) { |
195 | | - if (state.fstr_state) { |
196 | | - // inside f-str Expression |
197 | | - if (stream.match(delimiter)) { |
198 | | - // expression ends pre-maturally, but very common in editing |
199 | | - // Could show error to remind users to close brace here |
200 | | - state.fstr_state = null; |
201 | | - return OUTCLASS; |
202 | | - } else if (stream.match('{')) { |
203 | | - // starting brace, if not eaten below |
204 | | - return "punctuation"; |
205 | | - } else if (stream.match('}')) { |
206 | | - // return to regular inside string state |
207 | | - state.fstr_state = null; |
208 | | - return "punctuation"; |
209 | | - } else { |
210 | | - // use tokenBaseInner to parse the expression |
211 | | - return tokenBaseInner(stream, state.fstr_state); |
212 | | - } |
| 194 | + function tokenFString(stream, state) { |
| 195 | + // inside f-str Expression |
| 196 | + if (stream.match(delimiter)) { |
| 197 | + // expression ends pre-maturally, but very common in editing |
| 198 | + // Could show error to remind users to close brace here |
| 199 | + state.tokenize = tokenString |
| 200 | + return OUTCLASS; |
| 201 | + } else if (stream.match('{')) { |
| 202 | + // starting brace, if not eaten below |
| 203 | + return "punctuation"; |
| 204 | + } else if (stream.match('}')) { |
| 205 | + // return to regular inside string state |
| 206 | + state.tokenize = tokenString |
| 207 | + return "punctuation"; |
| 208 | + } else { |
| 209 | + // use tokenBaseInner to parse the expression |
| 210 | + return tokenBaseInner(stream, state); |
213 | 211 | } |
| 212 | + } |
| 213 | + |
| 214 | + function tokenString(stream, state) { |
214 | 215 | while (!stream.eol()) { |
215 | 216 | stream.eatWhile(/[^'"\{\}\\]/); |
216 | 217 | if (stream.eat("\\")) { |
217 | 218 | stream.next(); |
218 | 219 | if (singleline && stream.eol()) |
219 | 220 | return OUTCLASS; |
220 | 221 | } else if (stream.match(delimiter)) { |
221 | | - state.tokenize = tokenBase; |
| 222 | + state.tokenize = tokenOuter; |
222 | 223 | return OUTCLASS; |
223 | 224 | } else if (stream.match('{{')) { |
224 | 225 | // ignore {{ in f-str |
225 | 226 | return OUTCLASS; |
226 | 227 | } else if (stream.match('{', false)) { |
227 | 228 | // switch to nested mode |
228 | | - state.fstr_state = {}; |
| 229 | + state.tokenize = tokenFString |
229 | 230 | if (stream.current()) { |
230 | 231 | return OUTCLASS; |
231 | 232 | } else { |
|
246 | 247 | if (parserConf.singleLineStringErrors) |
247 | 248 | return ERRORCLASS; |
248 | 249 | else |
249 | | - state.tokenize = tokenBase; |
| 250 | + state.tokenize = tokenOuter; |
250 | 251 | } |
251 | 252 | return OUTCLASS; |
252 | 253 | } |
|
358 | 359 | return { |
359 | 360 | tokenize: tokenBase, |
360 | 361 | scopes: [{offset: basecolumn || 0, type: "py", align: null}], |
361 | | - fstr_state: null, |
362 | 362 | indent: basecolumn || 0, |
363 | 363 | lastToken: null, |
364 | 364 | lambda: false, |
|
0 commit comments