Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/revsetlang.py @ 33416:9467d5337292
revset: add experimental relation and subscript operators
The proposed syntax [1] was originally 'set{n rel}', but it seemed slightly
confusing if template is involved. On the other hand, we want to keep 'set[n]'
for future extension. So this patch introduces 'set#rel[n]' ternary operator.
I chose '#' just because it looks like applying an attribute.
This also adds stubs for 'set[n]' and 'set#rel' operators since these syntax
elements are fundamental for constructing 'set#rel[n]'.
[1]: https://www.mercurial-scm.org/wiki/RevsetOperatorPlan#ideas_from_mpm
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sat, 08 Jul 2017 13:07:59 +0900 |
parents | 371f59c6a89e |
children | 72b5f4d53c58 |
comparison
equal
deleted
inserted
replaced
33415:371f59c6a89e | 33416:9467d5337292 |
---|---|
19 ) | 19 ) |
20 | 20 |
21 elements = { | 21 elements = { |
22 # token-type: binding-strength, primary, prefix, infix, suffix | 22 # token-type: binding-strength, primary, prefix, infix, suffix |
23 "(": (21, None, ("group", 1, ")"), ("func", 1, ")"), None), | 23 "(": (21, None, ("group", 1, ")"), ("func", 1, ")"), None), |
24 "[": (21, None, None, ("subscript", 1, "]"), None), | |
25 "#": (21, None, None, ("relation", 21), None), | |
24 "##": (20, None, None, ("_concat", 20), None), | 26 "##": (20, None, None, ("_concat", 20), None), |
25 "~": (18, None, None, ("ancestor", 18), None), | 27 "~": (18, None, None, ("ancestor", 18), None), |
26 "^": (18, None, None, ("parent", 18), "parentpost"), | 28 "^": (18, None, None, ("parent", 18), "parentpost"), |
27 "-": (5, None, ("negate", 19), ("minus", 5), None), | 29 "-": (5, None, ("negate", 19), ("minus", 5), None), |
28 "::": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"), | 30 "::": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"), |
37 "|": (4, None, None, ("or", 4), None), | 39 "|": (4, None, None, ("or", 4), None), |
38 "+": (4, None, None, ("or", 4), None), | 40 "+": (4, None, None, ("or", 4), None), |
39 "=": (3, None, None, ("keyvalue", 3), None), | 41 "=": (3, None, None, ("keyvalue", 3), None), |
40 ",": (2, None, None, ("list", 2), None), | 42 ",": (2, None, None, ("list", 2), None), |
41 ")": (0, None, None, None, None), | 43 ")": (0, None, None, None, None), |
44 "]": (0, None, None, None, None), | |
42 "symbol": (0, "symbol", None, None, None), | 45 "symbol": (0, "symbol", None, None, None), |
43 "string": (0, "string", None, None, None), | 46 "string": (0, "string", None, None, None), |
44 "end": (0, None, None, None, None), | 47 "end": (0, None, None, None, None), |
45 } | 48 } |
46 | 49 |
47 keywords = {'and', 'or', 'not'} | 50 keywords = {'and', 'or', 'not'} |
48 | 51 |
49 _quoteletters = {'"', "'"} | 52 _quoteletters = {'"', "'"} |
50 _simpleopletters = set(pycompat.iterbytestr("():=,-|&+!~^%")) | 53 _simpleopletters = set(pycompat.iterbytestr("()[]#:=,-|&+!~^%")) |
51 | 54 |
52 # default set of valid characters for the initial letter of symbols | 55 # default set of valid characters for the initial letter of symbols |
53 _syminitletters = set(pycompat.iterbytestr( | 56 _syminitletters = set(pycompat.iterbytestr( |
54 string.ascii_letters.encode('ascii') + | 57 string.ascii_letters.encode('ascii') + |
55 string.digits.encode('ascii') + | 58 string.digits.encode('ascii') + |
329 return _fixops(('rangepost', post)) | 332 return _fixops(('rangepost', post)) |
330 elif op == 'or': | 333 elif op == 'or': |
331 # make number of arguments deterministic: | 334 # make number of arguments deterministic: |
332 # x + y + z -> (or x y z) -> (or (list x y z)) | 335 # x + y + z -> (or x y z) -> (or (list x y z)) |
333 return (op, _fixops(('list',) + x[1:])) | 336 return (op, _fixops(('list',) + x[1:])) |
337 elif op == 'subscript' and x[1][0] == 'relation': | |
338 # x#y[z] ternary | |
339 return _fixops(('relsubscript', x[1][1], x[1][2], x[2])) | |
334 | 340 |
335 return (op,) + tuple(_fixops(y) for y in x[1:]) | 341 return (op,) + tuple(_fixops(y) for y in x[1:]) |
336 | 342 |
337 def _analyze(x, order): | 343 def _analyze(x, order): |
338 if x is None: | 344 if x is None: |
367 return (op, None, order) | 373 return (op, None, order) |
368 elif op in ('rangepre', 'rangepost', 'parentpost'): | 374 elif op in ('rangepre', 'rangepost', 'parentpost'): |
369 return (op, _analyze(x[1], defineorder), order) | 375 return (op, _analyze(x[1], defineorder), order) |
370 elif op == 'group': | 376 elif op == 'group': |
371 return _analyze(x[1], order) | 377 return _analyze(x[1], order) |
372 elif op in ('dagrange', 'range', 'parent', 'ancestor'): | 378 elif op in ('dagrange', 'range', 'parent', 'ancestor', 'relation', |
379 'subscript'): | |
373 ta = _analyze(x[1], defineorder) | 380 ta = _analyze(x[1], defineorder) |
374 tb = _analyze(x[2], defineorder) | 381 tb = _analyze(x[2], defineorder) |
375 return (op, ta, tb, order) | 382 return (op, ta, tb, order) |
383 elif op == 'relsubscript': | |
384 ta = _analyze(x[1], defineorder) | |
385 tb = _analyze(x[2], defineorder) | |
386 tc = _analyze(x[3], defineorder) | |
387 return (op, ta, tb, tc, order) | |
376 elif op == 'list': | 388 elif op == 'list': |
377 return (op,) + tuple(_analyze(y, order) for y in x[1:]) | 389 return (op,) + tuple(_analyze(y, order) for y in x[1:]) |
378 elif op == 'keyvalue': | 390 elif op == 'keyvalue': |
379 return (op, x[1], _analyze(x[2], order)) | 391 return (op, x[1], _analyze(x[2], order)) |
380 elif op == 'func': | 392 elif op == 'func': |
479 elif op in ('dagrange', 'range'): | 491 elif op in ('dagrange', 'range'): |
480 wa, ta = _optimize(x[1], small) | 492 wa, ta = _optimize(x[1], small) |
481 wb, tb = _optimize(x[2], small) | 493 wb, tb = _optimize(x[2], small) |
482 order = x[3] | 494 order = x[3] |
483 return wa + wb, (op, ta, tb, order) | 495 return wa + wb, (op, ta, tb, order) |
484 elif op in ('parent', 'ancestor'): | 496 elif op in ('parent', 'ancestor', 'relation', 'subscript'): |
485 w, t = _optimize(x[1], small) | 497 w, t = _optimize(x[1], small) |
486 order = x[3] | 498 order = x[3] |
487 return w, (op, t, x[2], order) | 499 return w, (op, t, x[2], order) |
500 elif op == 'relsubscript': | |
501 w, t = _optimize(x[1], small) | |
502 order = x[4] | |
503 return w, (op, t, x[2], x[3], order) | |
488 elif op == 'list': | 504 elif op == 'list': |
489 ws, ts = zip(*(_optimize(y, small) for y in x[1:])) | 505 ws, ts = zip(*(_optimize(y, small) for y in x[1:])) |
490 return sum(ws), (op,) + ts | 506 return sum(ws), (op,) + ts |
491 elif op == 'keyvalue': | 507 elif op == 'keyvalue': |
492 w, t = _optimize(x[2], small) | 508 w, t = _optimize(x[2], small) |