From f6cc1948f115cb274312070d2bfb39a140e99286 Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Sun, 2 Sep 2012 15:29:30 +0000 Subject: [PATCH] Compiler for lua 5.2 fixes. --- src/core/org/luaj/vm2/compiler/FuncState.java | 2 - src/core/org/luaj/vm2/compiler/LexState.java | 223 ++++++++++-------- .../org/luaj/vm2/compiler/lua5.2.1-tests.zip | Bin 222443 -> 230059 bytes 3 files changed, 124 insertions(+), 101 deletions(-) diff --git a/src/core/org/luaj/vm2/compiler/FuncState.java b/src/core/org/luaj/vm2/compiler/FuncState.java index ad59f6b4..b48deb91 100644 --- a/src/core/org/luaj/vm2/compiler/FuncState.java +++ b/src/core/org/luaj/vm2/compiler/FuncState.java @@ -214,8 +214,6 @@ public class FuncState extends LuaC { void enterblock (BlockCnt bl, boolean isloop) { bl.isloop = isloop; bl.nactvar = nactvar; - if (ls.dyd == null) - ls.dyd = new LexState.Dyndata(); bl.firstlabel = (short) ls.dyd.n_label; bl.firstgoto = (short) ls.dyd.n_gt; bl.upval = false; diff --git a/src/core/org/luaj/vm2/compiler/LexState.java b/src/core/org/luaj/vm2/compiler/LexState.java index 2d43c944..dfc3aaa2 100644 --- a/src/core/org/luaj/vm2/compiler/LexState.java +++ b/src/core/org/luaj/vm2/compiler/LexState.java @@ -138,7 +138,7 @@ public class LexState { InputStream z; /* input stream */ byte[] buff; /* buffer for tokens */ int nbuff; /* length of buffer */ - Dyndata dyd; /* dynamic structures used by the parser */ + Dyndata dyd = new Dyndata(); /* dynamic structures used by the parser */ LuaString source; /* current source name */ LuaString envn; /* environment variable name */ byte decpoint; /* locale decimal point */ @@ -146,11 +146,11 @@ public class LexState { /* ORDER RESERVED */ final static String luaX_tokens [] = { "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", "if", + "end", "false", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", "..", "...", "==", ">=", "<=", "~=", - "", "", "", "", + "::", "", "", "", "", "", }; final static int @@ -191,6 +191,12 @@ public class LexState { return (c >= '0' && c <= '9'); } + private boolean isxdigit(int c) { + return (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'F' && c <= 'F'); + } + private boolean isspace(int c) { return (c <= ' '); } @@ -387,19 +393,22 @@ public class LexState { */ void read_numeral(SemInfo seminfo) { + String expo = "Ee"; + int first = current; LuaC._assert (isdigit(current)); - do { - save_and_next(); - } while (isdigit(current) || current == '.'); - if (check_next("Ee")) /* `E'? */ - check_next("+-"); /* optional exponent sign */ - while (isalnum(current) || current == '_') - save_and_next(); + save_and_next(); + if (first == '0' && check_next("Xx")) + expo = "PpEe"; + while (true) { + if (check_next(expo)) + check_next("+-"); + if(isxdigit(current)) + save_and_next(); + else + break; + } save('\0'); - buffreplace((byte)'.', decpoint); /* follow locale for decimal point */ String str = new String(buff, 0, nbuff); -// if (!str2d(str, seminfo)) /* format error? */ -// trydecpoint(str, seminfo); /* try to update decimal point separator */ str2d(str, seminfo); } @@ -544,6 +553,7 @@ public class LexState { int llex(SemInfo seminfo) { nbuff = 0; while (true) { + System.out.println("llex current " + ((int) current) + "("+((char)current)+")"); switch (current) { case '\n': case '\r': { @@ -616,6 +626,15 @@ public class LexState { return TK_NE; } } + case ':': { + nextChar(); + if (current != ':') + return ':'; + else { + nextChar(); + return TK_DBCOLON; + } + } case '"': case '\'': { read_string(current, seminfo); @@ -635,7 +654,12 @@ public class LexState { return TK_NUMBER; } } - case EOZ: { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + read_numeral(seminfo); + return TK_NUMBER; + } + case EOZ: { return TK_EOS; } default: { @@ -869,23 +893,18 @@ public class LexState { f.locvars[fs.nlocvars] = new LocVars(varname,0,0); return fs.nlocvars++; } - -// -// #define new_localvarliteral(ls,v,n) \ -// this.new_localvar(luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n) -// - void new_localvarliteral(String v, int n) { - LuaString ts = newstring(v); - new_localvar(ts, n); - } - - void new_localvar(LuaString name, int n) { + void new_localvar(LuaString name) { int reg = registerlocalvar(name); - fs.checklimit(fs.nactvar + n + 1, FuncState.LUAI_MAXVARS, "local variables"); + fs.checklimit(dyd.n_actvar + 1, FuncState.LUAI_MAXVARS, "local variables"); if (dyd.actvar == null || dyd.n_actvar + 1 > dyd.actvar.length) dyd.actvar = LuaC.realloc(dyd.actvar, Math.max(1, dyd.n_actvar * 2)); - dyd.actvar[dyd.n_actvar] = new Vardesc(reg); + dyd.actvar[dyd.n_actvar++] = new Vardesc(reg); + } + + void new_localvarliteral(String v) { + LuaString ts = newstring(v); + new_localvar(ts); } void adjustlocalvars(int nvars) { @@ -1080,8 +1099,8 @@ public class LexState { /* GRAMMAR RULES */ /*============================================================*/ - void field(expdesc v) { - /* field -> ['.' | ':'] NAME */ + void fieldsel(expdesc v) { + /* fieldsel -> ['.' | ':'] NAME */ FuncState fs = this.fs; expdesc key = new expdesc(); fs.exp2anyreg(v); @@ -1215,17 +1234,13 @@ public class LexState { do { switch (this.t.token) { case TK_NAME: { /* param . NAME */ - this.new_localvar(this.str_checkname(), nparams++); + this.new_localvar(this.str_checkname()); + ++nparams; break; } case TK_DOTS: { /* param . `...' */ this.next(); - if (LUA_COMPAT_VARARG) { - /* use `arg' as default name */ - this.new_localvarliteral("arg", nparams++); - f.is_vararg = LuaC.VARARG_HASARG | LuaC.VARARG_NEEDSARG; - } - f.is_vararg |= LuaC.VARARG_ISVARARG; + f.is_vararg = 1; break; } default: this.syntaxerror(" or " + LUA_QL("...") + " expected"); @@ -1246,7 +1261,7 @@ public class LexState { new_fs.f.linedefined = line; this.checknext('('); if (needself) { - new_localvarliteral("self", 0); + new_localvarliteral("self"); adjustlocalvars(1); } this.parlist(); @@ -1325,11 +1340,11 @@ public class LexState { ** ======================================================================= */ - void prefixexp(expdesc v) { - /* prefixexp -> NAME | '(' expr ')' */ - switch (this.t.token) { + void primaryexp (expdesc v) { + /* primaryexp -> NAME | '(' expr ')' */ + switch (t.token) { case '(': { - int line = this.linenumber; + int line = linenumber; this.next(); this.expr(v); this.check_match(')', '(', line); @@ -1337,28 +1352,26 @@ public class LexState { return; } case TK_NAME: { - this.singlevar(v); + singlevar(v); return; } default: { - this.syntaxerror("unexpected symbol"); + this.syntaxerror("unexpected symbol " + t.token + " (" + ((char) t.token) + ")"); return; } } } - void primaryexp(expdesc v) { - /* - * primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | - * funcargs } - */ - FuncState fs = this.fs; - this.prefixexp(v); + void suffixedexp (expdesc v) { + /* suffixedexp -> + primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ + int line = linenumber; + primaryexp(v); for (;;) { - switch (this.t.token) { - case '.': { /* field */ - this.field(v); + switch (t.token) { + case '.': { /* fieldsel */ + this.fieldsel(v); break; } case '[': { /* `[' exp1 `]' */ @@ -1387,7 +1400,7 @@ public class LexState { return; } } - } + } void simpleexp(expdesc v) { @@ -1435,7 +1448,7 @@ public class LexState { return; } default: { - this.primaryexp(v); + this.suffixedexp(v); return; } } @@ -1680,7 +1693,7 @@ public class LexState { next(); /* skip break */ label = LuaString.valueOf("break"); } - g = newlabelentry(LuaC.grow(dyd.gt, dyd.n_gt+1), dyd.n_gt++, label, line, pc); + g = newlabelentry(dyd.gt =LuaC.grow(dyd.gt, dyd.n_gt+1), dyd.n_gt++, label, line, pc); findlabel(g); /* close it if label already defined */ } @@ -1785,10 +1798,10 @@ public class LexState { /* fornum -> NAME = exp1,exp1[,exp1] forbody */ FuncState fs = this.fs; int base = fs.freereg; - this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_INDEX, 0); - this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_LIMIT, 1); - this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_STEP, 2); - this.new_localvar(varname, 3); + this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_INDEX); + this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_LIMIT); + this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_STEP); + this.new_localvar(varname); this.checknext('='); this.exp1(); /* initial value */ this.checknext(','); @@ -1807,17 +1820,19 @@ public class LexState { /* forlist -> NAME {,NAME} IN explist1 forbody */ FuncState fs = this.fs; expdesc e = new expdesc(); - int nvars = 0; + int nvars = 4; /* gen, state, control, plus at least one declared var */ int line; int base = fs.freereg; /* create control variables */ - this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_GENERATOR, nvars++); - this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_STATE, nvars++); - this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_CONTROL, nvars++); + this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_GENERATOR); + this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_STATE); + this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_CONTROL); /* create declared variables */ - this.new_localvar(indexname, nvars++); - while (this.testnext(',')) - this.new_localvar(this.str_checkname(), nvars++); + this.new_localvar(indexname); + while (this.testnext(',')) { + this.new_localvar(this.str_checkname()); + ++nvars; + } this.checknext(TK_IN); line = this.linenumber; this.adjust_assign(3, this.explist1(e), e); @@ -1850,45 +1865,54 @@ public class LexState { } - int test_then_block() { + void test_then_block(IntPtr escapelist) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ - int condexit; + expdesc v = new expdesc(); + BlockCnt bl = new BlockCnt(); + int jf; /* instruction to skip 'then' code (if condition is false) */ this.next(); /* skip IF or ELSEIF */ - condexit = this.cond(); + expr(v); /* read expression */ this.checknext(TK_THEN); - this.block(); /* `then' part */ - return condexit; + if (t.token == TK_GOTO || t.token == TK_BREAK) { + fs.goiffalse(v); /* will jump to label if condition is true */ + fs.enterblock(bl, false); /* must enter block before 'goto' */ + gotostat(v.t.i); /* handle goto/break */ + skipnoopstat(); /* skip other no-op statements */ + if (block_follow(false)) { /* 'goto' is the entire block? */ + fs.leaveblock(); + return; /* and that is it */ + } else + /* must skip over 'then' part if condition is false */ + jf = fs.jump(); + } else { /* regular case (not goto/break) */ + fs.goiftrue(v); /* skip over block if condition is false */ + fs.enterblock(bl, false); + jf = v.f.i; + } + statlist(); /* `then' part */ + fs.leaveblock(); + if (t.token == TK_ELSE || t.token == TK_ELSEIF) + fs.concat(escapelist, fs.jump()); /* must jump over it */ + fs.patchtohere(jf); } void ifstat(int line) { - /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] - * END */ - FuncState fs = this.fs; - int flist; - IntPtr escapelist = new IntPtr(NO_JUMP); - flist = test_then_block(); /* IF cond THEN block */ - while (this.t.token == TK_ELSEIF) { - fs.concat(escapelist, fs.jump()); - fs.patchtohere(flist); - flist = test_then_block(); /* ELSEIF cond THEN block */ - } - if (this.t.token == TK_ELSE) { - fs.concat(escapelist, fs.jump()); - fs.patchtohere(flist); - this.next(); /* skip ELSE (after patch, for correct line info) */ - this.block(); /* `else' part */ - } else - fs.concat(escapelist, flist); - fs.patchtohere(escapelist.i); - this.check_match(TK_END, TK_IF, line); + IntPtr escapelist = new IntPtr(NO_JUMP); /* exit list for finished parts */ + test_then_block(escapelist); /* IF cond THEN block */ + while (t.token == TK_ELSEIF) + test_then_block(escapelist); /* ELSEIF cond THEN block */ + if (testnext(TK_ELSE)) + block(); /* `else' part */ + check_match(TK_END, TK_IF, line); + fs.patchtohere(escapelist.i); /* patch escape list to 'if' end */ } void localfunc() { expdesc v = new expdesc(); expdesc b = new expdesc(); FuncState fs = this.fs; - this.new_localvar(this.str_checkname(), 0); + this.new_localvar(this.str_checkname()); v.init(VLOCAL, fs.freereg); fs.reserveregs(1); this.adjustlocalvars(1); @@ -1905,7 +1929,8 @@ public class LexState { int nexps; expdesc e = new expdesc(); do { - this.new_localvar(this.str_checkname(), nvars++); + this.new_localvar(this.str_checkname()); + ++nvars; } while (this.testnext(',')); if (this.testnext('=')) nexps = this.explist1(e); @@ -1920,15 +1945,15 @@ public class LexState { boolean funcname(expdesc v) { /* funcname -> NAME {field} [`:' NAME] */ - boolean needself = false; + boolean ismethod = false; this.singlevar(v); while (this.t.token == '.') - this.field(v); + this.fieldsel(v); if (this.t.token == ':') { - needself = true; - this.field(v); + ismethod = true; + this.fieldsel(v); } - return needself; + return ismethod; } diff --git a/test/junit/org/luaj/vm2/compiler/lua5.2.1-tests.zip b/test/junit/org/luaj/vm2/compiler/lua5.2.1-tests.zip index 980198fd6d36f646551f0f482bd21f1b23f19cd5..18467a8f0e42998551580968c4d97cdd6214c113 100644 GIT binary patch delta 8700 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 delta 3933 zcmai13s98T6}}Hx9j_-JgEm_TYZlUCDn@4vhJ%S_s3W|_J7obQ}_ zUf^N5F(1$&od2?E3OWNgmoRDGughY~N;6fa3)szH=NK*{m)K<`nBBR=-HdfCESZswtluJfRJ+*LQJGpIrZB{go`0`=kIO~ zhuOK@TdDcI6`Y3Q$v&!=VKgy>psh1Nj?`Ad-Hj;GVGEN zL4#3YE3PU77cGugFIDNJz5bKm-AeH#EQmFf*Ju}ey&c2PhtQDEPL-fb|ui<+G`yXcuf`RZlnpzPN}2`QK= zqYRrLQ8T3X$-H2!e{-y@9g_Q~$@y6y-5ClyW0`O@ql`zoEu+7SlFM@;vy4YLr^KjV8ueY&VexTbUrP>cLtyFw+`9C4+I188gIk<;i4}i22D7hOl zs(1{n?xNy3SV76_zMKo0RowFaNw#DdEULyTYl1C*XRaiMezN1EAxSLCmr0EL2Rj)g zpZ{aa!J8L+2+23dnuF`X+*NdsYsYlLjbQY)G=yLEfr>a;#6`*YrhRc-)E)XTsiQIh zij#Si^frD3FARjW(^0Yws;6^T+Dj^K&w)+TF+AZj_AYax%yQ_6Pa$2IWwb3h`_+ z(W*Hp4p? z(CG5B`1SDx8YD4NKBe~~;HgqBoW~xt%G037G%XG)6S4dnM9)ck!h5|lZX8=23$w~G zl?|fNTu*b}UB>csusfFtAnYcq`ebKH9$Tk}&Ke1Y{SzY%EUjgC{NdvUDUJOSElyPf zRSK)uYZ5jxvZpl&2gRKkVo)>y_KlQw{^&gx7Ya+xF(VY;W@hNAas?98o@0Ry> z3`S4@tX(S4Wl7uWTq=R-{1?OE+A3}}j3MGf3Dz)v;H7LVeS0rb=CAf7HQeT9WJ(fjUW0yh zZFc+R=1sR-!}ppD&uGwJdQNDBDbqRvV0@0$!kOTqQn2NsiA0S;*%WBc#nI^!)^aI~ z&O_fPXoSCffe2QG4S5n-L#vRA-R0%U&u2qVKDWAo(F-@fLS_Ntj@97yE+W{97MPI3 zgE1z91PghELtMCmT3cUyr}7d`dDfTPSTk8U?ov`*A;gy?~d{4sl!NY zE)~u9-Uu;b&puB`1bJG6bhLs9UN*tqVjdj-zscF<4Q)klv_-IMJ5j0H6?QFE!?BVf zC9|%H08+LUItyidw7d=7>rq;pQJ)T?QubgN(-n(R)ZQnyQ5OWm#_gDYvw ztvtOmM?m^ha->ki?!*DV4Ou?ow*pGeoE0HWA~>1i2gCIv$$Wl+nBssHg3($N>yj6@LmJ zq~&`^sU8y7NskDuujV7w?d=DNALeXAMQtyf2&97Zwawrmen_uDX{|piLnz1vptVM} z!_Wl)3Tjb98{+n8Di#5&yV)?ro^1eXHxI$jvQv;F^iP}J_+DE9jLqhw_@a?iECE)% zKP4pXC%(jwrAEw$=T_t0@bOeE1HnGT`*KzeUS7+kVi*RBycEGJd0jip^jUQSrIq zt-J6b6^p_k_!ke11}%8@F<4N%1*|ild4xJu9x|>frBo5C)3yX47Q|E#@OU zhra93p;8?Ku`~>N1i{$-d~yO4^C3oa9*cd>Z@s|a=moFyMC@q(W(Jchf<}Hy85-SH z2QQa#tH&rV2R3$KAB2=6k=B%RU(d~A+_G8Ee(2qRrB}a!4|<6us~HM z9yXnZX7S&hwO2QyEB(DpE&>`?pbCXPxCNorXcc#XL2TRvZ1x+E8NmY3{?t^rVy^^> zwZJPA#0=foJRa+EL+GjDLHtTQSDQkt3K~DoV=wTd6S=5=i+A$Az`|!6r$a^^x`^w7 d{|HaD`d}%~PxaM_`bxsT@JK>V&BY(J