[PATCH RFC] templater: provide ring operations on integers

Simon Farnsworth simonfar at fb.com
Sat Oct 8 12:26:30 EDT 2016


This is RFC because I have no idea what I'm doing in the parser. If 
someone at the sprint has 5 minutes available to educate me, I can 
update this to a better version.

On 08/10/2016 18:24, Simon Farnsworth wrote:
> # HG changeset patch
> # User Simon Farnsworth <simonfar at fb.com>
> # Date 1475943860 25200
> #      Sat Oct 08 09:24:20 2016 -0700
> # Node ID e89699ba5c9f0bf883bfae7c485e50219b90b2f9
> # Parent  91a3c58ecf938ed675f5364b88f0d663f12b0047
> templater: provide ring operations on integers
>
> The termwidth template keyword is of limited use without some way to ensure
> that margins are respected. Provide the three core ring operations -
> addition, subtraction and multiplication. We can extend to division and
> modulus later if necessary.
>
> diff --git a/mercurial/templater.py b/mercurial/templater.py
> --- a/mercurial/templater.py
> +++ b/mercurial/templater.py
> @@ -33,6 +33,9 @@
>      "|": (5, None, None, ("|", 5), None),
>      "%": (6, None, None, ("%", 6), None),
>      ")": (0, None, None, None, None),
> +    "+": (10, None, None, ("+", 10), None),
> +    "-": (10, None, ("negate", 10), ("-", 10), None),
> +    "*": (12, None, None, ("*", 12), None),
>      "integer": (0, "integer", None, None, None),
>      "symbol": (0, "symbol", None, None, None),
>      "string": (0, "string", None, None, None),
> @@ -48,7 +51,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
> @@ -70,7 +73,7 @@
>                  pos += 1
>              else:
>                  raise error.ParseError(_("unterminated string"), s)
> -        elif c.isdigit() or c == '-':
> +        elif c.isdigit():
>              s = pos
>              if c == '-': # simply take negate operator as part of integer
>                  pos += 1
> @@ -420,6 +423,29 @@
>              # If so, return the expanded value.
>              yield i
>
> +def buildnegate(exp, context):
> +    arg = compileexp(exp[1], context, exprmethods)
> +    return (runnegate, arg)
> +
> +def runnegate(context, mapping, data):
> +    data = evalinteger(context, mapping, data,
> +                        _('negation needs an integer argument'))
> +    return -data
> +
> +
> +def buildarithmetic(exp, context, func):
> +    left = compileexp(exp[1], context, exprmethods)
> +    right = compileexp(exp[2], context, exprmethods)
> +    return (runarithmetic, (func, left, right))
> +
> +def runarithmetic(context, mapping, data):
> +    func, left, right = data
> +    left = evalinteger(context, mapping, left,
> +                        _('arithmetic only defined on integers'))
> +    right = evalinteger(context, mapping, right,
> +                        _('arithmetic only defined on integers'))
> +    return func(left, right)
> +
>  def buildfunc(exp, context):
>      n = getsymbol(exp[1])
>      args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])]
> @@ -906,6 +932,7 @@
>  # methods to interpret function arguments or inner expressions (e.g. {_(x)})
>  exprmethods = {
>      "integer": lambda e, c: (runinteger, e[1]),
> +    "negate": lambda e, c: (runinteger, e[1]),
>      "string": lambda e, c: (runstring, e[1]),
>      "symbol": lambda e, c: (runsymbol, e[1]),
>      "template": buildtemplate,
> @@ -914,6 +941,10 @@
>      "|": buildfilter,
>      "%": buildmap,
>      "func": buildfunc,
> +    "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
> +    "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
> +    "negate": buildnegate,
> +    "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
>      }
>
>  # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
> diff --git a/tests/test-command-template.t b/tests/test-command-template.t
> --- a/tests/test-command-template.t
> +++ b/tests/test-command-template.t
> @@ -5,6 +5,8 @@
>    $ echo line 1 > b
>    $ echo line 2 >> b
>    $ hg commit -l b -d '1000000 0' -u 'User Name <user at hostname>'
> +  $ hg log -T '{date(date, "%s") + 1} {date(date, "%s") - 2 * 1}\n'
> +  1000001 999998
>
>    $ hg add b
>    $ echo other 1 > c
> @@ -2890,14 +2892,15 @@
>    $ hg debugtemplate -v '{(-4)}\n'
>    (template
>      (group
> -      ('integer', '-4'))
> +      (negate
> +        ('integer', '4')))
>      ('string', '\n'))
>    -4
>    $ hg debugtemplate '{(-)}\n'
> -  hg: parse error at 2: integer literal without digits
> +  hg: parse error at 3: not a prefix: )
>    [255]
>    $ hg debugtemplate '{(-a)}\n'
> -  hg: parse error at 2: integer literal without digits
> +  hg: parse error: negation needs an integer argument
>    [255]
>
>  top-level integer literal is interpreted as symbol (i.e. variable name):
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://urldefense.proofpoint.com/v2/url?u=https-3A__www.mercurial-2Dscm.org_mailman_listinfo_mercurial-2Ddevel&d=DQIGaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=mEgSWILcY4c4W3zjApBQLA&m=XFhoSiP_P_OfcF1nPonzg26UVzoFHwYzgiVf6eYEeTQ&s=MJGhJupzANn-msr3d3iC-NygLglXMLwtCUJOgegoM0I&e=
>

-- 
Simon Farnsworth


More information about the Mercurial-devel mailing list