App/Xtn/Mediawiki/Scribunto/Luaj
Contents
- 1 Source
- 2 Modification
-
3 luaj_xowa changes
- 3.1 Luaj 2.0.3 errors fixed in 3.0
- 3.2 Luaj 2.0.3 features removed from 3.0
-
3.3 Luaj 3.0 defects
- 3.3.1 os.date does not accept UTC format
- 3.3.2 string.gsub fails with out_of_bounds error
- 3.3.3 string.gsub fails if string is empty
- 3.3.4 string.format ignores precision for double args
- 3.3.5 string.gmatch issues
- 3.3.6 string.tonumber should trim all whitespace
- 3.3.7 multi-byte strings not fully supported
- 3.4 build.xml
- 3.5 Luaj tests
- 4 Scribunto related
- 5 Miscellaneous changes
Source
The luaj_xowa.jar was built using the source at http://sourceforge.net/projects/luaj/files/luaj-3.0/3.0-beta2/luaj-3.0-beta2.zip/download.
Its source is not currently included with XOWA. It is available at the following location: https://sourceforge.net/projects/xowa/files/support/luaj/
Modification
The luaj_xowa.jar was created for the following reasons:
- Backward compatibility:
- Scribunto is currently using Lua 5.1 whereas luaj 3.0 is designed for Lua 5.2
- Lua 5.2 is not backward-compatible with Lua 5.1; several functions are obsoleted (for example, table.maxn)
- The luaj_xowa.jar was tailored to support Scribunto's 5.1 environment.
- Patches / bug fixes:
- Luaj has a handful of minor issues / defects. They are listed below.
luaj_xowa changes
Luaj 2.0.3 errors fixed in 3.0
os.time doesn't handle dates before 1970
- fix : incorrect Birth / Date; EX: ru.w:Пушкин,_Александр_Сергеевич
- file: /src/core/org/luaj/vm2/lib/OsLib.java
pairs.next fails when setting val to null
- fix : Finnish declension table; EX:d:Latvia
- file: /src/core/org/luaj/vm2/LuaTable.java
Luaj 2.0.3 features removed from 3.0
string.gfind deprecated
- fix : missing Video_game_reviews; EX: w:Sonic_Heroes
- file: /src/core/org/luaj/vm2/lib/StringLib.java
- code: call
old: "sub"} ); new: "sub", "gfind"} );
- code: invoke
add: case 4: case 9: return StringLib.gmatch( args );
math.log10 deprecated
- fix : blank references; EX:w:Earth
- file: /src/jse/org/luaj/vm2/lib/JseMathLib.java
- code:
math.set("log10", new log10()); static final class log10 extends UnaryOp { protected double call(double d) { return Math.log10(d); } }
math.mod deprecated
- fix : missing table; EX:d:աղբիւր
- file: /src/core/org/luaj/vm2/lib/MathLib.java
- code:
fmod fmod_func = new fmod(); math.set("mod", fmod_func); math.set("fmod", fmod_func);
table.maxn deprecated
file: /src/core/org/luaj/vm2/lib/TableLib.java
- code:
public LuaValue getn() { int len = length(); for (int n = len; n > 0; --n ) if ( !rawget(n).isnil() ) return LuaInteger.valueOf(n); return ZERO; }
file: /src/core/org/luaj/vm2/lib/TableLib.java
table.set("maxn", new maxn()); static class maxn extends OneArgFunction { public LuaValue call(LuaValue arg) { return LuaValue.valueOf(arg.checktable().maxn()); } }
table.getn deprecated
- fix : missing text; EX: d:aceite d:Module:pt-verb-form-of
- file: /src/core/org/luaj/vm2/LuaTable.java
code:
public LuaValue getn() { int len = length(); for (int n = len; n > 0; --n ) if ( !rawget(n).isnil() ) return LuaInteger.valueOf(n); return ZERO; }
- file: /src/core/org/luaj/vm2/lib/TableLib.java
- code:
table.set("getn", new getn()); static class getn extends OneArgFunction { public LuaValue call(LuaValue arg) { return arg.checktable().getn(); } }
automatic arg variable in varargs function deprecated
- fix : Horizontal timeline; EX: w:Cretaceous%E2%80%93Paleogene_extinction_event
- file: /src/core/org/luaj/vm2/LuaClosure.java
code:
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */ // stack[a] = upValues[i>>>23].getValue().get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); // HACK: handle deprecated "arg" for "..." int OP_GETTABUP_c = (i>>14)&0x1ff; boolean OP_GETTABUP_b = OP_GETTABUP_c>0xff; LuaValue OP_GETTABUP_idx = OP_GETTABUP_b ? k[OP_GETTABUP_c&0x0ff]: stack[OP_GETTABUP_c]; stack[a] = upValues[i>>>23].getValue().get(OP_GETTABUP_idx); // HACK: handle deprecated "arg" if ( p.is_vararg == 1 && stack[a] == NIL && OP_GETTABUP_b && "arg".equals(OP_GETTABUP_idx.tojstring()) ) stack[a] = new LuaTable(varargs); continue;
Luaj 3.0 defects
os.date does not accept UTC format
- fix : incorrect age in ym; EX:w:Supreme_Court_of_the_United_States
- file: /src/core/org/luaj/vm2/lib/OsLib.java
- proc: invoke.DATE
boolean utc = false; if (s.startsWith("!")) { utc = true; s = s.substring(1); } if (s.equals("*t")) { Calendar d = Calendar.getInstance(); long time_in_ms = (long)(t*1000); if (utc) { java.util.TimeZone current_tz = d.getTimeZone(); int offset_from_utc = current_tz.getOffset(time_in_ms); time_in_ms += -offset_from_utc; }
string.gsub fails with out_of_bounds error
- fix : blank references; EX:w:Earth
- file: /src/core/org/luaj/vm2/lib/StringLib.java
- proc: gsub
old: if ( anchor ) break; new: if ( anchor ) break; if (soffset >= srclen) break; // assert soffset is in bounds, else will throw ArrayIndexOutOfBounds exception;
string.gsub fails if string is empty
- fix : blank references; EX:w:Woburn,_Massachusetts
- file: /src/core/org/luaj/vm2/lib/StringLib.java
- proc: gsub
static Varargs gsub( Varargs args ) { LuaString src = args.checkstring( 1 ); final int srclen = src.length(); if (srclen == 0) return varargsOf(src, LuaValue.ZERO); // exit early
string.format ignores precision for double args
- fix : Convert calls will show full precision for numbers; EX:w:Tomato
- file: /src/core/org/luaj/vm2/lib/StringLib.java
FormatDesc fdsc = new FormatDesc(args, fmt, i ); int fdsc_bgn = i;
old: case 'G': fdsc.format( result, args.checkdouble( arg ) ); new: case 'G': String fmt_str = new String(fmt.m_bytes, fdsc_bgn - 1, fdsc.length + 1); // -1 to include %; +1 to account for included %; basically get everything between % and f; EX: a%.1fb -> %.1f fdsc.format( result, fmt_str, args.checkdouble( arg ));
- proc: format
old: buf.append( v) ); new: // buf.append( String.valueOf( x ) ); if (fmt.startsWith("%0.")) fmt = "%" + fmt.substring(2); // remove leading 0, else MissingFormatWidthException int fmt_len = fmt.length(); if (fmt_len > 1 && fmt.charAt(fmt_len - 2) == '.') // penultimmate char has "." fmt = fmt.substring(0, fmt_len - 1) + "0" + fmt.charAt(fmt_len - 1); // add trailing 0, else UnknownFormatConversionException; EX: "02.f" -> "02.0f" buf.append( String.format(fmt, v) ); // call String.format
-
note: also fixes format failures
- %0.1f -> remove leading 0
- %02.f -> add trailing 0 after .
- note: forces a 1.5 JRE (as opposed to 1.3)
string.gmatch issues
- fix : Multiple pages in enwiki's Wikipedia namespace; EX: Wikipedia:CS1/test_basics
- file: /src/core/org/luaj/vm2/lib/StringLib.java
- proc: GmatchAux.invoke
old: for ( ; soffset<srclen; soffset++ ) { new: for ( ; soffset<=srclen; soffset++ ) {
old: soffset = res; new: int soffset_adj = res == soffset ? 1 : 0; soffset = res + soffset_adj;
string.tonumber should trim all whitespace
- fix: Population tables; EX: w:Woburn,_Massachusetts
- file: /src/core/org/luaj/vm2/LuaString.java
- proc: scannumber
// trim ws int idx = i; while (idx < j) { switch (m_bytes[idx]) { case 9: case 10: case 13: case 32: ++idx; i = idx; break; default: idx = j; break; } } idx = j - 1; while (idx >= i) { switch (m_bytes[idx]) { case 9: case 10: case 13: case 32: j = idx; --idx; break; default: idx = i -1; break; } }
multi-byte strings not fully supported
- fix : Thai calendar; EX:th.w:เหตุการณ์ปัจจุบัน
- file: /src/core/org/luaj/vm2/LuaString.java
public static LuaString valueOf(char[] chars, int off, int len) { // COMMENTED: does not handle 2+ byte chars; assumes 1 char = 1 byte // byte[] b = new byte[len]; // for ( int i=0; i<len; i++ ) // b[i] = (byte) chars[i + off]; // return valueOf(b, 0, len); int bry_len = 0; for (int i = 0; i < len; i++) { // iterate over chars to sum all single / multi-byte chars int b_len = LuaString.Utf16_Len_by_char((int)(chars[i + off])); if (b_len == 4) ++i; // 4 bytes; surrogate pair; skip next char; bry_len += b_len; } byte[] bry = new byte[bry_len]; int bry_idx = 0; int i = 0; while (i < len) { char c = chars[i + off]; int b_len = Utf16_Encode_char(c, chars, i, bry, bry_idx); bry_idx += b_len; i += b_len == 4 ? 2 : 1; // 4 bytes; surrogate pair; skip next char; } return valueOf(bry, 0, bry_len); } public static String decodeAsUtf8(byte[] bytes, int offset, int length) { // COMMENTED: does not handle 3+ byte chars // int i,j,n,b; // for ( i=offset,j=offset+length,n=0; i<j; ++n ) { // switch ( 0xE0 & bytes[i++] ) { // case 0xE0: ++i; // case 0xC0: ++i; // } // } // char[] chars=new char[n]; // for ( i=offset,j=offset+length,n=0; i<j; ) { // chars[n++] = (char) ( // ((b=bytes[i++])>=0||i>=j)? b: // (b<-32||i+1>=j)? (((b&0x3f) << 6) | (bytes[i++]&0x3f)): // (((b&0xf) << 12) | ((bytes[i++]&0x3f)<<6) | (bytes[i++]&0x3f))); // } // return new String(chars); return new String(bytes, offset, length, java.nio.charset.Charset.forName("UTF-8")); } public static int lengthAsUtf8(char[] chars) { // COMMENTED: does not handle 3+ byte chars // int i,b; // char c; // for ( i=b=chars.length; --i>=0; ) // if ( (c=chars[i]) >=0x80 ) // b += (c>=0x800)? 2: 1; // return b; int len = chars.length; int rv = 0; for (int i = 0; i < len; i++) { int b_len = LuaString.Utf16_Len_by_char(chars[i]); if (b_len == 4) ++i; // 4 bytes; surrogate pair; skip next char; rv += b_len; } return rv; } public static int encodeToUtf8(char[] chars, int nchars, byte[] bytes, int off) { // COMMENTED: does not handle 4+ byte chars; already using Encode_by_int, so might as well be consistent // char c; // int j = off; // for ( int i=0; i<nchars; i++ ) { // if ( (c = chars[i]) < 0x80 ) { // bytes[j++] = (byte) c; // } else if ( c < 0x800 ) { // bytes[j++] = (byte) (0xC0 | ((c>>6) & 0x1f)); // bytes[j++] = (byte) (0x80 | ( c & 0x3f)); // } else { // bytes[j++] = (byte) (0xE0 | ((c>>12) & 0x0f)); // bytes[j++] = (byte) (0x80 | ((c>>6) & 0x3f)); // bytes[j++] = (byte) (0x80 | ( c & 0x3f)); // } // } // return j - off; int bry_idx = off; int i = 0; while (i < nchars) { char c = chars[i]; int bytes_read = Utf16_Encode_char(c, chars, i, bytes, bry_idx); bry_idx += bytes_read; i += bytes_read == 4 ? 2 : 1; // 4 bytes; surrogate pair; skip next char; } return nchars; // NOTE: code returned # of bytes which is wrong; Globals.UTF8Stream.read caches rv as j which is used as index to char[] not byte[]; will throw out of bounds exception if bytes returned } private static int Utf16_Len_by_char(int c) { if ((c > -1) && (c < 128)) return 1; // 1 << 7 else if (c < 2048) return 2; // 1 << 11 else if((c > 55295) // 0xD800 && (c < 56320)) return 4; // 0xDFFF else if (c < 65536) return 3; // 1 << 16 else throw new RuntimeException("UTF-16 int must be between 0 and 2097152; char=" + c); } public static int Utf16_Len_by_int(int c) { if ((c > -1) && (c < 128)) return 1; // 1 << 7 else if (c < 2048) return 2; // 1 << 11 else if (c < 65536) return 3; // 1 << 16 else if (c < 2097152) return 4; else throw new RuntimeException("UTF-16 int must be between 0 and 2097152; char=" + c); } public static int Utf8_Len_of_char_by_1st_byte(byte b) {// SEE:w:UTF-8 int i = b & 0xff; // PATCH.JAVA:need to convert to unsigned byte switch (i) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: return 1; case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: return 2; case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: return 3; case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: return 4; default: throw new RuntimeException("invalid initial utf8 byte; byte=" + b); } } public static int Utf16_Decode_to_int(byte[] ary, int pos) { byte b0 = ary[pos]; if ((b0 & 0x80) == 0) { return b0; } else if ((b0 & 0xE0) == 0xC0) { return ( b0 & 0x1f) << 6 | ( ary[pos + 1] & 0x3f) ; } else if ((b0 & 0xF0) == 0xE0) { return ( b0 & 0x0f) << 12 | ((ary[pos + 1] & 0x3f) << 6) | ( ary[pos + 2] & 0x3f) ; } else if ((b0 & 0xF8) == 0xF0) { return ( b0 & 0x07) << 18 | ((ary[pos + 1] & 0x3f) << 12) | ((ary[pos + 2] & 0x3f) << 6) | ( ary[pos + 3] & 0x3f) ; } else throw new RuntimeException("invalid utf8 byte: byte=" + b0); } public static int Utf16_Encode_int(int c, byte[] src, int pos) { if ((c > -1) && (c < 128)) { src[ pos] = (byte)c; return 1; } else if (c < 2048) { src[ pos] = (byte)(0xC0 | (c >> 6)); src[++pos] = (byte)(0x80 | (c & 0x3F)); return 2; } else if (c < 65536) { src[pos] = (byte)(0xE0 | (c >> 12)); src[++pos] = (byte)(0x80 | (c >> 6) & 0x3F); src[++pos] = (byte)(0x80 | (c & 0x3F)); return 3; } else if (c < 2097152) { src[pos] = (byte)(0xF0 | (c >> 18)); src[++pos] = (byte)(0x80 | (c >> 12) & 0x3F); src[++pos] = (byte)(0x80 | (c >> 6) & 0x3F); src[++pos] = (byte)(0x80 | (c & 0x3F)); return 4; } else throw new RuntimeException("UTF-16 int must be between 0 and 2097152; char=" + c); } public static int Utf16_Encode_char(int c, char[] c_ary, int c_pos, byte[] b_ary, int b_pos) { if ((c > -1) && (c < 128)) { b_ary[ b_pos] = (byte)c; return 1; } else if (c < 2048) { b_ary[ b_pos] = (byte)(0xC0 | (c >> 6)); b_ary[++b_pos] = (byte)(0x80 | (c & 0x3F)); return 2; } else if((c > 55295) // 0xD800 && (c < 56320)) { // 0xDFFF if (c_pos >= c_ary.length) throw new RuntimeException("incomplete surrogate pair at end of string; char=" + c); int nxt_char = c_ary[c_pos + 1]; int v = Utf16_Surrogate_merge(c, nxt_char); b_ary[b_pos] = (byte)(0xF0 | (v >> 18)); b_ary[++b_pos] = (byte)(0x80 | (v >> 12) & 0x3F); b_ary[++b_pos] = (byte)(0x80 | (v >> 6) & 0x3F); b_ary[++b_pos] = (byte)(0x80 | (v & 0x3F)); return 4; } else { b_ary[b_pos] = (byte)(0xE0 | (c >> 12)); b_ary[++b_pos] = (byte)(0x80 | (c >> 6) & 0x3F); b_ary[++b_pos] = (byte)(0x80 | (c & 0x3F)); return 3; } } private static int Utf16_Surrogate_merge(int hi, int lo) { // REF: http://perldoc.perl.org/Encode/Unicode.html return 0x10000 + (hi - 0xD800) * 0x400 + (lo - 0xDC00); }
- file: /src/core/org/luaj/vm2/compiler/LexState.java
- proc: read_string
if (c > UCHAR_MAX) lexerror("escape sequence too large", TK_STRING); save(c, false); // NOTE: specify that c is integer and does not need conversion; EX: \128 -> 128 -> (char)128, not Utf8_encode(128)
- file: /src/core/org/luaj/vm2/compiler/LexState.java
void save(int c) {save(c, true);} void save(int c, boolean c_might_be_utf8) { int bytes_len = c_might_be_utf8 ? LuaString.Utf8_Len_of_char_by_1st_byte((byte)c) : 1; if (bytes_len > 1) { // c is 1st byte of utf8 multi-byte sequence; read required number of bytes and convert to char; EX: left-arrow is serialized in z as 226,134,144; c is currently 226; read 134 and 144 and convert to left-arrow temp_bry[0] = (byte)c; for (int i = 1; i < bytes_len; i++) { nextChar(); temp_bry[i] = (byte)current; } c = LuaString.Utf16_Decode_to_int(temp_bry, 0); } if ( buff == null || nbuff + 1 > buff.length ) buff = LuaC.realloc( buff, nbuff*2+1 ); buff[nbuff++] = (char)c; } private static byte[] temp_bry = new byte[6];
build.xml
- note: this change is needed to get luaj to compile with the String.format(String, double) call
- file: build.xml
old: <javac destdir="build/jme/classes" encoding="utf-8" source="1.3" target="1.2" bootclasspathref="wtk-libs" srcdir="build/jme/src"/> <javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3" classpath="lib/bcel-5.2.jar" srcdir="build/jse/src" excludes="**/script/*,**/Lua2Java*,lua*"/> <javac destdir="build/jse/classes" encoding="utf-8" source="1.5" target="1.5" classpath="build/jse/classes" srcdir="build/jse/src" includes="**/script/*,**/Lua2Java*"/> <javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3" classpath="build/jse/classes" srcdir="build/jse/src" includes="lua*"/> new: <javac destdir="build/jse/classes" encoding="utf-8" source="1.5" target="1.5" classpath="lib/bcel-5.2.jar" srcdir="build/jse/src" excludes="**/script/*,**/Lua2Java*,lua*"/> <javac destdir="build/jse/classes" encoding="utf-8" source="1.5" target="1.5" classpath="build/jse/classes" srcdir="build/jse/src" includes="**/script/*,**/Lua2Java*"/> <javac destdir="build/jse/classes" encoding="utf-8" source="1.5" target="1.5" classpath="build/jse/classes" srcdir="build/jse/src" includes="lua*"/>
Luaj tests
package org.luaj.vm2; import org.luaj.vm2.lib.StringLib; import junit.framework.*; public class Xowa_tst extends TestCase { private Xowa_fxt fxt = new Xowa_fxt(); public void test_tonumber_ws() { fxt.Test_tonumber_int("123" , 123); fxt.Test_tonumber_int("\t\n\r 123\t\n\r" , 123); fxt.Test_tonumber_nil("1a"); fxt.Test_tonumber_nil("1 2"); fxt.Test_tonumber_nil(""); fxt.Test_tonumber_nil("\t\n\r \t\n\r"); } public void test_gsub() { fxt.Test_gsub("abc", "a", "A", "Abc"); // basic fxt.Test_gsub("a#b", "#", "", "ab"); // match() fails when shortening string fxt.Test_gsub("", "%b<>", "A", ""); // balance() fails with out of index when find is blank } public void test_format() { fxt.Test_format("%.1f" , "1.23", "1.2"); // apply precision; 1 decimal place fxt.Test_format("(%.1f)", "1.23", "(1.2)"); // handle substring; format_string should be "%.1f" not "(%.1f)" fxt.Test_format("%0.1f" , "1.23", "1.2"); // handle invalid padding of 0 fxt.Test_format("%02.f" , "1.23", "01"); // handle missing precision } } class Xowa_fxt { public void Test_tonumber_int(String raw, int expd) { LuaString actl_str = LuaString.valueOf(raw); LuaInteger actl_int = (LuaInteger)actl_str.tonumber(); Assert.assertEquals(expd, actl_int.v); } public void Test_tonumber_nil(String raw) { LuaString actl_str = LuaString.valueOf(raw); Assert.assertEquals(LuaValue.NIL, actl_str.tonumber()); } public void Test_gsub(String text, String regx, String repl, String expd) { Varargs actl_args = StringLib.gsub_test(LuaValue.varargsOf(new LuaValue[] {LuaValue.valueOf(text), LuaValue.valueOf(regx), LuaValue.valueOf(repl)})); Assert.assertEquals(expd, actl_args.checkstring(1).tojstring()); } public void Test_format(String fmt, String val, String expd) { Varargs actl_args = StringLib.format_test(LuaValue.varargsOf(new LuaValue[] {LuaValue.valueOf(fmt), LuaValue.valueOf(val)})); Assert.assertEquals(expd, actl_args.checkstring(1).tojstring()); } }
None of these changes affect the luaj_xowa.jar. They are noted for comprehensiveness's sake.
Note that the $engines variable refers to /xowa/bin/any/lua/mediawiki/extensions/Scribunto/engines/
getfenv/setfenv deprecated
- add lua-compat-env
- source: https://github.com/davidm/lua-compat-env
- target: $engines/LuaCommon/lualib/lua-compat-env .lua
- add alias to $engines/Luaj/mw_main.lua
- _G.getfenv = require 'compat_env'.getfenv
- _G.setfenv = require 'compat_env'.setfenv
- change xowa.jar to load debugLibrary
- Globals.load(new DebugLib());
loadString deprecated
- add alias to $engines/Luaj/mw_main.lua
- _G.loadstring = load
table.unpack deprecated
- add alias to $engines/Luaj/mw_main.lua
- _G.unpack = table.unpack
Miscellaneous changes
-
2015-10-11: Increased LUAI_MAXVALUES from 200 to 249 else <ref> fails because function citation0 in en.wikipedia.org/wiki/Module:Citation/CS1 uses more than 200 local variables
- See: http://www.lua.org/source/5.1/luaconf.h.html LUAI_MAXVARS is the maximum number of local variables per function (must be smaller than 250).