mercurial/filesetlang.py
changeset 38879 e79a69af1593
parent 38865 899b4c74209c
child 43076 2372284d9457
equal deleted inserted replaced
38878:0f56d08e6271 38879:e79a69af1593
   169         getsymbol(x[1])  # function name must be a symbol
   169         getsymbol(x[1])  # function name must be a symbol
   170         ta = _analyze(x[2])
   170         ta = _analyze(x[2])
   171         return (op, x[1], ta)
   171         return (op, x[1], ta)
   172     raise error.ProgrammingError('invalid operator %r' % op)
   172     raise error.ProgrammingError('invalid operator %r' % op)
   173 
   173 
       
   174 def _insertstatushints(x):
       
   175     """Insert hint nodes where status should be calculated (first path)
       
   176 
       
   177     This works in bottom-up way, summing up status names and inserting hint
       
   178     nodes at 'and' and 'or' as needed. Thus redundant hint nodes may be left.
       
   179 
       
   180     Returns (status-names, new-tree) at the given subtree, where status-names
       
   181     is a sum of status names referenced in the given subtree.
       
   182     """
       
   183     if x is None:
       
   184         return (), x
       
   185 
       
   186     op = x[0]
       
   187     if op in {'string', 'symbol', 'kindpat'}:
       
   188         return (), x
       
   189     if op == 'not':
       
   190         h, t = _insertstatushints(x[1])
       
   191         return h, (op, t)
       
   192     if op == 'and':
       
   193         ha, ta = _insertstatushints(x[1])
       
   194         hb, tb = _insertstatushints(x[2])
       
   195         hr = ha + hb
       
   196         if ha and hb:
       
   197             return hr, ('withstatus', (op, ta, tb), ('string', ' '.join(hr)))
       
   198         return hr, (op, ta, tb)
       
   199     if op == 'or':
       
   200         hs, ts = zip(*(_insertstatushints(y) for y in x[1:]))
       
   201         hr = sum(hs, ())
       
   202         if sum(bool(h) for h in hs) > 1:
       
   203             return hr, ('withstatus', (op,) + ts, ('string', ' '.join(hr)))
       
   204         return hr, (op,) + ts
       
   205     if op == 'list':
       
   206         hs, ts = zip(*(_insertstatushints(y) for y in x[1:]))
       
   207         return sum(hs, ()), (op,) + ts
       
   208     if op == 'func':
       
   209         f = getsymbol(x[1])
       
   210         # don't propagate 'ha' crossing a function boundary
       
   211         ha, ta = _insertstatushints(x[2])
       
   212         if getattr(symbols.get(f), '_callstatus', False):
       
   213             return (f,), ('withstatus', (op, x[1], ta), ('string', f))
       
   214         return (), (op, x[1], ta)
       
   215     raise error.ProgrammingError('invalid operator %r' % op)
       
   216 
       
   217 def _mergestatushints(x, instatus):
       
   218     """Remove redundant status hint nodes (second path)
       
   219 
       
   220     This is the top-down path to eliminate inner hint nodes.
       
   221     """
       
   222     if x is None:
       
   223         return x
       
   224 
       
   225     op = x[0]
       
   226     if op == 'withstatus':
       
   227         if instatus:
       
   228             # drop redundant hint node
       
   229             return _mergestatushints(x[1], instatus)
       
   230         t = _mergestatushints(x[1], instatus=True)
       
   231         return (op, t, x[2])
       
   232     if op in {'string', 'symbol', 'kindpat'}:
       
   233         return x
       
   234     if op == 'not':
       
   235         t = _mergestatushints(x[1], instatus)
       
   236         return (op, t)
       
   237     if op == 'and':
       
   238         ta = _mergestatushints(x[1], instatus)
       
   239         tb = _mergestatushints(x[2], instatus)
       
   240         return (op, ta, tb)
       
   241     if op in {'list', 'or'}:
       
   242         ts = tuple(_mergestatushints(y, instatus) for y in x[1:])
       
   243         return (op,) + ts
       
   244     if op == 'func':
       
   245         # don't propagate 'instatus' crossing a function boundary
       
   246         ta = _mergestatushints(x[2], instatus=False)
       
   247         return (op, x[1], ta)
       
   248     raise error.ProgrammingError('invalid operator %r' % op)
       
   249 
   174 def analyze(x):
   250 def analyze(x):
   175     """Transform raw parsed tree to evaluatable tree which can be fed to
   251     """Transform raw parsed tree to evaluatable tree which can be fed to
   176     optimize() or getmatch()
   252     optimize() or getmatch()
   177 
   253 
   178     All pseudo operations should be mapped to real operations or functions
   254     All pseudo operations should be mapped to real operations or functions
   179     defined in methods or symbols table respectively.
   255     defined in methods or symbols table respectively.
   180     """
   256     """
   181     return _analyze(x)
   257     t = _analyze(x)
       
   258     _h, t = _insertstatushints(t)
       
   259     return _mergestatushints(t, instatus=False)
   182 
   260 
   183 def _optimizeandops(op, ta, tb):
   261 def _optimizeandops(op, ta, tb):
   184     if tb is not None and tb[0] == 'not':
   262     if tb is not None and tb[0] == 'not':
   185         return ('minus', ta, tb[1])
   263         return ('minus', ta, tb[1])
   186     return (op, ta, tb)
   264     return (op, ta, tb)
   203 def _optimize(x):
   281 def _optimize(x):
   204     if x is None:
   282     if x is None:
   205         return 0, x
   283         return 0, x
   206 
   284 
   207     op = x[0]
   285     op = x[0]
       
   286     if op == 'withstatus':
       
   287         w, t = _optimize(x[1])
       
   288         return w, (op, t, x[2])
   208     if op in {'string', 'symbol'}:
   289     if op in {'string', 'symbol'}:
   209         return WEIGHT_CHECK_FILENAME, x
   290         return WEIGHT_CHECK_FILENAME, x
   210     if op == 'kindpat':
   291     if op == 'kindpat':
   211         w, t = _optimize(x[2])
   292         w, t = _optimize(x[2])
   212         return w, (op, x[1], t)
   293         return w, (op, x[1], t)