static void PrintConstant(const Proto* f, int i) { const TValue* o=&f->k[i]; switch (ttype(o)) { case LUA_TNIL: printf("nil"); break; case LUA_TBOOLEAN: printf(bvalue(o) ? "true" : "false"); break; case LUA_TNUMFLT: { char buff[100]; #ifndef __NetBSD__ sprintf(buff,LUA_NUMBER_FMT,fltvalue(o)); #else /* __NetBSD__ */ l_sprintf(buff, sizeof(buff), LUA_NUMBER_FMT,fltvalue(o)); #endif /* __NetBSD__ */ printf("%s",buff); if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0"); break; } case LUA_TNUMINT: printf(LUA_INTEGER_FMT,ivalue(o)); break; case LUA_TSHRSTR: case LUA_TLNGSTR: PrintString(tsvalue(o)); break; default: /* cannot happen */ printf("? type=%d",ttype(o)); break; } }
/* ** Main operation for equality of Lua values; return 't1 == t2'. ** L == NULL means raw equality (no metamethods) */ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { const TValue *tm; if (ttype(t1) != ttype(t2)) { /* not the same variant? */ #ifndef _KERNEL if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) return 0; /* only numbers can be equal with different variants */ else { /* two numbers with different variants */ lua_Integer i1, i2; /* compare them as integers */ return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2); } #else /* _KERNEL */ return 0; /* numbers have only the integer variant */ #endif /* _KERNEL */ } /* values have same type and same variant */ switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2)); #ifndef _KERNEL case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); #endif /* _KERNEL */ case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TLCF: return fvalue(t1) == fvalue(t2); case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; else if (L == NULL) return 0; tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); if (tm == NULL) tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; else if (L == NULL) return 0; tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); if (tm == NULL) tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) /* no TM? */ return 0; /* objects are different */ luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */ return !l_isfalse(L->top); }
static void DumpConstants (const Proto *f, DumpState *D) { int i; int n = f->sizek; DumpInt(n, D); for (i = 0; i < n; i++) { const TValue *o = &f->k[i]; DumpByte(ttype(o), D); switch (ttype(o)) { case LUA_TNIL: break; case LUA_TBOOLEAN: DumpByte(bvalue(o), D); break; case LUA_TNUMFLT: DumpNumber(fltvalue(o), D); break; case LUA_TNUMINT: DumpInteger(ivalue(o), D); break; case LUA_TSHRSTR: case LUA_TLNGSTR: DumpString(tsvalue(o), D); break; default: lua_assert(0); } } }
/* ** this function is quite liberal in what it accepts, as 'luaO_str2num' ** will reject ill-formed numerals. */ static int read_numeral (LexState *ls, SemInfo *seminfo) { TValue obj; const char *expo = "Ee"; int first = ls->current; lua_assert(lisdigit(ls->current)); save_and_next(ls); if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ expo = "Pp"; for (;;) { if (check_next2(ls, expo)) /* exponent part? */ check_next2(ls, "-+"); /* optional exponent sign */ if (lisxdigit(ls->current)) save_and_next(ls); else if (ls->current == '.') save_and_next(ls); else break; } save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ if (!buff2num(ls->buff, &obj)) /* format error? */ trydecpoint(ls, &obj); /* try to update decimal point separator */ if (ttisinteger(&obj)) { seminfo->i = ivalue(&obj); return TK_INT; } else { lua_assert(ttisfloat(&obj)); seminfo->r = fltvalue(&obj); return TK_FLT; } }
/* ** this function is quite liberal in what it accepts, as 'luaO_str2num' ** will reject ill-formed numerals. */ static int read_numeral (LexState *ls, SemInfo *seminfo) { TValue obj; const char *expo = "Ee"; int first = ls->current; lua_assert(lisdigit(ls->current)); save_and_next(ls); if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ expo = "Pp"; for (;;) { if (check_next2(ls, expo)) /* exponent part? */ check_next2(ls, "-+"); /* optional exponent sign */ if (lisxdigit(ls->current)) save_and_next(ls); else if (ls->current == '.') save_and_next(ls); else break; } save(ls, '\0'); if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ lexerror(ls, "malformed number", TK_FLT); if (ttisinteger(&obj)) { seminfo->i = ivalue(&obj); return TK_INT; } else { lua_assert(ttisfloat(&obj)); seminfo->r = fltvalue(&obj); return TK_FLT; } }
/* ** Return 'l <= r', for numbers. */ static int LEnum (const TValue *l, const TValue *r) { if (ttisinteger(l)) { lua_Integer li = ivalue(l); if (ttisinteger(r)) return li <= ivalue(r); /* both are integers */ else /* 'l' is int and 'r' is float */ return LEintfloat(li, fltvalue(r)); /* l <= r ? */ } else { lua_Number lf = fltvalue(l); /* 'l' must be float */ if (ttisfloat(r)) return luai_numle(lf, fltvalue(r)); /* both are float */ else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ return 0; /* NaN <= i is always false */ else /* without NaN, (l <= r) <--> not(r < l) */ return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */ } }
/* ** Similar to 'tonumber', but does not attempt to convert strings and ** ensure correct precision (no extra bits). Used in comparisons. */ static int tofloat (const TValue *obj, lua_Number *n) { if (ttisfloat(obj)) *n = fltvalue(obj); else if (ttisinteger(obj)) { volatile lua_Number x = cast_num(ivalue(obj)); /* avoid extra precision */ *n = x; } else { *n = 0; /* to avoid warnings */ return 0; } return 1; }
/* ** Try to convert a value to a float. Check 'isinteger' first, because ** in general the float case is already handled by the macro 'tonumber'. */ int luaV_tonumber_ (const TValue *obj, lua_Number *n) { TValue v; again: if (ttisinteger(obj)) { *n = cast_num(ivalue(obj)); return 1; } else if (ttisfloat(obj)) { *n = fltvalue(obj); return 1; } else if (cvt2num(obj) && /* string convertible to number? */ luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) { obj = &v; goto again; /* convert result from 'luaO_str2num' to a float */ } return 0; /* conversion failed */ }
/* ** Try to "constant-fold" an operation; return 1 iff successful */ static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) { TValue v1, v2, res; if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) return 0; /* non-numeric operands or not safe to fold */ luaO_arith(fs->ls->L, op, &v1, &v2, &res); if (ttisinteger(&res)) { e1->k = VKINT; e1->u.ival = ivalue(&res); } else { lua_Number n = fltvalue(&res); if (luai_numisnan(n) || isminuszero(n)) return 0; /* folds neither NaN nor -0 */ e1->k = VKFLT; e1->u.nval = n; } return 1; }
int luaV_tostring (lua_State *L, StkId obj) { if (!ttisnumber(obj)) return 0; else { char buff[MAXNUMBER2STR]; size_t len; if (ttisinteger(obj)) len = lua_integer2str(buff, ivalue(obj)); else { len = lua_number2str(buff, fltvalue(obj)); if (strspn(buff, "-0123456789") == len) { /* look like an integer? */ buff[len++] = '.'; /* add a '.0' */ buff[len++] = '0'; buff[len] = '\0'; } } setsvalue2s(L, obj, luaS_newlstr(L, buff, len)); return 1; } }
/* ** Check whether key 'k1' is equal to the key in node 'n2'. ** This equality is raw, so there are no metamethods. Floats ** with integer values have been normalized, so integers cannot ** be equal to floats. It is assumed that 'eqshrstr' is simply ** pointer equality, so that short strings are handled in the ** default case. */ static int equalkey (const TValue *k1, const Node *n2) { if (rawtt(k1) != keytt(n2)) /* not the same variants? */ return 0; /* cannot be same key */ switch (ttypetag(k1)) { case LUA_TNIL: return 1; case LUA_TNUMINT: return (ivalue(k1) == keyival(n2)); case LUA_TNUMFLT: return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2))); case LUA_TBOOLEAN: return bvalue(k1) == bvalueraw(keyval(n2)); case LUA_TLIGHTUSERDATA: return pvalue(k1) == pvalueraw(keyval(n2)); case LUA_TLCF: return fvalue(k1) == fvalueraw(keyval(n2)); case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(k1), keystrval(n2)); default: return gcvalue(k1) == gcvalueraw(keyval(n2)); } }
/* ** 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 */ int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { TValue v; again: if (ttisfloat(obj)) { lua_Number n = fltvalue(obj); lua_Number f = l_floor(n); if (n != f) { /* not an integral value? */ if (mode == 0) return 0; /* fails if mode demands integral value */ else if (mode > 1) /* needs ceil? */ f += 1; /* convert floor to ceil (remember: n != f) */ } return lua_numbertointeger(f, p); } else if (ttisinteger(obj)) { *p = ivalue(obj); return 1; } else if (cvt2num(obj) && luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { obj = &v; goto again; /* convert result from 'luaO_str2num' to an integer */ } return 0; /* conversion failed */ }
/* ** 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 */ int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { TValue v; again: #ifndef _KERNEL if (ttisfloat(obj)) { lua_Number n = fltvalue(obj); lua_Number f = l_floor(n); if (n != f) { /* not an integral value? */ if (mode == 0) return 0; /* fails if mode demands integral value */ else if (mode > 1) /* needs ceil? */ f += 1; /* convert floor to ceil (remember: n != f) */ } return lua_numbertointeger(f, p); } else if (ttisinteger(obj)) { #else /* _KERNEL */ if (ttisinteger(obj)) { UNUSED(mode); #endif *p = ivalue(obj); return 1; } else if (cvt2num(obj) && luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { obj = &v; goto again; /* convert result from 'luaO_str2num' to an integer */ } return 0; /* conversion failed */ } #ifndef _KERNEL /* ** Try to convert a 'for' limit to an integer, preserving the ** semantics of the loop. ** (The following explanation assumes a non-negative step; it is valid ** for negative steps mutatis mutandis.) ** If the limit can be converted to an integer, rounding down, that is ** it. ** Otherwise, check whether the limit can be converted to a number. If ** the number is too large, it is OK to set the limit as LUA_MAXINTEGER, ** which means no limit. If the number is too negative, the loop ** should not run, because any initial integer value is larger than the ** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects ** the extreme case when the initial value is LUA_MININTEGER, in which ** case the LUA_MININTEGER limit would still run the loop once. */ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, int *stopnow) { *stopnow = 0; /* usually, let loops run */ if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */ lua_Number n; /* try to convert to float */ if (!tonumber(obj, &n)) /* cannot convert to float? */ return 0; /* not a number */ if (luai_numlt(0, n)) { /* if true, float is larger than max integer */ *p = LUA_MAXINTEGER; if (step < 0) *stopnow = 1; } else { /* float is smaller than min integer */ *p = LUA_MININTEGER; if (step >= 0) *stopnow = 1; } } return 1; }