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) |