2308 "ancestor": ancestorspec, |
2308 "ancestor": ancestorspec, |
2309 "parent": parentspec, |
2309 "parent": parentspec, |
2310 "parentpost": p1, |
2310 "parentpost": p1, |
2311 } |
2311 } |
2312 |
2312 |
|
2313 # Constants for ordering requirement, used in _analyze(): |
|
2314 # |
|
2315 # If 'define', any nested functions and operations can change the ordering of |
|
2316 # the entries in the set. If 'follow', any nested functions and operations |
|
2317 # should take the ordering specified by the first operand to the '&' operator. |
|
2318 # |
|
2319 # For instance, |
|
2320 # |
|
2321 # X & (Y | Z) |
|
2322 # ^ ^^^^^^^ |
|
2323 # | follow |
|
2324 # define |
|
2325 # |
|
2326 # will be evaluated as 'or(y(x()), z(x()))', where 'x()' can change the order |
|
2327 # of the entries in the set, but 'y()', 'z()' and 'or()' shouldn't. |
|
2328 # |
|
2329 # 'any' means the order doesn't matter. For instance, |
|
2330 # |
|
2331 # X & !Y |
|
2332 # ^ |
|
2333 # any |
|
2334 # |
|
2335 # 'y()' can either enforce its ordering requirement or take the ordering |
|
2336 # specified by 'x()' because 'not()' doesn't care the order. |
|
2337 # |
|
2338 # Transition of ordering requirement: |
|
2339 # |
|
2340 # 1. starts with 'define' |
|
2341 # 2. shifts to 'follow' by 'x & y' |
|
2342 # 3. changes back to 'define' on function call 'f(x)' or function-like |
|
2343 # operation 'x (f) y' because 'f' may have its own ordering requirement |
|
2344 # for 'x' and 'y' (e.g. 'first(x)') |
|
2345 # |
|
2346 anyorder = 'any' # don't care the order |
|
2347 defineorder = 'define' # should define the order |
|
2348 followorder = 'follow' # must follow the current order |
|
2349 |
|
2350 # transition table for 'x & y', from the current expression 'x' to 'y' |
|
2351 _tofolloworder = { |
|
2352 anyorder: anyorder, |
|
2353 defineorder: followorder, |
|
2354 followorder: followorder, |
|
2355 } |
|
2356 |
2313 def _matchonly(revs, bases): |
2357 def _matchonly(revs, bases): |
2314 """ |
2358 """ |
2315 >>> f = lambda *args: _matchonly(*map(parse, args)) |
2359 >>> f = lambda *args: _matchonly(*map(parse, args)) |
2316 >>> f('ancestors(A)', 'not ancestors(B)') |
2360 >>> f('ancestors(A)', 'not ancestors(B)') |
2317 ('list', ('symbol', 'A'), ('symbol', 'B')) |
2361 ('list', ('symbol', 'A'), ('symbol', 'B')) |
2347 # x + y + z -> (or x y z) -> (or (list x y z)) |
2391 # x + y + z -> (or x y z) -> (or (list x y z)) |
2348 return (op, _fixops(('list',) + x[1:])) |
2392 return (op, _fixops(('list',) + x[1:])) |
2349 |
2393 |
2350 return (op,) + tuple(_fixops(y) for y in x[1:]) |
2394 return (op,) + tuple(_fixops(y) for y in x[1:]) |
2351 |
2395 |
2352 def _analyze(x): |
2396 def _analyze(x, order): |
2353 if x is None: |
2397 if x is None: |
2354 return x |
2398 return x |
2355 |
2399 |
2356 op = x[0] |
2400 op = x[0] |
2357 if op == 'minus': |
2401 if op == 'minus': |
2358 return _analyze(('and', x[1], ('not', x[2]))) |
2402 return _analyze(('and', x[1], ('not', x[2])), order) |
2359 elif op == 'only': |
2403 elif op == 'only': |
2360 t = ('func', ('symbol', 'only'), ('list', x[1], x[2])) |
2404 t = ('func', ('symbol', 'only'), ('list', x[1], x[2])) |
2361 return _analyze(t) |
2405 return _analyze(t, order) |
2362 elif op == 'onlypost': |
2406 elif op == 'onlypost': |
2363 return _analyze(('func', ('symbol', 'only'), x[1])) |
2407 return _analyze(('func', ('symbol', 'only'), x[1]), order) |
2364 elif op == 'dagrangepre': |
2408 elif op == 'dagrangepre': |
2365 return _analyze(('func', ('symbol', 'ancestors'), x[1])) |
2409 return _analyze(('func', ('symbol', 'ancestors'), x[1]), order) |
2366 elif op == 'dagrangepost': |
2410 elif op == 'dagrangepost': |
2367 return _analyze(('func', ('symbol', 'descendants'), x[1])) |
2411 return _analyze(('func', ('symbol', 'descendants'), x[1]), order) |
2368 elif op == 'rangeall': |
2412 elif op == 'rangeall': |
2369 return _analyze(('range', ('string', '0'), ('string', 'tip'))) |
2413 return _analyze(('range', ('string', '0'), ('string', 'tip')), order) |
2370 elif op == 'rangepre': |
2414 elif op == 'rangepre': |
2371 return _analyze(('range', ('string', '0'), x[1])) |
2415 return _analyze(('range', ('string', '0'), x[1]), order) |
2372 elif op == 'rangepost': |
2416 elif op == 'rangepost': |
2373 return _analyze(('range', x[1], ('string', 'tip'))) |
2417 return _analyze(('range', x[1], ('string', 'tip')), order) |
2374 elif op == 'negate': |
2418 elif op == 'negate': |
2375 s = getstring(x[1], _("can't negate that")) |
2419 s = getstring(x[1], _("can't negate that")) |
2376 return _analyze(('string', '-' + s)) |
2420 return _analyze(('string', '-' + s), order) |
2377 elif op in ('string', 'symbol'): |
2421 elif op in ('string', 'symbol'): |
2378 return x |
2422 return x |
2379 elif op == 'and': |
2423 elif op == 'and': |
2380 ta = _analyze(x[1]) |
2424 ta = _analyze(x[1], order) |
2381 tb = _analyze(x[2]) |
2425 tb = _analyze(x[2], _tofolloworder[order]) |
2382 return (op, ta, tb) |
2426 return (op, ta, tb) |
2383 elif op == 'or': |
2427 elif op == 'or': |
2384 return (op, _analyze(x[1])) |
2428 return (op, _analyze(x[1], order)) |
2385 elif op == 'not': |
2429 elif op == 'not': |
2386 return (op, _analyze(x[1])) |
2430 return (op, _analyze(x[1], anyorder)) |
2387 elif op == 'parentpost': |
2431 elif op == 'parentpost': |
2388 return (op, _analyze(x[1])) |
2432 return (op, _analyze(x[1], defineorder)) |
2389 elif op == 'group': |
2433 elif op == 'group': |
2390 return _analyze(x[1]) |
2434 return _analyze(x[1], order) |
2391 elif op in ('dagrange', 'range', 'parent', 'ancestor'): |
2435 elif op in ('dagrange', 'range', 'parent', 'ancestor'): |
2392 ta = _analyze(x[1]) |
2436 ta = _analyze(x[1], defineorder) |
2393 tb = _analyze(x[2]) |
2437 tb = _analyze(x[2], defineorder) |
2394 return (op, ta, tb) |
2438 return (op, ta, tb) |
2395 elif op == 'list': |
2439 elif op == 'list': |
2396 return (op,) + tuple(_analyze(y) for y in x[1:]) |
2440 return (op,) + tuple(_analyze(y, order) for y in x[1:]) |
2397 elif op == 'keyvalue': |
2441 elif op == 'keyvalue': |
2398 return (op, x[1], _analyze(x[2])) |
2442 return (op, x[1], _analyze(x[2], order)) |
2399 elif op == 'func': |
2443 elif op == 'func': |
2400 return (op, x[1], _analyze(x[2])) |
2444 return (op, x[1], _analyze(x[2], defineorder)) |
2401 raise ValueError('invalid operator %r' % op) |
2445 raise ValueError('invalid operator %r' % op) |
2402 |
2446 |
2403 def analyze(x): |
2447 def analyze(x, order=defineorder): |
2404 """Transform raw parsed tree to evaluatable tree which can be fed to |
2448 """Transform raw parsed tree to evaluatable tree which can be fed to |
2405 optimize() or getset() |
2449 optimize() or getset() |
2406 |
2450 |
2407 All pseudo operations should be mapped to real operations or functions |
2451 All pseudo operations should be mapped to real operations or functions |
2408 defined in methods or symbols table respectively. |
2452 defined in methods or symbols table respectively. |
2409 """ |
2453 |
2410 return _analyze(x) |
2454 'order' specifies how the current expression 'x' is ordered (see the |
|
2455 constants defined above.) |
|
2456 """ |
|
2457 return _analyze(x, order) |
2411 |
2458 |
2412 def _optimize(x, small): |
2459 def _optimize(x, small): |
2413 if x is None: |
2460 if x is None: |
2414 return 0, x |
2461 return 0, x |
2415 |
2462 |