mercurial/templater.py
changeset 34535 78590585c0db
parent 34534 b3073e175c17
child 34536 4c1cfe54c08d
--- a/mercurial/templater.py	Sat Sep 09 19:13:25 2017 +0900
+++ b/mercurial/templater.py	Sat Sep 09 19:32:56 2017 +0900
@@ -35,6 +35,7 @@
 elements = {
     # token-type: binding-strength, primary, prefix, infix, suffix
     "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
+    ".": (18, None, None, (".", 18), None),
     "%": (15, None, None, ("%", 15), None),
     "|": (15, None, None, ("|", 15), None),
     "*": (5, None, None, ("*", 5), None),
@@ -60,7 +61,7 @@
         c = program[pos]
         if c.isspace(): # skip inter-token whitespace
             pass
-        elif c in "(=,)%|+-*/": # handle simple operators
+        elif c in "(=,).%|+-*/": # handle simple operators
             yield (c, None, pos)
         elif c in '"\'': # handle quoted templates
             s = pos + 1
@@ -450,6 +451,26 @@
             # If so, return the expanded value.
             yield v
 
+def buildmember(exp, context):
+    darg = compileexp(exp[1], context, methods)
+    memb = getsymbol(exp[2])
+    return (runmember, (darg, memb))
+
+def runmember(context, mapping, data):
+    darg, memb = data
+    d = evalrawexp(context, mapping, darg)
+    if util.safehasattr(d, 'tomap'):
+        lm = mapping.copy()
+        lm.update(d.tomap())
+        return runsymbol(context, lm, memb)
+    # TODO: d.get(memb) if dict-like?
+
+    sym = findsymbolicname(darg)
+    if sym:
+        raise error.ParseError(_("keyword '%s' has no member") % sym)
+    else:
+        raise error.ParseError(_("%r has no member") % d)
+
 def buildnegate(exp, context):
     arg = compileexp(exp[1], context, exprmethods)
     return (runnegate, arg)
@@ -1152,7 +1173,7 @@
     "symbol": lambda e, c: (runsymbol, e[1]),
     "template": buildtemplate,
     "group": lambda e, c: compileexp(e[1], c, exprmethods),
-#    ".": buildmember,
+    ".": buildmember,
     "|": buildfilter,
     "%": buildmap,
     "func": buildfunc,