mercurial/templater.py
changeset 30115 8e42dfde93d1
parent 30083 bd1f043d1ea3
child 30116 1c01fa29630f
equal deleted inserted replaced
30114:ad43458d3529 30115:8e42dfde93d1
    31     "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
    31     "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
    32     ",": (2, None, None, ("list", 2), None),
    32     ",": (2, None, None, ("list", 2), None),
    33     "|": (5, None, None, ("|", 5), None),
    33     "|": (5, None, None, ("|", 5), None),
    34     "%": (6, None, None, ("%", 6), None),
    34     "%": (6, None, None, ("%", 6), None),
    35     ")": (0, None, None, None, None),
    35     ")": (0, None, None, None, None),
       
    36     "+": (3, None, None, ("+", 3), None),
       
    37     "-": (3, None, ("negate", 10), ("-", 3), None),
       
    38     "*": (4, None, None, ("*", 4), None),
       
    39     "/": (4, None, None, ("/", 4), None),
    36     "integer": (0, "integer", None, None, None),
    40     "integer": (0, "integer", None, None, None),
    37     "symbol": (0, "symbol", None, None, None),
    41     "symbol": (0, "symbol", None, None, None),
    38     "string": (0, "string", None, None, None),
    42     "string": (0, "string", None, None, None),
    39     "template": (0, "template", None, None, None),
    43     "template": (0, "template", None, None, None),
    40     "end": (0, None, None, None, None),
    44     "end": (0, None, None, None, None),
    46     pos = start
    50     pos = start
    47     while pos < end:
    51     while pos < end:
    48         c = program[pos]
    52         c = program[pos]
    49         if c.isspace(): # skip inter-token whitespace
    53         if c.isspace(): # skip inter-token whitespace
    50             pass
    54             pass
    51         elif c in "(,)%|": # handle simple operators
    55         elif c in "(,)%|+-*/": # handle simple operators
    52             yield (c, None, pos)
    56             yield (c, None, pos)
    53         elif c in '"\'': # handle quoted templates
    57         elif c in '"\'': # handle quoted templates
    54             s = pos + 1
    58             s = pos + 1
    55             data, pos = _parsetemplate(program, s, end, c)
    59             data, pos = _parsetemplate(program, s, end, c)
    56             yield ('template', data, s)
    60             yield ('template', data, s)
    68                     yield ('string', program[s:pos], s)
    72                     yield ('string', program[s:pos], s)
    69                     break
    73                     break
    70                 pos += 1
    74                 pos += 1
    71             else:
    75             else:
    72                 raise error.ParseError(_("unterminated string"), s)
    76                 raise error.ParseError(_("unterminated string"), s)
    73         elif c.isdigit() or c == '-':
    77         elif c.isdigit():
    74             s = pos
    78             s = pos
    75             if c == '-': # simply take negate operator as part of integer
       
    76                 pos += 1
       
    77             if pos >= end or not program[pos].isdigit():
       
    78                 raise error.ParseError(_("integer literal without digits"), s)
       
    79             pos += 1
       
    80             while pos < end:
    79             while pos < end:
    81                 d = program[pos]
    80                 d = program[pos]
    82                 if not d.isdigit():
    81                 if not d.isdigit():
    83                     break
    82                     break
    84                 pos += 1
    83                 pos += 1
   418             # v is not an iterable of dicts, this happen when 'key'
   417             # v is not an iterable of dicts, this happen when 'key'
   419             # has been fully expanded already and format is useless.
   418             # has been fully expanded already and format is useless.
   420             # If so, return the expanded value.
   419             # If so, return the expanded value.
   421             yield i
   420             yield i
   422 
   421 
       
   422 def buildnegate(exp, context):
       
   423     arg = compileexp(exp[1], context, exprmethods)
       
   424     return (runnegate, arg)
       
   425 
       
   426 def runnegate(context, mapping, data):
       
   427     data = evalinteger(context, mapping, data,
       
   428                        _('negation needs an integer argument'))
       
   429     return -data
       
   430 
       
   431 def buildarithmetic(exp, context, func):
       
   432     left = compileexp(exp[1], context, exprmethods)
       
   433     right = compileexp(exp[2], context, exprmethods)
       
   434     return (runarithmetic, (func, left, right))
       
   435 
       
   436 def runarithmetic(context, mapping, data):
       
   437     func, left, right = data
       
   438     left = evalinteger(context, mapping, left,
       
   439                        _('arithmetic only defined on integers'))
       
   440     right = evalinteger(context, mapping, right,
       
   441                         _('arithmetic only defined on integers'))
       
   442     return func(left, right)
       
   443 
   423 def buildfunc(exp, context):
   444 def buildfunc(exp, context):
   424     n = getsymbol(exp[1])
   445     n = getsymbol(exp[1])
   425     args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])]
   446     args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])]
   426     if n in funcs:
   447     if n in funcs:
   427         f = funcs[n]
   448         f = funcs[n]
   711                 raise error.ParseError(_("localdate expects a timezone"))
   732                 raise error.ParseError(_("localdate expects a timezone"))
   712     else:
   733     else:
   713         tzoffset = util.makedate()[1]
   734         tzoffset = util.makedate()[1]
   714     return (date[0], tzoffset)
   735     return (date[0], tzoffset)
   715 
   736 
       
   737 @templatefunc('mod(a, b)')
       
   738 def mod(context, mapping, args):
       
   739     """Calculate a mod b such that a / b + a mod b == a"""
       
   740     if not len(args) == 2:
       
   741         # i18n: "mod" is a keyword
       
   742         raise error.ParseError(_("mod expects two arguments"))
       
   743 
       
   744     left = evalinteger(context, mapping, args[0],
       
   745                        _('arithmetic only defined on integers'))
       
   746     right = evalinteger(context, mapping, args[1],
       
   747                         _('arithmetic only defined on integers'))
       
   748 
       
   749     return left % right
       
   750 
   716 @templatefunc('relpath(path)')
   751 @templatefunc('relpath(path)')
   717 def relpath(context, mapping, args):
   752 def relpath(context, mapping, args):
   718     """Convert a repository-absolute path into a filesystem path relative to
   753     """Convert a repository-absolute path into a filesystem path relative to
   719     the current working directory."""
   754     the current working directory."""
   720     if len(args) != 1:
   755     if len(args) != 1:
   924     "group": lambda e, c: compileexp(e[1], c, exprmethods),
   959     "group": lambda e, c: compileexp(e[1], c, exprmethods),
   925 #    ".": buildmember,
   960 #    ".": buildmember,
   926     "|": buildfilter,
   961     "|": buildfilter,
   927     "%": buildmap,
   962     "%": buildmap,
   928     "func": buildfunc,
   963     "func": buildfunc,
       
   964     "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
       
   965     "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
       
   966     "negate": buildnegate,
       
   967     "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
       
   968     "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
   929     }
   969     }
   930 
   970 
   931 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
   971 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
   932 methods = exprmethods.copy()
   972 methods = exprmethods.copy()
   933 methods["integer"] = exprmethods["symbol"]  # '{1}' as variable
   973 methods["integer"] = exprmethods["symbol"]  # '{1}' as variable