11from __future__ import annotations
22
33import enum
4+ import functools
5+ import operator
46import re
57from typing import TYPE_CHECKING
68
@@ -220,11 +222,11 @@ def _emit(self, type: TokenType, value: str, line: int, column: int = 0) -> None
220222 """Emit a token with the given type and value at the specified line and column."""
221223 self ._tokens .append (Token (type , value , line , column ))
222224
223- def _read_until (self , condition : str | Callable [[str ], bool ], * , or_eof : bool = True ) -> str :
225+ def _read_conditional (self , condition : Callable [[str ], bool ], * , or_eof : bool = True ) -> str :
224226 """Read until the current character matches the condition.
225227
226228 Args:
227- condition: Characters to match, or a function that returns ``True`` to stop.
229+ condition: A function that returns ``True`` to stop.
228230 or_eof: If True, also stop if EOF is reached. If False, EOF will not stop the read and will raise an error.
229231 """
230232 start = self ._pos
@@ -234,47 +236,42 @@ def _read_until(self, condition: str | Callable[[str], bool], *, or_eof: bool =
234236 self ._assert_not_eof ()
235237 break
236238
237- ch = self .data [self ._pos ]
238- if isinstance (condition , str ):
239- if ch in condition :
240- break
241- else :
242- if condition (ch ):
243- break
239+ if condition (self .data [self ._pos ]):
240+ break
244241
245242 self ._pos += 1
246243
247244 end = self ._pos
248245 self ._pos = start
249246 return self ._take (end - start )
250247
248+ def _read_until (self , condition : str | Callable [[str ], bool ], * , or_eof : bool = True ) -> str :
249+ """Read until the current character matches the condition.
250+
251+ Args:
252+ condition: Characters to match, or a function that returns ``True`` to stop.
253+ or_eof: If True, also stop if EOF is reached. If False, EOF will not stop the read and will raise an error.
254+ """
255+ if isinstance (condition , str ):
256+ condition = functools .partial (operator .contains , condition )
257+
258+ return self ._read_conditional (condition , or_eof = or_eof )
259+
251260 def _read_while (self , condition : str | Callable [[str ], bool ], * , or_eof : bool = True ) -> str :
252261 """Read while the current character matches the condition.
253262
254263 Args:
255264 condition: Characters to match, or a function that returns ``True`` to continue.
256265 or_eof: If True, also stop if EOF is reached. If False, EOF will not stop the read and will raise an error.
257266 """
258- start = self ._pos
259- while True :
260- if self .eof :
261- if not or_eof :
262- self ._assert_not_eof ()
263- break
264267
265- ch = self .data [self ._pos ]
266- if isinstance (condition , str ):
267- if ch not in condition :
268- break
269- else :
270- if not condition (ch ):
271- break
268+ def _invert (condition : Callable [[str ], bool ], ch : str ) -> bool :
269+ return not condition (ch )
272270
273- self ._pos += 1
271+ if isinstance (condition , str ):
272+ condition = functools .partial (operator .contains , condition )
274273
275- end = self ._pos
276- self ._pos = start
277- return self ._take (end - start )
274+ return self ._read_conditional (functools .partial (_invert , condition ), or_eof = or_eof )
278275
279276 def _skip_whitespace (self ) -> None :
280277 """Skip whitespace characters."""
0 commit comments