Commit Graph

32 Commits

Author SHA1 Message Date
Yuya Nishihara
a71f259bd2 doctest: bulk-replace string literals with b'' for Python 3
Our code transformer can't rewrite string literals in docstrings, and I
don't want to make the transformer more complex.
2017-09-03 14:32:11 +09:00
Yuya Nishihara
6567bed4cb py3: fix mixed bytes/unicode in revsetlang._aliassyminitletters 2017-09-03 17:03:23 +09:00
Jun Wu
eaaeecf0d5 revset: optimize "draft() & ::x" pattern
The `draft() & ::x` type query could be common for selecting one or more
draft feature branches being worked on.

Before this patch, `::x` may travel through the changelog DAG for a long
distance until it gets a smaller revision number than `min(draft())`. It
could be very slow on long changelog with distant (in terms of revision
numbers) drafts.

This patch adds a fast path for this situation, and will stop traveling the
changelog DAG once `::x` hits a non-draft revision.

The fast path also works for `secret()` and `not public()`.

To measure the performance difference, I used drawdag to create a repo that
emulates distant drafts:

          DRAFT4
           |
          DRAFT3 # draft
          /
  PUBLIC9999 # public
      |
  PUBLIC9998
      |
      .   DRAFT2
      .    |
      .   DRAFT1 # draft
      |   /
  PUBLIC0001 # public

And measured the performance using the repo:

  (BEFORE)
  $ hg perfrevset 'draft() & ::(DRAFT2+DRAFT4)'
  ! wall 0.017132 comb 0.010000 user 0.010000 sys 0.000000 (best of 156)
  $ hg perfrevset 'draft() & ::(all())'
  ! wall 0.024221 comb 0.030000 user 0.030000 sys 0.000000 (best of 113)
  (AFTER)
  $ hg perfrevset 'draft() & ::(DRAFT2+DRAFT4)'
  ! wall 0.000243 comb 0.000000 user 0.000000 sys 0.000000 (best of 9303)
  $ hg perfrevset 'draft() & ::(all())'
  ! wall 0.004319 comb 0.000000 user 0.000000 sys 0.000000 (best of 655)

Differential Revision: https://phab.mercurial-scm.org/D441
2017-08-28 14:49:00 -07:00
Yuya Nishihara
6d9809531d revsetlang: remove unused functions
Superseded by the _match() function.
2017-08-19 22:04:03 +09:00
Yuya Nishihara
48edce65ce revsetlang: match tree by helper function on optimize
This should make optimize() more readable and less error-prone, but it doubles
the parsing cost.

  (original)
  $ python -m timeit -n10000 -s 'from mercurial import revsetlang as L' \
  'L.optimize(L.analyze(L.parse("ancestors(x) and not ancestors(y)")))'
  10000 loops, best of 3: 79.3 usec per loop

  (this patch)
  $ python -m timeit -n10000 -s 'from mercurial import revsetlang as L' \
  'L._treecache.clear(); \
   L.optimize(L.analyze(L.parse("ancestors(x) and not ancestors(y)")))'
  10000 loops, best of 3: 201 usec per loop
2016-02-17 21:40:59 +09:00
Yuya Nishihara
63d5f35621 revsetlang: build optimized tree by helper function
This should make optimize() more readable, but it doubles the parsing cost.

  (original)
  $ python -m timeit -n10000 -s 'from mercurial import revsetlang as L' \
  'L.optimize(L.analyze(L.parse("::tip")))'
  10000 loops, best of 3: 18.1 usec per loop

  (this patch)
  $ python -m timeit -n10000 -s 'from mercurial import revsetlang as L' \
  'L._treecache.clear(); L.optimize(L.analyze(L.parse("::tip")))'
  10000 loops, best of 3: 48.4 usec per loop

30usec isn't dominant compared to the revset evaluation, but that is a cost.
That's why a parsed tree is cached, which can benefit in hgweb or chg server.
2016-02-17 21:38:25 +09:00
Jun Wu
4cd80fdd9c revset: do not flip "and" arguments when optimizing
Rewrite `flipand(y, x)` to `andsmally(x, y)` so the AST order is unchanged,
which could be more friendly to developers.

Differential Revision: https://phab.mercurial-scm.org/D579
2017-08-30 16:05:12 -07:00
Yuya Nishihara
3de7eef1fb revset: move order constants from revsetlang
Thanks to the recent refactor, the ordering rule is fully processed at
runtime.
2017-08-30 22:32:47 +09:00
Jun Wu
a2849aacae revset: improve documentation about ordering handling
The old documentation is a bit confusing. Namely, it's unclear whether
`define` means "I should ALWAYS define a new order", or "I should SOMETIMES
define a new order", and if it's the latter, what's the difference between
`define` and `any`?

This patch clarifies that and adds more examples.

Differential Revision: https://phab.mercurial-scm.org/D523
2017-08-25 11:20:34 -07:00
Jun Wu
647a38e249 revset: remove order information from tree (API)
Keeping `order` in tree makes AST operation harder. And there could be
invalid cases if trees could be generated and compounded freely, like:

  SetA(order=define) & SetB(order=define)
                                  ^^^^^^ couldn't be satisfied

This patch changes the code to calculate order on the fly, during tree
traversal. Optimization of reordering `and` arguments is preserved by
introducing a new internal operation `flipand`.

.. api::

   revset.stringset() now takes 'order' as the last argument.

Differential Revision: https://phab.mercurial-scm.org/D451
2017-08-20 10:55:11 -07:00
Jun Wu
31517054b3 revset: drop optimization about reordering "or" set elements
The reordering optimization is more important for "and" than "or", given the
implementation details about "addset" and "filteredset" - reordering "or"
may help "__contains__" test but not iteration, reordering "and" could help
both. We are going to simplify the tree to remove ordering information.
Removing "or" reordering optimization would make things simpler.

This effectively reverts 6820a8a645ef. It tracks back to the "orset"
function added by the initial commit of revset (c9ce8ecd6).

In the future, we might consider optimization at runtime (ex. do reordering
and rewrites inside "orset").

Differential Revision: https://phab.mercurial-scm.org/D561
2017-08-28 23:44:47 -07:00
Yuya Nishihara
ad66ada8bf 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
2017-07-08 13:07:59 +09:00
Yuya Nishihara
f742cb36a6 revset: do not compute weight for integer literal argument
In x^n and x~n, n isn't a set expression. There's no need to optimize the
right-hand side.
2017-07-08 12:49:46 +09:00
Jun Wu
f50841989e revset: make repo.anyrevs accept customized alias override (API)
Previously repo.anyrevs only expand aliases in [revsetalias] config. This
patch makes it more flexible to accept a customized dict defining aliases
without having to couple with ui.

revsetlang.expandaliases now has the signature (tree, aliases, warn=None)
which is more consistent with templater.expandaliases. revsetlang.py is now
free from "ui", which seems to be a good thing.
2017-06-24 15:29:42 -07:00
Yuya Nishihara
d1abf1770e revsetlang: check arguments passed to ancestors() before optimizing to only()
Future patches will add depth parameter to ancestors(), which isn't compatible
with only().
2017-06-18 11:57:28 +09:00
Yuya Nishihara
fbc6f41a27 revsetlang: factor out helper to match ancestors() in parsed tree
More checks will be added.
2017-06-18 11:39:03 +09:00
Martin von Zweigbergk
c3406ac3db cleanup: use set literals
We no longer support Python 2.6, so we can now use set literals.
2017-02-10 16:56:29 -08:00
Denis Laxalde
f3c282d63c revsetlang: add a getboolean helper function
This will be used to parse followlines's "descend" argument.
2017-04-15 11:26:09 +02:00
Yuya Nishihara
d4c8257977 revsetlang: enable optimization of 'x + y' expression
It's been disabled since fa623f8a8cdd, but it can be enabled now as the
ordering requirement is resolved at analyze().
2016-05-14 20:51:57 +09:00
Augie Fackler
653b207160 revsetlang: fix _quote on int on python3
Thanks to Yuya for spotting the need.
2017-03-26 16:48:29 -04:00
Augie Fackler
b00133b3e1 revsetlang: perform quoting using ui.escapestr instead of repr()
This changes one of the doctest results, but I'm pretty sure on
inspection that it's an equivalent result.
2017-03-23 10:46:50 -04:00
Augie Fackler
7257c843f2 revsetlang: add docstring with some tests to _quote 2017-03-23 10:41:34 -04:00
Augie Fackler
434ea09250 revsetlang: move quoting function to not be a closure
I'm about to change the implementation here and I'd like to add some
doctests, which means this needs to not be hidden inside another
function.
2017-03-19 01:14:19 -04:00
Augie Fackler
9acabc5cd1 revsetlang: portably bytestring-ify another pair of int() calls 2017-03-23 10:33:20 -04:00
Augie Fackler
656aa696dc revsetlang: portably turn int into bytestring 2017-03-19 01:03:53 -04:00
Yuya Nishihara
eea0ef4b6e py3: use bytestr wrapper in revsetlang.tokenize()
This backs out a2d8ce9531e1 and wraps program by bytestr() instead.
2017-03-16 21:36:21 +09:00
Yuya Nishihara
a665b1ac40 py3: use bytestr wrapper in revsetlang.formatspec()
This backs out e6d1d689544f and wraps expr by bytestr() instead.
2017-03-16 21:33:25 +09:00
Yuya Nishihara
0b54547397 py3: fix slicing of bytes in revset.formatspec() 2017-03-12 17:16:43 -07:00
Yuya Nishihara
ce52228976 py3: make set of revset operators and quotes in bytes 2017-03-12 17:13:54 -07:00
Yuya Nishihara
b72ea4927a py3: convert set of revset initial symbols back to bytes
Otherwise tokenize() would fail due to comparison between unicode and bytes.
2017-03-12 17:10:14 -07:00
Augie Fackler
9d7c26df45 revsetlang: slice out single bytes instead of indexing
For portability with Python 3.
2017-03-12 00:46:59 -05:00
Yuya Nishihara
b2229f5117 revset: split language services to revsetlang module (API)
New revsetlang module hosts parser, tokenizer, and miscellaneous functions
working on parsed tree. It does not include functions for evaluation such as
getset() and match().

  2288 mercurial/revset.py
   684 mercurial/revsetlang.py
  2972 total

get*() functions are aliased since they are common in revset.py.
2017-02-19 18:19:33 +09:00