diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1998-07-12 13:16:43 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1998-07-12 13:16:43 -0300 |
| commit | afb5ef72e1974ba6d0fc336637c71f3ee8fb03a2 (patch) | |
| tree | 9e7c9bf902a86ae79a0eecb413dfb00ad1250665 /lbuiltin.c | |
| parent | 1d8edd347d728ba6b0160359f3c0391e7b1a8a44 (diff) | |
| download | lua-afb5ef72e1974ba6d0fc336637c71f3ee8fb03a2.tar.gz lua-afb5ef72e1974ba6d0fc336637c71f3ee8fb03a2.tar.bz2 lua-afb5ef72e1974ba6d0fc336637c71f3ee8fb03a2.zip | |
new function "sort" + many small changes
Diffstat (limited to 'lbuiltin.c')
| -rw-r--r-- | lbuiltin.c | 169 |
1 files changed, 125 insertions, 44 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lbuiltin.c,v 1.31 1998/06/19 18:47:06 roberto Exp roberto $ | 2 | ** $Id: lbuiltin.c,v 1.32 1998/06/29 18:24:06 roberto Exp roberto $ |
| 3 | ** Built-in functions | 3 | ** Built-in functions |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "ltm.h" | 23 | #include "ltm.h" |
| 24 | #include "lua.h" | 24 | #include "lua.h" |
| 25 | #include "lundump.h" | 25 | #include "lundump.h" |
| 26 | #include "lvm.h" | ||
| 26 | 27 | ||
| 27 | 28 | ||
| 28 | 29 | ||
| @@ -35,18 +36,17 @@ static void pushstring (TaggedString *s) | |||
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | 38 | ||
| 38 | static void nextvar (void) | 39 | static void nextvar (void) { |
| 39 | { | ||
| 40 | TObject *o = luaA_Address(luaL_nonnullarg(1)); | 40 | TObject *o = luaA_Address(luaL_nonnullarg(1)); |
| 41 | TaggedString *g; | 41 | TaggedString *g; |
| 42 | if (ttype(o) == LUA_T_NIL) | 42 | if (ttype(o) == LUA_T_NIL) |
| 43 | g = (TaggedString *)L->rootglobal.next; | 43 | g = (TaggedString *)L->rootglobal.next; /* first variable */ |
| 44 | else { | 44 | else { |
| 45 | luaL_arg_check(ttype(o) == LUA_T_STRING, 1, "variable name expected"); | 45 | luaL_arg_check(ttype(o) == LUA_T_STRING, 1, "variable name expected"); |
| 46 | g = tsvalue(o); | 46 | g = tsvalue(o); /* find given variable name */ |
| 47 | /* check whether name is in global var list */ | 47 | /* check whether name is in global var list */ |
| 48 | luaL_arg_check((GCnode *)g != g->head.next, 1, "variable name expected"); | 48 | luaL_arg_check((GCnode *)g != g->head.next, 1, "variable name expected"); |
| 49 | g = (TaggedString *)g->head.next; | 49 | g = (TaggedString *)g->head.next; /* get next */ |
| 50 | } | 50 | } |
| 51 | while (g && g->u.s.globalval.ttype == LUA_T_NIL) /* skip globals with nil */ | 51 | while (g && g->u.s.globalval.ttype == LUA_T_NIL) /* skip globals with nil */ |
| 52 | g = (TaggedString *)g->head.next; | 52 | g = (TaggedString *)g->head.next; |
| @@ -54,26 +54,26 @@ static void nextvar (void) | |||
| 54 | pushstring(g); | 54 | pushstring(g); |
| 55 | luaA_pushobject(&g->u.s.globalval); | 55 | luaA_pushobject(&g->u.s.globalval); |
| 56 | } | 56 | } |
| 57 | else lua_pushnil(); | 57 | else lua_pushnil(); /* no more globals */ |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | 60 | ||
| 61 | static void foreachvar (void) | 61 | static void foreachvar (void) { |
| 62 | { | ||
| 63 | TObject f = *luaA_Address(luaL_functionarg(1)); | 62 | TObject f = *luaA_Address(luaL_functionarg(1)); |
| 64 | GCnode *g; | 63 | GCnode *g; |
| 65 | StkId name = L->Cstack.base++; /* place to keep var name (to avoid GC) */ | 64 | StkId name = L->Cstack.base++; /* place to keep var name (to avoid GC) */ |
| 65 | luaD_checkstack(4); /* for var name, f, s, and globalvar */ | ||
| 66 | ttype(L->stack.stack+name) = LUA_T_NIL; | 66 | ttype(L->stack.stack+name) = LUA_T_NIL; |
| 67 | L->stack.top++; | 67 | L->stack.top++; /* top == base */ |
| 68 | for (g = L->rootglobal.next; g; g = g->next) { | 68 | for (g = L->rootglobal.next; g; g = g->next) { |
| 69 | TaggedString *s = (TaggedString *)g; | 69 | TaggedString *s = (TaggedString *)g; |
| 70 | if (s->u.s.globalval.ttype != LUA_T_NIL) { | 70 | if (s->u.s.globalval.ttype != LUA_T_NIL) { |
| 71 | ttype(L->stack.stack+name) = LUA_T_STRING; | 71 | ttype(L->stack.stack+name) = LUA_T_STRING; |
| 72 | tsvalue(L->stack.stack+name) = s; /* keep s on stack to avoid GC */ | 72 | tsvalue(L->stack.stack+name) = s; /* keep s on stack to avoid GC */ |
| 73 | luaA_pushobject(&f); | 73 | *(L->stack.top++) = f; |
| 74 | pushstring(s); | 74 | pushstring(s); |
| 75 | luaA_pushobject(&s->u.s.globalval); | 75 | *(L->stack.top++) = s->u.s.globalval; |
| 76 | luaD_call((L->stack.top-L->stack.stack)-2, 1); | 76 | luaD_calln(2, 1); |
| 77 | if (ttype(L->stack.top-1) != LUA_T_NIL) | 77 | if (ttype(L->stack.top-1) != LUA_T_NIL) |
| 78 | return; | 78 | return; |
| 79 | L->stack.top--; | 79 | L->stack.top--; |
| @@ -82,11 +82,9 @@ static void foreachvar (void) | |||
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | 84 | ||
| 85 | static void next (void) | 85 | static void next (void) { |
| 86 | { | 86 | Node *n = luaH_next(luaA_Address(luaL_tablearg(1)), |
| 87 | lua_Object o = luaL_tablearg(1); | 87 | luaA_Address(luaL_nonnullarg(2))); |
| 88 | lua_Object r = luaL_nonnullarg(2); | ||
| 89 | Node *n = luaH_next(luaA_Address(o), luaA_Address(r)); | ||
| 90 | if (n) { | 88 | if (n) { |
| 91 | luaA_pushobject(&n->ref); | 89 | luaA_pushobject(&n->ref); |
| 92 | luaA_pushobject(&n->val); | 90 | luaA_pushobject(&n->val); |
| @@ -95,18 +93,18 @@ static void next (void) | |||
| 95 | } | 93 | } |
| 96 | 94 | ||
| 97 | 95 | ||
| 98 | static void foreach (void) | 96 | static void foreach (void) { |
| 99 | { | ||
| 100 | TObject t = *luaA_Address(luaL_tablearg(1)); | 97 | TObject t = *luaA_Address(luaL_tablearg(1)); |
| 101 | TObject f = *luaA_Address(luaL_functionarg(2)); | 98 | TObject f = *luaA_Address(luaL_functionarg(2)); |
| 102 | int i; | 99 | int i; |
| 100 | luaD_checkstack(3); /* for f, ref, and val */ | ||
| 103 | for (i=0; i<avalue(&t)->nhash; i++) { | 101 | for (i=0; i<avalue(&t)->nhash; i++) { |
| 104 | Node *nd = &(avalue(&t)->node[i]); | 102 | Node *nd = &(avalue(&t)->node[i]); |
| 105 | if (ttype(ref(nd)) != LUA_T_NIL && ttype(val(nd)) != LUA_T_NIL) { | 103 | if (ttype(ref(nd)) != LUA_T_NIL && ttype(val(nd)) != LUA_T_NIL) { |
| 106 | luaA_pushobject(&f); | 104 | *(L->stack.top++) = f; |
| 107 | luaA_pushobject(ref(nd)); | 105 | *(L->stack.top++) = *ref(nd); |
| 108 | luaA_pushobject(val(nd)); | 106 | *(L->stack.top++) = *val(nd); |
| 109 | luaD_call((L->stack.top-L->stack.stack)-2, 1); | 107 | luaD_calln(2, 1); |
| 110 | if (ttype(L->stack.top-1) != LUA_T_NIL) | 108 | if (ttype(L->stack.top-1) != LUA_T_NIL) |
| 111 | return; | 109 | return; |
| 112 | L->stack.top--; | 110 | L->stack.top--; |
| @@ -138,8 +136,8 @@ static void internaldofile (void) | |||
| 138 | 136 | ||
| 139 | static void to_string (void) { | 137 | static void to_string (void) { |
| 140 | lua_Object obj = lua_getparam(1); | 138 | lua_Object obj = lua_getparam(1); |
| 141 | char *buff = luaL_openspace(30); | ||
| 142 | TObject *o = luaA_Address(obj); | 139 | TObject *o = luaA_Address(obj); |
| 140 | char buff[32]; | ||
| 143 | switch (ttype(o)) { | 141 | switch (ttype(o)) { |
| 144 | case LUA_T_NUMBER: | 142 | case LUA_T_NUMBER: |
| 145 | lua_pushstring(lua_getstring(obj)); | 143 | lua_pushstring(lua_getstring(obj)); |
| @@ -184,10 +182,10 @@ static void luaI_print (void) { | |||
| 184 | while ((obj = lua_getparam(i++)) != LUA_NOOBJECT) { | 182 | while ((obj = lua_getparam(i++)) != LUA_NOOBJECT) { |
| 185 | luaA_pushobject(&ts->u.s.globalval); | 183 | luaA_pushobject(&ts->u.s.globalval); |
| 186 | lua_pushobject(obj); | 184 | lua_pushobject(obj); |
| 187 | luaD_call((L->stack.top-L->stack.stack)-1, 1); | 185 | luaD_calln(1, 1); |
| 188 | if (ttype(L->stack.top-1) != LUA_T_STRING) | 186 | if (ttype(L->stack.top-1) != LUA_T_STRING) |
| 189 | lua_error("`tostring' must return a string to `print'"); | 187 | lua_error("`tostring' must return a string to `print'"); |
| 190 | printf("%s\t", svalue(L->stack.top-1)); | 188 | printf("%.200s\t", svalue(L->stack.top-1)); |
| 191 | L->stack.top--; | 189 | L->stack.top--; |
| 192 | } | 190 | } |
| 193 | printf("\n"); | 191 | printf("\n"); |
| @@ -197,12 +195,12 @@ static void luaI_print (void) { | |||
| 197 | static void luaI_type (void) | 195 | static void luaI_type (void) |
| 198 | { | 196 | { |
| 199 | lua_Object o = luaL_nonnullarg(1); | 197 | lua_Object o = luaL_nonnullarg(1); |
| 200 | lua_pushstring(luaO_typenames[-ttype(luaA_Address(o))]); | 198 | lua_pushstring(luaO_typename(luaA_Address(o))); |
| 201 | lua_pushnumber(lua_tag(o)); | 199 | lua_pushnumber(lua_tag(o)); |
| 202 | } | 200 | } |
| 203 | 201 | ||
| 204 | 202 | ||
| 205 | static void tonumber (void) | 203 | static void luaB_tonumber (void) |
| 206 | { | 204 | { |
| 207 | int base = luaL_opt_number(2, 10); | 205 | int base = luaL_opt_number(2, 10); |
| 208 | if (base == 10) { /* standard conversion */ | 206 | if (base == 10) { /* standard conversion */ |
| @@ -270,16 +268,30 @@ static void luatag (void) | |||
| 270 | } | 268 | } |
| 271 | 269 | ||
| 272 | 270 | ||
| 273 | static int getnarg (lua_Object table) | 271 | static int getsize (TObject *t) { |
| 274 | { | 272 | int max = 0; |
| 273 | int i; | ||
| 274 | Hash *h = avalue(t); | ||
| 275 | LUA_ASSERT(ttype(t) == LUA_T_ARRAY, "table expected"); | ||
| 276 | for (i = 0; i<nhash(h); i++) { | ||
| 277 | Node *n = h->node+i; | ||
| 278 | if (ttype(ref(n)) == LUA_T_NUMBER && ttype(val(n)) != LUA_T_NIL && | ||
| 279 | (int)nvalue(ref(n)) > max) | ||
| 280 | max = nvalue(ref(n)); | ||
| 281 | } | ||
| 282 | return max; | ||
| 283 | } | ||
| 284 | |||
| 285 | |||
| 286 | static int getnarg (lua_Object table) { | ||
| 275 | lua_Object temp; | 287 | lua_Object temp; |
| 276 | /* temp = table.n */ | 288 | /* temp = table.n */ |
| 277 | lua_pushobject(table); lua_pushstring("n"); temp = lua_rawgettable(); | 289 | lua_pushobject(table); lua_pushstring("n"); temp = lua_rawgettable(); |
| 278 | return (lua_isnumber(temp) ? lua_getnumber(temp) : MAX_INT); | 290 | return (lua_isnumber(temp) ? lua_getnumber(temp) : |
| 291 | getsize(luaA_Address(table))); | ||
| 279 | } | 292 | } |
| 280 | 293 | ||
| 281 | static void luaI_call (void) | 294 | static void luaI_call (void) { |
| 282 | { | ||
| 283 | lua_Object f = luaL_nonnullarg(1); | 295 | lua_Object f = luaL_nonnullarg(1); |
| 284 | lua_Object arg = luaL_tablearg(2); | 296 | lua_Object arg = luaL_tablearg(2); |
| 285 | char *options = luaL_opt_string(3, ""); | 297 | char *options = luaL_opt_string(3, ""); |
| @@ -291,14 +303,9 @@ static void luaI_call (void) | |||
| 291 | err = lua_seterrormethod(); | 303 | err = lua_seterrormethod(); |
| 292 | } | 304 | } |
| 293 | /* push arg[1...n] */ | 305 | /* push arg[1...n] */ |
| 294 | for (i=0; i<narg; i++) { | 306 | luaD_checkstack(narg); |
| 295 | lua_Object temp; | 307 | for (i=0; i<narg; i++) |
| 296 | /* temp = arg[i+1] */ | 308 | *(L->stack.top++) = *luaH_getint(avalue(luaA_Address(arg)), i+1); |
| 297 | lua_pushobject(arg); lua_pushnumber(i+1); temp = lua_rawgettable(); | ||
| 298 | if (narg == MAX_INT && lua_isnil(temp)) | ||
| 299 | break; | ||
| 300 | lua_pushobject(temp); | ||
| 301 | } | ||
| 302 | status = lua_callfunction(f); | 309 | status = lua_callfunction(f); |
| 303 | if (err != LUA_NOOBJECT) { /* restore old error method */ | 310 | if (err != LUA_NOOBJECT) { /* restore old error method */ |
| 304 | lua_pushobject(err); | 311 | lua_pushobject(err); |
| @@ -312,7 +319,7 @@ static void luaI_call (void) | |||
| 312 | else | 319 | else |
| 313 | lua_error(NULL); | 320 | lua_error(NULL); |
| 314 | } | 321 | } |
| 315 | else { /* no errors */ | 322 | else { /* no errors */ |
| 316 | if (strchr(options, 'p')) | 323 | if (strchr(options, 'p')) |
| 317 | luaA_packresults(); | 324 | luaA_packresults(); |
| 318 | else | 325 | else |
| @@ -390,6 +397,79 @@ static void luaI_collectgarbage (void) | |||
| 390 | } | 397 | } |
| 391 | 398 | ||
| 392 | 399 | ||
| 400 | |||
| 401 | static void swap (Hash *a, int i, int j) { | ||
| 402 | /* notice: must use two temporary vars, because luaH_setint may cause a | ||
| 403 | rehash and change the addresses of values in the array */ | ||
| 404 | TObject ai = *luaH_getint(a, i); | ||
| 405 | TObject aj = *luaH_getint(a, j); | ||
| 406 | luaH_setint(a, i, &aj); | ||
| 407 | luaH_setint(a, j, &ai); | ||
| 408 | } | ||
| 409 | |||
| 410 | static int sort_comp (TObject *f, TObject *a, TObject *b) { | ||
| 411 | /* notice: the caller (auxsort) must check stack space */ | ||
| 412 | if (f) { | ||
| 413 | *(L->stack.top++) = *f; | ||
| 414 | *(L->stack.top++) = *a; | ||
| 415 | *(L->stack.top++) = *b; | ||
| 416 | luaD_calln(2, 1); | ||
| 417 | } | ||
| 418 | else { /* a < b? */ | ||
| 419 | *(L->stack.top++) = *a; | ||
| 420 | *(L->stack.top++) = *b; | ||
| 421 | luaV_comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); | ||
| 422 | } | ||
| 423 | return ttype(--(L->stack.top)) != LUA_T_NIL; | ||
| 424 | } | ||
| 425 | |||
| 426 | /* | ||
| 427 | ** quicksort algorithm from "Programming Pearls", pg. 112 | ||
| 428 | */ | ||
| 429 | static void auxsort (Hash *a, int l, int u, TObject *f) { | ||
| 430 | if (u <= l) return; /* 0 or 1 element */ | ||
| 431 | luaD_checkstack(4); /* for pivot, f, a, b (sort_comp) */ | ||
| 432 | if (u-l == 1) { /* only two elements? */ | ||
| 433 | if (sort_comp(f, luaH_getint(a, u), luaH_getint(a, l))) /* a[u] < a[l]? */ | ||
| 434 | swap(a, l, u); | ||
| 435 | } | ||
| 436 | else { | ||
| 437 | int i; | ||
| 438 | int m = l; | ||
| 439 | swap(a, l, (l+u)/2); /* put middle element as pivot (a[l]) */ | ||
| 440 | *(L->stack.top++) = *luaH_getint(a, l); /* save pivot on stack (for GC) */ | ||
| 441 | for (i=l+1; i<=u; i++) { | ||
| 442 | /* invariant: a[l+1..m] < P <= a[m+1..i-1] */ | ||
| 443 | if (sort_comp(f, luaH_getint(a, i), L->stack.top-1)) { /* a[i] < P? */ | ||
| 444 | m++; | ||
| 445 | swap(a, m, i); | ||
| 446 | } | ||
| 447 | } | ||
| 448 | L->stack.top--; /* remove pivot from stack */ | ||
| 449 | swap(a, l, m); | ||
| 450 | /* a[l..m-1] < a[m] <= a[m+1..u] */ | ||
| 451 | auxsort(a, l, m-1, f); | ||
| 452 | auxsort(a, m+1, u, f); | ||
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | static void luaB_sort (void) { | ||
| 457 | lua_Object t = luaL_tablearg(1); | ||
| 458 | int n = getnarg(t); | ||
| 459 | Hash *a = avalue(luaA_Address(t)); | ||
| 460 | lua_Object func = lua_getparam(2); | ||
| 461 | TObject *f; | ||
| 462 | if (func == LUA_NOOBJECT) | ||
| 463 | f = NULL; | ||
| 464 | else { | ||
| 465 | luaL_arg_check(lua_isfunction(func), 2, "function expected"); | ||
| 466 | f = luaA_Address(func); | ||
| 467 | } | ||
| 468 | auxsort(a, 1, n, f); | ||
| 469 | lua_pushobject(t); | ||
| 470 | } | ||
| 471 | |||
| 472 | |||
| 393 | /* | 473 | /* |
| 394 | ** ======================================================= | 474 | ** ======================================================= |
| 395 | ** some DEBUG functions | 475 | ** some DEBUG functions |
| @@ -504,7 +584,8 @@ static struct luaL_reg int_funcs[] = { | |||
| 504 | {"settagmethod", settagmethod}, | 584 | {"settagmethod", settagmethod}, |
| 505 | {"gettagmethod", gettagmethod}, | 585 | {"gettagmethod", gettagmethod}, |
| 506 | {"settag", settag}, | 586 | {"settag", settag}, |
| 507 | {"tonumber", tonumber}, | 587 | {"sort", luaB_sort}, |
| 588 | {"tonumber", luaB_tonumber}, | ||
| 508 | {"tostring", to_string}, | 589 | {"tostring", to_string}, |
| 509 | {"tag", luatag}, | 590 | {"tag", luatag}, |
| 510 | {"type", luaI_type} | 591 | {"type", luaI_type} |
