diff options
Diffstat (limited to 'lvm.c')
-rw-r--r-- | lvm.c | 148 |
1 files changed, 93 insertions, 55 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 2.205 2014/05/01 18:18:06 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.206 2014/05/09 14:20:52 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -56,7 +56,8 @@ static int tofloat (const TValue *obj, lua_Number *n) { | |||
56 | 56 | ||
57 | 57 | ||
58 | /* | 58 | /* |
59 | ** Try to convert a value to a float | 59 | ** Try to convert a value to a float. Check 'isinteger' first, because |
60 | ** in general the float case is already handled by the macro 'tonumber'. | ||
60 | */ | 61 | */ |
61 | int luaV_tonumber_ (const TValue *obj, lua_Number *n) { | 62 | int luaV_tonumber_ (const TValue *obj, lua_Number *n) { |
62 | TValue v; | 63 | TValue v; |
@@ -69,7 +70,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) { | |||
69 | *n = fltvalue(obj); | 70 | *n = fltvalue(obj); |
70 | return 1; | 71 | return 1; |
71 | } | 72 | } |
72 | else if (ttisstring(obj) && | 73 | else if (ttisstring(obj) && /* string convertible to number? */ |
73 | luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) { | 74 | luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) { |
74 | obj = &v; | 75 | obj = &v; |
75 | goto again; /* convert result from 'luaO_str2num' to a float */ | 76 | goto again; /* convert result from 'luaO_str2num' to a float */ |
@@ -178,8 +179,12 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, | |||
178 | } | 179 | } |
179 | 180 | ||
180 | 181 | ||
182 | /* | ||
183 | ** Main function for table access (invoking metamethods if needed). | ||
184 | ** Compute 'val = t[key]' | ||
185 | */ | ||
181 | void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { | 186 | void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { |
182 | int loop; | 187 | int loop; /* counter to avoid infinite loops */ |
183 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | 188 | for (loop = 0; loop < MAXTAGLOOP; loop++) { |
184 | const TValue *tm; | 189 | const TValue *tm; |
185 | if (ttistable(t)) { /* `t' is a table? */ | 190 | if (ttistable(t)) { /* `t' is a table? */ |
@@ -187,32 +192,36 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { | |||
187 | const TValue *res = luaH_get(h, key); /* do a primitive get */ | 192 | const TValue *res = luaH_get(h, key); /* do a primitive get */ |
188 | if (!ttisnil(res) || /* result is not nil? */ | 193 | if (!ttisnil(res) || /* result is not nil? */ |
189 | (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ | 194 | (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ |
190 | setobj2s(L, val, res); | 195 | setobj2s(L, val, res); /* result is the raw get */ |
191 | return; | 196 | return; |
192 | } | 197 | } |
193 | /* else will try the tag method */ | 198 | /* else will try metamethod */ |
194 | } | 199 | } |
195 | else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) | 200 | else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) |
196 | luaG_typeerror(L, t, "index"); | 201 | luaG_typeerror(L, t, "index"); /* no metamethod */ |
197 | if (ttisfunction(tm)) { | 202 | if (ttisfunction(tm)) { /* metamethod is a function */ |
198 | luaT_callTM(L, tm, t, key, val, 1); | 203 | luaT_callTM(L, tm, t, key, val, 1); |
199 | return; | 204 | return; |
200 | } | 205 | } |
201 | t = tm; /* else repeat with 'tm' */ | 206 | t = tm; /* else repeat access over 'tm' */ |
202 | } | 207 | } |
203 | luaG_runerror(L, "gettable chain too long; possible loop"); | 208 | luaG_runerror(L, "gettable chain too long; possible loop"); |
204 | } | 209 | } |
205 | 210 | ||
206 | 211 | ||
212 | /* | ||
213 | ** Main function for table assignment (invoking metamethods if needed). | ||
214 | ** Compute 't[key] = val' | ||
215 | */ | ||
207 | void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { | 216 | void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { |
208 | int loop; | 217 | int loop; /* counter to avoid infinite loops */ |
209 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | 218 | for (loop = 0; loop < MAXTAGLOOP; loop++) { |
210 | const TValue *tm; | 219 | const TValue *tm; |
211 | if (ttistable(t)) { /* `t' is a table? */ | 220 | if (ttistable(t)) { /* `t' is a table? */ |
212 | Table *h = hvalue(t); | 221 | Table *h = hvalue(t); |
213 | TValue *oldval = cast(TValue *, luaH_get(h, key)); | 222 | TValue *oldval = cast(TValue *, luaH_get(h, key)); |
214 | /* if previous value is not nil, there must be a previous entry | 223 | /* if previous value is not nil, there must be a previous entry |
215 | in the table; moreover, a metamethod has no relevance */ | 224 | in the table; a metamethod has no relevance */ |
216 | if (!ttisnil(oldval) || | 225 | if (!ttisnil(oldval) || |
217 | /* previous value is nil; must check the metamethod */ | 226 | /* previous value is nil; must check the metamethod */ |
218 | ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && | 227 | ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && |
@@ -232,32 +241,40 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { | |||
232 | else /* not a table; check metamethod */ | 241 | else /* not a table; check metamethod */ |
233 | if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) | 242 | if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) |
234 | luaG_typeerror(L, t, "index"); | 243 | luaG_typeerror(L, t, "index"); |
235 | /* there is a metamethod */ | 244 | /* try the metamethod */ |
236 | if (ttisfunction(tm)) { | 245 | if (ttisfunction(tm)) { |
237 | luaT_callTM(L, tm, t, key, val, 0); | 246 | luaT_callTM(L, tm, t, key, val, 0); |
238 | return; | 247 | return; |
239 | } | 248 | } |
240 | t = tm; /* else repeat with 'tm' */ | 249 | t = tm; /* else repeat assginment over 'tm' */ |
241 | } | 250 | } |
242 | luaG_runerror(L, "settable chain too long; possible loop"); | 251 | luaG_runerror(L, "settable chain too long; possible loop"); |
243 | } | 252 | } |
244 | 253 | ||
245 | 254 | ||
255 | /* | ||
256 | ** Compare two strings 'ls' x 'rs', returning an integer smaller-equal- | ||
257 | ** -larger than zero if 'ls' is smaller-equal-larger than 'rs'. | ||
258 | ** The code is a little tricky because it allows '\0' in the strings | ||
259 | ** and it uses 'strcoll' (to respect locales) for each segments | ||
260 | ** of the strings. | ||
261 | */ | ||
246 | static int l_strcmp (const TString *ls, const TString *rs) { | 262 | static int l_strcmp (const TString *ls, const TString *rs) { |
247 | const char *l = getstr(ls); | 263 | const char *l = getstr(ls); |
248 | size_t ll = ls->tsv.len; | 264 | size_t ll = ls->tsv.len; |
249 | const char *r = getstr(rs); | 265 | const char *r = getstr(rs); |
250 | size_t lr = rs->tsv.len; | 266 | size_t lr = rs->tsv.len; |
251 | for (;;) { | 267 | for (;;) { /* for each segment */ |
252 | int temp = strcoll(l, r); | 268 | int temp = strcoll(l, r); |
253 | if (temp != 0) return temp; | 269 | if (temp != 0) /* not equal? */ |
254 | else { /* strings are equal up to a `\0' */ | 270 | return temp; /* done */ |
271 | else { /* strings are equal up to a '\0' */ | ||
255 | size_t len = strlen(l); /* index of first `\0' in both strings */ | 272 | size_t len = strlen(l); /* index of first `\0' in both strings */ |
256 | if (len == lr) /* r is finished? */ | 273 | if (len == lr) /* 'rs' is finished? */ |
257 | return (len == ll) ? 0 : 1; | 274 | return (len == ll) ? 0 : 1; /* check 'ls' */ |
258 | else if (len == ll) /* l is finished? */ | 275 | else if (len == ll) /* 'ls' is finished? */ |
259 | return -1; /* l is smaller than r (because r is not finished) */ | 276 | return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */ |
260 | /* both strings longer than `len'; go on comparing (after the `\0') */ | 277 | /* both strings longer than `len'; go on comparing after the '\0' */ |
261 | len++; | 278 | len++; |
262 | l += len; ll -= len; r += len; lr -= len; | 279 | l += len; ll -= len; r += len; lr -= len; |
263 | } | 280 | } |
@@ -265,29 +282,35 @@ static int l_strcmp (const TString *ls, const TString *rs) { | |||
265 | } | 282 | } |
266 | 283 | ||
267 | 284 | ||
285 | /* | ||
286 | ** Main operation less than; return 'l < r'. | ||
287 | */ | ||
268 | int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { | 288 | int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { |
269 | int res; | 289 | int res; |
270 | lua_Number nl, nr; | 290 | lua_Number nl, nr; |
271 | if (ttisinteger(l) && ttisinteger(r)) | 291 | if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */ |
272 | return (ivalue(l) < ivalue(r)); | 292 | return (ivalue(l) < ivalue(r)); |
273 | else if (tofloat(l, &nl) && tofloat(r, &nr)) | 293 | else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */ |
274 | return luai_numlt(nl, nr); | 294 | return luai_numlt(nl, nr); |
275 | else if (ttisstring(l) && ttisstring(r)) | 295 | else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ |
276 | return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; | 296 | return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; |
277 | else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) | 297 | else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ |
278 | luaG_ordererror(L, l, r); | 298 | luaG_ordererror(L, l, r); /* error */ |
279 | return res; | 299 | return res; |
280 | } | 300 | } |
281 | 301 | ||
282 | 302 | ||
303 | /* | ||
304 | ** Main operation less than or equal to; return 'l <= r'. | ||
305 | */ | ||
283 | int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { | 306 | int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { |
284 | int res; | 307 | int res; |
285 | lua_Number nl, nr; | 308 | lua_Number nl, nr; |
286 | if (ttisinteger(l) && ttisinteger(r)) | 309 | if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */ |
287 | return (ivalue(l) <= ivalue(r)); | 310 | return (ivalue(l) <= ivalue(r)); |
288 | else if (tofloat(l, &nl) && tofloat(r, &nr)) | 311 | else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */ |
289 | return luai_numle(nl, nr); | 312 | return luai_numle(nl, nr); |
290 | else if (ttisstring(l) && ttisstring(r)) | 313 | else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ |
291 | return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; | 314 | return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; |
292 | else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try `le' */ | 315 | else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try `le' */ |
293 | return res; | 316 | return res; |
@@ -298,15 +321,16 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { | |||
298 | 321 | ||
299 | 322 | ||
300 | /* | 323 | /* |
301 | ** equality of Lua values. L == NULL means raw equality (no metamethods) | 324 | ** Main operation for equality of Lua values; return 't1 == t2'. |
325 | ** L == NULL means raw equality (no metamethods) | ||
302 | */ | 326 | */ |
303 | int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { | 327 | int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { |
304 | const TValue *tm; | 328 | const TValue *tm; |
305 | if (ttype(t1) != ttype(t2)) { | 329 | if (ttype(t1) != ttype(t2)) { /* not the same variant? */ |
306 | if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) | 330 | if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) |
307 | return 0; /* only numbers can be equal with different variants */ | 331 | return 0; /* only numbers can be equal with different variants */ |
308 | else { /* two numbers with different variants */ | 332 | else { /* two numbers with different variants */ |
309 | lua_Number n1, n2; | 333 | lua_Number n1, n2; /* compare them as floats */ |
310 | lua_assert(ttisnumber(t1) && ttisnumber(t2)); | 334 | lua_assert(ttisnumber(t1) && ttisnumber(t2)); |
311 | cast_void(tofloat(t1, &n1)); cast_void(tofloat(t2, &n2)); | 335 | cast_void(tofloat(t1, &n1)); cast_void(tofloat(t2, &n2)); |
312 | return luai_numeq(n1, n2); | 336 | return luai_numeq(n1, n2); |
@@ -343,8 +367,13 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { | |||
343 | } | 367 | } |
344 | 368 | ||
345 | 369 | ||
370 | /* macro used by 'luaV_concat' to ensure that element at 'o' is a string */ | ||
346 | #define tostring(L,o) (ttisstring(o) || (luaV_tostring(L, o))) | 371 | #define tostring(L,o) (ttisstring(o) || (luaV_tostring(L, o))) |
347 | 372 | ||
373 | /* | ||
374 | ** Main operation for concatenation: concat 'total' values in the stack, | ||
375 | ** from 'L->top - total' up to 'L->top - 1'. | ||
376 | */ | ||
348 | void luaV_concat (lua_State *L, int total) { | 377 | void luaV_concat (lua_State *L, int total) { |
349 | lua_assert(total >= 2); | 378 | lua_assert(total >= 2); |
350 | do { | 379 | do { |
@@ -372,12 +401,12 @@ void luaV_concat (lua_State *L, int total) { | |||
372 | buffer = luaZ_openspace(L, &G(L)->buff, tl); | 401 | buffer = luaZ_openspace(L, &G(L)->buff, tl); |
373 | tl = 0; | 402 | tl = 0; |
374 | n = i; | 403 | n = i; |
375 | do { /* concat all strings */ | 404 | do { /* copy all strings to buffer */ |
376 | size_t l = tsvalue(top-i)->len; | 405 | size_t l = tsvalue(top-i)->len; |
377 | memcpy(buffer+tl, svalue(top-i), l * sizeof(char)); | 406 | memcpy(buffer+tl, svalue(top-i), l * sizeof(char)); |
378 | tl += l; | 407 | tl += l; |
379 | } while (--i > 0); | 408 | } while (--i > 0); |
380 | setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); | 409 | setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); /* create result */ |
381 | } | 410 | } |
382 | total -= n-1; /* got 'n' strings to create 1 new */ | 411 | total -= n-1; /* got 'n' strings to create 1 new */ |
383 | L->top -= n-1; /* popped 'n' strings and pushed one */ | 412 | L->top -= n-1; /* popped 'n' strings and pushed one */ |
@@ -385,6 +414,9 @@ void luaV_concat (lua_State *L, int total) { | |||
385 | } | 414 | } |
386 | 415 | ||
387 | 416 | ||
417 | /* | ||
418 | ** Main operation 'ra' = #rb'. | ||
419 | */ | ||
388 | void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { | 420 | void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { |
389 | const TValue *tm; | 421 | const TValue *tm; |
390 | switch (ttnov(rb)) { | 422 | switch (ttnov(rb)) { |
@@ -410,15 +442,18 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { | |||
410 | } | 442 | } |
411 | 443 | ||
412 | 444 | ||
413 | lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y) { | 445 | /* |
414 | if (l_castS2U(y) + 1u <= 1u) { /* special cases: -1 or 0 */ | 446 | ** Integer division; return 'm // n'. |
415 | if (y == 0) | 447 | */ |
448 | lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { | ||
449 | if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ | ||
450 | if (n == 0) | ||
416 | luaG_runerror(L, "attempt to divide by zero"); | 451 | luaG_runerror(L, "attempt to divide by zero"); |
417 | return intop(-, 0, x); /* y==-1; avoid overflow with 0x80000...//-1 */ | 452 | return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ |
418 | } | 453 | } |
419 | else { | 454 | else { |
420 | lua_Integer d = x / y; /* perform division */ | 455 | lua_Integer d = m / n; /* perform division */ |
421 | if ((x ^ y) >= 0 || x % y == 0) /* same signal or no rest? */ | 456 | if ((m ^ n) >= 0 || m % n == 0) /* same signal or no rest? */ |
422 | return d; | 457 | return d; |
423 | else | 458 | else |
424 | return d - 1; /* correct 'div' for negative case */ | 459 | return d - 1; /* correct 'div' for negative case */ |
@@ -426,33 +461,36 @@ lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y) { | |||
426 | } | 461 | } |
427 | 462 | ||
428 | 463 | ||
429 | lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y) { | 464 | /* |
430 | if (l_castS2U(y) + 1u <= 1u) { /* special cases: -1 or 0 */ | 465 | ** Integer modulus; return 'm % n'. |
431 | if (y == 0) | 466 | */ |
467 | lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { | ||
468 | if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ | ||
469 | if (n == 0) | ||
432 | luaG_runerror(L, "attempt to perform 'n%%0'"); | 470 | luaG_runerror(L, "attempt to perform 'n%%0'"); |
433 | return 0; /* y==-1; avoid overflow with 0x80000...%-1 */ | 471 | return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ |
434 | } | 472 | } |
435 | else { | 473 | else { |
436 | lua_Integer r = x % y; | 474 | lua_Integer r = m % n; |
437 | if (r == 0 || (x ^ y) >= 0) | 475 | if (r == 0 || (m ^ n) >= 0) |
438 | return r; | 476 | return r; |
439 | else | 477 | else |
440 | return r + y; /* correct 'mod' for negative case */ | 478 | return r + n; /* correct 'mod' for negative case */ |
441 | } | 479 | } |
442 | } | 480 | } |
443 | 481 | ||
444 | 482 | ||
445 | lua_Integer luaV_pow (lua_Integer x, lua_Integer y) { | 483 | lua_Integer luaV_pow (lua_Integer m, lua_Integer n) { |
446 | lua_assert(y >= 0); | 484 | lua_assert(n >= 0); |
447 | if (y == 0) | 485 | if (n == 0) |
448 | return 1; /* x^0 == 1 */ | 486 | return 1; /* m^0 == 1 */ |
449 | else { | 487 | else { |
450 | lua_Integer r = 1; | 488 | lua_Integer r = 1; |
451 | for (; y > 1; y >>= 1) { | 489 | for (; n > 1; n >>= 1) { |
452 | if (y & 1) r = intop(*, r, x); | 490 | if (n & 1) r = intop(*, r, m); |
453 | x = intop(*, x, x); | 491 | m = intop(*, m, m); |
454 | } | 492 | } |
455 | r = intop(*, r, x); | 493 | r = intop(*, r, m); |
456 | return r; | 494 | return r; |
457 | } | 495 | } |
458 | } | 496 | } |