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)