fileset: add phase to transform parsed tree
authorYuya Nishihara <yuya@tcha.org>
Sat, 21 Jul 2018 16:11:36 +0900
changeset 38826 6371ab78c3b3
parent 38825 8a9f6076e60c
child 38827 48fc2a8af345
fileset: add phase to transform parsed tree This isn't strictly necessary, but I decided to just follow the strategy of the revset parsing.
mercurial/debugcommands.py
mercurial/fileset.py
mercurial/filesetlang.py
mercurial/minifileset.py
tests/test-fileset.t
--- a/mercurial/debugcommands.py	Fri Aug 03 11:40:15 2018 -0400
+++ b/mercurial/debugcommands.py	Sat Jul 21 16:11:36 2018 +0900
@@ -901,6 +901,7 @@
 
     stages = [
         ('parsed', pycompat.identity),
+        ('analyzed', filesetlang.analyze),
     ]
     stagenames = set(n for n, f in stages)
 
--- a/mercurial/fileset.py	Fri Aug 03 11:40:15 2018 -0400
+++ b/mercurial/fileset.py	Sat Jul 21 16:11:36 2018 +0900
@@ -528,6 +528,7 @@
 def match(ctx, expr, badfn=None):
     """Create a matcher for a single fileset expression"""
     tree = filesetlang.parse(expr)
+    tree = filesetlang.analyze(tree)
     mctx = matchctx(ctx, _buildstatus(ctx, tree), badfn=badfn)
     return getmatch(mctx, tree)
 
--- a/mercurial/filesetlang.py	Fri Aug 03 11:40:15 2018 -0400
+++ b/mercurial/filesetlang.py	Sat Jul 21 16:11:36 2018 +0900
@@ -131,5 +131,41 @@
         raise error.ParseError(err)
     return l
 
+def _analyze(x):
+    if x is None:
+        return x
+
+    op = x[0]
+    if op in {'string', 'symbol'}:
+        return x
+    if op == 'kindpat':
+        getsymbol(x[1])  # kind must be a symbol
+        t = _analyze(x[2])
+        return (op, x[1], t)
+    if op in {'group', 'not', 'negate'}:
+        t = _analyze(x[1])
+        return (op, t)
+    if op in {'and', 'minus'}:
+        ta = _analyze(x[1])
+        tb = _analyze(x[2])
+        return (op, ta, tb)
+    if op in {'list', 'or'}:
+        ts = tuple(_analyze(y) for y in x[1:])
+        return (op,) + ts
+    if op == 'func':
+        getsymbol(x[1])  # function name must be a symbol
+        ta = _analyze(x[2])
+        return (op, x[1], ta)
+    raise error.ProgrammingError('invalid operator %r' % op)
+
+def analyze(x):
+    """Transform raw parsed tree to evaluatable tree which can be fed to
+    getmatch()
+
+    All pseudo operations should be mapped to real operations or functions
+    defined in methods or symbols table respectively.
+    """
+    return _analyze(x)
+
 def prettyformat(tree):
     return parser.prettyformat(tree, ('string', 'symbol'))
--- a/mercurial/minifileset.py	Fri Aug 03 11:40:15 2018 -0400
+++ b/mercurial/minifileset.py	Sat Jul 21 16:11:36 2018 +0900
@@ -89,4 +89,5 @@
     root except for "bin/README".
     """
     tree = filesetlang.parse(text)
+    tree = filesetlang.analyze(tree)
     return _compile(tree)
--- a/tests/test-fileset.t	Fri Aug 03 11:40:15 2018 -0400
+++ b/tests/test-fileset.t	Sat Jul 21 16:11:36 2018 +0900
@@ -169,6 +169,18 @@
         (func
           (symbol 'clean')
           None))))
+  * analyzed:
+  (or
+    (symbol 'a1')
+    (symbol 'a2')
+    (group
+      (and
+        (func
+          (symbol 'grep')
+          (string 'b'))
+        (func
+          (symbol 'clean')
+          None))))
   * matcher:
   <unionmatcher matchers=[
     <patternmatcher patterns='(?:a1$)'>,