mercurial/templater.py
changeset 28545 1d461ee26e1b
parent 28462 dbba18ba26d4
child 28546 1987ed32efca
--- a/mercurial/templater.py	Tue Mar 15 15:50:57 2016 -0700
+++ b/mercurial/templater.py	Sat Feb 13 23:54:24 2016 +0900
@@ -177,9 +177,15 @@
         raise error.ParseError(_("unterminated string"), start)
     return parsed, pos
 
-def compiletemplate(tmpl, context):
+def parse(tmpl):
+    """Parse template string into tree"""
     parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
-    return [compileexp(e, context, methods) for e in parsed]
+    assert pos == len(tmpl), 'unquoted template should be consumed'
+    return ('template', parsed)
+
+def compiletemplate(tmpl, context):
+    """Parse and compile template string to (func, data) pair"""
+    return compileexp(parse(tmpl), context, methods)
 
 def compileexp(exp, context, curmethods):
     t = exp[0]
@@ -202,8 +208,10 @@
     return [x]
 
 def gettemplate(exp, context):
+    """Compile given template tree or load named template from map file;
+    returns (func, data) pair"""
     if exp[0] == 'template':
-        return [compileexp(e, context, methods) for e in exp[1]]
+        return compileexp(exp, context, methods)
     if exp[0] == 'symbol':
         # unlike runsymbol(), here 'symbol' is always taken as template name
         # even if it exists in mapping. this allows us to override mapping
@@ -308,11 +316,11 @@
 
 def buildmap(exp, context):
     func, data = compileexp(exp[1], context, methods)
-    ctmpl = gettemplate(exp[2], context)
-    return (runmap, (func, data, ctmpl))
+    tfunc, tdata = gettemplate(exp[2], context)
+    return (runmap, (func, data, tfunc, tdata))
 
 def runmap(context, mapping, data):
-    func, data, ctmpl = data
+    func, data, tfunc, tdata = data
     d = func(context, mapping, data)
     if util.safehasattr(d, 'itermaps'):
         diter = d.itermaps()
@@ -330,7 +338,7 @@
         if isinstance(i, dict):
             lm.update(i)
             lm['originalnode'] = mapping.get('node')
-            yield runtemplate(context, lm, ctmpl)
+            yield tfunc(context, lm, tdata)
         else:
             # v is not an iterable of dicts, this happen when 'key'
             # has been fully expanded already and format is useless.
@@ -857,13 +865,13 @@
         if defaults is None:
             defaults = {}
         self._defaults = defaults
-        self._cache = {}
+        self._cache = {}  # key: (func, data)
 
     def _load(self, t):
         '''load, parse, and cache a template'''
         if t not in self._cache:
             # put poison to cut recursion while compiling 't'
-            self._cache[t] = [(_runrecursivesymbol, t)]
+            self._cache[t] = (_runrecursivesymbol, t)
             try:
                 self._cache[t] = compiletemplate(self._loader(t), self)
             except: # re-raises
@@ -875,7 +883,8 @@
         '''Perform expansion. t is name of map element to expand.
         mapping contains added elements for use during expansion. Is a
         generator.'''
-        return _flatten(runtemplate(self, mapping, self._load(t)))
+        func, data = self._load(t)
+        return _flatten(func(self, mapping, data))
 
 engines = {'default': engine}