mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 10:26:02 +00:00 
			
		
		
		
	 4fe72090de
			
		
	
	
		4fe72090de
		
			
		
	
	
	
	
		
			
			This is a little bit of clean-up, small fixes, and additional helpers prior to building an updated & accurate list of globals to eliminate.
		
			
				
	
	
		
			183 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import re
 | |
| 
 | |
| from ..info import KIND, ParsedItem, FileInfo
 | |
| 
 | |
| 
 | |
| class TextInfo:
 | |
| 
 | |
|     def __init__(self, text, start=None, end=None):
 | |
|         # immutable:
 | |
|         if not start:
 | |
|             start = 1
 | |
|         self.start = start
 | |
| 
 | |
|         # mutable:
 | |
|         lines = text.splitlines() or ['']
 | |
|         self.text = text.strip()
 | |
|         if not end:
 | |
|             end = start + len(lines) - 1
 | |
|         self.end = end
 | |
|         self.line = lines[-1]
 | |
| 
 | |
|     def __repr__(self):
 | |
|         args = (f'{a}={getattr(self, a)!r}'
 | |
|                 for a in ['text', 'start', 'end'])
 | |
|         return f'{type(self).__name__}({", ".join(args)})'
 | |
| 
 | |
|     def add_line(self, line, lno=None):
 | |
|         if lno is None:
 | |
|             lno = self.end + 1
 | |
|         else:
 | |
|             if isinstance(lno, FileInfo):
 | |
|                 fileinfo = lno
 | |
|                 if fileinfo.filename != self.filename:
 | |
|                     raise NotImplementedError((fileinfo, self.filename))
 | |
|                 lno = fileinfo.lno
 | |
|             # XXX
 | |
|             #if lno < self.end:
 | |
|             #    raise NotImplementedError((lno, self.end))
 | |
|         line = line.lstrip()
 | |
|         self.text += ' ' + line
 | |
|         self.line = line
 | |
|         self.end = lno
 | |
| 
 | |
| 
 | |
| class SourceInfo:
 | |
| 
 | |
|     _ready = False
 | |
| 
 | |
|     def __init__(self, filename, _current=None):
 | |
|         # immutable:
 | |
|         self.filename = filename
 | |
|         # mutable:
 | |
|         if isinstance(_current, str):
 | |
|             _current = TextInfo(_current)
 | |
|         self._current = _current
 | |
|         start = -1
 | |
|         self._start = _current.start if _current else -1
 | |
|         self._nested = []
 | |
|         self._set_ready()
 | |
| 
 | |
|     def __repr__(self):
 | |
|         args = (f'{a}={getattr(self, a)!r}'
 | |
|                 for a in ['filename', '_current'])
 | |
|         return f'{type(self).__name__}({", ".join(args)})'
 | |
| 
 | |
|     @property
 | |
|     def start(self):
 | |
|         if self._current is None:
 | |
|             return self._start
 | |
|         return self._current.start
 | |
| 
 | |
|     @property
 | |
|     def end(self):
 | |
|         if self._current is None:
 | |
|             return self._start
 | |
|         return self._current.end
 | |
| 
 | |
|     @property
 | |
|     def text(self):
 | |
|         if self._current is None:
 | |
|             return ''
 | |
|         return self._current.text
 | |
| 
 | |
|     def nest(self, text, before, start=None):
 | |
|         if self._current is None:
 | |
|             raise Exception('nesting requires active source text')
 | |
|         current = self._current
 | |
|         current.text = before
 | |
|         self._nested.append(current)
 | |
|         self._replace(text, start)
 | |
| 
 | |
|     def resume(self, remainder=None):
 | |
|         if not self._nested:
 | |
|             raise Exception('no nested text to resume')
 | |
|         if self._current is None:
 | |
|             raise Exception('un-nesting requires active source text')
 | |
|         if remainder is None:
 | |
|             remainder = self._current.text
 | |
|         self._clear()
 | |
|         self._current = self._nested.pop()
 | |
|         self._current.text += ' ' + remainder
 | |
|         self._set_ready()
 | |
| 
 | |
|     def advance(self, remainder, start=None):
 | |
|         if self._current is None:
 | |
|             raise Exception('advancing requires active source text')
 | |
|         if remainder.strip():
 | |
|             self._replace(remainder, start, fixnested=True)
 | |
|         else:
 | |
|             if self._nested:
 | |
|                 self._replace('', start, fixnested=True)
 | |
|                 #raise Exception('cannot advance while nesting')
 | |
|             else:
 | |
|                 self._clear(start)
 | |
| 
 | |
|     def resolve(self, kind, data, name, parent=None):
 | |
|         # "field" isn't a top-level kind, so we leave it as-is.
 | |
|         if kind and kind != 'field':
 | |
|             kind = KIND._from_raw(kind)
 | |
|         fileinfo = FileInfo(self.filename, self._start)
 | |
|         return ParsedItem(fileinfo, kind, parent, name, data)
 | |
| 
 | |
|     def done(self):
 | |
|         self._set_ready()
 | |
| 
 | |
|     def too_much(self, maxtext, maxlines):
 | |
|         if maxtext and len(self.text) > maxtext:
 | |
|             pass
 | |
|         elif maxlines and self.end - self.start > maxlines:
 | |
|             pass
 | |
|         else:
 | |
|             return False
 | |
| 
 | |
|         #if re.fullmatch(r'[^;]+\[\][ ]*=[ ]*[{]([ ]*\d+,)*([ ]*\d+,?)\s*',
 | |
|         #                self._current.text):
 | |
|         #    return False
 | |
|         return True
 | |
| 
 | |
|     def _set_ready(self):
 | |
|         if self._current is None:
 | |
|             self._ready = False
 | |
|         else:
 | |
|             self._ready = self._current.text.strip() != ''
 | |
| 
 | |
|     def _used(self):
 | |
|         ready = self._ready
 | |
|         self._ready = False
 | |
|         return ready
 | |
| 
 | |
|     def _clear(self, start=None):
 | |
|         old = self._current
 | |
|         if self._current is not None:
 | |
|             # XXX Fail if self._current wasn't used up?
 | |
|             if start is None:
 | |
|                 start = self._current.end
 | |
|             self._current = None
 | |
|         if start is not None:
 | |
|             self._start = start
 | |
|         self._set_ready()
 | |
|         return old
 | |
| 
 | |
|     def _replace(self, text, start=None, *, fixnested=False):
 | |
|         end = self._current.end
 | |
|         old = self._clear(start)
 | |
|         self._current = TextInfo(text, self._start, end)
 | |
|         if fixnested and self._nested and self._nested[-1] is old:
 | |
|             self._nested[-1] = self._current
 | |
|         self._set_ready()
 | |
| 
 | |
|     def _add_line(self, line, lno=None):
 | |
|         if not line.strip():
 | |
|             # We don't worry about multi-line string literals.
 | |
|             return
 | |
|         if self._current is None:
 | |
|             self._start = lno
 | |
|             self._current = TextInfo(line, lno)
 | |
|         else:
 | |
|             # XXX
 | |
|             #if lno < self._current.end:
 | |
|             #    # A circular include?
 | |
|             #    raise NotImplementedError((lno, self))
 | |
|             self._current.add_line(line, lno)
 | |
|         self._ready = True
 |