diff options
| author | Benoit Giannangeli <giann008@gmail.com> | 2017-02-11 17:11:56 +0100 | 
|---|---|---|
| committer | Benoit Giannangeli <giann008@gmail.com> | 2017-02-11 21:33:14 +0100 | 
| commit | 3c5cf1687c2da09f56ca1de340e5ada2119efca9 (patch) | |
| tree | 630bd9c476f050ea5e5cc367cb8767265b9172e2 /src/lvm.js | |
| parent | 5284fd99c801dcde51094ca68d2eae6c56aaa3f0 (diff) | |
| download | fengari-3c5cf1687c2da09f56ca1de340e5ada2119efca9.tar.gz fengari-3c5cf1687c2da09f56ca1de340e5ada2119efca9.tar.bz2 fengari-3c5cf1687c2da09f56ca1de340e5ada2119efca9.zip  | |
No more LuaVM class, moved functions around
Diffstat (limited to 'src/lvm.js')
| -rw-r--r-- | src/lvm.js | 1411 | 
1 files changed, 690 insertions, 721 deletions
@@ -19,846 +19,815 @@ const CallInfo       = lstate.CallInfo;  const llimit         = require('./llimit.js');  const ldo            = require('./ldo.js'); -class LuaVM { - -    constructor(L) { -        this.L = L; -    } - -    RA(base, i) { -       return base + i.A; -    } - -    RB(base, i) { -       return base + i.B; -    } +const RA = function(L, base, i) { +   return base + i.A; +} -    RC(base, i) { -       return base + i.C; -    } +const RB = function(L, base, i) { +   return base + i.B; +} -    RKB(base, k, i) { -        return OC.ISK(i.B) ? k[OC.INDEXK(i.B)] : this.L.stack[base + i.B]; -    } +const RC = function(L, base, i) { +   return base + i.C; +} -    RKC(base, k, i) { -        return OC.ISK(i.C) ? k[OC.INDEXK(i.C)] : this.L.stack[base + i.C]; -    } +const RKB = function(L, base, k, i) { +    return OC.ISK(i.B) ? k[OC.INDEXK(i.B)] : L.stack[base + i.B]; +} -    execute() { -        let L = this.L; +const RKC = function(L, base, k, i) { +    return OC.ISK(i.C) ? k[OC.INDEXK(i.C)] : L.stack[base + i.C]; +} -        let ci = L.ci; -        ci.callstatus |= lstate.CIST_FRESH; -        newframe: -        for (;;) { -            ci = L.ci; -            var cl = ci.func; -            let k = cl.p.k; -            let base = ci.u.l.base +const luaV_execute = function(L) { +    let ci = L.ci; +    ci.callstatus |= lstate.CIST_FRESH; +    newframe: +    for (;;) { +        ci = L.ci; +        var cl = ci.func; +        let k = cl.p.k; +        let base = ci.u.l.base -            let i = ci.u.l.savedpc[ci.pcOff++]; -            let ra = this.RA(base, i); +        let i = ci.u.l.savedpc[ci.pcOff++]; +        let ra = RA(L, base, i); -            switch (OC.OpCodes[i.opcode]) { -                case "OP_MOVE": { -                    L.stack[ra] = L.stack[this.RB(base, i)]; -                    break; -                } -                case "OP_LOADK": { -                    L.stack[ra] = k[i.Bx]; -                    break; -                } -                case "OP_LOADKX": { -                    assert(OC.OpCodes[ci.u.l.savedpc[ci.pcOff].opcode] === "OP_EXTRAARG"); -                    L.stack[ra] = k[ci.u.l.savedpc[ci.pcOff++].Ax]; -                    break; -                } -                case "OP_LOADBOOL": { -                    L.stack[ra] = new TValue(CT.LUA_TBOOLEAN, i.B !== 0); +        switch (OC.OpCodes[i.opcode]) { +            case "OP_MOVE": { +                L.stack[ra] = L.stack[RB(L, base, i)]; +                break; +            } +            case "OP_LOADK": { +                L.stack[ra] = k[i.Bx]; +                break; +            } +            case "OP_LOADKX": { +                assert(OC.OpCodes[ci.u.l.savedpc[ci.pcOff].opcode] === "OP_EXTRAARG"); +                L.stack[ra] = k[ci.u.l.savedpc[ci.pcOff++].Ax]; +                break; +            } +            case "OP_LOADBOOL": { +                L.stack[ra] = new TValue(CT.LUA_TBOOLEAN, i.B !== 0); -                    if (i.C !== 0) -                        ci.pcOff++; /* skip next instruction (if C) */ +                if (i.C !== 0) +                    ci.pcOff++; /* skip next instruction (if C) */ -                    break; -                } -                case "OP_LOADNIL": { -                    for (let j = 0; j <= i.B; j++) -                        L.stack[ra + j] = ldo.nil; -                    break; -                } -                case "OP_GETUPVAL": { -                    L.stack[ra] = cl.upvals[i.B].val(L); -                    break; -                } -                case "OP_SETUPVAL": { -                    cl.upvals[i.B].setval(L, ra); -                    break; -                } -                case "OP_GETTABUP": { -                    let table = cl.upvals[i.B].val(L); -                    let key = this.RKC(base, k, i); +                break; +            } +            case "OP_LOADNIL": { +                for (let j = 0; j <= i.B; j++) +                    L.stack[ra + j] = ldo.nil; +                break; +            } +            case "OP_GETUPVAL": { +                L.stack[ra] = cl.upvals[i.B].val(L); +                break; +            } +            case "OP_SETUPVAL": { +                cl.upvals[i.B].setval(L, ra); +                break; +            } +            case "OP_GETTABUP": { +                let table = cl.upvals[i.B].val(L); +                let key = RKC(L, base, k, i); -                    // if (!table.ttistable() || !table.metatable.__index(table, key)) { -                    //     // __index -                    // } else { -                        L.stack[ra] = table.metatable.__index(table, key); -                    // } -                    break; -                } -                case "OP_SETTABUP": { -                    let table = cl.upvals[i.A].val(L); -                    let key = this.RKB(base, k, i); -                    let v = this.RKC(base, k, i); +                // if (!table.ttistable() || !table.metatable.__index(table, key)) { +                //     // __index +                // } else { +                    L.stack[ra] = table.metatable.__index(table, key); +                // } +                break; +            } +            case "OP_SETTABUP": { +                let table = cl.upvals[i.A].val(L); +                let key = RKB(L, base, k, i); +                let v = RKC(L, base, k, i); -                    // if (!table.ttistable() || !table.metatable.__index(table, key)) { -                    //     // __index -                    // } else { -                        table.metatable.__newindex(table, key, v); -                    // } +                // if (!table.ttistable() || !table.metatable.__index(table, key)) { +                //     // __index +                // } else { +                    table.metatable.__newindex(table, key, v); +                // } -                    break; -                } -                case "OP_GETTABLE": { -                    let table = this.RKB(base, k, i); -                    let key = this.RKC(base, k, i); +                break; +            } +            case "OP_GETTABLE": { +                let table = RKB(L, base, k, i); +                let key = RKC(L, base, k, i); -                    // if (!table.ttistable() || !table.metatable.__index(table, key)) { -                    //     // __index -                    // } else { -                        L.stack[ra] = table.metatable.__index(table, key); -                    // } -                    break; -                } -                case "OP_SETTABLE": { -                    let table = L.stack[ra]; -                    let key = this.RKB(base, k, i); -                    let v = this.RKC(base, k, i); +                // if (!table.ttistable() || !table.metatable.__index(table, key)) { +                //     // __index +                // } else { +                    L.stack[ra] = table.metatable.__index(table, key); +                // } +                break; +            } +            case "OP_SETTABLE": { +                let table = L.stack[ra]; +                let key = RKB(L, base, k, i); +                let v = RKC(L, base, k, i); -                    // if (!table.ttistable() || !table.metatable.__index(table, key)) { -                    //     // __index -                    // } else { -                        table.metatable.__newindex(table, key, v); -                    // } +                // if (!table.ttistable() || !table.metatable.__index(table, key)) { +                //     // __index +                // } else { +                    table.metatable.__newindex(table, key, v); +                // } -                    break; -                } -                case "OP_NEWTABLE": { -                    L.stack[ra] = new Table(); -                    break; -                } -                case "OP_SELF": { -                    let table = L.stack[this.RB(base, i)]; -                    let key = this.RKC(base, k, i); +                break; +            } +            case "OP_NEWTABLE": { +                L.stack[ra] = new Table(); +                break; +            } +            case "OP_SELF": { +                let table = L.stack[RB(L, base, i)]; +                let key = RKC(L, base, k, i); -                    L.stack[ra + 1] = table; +                L.stack[ra + 1] = table; -                    // if (!table.ttistable() || !table.metatable.__index(table, key)) { -                    //     // __index -                    // } else { -                        L.stack[ra] = table.metatable.__index(table, key); -                    // } +                // if (!table.ttistable() || !table.metatable.__index(table, key)) { +                //     // __index +                // } else { +                    L.stack[ra] = table.metatable.__index(table, key); +                // } -                    break; -                } -                case "OP_ADD": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_ADD": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (op1.ttisinteger() && op2.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value + op2.value)|0); -                    } else if (numberop1 !== false && numberop2 !== false) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value + op2.value); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${op1.value} and ${op2.value}`); -                    } -                    break; +                if (op1.ttisinteger() && op2.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value + op2.value)|0); +                } else if (numberop1 !== false && numberop2 !== false) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value + op2.value); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${op1.value} and ${op2.value}`);                  } -                case "OP_SUB": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_SUB": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (op1.ttisinteger() && op2.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value - op2.value)|0); -                    } else if (numberop1 !== false && numberop2 !== false) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value - op2.value); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${op1.value} and ${k[i.C].value}`); -                    } -                    break; +                if (op1.ttisinteger() && op2.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value - op2.value)|0); +                } else if (numberop1 !== false && numberop2 !== false) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value - op2.value); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${op1.value} and ${k[i.C].value}`);                  } -                case "OP_MUL": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_MUL": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (op1.ttisinteger() && op2.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value * op2.value)|0); -                    } else if (numberop1 !== false && numberop2 !== false) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value * op2.value); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); -                    } -                    break; +                if (op1.ttisinteger() && op2.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value * op2.value)|0); +                } else if (numberop1 !== false && numberop2 !== false) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value * op2.value); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);                  } -                case "OP_MOD": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_MOD": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (op1.ttisinteger() && op2.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value % op2.value)|0); -                    } else if (numberop1 !== false && numberop2 !== false) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value % op2.value); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); -                    } -                    break; +                if (op1.ttisinteger() && op2.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value % op2.value)|0); +                } else if (numberop1 !== false && numberop2 !== false) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value % op2.value); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);                  } -                case "OP_POW": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_POW": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (numberop1 !== false && numberop2 !== false) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMFLT, Math.pow(op1.value, op2.value)); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); -                    } -                    break; +                if (numberop1 !== false && numberop2 !== false) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMFLT, Math.pow(op1.value, op2.value)); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);                  } -                case "OP_DIV": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_DIV": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (numberop1 !== false && numberop2 !== false) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value / op2.value); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); -                    } -                    break; +                if (numberop1 !== false && numberop2 !== false) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value / op2.value); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);                  } -                case "OP_IDIV": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_IDIV": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (op1.ttisinteger() && op2.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value / op2.value)|0); -                    } else if (numberop1 !== false && numberop2 !== false) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMFLT, (op1.value / op2.value)|0); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); -                    } -                    break; +                if (op1.ttisinteger() && op2.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value / op2.value)|0); +                } else if (numberop1 !== false && numberop2 !== false) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMFLT, (op1.value / op2.value)|0); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);                  } -                case "OP_BAND": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_BAND": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (op1.ttisinteger() && op2.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value & op2.value)|0); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); -                    } -                    break; +                if (op1.ttisinteger() && op2.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value & op2.value)|0); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);                  } -                case "OP_BOR": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_BOR": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (op1.ttisinteger() && op2.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value | op2.value)|0); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); -                    } -                    break; +                if (op1.ttisinteger() && op2.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value | op2.value)|0); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);                  } -                case "OP_BXOR": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_BXOR": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (op1.ttisinteger() && op2.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value ^ op2.value)|0); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); -                    } -                    break; +                if (op1.ttisinteger() && op2.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value ^ op2.value)|0); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);                  } -                case "OP_SHL": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_SHL": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (op1.ttisinteger() && op2.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value << op2.value)|0); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); -                    } -                    break; +                if (op1.ttisinteger() && op2.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value << op2.value)|0); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);                  } -                case "OP_SHR": { -                    let op1 = this.RKB(base, k, i); -                    let op2 = this.RKC(base, k, i); -                    let numberop1 = LuaVM.tonumber(op1); -                    let numberop2 = LuaVM.tonumber(op2); +                break; +            } +            case "OP_SHR": { +                let op1 = RKB(L, base, k, i); +                let op2 = RKC(L, base, k, i); +                let numberop1 = tonumber(op1); +                let numberop2 = tonumber(op2); -                    if (op1.ttisinteger() && op2.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value >> op2.value)|0); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`); -                    } -                    break; +                if (op1.ttisinteger() && op2.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, (op1.value >> op2.value)|0); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);                  } -                case "OP_UNM": { -                    let op = L.stack[this.RB(base, i)]; -                    let numberop = LuaVM.tonumber(op); +                break; +            } +            case "OP_UNM": { +                let op = L.stack[RB(L, base, i)]; +                let numberop = tonumber(op); -                    if (op.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, -op.value); -                    } else if (numberop !== false) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMFLT, -op.value); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform unary operation on ${op.value}`); -                    } -                    break; +                if (op.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, -op.value); +                } else if (numberop !== false) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMFLT, -op.value); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform unary operation on ${op.value}`);                  } -                case "OP_BNOT": { -                    let op = L.stack[this.RB(base, i)]; -                    let numberop = LuaVM.tonumber(op); +                break; +            } +            case "OP_BNOT": { +                let op = L.stack[RB(L, base, i)]; +                let numberop = tonumber(op); -                    if (op.ttisinteger()) { -                        L.stack[ra] = new TValue(CT.LUA_TNUMINT, ~op.value); -                    } else { -                        // Metamethod -                        throw new Error(`Can't perform unary operation on ${op.value}`); -                    } -                    break; +                if (op.ttisinteger()) { +                    L.stack[ra] = new TValue(CT.LUA_TNUMINT, ~op.value); +                } else { +                    // Metamethod +                    throw new Error(`Can't perform unary operation on ${op.value}`);                  } -                case "OP_NOT": { -                    let op = L.stack[this.RB(base, i)]; -                    L.stack[ra] = new TValue(CT.LUA_TBOOLEAN, LuaVM.l_isfalse(op)); -                    break; -                } -                case "OP_LEN": { -                    break; -                } -                case "OP_CONCAT": { -                    break; -                } -                case "OP_JMP": { -                    this.dojump(ci, i, 0); -                    break; -                } -                case "OP_EQ": { -                    if (LuaVM.luaV_equalobj(this.RKB(base, k, i), this.RKC(base, k, i)) !== i.A) -                        ci.pcOff++; -                    else -                        this.donextjump(ci); -                    base = ci.u.l.base; -                    break; -                } -                case "OP_LT": { -                    if (LuaVM.luaV_lessthan(this.RKB(base, k, i), this.RKC(base, k, i)) !== i.A) -                        ci.pcOff++; -                    else -                        this.donextjump(ci); -                    base = ci.u.l.base; -                    break; -                } -                case "OP_LE": { -                    if (LuaVM.luaV_lessequal(this.RKB(base, k, i), this.RKC(base, k, i)) !== i.A) -                        ci.pcOff++; -                    else -                        this.donextjump(ci); -                    base = ci.u.l.base; -                    break; -                } -                case "OP_TEST": { -                    if (i.C ? LuaVM.l_isfalse(L.stack[ra]) : !LuaVM.l_isfalse(L.stack[ra])) -                        ci.pcOff++; -                    else -                        this.donextjump(ci); -                    break; -                } -                case "OP_TESTSET": { -                    let rb = L.stack[this.RB(base, i)]; -                    if (i.C ? LuaVM.l_isfalse(rb) : !LuaVM.l_isfalse(rb)) -                        ci.pcOff++; -                    else { -                        L.stack[ra] = rb; -                        this.donextjump(ci); -                    } -                    break; -                } -                case "OP_CALL": { -                    let b = i.B; -                    let nresults = i.C - 1; - -                    if (b !== 0) -                        L.top = ra+b; - -                    if (ldo.precall(L, ra, L.stack[ra], nresults)) { -                        if (nresults >= 0) -                            L.top = ci.top; -                        base = ci.u.l.base; -                    } else { -                        ci = L.ci; -                        continue newframe; -                    } - -                    break; +                break; +            } +            case "OP_NOT": { +                let op = L.stack[RB(L, base, i)]; +                L.stack[ra] = new TValue(CT.LUA_TBOOLEAN, l_isfalse(op)); +                break; +            } +            case "OP_LEN": { +                break; +            } +            case "OP_CONCAT": { +                break; +            } +            case "OP_JMP": { +                dojump(L, ci, i, 0); +                break; +            } +            case "OP_EQ": { +                if (luaV_equalobj(RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A) +                    ci.pcOff++; +                else +                    donextjump(L, ci); +                base = ci.u.l.base; +                break; +            } +            case "OP_LT": { +                if (luaV_lessthan(RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A) +                    ci.pcOff++; +                else +                    donextjump(L, ci); +                base = ci.u.l.base; +                break; +            } +            case "OP_LE": { +                if (luaV_lessequal(RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A) +                    ci.pcOff++; +                else +                    donextjump(L, ci); +                base = ci.u.l.base; +                break; +            } +            case "OP_TEST": { +                if (i.C ? l_isfalse(L.stack[ra]) : !l_isfalse(L.stack[ra])) +                    ci.pcOff++; +                else +                    donextjump(L, ci); +                break; +            } +            case "OP_TESTSET": { +                let rb = L.stack[RB(L, base, i)]; +                if (i.C ? l_isfalse(rb) : !l_isfalse(rb)) +                    ci.pcOff++; +                else { +                    L.stack[ra] = rb; +                    donextjump(L, ci);                  } -                case "OP_TAILCALL": { -                    if (i.B !== 0) L.top = ra + i.B; -                    if (ldo.precall(L, ra, L.stack[ra], LUA_MULTRET)) { // JS function -                        base = ci.u.l.base; -                    } else { -                        /* tail call: put called frame (n) in place of caller one (o) */ -                        let nci = L.ci; -                        let oci = nci.previous; -                        let nfunc = nci.func; -                        let nfuncOff = nci.funcOff; -                        let ofunc = oci.func; -                        let ofuncOff = oci.funcOff; -                        let lim = nci.u.l.base + nfunc.p.numparams; -                        if (cl.p.p.length > 0) this.closeupvals(oci.u.l.base); -                        for (let aux = 0; nfuncOff + aux < lim; aux++) -                            L.stack[ofuncOff + aux] = L.stack[nfuncOff + aux]; -                        oci.func = nci.func; -                        oci.u.l.base = ofuncOff + (nci.u.l.base - nfuncOff); -                        L.top = ofuncOff + (L.top - nfuncOff); -                        oci.top = L.top; -                        oci.u.l.savedpc = nci.u.l.savedpc; -                        oci.pcOff = nci.pcOff; -                        oci.callstatus |= lstate.CIST_TAIL; -                        L.ci = oci; -                        ci = L.ci; -                        L.ciOff--; - -                        assert(L.top === oci.u.l.base + L.stack[ofuncOff].p.maxstacksize); +                break; +            } +            case "OP_CALL": { +                let b = i.B; +                let nresults = i.C - 1; -                        continue newframe; -                    } -                    break; -                } -                case "OP_RETURN": { -                    if (cl.p.p.length > 0) this.closeupvals(base); -                    let b = ldo.postcall(L, ci, ra, (i.B !== 0 ? i.B - 1 : L.top - ra)); +                if (b !== 0) +                    L.top = ra+b; -                    if (ci.callstatus & lstate.CIST_FRESH) -                        return; /* external invocation: return */ -                     +                if (ldo.precall(L, ra, L.stack[ra], nresults)) { +                    if (nresults >= 0) +                        L.top = ci.top; +                    base = ci.u.l.base; +                } else {                      ci = L.ci; -                    if (b) L.top = ci.top; -                      continue newframe; -                    break; -                } -                case "OP_FORLOOP": { -                    if (L.stack[ra].ttisinteger()) { /* integer loop? */ -                        let step = L.stack[ra + 2].value; -                        let idx = L.stack[ra].value + step; -                        let limit = L.stack[ra + 1].value; - -                        if (0 < step ? idx <= limit : limit <= idx) { -                            ci.pcOff += i.sBx; -                            L.stack[ra].value = idx; -                            L.stack[ra + 3] = new TValue(CT.LUA_TNUMINT, idx); // TODO: if tvalue already there, just update it -                        } -                    } else { /* floating loop */ -                        let step = L.stack[ra + 2].value; -                        let idx = L.stack[ra].value + step; -                        let limit = L.stack[ra + 1].value; - -                        // TODO: luai_numlt, luai_numle -                        if (0 < step ? idx <= limit : limit <= idx) { -                            ci.pcOff += i.sBx; -                            L.stack[ra].value = idx; -                            L.stack[ra + 3] = new TValue(CT.LUA_TNUMFLT, idx); // TODO: if tvalue already there, just update it -                        } -                    } -                    break;                  } -                case "OP_FORPREP": { -                    let init = L.stack[ra]; -                    let plimit = L.stack[ra + 1]; -                    let pstep = L.stack[ra + 2]; -                    let forlimit = LuaVM.forlimit(plimit, pstep.value); -                    if (init.ttisinteger() && pstep.ttisinteger() && forlimit.casted) { /* all values are integer */ -                        let initv = forlimit.stopnow ? 0 : init.value; -                        plimit.value = forlimit.ilimit; -                        init.value = initv - pstep.value; -                    } else { /* try making all values floats */ -                        let ninit = LuaVM.tonumber(init); -                        let nlimit = LuaVM.tonumber(plimit); -                        let nstep = LuaVM.tonumber(pstep); - -                        if (nlimit === false) -                            throw new Error("'for' limit must be a number"); +                break; +            } +            case "OP_TAILCALL": { +                if (i.B !== 0) L.top = ra + i.B; +                if (ldo.precall(L, ra, L.stack[ra], LUA_MULTRET)) { // JS function +                    base = ci.u.l.base; +                } else { +                    /* tail call: put called frame (n) in place of caller one (o) */ +                    let nci = L.ci; +                    let oci = nci.previous; +                    let nfunc = nci.func; +                    let nfuncOff = nci.funcOff; +                    let ofunc = oci.func; +                    let ofuncOff = oci.funcOff; +                    let lim = nci.u.l.base + nfunc.p.numparams; +                    if (cl.p.p.length > 0) lfunc.luaF_close(L, oci.u.l.base); +                    for (let aux = 0; nfuncOff + aux < lim; aux++) +                        L.stack[ofuncOff + aux] = L.stack[nfuncOff + aux]; +                    oci.func = nci.func; +                    oci.u.l.base = ofuncOff + (nci.u.l.base - nfuncOff); +                    L.top = ofuncOff + (L.top - nfuncOff); +                    oci.top = L.top; +                    oci.u.l.savedpc = nci.u.l.savedpc; +                    oci.pcOff = nci.pcOff; +                    oci.callstatus |= lstate.CIST_TAIL; +                    L.ci = oci; +                    ci = L.ci; +                    L.ciOff--; -                        plimit.type = CT.LUA_TNUMFLT; -                        plimit.value = nlimit.value; +                    assert(L.top === oci.u.l.base + L.stack[ofuncOff].p.maxstacksize); -                        if (nstep === false) -                            throw new Error("'for' step must be a number"); +                    continue newframe; +                } +                break; +            } +            case "OP_RETURN": { +                if (cl.p.p.length > 0) lfunc.luaF_close(L, base); +                let b = ldo.postcall(L, ci, ra, (i.B !== 0 ? i.B - 1 : L.top - ra)); -                        pstep.type = CT.LUA_TNUMFLT; -                        pstep.value = nstep.value; +                if (ci.callstatus & lstate.CIST_FRESH) +                    return; /* external invocation: return */ +                 +                ci = L.ci; +                if (b) L.top = ci.top; -                        if (ninit === false) -                            throw new Error("'for' initial value must be a number"); +                continue newframe; +                break; +            } +            case "OP_FORLOOP": { +                if (L.stack[ra].ttisinteger()) { /* integer loop? */ +                    let step = L.stack[ra + 2].value; +                    let idx = L.stack[ra].value + step; +                    let limit = L.stack[ra + 1].value; -                        init.type = CT.LUA_TNUMFLT; -                        init.value = ninit.value - nstep.value; +                    if (0 < step ? idx <= limit : limit <= idx) { +                        ci.pcOff += i.sBx; +                        L.stack[ra].value = idx; +                        L.stack[ra + 3] = new TValue(CT.LUA_TNUMINT, idx); // TODO: if tvalue already there, just update it                      } +                } else { /* floating loop */ +                    let step = L.stack[ra + 2].value; +                    let idx = L.stack[ra].value + step; +                    let limit = L.stack[ra + 1].value; -                    ci.pcOff += i.sBx; -                    break; -                } -                case "OP_TFORCALL": { -                    break; -                } -                case "OP_TFORLOOP": { -                    if (!L.stack[ra + 1].ttisnil()) { /* continue loop? */ -                        L.stack[ra] = L.stack[ra + 1]; /* save control variable */ -                        ci.cpOff += i.sBx; /* jump back */ +                    // TODO: luai_numlt, luai_numle +                    if (0 < step ? idx <= limit : limit <= idx) { +                        ci.pcOff += i.sBx; +                        L.stack[ra].value = idx; +                        L.stack[ra + 3] = new TValue(CT.LUA_TNUMFLT, idx); // TODO: if tvalue already there, just update it                      } -                    break;                  } -                case "OP_SETLIST": { -                    let n = i.B; -                    let c = i.C; +                break; +            } +            case "OP_FORPREP": { +                let init = L.stack[ra]; +                let plimit = L.stack[ra + 1]; +                let pstep = L.stack[ra + 2]; +                let forlim = forlimit(plimit, pstep.value); -                    if (n === 0) n = L.top - ra - 1; +                if (init.ttisinteger() && pstep.ttisinteger() && forlim.casted) { /* all values are integer */ +                    let initv = forlim.stopnow ? 0 : init.value; +                    plimit.value = forlim.ilimit; +                    init.value = initv - pstep.value; +                } else { /* try making all values floats */ +                    let ninit = tonumber(init); +                    let nlimit = tonumber(plimit); +                    let nstep = tonumber(pstep); -                    if (c === 0) { -                        assert(OC.OpCodes[ci.u.l.savedpc[ci.pcOff].opcode] === "OP_EXTRAARG"); -                        c = ci.u.l.savedpc[ci.pcOff++].Ax; -                    } +                    if (nlimit === false) +                        throw new Error("'for' limit must be a number"); -                    let table = L.stack[ra].value; -                    let last = ((c - 1) * OC.LFIELDS_PER_FLUSH) + n; +                    plimit.type = CT.LUA_TNUMFLT; +                    plimit.value = nlimit.value; -                    for (; n > 0; n--) { -                        table.array[last--] = L.stack[ra + n]; -                    } +                    if (nstep === false) +                        throw new Error("'for' step must be a number"); -                    L.top = ci.top; /* correct top (in case of previous open call) */ -                    break; -                } -                case "OP_CLOSURE": { -                    let p = cl.p.p[i.Bx]; -                    let nup = p.upvalues.length; -                    let uv = p.upvalues; -                    let ncl = new LClosure(nup); -                    ncl.p = p; +                    pstep.type = CT.LUA_TNUMFLT; +                    pstep.value = nstep.value; -                    L.stack[ra] = ncl; +                    if (ninit === false) +                        throw new Error("'for' initial value must be a number"); -                    for (let i = 0; i < nup; i++) { -                        if (uv[i].instack) -                            ncl.upvals[i] = this.findupval(base + uv[i].idx); -                        else -                            ncl.upvals[i] = cl.upvals[uv[i].idx]; -                        ncl.upvals[i].refcount++; -                    } -                    break; +                    init.type = CT.LUA_TNUMFLT; +                    init.value = ninit.value - nstep.value;                  } -                case "OP_VARARG": { -                    let b = i.B - 1; -                    let n = base - ci.funcOff - cl.p.numparams - 1; -                    let j; -                    if (n < 0) /* less arguments than parameters? */ -                        n = 0; /* no vararg arguments */ +                ci.pcOff += i.sBx; +                break; +            } +            case "OP_TFORCALL": { +                break; +            } +            case "OP_TFORLOOP": { +                if (!L.stack[ra + 1].ttisnil()) { /* continue loop? */ +                    L.stack[ra] = L.stack[ra + 1]; /* save control variable */ +                    ci.cpOff += i.sBx; /* jump back */ +                } +                break; +            } +            case "OP_SETLIST": { +                let n = i.B; +                let c = i.C; -                    if (b < 0) { -                        b = n;  /* get all var. arguments */ -                        base = ci.u.l.base; -                        ra = this.RA(base, i); /* previous call may change the stack */ +                if (n === 0) n = L.top - ra - 1; -                        L.top = ra + n; -                    } +                if (c === 0) { +                    assert(OC.OpCodes[ci.u.l.savedpc[ci.pcOff].opcode] === "OP_EXTRAARG"); +                    c = ci.u.l.savedpc[ci.pcOff++].Ax; +                } -                    for (j = 0; j < b && j < n; j++) -                        L.stack[ra + j] = L.stack[base - n + j]; +                let table = L.stack[ra].value; +                let last = ((c - 1) * OC.LFIELDS_PER_FLUSH) + n; -                    for (; j < b; j++) /* complete required results with nil */ -                        L.stack[ra + j] = ldo.nil; -                    break; +                for (; n > 0; n--) { +                    table.array[last--] = L.stack[ra + n];                  } -                case "OP_EXTRAARG": { -                    break; -                } -            } -        } -    } - -    findupval(level) { -        let L = this.L; -        let pp = L.openupval; -         -        while(pp !== null && pp.v >= level) { -            let p = pp; -            if (p.v === level) -                return p; +                L.top = ci.top; /* correct top (in case of previous open call) */ +                break; +            } +            case "OP_CLOSURE": { +                let p = cl.p.p[i.Bx]; +                let nup = p.upvalues.length; +                let uv = p.upvalues; +                let ncl = new LClosure(nup); +                ncl.p = p; -            pp = p.u.open.next; -        } +                L.stack[ra] = ncl; -        let uv = new UpVal(); -        uv.refcount = 0; -        uv.u.open.next = pp; -        uv.u.open.touched = true; +                for (let i = 0; i < nup; i++) { +                    if (uv[i].instack) +                        ncl.upvals[i] = lfunc.findupval(L, base + uv[i].idx); +                    else +                        ncl.upvals[i] = cl.upvals[uv[i].idx]; +                    ncl.upvals[i].refcount++; +                } +                break; +            } +            case "OP_VARARG": { +                let b = i.B - 1; +                let n = base - ci.funcOff - cl.p.numparams - 1; +                let j; -        pp = uv; +                if (n < 0) /* less arguments than parameters? */ +                    n = 0; /* no vararg arguments */ -        uv.v = level; +                if (b < 0) { +                    b = n;  /* get all var. arguments */ +                    base = ci.u.l.base; +                    ra = RA(L, base, i); /* previous call may change the stack */ -        // Thread with upvalue list business ? lfunc.c:75 +                    L.top = ra + n; +                } -        return uv; -    } +                for (j = 0; j < b && j < n; j++) +                    L.stack[ra + j] = L.stack[base - n + j]; -    closeupvals(level) { -        let L = this.L; -        while (L.openupval !== null && L.openupval.v >= level) { -            let uv = L.openupval; -            assert(uv.isopen()); -            L.openupval = uv.u.open.next; /* remove from 'open' list */ -            if (uv.refcount > 0) { -                uv.value = L.stack[uv.v]; -                uv.v = null; +                for (; j < b; j++) /* complete required results with nil */ +                    L.stack[ra + j] = ldo.nil; +                break; +            } +            case "OP_EXTRAARG": { +                break;              }          }      } +} -    dojump(ci, i, e) { -        let a = i.A; -        if (a != 0) closeupvals(ci.u.l.base + a - 1); -        ci.pcOff += i.sBx + e; -    } +const dojump = function(L, ci, i, e) { +    let a = i.A; +    if (a != 0) lfunc.luaF_close(L, ci.u.l.base + a - 1); +    ci.pcOff += i.sBx + e; +} -    donextjump(ci) { -        this.dojump(ci, ci.u.l.savedpc[ci.pcOff], 1); -    } +const donextjump = function(L, ci) { +    dojump(L, ci, ci.u.l.savedpc[ci.pcOff], 1); +} -    static luaV_lessequal(l, r) { -        if (l.ttisnumber() && r.ttisnumber()) -            return LuaVM.LEnum(l, r); -        else if (l.ttisstring() && r.ttisstring()) -            return LuaVM.l_strcmp(l, r) <= 0; -        // TODO: metatable -        // else if  (l.metatable.__le || r.metatable.__le) { -        //     let res = l.metatable.__le ? l.metatable.__le(l, r) : r.metatable.__le(l, r); -        //     if (res >= 0) -        //         return res; -        // } else { -        //     L.ci.callstatus |= lstate.CIST_LEQ; -        //     let res = l.metatable.__lt ? l.metatable.__lt(r, l) : r.metatable.__lt(r, l); -        //     L.ci.callstatus ^= lstate.CIST_LEQ; -        //     if (res < 0) -        //         throw new Error("attempt to compare ..."); -        //     return !res; -        // } -    } +const luaV_lessequal = function(l, r) { +    if (l.ttisnumber() && r.ttisnumber()) +        return LEnum(l, r); +    else if (l.ttisstring() && r.ttisstring()) +        return l_strcmp(l, r) <= 0; +    // TODO: metatable +    // else if  (l.metatable.__le || r.metatable.__le) { +    //     let res = l.metatable.__le ? l.metatable.__le(l, r) : r.metatable.__le(l, r); +    //     if (res >= 0) +    //         return res; +    // } else { +    //     L.ci.callstatus |= lstate.CIST_LEQ; +    //     let res = l.metatable.__lt ? l.metatable.__lt(r, l) : r.metatable.__lt(r, l); +    //     L.ci.callstatus ^= lstate.CIST_LEQ; +    //     if (res < 0) +    //         throw new Error("attempt to compare ..."); +    //     return !res; +    // } +} -    static luaV_lessthan(l, r) { -        if (l.ttisnumber() && r.ttisnumber()) -            return LuaVM.LTnum(l, r); -        else if (l.ttisstring() && r.ttisstring()) -            return LuaVM.l_strcmp(l, r) < 0; -        // TODO: metatable -        // else if  (l.metatable.__lt || r.metatable.__lt) { -        //     let res = l.metatable.__lt ? l.metatable.__lt(l, r) : r.metatable.__lt(l, r); -        //     if (res < 0) -        //         throw new Error("attempt to compare ...") -        //     return res; -        // } -    } +const luaV_lessthan = function(l, r) { +    if (l.ttisnumber() && r.ttisnumber()) +        return LTnum(l, r); +    else if (l.ttisstring() && r.ttisstring()) +        return l_strcmp(l, r) < 0; +    // TODO: metatable +    // else if  (l.metatable.__lt || r.metatable.__lt) { +    //     let res = l.metatable.__lt ? l.metatable.__lt(l, r) : r.metatable.__lt(l, r); +    //     if (res < 0) +    //         throw new Error("attempt to compare ...") +    //     return res; +    // } +} -    static luaV_equalobj(t1, t2) { -        if (t1.ttype() !== t2.ttype()) { /* not the same variant? */ -            if (t1.ttnov() !== t2.ttnov() || t1.ttnov() !== CT.LUA_NUMBER) -                return 0; /* only numbers can be equal with different variants */ -            else { /* two numbers with different variants */ -                /* compare them as integers */ -                return Math.floor(t1.value) === Math.floor(t2.value) // TODO: tointeger -            } +const luaV_equalobj = function(t1, t2) { +    if (t1.ttype() !== t2.ttype()) { /* not the same variant? */ +        if (t1.ttnov() !== t2.ttnov() || t1.ttnov() !== CT.LUA_NUMBER) +            return 0; /* only numbers can be equal with different variants */ +        else { /* two numbers with different variants */ +            /* compare them as integers */ +            return Math.floor(t1.value) === Math.floor(t2.value) // TODO: tointeger          } +    } -        /* values have same type and same variant */ -        switch(t1.ttype()) { -            case CT.LUA_TNIL: -                return 1; -            case CT.LUA_TNUMINT: -            case CT.LUA_TNUMFLT: -            case CT.LUA_TBOOLEAN: -            case CT.LUA_TLIGHTUSERDATA: -            case CT.LUA_TLCF: -            case CT.LUA_TSHRSTR: -            case CT.LUA_TLNGSTR: -                return t1.value === t2.value ? 1 : 0; -            case CT.LUA_TUSERDATA: -            case CT.LUA_TTABLE: -                if (t1 === t2) return 1; -                // TODO: __eq -            default: -                return t1.value === t2.value ? 1 : 0; -        } +    /* values have same type and same variant */ +    switch(t1.ttype()) { +        case CT.LUA_TNIL: +            return 1; +        case CT.LUA_TNUMINT: +        case CT.LUA_TNUMFLT: +        case CT.LUA_TBOOLEAN: +        case CT.LUA_TLIGHTUSERDATA: +        case CT.LUA_TLCF: +        case CT.LUA_TSHRSTR: +        case CT.LUA_TLNGSTR: +            return t1.value === t2.value ? 1 : 0; +        case CT.LUA_TUSERDATA: +        case CT.LUA_TTABLE: +            if (t1 === t2) return 1; +            // TODO: __eq +        default: +            return t1.value === t2.value ? 1 : 0;      } +} -    static forlimit(obj, step) { -        let stopnow = false; -        let ilimit = LuaVM.luaV_tointeger(obj, step < 0 ? 2 : 1); -        if (ilimit === false) { -            let n = LuaVM.tonumber(obj); -            if (n === false) -                return false; +const forlimit = function(obj, step) { +    let stopnow = false; +    let ilimit = luaV_tointeger(obj, step < 0 ? 2 : 1); +    if (ilimit === false) { +        let n = tonumber(obj); +        if (n === false) +            return false; -            if (0 < n) { -                ilimit = llimit.LUA_MAXINTEGER; -                if (step < 0) stopnow = true; -            } else { -                ilimit = llimit.LUA_MININTEGER; -                if (step >= 0) stopnow = true; -            } -        } - -        return { -            casted: true, -            stopnow: stopnow, -            ilimit: ilimit +        if (0 < n) { +            ilimit = llimit.LUA_MAXINTEGER; +            if (step < 0) stopnow = true; +        } else { +            ilimit = llimit.LUA_MININTEGER; +            if (step >= 0) stopnow = true;          }      } -    /* -    ** try to convert a value to an integer, rounding according to 'mode': -    ** mode == 0: accepts only integral values -    ** mode == 1: takes the floor of the number -    ** mode == 2: takes the ceil of the number -    */ -    static luaV_tointeger(obj, mode) { -        if (obj.ttisfloat()) { -            let n = obj.value; -            let f = n|0; +    return { +        casted: true, +        stopnow: stopnow, +        ilimit: ilimit +    } +} -            if (n !== f) { /* not an integral value? */ -                if (mode === 0) -                    return false;  /* fails if mode demands integral value */ -                else if (mode > 1)  /* needs ceil? */ -                    f += 1;  /* convert floor to ceil (remember: n != f) */ -            } +/* +** try to convert a value to an integer, rounding according to 'mode': +** mode == 0: accepts only integral values +** mode == 1: takes the floor of the number +** mode == 2: takes the ceil of the number +*/ +const luaV_tointeger = function(obj, mode) { +    if (obj.ttisfloat()) { +        let n = obj.value; +        let f = n|0; -            return f|0; -        } else if (obj.ttisinteger()) { -            return obj.value|0; -        } else if (obj.ttisstring()) { -            return LuaVM.luaV_tointeger(parseFloat(obj.value), mode); // TODO: luaO_str2num +        if (n !== f) { /* not an integral value? */ +            if (mode === 0) +                return false;  /* fails if mode demands integral value */ +            else if (mode > 1)  /* needs ceil? */ +                f += 1;  /* convert floor to ceil (remember: n != f) */          } -        return false; +        return f|0; +    } else if (obj.ttisinteger()) { +        return obj.value|0; +    } else if (obj.ttisstring()) { +        return luaV_tointeger(parseFloat(obj.value), mode); // TODO: luaO_str2num      } -    static tonumber(v) { -        if (v.type === CT.LUA_TNUMFLT) -            return new TValue(v.type, v.value); +    return false; +} -        if (v.type === CT.LUA_TNUMINT) -            return new TValue(CT.LUA_TNUMFLT, v.value); +const tonumber = function(v) { +    if (v.type === CT.LUA_TNUMFLT) +        return new TValue(v.type, v.value); -        if (v.type === CT.LUA_TSHRSTR || v.type === CT.LUA_TLNGSTR) -            return new TValue(CT.LUA_TNUMFLT, parseFloat(v.value)); // TODO: luaO_str2num +    if (v.type === CT.LUA_TNUMINT) +        return new TValue(CT.LUA_TNUMFLT, v.value); -        return false; -    } +    if (v.type === CT.LUA_TSHRSTR || v.type === CT.LUA_TLNGSTR) +        return new TValue(CT.LUA_TNUMFLT, parseFloat(v.value)); // TODO: luaO_str2num -    static LTnum(l, r) { -        if (l.ttisinteger()) { -            if (r.ttisinteger()) -                return l.value < r.value ? 1 : 0; -            else -                return LuaVM.LTintfloat(r.value, l.value); -        } else { -            if (r.ttisfloat()) -                return l.value < r.value ? 1 : 0; -            else if (isNan(l.value)) -                return 0; -            else -                return !LuaVM.LEintfloat(r.value, l.value); -        } -    } +    return false; +} -    static LEnum(l, r) { -        if (l.ttisinteger()) { -            if (r.ttisinteger()) -                return l.value <= r.value ? 1 : 0; -            else -                return LuaVM.LEintfloat(l.value, r.value); -        } else { -            if (r.ttisfloat()) -                return l.value <= r.value ? 1 : 0; -            else if (isNan(l.value)) -                return false; -            else -                return !LuaVM.LTintfloat(r.value, l.value); -        } +const LTnum = function(l, r) { +    if (l.ttisinteger()) { +        if (r.ttisinteger()) +            return l.value < r.value ? 1 : 0; +        else +            return LTintfloat(r.value, l.value); +    } else { +        if (r.ttisfloat()) +            return l.value < r.value ? 1 : 0; +        else if (isNan(l.value)) +            return 0; +        else +            return !LEintfloat(r.value, l.value);      } +} -    static LEintfloat(l, r) { -        // TODO: LEintfloat -        return l <= r ? 1 : 0; +const LEnum = function(l, r) { +    if (l.ttisinteger()) { +        if (r.ttisinteger()) +            return l.value <= r.value ? 1 : 0; +        else +            return LEintfloat(l.value, r.value); +    } else { +        if (r.ttisfloat()) +            return l.value <= r.value ? 1 : 0; +        else if (isNan(l.value)) +            return false; +        else +            return !LTintfloat(r.value, l.value);      } +} -    static LTintfloat(l, r) { -        // TODO: LTintfloat -        return l < r ? 1 : 0; -    } +const LEintfloat = function(l, r) { +    // TODO: LEintfloat +    return l <= r ? 1 : 0; +} -    static l_strcmp(ls, rs) { -        // TODO: lvm.c:248 static int l_strcmp (const TString *ls, const TString *rs) -        return ls.value === rs.value ? 0 : (ls.value < rs.value ? -1 : 1); -    } +const LTintfloat = function(l, r) { +    // TODO: LTintfloat +    return l < r ? 1 : 0; +} -    static l_isfalse(o) { -        return o.ttisnil() || (o.ttisboolean() && o.value === false) -    } +const l_strcmp = function(ls, rs) { +    // TODO: lvm.c:248 static int l_strcmp (const TString *ls, const TString *rs) +    return ls.value === rs.value ? 0 : (ls.value < rs.value ? -1 : 1); +} +const l_isfalse = function(o) { +    return o.ttisnil() || (o.ttisboolean() && o.value === false)  }  module.exports = { -    LuaVM: LuaVM +    RA:             RA, +    RB:             RB, +    RC:             RC, +    RKB:            RKB, +    RKC:            RKC, +    luaV_execute:   luaV_execute, +    dojump:         dojump, +    donextjump:     donextjump, +    luaV_lessequal: luaV_lessequal, +    luaV_lessthan:  luaV_lessthan, +    luaV_equalobj:  luaV_equalobj, +    forlimit:       forlimit, +    luaV_tointeger: luaV_tointeger, +    tonumber:       tonumber, +    LTnum:          LTnum, +    LEnum:          LEnum, +    LEintfloat:     LEintfloat, +    LTintfloat:     LTintfloat, +    l_strcmp:       l_strcmp, +    l_isfalse:      l_isfalse  };
\ No newline at end of file  | 
