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 980198fd..18467a8f 100644 Binary files a/test/junit/org/luaj/vm2/compiler/lua5.2.1-tests.zip and b/test/junit/org/luaj/vm2/compiler/lua5.2.1-tests.zip differ