(root)/
Python-3.11.7/
Tools/
c-analyzer/
c_parser/
parser/
_info.py
       1  import re
       2  
       3  from ..info import KIND, ParsedItem, FileInfo
       4  
       5  
       6  class ESC[4;38;5;81mTextInfo:
       7  
       8      def __init__(self, text, start=None, end=None):
       9          # immutable:
      10          if not start:
      11              start = 1
      12          self.start = start
      13  
      14          # mutable:
      15          lines = text.splitlines() or ['']
      16          self.text = text.strip()
      17          if not end:
      18              end = start + len(lines) - 1
      19          self.end = end
      20          self.line = lines[-1]
      21  
      22      def __repr__(self):
      23          args = (f'{a}={getattr(self, a)!r}'
      24                  for a in ['text', 'start', 'end'])
      25          return f'{type(self).__name__}({", ".join(args)})'
      26  
      27      def add_line(self, line, lno=None):
      28          if lno is None:
      29              lno = self.end + 1
      30          else:
      31              if isinstance(lno, FileInfo):
      32                  fileinfo = lno
      33                  if fileinfo.filename != self.filename:
      34                      raise NotImplementedError((fileinfo, self.filename))
      35                  lno = fileinfo.lno
      36              # XXX
      37              #if lno < self.end:
      38              #    raise NotImplementedError((lno, self.end))
      39          line = line.lstrip()
      40          self.text += ' ' + line
      41          self.line = line
      42          self.end = lno
      43  
      44  
      45  class ESC[4;38;5;81mSourceInfo:
      46  
      47      _ready = False
      48  
      49      def __init__(self, filename, _current=None):
      50          # immutable:
      51          self.filename = filename
      52          # mutable:
      53          if isinstance(_current, str):
      54              _current = TextInfo(_current)
      55          self._current = _current
      56          start = -1
      57          self._start = _current.start if _current else -1
      58          self._nested = []
      59          self._set_ready()
      60  
      61      def __repr__(self):
      62          args = (f'{a}={getattr(self, a)!r}'
      63                  for a in ['filename', '_current'])
      64          return f'{type(self).__name__}({", ".join(args)})'
      65  
      66      @property
      67      def start(self):
      68          if self._current is None:
      69              return self._start
      70          return self._current.start
      71  
      72      @property
      73      def end(self):
      74          if self._current is None:
      75              return self._start
      76          return self._current.end
      77  
      78      @property
      79      def text(self):
      80          if self._current is None:
      81              return ''
      82          return self._current.text
      83  
      84      def nest(self, text, before, start=None):
      85          if self._current is None:
      86              raise Exception('nesting requires active source text')
      87          current = self._current
      88          current.text = before
      89          self._nested.append(current)
      90          self._replace(text, start)
      91  
      92      def resume(self, remainder=None):
      93          if not self._nested:
      94              raise Exception('no nested text to resume')
      95          if self._current is None:
      96              raise Exception('un-nesting requires active source text')
      97          if remainder is None:
      98              remainder = self._current.text
      99          self._clear()
     100          self._current = self._nested.pop()
     101          self._current.text += ' ' + remainder
     102          self._set_ready()
     103  
     104      def advance(self, remainder, start=None):
     105          if self._current is None:
     106              raise Exception('advancing requires active source text')
     107          if remainder.strip():
     108              self._replace(remainder, start, fixnested=True)
     109          else:
     110              if self._nested:
     111                  self._replace('', start, fixnested=True)
     112                  #raise Exception('cannot advance while nesting')
     113              else:
     114                  self._clear(start)
     115  
     116      def resolve(self, kind, data, name, parent=None):
     117          # "field" isn't a top-level kind, so we leave it as-is.
     118          if kind and kind != 'field':
     119              kind = KIND._from_raw(kind)
     120          fileinfo = FileInfo(self.filename, self._start)
     121          return ParsedItem(fileinfo, kind, parent, name, data)
     122  
     123      def done(self):
     124          self._set_ready()
     125  
     126      def too_much(self, maxtext, maxlines):
     127          if maxtext and len(self.text) > maxtext:
     128              pass
     129          elif maxlines and self.end - self.start > maxlines:
     130              pass
     131          else:
     132              return False
     133  
     134          #if re.fullmatch(r'[^;]+\[\][ ]*=[ ]*[{]([ ]*\d+,)*([ ]*\d+,?)\s*',
     135          #                self._current.text):
     136          #    return False
     137          return True
     138  
     139      def _set_ready(self):
     140          if self._current is None:
     141              self._ready = False
     142          else:
     143              self._ready = self._current.text.strip() != ''
     144  
     145      def _used(self):
     146          ready = self._ready
     147          self._ready = False
     148          return ready
     149  
     150      def _clear(self, start=None):
     151          old = self._current
     152          if self._current is not None:
     153              # XXX Fail if self._current wasn't used up?
     154              if start is None:
     155                  start = self._current.end
     156              self._current = None
     157          if start is not None:
     158              self._start = start
     159          self._set_ready()
     160          return old
     161  
     162      def _replace(self, text, start=None, *, fixnested=False):
     163          end = self._current.end
     164          old = self._clear(start)
     165          self._current = TextInfo(text, self._start, end)
     166          if fixnested and self._nested and self._nested[-1] is old:
     167              self._nested[-1] = self._current
     168          self._set_ready()
     169  
     170      def _add_line(self, line, lno=None):
     171          if not line.strip():
     172              # We don't worry about multi-line string literals.
     173              return
     174          if self._current is None:
     175              self._start = lno
     176              self._current = TextInfo(line, lno)
     177          else:
     178              # XXX
     179              #if lno < self._current.end:
     180              #    # A circular include?
     181              #    raise NotImplementedError((lno, self))
     182              self._current.add_line(line, lno)
     183          self._ready = True