Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/filesetlang.py @ 38918:e79a69af1593
fileset: insert hints where status should be computed
This will allow us to compute status against a narrowed set of files.
For example, "path:build/ & (unknown() + missing())" is rewritten as
"path:build/ & <withstatus>(unknown() + missing(), 'unknown missing')",
and the status call can be narrowed by the left-hand-side matcher,
"path:build/".
mctx.buildstatus() calls will be solely processed by getmatchwithstatus().
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sat, 21 Jul 2018 20:27:53 +0900 |
parents | 899b4c74209c |
children | 2372284d9457 |
comparison
equal
deleted
inserted
replaced
38917:0f56d08e6271 | 38918: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) |