1*8e3e3a7aSWarner Losh /* 2*8e3e3a7aSWarner Losh ** $Id: ltm.c,v 2.38 2016/12/22 13:08:50 roberto Exp $ 3*8e3e3a7aSWarner Losh ** Tag methods 4*8e3e3a7aSWarner Losh ** See Copyright Notice in lua.h 5*8e3e3a7aSWarner Losh */ 6*8e3e3a7aSWarner Losh 7*8e3e3a7aSWarner Losh #define ltm_c 8*8e3e3a7aSWarner Losh #define LUA_CORE 9*8e3e3a7aSWarner Losh 10*8e3e3a7aSWarner Losh #include "lprefix.h" 11*8e3e3a7aSWarner Losh 12*8e3e3a7aSWarner Losh 13*8e3e3a7aSWarner Losh #include <string.h> 14*8e3e3a7aSWarner Losh 15*8e3e3a7aSWarner Losh #include "lua.h" 16*8e3e3a7aSWarner Losh 17*8e3e3a7aSWarner Losh #include "ldebug.h" 18*8e3e3a7aSWarner Losh #include "ldo.h" 19*8e3e3a7aSWarner Losh #include "lobject.h" 20*8e3e3a7aSWarner Losh #include "lstate.h" 21*8e3e3a7aSWarner Losh #include "lstring.h" 22*8e3e3a7aSWarner Losh #include "ltable.h" 23*8e3e3a7aSWarner Losh #include "ltm.h" 24*8e3e3a7aSWarner Losh #include "lvm.h" 25*8e3e3a7aSWarner Losh 26*8e3e3a7aSWarner Losh 27*8e3e3a7aSWarner Losh static const char udatatypename[] = "userdata"; 28*8e3e3a7aSWarner Losh 29*8e3e3a7aSWarner Losh LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { 30*8e3e3a7aSWarner Losh "no value", 31*8e3e3a7aSWarner Losh "nil", "boolean", udatatypename, "number", 32*8e3e3a7aSWarner Losh "string", "table", "function", udatatypename, "thread", 33*8e3e3a7aSWarner Losh "proto" /* this last case is used for tests only */ 34*8e3e3a7aSWarner Losh }; 35*8e3e3a7aSWarner Losh 36*8e3e3a7aSWarner Losh 37*8e3e3a7aSWarner Losh void luaT_init (lua_State *L) { 38*8e3e3a7aSWarner Losh static const char *const luaT_eventname[] = { /* ORDER TM */ 39*8e3e3a7aSWarner Losh "__index", "__newindex", 40*8e3e3a7aSWarner Losh "__gc", "__mode", "__len", "__eq", 41*8e3e3a7aSWarner Losh "__add", "__sub", "__mul", "__mod", "__pow", 42*8e3e3a7aSWarner Losh "__div", "__idiv", 43*8e3e3a7aSWarner Losh "__band", "__bor", "__bxor", "__shl", "__shr", 44*8e3e3a7aSWarner Losh "__unm", "__bnot", "__lt", "__le", 45*8e3e3a7aSWarner Losh "__concat", "__call" 46*8e3e3a7aSWarner Losh }; 47*8e3e3a7aSWarner Losh int i; 48*8e3e3a7aSWarner Losh for (i=0; i<TM_N; i++) { 49*8e3e3a7aSWarner Losh G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]); 50*8e3e3a7aSWarner Losh luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ 51*8e3e3a7aSWarner Losh } 52*8e3e3a7aSWarner Losh } 53*8e3e3a7aSWarner Losh 54*8e3e3a7aSWarner Losh 55*8e3e3a7aSWarner Losh /* 56*8e3e3a7aSWarner Losh ** function to be used with macro "fasttm": optimized for absence of 57*8e3e3a7aSWarner Losh ** tag methods 58*8e3e3a7aSWarner Losh */ 59*8e3e3a7aSWarner Losh const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { 60*8e3e3a7aSWarner Losh const TValue *tm = luaH_getshortstr(events, ename); 61*8e3e3a7aSWarner Losh lua_assert(event <= TM_EQ); 62*8e3e3a7aSWarner Losh if (ttisnil(tm)) { /* no tag method? */ 63*8e3e3a7aSWarner Losh events->flags |= cast_byte(1u<<event); /* cache this fact */ 64*8e3e3a7aSWarner Losh return NULL; 65*8e3e3a7aSWarner Losh } 66*8e3e3a7aSWarner Losh else return tm; 67*8e3e3a7aSWarner Losh } 68*8e3e3a7aSWarner Losh 69*8e3e3a7aSWarner Losh 70*8e3e3a7aSWarner Losh const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { 71*8e3e3a7aSWarner Losh Table *mt; 72*8e3e3a7aSWarner Losh switch (ttnov(o)) { 73*8e3e3a7aSWarner Losh case LUA_TTABLE: 74*8e3e3a7aSWarner Losh mt = hvalue(o)->metatable; 75*8e3e3a7aSWarner Losh break; 76*8e3e3a7aSWarner Losh case LUA_TUSERDATA: 77*8e3e3a7aSWarner Losh mt = uvalue(o)->metatable; 78*8e3e3a7aSWarner Losh break; 79*8e3e3a7aSWarner Losh default: 80*8e3e3a7aSWarner Losh mt = G(L)->mt[ttnov(o)]; 81*8e3e3a7aSWarner Losh } 82*8e3e3a7aSWarner Losh return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); 83*8e3e3a7aSWarner Losh } 84*8e3e3a7aSWarner Losh 85*8e3e3a7aSWarner Losh 86*8e3e3a7aSWarner Losh /* 87*8e3e3a7aSWarner Losh ** Return the name of the type of an object. For tables and userdata 88*8e3e3a7aSWarner Losh ** with metatable, use their '__name' metafield, if present. 89*8e3e3a7aSWarner Losh */ 90*8e3e3a7aSWarner Losh const char *luaT_objtypename (lua_State *L, const TValue *o) { 91*8e3e3a7aSWarner Losh Table *mt; 92*8e3e3a7aSWarner Losh if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || 93*8e3e3a7aSWarner Losh (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) { 94*8e3e3a7aSWarner Losh const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name")); 95*8e3e3a7aSWarner Losh if (ttisstring(name)) /* is '__name' a string? */ 96*8e3e3a7aSWarner Losh return getstr(tsvalue(name)); /* use it as type name */ 97*8e3e3a7aSWarner Losh } 98*8e3e3a7aSWarner Losh return ttypename(ttnov(o)); /* else use standard type name */ 99*8e3e3a7aSWarner Losh } 100*8e3e3a7aSWarner Losh 101*8e3e3a7aSWarner Losh 102*8e3e3a7aSWarner Losh void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, 103*8e3e3a7aSWarner Losh const TValue *p2, TValue *p3, int hasres) { 104*8e3e3a7aSWarner Losh ptrdiff_t result = savestack(L, p3); 105*8e3e3a7aSWarner Losh StkId func = L->top; 106*8e3e3a7aSWarner Losh setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ 107*8e3e3a7aSWarner Losh setobj2s(L, func + 1, p1); /* 1st argument */ 108*8e3e3a7aSWarner Losh setobj2s(L, func + 2, p2); /* 2nd argument */ 109*8e3e3a7aSWarner Losh L->top += 3; 110*8e3e3a7aSWarner Losh if (!hasres) /* no result? 'p3' is third argument */ 111*8e3e3a7aSWarner Losh setobj2s(L, L->top++, p3); /* 3rd argument */ 112*8e3e3a7aSWarner Losh /* metamethod may yield only when called from Lua code */ 113*8e3e3a7aSWarner Losh if (isLua(L->ci)) 114*8e3e3a7aSWarner Losh luaD_call(L, func, hasres); 115*8e3e3a7aSWarner Losh else 116*8e3e3a7aSWarner Losh luaD_callnoyield(L, func, hasres); 117*8e3e3a7aSWarner Losh if (hasres) { /* if has result, move it to its place */ 118*8e3e3a7aSWarner Losh p3 = restorestack(L, result); 119*8e3e3a7aSWarner Losh setobjs2s(L, p3, --L->top); 120*8e3e3a7aSWarner Losh } 121*8e3e3a7aSWarner Losh } 122*8e3e3a7aSWarner Losh 123*8e3e3a7aSWarner Losh 124*8e3e3a7aSWarner Losh int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, 125*8e3e3a7aSWarner Losh StkId res, TMS event) { 126*8e3e3a7aSWarner Losh const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ 127*8e3e3a7aSWarner Losh if (ttisnil(tm)) 128*8e3e3a7aSWarner Losh tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ 129*8e3e3a7aSWarner Losh if (ttisnil(tm)) return 0; 130*8e3e3a7aSWarner Losh luaT_callTM(L, tm, p1, p2, res, 1); 131*8e3e3a7aSWarner Losh return 1; 132*8e3e3a7aSWarner Losh } 133*8e3e3a7aSWarner Losh 134*8e3e3a7aSWarner Losh 135*8e3e3a7aSWarner Losh void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, 136*8e3e3a7aSWarner Losh StkId res, TMS event) { 137*8e3e3a7aSWarner Losh if (!luaT_callbinTM(L, p1, p2, res, event)) { 138*8e3e3a7aSWarner Losh switch (event) { 139*8e3e3a7aSWarner Losh case TM_CONCAT: 140*8e3e3a7aSWarner Losh luaG_concaterror(L, p1, p2); 141*8e3e3a7aSWarner Losh /* call never returns, but to avoid warnings: *//* FALLTHROUGH */ 142*8e3e3a7aSWarner Losh case TM_BAND: case TM_BOR: case TM_BXOR: 143*8e3e3a7aSWarner Losh case TM_SHL: case TM_SHR: case TM_BNOT: { 144*8e3e3a7aSWarner Losh lua_Number dummy; 145*8e3e3a7aSWarner Losh if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) 146*8e3e3a7aSWarner Losh luaG_tointerror(L, p1, p2); 147*8e3e3a7aSWarner Losh else 148*8e3e3a7aSWarner Losh luaG_opinterror(L, p1, p2, "perform bitwise operation on"); 149*8e3e3a7aSWarner Losh } 150*8e3e3a7aSWarner Losh /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ 151*8e3e3a7aSWarner Losh default: 152*8e3e3a7aSWarner Losh luaG_opinterror(L, p1, p2, "perform arithmetic on"); 153*8e3e3a7aSWarner Losh } 154*8e3e3a7aSWarner Losh } 155*8e3e3a7aSWarner Losh } 156*8e3e3a7aSWarner Losh 157*8e3e3a7aSWarner Losh 158*8e3e3a7aSWarner Losh int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, 159*8e3e3a7aSWarner Losh TMS event) { 160*8e3e3a7aSWarner Losh if (!luaT_callbinTM(L, p1, p2, L->top, event)) 161*8e3e3a7aSWarner Losh return -1; /* no metamethod */ 162*8e3e3a7aSWarner Losh else 163*8e3e3a7aSWarner Losh return !l_isfalse(L->top); 164*8e3e3a7aSWarner Losh } 165*8e3e3a7aSWarner Losh 166