lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi
 
I found the link eventually, I think this is it
 
https://github.com/idmillington/lua/tree/mutation-operators
 
Regards Geoff
 

From: spammealot1@live.co.uk
To: lua-l@lists.lua.org
Date: Fri, 7 Sep 2012 19:22:24 +0100
Subject: RE: increment shorthand

Hi Sven
 
I am pretty certain this work has already been done as a patch about a year or so ago but never made it to the power patch page. If I am not mistaken someone employed a Dev. to implement the patch which was then put into the public domain. I have been Googling for it but cant find it just now. If I come across it later I will post a link.
 
From what I hazily recall, I think the changes were pretty minimal, code ran a little faster, and of course would have no backwards compatibility problems. (If you know your code needs to run on older versions then dont use it)
 
So if we all keep asking for it maybe the Lua custodians will relent and add it in the next version just to shut us all up !
 
Geoff 
 

Date: Fri, 7 Sep 2012 11:06:52 -0700
From: sven2718@gmail.com
To: lua-l@lists.lua.org
Subject: increment shorthand

Hi guys,

So, yesterday afternoon I indulged in a little more parser hacking -- this time the goal was to make a lightweight patch that would give me a version of C's += sugar.

To keep things simple, the syntax sugar will only trigger in the case that we're assigning to a single lvalue, so "a,b+=2" remains a parse error.  

I know there's been a couple posts in the past inquiring about getting a C-style increment shorthand into lua.  The consensus seems to be that, if you decide you really must have a += shorthand, the best way to get there is to write a little token filter.  I don't really like token filtering in this context though.  It's difficult to write a filter that properly transforms expressions like "a*=5+2" -- one tends to end up with "a=a*5+2", rather than "a=(5+2)*a".  Expressions with complex lvalues, like "f({a=2}).y+=2", are also hard on token filters. 

Anyhow -- this does seem like the sort of thing that would be good to post on the power patch page, but I'm not entirely certain that my hack is bug free.  So perhaps it's better to just leave it at the level of a list post.  If anyone tries it, and notices a bug, (or looks at the code, and decides that it's safe), please let me know.

-Sven

The patch's entry point is in lparser.c's assignment() -- intercepting the nvars==1 case as follows:


/* hook for the increment case */
if(nvars==1) {
 
switch(ls->t.token) {
 
case '+': case '-': case '*': case '/': case TK_CONCAT:
 
return inc_assignment(ls,lh);
 
}
}

checknext(ls, '=');
nexps = explist(ls, &e);

The inc_assignment() function then looks like this:

/*
 This hack has some known deficiencies -- the biggest one being that it doesn't
 handle simple cases as efficiently as it could.  Specifically, if foo is a local, 'foo+=2'
 will result in 2 instructions, an ADD followed by a MOVE, while foo=foo+2 results in just one,
 an ADD that writes directly to the destination register.

 More complicated cases are more efficient -- for example, if we have 
   local bar = {foo={foo=2} }
 then 'bar.foo.foo=bar.foo.foo+2' will emit 3 GETs, an ADD and a SET, while 'bar.foo.foo+=2'
 only emits 2 GETs, because the += sugar is able to reuse the register holding bar.foo.

*/

static int inc_assignment(LexState *ls, struct LHS_assign *lh) {
int line;
BinOpr op = getbinopr(ls->t.token);
FuncState * fs=ls->fs;
int reg=fs->freereg;

/* it looks like we need to reserve a register here, so that in 
the case that our primary _expression_ indexed several subfields, the table
we're assigning to won't be lost.  */
luaK_reserveregs(fs,1);
luaX_next(ls);

checknext(ls, '=');

line=ls->linenumber;

enterlevel(ls);

expdesc e = lh->v;

luaK_infix(fs,op,&e);

/* we only match one expr(), so "a+=2,2" will be a parse error. */
expdesc v2;
expr(ls,&v2);

luaK_posfix(fs, op, &e, &v2, line);

leavelevel(ls);

luaK_exp2nextreg(fs,&e);

luaK_setoneret(ls->fs, &e); 
luaK_storevar(ls->fs, &lh->v, &e);
 
fs->freereg = reg; /* free registers */

return 0;
}