[PATCH RFC] templater: provide ring operations on integers
# HG changeset patch # User Simon Farnsworth # 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 '100 0' -u 'User Name ' + $ hg log -T '{date(date, "%s") + 1} {date(date, "%s") - 2 * 1}\n' + 101 98 $ 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@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH RFC] templater: provide ring operations on integers
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 # 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 '100 0' -u 'User Name ' + $ hg log -T '{date(date, "%s") + 1} {date(date, "%s") - 2 * 1}\n' + 101 98 $ 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@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
Re: [PATCH RFC] templater: provide ring operations on integers
On Sat, 8 Oct 2016 18:26:30 +0200, Simon Farnsworth wrote: > 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 > > # Date 1475943860 25200 > > # Sat Oct 08 09:24:20 2016 -0700 > > # Node ID e89699ba5c9f0bf883bfae7c485e50219b90b2f9 > > # Parent 91a3c58ecf938ed675f5364b88f0d663f12b0047 > > templater: provide ring operations on integers This generally looks good to me. A few nits follow. > > --- 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), Perhaps these operators should have lower binding values than template operations so 'x|y - z' is parsed as (x|y) - z. $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n' but "negate" will still need higher binding limit. $ hg debugtemplate -r0 -v '{-3|stringify}\n' https://selenic.com/repo/hg/rev/e797fdf91df4 > > -elif c.isdigit() or c == '-': > > +elif c.isdigit(): > > s = pos We can remove the next 4 or 5 lines which were necessary to handle '-'. > > if c == '-': # simply take negate operator as part of integer > > pos += 1 ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH RFC] templater: provide ring operations on integers
Simon Farnsworth wrote: > @@ -33,6 +33,9 @@ > +"+": (10, None, None, ("+", 10), None), > +"-": (10, None, ("negate", 10), ("-", 10), None), > +"*": (12, None, None, ("*", 12), None), Is it reasonable for me to ask for some user facing documentation of this? Possibly just an example. Although, we might want to wait until we're sure that this is the way we want to go before publishing it. I'd definitely like to see what the docs would look like. -- And yes, in theory math is "simple", but as soon as you switch from {Integers} to {Rings} you are going to confuse someone. If I do 20*20 on a 137 character wide screen, what happens? ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel