Show More
@@ -902,6 +902,7 def debugfileset(ui, repo, expr, **opts) | |||||
902 | stages = [ |
|
902 | stages = [ | |
903 | ('parsed', pycompat.identity), |
|
903 | ('parsed', pycompat.identity), | |
904 | ('analyzed', filesetlang.analyze), |
|
904 | ('analyzed', filesetlang.analyze), | |
|
905 | ('optimized', filesetlang.optimize), | |||
905 | ] |
|
906 | ] | |
906 | stagenames = set(n for n, f in stages) |
|
907 | stagenames = set(n for n, f in stages) | |
907 |
|
908 |
@@ -524,6 +524,7 def match(ctx, expr, badfn=None): | |||||
524 | """Create a matcher for a single fileset expression""" |
|
524 | """Create a matcher for a single fileset expression""" | |
525 | tree = filesetlang.parse(expr) |
|
525 | tree = filesetlang.parse(expr) | |
526 | tree = filesetlang.analyze(tree) |
|
526 | tree = filesetlang.analyze(tree) | |
|
527 | tree = filesetlang.optimize(tree) | |||
527 | mctx = matchctx(ctx, _buildstatus(ctx, tree), badfn=badfn) |
|
528 | mctx = matchctx(ctx, _buildstatus(ctx, tree), badfn=badfn) | |
528 | return getmatch(mctx, tree) |
|
529 | return getmatch(mctx, tree) | |
529 |
|
530 |
@@ -164,12 +164,50 def _analyze(x): | |||||
164 |
|
164 | |||
165 | def analyze(x): |
|
165 | def analyze(x): | |
166 | """Transform raw parsed tree to evaluatable tree which can be fed to |
|
166 | """Transform raw parsed tree to evaluatable tree which can be fed to | |
167 | getmatch() |
|
167 | optimize() or getmatch() | |
168 |
|
168 | |||
169 | All pseudo operations should be mapped to real operations or functions |
|
169 | All pseudo operations should be mapped to real operations or functions | |
170 | defined in methods or symbols table respectively. |
|
170 | defined in methods or symbols table respectively. | |
171 | """ |
|
171 | """ | |
172 | return _analyze(x) |
|
172 | return _analyze(x) | |
173 |
|
173 | |||
|
174 | def _optimize(x): | |||
|
175 | if x is None: | |||
|
176 | return 0, x | |||
|
177 | ||||
|
178 | op = x[0] | |||
|
179 | if op in {'string', 'symbol'}: | |||
|
180 | return 0.5, x | |||
|
181 | if op == 'kindpat': | |||
|
182 | w, t = _optimize(x[2]) | |||
|
183 | return w, (op, x[1], t) | |||
|
184 | if op == 'not': | |||
|
185 | w, t = _optimize(x[1]) | |||
|
186 | return w, (op, t) | |||
|
187 | if op in {'and', 'minus'}: | |||
|
188 | wa, ta = _optimize(x[1]) | |||
|
189 | wb, tb = _optimize(x[2]) | |||
|
190 | return max(wa, wb), (op, ta, tb) | |||
|
191 | if op == 'or': | |||
|
192 | ws, ts = zip(*(_optimize(y) for y in x[1:])) | |||
|
193 | return max(ws), (op,) + ts | |||
|
194 | if op == 'list': | |||
|
195 | ws, ts = zip(*(_optimize(y) for y in x[1:])) | |||
|
196 | return sum(ws), (op,) + ts | |||
|
197 | if op == 'func': | |||
|
198 | f = getsymbol(x[1]) | |||
|
199 | w = getattr(symbols.get(f), '_weight', 1) | |||
|
200 | wa, ta = _optimize(x[2]) | |||
|
201 | return w + wa, (op, x[1], ta) | |||
|
202 | raise error.ProgrammingError('invalid operator %r' % op) | |||
|
203 | ||||
|
204 | def optimize(x): | |||
|
205 | """Reorder/rewrite evaluatable tree for optimization | |||
|
206 | ||||
|
207 | All pseudo operations should be transformed beforehand. | |||
|
208 | """ | |||
|
209 | _w, t = _optimize(x) | |||
|
210 | return t | |||
|
211 | ||||
174 | def prettyformat(tree): |
|
212 | def prettyformat(tree): | |
175 | return parser.prettyformat(tree, ('string', 'symbol')) |
|
213 | return parser.prettyformat(tree, ('string', 'symbol')) |
@@ -86,4 +86,5 def compile(text): | |||||
86 | """ |
|
86 | """ | |
87 | tree = filesetlang.parse(text) |
|
87 | tree = filesetlang.parse(text) | |
88 | tree = filesetlang.analyze(tree) |
|
88 | tree = filesetlang.analyze(tree) | |
|
89 | tree = filesetlang.optimize(tree) | |||
89 | return _compile(tree) |
|
90 | return _compile(tree) |
@@ -247,6 +247,9 class filesetpredicate(_funcregistrarbas | |||||
247 | implies 'matchctx.status()' at runtime or not (False, by |
|
247 | implies 'matchctx.status()' at runtime or not (False, by | |
248 | default). |
|
248 | default). | |
249 |
|
249 | |||
|
250 | Optional argument 'weight' indicates the estimated run-time cost, useful | |||
|
251 | for static optimization, default is 1. Higher weight means more expensive. | |||
|
252 | ||||
250 | 'filesetpredicate' instance in example above can be used to |
|
253 | 'filesetpredicate' instance in example above can be used to | |
251 | decorate multiple functions. |
|
254 | decorate multiple functions. | |
252 |
|
255 | |||
@@ -259,8 +262,9 class filesetpredicate(_funcregistrarbas | |||||
259 | _getname = _funcregistrarbase._parsefuncdecl |
|
262 | _getname = _funcregistrarbase._parsefuncdecl | |
260 | _docformat = "``%s``\n %s" |
|
263 | _docformat = "``%s``\n %s" | |
261 |
|
264 | |||
262 | def _extrasetup(self, name, func, callstatus=False): |
|
265 | def _extrasetup(self, name, func, callstatus=False, weight=1): | |
263 | func._callstatus = callstatus |
|
266 | func._callstatus = callstatus | |
|
267 | func._weight = weight | |||
264 |
|
268 | |||
265 | class _templateregistrarbase(_funcregistrarbase): |
|
269 | class _templateregistrarbase(_funcregistrarbase): | |
266 | """Base of decorator to register functions as template specific one |
|
270 | """Base of decorator to register functions as template specific one |
@@ -180,6 +180,17 Show parsed tree at stages: | |||||
180 | (func |
|
180 | (func | |
181 | (symbol 'clean') |
|
181 | (symbol 'clean') | |
182 | None))) |
|
182 | None))) | |
|
183 | * optimized: | |||
|
184 | (or | |||
|
185 | (symbol 'a1') | |||
|
186 | (symbol 'a2') | |||
|
187 | (and | |||
|
188 | (func | |||
|
189 | (symbol 'grep') | |||
|
190 | (string 'b')) | |||
|
191 | (func | |||
|
192 | (symbol 'clean') | |||
|
193 | None))) | |||
183 | * matcher: |
|
194 | * matcher: | |
184 | <unionmatcher matchers=[ |
|
195 | <unionmatcher matchers=[ | |
185 | <patternmatcher patterns='(?:a1$)'>, |
|
196 | <patternmatcher patterns='(?:a1$)'>, |
General Comments 0
You need to be logged in to leave comments.
Login now