static void lll_forprep (lua_State *L, TValue *ra) { TValue *init = ra; TValue *plimit = ra + 1; TValue *pstep = ra + 2; lua_Integer ilimit; int stopnow; if (ttisinteger(init) && ttisinteger(pstep) && forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { /* all values are integer */ lua_Integer initv = (stopnow ? 0 : ivalue(init)); setivalue(plimit, ilimit); setivalue(init, initv - ivalue(pstep)); } else { /* try making all values floats */ lua_Number ninit; lua_Number nlimit; lua_Number nstep; if (!tonumber(plimit, &nlimit)) luaG_runerror(L, "'for' limit must be a number"); setfltvalue(plimit, nlimit); if (!tonumber(pstep, &nstep)) luaG_runerror(L, "'for' step must be a number"); setfltvalue(pstep, nstep); if (!tonumber(init, &ninit)) luaG_runerror(L, "'for' initial value must be a number"); setfltvalue(init, luai_numsub(L, ninit, nstep)); } }
/* ** Main operation less than; return 'l < r'. */ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int res; #ifndef _KERNEL if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ return LTnum(l, r); #else /* _KERNEL */ if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */ return (ivalue(l) < ivalue(r)); #endif /* _KERNEL */ else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ return l_strcmp(tsvalue(l), tsvalue(r)) < 0; else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ luaG_ordererror(L, l, r); /* error */ return res; }
void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, TValue *res) { switch (op) { case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* operate only on integers */ lua_Integer i1; lua_Integer i2; if (tointeger(p1, &i1) && tointeger(p2, &i2)) { setivalue(res, intarith(L, op, i1, i2)); return; } else break; /* go to the end */ } #ifndef _KERNEL case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ lua_Number n1; lua_Number n2; if (tonumber(p1, &n1) && tonumber(p2, &n2)) { setfltvalue(res, numarith(L, op, n1, n2)); return; } else break; /* go to the end */ } #endif default: { /* other operations */ #ifndef _KERNEL lua_Number n1; lua_Number n2; if (ttisinteger(p1) && ttisinteger(p2)) { setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); return; } else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { setfltvalue(res, numarith(L, op, n1, n2)); return; } #else /* _KERNEL */ lua_Integer i1; lua_Integer i2; if (tointeger(p1, &i1) && tointeger(p2, &i2)) { setivalue(res, intarith(L, op, i1, i2)); return; } #endif else break; /* go to the end */ } } /* could not perform raw operation; try metamethod */ lua_assert(L != NULL); /* should not fail when folding (compile time) */ luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); }
/* ** 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; } }
/* ** Add constant 'v' to prototype's list of constants (field 'k'). ** Use scanner's table to cache position of constants in constant list ** and try to reuse constants. Because some values should not be used ** as keys (nil cannot be a key, integer keys can collapse with float ** keys), the caller must provide a useful 'key' for indexing the cache. */ static int addk (FuncState *fs, TValue *key, TValue *v) { lua_State *L = fs->ls->L; Proto *f = fs->f; TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ int k, oldsize; if (ttisinteger(idx)) { /* is there an index there? */ k = cast_int(ivalue(idx)); /* correct value? (warning: must distinguish floats from integers!) */ if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && luaV_rawequalobj(&f->k[k], v)) return k; /* reuse index */ } /* constant not found; create a new entry */ oldsize = f->sizek; k = fs->nk; /* numerical value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ setivalue(idx, k); luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); setobj(L, &f->k[k], v); fs->nk++; luaC_barrier(L, f, v); return k; }
/* ** 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; } }
/* ** 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) ? */ } }
/* ** return false if folding can raise an error */ static int validop (int op, TValue *v1, TValue *v2) { lua_Number a, b; lua_Integer i; cast_void(a); cast_void(b); /* macro may not use its arguments */ if (luai_numinvalidop(op, (cast_void(tonumber(v1, &a)), a), (cast_void(tonumber(v2, &b)), b))) return 0; switch (op) { case LUA_OPIDIV: /* division by 0 and conversion errors */ return (tointeger(v1, &i) && tointeger(v2, &i) && i != 0); case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: /* conversion errors */ return (tointeger(v1, &i) && tointeger(v2, &i)); case LUA_OPMOD: /* integer module by 0 */ return !(ttisinteger(v1) && ttisinteger(v2) && ivalue(v2) == 0); default: return 1; /* everything else is valid */ } }
/* ** try to convert a non-integer value to an integer */ int luaV_tointeger_ (const TValue *obj, lua_Integer *p) { lua_Number n; lua_assert(!ttisinteger(obj)); if (tonumber(obj, &n)) { n = l_floor(n); return luaV_numtointeger(n, p); } else return 0; }
int luaV_tonumber_ (const TValue *obj, lua_Number *n) { lua_assert(!ttisfloat(obj)); if (ttisinteger(obj)) { *n = cast_num(ivalue(obj)); return 1; } else return (ttisstring(obj) && luaO_str2d(svalue(obj), tsvalue(obj)->len, n)); }
/* ** 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; }
/* ** Main operation less than or equal to; return 'l <= r'. If it needs ** a metamethod and there is no '__le', try '__lt', based on ** l <= r iff !(r < l) (assuming a total order). If the metamethod ** yields during this substitution, the continuation has to know ** about it (to negate the result of r<l); bit CIST_LEQ in the call ** status keeps that information. */ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; #ifndef _KERNEL if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ return LEnum(l, r); #else /* _KERNEL */ if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */ return (ivalue(l) <= ivalue(r)); #endif /* _KERNEL */ else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */ return res; else { /* try 'lt': */ L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ res = luaT_callorderTM(L, r, l, TM_LT); L->ci->callstatus ^= CIST_LEQ; /* clear mark */ if (res < 0) luaG_ordererror(L, l, r); return !res; /* result is negated */ } }
/* ** Try to convert a value to a float. The float case is already handled ** by the macro 'tonumber'. */ int luaV_tonumber_ (const TValue *obj, lua_Number *n) { TValue v; if (ttisinteger(obj)) { *n = cast_num(ivalue(obj)); return 1; } else if (cvt2num(obj) && /* string convertible to number? */ luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ return 1; } else return 0; /* conversion failed */ }
/* ** returns the index of a 'key' for table traversals. First goes all ** elements in the array part, then elements in the hash part. The ** beginning of a traversal is signaled by 0. */ static unsigned int findindex (lua_State *L, Table *t, TValue *key, unsigned int asize) { unsigned int i; if (ttisnil(key)) return 0; /* first iteration */ i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0; if (i != 0 && i <= asize) /* is 'key' inside array part? */ return i; /* yes; that's the index */ else { const TValue *n = getgeneric(t, key); if (unlikely(isabstkey(n))) luaG_runerror(L, "invalid key to 'next'"); /* key not found */ i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ return (i + 1) + asize; } }
/* ** 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; }
static int read_numeral (LexState *ls, SemInfo *seminfo) { TValue obj; int first = ls->current; lua_assert(lisdigit(ls->current)); save_and_next(ls); if (first == '0') check_next2(ls, "xX"); /* hexadecimal? */ for (;;) { if (lisxdigit(ls->current)) save_and_next(ls); else break; } save(ls, '\0'); if (!buff2num(ls->buff, &obj)) /* format error? */ lexerror(ls, "malformed number", TK_INT); lua_assert(ttisinteger(&obj)); seminfo->i = ivalue(&obj); return TK_INT; }
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; } }
/* ** 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 */ }
LUA_API int lua_isinteger (lua_State *L, int idx) { StkId o = index2addr(L, idx); return ttisinteger(o); }
/* ** 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; }