summaryrefslogtreecommitdiff
path: root/src/ltm.js
blob: 041e233cb7c48af945b1b49b50b8a0a1c3155464 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*jshint esversion: 6 */
"use strict";

const lobject = require('./lobject.js');
const TValue  = lobject.TValue;
const Table   = lobject.Table;
const ldo     = require('./ldo.js');
const lstate  = require('./lstate.js');
const lua     = require('./lua.js');
const CT      = lua.constant_types;


const TMS = {
    TM_INDEX:    "__index",
    TM_NEWINDEX: "__newindex",
    TM_GC:       "__gc",
    TM_MODE:     "__mode",
    TM_LEN:      "__len",
    TM_EQ:       "__eq",  /* last tag method with fast access */
    TM_ADD:      "__add",
    TM_SUB:      "__sub",
    TM_MUL:      "__mul",
    TM_MOD:      "__mod",
    TM_POW:      "__pow",
    TM_DIV:      "__div",
    TM_IDIV:     "__idiv",
    TM_BAND:     "__band",
    TM_BOR:      "__bor",
    TM_BXOR:     "__bxor",
    TM_SHL:      "__shl",
    TM_SHR:      "__shr",
    TM_UNM:      "__unm",
    TM_BNOT:     "__bnot",
    TM_LT:       "__lt",
    TM_LE:       "__le",
    TM_CONCAT:   "__concat",
    TM_CALL:     "__call",
    TM_N:        26
};

const luaT_callTM = function(L, f, p1, p2, p3, hasres) {
    let result = p3;
    let func = L.top;

    L.stack[L.top] = f;      /* push function (assume EXTRA_STACK) */
    L.stack[L.top + 1] = p1; /* 1st argument */
    L.stack[L.top + 2] = p2; /* 2nd argument */
    L.top += 3;

    if (!hasres)  /* no result? 'p3' is third argument */
        L.stack[L.top++] = p3;  /* 3rd argument */

    if (L.ci.callstatus & lstate.CIST_LUA)
        ldo.luaD_call(L, func, hasres);
    else
        ldo.luaD_callnoyield(L, func, hasres);

    if (hasres) {
        L.stack[result] = L.stack[--L.top];
    }
};

const luaT_callbinTM = function(L, p1, p2, res, event) {
    let tm = luaT_gettmbyobj(L, p1, event);
    if (tm.ttisnil())
        tm = luaT_gettmbyobj(L, p2, event);
    if (tm.ttisnil()) return false;
    luaT_callTM(L, tm, p1, p2, res, 1);
    return true;
};

const luaT_trybinTM = function(L, p1, p2, res, event) {
    if (!luaT_gettmbyobj(L, p1, p2, res, event)) {
        throw new Error("TM error"); // TODO: luaG_error
    }
};

const luaT_callorderTM = function(L, p1, p2, event) {
    if (!luaT_callbinTM(L, p2, p2, L.top, event))
        return -1;
    else
        return !L.stack[L.top].l_isfalse() ? 1 : 0;
};

const luaT_gettmbyobj = function(L, o, event) {
    let mt;
    switch(o.ttnov()) {
        case CT.LUA_TTABLE:
        case CT.LUA_TTUSERDATA:
            mt = o.value.metatable;
            break;
        default:
            // TODO: mt = G(L)->mt[ttnov(o)];
    }

    return mt ? mt.__index(mt, event) : ldo.nil;
};

module.exports = {
    TMS:              TMS,
    luaT_callTM:      luaT_callTM,
    luaT_callbinTM:   luaT_callbinTM,
    luaT_trybinTM:    luaT_trybinTM,
    luaT_callorderTM: luaT_callorderTM,
    luaT_gettmbyobj:  luaT_gettmbyobj
};