Bring Lua to 5.4.6. (#1214)

This essentially re-does the work of #875 on top of master.

This is what I did to check that Cosmo's Lua extensions still worked:

```
$ build/bootstrap/make MODE=aarch64 o/aarch64/third_party/lua/lua
$ ape o/aarch64/third_party/lua/lua
>: 10
10
>: 010
8
>: 0b10
2
>: string.byte("\e")
27
>: "Hello, %s" % {"world"}
Hello, world
>: "*" * 3
***
```

`luaL_traceback2` was used to show the stack trace with parameter
values; it's used in `LuaCallWithTrace`, which is used in Redbean to run
Lua code. You should be able to see the extended stack trace by running
something like this: `redbean -e "function a(b)c()end a(2)"` (with
"params" indicating the extended stack trace):

```
stack traceback:
 [string "function a(b)c()end a(2)"]:1: in function 'a', params: b = 2;
 [string "function a(b)c()end a(2)"]:1: in main chunk
```
@pkulchenko confirmed that I get the expected result with the updated
code.

This is what I did to check that Lua itself still worked:

```
$ cd third_party/lua/test/
$ ape ../../../o/aarch64/third_party/lua/lua all.lua
```

There's one test failure, in `files.lua`:

```
***** FILE 'files.lua'*****
testing i/o
../../../o/aarch64/third_party/lua/lua: files.lua:84: assertion failed!
stack traceback:
[C]: in function 'assert'
files.lua:84: in main chunk
(...tail calls...)
all.lua:195: in main chunk
[C]: in ?
.>>> closing state <<<
```

That isn't a result of these changes; the same test is failing in
master.

The failure is here:

```lua
if not _port then   -- invalid seek
  local status, msg, code = io.stdin:seek("set", 1000)
  assert(not status and type(msg) == "string" and type(code) == "number")
end
```

The test expects a seek to offset 1,000 on stdin to fail — but it
doesn't. `status` ends up being the new offset rather than `nil`.

If I comment out that one test, the remaining tests succeed.
This commit is contained in:
Michael Lenaghan 2024-06-15 20:13:08 -04:00 committed by GitHub
parent 3a599bfbe1
commit 0dbf01bf1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
90 changed files with 2741 additions and 1376 deletions

View file

@ -9,14 +9,14 @@ PROVENANCE
https://github.com/lua/lua/
commit e7803f7dbcdc966ab1f9db143424ee811ab1a398
commit 6443185167c77adcc8552a3fee7edab7895db1a9
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Wed Mar 3 09:44:20 2021 -0300
Date: May 2, 2023 at 3:44 PM EDT
New release number (5.4.3)
New release number (5.4.6)
luac.c needed to be sourced from:
https://www.lua.org/ftp/lua-5.4.3.tar.gz
https://www.lua.org/ftp/lua-5.4.6.tar.gz
LOCAL MODIFICATIONS
@ -31,10 +31,130 @@ LOCAL MODIFICATIONS
character. It may be used for teletypewriter control like having
bold text, which can be encoded elegantly as `\e[1mHELLO\e[0m`.
Added Python-like printf modulus operator for strings, e.g.:
`"Hello, %s!" % {"world"}`.
Added Python-like printf multiply operator for strings, e.g.:
`"Hello, world! " * 3`.
Added `unix` module that exposes the low-level System Five system
call interface, e.g.: `require("unix"); print(unix.getcwd())`.
Added luaL_traceback2() for function parameters in traceback.
Added Python-like printf modulus operator for strings.
Added Python-like printf multiply operator for strings.
Fixed a buffer overflow in os.tmpname
NOTES
If you'd like to update Cosmo's Lua to the latest version, here
are some things that might be helpful to know.
Cosmo's Lua adds ~20 or so files (e.g., `luacallwithtrace.c`,
`luaencodejsondata.c`, `luaencodeluadata.c`, etc.) to the
directory. In other words, a bunch of Cosmo's files don't
have any Lua counterpart.
Some of those files (e.g., `lunix.c`, `lunix.h`) implement
functionality that's available within the `lua` that Cosmo builds;
most, though, implement functionality that's (currently?) only
available within `redbean`. In other words, not everything can be
tested using `lua`; some things need to be tested using `redbean`.
Some of Lua's files were renamed. For example, `lua.c` was renamed
to `lua.main.c`, and `luac.c` (which is only available in Lua's
distributions, and not in Lua's Github repo) was renamed to
`luac.main.c`. `ljumptab.h` was renamed to `ljumptab.inc`, and
`lopnames.h` was renamed to `lopnames.inc`. In other words, you'll
need to take some kind of action in order to properly diff all of
Lua's files.
Lua's `.h` files had the comment headers that look like this
removed:
/*
** $Id: lua.h $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
*/
Lua's `.c` files *replaced* those comment headers with a Cosmo
emacs/vim header followed by a Lua copyright declaration.
The `.c` files also added a `__static_yoink("lua_notice");`
right after the `#include`s.
Some of Lua's tests have been modified to accommodate Cosmo's
changes. (And some of Lua's tests have been commented out
due to Cosmo's changes.)
Five of Lua's test files intentionally contain ISO-8859-1 (rather
than UTF-8) characters:
* test/db.lua
* test/files.lua
* test/pm.lua
* test/sort.lua
* test/strings.lua
If you edit those files as if they were UTF-8-encoded you'll
corrupt the ISO-8859-1 characters and cause certain tests to fail.
(Some of the tests count bytes, so you can't just fix the problem
by converting the files — you also have to change various expected
results.)
The modifications listed way up above are really only the
*user-visible* modifications. There are many that aren't
user-visible. For example, `_longjmp` was replaced with
`gclongjmp`, and `abort` was replaced, ultimately, with a
call to `_Exit`.
To update Cosmo's Lua, you'll need to diff the latest Lua against
the previous Lua, and Cosmo's Lua against the latest Lua. As you
do that, you'll be trying to figure out both what Lua changed
*and* what Cosmo changed; you'll be trying to add Lua's changes
without accidentally removing Cosmo's changes.
It's tricky!
We've started to try to make that process a bit easier by tagging
Cosmo's changes with `[jart]`. For example, one side of the diff
might (now) show:
#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
while the other side might (now) show:
#define LUAI_THROW(L,c) gclongjmp((c)->b, 1) // [jart]
The presence of the `[jart]` tag makes it easy to see that the
Cosmo change was intentional.
Be aware that not all changes have been tagged!
There are *other* things we've done that are *also* meant to make
diffing easier — though the intention is less obvious.
For example, Cosmo moved the `enum` of opcodes from `ltm.h` to
`tms.h`. Originally nothing at all was left behind in `ltm.h`.
Because of that, you'd see an `enum` in Lua that seemed to be
missing in Cosmo's Lua — as though the `enum` had recently been
added to Lua, and now needed to be added to Cosmo! To make the
intention of Cosmo's change more obvious, we added a tombstone
of sorts to `ltm.h`:
/*
* WARNING: if you change the order of this enumeration,
* grep "ORDER TM" and "ORDER OP"
*/
// [jart] moved to tms.h
The comment just above the tag comes from Lua; it's the comment
above Lua's original `enum`. *The presence of the comment in both
Lua and Cosmo helps diff tools "resync" at that point.* That in
turn makes it easier to see Cosmo's change, and to see that it was
intentional.
The more things like that we do — the easier we can make it to
quickly and correctly read diffs — the easier we'll make it to
keep Cosmo's Lua in sync with the latest Lua.

292
third_party/lua/lapi.c vendored
View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lapi_c
#define LUA_CORE
#include "third_party/lua/lapi.h"
#include "third_party/lua/ldebug.h"
#include "third_party/lua/ldo.h"
@ -66,45 +67,57 @@ const char lua_ident[] =
#define isupvalue(i) ((i) < LUA_REGISTRYINDEX)
/*
** Convert an acceptable index to a pointer to its respective value.
** Non-valid indices return the special nil value 'G(L)->nilvalue'.
*/
static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
StkId o = ci->func + idx;
api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index");
if (o >= L->top) return &G(L)->nilvalue;
StkId o = ci->func.p + idx;
api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
if (o >= L->top.p) return &G(L)->nilvalue;
else return s2v(o);
}
else if (!ispseudo(idx)) { /* negative index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
return s2v(L->top + idx);
api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
"invalid index");
return s2v(L->top.p + idx);
}
else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry;
else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
if (ttislcf(s2v(ci->func))) /* light C function? */
return &G(L)->nilvalue; /* it has no upvalues */
else {
CClosure *func = clCvalue(s2v(ci->func));
if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */
CClosure *func = clCvalue(s2v(ci->func.p));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue;
}
else { /* light C function or Lua function (through a hook)?) */
api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function");
return &G(L)->nilvalue; /* no upvalues */
}
}
}
static StkId index2stack (lua_State *L, int idx) {
/*
** Convert a valid actual index (not a pseudo-index) to its address.
*/
l_sinline StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
StkId o = ci->func + idx;
api_check(L, o < L->top, "unacceptable index");
StkId o = ci->func.p + idx;
api_check(L, o < L->top.p, "invalid index");
return o;
}
else { /* non-positive index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
"invalid index");
api_check(L, !ispseudo(idx), "invalid index");
return L->top + idx;
return L->top.p + idx;
}
}
@ -115,17 +128,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
lua_lock(L);
ci = L->ci;
api_check(L, n >= 0, "negative 'n'");
if (L->stack_last - L->top > n) /* stack large enough? */
if (L->stack_last.p - L->top.p > n) /* stack large enough? */
res = 1; /* yes; check is OK */
else { /* no; need to grow stack */
int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
res = 0; /* no */
else /* try to grow stack */
else /* need to grow stack */
res = luaD_growstack(L, n, 0);
}
if (res && ci->top < L->top + n)
ci->top = L->top + n; /* adjust frame top */
if (res && ci->top.p < L->top.p + n)
ci->top.p = L->top.p + n; /* adjust frame top */
lua_unlock(L);
return res;
}
@ -142,11 +150,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to);
api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states");
api_check(from, to->ci->top - to->top >= n, "stack overflow");
from->top -= n;
api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
from->top.p -= n;
for (i = 0; i < n; i++) {
setobjs2s(to, to->top, from->top + i);
to->top++; /* stack already checked by previous 'api_check' */
setobjs2s(to, to->top.p, from->top.p + i);
to->top.p++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
}
@ -199,7 +207,7 @@ LUA_API lua_Number lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx))
? idx
: cast_int(L->top - L->ci->func) + idx;
: cast_int(L->top.p - L->ci->func.p) + idx;
}
/**
@ -210,7 +218,7 @@ LUA_API int lua_absindex (lua_State *L, int idx) {
* particular, 0 means an empty stack.
*/
LUA_API int lua_gettop (lua_State *L) {
return cast_int(L->top - (L->ci->func + 1));
return cast_int(L->top.p - (L->ci->func.p + 1));
}
/**
@ -229,24 +237,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
ptrdiff_t diff; /* difference for new top */
lua_lock(L);
ci = L->ci;
func = ci->func;
func = ci->func.p;
if (idx >= 0) {
api_check(L, idx <= ci->top - (func + 1), "new top too large");
diff = ((func + 1) + idx) - L->top;
api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
diff = ((func + 1) + idx) - L->top.p;
for (; diff > 0; diff--)
setnilvalue(s2v(L->top++)); /* clear new slots */
setnilvalue(s2v(L->top.p++)); /* clear new slots */
}
else {
api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
diff = idx + 1; /* will "subtract" index (as it is negative) */
}
api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
newtop = L->top + diff;
if (diff < 0 && L->tbclist >= newtop) {
api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
newtop = L->top.p + diff;
if (diff < 0 && L->tbclist.p >= newtop) {
lua_assert(hastocloseCfunc(ci->nresults));
luaF_close(L, newtop, CLOSEKTOP, 0);
newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
}
L->top = newtop; /* correct top only after closing any upvalue */
L->top.p = newtop; /* correct top only after closing any upvalue */
lua_unlock(L);
}
@ -255,10 +263,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
StkId level;
lua_lock(L);
level = index2stack(L, idx);
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
"no variable to close at given level");
luaF_close(L, level, CLOSEKTOP, 0);
level = index2stack(L, idx); /* stack may be moved */
level = luaF_close(L, level, CLOSEKTOP, 0);
setnilvalue(s2v(level));
lua_unlock(L);
}
@ -270,7 +277,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
** Note that we move(copy) only the value inside the stack.
** (We do not move additional fields that may exist.)
*/
static void reverse (lua_State *L, StkId from, StkId to) {
l_sinline void reverse (lua_State *L, StkId from, StkId to) {
for (; from < to; from++, to--) {
TValue temp;
setobj(L, &temp, s2v(from));
@ -287,7 +294,7 @@ static void reverse (lua_State *L, StkId from, StkId to) {
LUA_API void lua_rotate (lua_State *L, int idx, int n) {
StkId p, t, m;
lua_lock(L);
t = L->top - 1; /* end of stack segment being rotated */
t = L->top.p - 1; /* end of stack segment being rotated */
p = index2stack(L, idx); /* start of segment */
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
@ -306,7 +313,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
api_check(L, isvalid(L, to), "invalid index");
setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */
luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr);
luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr);
/* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */
lua_unlock(L);
@ -315,7 +322,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
LUA_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L);
setobj2s(L, L->top, index2value(L, idx));
setobj2s(L, L->top.p, index2value(L, idx));
api_incr_top(L);
lua_unlock(L);
}
@ -384,12 +391,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
api_checknelems(L, 2); /* all other operations expect two operands */
else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1);
setobjs2s(L, L->top, L->top - 1);
setobjs2s(L, L->top.p, L->top.p - 1);
api_incr_top(L);
}
/* first operand at top - 2, second at top - 1; result go to top - 2 */
luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2);
L->top--; /* remove second operand */
luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
L->top.p--; /* remove second operand */
lua_unlock(L);
}
@ -415,7 +422,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
size_t sz = luaO_str2num(s, s2v(L->top));
size_t sz = luaO_str2num(s, s2v(L->top.p));
if (sz != 0)
api_incr_top(L);
return sz;
@ -490,7 +497,7 @@ LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
}
static void *touserdata (const TValue *o) {
l_sinline void *touserdata (const TValue *o) {
switch (ttype(o)) {
case LUA_TUSERDATA: return getudatamem(uvalue(o));
case LUA_TLIGHTUSERDATA: return pvalue(o);
@ -572,7 +579,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
*/
LUA_API void lua_pushnil (lua_State *L) {
lua_lock(L);
setnilvalue(s2v(L->top));
setnilvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@ -585,7 +592,7 @@ LUA_API void lua_pushnil (lua_State *L) {
*/
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L);
setfltvalue(s2v(L->top), n);
setfltvalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@ -600,7 +607,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
*/
LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
lua_lock(L);
setivalue(s2v(L->top), n);
setivalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@ -615,7 +622,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts;
lua_lock(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts);
setsvalue2s(L, L->top.p, ts);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@ -637,11 +644,11 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_lock(L);
if (s == NULL)
setnilvalue(s2v(L->top));
setnilvalue(s2v(L->top.p));
else {
TString *ts;
ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts);
setsvalue2s(L, L->top.p, ts);
s = getstr(ts); /* internal copy's address */
}
api_incr_top(L);
@ -729,7 +736,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L);
if (n == 0) {
setfvalue(s2v(L->top), fn);
setfvalue(s2v(L->top.p), fn);
api_incr_top(L);
}
else {
@ -738,13 +745,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n);
cl->f = fn;
L->top -= n;
L->top.p -= n;
while (n--) {
setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
/* does not need barrier because closure is white */
lua_assert(iswhite(cl));
}
setclCvalue(L, s2v(L->top), cl);
setclCvalue(L, s2v(L->top.p), cl);
api_incr_top(L);
luaC_checkGC(L);
}
@ -761,9 +768,9 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
lua_lock(L);
/* a.k.a. L->top->val.tt_ = b ? LUA_VTRUE : LUA_VFALSE; */
if (b)
setbtvalue(s2v(L->top));
setbtvalue(s2v(L->top.p));
else
setbfvalue(s2v(L->top));
setbfvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@ -781,7 +788,7 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
*/
LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
lua_lock(L);
setpvalue(s2v(L->top), p);
setpvalue(s2v(L->top.p), p);
api_incr_top(L);
lua_unlock(L);
}
@ -795,7 +802,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
*/
LUA_API int lua_pushthread (lua_State *L) {
lua_lock(L);
setthvalue(L, s2v(L->top), L);
setthvalue(L, s2v(L->top.p), L);
api_incr_top(L);
lua_unlock(L);
return (G(L)->mainthread == L);
@ -808,20 +815,20 @@ LUA_API int lua_pushthread (lua_State *L) {
*/
static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, slot);
setobj2s(L, L->top.p, slot);
api_incr_top(L);
}
else {
setsvalue2s(L, L->top, str);
setsvalue2s(L, L->top.p, str);
api_incr_top(L);
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
}
lua_unlock(L);
return ttype(s2v(L->top - 1));
return ttype(s2v(L->top.p - 1));
}
@ -848,13 +855,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) {
setobj2s(L, L->top - 1, slot);
if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
setobj2s(L, L->top.p - 1, slot);
}
else
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
lua_unlock(L);
return ttype(s2v(L->top - 1));
return ttype(s2v(L->top.p - 1));
}
@ -870,27 +877,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
setobj2s(L, L->top, slot);
setobj2s(L, L->top.p, slot);
}
else {
TValue aux;
setivalue(&aux, n);
luaV_finishget(L, t, &aux, L->top, slot);
luaV_finishget(L, t, &aux, L->top.p, slot);
}
api_incr_top(L);
lua_unlock(L);
return ttype(s2v(L->top - 1));
return ttype(s2v(L->top.p - 1));
}
static int finishrawget (lua_State *L, const TValue *val) {
l_sinline int finishrawget (lua_State *L, const TValue *val) {
if (isempty(val)) /* avoid copying empty items to the stack */
setnilvalue(s2v(L->top));
setnilvalue(s2v(L->top.p));
else
setobj2s(L, L->top, val);
setobj2s(L, L->top.p, val);
api_incr_top(L);
lua_unlock(L);
return ttype(s2v(L->top - 1));
return ttype(s2v(L->top.p - 1));
}
@ -913,8 +920,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
val = luaH_get(t, s2v(L->top - 1));
L->top--; /* remove key */
val = luaH_get(t, s2v(L->top.p - 1));
L->top.p--; /* remove key */
return finishrawget(L, val);
}
@ -961,7 +968,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
t = luaH_new(L);
sethvalue2s(L, L->top, t);
sethvalue2s(L, L->top.p, t);
api_incr_top(L);
if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec);
@ -997,7 +1004,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
break;
}
if (mt != NULL) {
sethvalue2s(L, L->top, mt);
sethvalue2s(L, L->top.p, mt);
api_incr_top(L);
res = 1;
}
@ -1024,12 +1031,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected");
if (n <= 0 || n > uvalue(o)->nuvalue) {
setnilvalue(s2v(L->top));
setnilvalue(s2v(L->top.p));
t = LUA_TNONE;
}
else {
setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv);
t = ttype(s2v(L->top));
setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
t = ttype(s2v(L->top.p));
}
api_incr_top(L);
lua_unlock(L);
@ -1049,14 +1056,14 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1));
L->top--; /* pop value */
luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
L->top.p--; /* pop value */
}
else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot);
L->top -= 2; /* pop value and key */
luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
L->top.p -= 2; /* pop value and key */
}
lua_unlock(L); /* lock done by caller */
}
@ -1076,12 +1083,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 2);
t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1));
if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else
luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot);
L->top -= 2; /* pop index and value */
luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
L->top.p -= 2; /* pop index and value */
lua_unlock(L);
}
@ -1108,14 +1115,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1));
luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else {
TValue aux;
setivalue(&aux, n);
luaV_finishset(L, t, &aux, s2v(L->top - 1), slot);
luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
}
L->top--; /* pop value */
L->top.p--; /* pop value */
lua_unlock(L);
}
@ -1125,10 +1132,10 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
lua_lock(L);
api_checknelems(L, n);
t = gettable(L, idx);
luaH_set(L, t, key, s2v(L->top - 1));
luaH_set(L, t, key, s2v(L->top.p - 1));
invalidateTMcache(t);
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
L->top -= n;
luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top.p -= n;
lua_unlock(L);
}
@ -1140,7 +1147,7 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
* metamethods).
*/
LUA_API void lua_rawset (lua_State *L, int idx) {
aux_rawset(L, idx, s2v(L->top - 2), 2);
aux_rawset(L, idx, s2v(L->top.p - 2), 2);
}
@ -1175,9 +1182,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
luaH_setint(L, t, n, s2v(L->top - 1));
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
L->top--;
luaH_setint(L, t, n, s2v(L->top.p - 1));
luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top.p--;
lua_unlock(L);
}
@ -1197,11 +1204,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
lua_lock(L);
api_checknelems(L, 1);
obj = index2value(L, objindex);
if (ttisnil(s2v(L->top - 1)))
if (ttisnil(s2v(L->top.p - 1)))
mt = NULL;
else {
api_check(L, ttistable(s2v(L->top - 1)), "table expected");
mt = hvalue(s2v(L->top - 1));
api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
mt = hvalue(s2v(L->top.p - 1));
}
switch (ttype(obj)) {
case LUA_TTABLE: {
@ -1225,7 +1232,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
break;
}
}
L->top--;
L->top.p--;
lua_unlock(L);
return 1;
}
@ -1248,11 +1255,11 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
else {
setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1));
luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
res = 1;
}
L->top--;
L->top.p--;
lua_unlock(L);
return res;
}
@ -1264,7 +1271,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
#define checkresults(L,na,nr) \
api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
api_check(L, (nr) == LUA_MULTRET \
|| (L->ci->top.p - L->top.p >= (nr) - (na)), \
"results from function overflow current stack size")
@ -1277,7 +1285,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults);
func = L->top - (nargs+1);
func = L->top.p - (nargs+1);
if (k != NULL && yieldable(L)) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */
@ -1325,7 +1333,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
func = savestack(L, o);
}
c.func = L->top - (nargs+1); /* function to be called */
c.func = L->top.p - (nargs+1); /* function to be called */
if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
@ -1360,12 +1368,12 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode);
if (status == LUA_OK) { /* no errors? */
LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */
LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */
if (f->nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */
const TValue *gt = getGtable(L);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
setobj(L, f->upvals[0]->v, gt);
setobj(L, f->upvals[0]->v.p, gt);
luaC_barrier(L, f->upvals[0], gt);
}
}
@ -1379,7 +1387,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
TValue *o;
lua_lock(L);
api_checknelems(L, 1);
o = s2v(L->top - 1);
o = s2v(L->top.p - 1);
if (isLfunction(o))
status = luaU_dump(L, getproto(o), writer, data, strip);
else
@ -1400,18 +1408,19 @@ LUA_API int lua_status (lua_State *L) {
LUA_API int lua_gc (lua_State *L, int what, ...) {
va_list argp;
int res = 0;
global_State *g;
global_State *g = G(L);
if (g->gcstp & GCSTPGC) /* internal stop? */
return -1; /* all options are invalid when stopped */
lua_lock(L);
g = G(L);
va_start(argp, what);
switch (what) {
case LUA_GCSTOP: {
g->gcrunning = 0;
g->gcstp = GCSTPUSR; /* stopped by the user */
break;
}
case LUA_GCRESTART: {
luaE_setdebt(g, 0);
g->gcrunning = 1;
g->gcstp = 0; /* (GCSTPGC must be already zero here) */
break;
}
case LUA_GCCOLLECT: {
@ -1430,8 +1439,8 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
case LUA_GCSTEP: {
int data = va_arg(argp, int);
l_mem debt = 1; /* =1 to signal that it did an actual step */
lu_byte oldrunning = g->gcrunning;
g->gcrunning = 1; /* allow GC to run */
lu_byte oldstp = g->gcstp;
g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */
if (data == 0) {
luaE_setdebt(g, 0); /* do a basic step */
luaC_step(L);
@ -1441,7 +1450,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
luaE_setdebt(g, debt);
luaC_checkGC(L);
}
g->gcrunning = oldrunning; /* restore previous state */
g->gcstp = oldstp; /* restore previous state */
if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */
res = 1; /* signal it */
break;
@ -1459,7 +1468,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
break;
}
case LUA_GCISRUNNING: {
res = g->gcrunning;
res = gcrunning(g);
break;
}
case LUA_GCGEN: {
@ -1511,7 +1520,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
LUA_API int lua_error (lua_State *L) {
TValue *errobj;
lua_lock(L);
errobj = s2v(L->top - 1);
errobj = s2v(L->top.p - 1);
api_checknelems(L, 1);
/* error object is the memory error message? */
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
@ -1519,7 +1528,7 @@ LUA_API int lua_error (lua_State *L) {
else
luaG_errormsg(L); /* raise a regular error */
/* code unreachable; will unlock when control actually leaves the kernel */
__builtin_unreachable();
__builtin_unreachable(); // [jart]
}
@ -1558,12 +1567,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
more = luaH_next(L, t, L->top - 1);
more = luaH_next(L, t, L->top.p - 1);
if (more) {
api_incr_top(L);
}
else /* no more elements */
L->top -= 1; /* remove key */
L->top.p -= 1; /* remove key */
lua_unlock(L);
return more;
}
@ -1596,7 +1605,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
lua_lock(L);
o = index2stack(L, idx);
nresults = L->ci->nresults;
api_check(L, L->tbclist < o, "given index below or equal a marked one");
api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */
@ -1619,7 +1628,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
if (n > 0)
luaV_concat(L, n);
else { /* nothing to concatenate */
setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */
setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */
api_incr_top(L);
}
luaC_checkGC(L);
@ -1638,7 +1647,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
luaV_objlen(L, L->top, t);
luaV_objlen(L, L->top.p, t);
api_incr_top(L);
lua_unlock(L);
}
@ -1725,7 +1734,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
lua_lock(L);
api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
u = luaS_newudata(L, size, nuvalue);
setuvalue(L, s2v(L->top), u);
setuvalue(L, s2v(L->top.p), u);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@ -1733,6 +1742,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
}
static const char *aux_upvalue (TValue *fi, int n, TValue **val,
GCObject **owner) {
switch (ttypetag(fi)) {
@ -1750,7 +1760,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
Proto *p = f->p;
if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
return NULL; /* 'n' not in [1, p->sizeupvalues] */
*val = f->upvals[n-1]->v;
*val = f->upvals[n-1]->v.p;
if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name;
return (name == NULL) ? "(no name)" : getstr(name);
@ -1776,7 +1786,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
lua_lock(L);
name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
if (name) {
setobj2s(L, L->top, val);
setobj2s(L, L->top.p, val);
api_incr_top(L);
}
lua_unlock(L);
@ -1806,8 +1816,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner);
if (name) {
L->top--;
setobj(L, val, s2v(L->top));
L->top.p--;
setobj(L, val, s2v(L->top.p));
luaC_barrier(L, owner, val);
}
lua_unlock(L);

View file

@ -5,22 +5,25 @@
#include "third_party/lua/lstate.h"
/* Increments 'L->top', checking for stack overflows */
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
/* Increments 'L->top.p', checking for stack overflows */
#define api_incr_top(L) {L->top.p++; \
api_check(L, L->top.p <= L->ci->top.p, \
"stack overflow");}
/*
** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro
** increases its stack space ('L->ci->top').
** increases its stack space ('L->ci->top.p').
*/
#define adjustresults(L,nres) \
{ if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
{ if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
L->ci->top.p = L->top.p; }
/* Ensure the stack has at least 'n' elements */
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
#define api_checknelems(L,n) \
api_check(L, (n) < (L->top.p - L->ci->func.p), \
"not enough elements in the stack")

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lauxlib_c
#define LUA_LIB
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/mem/mem.h"
@ -38,34 +39,34 @@ __static_yoink("lua_notice");
/**
* @fileoverview The Auxiliary Library
*
* The auxiliary library provides several convenient functions to interface C
* with Lua. While the basic API provides the primitive functions for all
* interactions between C and Lua, the auxiliary library provides
* higher-level functions for some common tasks.
*
* All functions and types from the auxiliary library are defined in header
* file lauxlib.h and have a prefix luaL_.
*
* All functions in the auxiliary library are built on top of the basic API,
* and so they provide nothing that cannot be done with that API.
* Nevertheless, the use of the auxiliary library ensures more consistency to
* your code.
*
* Several functions in the auxiliary library use internally some extra stack
* slots. When a function in the auxiliary library uses less than five slots,
* it does not check the stack size; it simply assumes that there are enough
* slots.
*
* Several functions in the auxiliary library are used to check C function
* arguments. Because the error message is formatted for arguments (e.g.,
* "bad argument #1"), you should not use these functions for other stack
* values.
*
* Functions called luaL_check* always raise an error if the check is not
* satisfied.
*/
* @fileoverview The Auxiliary Library
*
* The auxiliary library provides several convenient functions to interface C
* with Lua. While the basic API provides the primitive functions for all
* interactions between C and Lua, the auxiliary library provides
* higher-level functions for some common tasks.
*
* All functions and types from the auxiliary library are defined in header
* file lauxlib.h and have a prefix luaL_.
*
* All functions in the auxiliary library are built on top of the basic API,
* and so they provide nothing that cannot be done with that API.
* Nevertheless, the use of the auxiliary library ensures more consistency to
* your code.
*
* Several functions in the auxiliary library use internally some extra stack
* slots. When a function in the auxiliary library uses less than five slots,
* it does not check the stack size; it simply assumes that there are enough
* slots.
*
* Several functions in the auxiliary library are used to check C function
* arguments. Because the error message is formatted for arguments (e.g.,
* "bad argument #1"), you should not use these functions for other stack
* values.
*
* Functions called luaL_check* always raise an error if the check is not
* satisfied.
*/
#if !defined(MAX_SIZET)
@ -191,21 +192,21 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
while (lua_getstack(L1, level++, &ar)) {
if (limit2show-- == 0) { /* too many levels? */
int n = last - level - LEVELS2 + 1; /* number of levels to skip */
lua_pushfstring(L, "\n...(skipping %d levels)", n);
lua_pushfstring(L, "\n\t...\t(skipping %d levels)", n);
luaL_addvalue(&b); /* add warning about skip */
level += n; /* and skip to last levels */
}
else {
lua_getinfo(L1, "Slnt", &ar);
if (ar.currentline <= 0)
lua_pushfstring(L, "\n%s: in ", ar.short_src);
lua_pushfstring(L, "\n\t%s: in ", ar.short_src);
else
lua_pushfstring(L, "\n%s:%d: in ", ar.short_src, ar.currentline);
lua_pushfstring(L, "\n\t%s:%d: in ", ar.short_src, ar.currentline);
luaL_addvalue(&b);
pushfuncname(L, &ar);
luaL_addvalue(&b);
if (ar.istailcall)
luaL_addstring(&b, "\n(...tail calls...)");
luaL_addstring(&b, "\n\t(...tail calls...)");
}
}
luaL_pushresult(&b);
@ -764,13 +765,14 @@ static void newbox (lua_State *L) {
/*
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
** bytes.
** bytes. (The test for "not big enough" also gets the case when the
** computation of 'newsize' overflows.)
*/
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
size_t newsize = B->size * 2; /* double buffer size */
size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
return luaL_error(B->L, "buffer too large");
if (newsize < B->n + sz) /* double is not big enough? */
if (newsize < B->n + sz) /* not big enough? */
newsize = B->n + sz;
return newsize;
}
@ -872,7 +874,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
** box (if existent) is not on the top of the stack. So, instead of
** calling 'luaL_addlstring', it replicates the code using -2 as the
** last argument to 'prepbuffsize', signaling that the box is (or will
** be) bellow the string being added to the buffer. (Box creation can
** be) below the string being added to the buffer. (Box creation can
** trigger an emergency GC, so we should not remove the string from the
** stack before we have the space guaranteed.)
*/
@ -1020,17 +1022,18 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
}
static int skipBOM (LoadF *lf) {
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
int c;
lf->n = 0;
do {
c = getc(lf->f);
if (c == EOF || c != *(const unsigned char *)p++) return c;
lf->buff[lf->n++] = c; /* to be read by the parser */
} while (*p != '\0');
lf->n = 0; /* prefix matched; discard it */
return getc(lf->f); /* return next character */
/*
** Skip an optional BOM at the start of a stream. If there is an
** incomplete BOM (the first character is correct but the rest is
** not), returns the first character anyway to force an error
** (as no chunk can start with 0xEF).
*/
static int skipBOM (FILE *f) {
int c = getc(f); /* read first character */
if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
return getc(f); /* ignore BOM and return next char */
else /* no (valid) BOM */
return c; /* return first character */
}
@ -1041,13 +1044,13 @@ static int skipBOM (LoadF *lf) {
** first "valid" character of the file (after the optional BOM and
** a first-line comment).
*/
static int skipcomment (LoadF *lf, int *cp) {
int c = *cp = skipBOM(lf);
static int skipcomment (FILE *f, int *cp) {
int c = *cp = skipBOM(f);
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
c = getc(lf->f);
c = getc(f);
} while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */
*cp = getc(f); /* next character after comment, if present */
return 1; /* there was a comment */
}
else return 0; /* no comment */
@ -1084,12 +1087,16 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
}
if (skipcomment(&lf, &c)) /* read initial portion */
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
lf.n = 0;
if (skipcomment(lf.f, &c)) /* read initial portion */
lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
if (c == LUA_SIGNATURE[0]) { /* binary file? */
lf.n = 0; /* remove possible newline */
if (filename) { /* "real" file? */
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
skipcomment(&lf, &c); /* re-read initial portion */
skipcomment(lf.f, &c); /* re-read initial portion */
}
}
if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
@ -1236,6 +1243,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
* the result of the call as its result.
*/
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
idx = lua_absindex(L,idx);
if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */
if (!lua_isstring(L, -1))
luaL_error(L, "'__tostring' must return a string");

View file

@ -1,10 +1,12 @@
#ifndef lauxlib_h
#define lauxlib_h
#include "libc/assert.h"
#include "libc/stdio/stdio.h"
#include "third_party/lua/lua.h"
#include "third_party/lua/luaconf.h"
/* global table */
#define LUA_GNAME "_G"
@ -91,7 +93,7 @@ LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s,
LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s,
const char *p, const char *r);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s,
const char *p, const char *r);
@ -146,6 +148,14 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
/*
** Perform arithmetic operations on lua_Integer values with wrap-around
** semantics, as the Lua core does.
*/
#define luaL_intop(op,v1,v2) \
((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2)))
/* push the value used to represent failure/error */
#define luaL_pushfail(L) lua_pushnil(L)
@ -158,6 +168,7 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
#if defined LUAI_ASSERT
#define lua_assert(c) assert(c)
#else
// [jart]
#define lua_assert(c) unassert(c)
#endif

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lbaselib_c
#define LUA_LIB
#include "libc/str/str.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lprefix.h"
@ -196,12 +197,20 @@ static int luaB_rawset (lua_State *L) {
static int pushmode (lua_State *L, int oldmode) {
if (oldmode == -1)
luaL_pushfail(L); /* invalid call to 'lua_gc' */
else
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
: "generational");
return 1;
}
/*
** check whether call to 'lua_gc' was valid (not inside a finalizer)
*/
#define checkvalres(res) { if (res == -1) break; }
static int luaB_collectgarbage (lua_State *L) {
static const char *const opts[] = {"stop", "restart", "collect",
"count", "step", "setpause", "setstepmul",
@ -214,12 +223,14 @@ static int luaB_collectgarbage (lua_State *L) {
case LUA_GCCOUNT: {
int k = lua_gc(L, o);
int b = lua_gc(L, LUA_GCCOUNTB);
checkvalres(k);
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
return 1;
}
case LUA_GCSTEP: {
int step = (int)luaL_optinteger(L, 2, 0);
int res = lua_gc(L, o, step);
checkvalres(res);
lua_pushboolean(L, res);
return 1;
}
@ -227,11 +238,13 @@ static int luaB_collectgarbage (lua_State *L) {
case LUA_GCSETSTEPMUL: {
int p = (int)luaL_optinteger(L, 2, 0);
int previous = lua_gc(L, o, p);
checkvalres(previous);
lua_pushinteger(L, previous);
return 1;
}
case LUA_GCISRUNNING: {
int res = lua_gc(L, o);
checkvalres(res);
lua_pushboolean(L, res);
return 1;
}
@ -248,10 +261,13 @@ static int luaB_collectgarbage (lua_State *L) {
}
default: {
int res = lua_gc(L, o);
checkvalres(res);
lua_pushinteger(L, res);
return 1;
}
}
luaL_pushfail(L); /* invalid call (inside a finalizer) */
return 1;
}
@ -275,6 +291,11 @@ static int luaB_next (lua_State *L) {
}
static int pairscont (lua_State *L, int status, lua_KContext k) {
(void)L; (void)status; (void)k; /* unused */
return 3;
}
static int luaB_pairs (lua_State *L) {
luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
@ -284,7 +305,7 @@ static int luaB_pairs (lua_State *L) {
}
else {
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
lua_call(L, 1, 3); /* get 3 values from metamethod */
lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */
}
return 3;
}
@ -294,7 +315,8 @@ static int luaB_pairs (lua_State *L) {
** Traversal function for 'ipairs'
*/
static int ipairsaux (lua_State *L) {
lua_Integer i = luaL_checkinteger(L, 2) + 1;
lua_Integer i = luaL_checkinteger(L, 2);
i = luaL_intop(+, i, 1);
lua_pushinteger(L, i);
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
}

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lcode_c
#define LUA_CORE
#include "libc/fmt/conv.h"
#include "third_party/lua/lcode.h"
#include "third_party/lua/ldebug.h"
@ -595,24 +596,41 @@ static int stringK (FuncState *fs, TString *s) {
/*
** Add an integer to list of constants and return its index.
** Integers use userdata as keys to avoid collision with floats with
** same value; conversion to 'void*' is used only for hashing, so there
** are no "precision" problems.
*/
static int luaK_intK (FuncState *fs, lua_Integer n) {
TValue k, o;
setpvalue(&k, cast_voidp(cast_sizet(n)));
TValue o;
setivalue(&o, n);
return addk(fs, &k, &o);
return addk(fs, &o, &o); /* use integer itself as key */
}
/*
** Add a float to list of constants and return its index.
** Add a float to list of constants and return its index. Floats
** with integral values need a different key, to avoid collision
** with actual integers. To that, we add to the number its smaller
** power-of-two fraction that is still significant in its scale.
** For doubles, that would be 1/2^52.
** (This method is not bulletproof: there may be another float
** with that value, and for floats larger than 2^53 the result is
** still an integer. At worst, this only wastes an entry with
** a duplicate.)
*/
static int luaK_numberK (FuncState *fs, lua_Number r) {
TValue o;
lua_Integer ik;
setfltvalue(&o, r);
if (!luaV_flttointeger(r, &ik, F2Ieq)) /* not an integral value? */
return addk(fs, &o, &o); /* use number itself as key */
else { /* must build an alternative key */
const int nbm = l_floatatt(MANT_DIG);
const lua_Number q = l_mathop(ldexp)(l_mathop(1.0), -nbm + 1);
const lua_Number k = (ik == 0) ? q : r + r*q; /* new key */
TValue kv;
setfltvalue(&kv, k);
/* result is not an integral value, unless value is too large */
lua_assert(!luaV_flttointeger(k, &ik, F2Ieq) ||
l_mathop(fabs)(r) >= l_mathop(1e6));
return addk(fs, &kv, &o);
}
}
@ -1348,6 +1366,35 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
}
/*
** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) {
lua_assert(baser <= opr &&
((baser == OPR_ADD && opr <= OPR_SHR) ||
(baser == OPR_LT && opr <= OPR_LE)));
return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base));
}
/*
** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode unopr2op (UnOpr opr) {
return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) +
cast_int(OP_UNM));
}
/*
** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM)
*/
l_sinline TMS binopr2TM (BinOpr opr) {
lua_assert(OPR_ADD <= opr && opr <= OPR_SHR);
return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD));
}
/*
** Emit code for unary expressions that "produce values"
** (everything but 'not').
@ -1386,12 +1433,15 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
** Emit code for binary expressions that "produce values" over
** two registers.
*/
static void codebinexpval (FuncState *fs, OpCode op,
static void codebinexpval (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */
OpCode op = binopr2op(opr, OPR_ADD, OP_ADD);
int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */
/* 'e1' must be already in a register or it is a constant */
lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
e1->k == VNONRELOC || e1->k == VRELOC);
lua_assert(OP_ADD <= op && op <= OP_SHR);
finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN,
cast(TMS, (op - OP_ADD) + TM_ADD));
finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr));
}
@ -1407,6 +1457,18 @@ static void codebini (FuncState *fs, OpCode op,
}
/*
** Code binary operators with K operand.
*/
static void codebinK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = binopr2TM(opr);
int v2 = e2->u.info; /* K index */
OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK);
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
}
/* Try to code a binary operator negating its second operand.
** For the metamethod, 2nd operand must keep its original value.
*/
@ -1434,24 +1496,27 @@ static void swapexps (expdesc *e1, expdesc *e2) {
}
/*
** Code binary operators with no constant operand.
*/
static void codebinNoK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
if (flip)
swapexps(e1, e2); /* back to original order */
codebinexpval(fs, opr, e1, e2, line); /* use standard operators */
}
/*
** Code arithmetic operators ('+', '-', ...). If second operand is a
** constant in the proper range, use variant opcodes with K operands.
*/
static void codearith (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = cast(TMS, opr + TM_ADD);
if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */
int v2 = e2->u.info; /* K index */
OpCode op = cast(OpCode, opr + OP_ADDK);
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
}
else { /* 'e2' is neither an immediate nor a K operand */
OpCode op = cast(OpCode, opr + OP_ADD);
if (flip)
swapexps(e1, e2); /* back to original order */
codebinexpval(fs, op, e1, e2, line); /* use standard operators */
}
if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */
codebinK(fs, opr, e1, e2, flip, line);
else /* 'e2' is neither an immediate nor a K operand */
codebinNoK(fs, opr, e1, e2, flip, line);
}
@ -1468,35 +1533,27 @@ static void codecommutative (FuncState *fs, BinOpr op,
flip = 1;
}
if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */
codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD);
codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD);
else
codearith(fs, op, e1, e2, flip, line);
}
/*
** Code bitwise operations; they are all associative, so the function
** Code bitwise operations; they are all commutative, so the function
** tries to put an integer constant as the 2nd operand (a K operand).
*/
static void codebitwise (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
int flip = 0;
int v2;
OpCode op;
if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
if (e1->k == VKINT) {
swapexps(e1, e2); /* 'e2' will be the constant operand */
flip = 1;
}
else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */
op = cast(OpCode, opr + OP_ADD);
codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */
return;
}
v2 = e2->u.info; /* index in K array */
op = cast(OpCode, opr + OP_ADDK);
lua_assert(ttisinteger(&fs->f->k[v2]));
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
cast(TMS, opr + TM_ADD));
if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */
codebinK(fs, opr, e1, e2, flip, line);
else /* no constants */
codebinNoK(fs, opr, e1, e2, flip, line);
}
@ -1504,25 +1561,27 @@ static void codebitwise (FuncState *fs, BinOpr opr,
** Emit code for order comparisons. When using an immediate operand,
** 'isfloat' tells whether the original value was a float.
*/
static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int r1, r2;
int im;
int isfloat = 0;
OpCode op;
if (isSCnumber(e2, &im, &isfloat)) {
/* use immediate operand */
r1 = luaK_exp2anyreg(fs, e1);
r2 = im;
op = cast(OpCode, (op - OP_LT) + OP_LTI);
op = binopr2op(opr, OPR_LT, OP_LTI);
}
else if (isSCnumber(e1, &im, &isfloat)) {
/* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
r1 = luaK_exp2anyreg(fs, e2);
r2 = im;
op = (op == OP_LT) ? OP_GTI : OP_GEI;
op = binopr2op(opr, OPR_LT, OP_GTI);
}
else { /* regular case, compare two registers */
r1 = luaK_exp2anyreg(fs, e1);
r2 = luaK_exp2anyreg(fs, e2);
op = binopr2op(opr, OPR_LT, OP_LT);
}
freeexps(fs, e1, e2);
e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
@ -1548,7 +1607,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
op = OP_EQI;
r2 = im; /* immediate operand */
}
else if (luaK_exp2RK(fs, e2)) { /* 1st expression is constant? */
else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */
op = OP_EQK;
r2 = e2->u.info; /* constant index */
}
@ -1565,16 +1624,16 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
/*
** Apply prefix operation 'op' to expression 'e'.
*/
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) {
static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
luaK_dischargevars(fs, e);
switch (op) {
switch (opr) {
case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
if (constfolding(fs, op + LUA_OPUNM, e, &ef))
if (constfolding(fs, opr + LUA_OPUNM, e, &ef))
break;
/* else */ /* FALLTHROUGH */
case OPR_LEN:
codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
codeunexpval(fs, unopr2op(opr), e, line);
break;
case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0);
@ -1608,7 +1667,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL))
luaK_exp2anyreg(fs, v);
/* else keep numeral, which may be folded with 2nd operand */
/* else keep numeral, which may be folded or used as an immediate
operand */
break;
}
case OPR_EQ: case OPR_NE: {
@ -1703,30 +1763,27 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
/* coded as (r1 >> -I) */;
}
else /* regular case (two registers) */
codebinexpval(fs, OP_SHL, e1, e2, line);
codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_SHR: {
if (isSCint(e2))
codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */
else /* regular case (two registers) */
codebinexpval(fs, OP_SHR, e1, e2, line);
codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_EQ: case OPR_NE: {
codeeq(fs, opr, e1, e2);
break;
}
case OPR_LT: case OPR_LE: {
OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
codeorder(fs, op, e1, e2);
break;
}
case OPR_GT: case OPR_GE: {
/* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */
OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
swapexps(e1, e2);
codeorder(fs, op, e1, e2);
opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT);
} /* FALLTHROUGH */
case OPR_LT: case OPR_LE: {
codeorder(fs, opr, e1, e2);
break;
}
default: lua_assert(0);

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lcorolib_c
#define LUA_LIB
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lprefix.h"
#include "third_party/lua/lua.h"
@ -92,9 +93,9 @@ static int luaB_auxwrap (lua_State *L) {
if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
stat = lua_resetthread(co); /* close its tbc variables */
stat = lua_closethread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* copy error message */
lua_xmove(co, L, 1); /* move error message to the caller */
}
if (stat != LUA_ERRMEM && /* not a memory error and ... */
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
@ -188,14 +189,14 @@ static int luaB_close (lua_State *L) {
int status = auxstatus(L, co);
switch (status) {
case COS_DEAD: case COS_YIELD: {
status = lua_resetthread(co);
status = lua_closethread(co, L);
if (status == LUA_OK) {
lua_pushboolean(L, 1);
return 1;
}
else {
lua_pushboolean(L, 0);
lua_xmove(co, L, 1); /* copy error message */
lua_xmove(co, L, 1); /* move error message */
return 2;
}
}

View file

@ -1,7 +1,9 @@
#ifndef lctype_h
#define lctype_h
#include "third_party/lua/lua.h"
/*
** In ASCII, this 'ltolower' is correct for alphabetic characters and
** for '.'. That is enough for Lua needs. ('check_exp' ensures that
@ -12,6 +14,7 @@
check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')), \
(c) | ('A' ^ 'a'))
// [jart]
#define lisdigit(C) \
({ \
unsigned char c_ = (C); \

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define ldblib_c
#define LUA_LIB
#include "libc/str/str.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lprefix.h"
@ -495,3 +496,4 @@ LUAMOD_API int luaopen_debug (lua_State *L) {
luaL_newlib(L, dblib);
return 1;
}

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define ldebug_c
#define LUA_CORE
#include "libc/str/str.h"
#include "third_party/lua/lapi.h"
#include "third_party/lua/lcode.h"
@ -48,7 +49,7 @@ __static_yoink("lua_notice");
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL)
static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
const char **name);
@ -78,7 +79,7 @@ static int getbaseline (const Proto *f, int pc, int *basepc) {
}
else {
int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */
/* estimate must be a lower bond of the correct base */
/* estimate must be a lower bound of the correct base */
lua_assert(i < 0 ||
(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
@ -196,10 +197,10 @@ static const char *upvalname (const Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
if (clLvalue(s2v(ci->func))->p->is_vararg) {
if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
int nextra = ci->u.l.nextraargs;
if (n >= -nextra) { /* 'n' is negative */
*pos = ci->func - nextra - (n + 1);
*pos = ci->func.p - nextra - (n + 1);
return "(vararg)"; /* generic name for any vararg */
}
}
@ -208,7 +209,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
StkId base = ci->func + 1;
StkId base = ci->func.p + 1;
const char *name = NULL;
if (isLua(ci)) {
if (n < 0) /* access to vararg values? */
@ -217,7 +218,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
}
if (name == NULL) { /* no 'standard' name? */
StkId limit = (ci == L->ci) ? L->top : ci->next->func;
StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
/* generic name for any valid slot */
name = isLua(ci) ? "(temporary)" : "(C temporary)";
@ -235,16 +236,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name;
lua_lock(L);
if (ar == NULL) { /* information about non-active function? */
if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */
if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
name = NULL;
else /* consider live variables at function start (parameters) */
name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0);
name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
}
else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobjs2s(L, L->top, pos);
setobjs2s(L, L->top.p, pos);
api_incr_top(L);
}
}
@ -259,8 +260,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
lua_lock(L);
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobjs2s(L, pos, L->top - 1);
L->top--; /* pop value */
setobjs2s(L, pos, L->top.p - 1);
L->top.p--; /* pop value */
}
lua_unlock(L);
return name;
@ -303,7 +304,7 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) {
setnilvalue(s2v(L->top));
setnilvalue(s2v(L->top.p));
api_incr_top(L);
}
else {
@ -312,10 +313,17 @@ static void collectvalidlines (lua_State *L, Closure *f) {
const Proto *p = f->l.p;
int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */
sethvalue2s(L, L->top, t); /* push it on stack */
sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
for (i = 0; i < p->sizelineinfo; i++) { /* for all instructions */
if (!p->is_vararg) /* regular function? */
i = 0; /* consider all instructions */
else { /* vararg function */
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
currentline = nextline(p, currentline, 0);
i = 1; /* skip first instruction (OP_VARARGPREP) */
}
for (; i < p->sizelineinfo; i++) { /* for each instruction */
currentline = nextline(p, currentline, i); /* get its line */
luaH_setint(L, t, currentline, &v); /* table[line] = true */
}
@ -324,15 +332,9 @@ static void collectvalidlines (lua_State *L, Closure *f) {
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
if (ci == NULL) /* no 'ci'? */
return NULL; /* no info */
else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */
*name = "__gc";
return "metamethod"; /* report it as such */
}
/* calling function is a known Lua function? */
else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
return funcnamefromcode(L, ci->previous, name);
/* calling function is a known function? */
if (ci != NULL && !(ci->callstatus & CIST_TAIL))
return funcnamefromcall(L, ci->previous, name);
else return NULL; /* no way to find a name */
}
@ -401,20 +403,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
lua_lock(L);
if (*what == '>') {
ci = NULL;
func = s2v(L->top - 1);
func = s2v(L->top.p - 1);
api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
L->top--; /* pop function */
L->top.p--; /* pop function */
}
else {
ci = ar->i_ci;
func = s2v(ci->func);
func = s2v(ci->func.p);
lua_assert(ttisfunction(func));
}
cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) {
setobj2s(L, L->top, func);
setobj2s(L, L->top.p, func);
api_incr_top(L);
}
if (strchr(what, 'L'))
@ -604,16 +606,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
** Returns what the name is (e.g., "for iterator", "method",
** "metamethod") and sets '*name' to point to the name.
*/
static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
const char **name) {
static const char *funcnamefromcode (lua_State *L, const Proto *p,
int pc, const char **name) {
TMS tm = (TMS)0; /* (initial value avoids warnings) */
const Proto *p = ci_func(ci)->p; /* calling function */
int pc = currentpc(ci); /* calling instruction index */
Instruction i = p->code[pc]; /* calling instruction */
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
*name = "?";
return "hook";
}
switch (GET_OPCODE(i)) {
case OP_CALL:
case OP_TAILCALL:
@ -650,23 +646,44 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
return "metamethod";
}
/*
** Try to find a name for a function based on how it was called.
*/
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
const char **name) {
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
*name = "?";
return "hook";
}
else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */
*name = "__gc";
return "metamethod"; /* report it as such */
}
else if (isLua(ci))
return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name);
else
return NULL;
}
/* }====================================================== */
/*
** Check whether pointer 'o' points to some value in the stack
** frame of the current function. Because 'o' may not point to a
** value in this stack, we cannot compare it with the region
** boundaries (undefined behaviour in ISO C).
** Check whether pointer 'o' points to some value in the stack frame of
** the current function and, if so, returns its index. Because 'o' may
** not point to a value in this stack, we cannot compare it with the
** region boundaries (undefined behavior in ISO C).
*/
static int isinstack (CallInfo *ci, const TValue *o) {
StkId pos;
for (pos = ci->func + 1; pos < ci->top; pos++) {
if (o == s2v(pos))
return 1;
static int instack (CallInfo *ci, const TValue *o) {
int pos;
StkId base = ci->func.p + 1;
for (pos = 0; base + pos < ci->top.p; pos++) {
if (o == s2v(base + pos))
return pos;
}
return 0; /* not found */
return -1; /* not found */
}
@ -680,7 +697,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
LClosure *c = ci_func(ci);
int i;
for (i = 0; i < c->nupvalues; i++) {
if (c->upvals[i]->v == o) {
if (c->upvals[i]->v.p == o) {
*name = upvalname(c->p, i);
return "upvalue";
}
@ -689,36 +706,64 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
}
static const char *formatvarinfo (lua_State *L, const char *kind,
const char *name) {
if (kind == NULL)
return ""; /* no information */
else
return luaO_pushfstring(L, " (%s '%s')", kind, name);
}
/*
** Build a string with a "description" for the value 'o', such as
** "variable 'x'" or "upvalue 'y'".
*/
static const char *varinfo (lua_State *L, const TValue *o) {
const char *name = NULL; /* to avoid warnings */
CallInfo *ci = L->ci;
const char *name = NULL; /* to avoid warnings */
const char *kind = NULL;
if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
if (!kind && isinstack(ci, o)) /* no? try a register */
kind = getobjname(ci_func(ci)->p, currentpc(ci),
cast_int(cast(StkId, o) - (ci->func + 1)), &name);
if (!kind) { /* not an upvalue? */
int reg = instack(ci, o); /* try a register */
if (reg >= 0) /* is 'o' a register? */
kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
}
}
return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : "";
return formatvarinfo(L, kind, name);
}
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
/*
** Raise a type error
*/
static l_noret typeerror (lua_State *L, const TValue *o, const char *op,
const char *extra) {
const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
luaG_runerror(L, "attempt to %s a %s value%s", op, t, extra);
}
/*
** Raise a type error with "standard" information about the faulty
** object 'o' (using 'varinfo').
*/
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
typeerror(L, o, op, varinfo(L, o));
}
/*
** Raise an error for calling a non-callable object. Try to find a name
** for the object based on how it was called ('funcnamefromcall'); if it
** cannot get a name there, try 'varinfo'.
*/
l_noret luaG_callerror (lua_State *L, const TValue *o) {
CallInfo *ci = L->ci;
const char *name = NULL; /* to avoid warnings */
const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL;
if (what != NULL) {
const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t);
}
else
luaG_typeerror(L, o, "call");
const char *kind = funcnamefromcall(L, ci, &name);
const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o);
typeerror(L, o, "call", extra);
}
@ -780,10 +825,10 @@ l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc);
lua_assert(ttisfunction(s2v(errfunc)));
setobjs2s(L, L->top, L->top - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */
L->top++; /* assume EXTRA_STACK */
luaD_callnoyield(L, L->top - 2, 1); /* call it */
setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
setobjs2s(L, L->top.p - 1, errfunc); /* push function */
L->top.p++; /* assume EXTRA_STACK */
luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
@ -797,8 +842,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);
if (isLua(ci)) /* if Lua function, add source:line information */
if (isLua(ci)) { /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
L->top.p--;
}
luaG_errormsg(L);
}
@ -815,7 +863,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
if (p->lineinfo == NULL) /* no debug information? */
return 0;
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
int delta = 0; /* line diference */
int delta = 0; /* line difference */
int pc = oldpc;
for (;;) {
int lineinfo = p->lineinfo[++pc];
@ -842,7 +890,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** at most causes an extra call to a line hook.)
** This function is not "Protected" when called, so it should correct
** 'L->top' before calling anything that can run the GC.
** 'L->top.p' before calling anything that can run the GC.
*/
int luaG_traceexec (lua_State *L, const Instruction *pc) {
CallInfo *ci = L->ci;
@ -865,7 +913,7 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
return 1; /* do not call hook again (VM yielded, so it did not move) */
}
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
L->top = ci->top; /* correct top */
L->top.p = ci->top.p; /* correct top */
if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
if (mask & LUA_MASKLINE) {

View file

@ -1,15 +1,15 @@
#ifndef ldebug_h
#define ldebug_h
#include "third_party/lua/lstate.h"
#include "third_party/lua/lstate.h"
#define pcRel(pc, p) (cast_int((pc) - (p)->code) - 1)
/* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue(s2v((ci)->func)))
#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define resethookcount(L) (L->hookcount = L->basehookcount)

333
third_party/lua/ldo.c vendored
View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,7 +27,7 @@
*/
#define ldo_c
#define LUA_CORE
#include "third_party/lua/ldo.h"
#include "libc/intrin/weaken.h"
#include "libc/log/log.h"
#include "libc/mem/gc.h"
@ -82,14 +82,14 @@ __static_yoink("lua_notice");
#elif defined(LUA_USE_POSIX) /* }{ */
/* in POSIX, try _longjmp/_setjmp (more efficient) */
#define LUAI_THROW(L,c) gclongjmp((c)->b, 1)
#define LUAI_THROW(L,c) gclongjmp((c)->b, 1) // [jart]
#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
#else /* }{ */
/* ISO C handling with long jumps */
#define LUAI_THROW(L,c) gclongjmp((c)->b, 1)
#define LUAI_THROW(L,c) gclongjmp((c)->b, 1) // [jart]
#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
@ -123,11 +123,11 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
}
default: {
lua_assert(errorstatus(errcode)); /* real error */
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */
break;
}
}
L->top = oldtop + 1;
L->top.p = oldtop + 1;
}
@ -140,7 +140,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
global_State *g = G(L);
errcode = luaE_resetthread(L, errcode); /* close all upvalues */
if (g->mainthread->errorJmp) { /* main thread has a handler? */
setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
}
else { /* no handler at all; abort */
@ -148,7 +148,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
lua_unlock(L);
g->panic(L); /* call panic function (last chance to jump out) */
}
if (_weaken(__die)) _weaken(__die)();
if (_weaken(__die)) _weaken(__die)(); // [jart]
_Exit(41);
}
}
@ -177,16 +177,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
** Stack reallocation
** ===================================================================
*/
static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/*
** Change all pointers to the stack into offsets.
*/
static void relstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
L->top = (L->top - oldstack) + newstack;
L->tbclist = (L->tbclist - oldstack) + newstack;
L->top.offset = savestack(L, L->top.p);
L->tbclist.offset = savestack(L, L->tbclist.p);
for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v = s2v((uplevel(up) - oldstack) + newstack);
up->v.offset = savestack(L, uplevel(up));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top = (ci->top - oldstack) + newstack;
ci->func = (ci->func - oldstack) + newstack;
ci->top.offset = savestack(L, ci->top.p);
ci->func.offset = savestack(L, ci->func.p);
}
}
/*
** Change back all offsets into pointers.
*/
static void correctstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
L->top.p = restorestack(L, L->top.offset);
L->tbclist.p = restorestack(L, L->tbclist.offset);
for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v.p = s2v(restorestack(L, up->v.offset));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top.p = restorestack(L, ci->top.offset);
ci->func.p = restorestack(L, ci->func.offset);
if (isLua(ci))
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
}
@ -196,44 +218,45 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/* some space for error handling */
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
/*
** Reallocate the stack to a new size, correcting all pointers into
** it. (There are pointers to a stack from its upvalues, from its list
** of call infos, plus a few individual pointers.) The reallocation is
** done in two steps (allocation + free) because the correction must be
** done while both addresses (the old stack and the new one) are valid.
** (In ISO C, any pointer use after the pointer has been deallocated is
** undefined behavior.)
** Reallocate the stack to a new size, correcting all pointers into it.
** In ISO C, any pointer use after the pointer has been deallocated is
** undefined behavior. So, before the reallocation, all pointers are
** changed to offsets, and after the reallocation they are changed back
** to pointers. As during the reallocation the pointers are invalid, the
** reallocation cannot run emergency collections.
**
** In case of allocation error, raise an error or return false according
** to 'raiseerror'.
*/
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int oldsize = stacksize(L);
int i;
StkId newstack = luaM_reallocvector(L, NULL, 0,
newsize + EXTRA_STACK, StackValue);
StkId newstack;
int oldgcstop = G(L)->gcstopem;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
relstack(L); /* change pointers to offsets */
G(L)->gcstopem = 1; /* stop emergency collection */
newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
newsize + EXTRA_STACK, StackValue);
G(L)->gcstopem = oldgcstop; /* restore emergency collection */
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
correctstack(L); /* change offsets back to pointers */
if (raiseerror)
luaM_error(L);
else return 0; /* do not raise an error */
}
/* number of elements to be copied to the new stack */
i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
memcpy(newstack, L->stack, i * sizeof(StackValue));
for (; i < newsize + EXTRA_STACK; i++)
L->stack.p = newstack;
correctstack(L); /* change offsets back to pointers */
L->stack_last.p = L->stack.p + newsize;
for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */
correctstack(L, L->stack, newstack);
luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
L->stack = newstack;
L->stack_last = L->stack + newsize;
return 1;
}
/*
** Try to grow the stack by at least 'n' elements. when 'raiseerror'
** Try to grow the stack by at least 'n' elements. When 'raiseerror'
** is true, raises any error; otherwise, return 0 in case of errors.
*/
int luaD_growstack (lua_State *L, int n, int raiseerror) {
@ -247,35 +270,38 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
luaD_throw(L, LUA_ERRERR); /* error inside message handler */
return 0; /* if not 'raiseerror', just signal it */
}
else {
else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */
int newsize = 2 * size; /* tentative new size */
int needed = cast_int(L->top - L->stack) + n;
int needed = cast_int(L->top.p - L->stack.p) + n;
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
newsize = LUAI_MAXSTACK;
if (newsize < needed) /* but must respect what was asked for */
newsize = needed;
if (l_likely(newsize <= LUAI_MAXSTACK))
return luaD_reallocstack(L, newsize, raiseerror);
else { /* stack overflow */
}
/* else stack overflow */
/* add extra size to be able to handle the error message */
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
if (raiseerror)
luaG_runerror(L, "stack overflow");
return 0;
}
}
}
/*
** Compute how much of the stack is being used, by computing the
** maximum top of all call frames in the stack and the current top.
*/
static int stackinuse (lua_State *L) {
CallInfo *ci;
int res;
StkId lim = L->top;
StkId lim = L->top.p;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
if (lim < ci->top) lim = ci->top;
if (lim < ci->top.p) lim = ci->top.p;
}
lua_assert(lim <= L->stack_last);
res = cast_int(lim - L->stack) + 1; /* part of stack in use */
lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */
if (res < LUA_MINSTACK)
res = LUA_MINSTACK; /* ensure a minimum size */
return res;
@ -293,17 +319,13 @@ static int stackinuse (lua_State *L) {
*/
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
int nsize = inuse * 2; /* proposed new size */
int max = inuse * 3; /* maximum "reasonable" size */
if (max > LUAI_MAXSTACK) {
max = LUAI_MAXSTACK; /* respect stack limit */
if (nsize > LUAI_MAXSTACK)
nsize = LUAI_MAXSTACK;
}
int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
/* if thread is currently not handling a stack overflow and its
size is larger than maximum "reasonable" size, shrink it */
if (inuse <= LUAI_MAXSTACK && stacksize(L) > max)
if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
luaD_reallocstack(L, nsize, 0); /* ok if that fails */
}
else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */
luaE_shrinkCI(L); /* shrink CI list */
@ -312,7 +334,7 @@ void luaD_shrinkstack (lua_State *L) {
void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1);
L->top++;
L->top.p++;
}
/* }================================================================== */
@ -329,8 +351,8 @@ void luaD_hook (lua_State *L, int event, int line,
if (hook && L->allowhook) { /* make sure there is a hook */
int mask = CIST_HOOKED;
CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */
ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */
ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */
ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */
lua_Debug ar;
ar.event = event;
ar.currentline = line;
@ -340,11 +362,11 @@ void luaD_hook (lua_State *L, int event, int line,
ci->u2.transferinfo.ftransfer = ftransfer;
ci->u2.transferinfo.ntransfer = ntransfer;
}
if (isLua(ci) && L->top < ci->top)
L->top = ci->top; /* protect entire activation register */
if (isLua(ci) && L->top.p < ci->top.p)
L->top.p = ci->top.p; /* protect entire activation register */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
if (ci->top < L->top + LUA_MINSTACK)
ci->top = L->top + LUA_MINSTACK;
if (ci->top.p < L->top.p + LUA_MINSTACK)
ci->top.p = L->top.p + LUA_MINSTACK;
L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= mask;
lua_unlock(L);
@ -352,8 +374,8 @@ void luaD_hook (lua_State *L, int event, int line,
lua_lock(L);
lua_assert(!L->allowhook);
L->allowhook = 1;
ci->top = restorestack(L, ci_top);
L->top = restorestack(L, top);
ci->top.p = restorestack(L, ci_top);
L->top.p = restorestack(L, top);
ci->callstatus &= ~mask;
}
}
@ -384,7 +406,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
*/
static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
StkId firstres = L->top - nres; /* index of first result */
StkId firstres = L->top.p - nres; /* index of first result */
int delta = 0; /* correction for vararg functions */
int ftransfer;
if (isLua(ci)) {
@ -392,10 +414,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (p->is_vararg)
delta = ci->u.l.nextraargs + p->numparams + 1;
}
ci->func += delta; /* if vararg, back to virtual 'func' */
ftransfer = cast(unsigned short, firstres - ci->func);
ci->func.p += delta; /* if vararg, back to virtual 'func' */
ftransfer = cast(unsigned short, firstres - ci->func.p);
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
ci->func -= delta;
ci->func.p -= delta;
}
if (isLua(ci = ci->previous))
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
@ -407,15 +429,18 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
** stack, below original 'func', so that 'luaD_precall' can call it. Raise
** an error if there is no '__call' metafield.
*/
void luaD_tryfuncTM (lua_State *L, StkId func) {
const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL);
StkId luaD_tryfuncTM (lua_State *L, StkId func) {
const TValue *tm;
StkId p;
checkstackGCp(L, 1, func); /* space for metamethod */
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */
for (p = L->top; p > func; p--) /* open space for metamethod */
for (p = L->top.p; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1);
L->top++; /* stack space pre-allocated by the caller */
L->top.p++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */
return func;
}
@ -425,33 +450,34 @@ void luaD_tryfuncTM (lua_State *L, StkId func) {
** expressions, multiple results for tail calls/single parameters)
** separated.
*/
static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
StkId firstresult;
int i;
switch (wanted) { /* handle typical cases separately */
case 0: /* no values needed */
L->top = res;
L->top.p = res;
return;
case 1: /* one value needed */
if (nres == 0) /* no results? */
setnilvalue(s2v(res)); /* adjust with nil */
else /* at least one result */
setobjs2s(L, res, L->top - nres); /* move it to proper place */
L->top = res + 1;
setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
L->top.p = res + 1;
return;
case LUA_MULTRET:
wanted = nres; /* we want all results */
break;
default: /* two/more results and/or to-be-closed variables */
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
ptrdiff_t savedres = savestack(L, res);
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
L->ci->u2.nres = nres;
luaF_close(L, res, CLOSEKTOP, 1);
res = luaF_close(L, res, CLOSEKTOP, 1);
L->ci->callstatus &= ~CIST_CLSRET;
if (L->hookmask) /* if needed, call hook after '__close's */
if (L->hookmask) { /* if needed, call hook after '__close's */
ptrdiff_t savedres = savestack(L, res);
rethook(L, L->ci, nres);
res = restorestack(L, savedres); /* close and hook can move stack */
res = restorestack(L, savedres); /* hook can move stack */
}
wanted = decodeNresults(wanted);
if (wanted == LUA_MULTRET)
wanted = nres; /* we want all results */
@ -459,14 +485,14 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
break;
}
/* generic case */
firstresult = L->top - nres; /* index of first result */
firstresult = L->top.p - nres; /* index of first result */
if (nres > wanted) /* extra results? */
nres = wanted; /* don't need them */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstresult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(s2v(res + i));
L->top = res + wanted; /* top points after the last result */
L->top.p = res + wanted; /* top points after the last result */
}
@ -481,7 +507,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
rethook(L, ci, nres);
/* move results to proper place */
moveresults(L, ci->func, nres, wanted);
moveresults(L, ci->func.p, nres, wanted);
/* function cannot be in any of these cases when returning */
lua_assert(!(ci->callstatus &
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
@ -493,27 +519,81 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L))
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
int mask, StkId top) {
CallInfo *ci = L->ci = next_ci(L); /* new frame */
ci->func.p = func;
ci->nresults = nret;
ci->callstatus = mask;
ci->top.p = top;
return ci;
}
/*
** precall for C functions
*/
l_sinline int precallC (lua_State *L, StkId func, int nresults,
lua_CFunction f) {
int n; /* number of returns */
CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
L->top.p + LUA_MINSTACK);
lua_assert(ci->top.p <= L->stack_last.p);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
int narg = cast_int(L->top.p - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
}
lua_unlock(L);
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
luaD_poscall(L, ci, n);
return n;
}
/*
** Prepare a function for a tail call, building its call info on top
** of the current call info. 'narg1' is the number of arguments plus 1
** (so that it includes the function itself).
** (so that it includes the function itself). Return the number of
** results, if it was a C function, or -1 for a Lua function.
*/
void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int narg1, int delta) {
retry:
switch (ttypetag(s2v(func))) {
case LUA_VCCL: /* C closure */
return precallC(L, func, LUA_MULTRET, clCvalue(s2v(func))->f);
case LUA_VLCF: /* light C function */
return precallC(L, func, LUA_MULTRET, fvalue(s2v(func)));
case LUA_VLCL: { /* Lua function */
Proto *p = clLvalue(s2v(func))->p;
int fsize = p->maxstacksize; /* frame size */
int nfixparams = p->numparams;
int i;
checkstackGCp(L, fsize - delta, func);
ci->func.p -= delta; /* restore 'func' (if vararg) */
for (i = 0; i < narg1; i++) /* move down function and arguments */
setobjs2s(L, ci->func + i, func + i);
checkstackGC(L, fsize);
func = ci->func; /* moved-down function */
setobjs2s(L, ci->func.p + i, func + i);
func = ci->func.p; /* moved-down function */
for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
ci->top = func + 1 + fsize; /* top for new function */
lua_assert(ci->top <= L->stack_last);
ci->top.p = func + 1 + fsize; /* top for new function */
lua_assert(ci->top.p <= L->stack_last.p);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL;
L->top = func + narg1; /* set top */
L->top.p = func + narg1; /* set top */
return -1;
}
default: { /* not a function */
func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
/* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */
narg1++;
goto retry; /* try again */
}
}
}
@ -526,56 +606,31 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
** original function position.
*/
CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
lua_CFunction f;
retry:
switch (ttypetag(s2v(func))) {
case LUA_VCCL: /* C closure */
f = clCvalue(s2v(func))->f;
goto Cfunc;
case LUA_VLCF: /* light C function */
f = fvalue(s2v(func));
Cfunc: {
int n; /* number of returns */
CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = next_ci(L);
ci->nresults = nresults;
ci->callstatus = CIST_C;
ci->top = L->top + LUA_MINSTACK;
ci->func = func;
lua_assert(ci->top <= L->stack_last);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
int narg = cast_int(L->top - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
}
lua_unlock(L);
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
luaD_poscall(L, ci, n);
precallC(L, func, nresults, clCvalue(s2v(func))->f);
return NULL;
case LUA_VLCF: /* light C function */
precallC(L, func, nresults, fvalue(s2v(func)));
return NULL;
}
case LUA_VLCL: { /* Lua function */
CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p;
int narg = cast_int(L->top - func) - 1; /* number of real arguments */
int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */
int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func);
L->ci = ci = next_ci(L);
ci->nresults = nresults;
L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */
ci->top = func + 1 + fsize;
ci->func = func;
L->ci = ci;
for (; narg < nfixparams; narg++)
setnilvalue(s2v(L->top++)); /* complete missing arguments */
lua_assert(ci->top <= L->stack_last);
setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
lua_assert(ci->top.p <= L->stack_last.p);
return ci;
}
default: { /* not a function */
checkstackGCp(L, 1, func); /* space for metamethod */
luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
/* return luaD_precall(L, func, nresults); */
goto retry; /* try again with metamethod */
}
}
@ -586,12 +641,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** Call a function (C or Lua) through C. 'inc' can be 1 (increment
** number of recursive invocations in the C stack) or nyci (the same
** plus increment number of non-yieldable calls).
** This function can be called with some use of EXTRA_STACK, so it should
** check the stack before doing anything else. 'luaD_precall' already
** does that.
*/
static void ccall (lua_State *L, StkId func, int nResults, int inc) {
l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) {
CallInfo *ci;
L->nCcalls += inc;
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
luaE_checkcstack(L);
}
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
luaV_execute(L, ci); /* call it */
@ -639,8 +699,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
else { /* error */
StkId func = restorestack(L, ci->u2.funcidx);
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
luaF_close(L, func, status, 1); /* can yield or raise an error */
func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
func = luaF_close(L, func, status, 1); /* can yield or raise an error */
luaD_seterrorobj(L, status, func);
luaD_shrinkstack(L); /* restore stack size in case of overflow */
setcistrecst(ci, LUA_OK); /* clear original status */
@ -728,8 +787,8 @@ static CallInfo *findpcall (lua_State *L) {
** coroutine error handler and should not kill the coroutine.)
*/
static int resume_error (lua_State *L, const char *msg, int narg) {
L->top -= narg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
L->top.p -= narg; /* remove args from the stack */
setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */
api_incr_top(L);
lua_unlock(L);
return LUA_ERRRUN;
@ -745,16 +804,15 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
*/
static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */
StkId firstArg = L->top - n; /* first argument */
StkId firstArg = L->top.p - n; /* first argument */
CallInfo *ci = L->ci;
if (L->status == LUA_OK) /* starting a coroutine? */
ccall(L, firstArg - 1, LUA_MULTRET, 1); /* just call its body */
ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
else { /* resuming from previous yield */
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
luaE_incCstack(L); /* control the C stack */
if (isLua(ci)) { /* yielded inside a hook? */
L->top = firstArg; /* discard arguments */
L->top.p = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */
}
else { /* 'common' yield */
@ -797,12 +855,15 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs);
else if (L->top - (L->ci->func + 1) == nargs) /* no function? */
else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */
return resume_error(L, "cannot resume dead coroutine", nargs);
}
else if (L->status != LUA_YIELD) /* ended with errors? */
return resume_error(L, "cannot resume dead coroutine", nargs);
L->nCcalls = (from) ? getCcalls(from) : 0;
if (getCcalls(L) >= LUAI_MAXCCALLS)
return resume_error(L, "C stack overflow", nargs);
L->nCcalls++;
luai_userstateresume(L, nargs);
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, &nargs);
@ -812,11 +873,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */
luaD_seterrorobj(L, status, L->top); /* push error message */
L->ci->top = L->top;
luaD_seterrorobj(L, status, L->top.p); /* push error message */
L->ci->top.p = L->top.p;
}
*nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
: cast_int(L->top - (L->ci->func + 1));
: cast_int(L->top.p - (L->ci->func.p + 1));
lua_unlock(L);
return status;
}
@ -971,7 +1032,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff);
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);

18
third_party/lua/ldo.h vendored
View file

@ -16,7 +16,7 @@
** at every check.
*/
#define luaD_checkstackaux(L,n,pre,pos) \
if (l_unlikely(L->stack_last - L->top <= (n))) \
if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
{ pre; luaD_growstack(L, n, 1); pos; } \
else { condmovestack(L,pre,pos); }
@ -25,11 +25,18 @@
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
#define restorestack(L,n) ((StkId)((char *)L->stack + (n)))
#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
/* macro to check stack size, preserving 'p' */
#define checkstackp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
@ -51,11 +58,12 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n);
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func);
LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func);
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef);

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define ldump_c
#define LUA_CORE
#include "third_party/lua/lobject.h"
#include "third_party/lua/lprefix.h"
#include "third_party/lua/lstate.h"
@ -71,8 +72,11 @@ static void dumpByte (DumpState *D, int y) {
}
/* dumpInt Buff Size */
#define DIBS ((sizeof(size_t) * 8 / 7) + 1)
/*
** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
** rounds up the division.)
*/
#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7)
static void dumpSize (DumpState *D, size_t x) {
lu_byte buff[DIBS];

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lfunc_c
#define LUA_CORE
#include "third_party/lua/ldebug.h"
#include "third_party/lua/ldo.h"
#include "third_party/lua/lfunc.h"
@ -66,8 +67,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
for (i = 0; i < cl->nupvalues; i++) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
uv->v = &uv->u.value; /* make it closed */
setnilvalue(uv->v);
uv->v.p = &uv->u.value; /* make it closed */
setnilvalue(uv->v.p);
cl->upvals[i] = uv;
luaC_objbarrier(L, cl, uv);
}
@ -78,12 +79,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
** Create a new upvalue at the given level, and link it to the list of
** open upvalues of 'L' after entry 'prev'.
**/
static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
UpVal *next = *prev;
uv->v = s2v(level); /* current value lives in the stack */
uv->tbc = tbc;
uv->v.p = s2v(level); /* current value lives in the stack */
uv->u.open.next = next; /* link it to list of open upvalues */
uv->u.open.previous = prev;
if (next)
@ -112,7 +112,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
pp = &p->u.open.next;
}
/* not found: create a new upvalue after 'pp' */
return newupval(L, 0, level, pp);
return newupval(L, level, pp);
}
@ -122,12 +122,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
** (This function assumes EXTRA_STACK.)
*/
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
StkId top = L->top;
StkId top = L->top.p;
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
L->top = top + 3; /* add function and arguments */
L->top.p = top + 3; /* add function and arguments */
if (yy)
luaD_call(L, top, 0);
else
@ -142,7 +142,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
static void checkclosemth (lua_State *L, StkId level) {
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
if (ttisnil(tm)) { /* no metamethod? */
int idx = cast_int(level - L->ci->func); /* variable index */
int idx = cast_int(level - L->ci->func.p); /* variable index */
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
if (vname == NULL) vname = "?";
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
@ -176,23 +176,23 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
** is used.)
*/
#define MAXDELTA \
((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
/*
** Insert a variable in the list of to-be-closed variables.
*/
void luaF_newtbcupval (lua_State *L, StkId level) {
lua_assert(level > L->tbclist);
lua_assert(level > L->tbclist.p);
if (l_isfalse(s2v(level)))
return; /* false doesn't need to be closed */
checkclosemth(L, level); /* value must have a close method */
while (cast_uint(level - L->tbclist) > MAXDELTA) {
L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
L->tbclist->tbclist.delta = 0;
while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
L->tbclist.p->tbclist.delta = 0;
}
level->tbclist.delta = cast(unsigned short, level - L->tbclist);
L->tbclist = level;
level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
L->tbclist.p = level;
}
@ -212,10 +212,10 @@ void luaF_closeupval (lua_State *L, StkId level) {
StkId upl; /* stack index pointed by 'uv' */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
TValue *slot = &uv->u.value; /* new position for value */
lua_assert(uplevel(uv) < L->top);
lua_assert(uplevel(uv) < L->top.p);
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
setobj(L, slot, uv->v); /* move value to upvalue slot */
uv->v = slot; /* now current value lives here */
setobj(L, slot, uv->v.p); /* move value to upvalue slot */
uv->v.p = slot; /* now current value lives here */
if (!iswhite(uv)) { /* neither white nor dead? */
nw2black(uv); /* closed upvalues cannot be gray */
luaC_barrier(L, uv, slot);
@ -225,31 +225,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
/*
** Remove firt element from the tbclist plus its dummy nodes.
** Remove first element from the tbclist plus its dummy nodes.
*/
static void poptbclist (lua_State *L) {
StkId tbc = L->tbclist;
StkId tbc = L->tbclist.p;
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
tbc -= tbc->tbclist.delta;
while (tbc > L->stack && tbc->tbclist.delta == 0)
while (tbc > L->stack.p && tbc->tbclist.delta == 0)
tbc -= MAXDELTA; /* remove dummy nodes */
L->tbclist = tbc;
L->tbclist.p = tbc;
}
/*
** Close all upvalues and to-be-closed variables up to the given stack
** level.
** level. Return restored 'level'.
*/
void luaF_close (lua_State *L, StkId level, int status, int yy) {
StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
ptrdiff_t levelrel = savestack(L, level);
luaF_closeupval(L, level); /* first, close the upvalues */
while (L->tbclist >= level) { /* traverse tbc's down to that level */
StkId tbc = L->tbclist; /* get variable index */
while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
StkId tbc = L->tbclist.p; /* get variable index */
poptbclist(L); /* remove it from list */
prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel);
}
return level;
}

View file

@ -22,10 +22,10 @@
#define MAXUPVAL 255
#define upisopen(up) ((up)->v != &(up)->u.value)
#define upisopen(up) ((up)->v.p != &(up)->u.value)
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v))
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
/*
@ -47,7 +47,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,

124
third_party/lua/lgc.c vendored
View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lgc_c
#define LUA_CORE
#include "libc/str/str.h"
#include "third_party/lua/ldebug.h"
#include "third_party/lua/ldo.h"
@ -268,12 +269,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
/*
** create a new collectable object (with given type and size) and link
** it to 'allgc' list.
** create a new collectable object (with given type, size, and offset)
** and link it to 'allgc' list.
*/
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
global_State *g = G(L);
GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
GCObject *o = cast(GCObject *, p + offset);
o->marked = luaC_white(g);
o->tt = tt;
o->next = g->allgc;
@ -281,6 +283,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return o;
}
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return luaC_newobjdt(L, tt, sz, 0);
}
/* }====================================================== */
@ -317,7 +324,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
set2gray(uv); /* open upvalues are kept gray */
else
set2black(uv); /* closed upvalues are visited here */
markvalue(g, uv->v); /* mark its content */
markvalue(g, uv->v.p); /* mark its content */
break;
}
case LUA_VUSERDATA: {
@ -392,7 +399,7 @@ static int remarkupvals (global_State *g) {
work++;
if (!iswhite(uv)) { /* upvalue already visited? */
lua_assert(upisopen(uv) && isgray(uv));
markvalue(g, uv->v); /* mark its value */
markvalue(g, uv->v.p); /* mark its value */
}
}
}
@ -636,19 +643,19 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
*/
static int traversethread (global_State *g, lua_State *th) {
UpVal *uv;
StkId o = th->stack;
StkId o = th->stack.p;
if (isold(th) || g->gcstate == GCSpropagate)
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
if (o == NULL)
return 1; /* stack not completely built yet */
lua_assert(g->gcstate == GCSatomic ||
th->openupval == NULL || isintwups(th));
for (; o < th->top; o++) /* mark live elements in the stack */
for (; o < th->top.p; o++) /* mark live elements in the stack */
markvalue(g, s2v(o));
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markobject(g, uv); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */
for (; o < th->stack_last + EXTRA_STACK; o++)
for (; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
@ -908,7 +915,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) {
UNUSED(ud);
luaD_callnoyield(L, L->top - 2, 0);
luaD_callnoyield(L, L->top.p - 2, 0);
}
@ -922,19 +929,19 @@ static void GCTM (lua_State *L) {
if (!notm(tm)) { /* is there a finalizer? */
int status;
lu_byte oldah = L->allowhook;
int running = g->gcrunning;
int oldgcstp = g->gcstp;
g->gcstp |= GCSTPGC; /* avoid GC steps */
L->allowhook = 0; /* stop debug hooks during GC metamethod */
g->gcrunning = 0; /* avoid GC steps */
setobj2s(L, L->top++, tm); /* push finalizer... */
setobj2s(L, L->top++, &v); /* ... and its argument */
setobj2s(L, L->top.p++, tm); /* push finalizer... */
setobj2s(L, L->top.p++, &v); /* ... and its argument */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */
g->gcrunning = running; /* restore state */
g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc metamethod");
L->top--; /* pops error object */
luaE_warnerror(L, "__gc");
L->top.p--; /* pops error object */
}
}
}
@ -1027,7 +1034,8 @@ static void correctpointers (global_State *g, GCObject *o) {
void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
global_State *g = G(L);
if (tofinalize(o) || /* obj. is already marked... */
gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */
gfasttm(g, mt, TM_GC) == NULL || /* or has no finalizer... */
(g->gcstp & GCSTPCLS)) /* or closing state? */
return; /* nothing to be done */
else { /* move 'o' to 'finobj' list */
GCObject **p;
@ -1056,7 +1064,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** =======================================================
*/
static void setpause (global_State *g);
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/*
@ -1300,6 +1326,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
}
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/*
** Enter generational mode. Must go until the end of an atomic cycle
** to ensure that all objects are correctly marked and weak tables
@ -1312,6 +1347,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
numobjs = atomic(L); /* propagates all and then do the atomic stuff */
atomic2gen(L, g);
setminordebt(g); /* set debt assuming next cycle will be minor */
return numobjs;
}
@ -1357,15 +1393,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
}
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/*
** Does a major collection after last collection was a "bad collection".
**
@ -1437,8 +1464,8 @@ static void genstep (lua_State *L, global_State *g) {
lu_mem numobjs = fullgen(L, g); /* do a major collection */
if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
/* collected at least half of memory growth since last major
collection; keep doing minor collections */
setminordebt(g);
collection; keep doing minor collections. */
lua_assert(g->lastatomic == 0);
}
else { /* bad collection */
g->lastatomic = numobjs; /* signal that last collection was bad */
@ -1464,26 +1491,6 @@ static void genstep (lua_State *L, global_State *g) {
*/
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/*
** Enter first sweep phase.
** The call to 'sweeptolive' makes the pointer point to an object
@ -1518,12 +1525,13 @@ static void deletelist (lua_State *L, GCObject *p, GCObject *limit) {
*/
void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L);
g->gcstp = GCSTPCLS; /* no extra finalizers after here */
luaC_changemode(L, KGC_INC);
separatetobefnz(g, 1); /* separate all objects with finalizers */
lua_assert(g->finobj == NULL);
callallpendingfinalizers(L);
deletelist(L, g->allgc, obj2gco(g->mainthread));
deletelist(L, g->finobj, NULL);
lua_assert(g->finobj == NULL); /* no new finalizers */
deletelist(L, g->fixedgc, NULL); /* collect fixed objects */
lua_assert(g->strt.nuse == 0);
}
@ -1663,6 +1671,7 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
}
/*
** Performs a basic incremental step. The debt and step size are
** converted from bytes to "units of work"; then the function loops
@ -1689,12 +1698,15 @@ static void incstep (lua_State *L, global_State *g) {
}
/*
** performs a basic GC step if collector is running
** Performs a basic GC step if collector is running. (If collector is
** not running, set a reasonable debt to avoid it being called at
** every single check.)
*/
void luaC_step (lua_State *L) {
global_State *g = G(L);
lua_assert(!g->gcemergency);
if (g->gcrunning) { /* running? */
if (!gcrunning(g)) /* not running? */
luaE_setdebt(g, -2000);
else {
if(isdecGCmodegen(g))
genstep(L, g);
else

29
third_party/lua/lgc.h vendored
View file

@ -142,6 +142,16 @@
*/
#define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0)
/*
** Control when GC is running:
*/
#define GCSTPUSR 1 /* bit true when GC stopped by user */
#define GCSTPGC 2 /* bit true when GC stopped by itself */
#define GCSTPCLS 4 /* bit true when closing Lua state */
#define gcrunning(g) ((g)->gcstp == 0)
/*
** Does one step of collection when debt becomes positive. 'pre'/'pos'
** allows some adjustments to be done only when needed. macro
@ -156,24 +166,27 @@
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_barrier(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrierback_(L,p) : cast_void(0))
#define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_barrier(L,p,v) ( \
iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
#define luaC_objbarrierback(L,p,o) ( \
(isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
size_t offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define linit_c
#define LUA_LIB
/*
** If you embed Lua in your program and need to open the standard
** libraries, call luaL_openlibs in your program. If you need a
@ -42,6 +43,7 @@
** lua_setfield(L, -2, modname);
** lua_pop(L, 1); // remove PRELOAD table
*/
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lprefix.h"
#include "third_party/lua/lua.h"

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define liolib_c
#define LUA_LIB
#include "libc/calls/calls.h"
#include "libc/calls/weirdtypes.h"
#include "libc/errno.h"

View file

@ -1,9 +1,3 @@
/*
** $Id: ljumptab.h $
** Jump Table for the Lua interpreter
** See Copyright Notice in lua.h
*/
#undef vmdispatch
#undef vmcase
#undef vmbreak

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define llex_c
#define LUA_CORE
#include "third_party/lua/llex.h"
#include "third_party/lua/lctype.h"
#include "third_party/lua/ldebug.h"
@ -142,7 +143,7 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
** ensuring there is only one copy of each unique string. The table
** here is used as a set: the string enters as the key, while its value
** is irrelevant. We use the string itself as the value only because it
** is a TValue readly available. Later, the code generation can change
** is a TValue readily available. Later, the code generation can change
** this value.
*/
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
@ -152,12 +153,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
if (!ttisnil(o)) /* string already present? */
ts = keystrval(nodefromval(o)); /* get saved copy */
else { /* not in use yet */
TValue *stv = s2v(L->top++); /* reserve stack space for string */
TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
setsvalue(L, stv, ts); /* temporarily anchor the string */
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
/* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L);
L->top--; /* remove string from stack */
L->top.p--; /* remove string from stack */
}
return ts;
}
@ -408,9 +409,9 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) {
int c; /* final character to be saved */
save_and_next(ls); /* keep '\\' for error messages */
switch (ls->current) {
case 'e': c = '\e'; goto read_save;
case 'a': c = '\a'; goto read_save;
case 'b': c = '\b'; goto read_save;
case 'e': c = '\e'; goto read_save; // [jart]
case 'f': c = '\f'; goto read_save;
case 'n': c = '\n'; goto read_save;
case 'r': c = '\r'; goto read_save;

View file

@ -1,9 +1,3 @@
/*
** $Id: llex.h $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
#ifndef llex_h
#define llex_h

View file

@ -62,11 +62,24 @@ typedef signed char ls_byte;
/*
** conversion of pointer to unsigned integer:
** this is for hashing only; there is no problem if the integer
** cannot hold the whole pointer value
** conversion of pointer to unsigned integer: this is for hashing only;
** there is no problem if the integer cannot hold the whole pointer
** value. (In strict ISO C this may cause undefined behavior, but no
** actual machine seems to bother.)
*/
#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 199901L
#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
#define L_P2I uintptr_t
#else /* no 'intptr'? */
#define L_P2I uintmax_t /* use the largest available integer */
#endif
#else /* C89 option */
#define L_P2I size_t
#endif
#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX))
@ -155,6 +168,20 @@ typedef LUAI_UACINT l_uacInt;
#endif
/*
** Inline functions
*/
#if !defined(LUA_USE_C89)
#define l_inline inline
#elif defined(__GNUC__)
#define l_inline __inline__
#else
#define l_inline /* empty */
#endif
#define l_sinline static l_inline
/*
** type for virtual-machine instructions;
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
@ -337,7 +364,7 @@ typedef l_uint32 Instruction;
#define condchangemem(L,pre,pos) ((void)0)
#else
#define condchangemem(L,pre,pos) \
{ if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } }
{ if (gcrunning(G(L))) { pre; luaC_fullgc(L, 0); pos; } }
#endif
#endif

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lmathlib_c
#define LUA_LIB
#include "libc/calls/calls.h"
#include "libc/math.h"
#include "libc/nt/struct/msg.h"
@ -282,7 +283,7 @@ static int math_type (lua_State *L) {
/* try to find an integer type with at least 64 bits */
#if (ULONG_MAX >> 31 >> 31) >= 3
#if ((ULONG_MAX >> 31) >> 31) >= 3
/* 'long' has at least 64 bits */
#define Rand64 unsigned long
@ -292,9 +293,9 @@ static int math_type (lua_State *L) {
/* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long
#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3
#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
/* 'lua_Integer' has at least 64 bits */
/* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned
#endif
@ -490,7 +491,7 @@ static lua_Number I2d (Rand64 x) {
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
#define scaleFIG \
((lua_Number)1.0 / (UONE << 30) / 8.0 / (UONE << (FIGS - 33)))
(l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
/*
** use FIGS - 32 bits from lower half, throwing out the other
@ -501,7 +502,7 @@ static lua_Number I2d (Rand64 x) {
/*
** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32)
*/
#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * 2.0)
#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * l_mathop(2.0))
static lua_Number I2d (Rand64 x) {
@ -515,12 +516,12 @@ static lua_Number I2d (Rand64 x) {
/* convert a 'Rand64' to a 'lua_Unsigned' */
static lua_Unsigned I2UInt (Rand64 x) {
return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l);
return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
}
/* convert a 'lua_Unsigned' to a 'Rand64' */
static Rand64 Int2I (lua_Unsigned n) {
return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n);
return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
}
#endif /* } */

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lmem_c
#define LUA_CORE
#include "libc/log/log.h"
#include "third_party/lua/ldebug.h"
#include "third_party/lua/ldo.h"
@ -39,26 +40,6 @@
__static_yoink("lua_notice");
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail whenever not building initial state.
** (This fail will trigger 'tryagain' and a full GC cycle at every
** allocation.)
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (completestate(g) && ns > 0) /* frees never fail */
return NULL; /* fail */
else /* normal allocation */
return (*g->frealloc)(g->ud, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
#endif
/*
** About the realloc function:
** void *frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
@ -77,6 +58,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
*/
/*
** Macro to call the allocation function.
*/
#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
/*
** When an allocation fails, it will try again after an emergency
** collection, except when it cannot run a collection. The GC should
** not be called while the state is not fully built, as the collector
** is not yet fully initialized. Also, it should not be called when
** 'gcstopem' is true, because then the interpreter is in the middle of
** a collection step.
*/
#define cantryagain(g) (completestate(g) && !g->gcstopem)
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail except when freeing a block (frees never
** fail) and when it cannot try again; this fail will trigger 'tryagain'
** and a full GC cycle at every allocation.
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (ns > 0 && cantryagain(g))
return NULL; /* fail */
else /* normal allocation */
return callfrealloc(g, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
#endif
/*
@ -149,7 +167,7 @@ l_noret luaM_toobig (lua_State *L) {
void luaM_free_ (lua_State *L, void *block, size_t osize) {
global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL));
(*g->frealloc)(g->ud, block, osize, 0);
callfrealloc(g, block, osize, 0);
g->GCdebt -= osize;
}
@ -157,20 +175,16 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
/*
** In case of allocation fail, this function will do an emergency
** collection to free some memory and then try the allocation again.
** The GC should not be called while state is not fully built, as the
** collector is not yet fully initialized. Also, it should not be called
** when 'gcstopem' is true, because then the interpreter is in the
** middle of a collection step.
*/
static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) {
global_State *g = G(L);
if (completestate(g) && !g->gcstopem) {
WARNF("reacting to malloc() failure by running lua garbage collector...");
if (cantryagain(g)) {
WARNF("reacting to malloc() failure by running lua garbage collector..."); // [jart]
luaC_fullgc(L, 1); /* try to free some memory... */
return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
return callfrealloc(g, block, osize, nsize); /* try again */
}
else return NULL; /* cannot free any memory without a full state */
else return NULL; /* cannot run an emergency collection */
}

View file

@ -1,3 +1,3 @@
__notice(lua_notice, "\
Lua 5.4.3 (MIT License)\n\
Copyright 19942021 Lua.org, PUC-Rio.");
Lua 5.4.6 (MIT License)\n\
Copyright 19942023 Lua.org, PUC-Rio.");

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define loadlib_c
#define LUA_LIB
#include "libc/dlopen/dlfcn.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
@ -36,14 +37,16 @@
#include "third_party/lua/lualib.h"
__static_yoink("lua_notice");
/*
** This module contains an implementation of loadlib for Unix systems
**
** [jart] This module contains an implementation of loadlib for Unix systems
** that have dlfcn, an implementation for Windows, and a stub for other
** systems.
*/
const char *g_lua_path_default = LUA_PATH_DEFAULT;
const char *g_lua_path_default = LUA_PATH_DEFAULT; // [jart]
/*
@ -728,8 +731,13 @@ static const luaL_Reg ll_funcs[] = {
static void createsearcherstable (lua_State *L) {
static const lua_CFunction searchers[] =
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
static const lua_CFunction searchers[] = {
searcher_preload,
searcher_Lua,
searcher_C,
searcher_Croot,
NULL
};
int i;
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
@ -757,7 +765,7 @@ static void createclibstable (lua_State *L) {
static const char *GetLuaPathDefault(void) {
return g_lua_path_default;
return g_lua_path_default; // [jart]
}

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lobject_c
#define LUA_CORE
#include "libc/str/str.h"
#include "third_party/lua/lctype.h"
#include "third_party/lua/ldebug.h"
@ -41,6 +42,12 @@
__static_yoink("lua_notice");
/*
** Computes ceil(log2(x))
*/
// [jart] moved to lobject.h
static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
lua_Integer v2) {
switch (op) {
@ -53,7 +60,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2);
case LUA_OPSHL: return luaV_shiftl(v1, v2);
case LUA_OPSHR: return luaV_shiftl(v1, -v2);
case LUA_OPSHR: return luaV_shiftr(v1, v2);
case LUA_OPUNM: return intop(-, 0, v1);
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
default: lua_assert(0); return 0;
@ -155,7 +162,7 @@ static int isneg (const char **s) {
*/
static lua_Number lua_strx2number (const char *s, char **endptr) {
int dot = lua_getlocaledecpoint();
lua_Number r = 0.0; /* result (accumulator) */
lua_Number r = l_mathop(0.0); /* result (accumulator) */
int sigdig = 0; /* number of significant digits */
int nosigdig = 0; /* number of non-significant digits */
int e = 0; /* exponent correction */
@ -165,7 +172,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
neg = isneg(&s); /* check sign */
if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
return 0.0; /* invalid format (no '0x') */
return l_mathop(0.0); /* invalid format (no '0x') */
for (s += 2; ; s++) { /* skip '0x' and read numeral */
if (*s == dot) {
if (hasdot) break; /* second dot? stop loop */
@ -175,14 +182,14 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
nosigdig++;
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
r = (r * cast_num(16.0)) + luaO_hexavalue(*s);
r = (r * l_mathop(16.0)) + luaO_hexavalue(*s);
else e++; /* too many digits; ignore, but still count for exponent */
if (hasdot) e--; /* decimal digit? correct exponent */
}
else break; /* neither a dot nor a digit */
}
if (nosigdig + sigdig == 0) /* no digits? */
return 0.0; /* invalid format */
return l_mathop(0.0); /* invalid format */
*endptr = cast_charp(s); /* valid up to here */
e *= 4; /* each digit multiplies/divides value by 2^4 */
if (*s == 'p' || *s == 'P') { /* exponent part? */
@ -191,7 +198,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
s++; /* skip 'p' */
neg1 = isneg(&s); /* sign */
if (!lisdigit(cast_uchar(*s)))
return 0.0; /* invalid; must have at least one digit */
return l_mathop(0.0); /* invalid; must have at least one digit */
while (lisdigit(cast_uchar(*s))) /* read exponent */
exp1 = exp1 * 10 + *(s++) - '0';
if (neg1) exp1 = -exp1;
@ -262,9 +269,9 @@ static const char *l_str2d (const char *s, lua_Number *result) {
#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10)
#define MAXBY8 cast(lua_Unsigned, LUA_MAXINTEGER / 8)
#define MAXBY8 cast(lua_Unsigned, LUA_MAXINTEGER / 8) // [jart]
#define MAXLASTD cast_int(LUA_MAXINTEGER % 10)
#define MAXLASTD8 cast_int(LUA_MAXINTEGER % 8)
#define MAXLASTD8 cast_int(LUA_MAXINTEGER % 8) // [jart]
static const char *l_str2int (const char *s, lua_Integer *result) {
lua_Unsigned a = 0;
@ -396,29 +403,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
** ===================================================================
*/
/* size for buffer space used by 'luaO_pushvfstring' */
#define BUFVFS 200
/*
** Size for buffer space used by 'luaO_pushvfstring'. It should be
** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
** so that 'luaG_addinfo' can work directly on the buffer.
*/
#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS {
lua_State *L;
int pushed; /* number of string pieces already on the stack */
int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */
} BuffFS;
/*
** Push given string to the stack, as part of the buffer, and
** join the partial strings in the stack into one.
** Push given string to the stack, as part of the result, and
** join it to previous partial result if there is one.
** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
** This call cannot invoke metamethods, as both operands must be
** strings. It can, however, raise an error if the result is too
** long. In that case, 'luaV_concat' frees the extra slot before
** raising the error.
*/
static void pushstr (BuffFS *buff, const char *str, size_t l) {
static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L;
setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
L->top++; /* may use one extra slot */
buff->pushed++;
luaV_concat(L, buff->pushed); /* join partial results into one */
buff->pushed = 1;
setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
L->top.p++; /* may use one slot from EXTRA_STACK */
if (!buff->pushed) /* no previous string on the stack? */
buff->pushed = 1; /* now there is one */
else /* join previous string with new one */
luaV_concat(L, 2);
}
@ -464,7 +481,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
/*
** Add a number to the buffer.
** Add a numeral to the buffer.
*/
static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR);
@ -542,7 +559,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1);
return svalue(s2v(L->top - 1));
return svalue(s2v(L->top.p - 1));
}

View file

@ -13,11 +13,14 @@
#define LUA_TPROTO (LUA_NUMTYPES + 1) /* function prototypes */
#define LUA_TDEADKEY (LUA_NUMTYPES + 2) /* removed keys in tables */
/*
** number of all possible types (including LUA_TNONE but excluding DEADKEY)
*/
#define LUA_TOTALTYPES (LUA_TPROTO + 2)
/*
** tags for Tagged Values have the following use of bits:
** bits 0-3: actual tag (a LUA_T* constant)
@ -39,6 +42,8 @@ typedef union Value {
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
/* not used, but may avoid warnings for uninitialized value */
lu_byte ub;
} Value;
@ -55,7 +60,7 @@ typedef struct TValue {
#define val_(o) ((o)->value_)
#define valraw(o) (&val_(o))
#define valraw(o) (val_(o))
/* raw type tag of a TValue */
@ -99,7 +104,7 @@ typedef struct TValue {
#define settt_(o,t) ((o)->tt_=(t))
/* main macro to copy values (from 'obj1' to 'obj2') */
/* main macro to copy values (from 'obj2' to 'obj1') */
#define setobj(L,obj1,obj2) \
{ TValue *io1=(obj1); const TValue *io2=(obj2); \
io1->value_ = io2->value_; settt_(io1, io2->tt_); \
@ -142,6 +147,17 @@ typedef union StackValue {
/* index to stack elements */
typedef StackValue *StkId;
/*
** When reallocating the stack, change all pointers to the stack into
** proper offsets.
*/
typedef union {
StkId p; /* actual pointer */
ptrdiff_t offset; /* used while the stack is being reallocated */
} StkIdRel;
/* convert a 'StackValue' to a 'TValue' */
#define s2v(o) (&(o)->val)
@ -602,8 +618,10 @@ typedef struct Proto {
*/
typedef struct UpVal {
CommonHeader;
lu_byte tbc; /* true if it represents a to-be-closed variable */
TValue *v; /* points to stack or to its own value */
union {
TValue *p; /* points to stack or to its own value */
ptrdiff_t offset; /* used while the stack is being reallocated */
} v;
union {
struct { /* (when open) */
struct UpVal *next; /* linked list */
@ -785,7 +803,7 @@ LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t srclen);
** Computes ceil(log2(x))
*/
static inline int luaO_ceillog2 (unsigned int x) {
return --x ? bsr(x) + 1 : 0;
return --x ? _bsr(x) + 1 : 0; // [jart]
}
#endif

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lopcodes_c
#define LUA_CORE
#include "third_party/lua/lopcodes.h"
#include "third_party/lua/lprefix.h"
__static_yoink("lua_notice");

View file

@ -15,7 +15,7 @@ iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) |
isJ sJ(25) | Op(7) |
isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the
@ -184,7 +184,8 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
/*
** grep "ORDER OP" if you change these enums
** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*)
** has extra descriptions in the notes after the enumeration.
*/
typedef enum {
@ -197,7 +198,7 @@ OP_LOADF,/* A sBx R[A] := (lua_Number)sBx */
OP_LOADK,/* A Bx R[A] := K[Bx] */
OP_LOADKX,/* A R[A] := K[extra arg] */
OP_LOADFALSE,/* A R[A] := false */
OP_LFALSESKIP,/*A R[A] := false; pc++ */
OP_LFALSESKIP,/*A R[A] := false; pc++ (*) */
OP_LOADTRUE,/* A R[A] := true */
OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
@ -248,7 +249,7 @@ OP_BXOR,/* A B C R[A] := R[B] ~ R[C] */
OP_SHL,/* A B C R[A] := R[B] << R[C] */
OP_SHR,/* A B C R[A] := R[B] >> R[C] */
OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] */
OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] (*) */
OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */
OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */
@ -274,7 +275,7 @@ OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */
OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */
OP_TEST,/* A k if (not R[A] == k) then pc++ */
OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] */
OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */
OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */
OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */
@ -309,6 +310,18 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
/*===========================================================================
Notes:
(*) Opcode OP_LFALSESKIP is used to convert a condition to a boolean
value, in a code equivalent to (not cond ? false : true). (It
produces false and skips the next instruction producing true.)
(*) Opcodes OP_MMBIN and variants follow each arithmetic and
bitwise opcode. If the operation succeeds, it skips this next
opcode. Otherwise, this opcode calls the corresponding metamethod.
(*) Opcode OP_TESTSET is used in short-circuit expressions that need
both to jump and to produce a value, such as (a = b or c).
(*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then
'top' is set to last_result+1, so next open instruction (OP_CALL,
OP_RETURN*, OP_SETLIST) may use 'top'.

View file

@ -1,14 +1,7 @@
/*
** $Id: lopnames.h $
** Opcode names
** See Copyright Notice in lua.h
*/
#if !defined(lopnames_h)
#ifndef lopnames_h
#define lopnames_h
/* ORDER OP */
static const char *const opnames[] = {

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define loslib_c
#define LUA_LIB
#include "libc/calls/calls.h"
#include "libc/calls/weirdtypes.h"
#include "libc/errno.h"
@ -51,23 +52,14 @@ __static_yoink("lua_notice");
*/
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
/* options for ANSI C 89 (only 1-char options) */
#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
/* options for ISO C 99 and POSIX */
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
/* options for Windows */
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
#elif defined(LUA_USE_C89)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
#else /* C99 specification */
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
#endif
#endif /* } */
@ -135,6 +127,7 @@ __static_yoink("lua_notice");
#define LUA_TMPNAMBUFSIZE 128
// [jart]
#define lua_tmpnam(b,e) { \
strlcpy(b, __get_tmpdir(), LUA_TMPNAMBUFSIZE); \
e = strlcat(b, "lua_XXXXXX", LUA_TMPNAMBUFSIZE) >= LUA_TMPNAMBUFSIZE; \
@ -154,12 +147,21 @@ __static_yoink("lua_notice");
/* }================================================================== */
#if !defined(l_system)
#if defined(LUA_USE_IOS)
/* Despite claiming to be ISO C, iOS does not implement 'system'. */
#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
#else
#define l_system(cmd) system(cmd) /* default definition */
#endif
#endif
static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL);
int stat;
errno = 0;
stat = system(cmd);
stat = l_system(cmd);
if (cmd != NULL)
return luaL_execresult(L, stat);
else {
@ -276,9 +278,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
res = d;
}
else {
/* unsigned avoids overflow when lua_Integer has 32 bits */
if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
: (lua_Integer)INT_MIN + delta <= res))
if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta;
}

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lparser_c
#define LUA_CORE
#include "libc/str/str.h"
#include "third_party/lua/lcode.h"
#include "third_party/lua/ldebug.h"
@ -431,6 +432,17 @@ static void markupval (FuncState *fs, int level) {
}
/*
** Mark that current block has a to-be-closed variable.
*/
static void marktobeclosed (FuncState *fs) {
BlockCnt *bl = fs->bl;
bl->upval = 1;
bl->insidetbc = 1;
fs->needclose = 1;
}
/*
** Find a variable with the given name 'n'. If it is an upvalue, add
** this upvalue into all intermediate functions. If it is a global, set
@ -472,6 +484,7 @@ static void singlevar (LexState *ls, expdesc *var) {
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */
luaK_exp2anyregup(fs, var); /* but could be a constant */
codestring(&key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@ -524,12 +537,12 @@ static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
/*
** Solves the goto at index 'g' to given 'label' and removes it
** from the list of pending goto's.
** from the list of pending gotos.
** If it jumps into the scope of some variable, raises an error.
*/
static void solvegoto (LexState *ls, int g, Labeldesc *label) {
int i;
Labellist *gl = &ls->dyd->gt; /* list of goto's */
Labellist *gl = &ls->dyd->gt; /* list of gotos */
Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */
lua_assert(eqstr(gt->name, label->name));
if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
@ -583,7 +596,7 @@ static int newgotoentry (LexState *ls, TString *name, int line, int pc) {
/*
** Solves forward jumps. Check whether new label 'lb' matches any
** pending gotos in current block and solves them. Return true
** if any of the goto's need to close upvalues.
** if any of the gotos need to close upvalues.
*/
static int solvegotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt;
@ -604,7 +617,7 @@ static int solvegotos (LexState *ls, Labeldesc *lb) {
/*
** Create a new label with the given 'name' at the given 'line'.
** 'last' tells whether label is the last non-op statement in its
** block. Solves all pending goto's to this new label and adds
** block. Solves all pending gotos to this new label and adds
** a close instruction if necessary.
** Returns true iff it added a close instruction.
*/
@ -677,19 +690,19 @@ static void leaveblock (FuncState *fs) {
LexState *ls = fs->ls;
int hasclose = 0;
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
if (bl->isloop) /* fix pending breaks? */
removevars(fs, bl->nactvar); /* remove block locals */
lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
if (bl->isloop) /* has to fix pending breaks? */
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
if (!hasclose && bl->previous && bl->upval)
if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */
luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
fs->bl = bl->previous;
removevars(fs, bl->nactvar);
lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = stklevel; /* free registers */
ls->dyd->label.n = bl->firstlabel; /* remove local labels */
if (bl->previous) /* inner block? */
movegotosout(fs, bl); /* update pending gotos to outer block */
fs->bl = bl->previous; /* current block now is previous one */
if (bl->previous) /* was it a nested block? */
movegotosout(fs, bl); /* update pending gotos to enclosing block */
else {
if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */
if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
}
}
@ -1614,7 +1627,7 @@ static void forlist (LexState *ls, TString *indexname) {
line = ls->linenumber;
adjust_assign(ls, 4, explist(ls, &e), &e);
adjustlocalvars(ls, 4); /* control variables */
markupval(fs, fs->nactvar); /* last control var. must be closed */
marktobeclosed(fs); /* last control var. must be closed */
luaK_checkstack(fs, 3); /* extra space to call generator */
forbody(ls, base, line, nvars - 4, 1);
}
@ -1718,11 +1731,9 @@ static int getlocalattribute (LexState *ls) {
}
static void checktoclose (LexState *ls, int level) {
static void checktoclose (FuncState *fs, int level) {
if (level != -1) { /* is there a to-be-closed variable? */
FuncState *fs = ls->fs;
markupval(fs, level + 1);
fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
marktobeclosed(fs);
luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0);
}
}
@ -1766,7 +1777,7 @@ static void localstat (LexState *ls) {
adjust_assign(ls, nvars, nexps, &e);
adjustlocalvars(ls, nvars);
}
checktoclose(ls, toclose);
checktoclose(fs, toclose);
}
@ -1791,6 +1802,7 @@ static void funcstat (LexState *ls, int line) {
luaX_next(ls); /* skip FUNCTION */
ismethod = funcname(ls, &v);
body(ls, &b, ismethod, line);
check_readonly(ls, &v);
luaK_storevar(ls->fs, &v, &b);
luaK_fixline(ls->fs, line); /* definition "happens" in the first line */
}
@ -1948,10 +1960,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LexState lexstate;
FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue2s(L, L->top, cl); /* anchor it (to avoid being collected) */
setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue2s(L, L->top, lexstate.h); /* anchor it */
sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
@ -1965,7 +1977,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
L->top--; /* remove scanner's table */
L->top.p--; /* remove scanner's table */
return cl; /* closure is on the stack, too */
}

View file

@ -1,6 +1,7 @@
#ifndef lprefix_h
#define lprefix_h
/*
** Allows POSIX/XSI stuff
*/
@ -22,6 +23,7 @@
#endif /* } */
/*
** Windows stuff
*/

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lstate_c
#define LUA_CORE
#include "libc/str/str.h"
#include "libc/time.h"
#include "third_party/lua/lapi.h"
@ -180,7 +181,7 @@ void luaE_checkcstack (lua_State *L) {
if (getCcalls(L) == LUAI_MAXCCALLS)
luaG_runerror(L, "C stack overflow");
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
luaD_throw(L, LUA_ERRERR); /* error while handling stack error */
}
@ -194,33 +195,33 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci;
/* initialize stack array */
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
L1->tbclist = L1->stack;
L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
L1->tbclist.p = L1->stack.p;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
setnilvalue(s2v(L1->stack + i)); /* erase new stack */
L1->top = L1->stack;
L1->stack_last = L1->stack + BASIC_STACK_SIZE;
setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
L1->top.p = L1->stack.p;
L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
/* initialize first ci */
ci = &L1->base_ci;
ci->next = ci->previous = NULL;
ci->callstatus = CIST_C;
ci->func = L1->top;
ci->func.p = L1->top.p;
ci->u.c.k = NULL;
ci->nresults = 0;
setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */
L1->top++;
ci->top = L1->top + LUA_MINSTACK;
setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
L1->top.p++;
ci->top.p = L1->top.p + LUA_MINSTACK;
L1->ci = ci;
}
static void freestack (lua_State *L) {
if (L->stack == NULL)
if (L->stack.p == NULL)
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
lua_assert(L->nci == 0);
luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */
luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
}
@ -250,7 +251,7 @@ static void f_luaopen (lua_State *L, void *ud) {
luaS_init(L);
luaT_init(L);
luaX_init(L);
g->gcrunning = 1; /* allow gc */
g->gcstp = 0; /* allow gc */
setnilvalue(&g->nilvalue); /* now state is complete */
luai_userstateopen(L);
}
@ -262,7 +263,7 @@ static void f_luaopen (lua_State *L, void *ud) {
*/
static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
L->stack = NULL;
L->stack.p = NULL;
L->ci = NULL;
L->nci = 0;
L->twups = L; /* thread has no upvalues */
@ -283,8 +284,9 @@ static void preinit_thread (lua_State *L, global_State *g) {
static void close_state (lua_State *L) {
global_State *g = G(L);
if (!completestate(g)) /* closing a partially built state? */
luaC_freeallobjects(L); /* jucst collect its objects */
luaC_freeallobjects(L); /* just collect its objects */
else { /* closing a fully built state */
L->ci = &L->base_ci; /* unwind CallInfo list */
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
luaC_freeallobjects(L); /* collect all objects */
luai_userstateclose(L);
@ -307,20 +309,16 @@ static void close_state (lua_State *L) {
* Threads are subject to garbage collection, like any Lua object.
*/
LUA_API lua_State *lua_newthread (lua_State *L) {
global_State *g;
global_State *g = G(L);
GCObject *o;
lua_State *L1;
lua_lock(L);
g = G(L);
luaC_checkGC(L);
/* create new thread */
L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
L1->marked = luaC_white(g);
L1->tt = LUA_VTHREAD;
/* link it on list 'allgc' */
L1->next = g->allgc;
g->allgc = obj2gco(L1);
o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
L1 = gco2th(o);
/* anchor it on L stack */
setthvalue2s(L, L->top, L1);
setthvalue2s(L, L->top.p, L1);
api_incr_top(L);
preinit_thread(L1, g);
L1->hookmask = L->hookmask;
@ -339,7 +337,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
luaF_closeupval(L1, L1->stack); /* close all upvalues */
luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1);
freestack(L1);
@ -349,32 +347,41 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
int luaE_resetthread (lua_State *L, int status) {
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
ci->func = L->stack;
setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
ci->func.p = L->stack.p;
ci->callstatus = CIST_C;
if (status == LUA_YIELD)
status = LUA_OK;
L->status = LUA_OK; /* so it can run __close metamethods */
status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */
luaD_seterrorobj(L, status, L->stack + 1);
luaD_seterrorobj(L, status, L->stack.p + 1);
else
L->top = L->stack + 1;
ci->top = L->top + LUA_MINSTACK;
L->status = cast_byte(status);
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
L->top.p = L->stack.p + 1;
ci->top.p = L->top.p + LUA_MINSTACK;
luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
return status;
}
LUA_API int lua_resetthread (lua_State *L) {
LUA_API int lua_closethread (lua_State *L, lua_State *from) {
int status;
lua_lock(L);
L->nCcalls = (from) ? getCcalls(from) : 0;
status = luaE_resetthread(L, L->status);
lua_unlock(L);
return status;
}
/*
** Deprecated! Use 'lua_closethread' instead.
*/
LUA_API int lua_resetthread (lua_State *L) {
return lua_closethread(L, NULL);
}
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
@ -396,7 +403,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->ud_warn = NULL;
g->mainthread = L;
g->seed = luai_makeseed(L);
g->gcrunning = 0; /* no GC while building state */
g->gcstp = GCSTPGC; /* no GC while building state */
g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
@ -449,7 +456,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
** Generate a warning from an error message
*/
void luaE_warnerror (lua_State *L, const char *where) {
TValue *errobj = s2v(L->top - 1); /* error object */
TValue *errobj = s2v(L->top.p - 1); /* error object */
const char *msg = (ttisstring(errobj))
? svalue(errobj)
: "error object is not a string";

View file

@ -1,6 +1,9 @@
#ifndef lstate_h
#define lstate_h
/* Some header files included here need this definition */
typedef struct CallInfo CallInfo;
#include "libc/calls/calls.h"
#include "third_party/lua/lobject.h"
#include "third_party/lua/lua.h"
@ -132,7 +135,7 @@ struct lua_longjmp; /* defined in ldo.c */
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
#define stacksize(th) cast_int((th)->stack_last - (th)->stack)
#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
/* kinds of Garbage Collection */
@ -158,13 +161,13 @@ typedef struct stringtable {
** - field 'nyield' is used only while a function is "doing" an
** yield (from the yield until the next resume);
** - field 'nres' is used only while closing tbc variables when
** returning from a C function;
** returning from a function;
** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends.
*/
typedef struct CallInfo {
StkId func; /* function index in the stack */
StkId top; /* top for this function */
struct CallInfo {
StkIdRel func; /* function index in the stack */
StkIdRel top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */
union {
struct { /* only for Lua functions */
@ -189,7 +192,7 @@ typedef struct CallInfo {
} u2;
short nresults; /* expected number of results from this function */
unsigned short callstatus;
} CallInfo;
};
/*
@ -202,7 +205,7 @@ typedef struct CallInfo {
#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */
#define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
#define CIST_FIN (1<<7) /* call is running a finalizer */
#define CIST_FIN (1<<7) /* function "called" a finalizer */
#define CIST_TRAN (1<<8) /* 'ci' has transfer information */
#define CIST_CLSRET (1<<9) /* function is closing tbc variables */
/* Bits 10-12 are used for CIST_RECST (see below) */
@ -256,7 +259,7 @@ typedef struct global_State {
lu_byte gcstopem; /* stops emergency collections */
lu_byte genminormul; /* control for minor generational collections */
lu_byte genmajormul; /* control for major generational collections */
lu_byte gcrunning; /* true if GC is running */
lu_byte gcstp; /* control whether GC is running */
lu_byte gcemergency; /* true if this is an emergency collection */
lu_byte gcpause; /* size of pause between successive GCs */
lu_byte gcstepmul; /* GC "speed" */
@ -284,7 +287,7 @@ typedef struct global_State {
struct lua_State *mainthread;
TString *memerrmsg; /* message for memory-allocation errors */
TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
lua_WarnFunction warnf; /* warning function */
void *ud_warn; /* auxiliary data to 'warnf' */
@ -299,13 +302,13 @@ struct lua_State {
lu_byte status;
lu_byte allowhook;
unsigned short nci; /* number of items in 'ci' list */
StkId top; /* first free slot in the stack */
StkIdRel top; /* first free slot in the stack */
global_State *l_G;
CallInfo *ci; /* call info for current function */
StkId stack_last; /* end of stack (last element + 1) */
StkId stack; /* stack base */
StkIdRel stack_last; /* end of stack (last element + 1) */
StkIdRel stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */
StkId tbclist; /* list of to-be-closed variables */
StkIdRel tbclist; /* list of to-be-closed variables */
GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lstring_c
#define LUA_CORE
#include "libc/str/str.h"
#include "third_party/lua/ldebug.h"
#include "third_party/lua/ldo.h"

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lstrlib_c
#define LUA_LIB
#include "libc/math.h"
#include "libc/str/str.h"
#include "third_party/lua/cosmo.h"
@ -62,7 +63,7 @@ __static_yoink("lua_notice");
static int str_format(lua_State *);
static int str_format(lua_State *); // [jart]
static int str_len (lua_State *L) {
@ -607,7 +608,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
static const char *match (MatchState *ms, const char *s, const char *p) {
if (l_unlikely(ms->matchdepth-- == 0))
luaL_error(ms->L, "pattern too complex");
init: /* using goto's to optimize tail recursion */
init: /* using goto to optimize tail recursion */
if (p != ms->p_end) { /* end of pattern? */
switch (*p) {
case '(': { /* start capture */
@ -1127,13 +1128,31 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
/* valid flags in a format specification */
#if !defined(L_FMTFLAGS)
#define L_FMTFLAGS "-+ #0"
#if !defined(L_FMTFLAGSF)
/* valid flags for a, A, e, E, f, F, g, and G conversions */
#define L_FMTFLAGSF "-+#0 "
/* valid flags for o, x, and X conversions */
#define L_FMTFLAGSX "-#0"
/* valid flags for d and i conversions */
#define L_FMTFLAGSI "-+0 "
/* valid flags for u conversions */
#define L_FMTFLAGSU "-0"
/* valid flags for c, p, and s conversions */
#define L_FMTFLAGSC "-"
#endif
/*
** maximum size of each format specification (such as "%-099.99d")
** Maximum size of each format specification (such as "%-099.99d"):
** Initial '%', flags (up to 5), width (2), period, precision (2),
** length modifier (8), conversion specifier, and final '\0', plus some
** extra.
*/
#define MAX_FORMAT 32
@ -1226,25 +1245,53 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
}
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
const char *p = strfrmt;
while (*p != '\0' && strchr(L_FMTFLAGS, *p) != NULL) p++; /* skip flags */
if ((size_t)(p - strfrmt) >= sizeof(L_FMTFLAGS)/sizeof(char))
luaL_error(L, "invalid format (repeated flags)");
if (isdigit(uchar(*p))) p++; /* skip width */
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
if (*p == '.') {
p++;
if (isdigit(uchar(*p))) p++; /* skip precision */
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
static const char *get2digits (const char *s) {
if (isdigit(uchar(*s))) {
s++;
if (isdigit(uchar(*s))) s++; /* (2 digits at most) */
}
if (isdigit(uchar(*p)))
luaL_error(L, "invalid format (width or precision too long)");
return s;
}
/*
** Check whether a conversion specification is valid. When called,
** first character in 'form' must be '%' and last character must
** be a valid conversion specifier. 'flags' are the accepted flags;
** 'precision' signals whether to accept a precision.
*/
static void checkformat (lua_State *L, const char *form, const char *flags,
int precision) {
const char *spec = form + 1; /* skip '%' */
spec += strspn(spec, flags); /* skip flags */
if (*spec != '0') { /* a width cannot start with '0' */
spec = get2digits(spec); /* skip width */
if (*spec == '.' && precision) {
spec++;
spec = get2digits(spec); /* skip precision */
}
}
if (!isalpha(uchar(*spec))) /* did not go to the end? */
luaL_error(L, "invalid conversion specification: '%s'", form);
}
/*
** Get a conversion specification and copy it to 'form'.
** Return the address of its last character.
*/
static const char *getformat (lua_State *L, const char *strfrmt,
char *form) {
/* spans flags, width, and precision ('0' is included as a flag) */
size_t len = strspn(strfrmt, L_FMTFLAGSF "123456789.");
len++; /* adds following character (should be the specifier) */
/* still needs space for '%', '\0', plus a length modifier */
if (len >= MAX_FORMAT - 10)
luaL_error(L, "invalid format (too long)");
*(form++) = '%';
memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
form += (p - strfrmt) + 1;
*form = '\0';
return p;
memcpy(form, strfrmt, len * sizeof(char));
*(form + len) = '\0';
return strfrmt + len - 1;
}
@ -1267,6 +1314,7 @@ static int str_format (lua_State *L) {
size_t sfl;
const char *strfrmt = luaL_checklstring(L, arg, &sfl);
const char *strfrmt_end = strfrmt+sfl;
const char *flags;
luaL_Buffer b;
luaL_buffinit(L, &b);
while (strfrmt < strfrmt_end) {
@ -1276,25 +1324,35 @@ static int str_format (lua_State *L) {
luaL_addchar(&b, *strfrmt++); /* %% */
else { /* format item */
char form[MAX_FORMAT]; /* to store the format ('%...') */
int maxitem = MAX_ITEM;
char *buff = luaL_prepbuffsize(&b, maxitem); /* to put formatted item */
int nb = 0; /* number of bytes in added item */
int maxitem = MAX_ITEM; /* maximum length for the result */
char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */
int nb = 0; /* number of bytes in result */
if (++arg > top)
return luaL_argerror(L, arg, "no value");
strfrmt = scanformat(L, strfrmt, form);
strfrmt = getformat(L, strfrmt, form);
switch (*strfrmt++) {
case 'c': {
checkformat(L, form, L_FMTFLAGSC, 0);
nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg));
break;
}
case 'd': case 'i':
case 'o': case 'u': case 'x': case 'X': {
flags = L_FMTFLAGSI;
goto intcase;
case 'u':
flags = L_FMTFLAGSU;
goto intcase;
case 'o': case 'x': case 'X':
flags = L_FMTFLAGSX;
intcase: {
lua_Integer n = luaL_checkinteger(L, arg);
checkformat(L, form, flags, 1);
addlenmod(form, LUA_INTEGER_FRMLEN);
nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n);
break;
}
case 'a': case 'A':
checkformat(L, form, L_FMTFLAGSF, 1);
addlenmod(form, LUA_NUMBER_FRMLEN);
nb = lua_number2strx(L, buff, maxitem, form,
luaL_checknumber(L, arg));
@ -1305,12 +1363,14 @@ static int str_format (lua_State *L) {
/* FALLTHROUGH */
case 'e': case 'E': case 'g': case 'G': {
lua_Number n = luaL_checknumber(L, arg);
checkformat(L, form, L_FMTFLAGSF, 1);
addlenmod(form, LUA_NUMBER_FRMLEN);
nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
break;
}
case 'p': {
const void *p = lua_topointer(L, arg);
checkformat(L, form, L_FMTFLAGSC, 0);
if (p == NULL) { /* avoid calling 'printf' with argument NULL */
p = "(null)"; /* result */
form[strlen(form) - 1] = 's'; /* format it as a string */
@ -1331,7 +1391,8 @@ static int str_format (lua_State *L) {
luaL_addvalue(&b); /* keep entire string */
else {
luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
if (!strchr(form, '.') && l >= 100) {
checkformat(L, form, L_FMTFLAGSC, 1);
if (strchr(form, '.') == NULL && l >= 100) {
/* no precision and string is too long to be formatted */
luaL_addvalue(&b); /* keep entire string */
}
@ -1389,15 +1450,6 @@ static const union {
} nativeendian = {1};
/* dummy structure to get native alignment requirements */
struct cD {
char c;
union { double d; void *p; lua_Integer i; lua_Number n; } u;
};
#define MAXALIGN (offsetof(struct cD, u))
/*
** information to pack/unpack stuff
*/
@ -1472,6 +1524,8 @@ static void initheader (lua_State *L, Header *h) {
** Read and classify next option. 'size' is filled with option's size.
*/
static KOption getoption (Header *h, const char **fmt, int *size) {
/* dummy structure to get native alignment requirements */
struct cD { char c; union { LUAI_MAXALIGN; } u; };
int opt = *((*fmt)++);
*size = 0; /* default */
switch (opt) {
@ -1502,7 +1556,11 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
case '<': h->islittle = 1; break;
case '>': h->islittle = 0; break;
case '=': h->islittle = nativeendian.little; break;
case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break;
case '!': {
const int maxalign = offsetof(struct cD, u);
h->maxalign = getnumlimit(h, fmt, maxalign);
break;
}
default: luaL_error(h->L, "invalid format option '%c'", opt);
}
return Knop;

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define ltable_c
#define LUA_CORE
#include "third_party/lua/ldebug.h"
#include "third_party/lua/ldo.h"
#include "third_party/lua/lgc.h"
@ -100,8 +101,6 @@ __static_yoink("lua_notice");
#define hashstr(t,str) hashpow2(t, (str)->hash)
#define hashboolean(t,p) hashpow2(t, p)
#define hashint(t,i) hashpow2(t, i)
#define hashpointer(t,p) hashmod(t, point2uint(p))
@ -117,6 +116,20 @@ static const Node dummynode_ = {
static const TValue absentkey = {ABSTKEYCONSTANT};
/*
** Hash for integers. To allow a good hash, use the remainder operator
** ('%'). If integer fits as a non-negative int, compute an int
** remainder, which is faster. Otherwise, use an unsigned-integer
** remainder, which uses all bits and ensures a non-negative result.
*/
static Node *hashint (const Table *t, lua_Integer i) {
lua_Unsigned ui = l_castS2U(i);
if (ui <= cast_uint(INT_MAX))
return hashmod(t, cast_int(ui));
else
return hashmod(t, ui);
}
/*
** Hash for floating-point numbers.
@ -150,26 +163,24 @@ static int l_hashfloat (lua_Number n) {
/*
** returns the 'main' position of an element in a table (that is,
** the index of its hash value). The key comes broken (tag in 'ktt'
** and value in 'vkl') so that we can call it on keys inserted into
** nodes.
** the index of its hash value).
*/
static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
switch (withvariant(ktt)) {
static Node *mainpositionTV (const Table *t, const TValue *key) {
switch (ttypetag(key)) {
case LUA_VNUMINT: {
lua_Integer key = ivalueraw(*kvl);
return hashint(t, key);
lua_Integer i = ivalue(key);
return hashint(t, i);
}
case LUA_VNUMFLT: {
lua_Number n = fltvalueraw(*kvl);
lua_Number n = fltvalue(key);
return hashmod(t, l_hashfloat(n));
}
case LUA_VSHRSTR: {
TString *ts = tsvalueraw(*kvl);
TString *ts = tsvalue(key);
return hashstr(t, ts);
}
case LUA_VLNGSTR: {
TString *ts = tsvalueraw(*kvl);
TString *ts = tsvalue(key);
return hashpow2(t, luaS_hashlongstr(ts));
}
case LUA_VFALSE:
@ -177,26 +188,25 @@ static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
case LUA_VTRUE:
return hashboolean(t, 1);
case LUA_VLIGHTUSERDATA: {
void *p = pvalueraw(*kvl);
void *p = pvalue(key);
return hashpointer(t, p);
}
case LUA_VLCF: {
lua_CFunction f = fvalueraw(*kvl);
lua_CFunction f = fvalue(key);
return hashpointer(t, f);
}
default: {
GCObject *o = gcvalueraw(*kvl);
GCObject *o = gcvalue(key);
return hashpointer(t, o);
}
}
}
/*
** Returns the main position of an element given as a 'TValue'
*/
static Node *mainpositionTV (const Table *t, const TValue *key) {
return mainposition(t, rawtt(key), valraw(key));
l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) {
TValue key;
getnodekey(cast(lua_State *, NULL), &key, nd);
return mainpositionTV(t, &key);
}
@ -264,9 +274,11 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
size |= (size >> 2);
size |= (size >> 4);
size |= (size >> 8);
#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */
size |= (size >> 16);
#if (UINT_MAX >> 30) > 3
size |= (size >> 32); /* unsigned int has more than 32 bits */
#endif
#endif
size++;
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
@ -495,7 +507,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
luaG_runerror(L, "table overflow");
size = twoto(lsize);
t->node = luaM_newvector(L, size, Node);
for (i = 0; i < (int)size; i++) {
for (i = 0; i < cast_int(size); i++) {
Node *n = gnode(t, i);
gnext(n) = 0;
setnilkey(n);
@ -695,7 +707,7 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
return;
}
lua_assert(!isdummy(t));
othern = mainposition(t, keytt(mp), &keyval(mp));
othern = mainpositionfromnode(t, mp);
if (othern != mp) { /* is colliding node out of its main position? */
/* yes; move colliding node into free position */
while (othern + gnext(othern) != mp) /* find previous */
@ -982,6 +994,4 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainpositionTV(t, key);
}
int luaH_isdummy (const Table *t) { return isdummy(t); }
#endif

View file

@ -53,7 +53,6 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t);
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
LUAI_FUNC int luaH_isdummy (const Table *t);
#endif

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define ltablib_c
#define LUA_LIB
#include "libc/calls/calls.h"
#include "libc/calls/weirdtypes.h"
#include "libc/str/str.h"
@ -76,8 +77,9 @@ static void checktab (lua_State *L, int arg, int what) {
static int tinsert (lua_State *L) {
lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
lua_Integer pos; /* where to insert new element */
lua_Integer e = aux_getn(L, 1, TAB_RW);
e = luaL_intop(+, e, 1); /* first empty element */
switch (lua_gettop(L)) {
case 2: { /* called with only 2 arguments */
pos = e; /* insert new element at the end */
@ -109,7 +111,7 @@ static int tremove (lua_State *L) {
lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */
/* check whether 'pos' is in [1, size + 1] */
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1,
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
"position out of bounds");
lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) {
@ -164,7 +166,7 @@ static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
lua_geti(L, 1, i);
if (l_unlikely(!lua_isstring(L, -1)))
luaL_error(L, "invalid value (%s) at index %I in table for 'concat'",
luaL_typename(L, -1), i);
luaL_typename(L, -1), (LUAI_UACINT)i);
luaL_addvalue(b);
}

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define ltests_c
#define LUA_CORE
#include "third_party/lua/lapi.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lcode.h"
@ -55,7 +56,7 @@ __static_yoink("lua_notice");
void *l_Trick = 0;
#define obj_at(L,k) s2v(L->ci->func + (k))
#define obj_at(L,k) s2v(L->ci->func.p + (k))
static int runC (lua_State *L, lua_State *L1, const char *pc);
@ -68,7 +69,7 @@ static void setnameval (lua_State *L, const char *name, int val) {
static void pushobject (lua_State *L, const TValue *o) {
setobj2s(L, L->top, o);
setobj2s(L, L->top.p, o);
api_incr_top(L);
}
@ -430,7 +431,7 @@ static void checkLclosure (global_State *g, LClosure *cl) {
if (uv) {
checkobjrefN(g, clgc, uv);
if (!upisopen(uv))
checkvalref(g, obj2gco(uv), uv->v);
checkvalref(g, obj2gco(uv), uv->v.p);
}
}
}
@ -439,7 +440,7 @@ static void checkLclosure (global_State *g, LClosure *cl) {
static int lua_checkpc (CallInfo *ci) {
if (!isLua(ci)) return 1;
else {
StkId f = ci->func;
StkId f = ci->func.p;
Proto *p = clLvalue(s2v(f))->p;
return p->code <= ci->u.l.savedpc &&
ci->u.l.savedpc <= p->code + p->sizecode;
@ -452,19 +453,19 @@ static void checkstack (global_State *g, lua_State *L1) {
CallInfo *ci;
UpVal *uv;
assert(!isdead(g, L1));
if (L1->stack == NULL) { /* incomplete thread? */
if (L1->stack.p == NULL) { /* incomplete thread? */
assert(L1->openupval == NULL && L1->ci == NULL);
return;
}
for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next)
assert(upisopen(uv)); /* must be open */
assert(L1->top <= L1->stack_last);
assert(L1->tbclist <= L1->top);
assert(L1->top.p <= L1->stack_last.p);
assert(L1->tbclist.p <= L1->top.p);
for (ci = L1->ci; ci != NULL; ci = ci->previous) {
assert(ci->top <= L1->stack_last);
assert(ci->top.p <= L1->stack_last.p);
assert(lua_checkpc(ci));
}
for (o = L1->stack; o < L1->stack_last; o++)
for (o = L1->stack.p; o < L1->stack_last.p; o++)
checkliveness(L1, s2v(o)); /* entire stack must have valid values */
}
@ -476,7 +477,7 @@ static void checkrefs (global_State *g, GCObject *o) {
break;
}
case LUA_VUPVAL: {
checkvalref(g, o, gco2upv(o)->v);
checkvalref(g, o, gco2upv(o)->v.p);
break;
}
case LUA_VTABLE: {
@ -544,7 +545,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead,
static lu_mem checkgraylist (global_State *g, GCObject *o) {
int total = 0; /* count number of elements in the list */
((void)g); /* better to keep it available if we need to print an object */
cast_void(g); /* better to keep it if we need to print an object */
while (o) {
assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2));
assert(!testbit(o->marked, TESTBIT));
@ -991,7 +992,7 @@ static int hash_query (lua_State *L) {
static int stacklevel (lua_State *L) {
unsigned long a = 0;
lua_pushinteger(L, (L->top - L->stack));
lua_pushinteger(L, (L->top.p - L->stack.p));
lua_pushinteger(L, stacksize(L));
lua_pushinteger(L, L->nCcalls);
lua_pushinteger(L, L->nci);
@ -1051,7 +1052,7 @@ static int string_query (lua_State *L) {
TString *ts;
int n = 0;
for (ts = tb->hash[s]; ts != NULL; ts = ts->u.hnext) {
setsvalue2s(L, L->top, ts);
setsvalue2s(L, L->top.p, ts);
api_incr_top(L);
n++;
}
@ -1066,7 +1067,7 @@ static int tref (lua_State *L) {
luaL_checkany(L, 1);
lua_pushvalue(L, 1);
lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX));
(void)level; /* to avoid warnings */
cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level+1); /* +1 for result */
return 1;
}
@ -1074,7 +1075,7 @@ static int tref (lua_State *L) {
static int getref (lua_State *L) {
int level = lua_gettop(L);
lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkinteger(L, 1));
(void)level; /* to avoid warnings */
cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level+1);
return 1;
}
@ -1082,7 +1083,7 @@ static int getref (lua_State *L) {
static int unref (lua_State *L) {
int level = lua_gettop(L);
luaL_unref(L, LUA_REGISTRYINDEX, cast_int(luaL_checkinteger(L, 1)));
(void)level; /* to avoid warnings */
cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level);
return 0;
}
@ -1258,7 +1259,7 @@ static int panicback (lua_State *L) {
b = (struct Aux *)lua_touserdata(L, -1);
lua_pop(L, 1); /* remove 'Aux' struct */
runC(b->L, L, b->paniccode); /* run optional panic code */
gclongjmp(b->jb, 1);
gclongjmp(b->jb, 1); // [jart]
return 1; /* to avoid warnings */
}
@ -1544,7 +1545,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
lua_newthread(L1);
}
else if EQ("resetthread") {
lua_pushinteger(L1, lua_resetthread(L1));
lua_pushinteger(L1, lua_resetthread(L1)); /* deprecated */
}
else if EQ("newuserdata") {
lua_newuserdata(L1, getnum);
@ -1719,7 +1720,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
lua_error(L1);
}
else if EQ("abort") {
__die();
__die(); // [jart]
}
else if EQ("throw") {
#if defined(__cplusplus)
@ -1751,9 +1752,12 @@ static struct X { int x; } x;
else if EQ("tostring") {
const char *s = lua_tostring(L1, getindex);
const char *s1 = lua_pushstring(L1, s);
(void)s1; /* to avoid warnings */
cast_void(s1); /* to avoid warnings */
lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0);
}
else if EQ("Ltolstring") {
luaL_tolstring(L1, getindex, NULL);
}
else if EQ("type") {
lua_pushstring(L1, luaL_typename(L1, getnum));
}

View file

@ -1,5 +1,6 @@
#ifndef ltests_h
#define ltests_h
#include "third_party/lua/lua.h"
@ -117,6 +118,13 @@ LUA_API void *debug_realloc (void *ud, void *block,
#define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; }
/*
** This one is not compatible with tests for opcode optimizations,
** as it blocks some optimizations
#define MAXINDEXRK 0
*/
/* make stack-overflow tests run faster */
#undef LUAI_MAXSTACK
#define LUAI_MAXSTACK 50000

41
third_party/lua/ltm.c vendored
View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define ltm_c
#define LUA_CORE
#include "third_party/lua/ldebug.h"
#include "third_party/lua/ldo.h"
#include "third_party/lua/lgc.h"
@ -118,12 +119,12 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3) {
StkId func = L->top;
StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
setobj2s(L, func + 3, p3); /* 3rd argument */
L->top = func + 4;
L->top.p = func + 4;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 0);
@ -135,18 +136,18 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, StkId res) {
ptrdiff_t result = savestack(L, res);
StkId func = L->top;
StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
L->top += 3;
L->top.p += 3;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 1);
else
luaD_callnoyield(L, func, 1);
res = restorestack(L, result);
setobjs2s(L, res, --L->top); /* move result to its place */
setobjs2s(L, res, --L->top.p); /* move result to its place */
}
@ -181,7 +182,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
void luaT_tryconcatTM (lua_State *L) {
StkId top = L->top;
StkId top = L->top.p;
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
TM_CONCAT)))
luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
@ -216,15 +217,15 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
*/
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) {
if (callbinTM(L, p1, p2, L->top, event)) /* try original event */
return !l_isfalse(s2v(L->top));
if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */
return !l_isfalse(s2v(L->top.p));
#if defined(LUA_COMPAT_LT_LE)
else if (event == TM_LE) {
/* try '!(p2 < p1)' for '(p1 <= p2)' */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
if (callbinTM(L, p2, p1, L->top, TM_LT)) {
if (callbinTM(L, p2, p1, L->top.p, TM_LT)) {
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
return l_isfalse(s2v(L->top));
return l_isfalse(s2v(L->top.p));
}
/* else error will remove this 'ci'; no need to clear mark */
}
@ -254,20 +255,20 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
const Proto *p) {
int i;
int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */
int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */
int nextra = actual - nfixparams; /* number of extra arguments */
ci->u.l.nextraargs = nextra;
luaD_checkstack(L, p->maxstacksize + 1);
/* copy function to the top of the stack */
setobjs2s(L, L->top++, ci->func);
setobjs2s(L, L->top.p++, ci->func.p);
/* move fixed parameters to the top of the stack */
for (i = 1; i <= nfixparams; i++) {
setobjs2s(L, L->top++, ci->func + i);
setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */
setobjs2s(L, L->top.p++, ci->func.p + i);
setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
}
ci->func += actual + 1;
ci->top += actual + 1;
lua_assert(L->top <= ci->top && ci->top <= L->stack_last);
ci->func.p += actual + 1;
ci->top.p += actual + 1;
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
}
@ -277,10 +278,10 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
if (wanted < 0) {
wanted = nextra; /* get all extra arguments available */
checkstackGCp(L, nextra, where); /* ensure stack space */
L->top = where + nextra; /* next instruction will need top */
L->top.p = where + nextra; /* next instruction will need top */
}
for (i = 0; i < wanted && i < nextra; i++)
setobjs2s(L, where + i, ci->func - nextra + i);
setobjs2s(L, where + i, ci->func.p - nextra + i);
for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i));
}

13
third_party/lua/ltm.h vendored
View file

@ -1,9 +1,18 @@
#ifndef ltm_h
#define ltm_h
#include "third_party/lua/lobject.h"
#include "third_party/lua/lstate.h"
#include "third_party/lua/luaconf.h"
#include "third_party/lua/tms.h"
/*
* WARNING: if you change the order of this enumeration,
* grep "ORDER TM" and "ORDER OP"
*/
// [jart] moved to tms.h
/*
** Mask with 1 in all fast-access methods. A 1 in any of these bits
** in the flag of a (meta)table means the metatable does not have the
@ -54,8 +63,8 @@ LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
int inv, int isfloat, TMS event);
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
struct CallInfo *ci, const Proto *p);
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
CallInfo *ci, const Proto *p);
LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
StkId where, int wanted);

30
third_party/lua/lua.h vendored
View file

@ -1,18 +1,21 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_LUA_LUA_H_
#define COSMOPOLITAN_THIRD_PARTY_LUA_LUA_H_
#include "third_party/lua/luaconf.h"
COSMOPOLITAN_C_START_
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4"
#define LUA_VERSION_RELEASE "3"
#define LUA_VERSION_RELEASE "6"
#define LUA_VERSION_NUM 504
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 0)
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2021 Lua.org, PUC-Rio"
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@ -118,6 +121,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
/*
** Type used by the debug API to collect debug information
*/
typedef struct lua_Debug lua_Debug;
/*
** Functions to be called by the debugger in specific events
*/
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
/*
@ -140,7 +153,8 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API int (lua_resetthread) (lua_State *L);
LUA_API int (lua_closethread) (lua_State *L, lua_State *from);
LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
@ -429,12 +443,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debugger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
@ -477,7 +485,7 @@ struct lua_Debug {
/* }====================================================================== */
extern const char *g_lua_path_default;
extern const char *g_lua_path_default; // [jart]
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_THIRD_PARTY_LUA_LUA_H_ */

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -26,6 +26,7 @@
*/
#define lua_c
#include "third_party/lua/lua.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
@ -52,6 +53,7 @@
#include "tool/args/args.h"
__static_yoink("lua_notice");
STATIC_STACK_ALIGN(GetStackSize());
#if !defined(LUA_PROGNAME)
@ -81,7 +83,8 @@ static void print_usage (const char *badoption) {
"Available options are:\n"
" -e stat execute string 'stat'\n"
" -i enter interactive mode after executing 'script'\n"
" -l name require library 'name' into global 'name'\n"
" -l mod require library 'mod' into global 'mod'\n"
" -l g=mod require library 'mod' into global 'g'\n"
" -v show version information\n"
" -E ignore environment variables\n"
" -W turn warnings on\n"
@ -105,10 +108,11 @@ static void print_version (void) {
** to the script (everything after 'script') go to positive indices;
** other arguments (before the script name) go to negative indices.
** If there is no script name, assume interpreter's name as base.
** (If there is no interpreter's name either, 'script' is -1, so
** table sizes are zero.)
*/
static void createargtable (lua_State *L, char **argv, int argc, int script) {
int i, narg;
if (script == argc) script = 0; /* no script name? */
narg = argc - (script + 1); /* number of positive indices */
lua_createtable(L, narg, script + 1);
for (i = 0; i < argc; i++) {
@ -136,16 +140,22 @@ static int dostring (lua_State *L, const char *s, const char *name) {
/*
** Calls 'require(name)' and stores the result in a global variable
** with the given name.
** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
*/
static int dolibrary (lua_State *L, const char *name) {
static int dolibrary (lua_State *L, char *globname) {
int status;
char *modname = strchr(globname, '=');
if (modname == NULL) /* no explicit name? */
modname = globname; /* module name is equal to global name */
else {
*modname = '\0'; /* global name ends here */
modname++; /* module name starts after the '=' */
}
lua_getglobal(L, "require");
lua_pushstring(L, name);
status = lua_runchunk(L, 1, 1); /* call 'require(name)' */
lua_pushstring(L, modname);
status = lua_runchunk(L, 1, 1); /* call 'require(modname)' */
if (status == LUA_OK)
lua_setglobal(L, name); /* global[name] = require return */
lua_setglobal(L, globname); /* globname = require(modname) */
return lua_report(L, status);
}
@ -190,14 +200,23 @@ static int handle_script (lua_State *L, char **argv) {
/*
** Traverses all arguments from 'argv', returning a mask with those
** needed before running any Lua code (or an error code if it finds
** any invalid argument). 'first' returns the first not-handled argument
** (either the script name or a bad argument in case of error).
** needed before running any Lua code or an error code if it finds any
** invalid argument. In case of error, 'first' is the index of the bad
** argument. Otherwise, 'first' is -1 if there is no program name,
** 0 if there is no script name, or the index of the script name.
*/
static int collectargs (char **argv, int *first) {
int args = 0;
int i;
for (i = 1; argv[i] != NULL; i++) {
if (argv[0] != NULL) { /* is there a program name? */
if (argv[0][0]) /* not empty? */
lua_progname = argv[0]; /* save it */
}
else { /* no program name */
*first = -1;
return 0;
}
for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
*first = i;
if (argv[i][0] != '-') /* not an option? */
return args; /* stop handling options */
@ -238,7 +257,7 @@ static int collectargs (char **argv, int *first) {
return has_error;
}
}
*first = i; /* no script name */
*first = 0; /* no script name */
return args;
}
@ -256,7 +275,7 @@ static int runargs (lua_State *L, char **argv, int n) {
switch (option) {
case 'e': case 'l': {
int status;
const char *extra = argv[i] + 2; /* both options need an argument */
char *extra = argv[i] + 2; /* both options need an argument */
if (*extra == '\0') extra = argv[++i];
lua_assert(extra != NULL);
status = (option == 'e')
@ -344,9 +363,8 @@ static int pmain (lua_State *L) {
char **argv = (char **)lua_touserdata(L, 2);
int script;
int args = collectargs(argv, &script);
int optlim = (script > 0) ? script : argc; /* first argv not an option */
luaL_checkversion(L); /* check that interpreter has correct version */
lua_progname = LUA_PROGNAME;
if (argv[0] && argv[0][0]) lua_progname = argv[0];
if (args == has_error) { /* bad arg? */
print_usage(argv[script]); /* 'script' has index of bad arg. */
return 0;
@ -361,19 +379,21 @@ static int pmain (lua_State *L) {
luaL_requiref(L, "unix", LuaUnix, 1);
lua_pop(L, 1);
createargtable(L, argv, argc, script); /* create table 'arg' */
lua_gc(L, LUA_GCGEN, 0, 0); /* GC in generational mode */
lua_gc(L, LUA_GCRESTART); /* start GC... */
lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */
if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */
}
if (!runargs(L, argv, script)) /* execute arguments -e and -l */
if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */
return 0; /* something failed */
if (script < argc && /* execute main script (if there is one) */
handle_script(L, argv + script) != LUA_OK)
return 0;
if (script > 0) { /* execute main script (if there is one) */
if (handle_script(L, argv + script) != LUA_OK)
return 0; /* interrupt in case of error */
}
if (args & has_i) /* -i option? */
doREPL(L); /* do read-eval-print loop */
else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */
else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
if (lua_stdin_is_tty()) { /* running in interactive mode? */
print_version();
doREPL(L); /* do read-eval-print loop */
@ -397,6 +417,7 @@ int main (int argc, char **argv) {
lua_l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
}
lua_gc(L, LUA_GCSTOP); /* stop GC while building state */
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
lua_pushinteger(L, argc); /* 1st argument */
lua_pushlightuserdata(L, argv); /* 2nd argument */

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define luac_c
#define LUA_CORE
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/errno.h"
@ -45,6 +46,7 @@
#include "third_party/lua/lundump.h"
__static_yoink("lua_notice");
static void PrintFunction(const Proto* f, int full);
#define luaU_print PrintFunction
@ -141,7 +143,7 @@ static int doargs(int argc, char* argv[])
return i;
}
#define FUNCTION "(function()end)();"
#define FUNCTION "(function()end)();\n"
static const char* reader(lua_State* L, void* ud, size_t* size)
{
@ -158,7 +160,7 @@ static const char* reader(lua_State* L, void* ud, size_t* size)
}
}
#define toproto(L,i) getproto(s2v(L->top+(i)))
#define toproto(L,i) getproto(s2v(L->top.p+(i)))
static const Proto* combine(lua_State* L, int n)
{
@ -175,7 +177,6 @@ static const Proto* combine(lua_State* L, int n)
f->p[i]=toproto(L,i-n-1);
if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
}
f->sizelineinfo=0;
return f;
}
}
@ -620,11 +621,11 @@ static void PrintCode(const Proto* f)
if (c==0) printf("all out"); else printf("%d out",c-1);
break;
case OP_TAILCALL:
printf("%d %d %d",a,b,c);
printf("%d %d %d%s",a,b,c,ISK);
printf(COMMENT "%d in",b-1);
break;
case OP_RETURN:
printf("%d %d %d",a,b,c);
printf("%d %d %d%s",a,b,c,ISK);
printf(COMMENT);
if (b==0) printf("all out"); else printf("%d out",b-1);
break;
@ -639,7 +640,7 @@ static void PrintCode(const Proto* f)
break;
case OP_FORPREP:
printf("%d %d",a,bx);
printf(COMMENT "to %d",pc+bx+2);
printf(COMMENT "exit to %d",pc+bx+3);
break;
case OP_TFORPREP:
printf("%d %d",a,bx);

View file

@ -1,5 +1,6 @@
#ifndef luaconf_h
#define luaconf_h
#include "libc/assert.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
@ -7,8 +8,9 @@
#include "libc/stdio/stdio.h"
#include "libc/str/unicode.h"
#define LUA_USE_POSIX
#define LUA_USE_LINENOISE
#define LUA_USE_POSIX
/*
@ -69,6 +71,12 @@
#endif
#if defined(LUA_USE_IOS)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN
#endif
/*
@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
*/
@ -422,7 +430,6 @@
@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
@@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED.
@@ LUA_UNSIGNEDBITS is the number of bits in a LUA_UNSIGNED.
@@ lua_integer2str converts an integer to a string.
*/
@ -443,9 +450,6 @@
#define LUA_UNSIGNED unsigned LUAI_UACINT
#define LUA_UNSIGNEDBITS (sizeof(LUA_UNSIGNED) * CHAR_BIT)
/* now the variable definitions */
#if LUA_INT_TYPE == LUA_INT_INT /* { int */
@ -667,7 +671,7 @@
** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices).
** (It must fit into max(size_t)/32.)
** (It must fit into max(size_t)/32 and max(int)/2.)
*/
#if LUAI_IS32INT
#define LUAI_MAXSTACK 1000000
@ -686,14 +690,15 @@
/*
@@ LUA_IDSIZE gives the maximum size for the description of the source
@@ of a function in debug information.
** of a function in debug information.
** CHANGE it if you want a different size.
*/
#define LUA_IDSIZE 60
/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
** buffer system.
*/
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))

View file

@ -1,5 +1,6 @@
#ifndef lualib_h
#define lualib_h
#include "third_party/lua/lua.h"

View file

@ -1,9 +1,30 @@
/*
** $Id: lundump.c $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Lua
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define lundump_c
#define LUA_CORE
@ -18,6 +39,7 @@
#include "third_party/lua/lua.h"
#include "third_party/lua/lundump.h"
#include "third_party/lua/lzio.h"
__static_yoink("lua_notice");
#if !defined(luai_verifycode)
@ -115,10 +137,10 @@ static TString *loadStringN (LoadState *S, Proto *p) {
}
else { /* long string */
ts = luaS_createlngstrobj(L, size); /* create string */
setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
luaD_inctop(L);
loadVector(S, getstr(ts), size); /* load directly in final place */
L->top--; /* pop string */
L->top.p--; /* pop string */
}
luaC_objbarrier(L, p, ts);
return ts;
@ -243,6 +265,8 @@ static void loadDebug (LoadState *S, Proto *f) {
f->locvars[i].endpc = loadInt(S);
}
n = loadInt(S);
if (n != 0) /* does it have debug information? */
n = f->sizeupvalues; /* must be this many */
for (i = 0; i < n; i++)
f->upvalues[i].name = loadStringN(S, f);
}
@ -316,7 +340,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
S.Z = Z;
checkHeader(&S);
cl = luaF_newLclosure(L, loadByte(&S));
setclLvalue2s(L, L->top, cl);
setclLvalue2s(L, L->top.p, cl);
luaD_inctop(L);
cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);

View file

@ -1,5 +1,6 @@
#ifndef lundump_h
#define lundump_h
#include "third_party/lua/llimits.h"
#include "third_party/lua/lobject.h"
#include "third_party/lua/lzio.h"

View file

@ -1,9 +1,30 @@
/*
** $Id: lutf8lib.c $
** Standard library for UTF-8 manipulation
** See Copyright Notice in lua.h
*/
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Lua
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define lutf8lib_c
#define LUA_LIB
@ -11,12 +32,16 @@
#include "third_party/lua/lprefix.h"
#include "third_party/lua/lua.h"
#include "third_party/lua/lualib.h"
__static_yoink("lua_notice");
#define MAXUNICODE 0x10FFFFu
#define MAXUTF 0x7FFFFFFFu
#define MSGInvalid "invalid UTF-8 code"
/*
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
*/
@ -27,7 +52,8 @@ typedef unsigned long utfint;
#endif
#define iscont(p) ((*(p) & 0xC0) == 0x80)
#define iscont(c) (((c) & 0xC0) == 0x80)
#define iscontp(p) iscont(*(p))
/* from strlib */
@ -57,7 +83,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
int count = 0; /* to count number of continuation bytes */
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
if (!iscont(cc)) /* not a continuation byte? */
return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
}
@ -132,7 +158,7 @@ static int codepoint (lua_State *L) {
utfint code;
s = utf8_decode(s, &code, !lax);
if (s == NULL)
return luaL_error(L, "invalid UTF-8 code");
return luaL_error(L, MSGInvalid);
lua_pushinteger(L, code);
n++;
}
@ -182,16 +208,16 @@ static int byteoffset (lua_State *L) {
"position out of bounds");
if (n == 0) {
/* find beginning of current byte sequence */
while (posi > 0 && iscont(s + posi)) posi--;
while (posi > 0 && iscontp(s + posi)) posi--;
}
else {
if (iscont(s + posi))
if (iscontp(s + posi))
return luaL_error(L, "initial position is a continuation byte");
if (n < 0) {
while (n < 0 && posi > 0) { /* move back */
do { /* find beginning of previous character */
posi--;
} while (posi > 0 && iscont(s + posi));
} while (posi > 0 && iscontp(s + posi));
n++;
}
}
@ -200,7 +226,7 @@ static int byteoffset (lua_State *L) {
while (n > 0 && posi < (lua_Integer)len) {
do { /* find beginning of next character */
posi++;
} while (iscont(s + posi)); /* (cannot pass final '\0') */
} while (iscontp(s + posi)); /* (cannot pass final '\0') */
n--;
}
}
@ -216,20 +242,17 @@ static int byteoffset (lua_State *L) {
static int iter_aux (lua_State *L, int strict) {
size_t len;
const char *s = luaL_checklstring(L, 1, &len);
lua_Integer n = lua_tointeger(L, 2) - 1;
if (n < 0) /* first iteration? */
n = 0; /* start from here */
else if (n < (lua_Integer)len) {
n++; /* skip current byte */
while (iscont(s + n)) n++; /* and its continuations */
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
if (n < len) {
while (iscontp(s + n)) n++; /* go to next character */
}
if (n >= (lua_Integer)len)
if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */
else {
utfint code;
const char *next = utf8_decode(s + n, &code, strict);
if (next == NULL)
return luaL_error(L, "invalid UTF-8 code");
if (next == NULL || iscontp(next))
return luaL_error(L, MSGInvalid);
lua_pushinteger(L, n + 1);
lua_pushinteger(L, code);
return 2;
@ -248,7 +271,8 @@ static int iter_auxlax (lua_State *L) {
static int iter_codes (lua_State *L) {
int lax = lua_toboolean(L, 2);
luaL_checkstring(L, 1);
const char *s = luaL_checkstring(L, 1);
luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
lua_pushvalue(L, 1);
lua_pushinteger(L, 0);

234
third_party/lua/lvm.c vendored
View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lvm_c
#define LUA_CORE
#include "libc/str/str.h"
#include "third_party/lua/ldebug.h"
#include "third_party/lua/ldo.h"
@ -419,7 +420,7 @@ static int l_strcmp (const TString *ls, const TString *rs) {
** from float to int.)
** When 'f' is NaN, comparisons must result in false.
*/
static int LTintfloat (lua_Integer i, lua_Number f) {
l_sinline int LTintfloat (lua_Integer i, lua_Number f) {
if (l_intfitsf(i))
return luai_numlt(cast_num(i), f); /* compare them as floats */
else { /* i < f <=> i < ceil(f) */
@ -436,7 +437,7 @@ static int LTintfloat (lua_Integer i, lua_Number f) {
** Check whether integer 'i' is less than or equal to float 'f'.
** See comments on previous function.
*/
static int LEintfloat (lua_Integer i, lua_Number f) {
l_sinline int LEintfloat (lua_Integer i, lua_Number f) {
if (l_intfitsf(i))
return luai_numle(cast_num(i), f); /* compare them as floats */
else { /* i <= f <=> i <= floor(f) */
@ -453,7 +454,7 @@ static int LEintfloat (lua_Integer i, lua_Number f) {
** Check whether float 'f' is less than integer 'i'.
** See comments on previous function.
*/
static int LTfloatint (lua_Number f, lua_Integer i) {
l_sinline int LTfloatint (lua_Number f, lua_Integer i) {
if (l_intfitsf(i))
return luai_numlt(f, cast_num(i)); /* compare them as floats */
else { /* f < i <=> floor(f) < i */
@ -470,7 +471,7 @@ static int LTfloatint (lua_Number f, lua_Integer i) {
** Check whether float 'f' is less than or equal to integer 'i'.
** See comments on previous function.
*/
static int LEfloatint (lua_Number f, lua_Integer i) {
l_sinline int LEfloatint (lua_Number f, lua_Integer i) {
if (l_intfitsf(i))
return luai_numle(f, cast_num(i)); /* compare them as floats */
else { /* f <= i <=> ceil(f) <= i */
@ -486,7 +487,7 @@ static int LEfloatint (lua_Number f, lua_Integer i) {
/*
** Return 'l < r', for numbers.
*/
static int LTnum (const TValue *l, const TValue *r) {
l_sinline int LTnum (const TValue *l, const TValue *r) {
lua_assert(ttisnumber(l) && ttisnumber(r));
if (ttisinteger(l)) {
lua_Integer li = ivalue(l);
@ -508,7 +509,7 @@ static int LTnum (const TValue *l, const TValue *r) {
/*
** Return 'l <= r', for numbers.
*/
static int LEnum (const TValue *l, const TValue *r) {
l_sinline int LEnum (const TValue *l, const TValue *r) {
lua_assert(ttisnumber(l) && ttisnumber(r));
if (ttisinteger(l)) {
lua_Integer li = ivalue(l);
@ -621,8 +622,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (tm == NULL) /* no TM? */
return 0; /* objects are different */
else {
luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */
return !l_isfalse(s2v(L->top));
luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
return !l_isfalse(s2v(L->top.p));
}
}
@ -646,17 +647,17 @@ static void copy2buff (StkId top, int n, char *buff) {
/*
** Main operation for concatenation: concat 'total' values in the stack,
** from 'L->top - total' up to 'L->top - 1'.
** from 'L->top.p - total' up to 'L->top.p - 1'.
*/
void luaV_concat (lua_State *L, int total) {
if (total == 1)
return; /* "all" values already concatenated */
do {
StkId top = L->top;
StkId top = L->top.p;
int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) ||
!tostring(L, s2v(top - 1)))
luaT_tryconcatTM(L);
luaT_tryconcatTM(L); /* may invalidate 'top' */
else if (isemptystr(s2v(top - 1))) /* second operand is empty? */
cast_void(tostring(L, s2v(top - 2))); /* result is first operand */
else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */
@ -669,8 +670,10 @@ void luaV_concat (lua_State *L, int total) {
/* collect total length and number of strings */
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
size_t l = vslen(s2v(top - n - 1));
if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) {
L->top.p = top - total; /* pop strings to avoid wasting stack */
luaG_runerror(L, "string length overflow");
}
tl += l;
}
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
@ -684,8 +687,8 @@ void luaV_concat (lua_State *L, int total) {
}
setsvalue2s(L, top - n, ts); /* create result */
}
total -= n-1; /* got 'n' strings to create 1 new */
L->top -= n-1; /* popped 'n' strings and pushed one */
total -= n - 1; /* got 'n' strings to create one new */
L->top.p -= n - 1; /* popped 'n' strings and pushed one */
} while (total > 1); /* repeat until only 1 result left */
}
@ -776,11 +779,10 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
/* number of bits in an integer */
#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
/*
** Shift left operation. (Shift right just negates 'y'.)
*/
#define luaV_shiftr(x,y) luaV_shiftl(x,-(y))
lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
if (y < 0) { /* shift right? */
if (y <= -NBITS) return 0;
@ -820,26 +822,26 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
*/
void luaV_finishOp (lua_State *L) {
CallInfo *ci = L->ci;
StkId base = ci->func + 1;
StkId base = ci->func.p + 1;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top);
setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p);
break;
}
case OP_UNM: case OP_BNOT: case OP_LEN:
case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
case OP_GETFIELD: case OP_SELF: {
setobjs2s(L, base + GETARG_A(inst), --L->top);
setobjs2s(L, base + GETARG_A(inst), --L->top.p);
break;
}
case OP_LT: case OP_LE:
case OP_LTI: case OP_LEI:
case OP_GTI: case OP_GEI:
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
int res = !l_isfalse(s2v(L->top - 1));
L->top--;
int res = !l_isfalse(s2v(L->top.p - 1));
L->top.p--;
#if defined(LUA_COMPAT_LT_LE)
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
ci->callstatus ^= CIST_LEQ; /* clear mark */
@ -852,18 +854,27 @@ void luaV_finishOp (lua_State *L) {
break;
}
case OP_CONCAT: {
StkId top = L->top - 1; /* top when 'luaT_tryconcatTM' was called */
StkId top = L->top.p - 1; /* top when 'luaT_tryconcatTM' was called */
int a = GETARG_A(inst); /* first element to concatenate */
int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
setobjs2s(L, top - 2, top); /* put TM result in proper position */
L->top = top - 1; /* top is one after last element (at top-2) */
L->top.p = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total); /* concat them (may yield again) */
break;
}
case OP_CLOSE: case OP_RETURN: { /* yielded closing variables */
case OP_CLOSE: { /* yielded closing variables */
ci->u.l.savedpc--; /* repeat instruction to close other vars. */
break;
}
case OP_RETURN: { /* yielded closing variables */
StkId ra = base + GETARG_A(inst);
/* adjust top to signal correct number of returns, in case the
return is "up to top" ('isIT') */
L->top.p = ra + ci->u2.nres;
/* repeat instruction to close other vars. and complete the return */
ci->u.l.savedpc--;
break;
}
default: {
/* only these other opcodes can yield */
lua_assert(op == OP_TFORCALL || op == OP_CALL ||
@ -901,6 +912,7 @@ void luaV_finishOp (lua_State *L) {
** operation, 'fop' is the float operation.
*/
#define op_arithI(L,iop,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
int imm = GETARG_sC(i); \
if (ttisinteger(v1)) { \
@ -929,6 +941,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over floats and others with register operands.
*/
#define op_arithf(L,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
op_arithf_aux(L, v1, v2, fop); }
@ -938,6 +951,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations with K operands for floats.
*/
#define op_arithfK(L,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arithf_aux(L, v1, v2, fop); }
@ -947,6 +961,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over integers and floats.
*/
#define op_arith_aux(L,v1,v2,iop,fop) { \
StkId ra = RA(i); \
if (ttisinteger(v1) && ttisinteger(v2)) { \
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
@ -976,6 +991,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with constant operand.
*/
#define op_bitwiseK(L,op) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \
lua_Integer i1; \
@ -989,6 +1005,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with register operands.
*/
#define op_bitwise(L,op) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
lua_Integer i1; lua_Integer i2; \
@ -1003,6 +1020,7 @@ void luaV_finishOp (lua_State *L) {
** integers.
*/
#define op_order(L,opi,opn,other) { \
StkId ra = RA(i); \
int cond; \
TValue *rb = vRB(i); \
if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
@ -1022,6 +1040,7 @@ void luaV_finishOp (lua_State *L) {
** always small enough to have an exact representation as a float.)
*/
#define op_orderI(L,opi,opf,inv,tm) { \
StkId ra = RA(i); \
int cond; \
int im = GETARG_sB(i); \
if (ttisinteger(s2v(ra))) \
@ -1064,7 +1083,7 @@ void luaV_finishOp (lua_State *L) {
#define updatetrap(ci) (trap = ci->u.l.trap)
#define updatebase(ci) (base = ci->func + 1)
#define updatebase(ci) (base = ci->func.p + 1)
#define updatestack(ci) \
@ -1099,7 +1118,7 @@ void luaV_finishOp (lua_State *L) {
** Whenever code can raise errors, the global 'pc' and the global
** 'top' must be correct to report occasional errors.
*/
#define savestate(L,ci) (savepc(L), L->top = ci->top)
#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p)
/*
@ -1112,14 +1131,14 @@ void luaV_finishOp (lua_State *L) {
#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci))
/*
** Protect code that can only raise errors. (That is, it cannnot change
** Protect code that can only raise errors. (That is, it cannot change
** the stack or hooks.)
*/
#define halfProtect(exp) (savestate(L,ci), (exp))
/* 'c' is the limit of live values in the stack */
#define checkGC(L,c) \
{ luaC_condGC(L, (savepc(L), L->top = (c)), \
{ luaC_condGC(L, (savepc(L), L->top.p = (c)), \
updatetrap(ci)); \
luai_threadyield(L); }
@ -1131,7 +1150,6 @@ void luaV_finishOp (lua_State *L) {
updatebase(ci); /* correct stack */ \
} \
i = *(pc++); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
}
#define vmdispatch(o) switch(o)
@ -1151,7 +1169,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
startfunc:
trap = L->hookmask;
returning: /* trap already set */
cl = clLvalue(s2v(ci->func));
cl = clLvalue(s2v(ci->func.p));
k = cl->p->k;
pc = ci->u.l.savedpc;
if (l_unlikely(trap)) {
@ -1163,58 +1181,68 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
ci->u.l.trap = 1; /* assume trap is on, for now */
}
base = ci->func + 1;
base = ci->func.p + 1;
/* main loop of interpreter */
for (;;) {
Instruction i; /* instruction being executed */
StkId ra; /* instruction's A register */
vmfetch();
// low-level line tracing for debugging Lua
// printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
lua_assert(base == ci->func + 1);
lua_assert(base <= L->top && L->top < L->stack_last);
#if 0
/* low-level line tracing for debugging Lua */
printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
#endif
lua_assert(base == ci->func.p + 1);
lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p);
/* invalidate top for instructions not expecting it */
lua_assert(isIT(i) || (cast_void(L->top = base), 1));
lua_assert(isIT(i) || (cast_void(L->top.p = base), 1));
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
StkId ra = RA(i);
setobjs2s(L, ra, RB(i));
vmbreak;
}
vmcase(OP_LOADI) {
StkId ra = RA(i);
lua_Integer b = GETARG_sBx(i);
setivalue(s2v(ra), b);
vmbreak;
}
vmcase(OP_LOADF) {
StkId ra = RA(i);
int b = GETARG_sBx(i);
setfltvalue(s2v(ra), cast_num(b));
vmbreak;
}
vmcase(OP_LOADK) {
StkId ra = RA(i);
TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADKX) {
StkId ra = RA(i);
TValue *rb;
rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADFALSE) {
StkId ra = RA(i);
setbfvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LFALSESKIP) {
StkId ra = RA(i);
setbfvalue(s2v(ra));
pc++; /* skip next instruction */
vmbreak;
}
vmcase(OP_LOADTRUE) {
StkId ra = RA(i);
setbtvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LOADNIL) {
StkId ra = RA(i);
int b = GETARG_B(i);
do {
setnilvalue(s2v(ra++));
@ -1222,19 +1250,22 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETUPVAL) {
StkId ra = RA(i);
int b = GETARG_B(i);
setobj2s(L, ra, cl->upvals[b]->v);
setobj2s(L, ra, cl->upvals[b]->v.p);
vmbreak;
}
vmcase(OP_SETUPVAL) {
StkId ra = RA(i);
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, s2v(ra));
setobj(L, uv->v.p, s2v(ra));
luaC_barrier(L, uv, s2v(ra));
vmbreak;
}
vmcase(OP_GETTABUP) {
StkId ra = RA(i);
const TValue *slot;
TValue *upval = cl->upvals[GETARG_B(i)]->v;
TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i);
TString *key = tsvalue(rc); /* key must be a string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
@ -1245,6 +1276,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETTABLE) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = vRC(i);
@ -1259,6 +1291,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETI) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
int c = GETARG_C(i);
@ -1273,6 +1306,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETFIELD) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = KC(i);
@ -1286,7 +1320,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
vmcase(OP_SETTABUP) {
const TValue *slot;
TValue *upval = cl->upvals[GETARG_A(i)]->v;
TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
TValue *rb = KB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rb); /* key must be a string */
@ -1298,6 +1332,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SETTABLE) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i); /* key (table is in 'ra') */
TValue *rc = RKC(i); /* value */
@ -1312,6 +1347,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SETI) {
StkId ra = RA(i);
const TValue *slot;
int c = GETARG_B(i);
TValue *rc = RKC(i);
@ -1326,6 +1362,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SETFIELD) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = KB(i);
TValue *rc = RKC(i);
@ -1338,6 +1375,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_NEWTABLE) {
StkId ra = RA(i);
int b = GETARG_B(i); /* log2(hash size) + 1 */
int c = GETARG_C(i); /* array size */
Table *t;
@ -1347,7 +1385,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
if (TESTARG_k(i)) /* non-zero extra argument? */
c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */
pc++; /* skip extra argument */
L->top = ra + 1; /* correct top in case of emergency GC */
L->top.p = ra + 1; /* correct top in case of emergency GC */
t = luaH_new(L); /* memory allocation */
sethvalue2s(L, ra, t);
if (b != 0 || c != 0)
@ -1356,6 +1394,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SELF) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = RKC(i);
@ -1385,6 +1424,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MODK) {
savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_mod, luaV_modf);
vmbreak;
}
@ -1397,6 +1437,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_IDIVK) {
savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@ -1413,6 +1454,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SHRI) {
StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@ -1422,6 +1464,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SHLI) {
StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@ -1443,6 +1486,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MOD) {
savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_mod, luaV_modf);
vmbreak;
}
@ -1455,6 +1499,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_IDIV) { /* floor division */
savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@ -1479,6 +1524,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MMBIN) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *rb = vRB(i);
TMS tm = (TMS)GETARG_C(i);
@ -1488,6 +1534,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MMBINI) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
int imm = GETARG_sB(i);
TMS tm = (TMS)GETARG_C(i);
@ -1497,6 +1544,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MMBINK) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *imm = KB(i);
TMS tm = (TMS)GETARG_C(i);
@ -1506,6 +1554,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_UNM) {
StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Number nb;
if (ttisinteger(rb)) {
@ -1520,6 +1569,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_BNOT) {
StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Integer ib;
if (tointegerns(rb, &ib)) {
@ -1530,6 +1580,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_NOT) {
StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb))
setbtvalue(s2v(ra));
@ -1538,21 +1589,25 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_LEN) {
StkId ra = RA(i);
Protect(luaV_objlen(L, ra, vRB(i)));
vmbreak;
}
vmcase(OP_CONCAT) {
StkId ra = RA(i);
int n = GETARG_B(i); /* number of elements to concatenate */
L->top = ra + n; /* mark the end of concat operands */
L->top.p = ra + n; /* mark the end of concat operands */
ProtectNT(luaV_concat(L, n));
checkGC(L, L->top); /* 'luaV_concat' ensures correct top */
checkGC(L, L->top.p); /* 'luaV_concat' ensures correct top */
vmbreak;
}
vmcase(OP_CLOSE) {
StkId ra = RA(i);
Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak;
}
vmcase(OP_TBC) {
StkId ra = RA(i);
/* create new to-be-closed upvalue */
halfProtect(luaF_newtbcupval(L, ra));
vmbreak;
@ -1562,6 +1617,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_EQ) {
StkId ra = RA(i);
int cond;
TValue *rb = vRB(i);
Protect(cond = luaV_equalobj(L, s2v(ra), rb));
@ -1577,6 +1633,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_EQK) {
StkId ra = RA(i);
TValue *rb = KB(i);
/* basic types do not use '__eq'; we can use raw equality */
int cond = luaV_rawequalobj(s2v(ra), rb);
@ -1584,6 +1641,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_EQI) {
StkId ra = RA(i);
int cond;
int im = GETARG_sB(i);
if (ttisinteger(s2v(ra)))
@ -1612,11 +1670,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_TEST) {
StkId ra = RA(i);
int cond = !l_isfalse(s2v(ra));
docondjump();
vmbreak;
}
vmcase(OP_TESTSET) {
StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb) == GETARG_k(i))
pc++;
@ -1627,78 +1687,74 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_CALL) {
StkId ra = RA(i);
CallInfo *newci;
int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1;
if (b != 0) /* fixed number of arguments? */
L->top = ra + b; /* top signals number of arguments */
L->top.p = ra + b; /* top signals number of arguments */
/* else previous instruction set top */
savepc(L); /* in case of errors */
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
updatetrap(ci); /* C call; nothing else to be done */
else { /* Lua call: run function in this same C frame */
ci = newci;
ci->callstatus = 0; /* call re-uses 'luaV_execute' */
goto startfunc;
}
vmbreak;
}
vmcase(OP_TAILCALL) {
StkId ra = RA(i);
int b = GETARG_B(i); /* number of arguments + 1 (function) */
int n; /* number of results when calling a C function */
int nparams1 = GETARG_C(i);
/* delta is virtual 'func' - real 'func' (vararg functions) */
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
if (b != 0)
L->top = ra + b;
L->top.p = ra + b;
else /* previous instruction set top */
b = cast_int(L->top - ra);
b = cast_int(L->top.p - ra);
savepc(ci); /* several calls here can raise errors */
if (TESTARG_k(i)) {
luaF_closeupval(L, base); /* close upvalues from current call */
lua_assert(L->tbclist < base); /* no pending tbc variables */
lua_assert(base == ci->func + 1);
lua_assert(L->tbclist.p < base); /* no pending tbc variables */
lua_assert(base == ci->func.p + 1);
}
while (!ttisfunction(s2v(ra))) { /* not a function? */
luaD_tryfuncTM(L, ra); /* try '__call' metamethod */
b++; /* there is now one extra argument */
checkstackGCp(L, 1, ra);
}
if (!ttisLclosure(s2v(ra))) { /* C function? */
luaD_precall(L, ra, LUA_MULTRET); /* call it */
updatetrap(ci);
updatestack(ci); /* stack may have been relocated */
ci->func -= delta; /* restore 'func' (if vararg) */
luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */
if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
goto startfunc; /* execute the callee */
else { /* C function? */
ci->func.p -= delta; /* restore 'func' (if vararg) */
luaD_poscall(L, ci, n); /* finish caller */
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; /* caller returns after the tail call */
}
ci->func -= delta; /* restore 'func' (if vararg) */
luaD_pretailcall(L, ci, ra, b); /* prepare call frame */
goto startfunc; /* execute the callee */
}
vmcase(OP_RETURN) {
StkId ra = RA(i);
int n = GETARG_B(i) - 1; /* number of results */
int nparams1 = GETARG_C(i);
if (n < 0) /* not fixed? */
n = cast_int(L->top - ra); /* get what is available */
n = cast_int(L->top.p - ra); /* get what is available */
savepc(ci);
if (TESTARG_k(i)) { /* may there be open upvalues? */
if (L->top < ci->top)
L->top = ci->top;
ci->u2.nres = n; /* save number of returns */
if (L->top.p < ci->top.p)
L->top.p = ci->top.p;
luaF_close(L, base, CLOSEKTOP, 1);
updatetrap(ci);
updatestack(ci);
}
if (nparams1) /* vararg function? */
ci->func -= ci->u.l.nextraargs + nparams1;
L->top = ra + n; /* set call for 'luaD_poscall' */
ci->func.p -= ci->u.l.nextraargs + nparams1;
L->top.p = ra + n; /* set call for 'luaD_poscall' */
luaD_poscall(L, ci, n);
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret;
}
vmcase(OP_RETURN0) {
if (l_unlikely(L->hookmask)) {
L->top = ra;
StkId ra = RA(i);
L->top.p = ra;
savepc(ci);
luaD_poscall(L, ci, 0); /* no hurry... */
trap = 1;
@ -1706,15 +1762,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
else { /* do the 'poscall' here */
int nres;
L->ci = ci->previous; /* back to caller */
L->top = base - 1;
L->top.p = base - 1;
for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
setnilvalue(s2v(L->top++)); /* all results are nil */
setnilvalue(s2v(L->top.p++)); /* all results are nil */
}
goto ret;
}
vmcase(OP_RETURN1) {
if (l_unlikely(L->hookmask)) {
L->top = ra + 1;
StkId ra = RA(i);
L->top.p = ra + 1;
savepc(ci);
luaD_poscall(L, ci, 1); /* no hurry... */
trap = 1;
@ -1723,12 +1780,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
int nres = ci->nresults;
L->ci = ci->previous; /* back to caller */
if (nres == 0)
L->top = base - 1; /* asked for no results */
L->top.p = base - 1; /* asked for no results */
else {
StkId ra = RA(i);
setobjs2s(L, base - 1, ra); /* at least this result */
L->top = base;
L->top.p = base;
for (; l_unlikely(nres > 1); nres--)
setnilvalue(s2v(L->top++)); /* complete missing results */
setnilvalue(s2v(L->top.p++)); /* complete missing results */
}
}
ret: /* return from a Lua function */
@ -1740,6 +1798,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
}
vmcase(OP_FORLOOP) {
StkId ra = RA(i);
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
if (count > 0) { /* still more iterations? */
@ -1758,12 +1817,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_FORPREP) {
StkId ra = RA(i);
savestate(L, ci); /* in case of errors */
if (forprep(L, ra))
pc += GETARG_Bx(i) + 1; /* skip the loop */
vmbreak;
}
vmcase(OP_TFORPREP) {
StkId ra = RA(i);
/* create to-be-closed upvalue (if needed) */
halfProtect(luaF_newtbcupval(L, ra + 3));
pc += GETARG_Bx(i);
@ -1772,7 +1833,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
goto l_tforcall;
}
vmcase(OP_TFORCALL) {
l_tforcall:
l_tforcall: {
StkId ra = RA(i);
/* 'ra' has the iterator function, 'ra + 1' has the state,
'ra + 2' has the control variable, and 'ra + 3' has the
to-be-closed variable. The call will use the stack after
@ -1780,29 +1842,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
*/
/* push function, state, and control variable */
memcpy(ra + 4, ra, 3 * sizeof(*ra));
L->top = ra + 4 + 3;
L->top.p = ra + 4 + 3;
ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
updatestack(ci); /* stack may have changed */
i = *(pc++); /* go to next instruction */
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
goto l_tforloop;
}
}}
vmcase(OP_TFORLOOP) {
l_tforloop:
l_tforloop: {
StkId ra = RA(i);
if (!ttisnil(s2v(ra + 4))) { /* continue loop? */
setobjs2s(L, ra + 2, ra + 4); /* save control variable */
pc -= GETARG_Bx(i); /* jump back */
}
vmbreak;
}
}}
vmcase(OP_SETLIST) {
StkId ra = RA(i);
int n = GETARG_B(i);
unsigned int last = GETARG_C(i);
Table *h = hvalue(s2v(ra));
if (n == 0)
n = cast_int(L->top - ra) - 1; /* get up to the top */
n = cast_int(L->top.p - ra) - 1; /* get up to the top */
else
L->top = ci->top; /* correct top in case of emergency GC */
L->top.p = ci->top.p; /* correct top in case of emergency GC */
last += n;
if (TESTARG_k(i)) {
last += GETARG_Ax(*pc) * (MAXARG_C + 1);
@ -1819,12 +1883,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_CLOSURE) {
StkId ra = RA(i);
Proto *p = cl->p->p[GETARG_Bx(i)];
halfProtect(pushclosure(L, p, cl->upvals, base, ra));
checkGC(L, ra + 1);
vmbreak;
}
vmcase(OP_VARARG) {
StkId ra = RA(i);
int n = GETARG_C(i) - 1; /* required results */
Protect(luaT_getvarargs(L, ci, ra, n));
vmbreak;

View file

@ -1,5 +1,6 @@
#ifndef lvm_h
#define lvm_h
#include "third_party/lua/ldo.h"
#include "third_party/lua/lobject.h"
#include "third_party/lua/ltm.h"
@ -102,6 +103,11 @@ typedef enum {
luaC_barrierback(L, gcvalue(t), v); }
/*
** Shift right is the same as shift left with a negative 'y'
*/
#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);

View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -27,6 +27,7 @@
*/
#define lzio_c
#define LUA_CORE
#include "libc/str/str.h"
#include "third_party/lua/llimits.h"
#include "third_party/lua/lmem.h"

View file

@ -1,9 +1,3 @@
/*
** $Id: lzio.h $
** Buffered streams
** See Copyright Notice in lua.h
*/
#ifndef lzio_h
#define lzio_h

View file

@ -163,6 +163,7 @@ f()
dofile('db.lua')
assert(dofile('calls.lua') == deep and deep)
_G.deep = nil
olddofile('strings.lua')
olddofile('literals.lua')
dofile('tpack.lua')

View file

@ -14,7 +14,7 @@ local pack = table.pack
-- standard error message for memory errors
local MEMERRMSG = "not enough memory"
function tcheck (t1, t2)
local function tcheck (t1, t2)
assert(t1.n == (t2.n or #t2) + 1)
for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end
end
@ -28,7 +28,7 @@ end
print('testing C API')
a = T.testC("pushvalue R; return 1")
local a = T.testC("pushvalue R; return 1")
assert(a == debug.getregistry())
@ -43,10 +43,10 @@ a = T.d2s(12458954321123.0)
assert(a == string.pack("d", 12458954321123.0))
assert(T.s2d(a) == 12458954321123.0)
a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2")
local a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2")
assert(a == 2 and b == 3 and not c)
f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2")
local f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2")
a,b,c = f()
assert(a == 2 and b == 3 and not c)
@ -61,7 +61,7 @@ assert(a==false and b==true and c==false)
a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40)
assert(a == 40 and b == 5 and not c)
t = pack(T.testC("settop 5; return *", 2, 3))
local t = pack(T.testC("settop 5; return *", 2, 3))
tcheck(t, {n=4,2,3})
t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23))
@ -166,16 +166,17 @@ end
-- testing globals
_G.a = 14; _G.b = "a31"
_G.AA = 14; _G.BB = "a31"
local a = {T.testC[[
getglobal a;
getglobal b;
getglobal b;
setglobal a;
getglobal AA;
getglobal BB;
getglobal BB;
setglobal AA;
return *
]]}
assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.a == "a31")
assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.AA == "a31")
_G.AA, _G.BB = nil
-- testing arith
assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5)
@ -199,13 +200,14 @@ a,b,c = T.testC([[pushnum 1;
pushstring 10; arith _;
pushstring 5; return 3]])
assert(a == 1 and b == -10 and c == "5")
mt = {__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end,
local mt = {
__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end,
__mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end,
__unm = function (a) return setmetatable({a[1]* 2}, mt) end}
a,b,c = setmetatable({4}, mt),
setmetatable({8}, mt),
setmetatable({-3}, mt)
x,y,z = T.testC("arith +; return 2", 10, a, b)
local x,y,z = T.testC("arith +; return 2", 10, a, b)
assert(x == 10 and y[1] == 12 and z == nil)
assert(T.testC("arith %; return 1", a, c)[1] == 4%-3)
assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] ==
@ -312,9 +314,9 @@ assert(T.testC("concat 1; return 1", "xuxu") == "xuxu")
-- testing lua_is
function B(x) return x and 1 or 0 end
local function B (x) return x and 1 or 0 end
function count (x, n)
local function count (x, n)
n = n or 2
local prog = [[
isnumber %d;
@ -345,7 +347,7 @@ assert(count(nil, 15) == 100)
-- testing lua_to...
function to (s, x, n)
local function to (s, x, n)
n = n or 2
return T.testC(string.format("%s %d; return 1", s, n), x)
end
@ -486,11 +488,12 @@ a = T.testC([[
pushvalue 3; insert -2; pcall 1 1 0;
pcall 0 0 0;
return 1
]], "x=150", function (a) assert(a==nil); return 3 end)
]], "XX=150", function (a) assert(a==nil); return 3 end)
assert(type(a) == 'string' and x == 150)
assert(type(a) == 'string' and XX == 150)
_G.XX = nil
function check3(p, ...)
local function check3(p, ...)
local arg = {...}
assert(#arg == 3)
assert(string.find(arg[3], p))
@ -500,7 +503,7 @@ check3("%.", T.testC("loadfile 2; return *", "."))
check3("xxxx", T.testC("loadfile 2; return *", "xxxx"))
-- test errors in non protected threads
function checkerrnopro (code, msg)
local function checkerrnopro (code, msg)
local th = coroutine.create(function () end) -- create new thread
local stt, err = pcall(T.testC, th, code) -- run code there
assert(not stt and string.find(err, msg))
@ -510,8 +513,9 @@ if not _soft then
collectgarbage("stop") -- avoid __gc with full stack
checkerrnopro("pushnum 3; call 0 0", "attempt to call")
print"testing stack overflow in unprotected thread"
function f () f() end
checkerrnopro("getglobal 'f'; call 0 0;", "stack overflow")
function F () F() end
checkerrnopro("getglobal 'F'; call 0 0;", "stack overflow")
F = nil
collectgarbage("restart")
end
print"+"
@ -588,7 +592,7 @@ assert(a[a] == "x")
b = setmetatable({p = a}, {})
getmetatable(b).__index = function (t, i) return t.p[i] end
k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x")
local k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x")
assert(x == 15 and k == 35)
k = T.testC("getfield 2 y, return 1", b)
assert(k == 12)
@ -748,8 +752,8 @@ local i = T.ref{}
T.unref(i)
assert(T.ref{} == i)
Arr = {}
Lim = 100
local Arr = {}
local Lim = 100
for i=1,Lim do -- lock many objects
Arr[i] = T.ref({})
end
@ -761,7 +765,7 @@ for i=1,Lim do -- unlock all them
T.unref(Arr[i])
end
function printlocks ()
local function printlocks ()
local f = T.makeCfunc("gettable R; return 1")
local n = f("n")
print("n", n)
@ -793,8 +797,8 @@ assert(type(T.getref(a)) == 'table')
-- colect in cl the `val' of all collected userdata
tt = {}
cl = {n=0}
local tt = {}
local cl = {n=0}
A = nil; B = nil
local F
F = function (x)
@ -804,20 +808,20 @@ F = function (x)
d = nil
assert(debug.getmetatable(x).__gc == F)
assert(load("table.insert({}, {})"))() -- create more garbage
collectgarbage() -- force a GC during GC
assert(debug.getmetatable(x).__gc == F) -- previous GC did not mess this?
assert(not collectgarbage()) -- GC during GC (no op)
local dummy = {} -- create more garbage during GC
if A ~= nil then
assert(type(A) == "userdata")
assert(T.udataval(A) == B)
debug.getmetatable(A) -- just access it
end
A = x -- ressucita userdata
A = x -- ressurect userdata
B = udval
return 1,2,3
end
tt.__gc = F
-- test whether udate collection frees memory in the right time
do
collectgarbage();
@ -854,9 +858,9 @@ end
collectgarbage("stop")
-- create 3 userdatas with tag `tt'
a = T.newuserdata(0); debug.setmetatable(a, tt); na = T.udataval(a)
b = T.newuserdata(0); debug.setmetatable(b, tt); nb = T.udataval(b)
c = T.newuserdata(0); debug.setmetatable(c, tt); nc = T.udataval(c)
a = T.newuserdata(0); debug.setmetatable(a, tt); local na = T.udataval(a)
b = T.newuserdata(0); debug.setmetatable(b, tt); local nb = T.udataval(b)
c = T.newuserdata(0); debug.setmetatable(c, tt); local nc = T.udataval(c)
-- create userdata without meta table
x = T.newuserdata(4)
@ -867,9 +871,9 @@ checkerr("FILE%* expected, got userdata", io.input, x)
assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil)
d=T.ref(a);
e=T.ref(b);
f=T.ref(c);
local d = T.ref(a);
local e = T.ref(b);
local f = T.ref(c);
t = {T.getref(d), T.getref(e), T.getref(f)}
assert(t[1] == a and t[2] == b and t[3] == c)
@ -889,7 +893,7 @@ tt=nil -- frees tt for GC
A = nil
b = nil
T.unref(d);
n5 = T.newuserdata(0)
local n5 = T.newuserdata(0)
debug.setmetatable(n5, {__gc=F})
n5 = T.udataval(n5)
collectgarbage()
@ -960,11 +964,11 @@ print'+'
-- testing changing hooks during hooks
_G.t = {}
_G.TT = {}
T.sethook([[
# set a line hook after 3 count hooks
sethook 4 0 '
getglobal t;
getglobal TT;
pushvalue -3; append -2
pushvalue -2; append -2
']], "c", 3)
@ -974,12 +978,13 @@ a = 1 -- count hook (set line hook)
a = 1 -- line hook
a = 1 -- line hook
debug.sethook()
t = _G.t
local t = _G.TT
assert(t[1] == "line")
line = t[2]
local line = t[2]
assert(t[3] == "line" and t[4] == line + 1)
assert(t[5] == "line" and t[6] == line + 2)
assert(t[7] == nil)
_G.TT = nil
-------------------------------------------------------------------------
@ -1004,6 +1009,7 @@ do -- testing errors during GC
collectgarbage("restart")
warn("@on")
end
_G.A = nil
-------------------------------------------------------------------------
-- test for userdata vals
do
@ -1033,8 +1039,8 @@ assert(a == 'alo' and b == '3')
T.doremote(L1, "_ERRORMESSAGE = nil")
-- error: `sin' is not defined
a, _, b = T.doremote(L1, "return sin(1)")
assert(a == nil and b == 2) -- 2 == run-time error
a, b, c = T.doremote(L1, "return sin(1)")
assert(a == nil and c == 2) -- 2 == run-time error
-- error: syntax error
a, b, c = T.doremote(L1, "return a+")
@ -1205,7 +1211,7 @@ T.alloccount() -- remove limit
-- o that we get memory errors in all allocations of a given
-- task, until there is enough memory to complete the task without
-- errors.
function testbytes (s, f)
local function testbytes (s, f)
collectgarbage()
local M = T.totalmem()
local oldM = M
@ -1230,7 +1236,7 @@ end
-- task, until there is enough allocations to complete the task without
-- errors.
function testalloc (s, f)
local function testalloc (s, f)
collectgarbage()
local M = 0
local a,b = nil
@ -1297,12 +1303,12 @@ end)
-- testing threads
-- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1)
mt = T.testC("rawgeti R 1; return 1")
local mt = T.testC("rawgeti R 1; return 1")
assert(type(mt) == "thread" and coroutine.running() == mt)
function expand (n,s)
local function expand (n,s)
if n==0 then return "" end
local e = string.rep("=", n)
return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
@ -1312,9 +1318,10 @@ end
G=0; collectgarbage(); a =collectgarbage("count")
load(expand(20,"G=G+1"))()
assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1)
G = nil
testamem("running code on new thread", function ()
return T.doonnewstack("x=1") == 0 -- try to create thread
return T.doonnewstack("local x=1") == 0 -- try to create thread
end)
@ -1328,13 +1335,13 @@ end)
local testprog = [[
local function foo () return end
local t = {"x"}
a = "aaa"
for i = 1, #t do a=a..t[i] end
AA = "aaa"
for i = 1, #t do AA = AA .. t[i] end
return true
]]
-- testing memory x dofile
_G.a = nil
_G.AA = nil
local t =os.tmpname()
local f = assert(io.open(t, "w"))
f:write(testprog)
@ -1344,7 +1351,7 @@ testamem("dofile", function ()
return a and a()
end)
assert(os.remove(t))
assert(_G.a == "aaax")
assert(_G.AA == "aaax")
-- other generic tests
@ -1361,6 +1368,8 @@ testamem("dump/undump", function ()
return a and a()
end)
_G.AA = nil
local t = os.tmpname()
testamem("file creation", function ()
local f = assert(io.open(t, 'w'))
@ -1382,7 +1391,7 @@ testamem("constructors", function ()
end)
local a = 1
close = nil
local close = nil
testamem("closure creation", function ()
function close (b)
return function (x) return b + x end

View file

@ -85,7 +85,7 @@ local DIR = "libs" .. dirsep
-- prepend DIR to a name and correct directory separators
local function D (x)
x = string.gsub(x, "/", dirsep)
local x = string.gsub(x, "/", dirsep)
return DIR .. x
end
@ -106,7 +106,7 @@ local function createfiles (files, preextras, posextras)
end
end
function removefiles (files)
local function removefiles (files)
for n in pairs(files) do
os.remove(D(n))
end
@ -154,10 +154,9 @@ local try = function (p, n, r, ext)
assert(ext == x)
end
a = require"names"
local a = require"names"
assert(a[1] == "names" and a[2] == D"names.lua")
_G.a = nil
local st, msg = pcall(require, "err")
assert(not st and string.find(msg, "arithmetic") and B == 15)
st, msg = pcall(require, "synerr")
@ -191,6 +190,7 @@ try("X", "XXxX", AA, "libs/XXxX")
removefiles(files)
NAME, REQUIRED, AA, B = nil
-- testing require of sub-packages
@ -223,7 +223,7 @@ assert(require"P1" == m and m.AA == 10)
removefiles(files)
AA = nil
package.path = ""
assert(not pcall(require, "file_does_not_exist"))
@ -305,6 +305,7 @@ else
assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
assert(string.find(ext, "libs/lib1", 1, true))
assert(fs.id(45) == 45)
_ENV.x, _ENV.y = nil
end
_ENV = _G
@ -338,10 +339,10 @@ print("testing assignments, logical operators, and constructors")
local res, res2 = 27
a, b = 1, 2+3
local a, b = 1, 2+3
assert(a==1 and b==5)
a={}
function f() return 10, 11, 12 end
local function f() return 10, 11, 12 end
a.x, b, a[1] = 1, 2, f()
assert(a.x==1 and b==2 and a[1]==10)
a[f()], b, a[f()+3] = f(), a, 'x'
@ -353,15 +354,15 @@ do
local a,b,c
a,b = 0, f(1)
assert(a == 0 and b == 1)
A,b = 0, f(1)
assert(A == 0 and b == 1)
a,b = 0, f(1)
assert(a == 0 and b == 1)
a,b,c = 0,5,f(4)
assert(a==0 and b==5 and c==1)
a,b,c = 0,5,f(0)
assert(a==0 and b==5 and c==nil)
end
a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6
local a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6
assert(not a and b and c and d==6)
d = 20
@ -419,6 +420,7 @@ assert(not pcall(function () local a = {[nil] = 10} end))
assert(a[nil] == undef)
a = nil
local a, b, c
a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'}
a, a.x, a.y = a, a[-3]
assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y)
@ -434,6 +436,16 @@ a.aVeryLongName012345678901234567890123456789012345678901234567890123456789 ==
10)
do
-- _ENV constant
local function foo ()
local _ENV <const> = 11
X = "hi"
end
local st, msg = pcall(foo)
assert(not st and string.find(msg, "number"))
end
-- test of large float/integer indices
@ -445,7 +457,7 @@ while maxint ~= (maxint + 0.0) or (maxint - 1) ~= (maxint - 1.0) do
maxint = maxint // 2
end
maxintF = maxint + 0.0 -- float version
local maxintF = maxint + 0.0 -- float version
assert(maxintF == maxint and math.type(maxintF) == "float" and
maxintF >= 2.0^14)

View file

@ -32,7 +32,7 @@ setmetatable(env, {
})
X = nil
co = coroutine.wrap(f)
local co = coroutine.wrap(f)
assert(co() == 's')
assert(co() == 'g')
assert(co() == 'g')

View file

@ -38,6 +38,18 @@ d = d << 32
assert(a | b ~ c & d == 0xF4000000 << 32)
assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1)
do -- constant folding
local code = string.format("return -1 >> %d", math.maxinteger)
assert(load(code)() == 0)
local code = string.format("return -1 >> %d", math.mininteger)
assert(load(code)() == 0)
local code = string.format("return -1 << %d", math.maxinteger)
assert(load(code)() == 0)
local code = string.format("return -1 << %d", math.mininteger)
assert(load(code)() == 0)
end
assert(-1 >> 1 == (1 << (numbits - 1)) - 1 and 1 << 31 == 0x80000000)
assert(-1 >> (numbits - 1) == 1)
assert(-1 >> numbits == 0 and
@ -45,6 +57,11 @@ assert(-1 >> numbits == 0 and
-1 << numbits == 0 and
-1 << -numbits == 0)
assert(1 >> math.mininteger == 0)
assert(1 >> math.maxinteger == 0)
assert(1 << math.mininteger == 0)
assert(1 << math.maxinteger == 0)
assert((2^30 - 1) << 2^30 == 0)
assert((2^30 - 1) >> 2^30 == 0)

View file

@ -16,7 +16,7 @@ assert(type(nil) == 'nil'
and type(type) == 'function')
assert(type(assert) == type(print))
function f (x) return a:x (x) end
local function f (x) return a:x (x) end
assert(type(f) == 'function')
assert(not pcall(type))
@ -33,10 +33,11 @@ do
assert(fact(5) == 120)
end
assert(fact == false)
fact = nil
-- testing declarations
a = {i = 10}
self = 20
local a = {i = 10}
local self = 20
function a:x (x) return x+self.i end
function a.y (x) return x+self end
@ -72,6 +73,8 @@ f(1,2, -- this one too
3,4)
assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a')
t = nil -- delete 't'
function fat(x)
if x <= 1 then return 1
else return x*load("return fat(" .. x-1 .. ")", "")()
@ -80,26 +83,29 @@ end
assert(load "load 'assert(fat(6)==720)' () ")()
a = load('return fat(5), 3')
a,b = a()
local a,b = a()
assert(a == 120 and b == 3)
fat = nil
print('+')
function err_on_n (n)
local function err_on_n (n)
if n==0 then error(); exit(1);
else err_on_n (n-1); exit(1);
end
end
do
function dummy (n)
local function dummy (n)
if n > 0 then
assert(not pcall(err_on_n, n))
dummy(n-1)
end
end
dummy(10)
end
dummy(10)
_G.deep = nil -- "declaration" (used by 'all.lua')
function deep (n)
if n>0 then deep(n-1) end
@ -151,6 +157,16 @@ do -- tail calls x varargs
end
do -- C-stack overflow while handling C-stack overflow
local function loop ()
assert(pcall(loop))
end
local err, msg = xpcall(loop, loop)
assert(not err and string.find(msg, "error"))
end
do -- tail calls x chain of __call
local n = 10000 -- depth
@ -199,7 +215,7 @@ assert(a == 23 and (function (x) return x*2 end)(20) == 40)
-- testing closures
-- fixed-point operator
Z = function (le)
local Z = function (le)
local function a (f)
return le(function (x) return f(f)(x) end)
end
@ -209,14 +225,14 @@ Z = function (le)
-- non-recursive factorial
F = function (f)
local F = function (f)
return function (n)
if n == 0 then return 1
else return n*f(n-1) end
end
end
fat = Z(F)
local fat = Z(F)
assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(F)(4))
@ -227,22 +243,21 @@ local function g (z)
return f(z,z+1,z+2,z+3)
end
f = g(10)
local f = g(10)
assert(f(9, 16) == 10+11+12+13+10+9+16+10)
Z, F, f = nil
print('+')
-- testing multiple returns
function unlpack (t, i)
local function unlpack (t, i)
i = i or 1
if (i <= #t) then
return t[i], unlpack(t, i+1)
end
end
function equaltab (t1, t2)
local function equaltab (t1, t2)
assert(#t1 == #t2)
for i = 1, #t1 do
assert(t1[i] == t2[i])
@ -251,8 +266,8 @@ end
local pack = function (...) return (table.pack(...)) end
function f() return 1,2,30,4 end
function ret2 (a,b) return a,b end
local function f() return 1,2,30,4 end
local function ret2 (a,b) return a,b end
local a,b,c,d = unlpack{1,2,3}
assert(a==1 and b==2 and c==3 and d==nil)
@ -281,7 +296,7 @@ table.sort({10,9,8,4,19,23,0,0}, function (a,b) return a<b end, "extra arg")
local x = "-- a comment\0\0\0\n x = 10 + \n23; \
local a = function () x = 'hi' end; \
return '\0'"
function read1 (x)
local function read1 (x)
local i = 0
return function ()
collectgarbage()
@ -290,7 +305,7 @@ function read1 (x)
end
end
function cannotload (msg, a,b)
local function cannotload (msg, a,b)
assert(not a and string.find(b, msg))
end
@ -327,11 +342,26 @@ do -- another bug (in 5.4.0)
end
do -- another bug (since 5.2)
-- corrupted binary dump: list of upvalue names is larger than number
-- of upvalues, overflowing the array of upvalues.
local code =
"\x1b\x4c\x75\x61\x54\x00\x19\x93\x0d\x0a\x1a\x0a\x04\x08\x08\x78\x56\z
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x77\x40\x00\x86\x40\z
\x74\x65\x6d\x70\x81\x81\x01\x00\x02\x82\x48\x00\x02\x00\xc7\x00\x01\z
\x00\x80\x80\x80\x82\x00\x00\x80\x81\x82\x78\x80\x82\x81\x86\x40\x74\z
\x65\x6d\x70"
assert(load(code)) -- segfaults in previous versions
end
x = string.dump(load("x = 1; return x"))
a = assert(load(read1(x), nil, "b"))
assert(a() == 1 and _G.x == 1)
cannotload("attempt to load a binary chunk", load(read1(x), nil, "t"))
cannotload("attempt to load a binary chunk", load(x, nil, "t"))
_G.x = nil
assert(not pcall(string.dump, print)) -- no dump of C functions
@ -356,7 +386,7 @@ debug.setupvalue(x, 2, _G)
assert(x() == 123)
assert(assert(load("return XX + ...", nil, nil, {XX = 13}))(4) == 17)
XX = nil
-- test generic load with nested functions
x = [[

View file

@ -4,7 +4,7 @@
print "testing closures"
local A,B = 0,{g=10}
function f(x)
local function f(x)
local a = {}
for i=1,1000 do
local y = 0
@ -89,6 +89,7 @@ assert(r == "a" and s == "b")
-- testing closures with 'for' control variable x break
local f
for i=1,3 do
f = function () return i end
break
@ -139,7 +140,7 @@ assert(b('get') == 'xuxu')
b('set', 10); assert(b('get') == 14)
local w
local y, w
-- testing multi-level closure
function f(x)
return function (y)
@ -230,6 +231,7 @@ t()
-- test for debug manipulation of upvalues
local debug = require'debug'
local foo1, foo2, foo3
do
local a , b, c = 3, 5, 7
foo1 = function () return a+b end;

View file

@ -69,10 +69,24 @@ foo = function (f, a)
checkKlist(foo, {100000, 100000.0, -100000, -100000.0})
-- floats x integers
foo = function (t, a)
t[a] = 1; t[a] = 1.0
t[a] = 1; t[a] = 1.0
t[a] = 2; t[a] = 2.0
t[a] = 0; t[a] = 0.0
t[a] = 1; t[a] = 1.0
t[a] = 2; t[a] = 2.0
t[a] = 0; t[a] = 0.0
end
checkKlist(foo, {1, 1.0, 2, 2.0, 0, 0.0})
-- testing opcodes
-- check that 'f' opcodes match '...'
function check (f, ...)
local function check (f, ...)
local arg = {...}
local c = T.listcode(f)
for i=1, #arg do
@ -85,7 +99,7 @@ end
-- check that 'f' opcodes match '...' and that 'f(p) == r'.
function checkR (f, p, r, ...)
local function checkR (f, p, r, ...)
local r1 = f(p)
assert(r == r1 and math.type(r) == math.type(r1))
check(f, ...)
@ -93,7 +107,7 @@ end
-- check that 'a' and 'b' has the same opcodes
function checkequal (a, b)
local function checkequal (a, b)
a = T.listcode(a)
b = T.listcode(b)
assert(#a == #b)

View file

@ -11,6 +11,7 @@ local function checkload (s, msg)
end
-- testing semicollons
local a
do ;;; end
; do ; a = 3; assert(a == 3) end;
;
@ -49,10 +50,10 @@ assert((((nil and true) or false) and true) == false)
local a,b = 1,nil;
assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75);
x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x);
local x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x);
x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x);
x,y=1,2;
local x, y = 1, 2;
assert((x>y) and x or y == 2);
x,y=2,1;
assert((x>y) and x or y == 2);
@ -77,13 +78,13 @@ do -- testing operators with diffent kinds of constants
local gab = f(o1, o2)
_ENV.XX = o1
code = string.format("return XX %s %s", op, o2)
res = assert(load(code))()
local code = string.format("return XX %s %s", op, o2)
local res = assert(load(code))()
assert(res == gab)
_ENV.XX = o2
local code = string.format("return (%s) %s XX", o1, op)
local res = assert(load(code))()
code = string.format("return (%s) %s XX", o1, op)
res = assert(load(code))()
assert(res == gab)
code = string.format("return (%s) %s %s", o1, op, o2)
@ -92,6 +93,7 @@ do -- testing operators with diffent kinds of constants
end
end
end
_ENV.XX = nil
end
@ -100,10 +102,35 @@ repeat until 1; repeat until true;
while false do end; while nil do end;
do -- test old bug (first name could not be an `upvalue')
local a; function f(x) x={a=1}; x={x=1}; x={G=1} end
local a; local function f(x) x={a=1}; x={x=1}; x={G=1} end
end
function f (i)
do -- bug since 5.4.0
-- create code with a table using more than 256 constants
local code = {"local x = {"}
for i = 1, 257 do
code[#code + 1] = i .. ".1,"
end
code[#code + 1] = "};"
code = table.concat(code)
-- add "ret" to the end of that code and checks that
-- it produces the expected value "val"
local function check (ret, val)
local code = code .. ret
code = load(code)
assert(code() == val)
end
check("return (1 ~ (2 or 3))", 1 ~ 2)
check("return (1 | (2 or 3))", 1 | 2)
check("return (1 + (2 or 3))", 1 + 2)
check("return (1 << (2 or 3))", 1 << 2)
end
local function f (i)
if type(i) ~= 'number' then return i,'jojo'; end;
if i > 0 then return i, f(i-1); end;
end
@ -129,10 +156,10 @@ end
assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil)
for i=1,1000 do break; end;
n=100;
i=3;
t = {};
a=nil
local n=100;
local i=3;
local t = {};
local a=nil
while not a do
a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end;
end
@ -175,14 +202,14 @@ a={y=1}
x = {a.y}
assert(x[1] == 1)
function f(i)
local function f (i)
while 1 do
if i>0 then i=i-1;
else return; end;
end;
end;
function g(i)
local function g(i)
while 1 do
if i>0 then i=i-1
else return end
@ -247,7 +274,7 @@ function g (a,b,c,d,e)
if not (a>=b or c or d and e or nil) then return 0; else return 1; end;
end
function h (a,b,c,d,e)
local function h (a,b,c,d,e)
while (a>=b or c or (d and e) or nil) do return 1; end;
return 0;
end;
@ -275,7 +302,7 @@ do
assert(a==2)
end
function F(a)
local function F (a)
assert(debug.getinfo(1, "n").name == 'F')
return a,2,3
end
@ -368,6 +395,8 @@ for n = 1, level do
if i % 60000 == 0 then print('+') end
end
end
IX = nil
_G.GLOB1 = nil
------------------------------------------------------------------
-- testing some syntax errors (chosen through 'gcov')

View file

@ -30,7 +30,8 @@ local function eqtab (t1, t2)
end
_G.x = nil -- declare x
function foo (a, ...)
_G.f = nil -- declare f
local function foo (a, ...)
local x, y = coroutine.running()
assert(x == f and y == false)
-- next call should not corrupt coroutine (but must fail,
@ -67,10 +68,11 @@ assert(coroutine.status(f) == "dead")
s, a = coroutine.resume(f, "xuxu")
assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead")
_G.f = nil
-- yields in tail calls
local function foo (i) return coroutine.yield(i) end
f = coroutine.wrap(function ()
local f = coroutine.wrap(function ()
for i=1,10 do
assert(foo(i) == _G.x)
end
@ -79,8 +81,10 @@ end)
for i=1,10 do _G.x = i; assert(f(i) == i) end
_G.x = 'xuxu'; assert(f('xuxu') == 'a')
_G.x = nil
-- recursive
function pf (n, i)
local function pf (n, i)
coroutine.yield(n)
pf(n*i, i+1)
end
@ -93,14 +97,14 @@ for i=1,10 do
end
-- sieve
function gen (n)
local function gen (n)
return coroutine.wrap(function ()
for i=2,n do coroutine.yield(i) end
end)
end
function filter (p, g)
local function filter (p, g)
return coroutine.wrap(function ()
while 1 do
local n = g()
@ -136,6 +140,10 @@ do
assert(coroutine.status(co) == "dead")
local st, msg = coroutine.close(co)
assert(st and msg == nil)
-- also ok to close it again
st, msg = coroutine.close(co)
assert(st and msg == nil)
-- cannot close the running coroutine
local st, msg = pcall(coroutine.close, coroutine.running())
@ -149,6 +157,22 @@ do
assert(not st and string.find(msg, "normal"))
end))()
-- cannot close a coroutine while closing it
do
local co
co = coroutine.create(
function()
local x <close> = func2close(function()
coroutine.close(co) -- try to close it again
end)
coroutine.yield(20)
end)
local st, msg = coroutine.resume(co)
assert(st and msg == 20)
st, msg = coroutine.close(co)
assert(not st and string.find(msg, "running coroutine"))
end
-- to-be-closed variables in coroutines
local X
@ -158,6 +182,9 @@ do
assert(not st and msg == 100)
st, msg = coroutine.close(co)
assert(not st and msg == 100)
-- after closing, no more errors
st, msg = coroutine.close(co)
assert(st and msg == nil)
co = coroutine.create(function ()
local x <close> = func2close(function (self, err)
@ -189,23 +216,26 @@ do
local st, msg = coroutine.close(co)
assert(st == false and coroutine.status(co) == "dead" and msg == 200)
assert(x == 200)
-- after closing, no more errors
st, msg = coroutine.close(co)
assert(st and msg == nil)
end
do
-- <close> versus pcall in coroutines
local X = false
local Y = false
function foo ()
local function foo ()
local x <close> = func2close(function (self, err)
Y = debug.getinfo(2)
X = err
end)
error(43)
end
co = coroutine.create(function () return pcall(foo) end)
local co = coroutine.create(function () return pcall(foo) end)
local st1, st2, err = coroutine.resume(co)
assert(st1 and not st2 and err == 43)
assert(X == 43 and Y.name == "pcall")
assert(X == 43 and Y.what == "C")
-- recovering from errors in __close metamethods
local track = {}
@ -249,7 +279,7 @@ end
-- yielding across C boundaries
co = coroutine.wrap(function()
local co = coroutine.wrap(function()
assert(not pcall(table.sort,{1,2,3}, coroutine.yield))
assert(coroutine.isyieldable())
coroutine.yield(20)
@ -277,15 +307,15 @@ local r1, r2, v = f1(nil)
assert(r1 and not r2 and v[1] == (10 + 1)*10/2)
function f (a, b) a = coroutine.yield(a); error{a + b} end
function g(x) return x[1]*2 end
local function f (a, b) a = coroutine.yield(a); error{a + b} end
local function g(x) return x[1]*2 end
co = coroutine.wrap(function ()
coroutine.yield(xpcall(f, g, 10, 20))
end)
assert(co() == 10)
r, msg = co(100)
local r, msg = co(100)
assert(not r and msg == 240)
@ -347,9 +377,10 @@ assert(not a and b == foo and coroutine.status(x) == "dead")
a,b = coroutine.resume(x)
assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead")
goo = nil
-- co-routines x for loop
function all (a, n, k)
local function all (a, n, k)
if k == 0 then coroutine.yield(a)
else
for i=1,n do
@ -389,7 +420,7 @@ assert(f() == 43 and f() == 53)
-- old bug: attempt to resume itself
function co_func (current_co)
local function co_func (current_co)
assert(coroutine.running() == current_co)
assert(coroutine.resume(current_co) == false)
coroutine.yield(10, 20)
@ -419,7 +450,7 @@ do
local X = false
A = coroutine.wrap(function()
local _ <close> = setmetatable({}, {__close = function () X = true end})
local _ <close> = func2close(function () X = true end)
return pcall(A, 1)
end)
st, res = A()
@ -427,6 +458,22 @@ do
end
-- bug in 5.4.1
do
-- coroutine ran close metamethods with invalid status during a
-- reset.
local co
co = coroutine.wrap(function()
local x <close> = func2close(function() return pcall(co) end)
error(111)
end)
local st, errobj = pcall(co)
assert(not st and errobj == 111)
st, errobj = pcall(co)
assert(not st and string.find(errobj, "dead coroutine"))
end
-- attempt to resume 'normal' coroutine
local co1, co2
co1 = coroutine.create(function () return co2() end)
@ -449,15 +496,16 @@ a = nil
-- access to locals of erroneous coroutines
local x = coroutine.create (function ()
local a = 10
_G.f = function () a=a+1; return a end
_G.F = function () a=a+1; return a end
error('x')
end)
assert(not coroutine.resume(x))
-- overwrite previous position of local `a'
assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1))
assert(_G.f() == 11)
assert(_G.f() == 12)
assert(_G.F() == 11)
assert(_G.F() == 12)
_G.F = nil
if not T then
@ -468,7 +516,7 @@ else
local turn
function fact (t, x)
local function fact (t, x)
assert(turn == t)
if x == 0 then return 1
else return x*fact(t, x-1)
@ -537,6 +585,7 @@ else
_G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil)
_G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20)
assert(co() == 10)
_G.X = nil
-- testing yields in count hook
co = coroutine.wrap(function ()
@ -614,6 +663,8 @@ else
assert(X == 'a a a' and Y == 'OK')
X, Y = nil
-- resuming running coroutine
C = coroutine.create(function ()
@ -659,7 +710,7 @@ else
X = function (x) coroutine.yield(x, 'BB'); return 'CC' end;
return 'ok']]))
t = table.pack(T.testC(state, [[
local t = table.pack(T.testC(state, [[
rawgeti R 1 # get main thread
pushstring 'XX'
getglobal X # get function for body
@ -688,31 +739,28 @@ end
-- leaving a pending coroutine open
_X = coroutine.wrap(function ()
_G.TO_SURVIVE = coroutine.wrap(function ()
local a = 10
local x = function () a = a+1 end
coroutine.yield()
end)
_X()
_G.TO_SURVIVE()
if not _soft then
-- bug (stack overflow)
local j = 2^9
local lim = 1000000 -- (C stack limit; assume 32-bit machine)
local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1}
local lim = 1000000 -- stack limit; assume 32-bit machine
local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1, lim + 5}
for i = 1, #t do
local j = t[i]
co = coroutine.create(function()
local t = {}
for i = 1, j do t[i] = i end
return table.unpack(t)
local co = coroutine.create(function()
return table.unpack({}, 1, j)
end)
local r, msg = coroutine.resume(co)
assert(not r)
-- must fail for unpacking larger than stack limit
assert(j < lim or not r)
end
co = nil
end
@ -896,7 +944,7 @@ assert(run(function ()
do local _ENV = _ENV
f = function () AAA = BBB + 1; return AAA end
end
g = new(10); g.k.BBB = 10;
local g = new(10); g.k.BBB = 10;
debug.setupvalue(f, 1, g)
assert(run(f, {"idx", "nidx", "idx"}) == 11)
assert(g.k.AAA == 11)
@ -1036,6 +1084,8 @@ assert(#a == 3 and a[1] == a[2] and a[2] == a[3] and a[3] == 34)
-- testing yields with continuations
local y
co = coroutine.wrap(function (...) return
T.testC([[ # initial function
yieldk 1 2
@ -1088,6 +1138,9 @@ assert(x == "YIELD" and y == 4)
assert(not pcall(co)) -- coroutine should be dead
_G.ctx = nil
_G.status = nil
-- bug in nCcalls
local co = coroutine.wrap(function ()

View file

@ -84,6 +84,32 @@ do -- bug in 5.4.0
end
do -- bug since 5.4.0
local count = 0
print("chain of 'coroutine.close'")
-- create N coroutines forming a list so that each one, when closed,
-- closes the previous one. (With a large enough N, previous Lua
-- versions crash in this test.)
local coro = false
for i = 1, 1000 do
local previous = coro
coro = coroutine.create(function()
local cc <close> = setmetatable({}, {__close=function()
count = count + 1
if previous then
assert(coroutine.close(previous))
end
end})
coroutine.yield() -- leaves 'cc' pending to be closed
end)
assert(coroutine.resume(coro)) -- start it and run until it yields
end
local st, msg = coroutine.close(coro)
assert(not st and string.find(msg, "C stack overflow"))
print("final count: ", count)
end
do
print("nesting of resuming yielded coroutines")
local count = 0
@ -103,6 +129,20 @@ do
end
do -- bug in 5.4.2
print("nesting coroutines running after recoverable errors")
local count = 0
local function foo()
count = count + 1
pcall(1) -- create an error
-- running now inside 'precover' ("protected recover")
coroutine.wrap(foo)() -- call another coroutine
end
checkerror("C stack overflow", foo)
print("final count: ", count)
end
if T then
print("testing stack recovery")
local N = 0 -- trace number of calls

View file

@ -16,7 +16,7 @@ end
assert(not debug.gethook())
local testline = 19 -- line where 'test' is defined
function test (s, l, p) -- this must be line 19
local function test (s, l, p) -- this must be line 19
collectgarbage() -- avoid gc during trace
local function f (event, line)
assert(event == 'line')
@ -50,7 +50,7 @@ end
-- test file and string names truncation
a = "function f () end"
local a = "function f () end"
local function dostring (s, x) return load(s, x)() end
dostring(a)
assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
@ -72,7 +72,8 @@ dostring(a, string.format("=%s", string.rep('x', 500)))
assert(string.find(debug.getinfo(f).short_src, "^x*$"))
dostring(a, "=")
assert(debug.getinfo(f).short_src == "")
a = nil; f = nil;
_G.a = nil; _G.f = nil;
_G[string.rep("p", 400)] = nil
repeat
@ -120,6 +121,7 @@ else
end
]], {2,3,4,7})
test([[
local function foo()
end
@ -128,6 +130,7 @@ A = 1
A = 2
A = 3
]], {2, 3, 2, 4, 5, 6})
_G.A = nil
test([[--
@ -175,6 +178,8 @@ end
test([[for i=1,4 do a=1 end]], {1,1,1,1})
_G.a = nil
do -- testing line info/trace with large gaps in source
@ -194,6 +199,50 @@ do -- testing line info/trace with large gaps in source
end
end
end
_G.a = nil
do -- testing active lines
local function checkactivelines (f, lines)
local t = debug.getinfo(f, "SL")
for _, l in pairs(lines) do
l = l + t.linedefined
assert(t.activelines[l])
t.activelines[l] = undef
end
assert(next(t.activelines) == nil) -- no extra lines
end
checkactivelines(function (...) -- vararg function
-- 1st line is empty
-- 2nd line is empty
-- 3th line is empty
local a = 20
-- 5th line is empty
local b = 30
-- 7th line is empty
end, {4, 6, 8})
checkactivelines(function (a)
-- 1st line is empty
-- 2nd line is empty
local a = 20
local b = 30
-- 5th line is empty
end, {3, 4, 6})
checkactivelines(function (a, b, ...) end, {0})
checkactivelines(function (a, b)
end, {1})
for _, n in pairs{0, 1, 2, 10, 50, 100, 1000, 10000} do
checkactivelines(
load(string.format("%s return 1", string.rep("\n", n))),
{n + 1})
end
end
print'+'
@ -244,7 +293,6 @@ foo(200, 3, 4)
local a = {}
for i = 1, (_soft and 100 or 1000) do a[i] = i end
foo(table.unpack(a))
a = nil
@ -264,13 +312,14 @@ do -- test hook presence in debug info
debug.sethook()
assert(count == 4)
end
_ENV.a = nil
-- hook table has weak keys
assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k')
a = {}; L = nil
a = {}; local L = nil
local glob = 1
local oldglob = glob
debug.sethook(function (e,l)
@ -311,7 +360,7 @@ function foo()
end; foo() -- set L
-- check line counting inside strings and empty lines
_ = 'alo\
local _ = 'alo\
alo' .. [[
]]
@ -360,6 +409,7 @@ function g(a,b) return (a+1) + f() end
assert(g(0,0) == 30)
_G.f, _G.g = nil
debug.sethook(nil);
assert(not debug.gethook())
@ -403,7 +453,7 @@ local function collectlocals (level)
end
X = nil
local X = nil
a = {}
function a:f (a, b, ...) local arg = {...}; local c = 13 end
debug.sethook(function (e)
@ -426,6 +476,7 @@ a:f(1,2,3,4,5)
assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil)
assert(XX == 12)
assert(not debug.gethook())
_G.XX = nil
-- testing access to local variables in return hook (bug in 5.2)
@ -550,6 +601,7 @@ end
debug.sethook()
local g, g1
-- tests for tail calls
local function f (x)
@ -595,7 +647,7 @@ h(false)
debug.sethook()
assert(b == 2) -- two tail calls
lim = _soft and 3000 or 30000
local lim = _soft and 3000 or 30000
local function foo (x)
if x==0 then
assert(debug.getinfo(2).what == "main")
@ -844,7 +896,7 @@ do -- testing debug info for finalizers
-- create a piece of garbage with a finalizer
setmetatable({}, {__gc = function ()
local t = debug.getinfo(2) -- get callee information
local t = debug.getinfo(1) -- get function information
assert(t.namewhat == "metamethod")
name = t.name
end})
@ -897,7 +949,7 @@ end
print("testing debug functions on chunk without debug info")
prog = [[-- program to be loaded without debug information (strip)
local prog = [[-- program to be loaded without debug information (strip)
local debug = require'debug'
local a = 12 -- a local variable

View file

@ -26,7 +26,7 @@ end
local function checkmessage (prog, msg, debug)
local m = doit(prog)
if debug then print(m) end
if debug then print(m, msg) end
assert(string.find(m, msg, 1, true))
end
@ -114,12 +114,14 @@ checkmessage("a = {} | 1", "bitwise operation")
checkmessage("a = {} < 1", "attempt to compare")
checkmessage("a = {} <= 1", "attempt to compare")
checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'")
checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'")
checkmessage("aaa=1; bbbb=2; aaa=math.sin(3)+bbbb(3)", "global 'bbbb'")
checkmessage("aaa={}; do local aaa=1 end aaa:bbbb(3)", "method 'bbbb'")
checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'"))
checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number")
checkmessage("a=(1)..{}", "a table value")
assert(not string.find(doit"aaa={13}; local bbbb=1; aaa[bbbb](3)", "'bbbb'"))
checkmessage("aaa={13}; local bbbb=1; aaa[bbbb](3)", "number")
checkmessage("aaa=(1)..{}", "a table value")
_G.aaa, _G.bbbb = nil
-- calls
checkmessage("local a; a(13)", "local 'a'")
@ -134,12 +136,13 @@ checkmessage([[
-- tail calls
checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'")
checkmessage("a={}; do local a=1 end; return a:bbbb(3)", "method 'bbbb'")
checkmessage("aaa={}; do local aaa=1 end; return aaa:bbbb(3)", "method 'bbbb'")
checkmessage("a = #print", "length of a function value")
checkmessage("a = #3", "length of a number value")
checkmessage("aaa = #print", "length of a function value")
checkmessage("aaa = #3", "length of a number value")
_G.aaa = nil
aaa = nil
checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
@ -152,15 +155,16 @@ checkmessage("local a,b,cc; (function () a.x = 1 end)()", "upvalue 'a'")
checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'")
checkmessage("b=1; local aaa={}; x=aaa+b", "local 'aaa'")
checkmessage("BB=1; local aaa={}; x=aaa+BB", "local 'aaa'")
checkmessage("aaa={}; x=3.3/aaa", "global 'aaa'")
checkmessage("aaa=2; b=nil;x=aaa*b", "global 'b'")
checkmessage("aaa=2; BB=nil;x=aaa*BB", "global 'BB'")
checkmessage("aaa={}; x=-aaa", "global 'aaa'")
-- short circuit
checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)",
checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = math.sin(1) and bbbb(3)",
"local 'bbbb'")
checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = bbbb(1) or aaa(3)",
"local 'bbbb'")
checkmessage("a=1; local a,bbbb=2,3; a = bbbb(1) or a(3)", "local 'bbbb'")
checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'")
checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value")
assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
@ -187,8 +191,8 @@ checkmessage("return ~-3e40", "has no integer representation")
checkmessage("return ~-3.009", "has no integer representation")
checkmessage("return 3.009 & 1", "has no integer representation")
checkmessage("return 34 >> {}", "table value")
checkmessage("a = 24 // 0", "divide by zero")
checkmessage("a = 1 % 0", "'n%0'")
checkmessage("aaa = 24 // 0", "divide by zero")
checkmessage("aaa = 1 % 0", "'n%0'")
-- type error for an object which is neither in an upvalue nor a register.
@ -228,6 +232,22 @@ do -- named objects (field '__name')
checkmessage("return {} < XX", "table with My Type")
checkmessage("return XX < io.stdin", "My Type with FILE*")
_G.XX = nil
if T then -- extra tests for 'luaL_tolstring'
-- bug in 5.4.3; 'luaL_tolstring' with negative indices
local x = setmetatable({}, {__name="TABLE"})
assert(T.testC("Ltolstring -1; return 1", x) == tostring(x))
local a, b = T.testC("pushint 10; Ltolstring -2; return 2", x)
assert(a == 10 and b == tostring(x))
setmetatable(x, {__tostring=function (o)
assert(o == x)
return "ABC"
end})
local a, b, c = T.testC("pushint 10; Ltolstring -2; return 3", x)
assert(a == x and b == 10 and c == "ABC")
end
end
-- global functions
@ -253,13 +273,13 @@ end
-- tests for field accesses after RK limit
local t = {}
for i = 1, 1000 do
t[i] = "a = x" .. i
t[i] = "aaa = x" .. i
end
local s = table.concat(t, "; ")
t = nil
checkmessage(s.."; a = bbb + 1", "global 'bbb'")
checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'")
checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'")
checkmessage(s.."; aaa = bbb + 1", "global 'bbb'")
checkmessage("local _ENV=_ENV;"..s.."; aaa = bbb + 1", "global 'bbb'")
checkmessage(s.."; local t = {}; aaa = t.bbb + 1", "field 'bbb'")
checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'")
checkmessage([[aaa=9
@ -289,7 +309,7 @@ end]], "global 'insert'")
checkmessage([[ -- tail call
return math.sin("a")
]], "'sin'")
]], "sin")
checkmessage([[collectgarbage("nooption")]], "invalid option")
@ -308,14 +328,17 @@ main()
]], "global 'NoSuchName'")
print'+'
a = {}; setmetatable(a, {__index = string})
checkmessage("a:sub()", "bad self")
aaa = {}; setmetatable(aaa, {__index = string})
checkmessage("aaa:sub()", "bad self")
checkmessage("string.sub('a', {})", "#2")
checkmessage("('a'):sub{}", "#1")
checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'")
checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'")
_G.aaa = nil
-- tests for errors in coroutines
local function f (n)
@ -333,7 +356,7 @@ checkerr("yield across", f)
-- testing size of 'source' info; size of buffer for that info is
-- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'.
idsize = 60 - 1
local idsize = 60 - 1
local function checksize (source)
-- syntax error
local _, msg = load("x", source)
@ -395,13 +418,14 @@ x
local p = [[
function g() f() end
function f(x) error('a', X) end
function f(x) error('a', XX) end
g()
]]
X=3;lineerror((p), 3)
X=0;lineerror((p), false)
X=1;lineerror((p), 2)
X=2;lineerror((p), 1)
XX=3;lineerror((p), 3)
XX=0;lineerror((p), false)
XX=1;lineerror((p), 2)
XX=2;lineerror((p), 1)
_G.XX, _G.g, _G.f = nil
lineerror([[
@ -420,6 +444,14 @@ if not b then
end
end]], 5)
-- bug in 5.4.0
lineerror([[
local a = 0
local b = 1
local c = b % a
]], 3)
do
-- Force a negative estimate for base line. Error in instruction 2
-- (after VARARGPREP, GETGLOBAL), with first absolute line information
@ -433,11 +465,11 @@ if not _soft then
-- several tests that exaust the Lua stack
collectgarbage()
print"testing stack overflow"
C = 0
local C = 0
-- get line where stack overflow will happen
local l = debug.getinfo(1, "l").currentline + 1
local function auxy () C=C+1; auxy() end -- produce a stack overflow
function y ()
function YY ()
collectgarbage("stop") -- avoid running finalizers without stack space
auxy()
collectgarbage("restart")
@ -449,9 +481,11 @@ if not _soft then
return (string.find(m, "stack overflow"))
end
-- repeated stack overflows (to check stack recovery)
assert(checkstackmessage(doit('y()')))
assert(checkstackmessage(doit('y()')))
assert(checkstackmessage(doit('y()')))
assert(checkstackmessage(doit('YY()')))
assert(checkstackmessage(doit('YY()')))
assert(checkstackmessage(doit('YY()')))
_G.YY = nil
-- error lines in stack overflow
@ -545,7 +579,7 @@ do
end
-- xpcall with arguments
a, b, c = xpcall(string.find, error, "alo", "al")
local a, b, c = xpcall(string.find, error, "alo", "al")
assert(a and b == 1 and c == 2)
a, b, c = xpcall(string.find, function (x) return {} end, true, "al")
assert(not a and type(b) == "table" and c == nil)
@ -565,11 +599,12 @@ checksyntax("a\1a = 1", "", "<\\1>", 1)
-- test 255 as first char in a chunk
checksyntax("\255a = 1", "", "<\\255>", 1)
doit('I = load("a=9+"); a=3')
assert(a==3 and not I)
doit('I = load("a=9+"); aaa=3')
assert(_G.aaa==3 and not _G.I)
_G.I,_G.aaa = nil
print('+')
lim = 1000
local lim = 1000
if _soft then lim = 100 end
for i=1,lim do
doit('a = ')

View file

@ -420,6 +420,9 @@ assert(i == 3 and x[1] == 3 and x[3] == 5)
assert(_G.X == 20)
_G.X, _G.B = nil
print'+'
local _g = _G

View file

@ -507,15 +507,17 @@ load((io.lines(file, 1)))()
assert(_G.X == 4)
load((io.lines(file, 3)))()
assert(_G.X == 8)
_G.X = nil
print('+')
local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'"
io.output(file)
assert(io.write(string.format("x2 = %q\n-- comment without ending EOS", x1)))
assert(io.write(string.format("X2 = %q\n-- comment without ending EOS", x1)))
io.close()
assert(loadfile(file))()
assert(x1 == x2)
assert(x1 == _G.X2)
_G.X2 = nil
print('+')
assert(os.remove(file))
assert(not os.remove(file))
@ -610,6 +612,7 @@ do
assert(os.remove(file))
end
io.output(file)
assert(io.write("qualquer coisa\n"))
assert(io.write("mais qualquer coisa"))
@ -743,7 +746,7 @@ if not _port then
{"exit 129", "exit", 129},
{"kill -s HUP $$", "signal", 1},
{"kill -s KILL $$", "signal", 9},
{"sh -c 'kill -s HUP $$'", "signal", 1},
{"sh -c 'kill -s HUP $$'", "signal", 1}, -- [jart]
{progname .. ' -e " "', "ok"},
{progname .. ' -e "os.exit(0, true)"', "ok"},
{progname .. ' -e "os.exit(20, true)"', "exit", 20},
@ -833,8 +836,17 @@ checkerr("missing", os.time, {hour = 12}) -- missing date
if string.packsize("i") == 4 then -- 4-byte ints
checkerr("field 'year' is out-of-bound", os.time,
{year = -(1 << 31) + 1899, month = 1, day = 1})
checkerr("field 'year' is out-of-bound", os.time,
{year = -(1 << 31), month = 1, day = 1})
if math.maxinteger > 2^31 then -- larger lua_integer?
checkerr("field 'year' is out-of-bound", os.time,
{year = (1 << 31) + 1900, month = 1, day = 1})
end
end
if not _port then
-- test Posix-specific modifiers
assert(type(os.date("%Ex")) == 'string')

View file

@ -125,7 +125,7 @@ do
end
a:test()
_G.temp = nil
end
@ -134,7 +134,7 @@ do local f = function () end end
print("functions with errors")
prog = [[
local prog = [[
do
a = 10;
function foo(x,y)
@ -153,22 +153,25 @@ do
end
end
end
rawset(_G, "a", nil)
_G.x = nil
do
foo = nil
print('long strings')
x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
local x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
assert(string.len(x)==80)
s = ''
k = math.min(300, (math.maxinteger // 80) // 2)
for n = 1, k do s = s..x; j=tostring(n) end
local s = ''
local k = math.min(300, (math.maxinteger // 80) // 2)
for n = 1, k do s = s..x; local j=tostring(n) end
assert(string.len(s) == k*80)
s = string.sub(s, 1, 10000)
s, i = string.gsub(s, '(%d%d%d%d)', '')
local s, i = string.gsub(s, '(%d%d%d%d)', '')
assert(i==10000 // 4)
s = nil
x = nil
assert(_G["while"] == 234)
_G["while"] = nil
end
--
@ -227,8 +230,8 @@ end
print("clearing tables")
lim = 15
a = {}
local lim = 15
local a = {}
-- fill a with `collectable' indices
for i=1,lim do a[{}] = i end
b = {}
@ -371,7 +374,7 @@ if T then
warn("@on"); warn("@store")
collectgarbage()
assert(string.find(_WARN, "error in __gc metamethod"))
assert(string.find(_WARN, "error in __gc"))
assert(string.match(_WARN, "@(.-)@") == "expected"); _WARN = false
for i = 8, 10 do assert(s[i]) end
@ -552,6 +555,7 @@ do
for i=1,1000 do _ENV.a = {} end -- no collection during the loop
until gcinfo() > 2 * x
collectgarbage"restart"
_ENV.a = nil
end
@ -676,11 +680,13 @@ end
-- just to make sure
assert(collectgarbage'isrunning')
do -- check that the collector is reentrant in incremental mode
do -- check that the collector is not reentrant in incremental mode
local res = true
setmetatable({}, {__gc = function ()
collectgarbage()
res = collectgarbage()
end})
collectgarbage()
assert(not res)
end

View file

@ -11,17 +11,17 @@ CFLAGS = -Wall -std=gnu99 -O2 -I$(LUA_DIR) -fPIC -shared
all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so
touch all
lib1.so: lib1.c $(LUA_DIR)/luaconf.h
lib1.so: lib1.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib1.so lib1.c
lib11.so: lib11.c $(LUA_DIR)/luaconf.h
lib11.so: lib11.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib11.so lib11.c
lib2.so: lib2.c $(LUA_DIR)/luaconf.h
lib2.so: lib2.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib2.so lib2.c
lib21.so: lib21.c $(LUA_DIR)/luaconf.h
lib21.so: lib21.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib21.so lib21.c
lib2-v2.so: lib21.c $(LUA_DIR)/luaconf.h
lib2-v2.so: lib21.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib2-v2.so lib22.c

View file

@ -10,6 +10,7 @@ local function dostring (x) return assert(load(x), "")() end
dostring("x \v\f = \t\r 'a\0a' \v\f\f")
assert(x == 'a\0a' and string.len(x) == 3)
_G.x = nil
-- escape sequences
assert('\n\"\'\\' == [[
@ -129,16 +130,16 @@ end
-- long variable names
var1 = string.rep('a', 15000) .. '1'
var2 = string.rep('a', 15000) .. '2'
prog = string.format([[
local var1 = string.rep('a', 15000) .. '1'
local var2 = string.rep('a', 15000) .. '2'
local prog = string.format([[
%s = 5
%s = %s + 1
return function () return %s - %s end
]], var1, var2, var1, var1, var2)
local f = dostring(prog)
assert(_G[var1] == 5 and _G[var2] == 6 and f() == -1)
var1, var2, f = nil
_G[var1], _G[var2] = nil
print('+')
-- escapes --
@ -150,13 +151,13 @@ assert([[
$debug]] == "\n $debug")
assert([[ [ ]] ~= [[ ] ]])
-- long strings --
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
local b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
assert(string.len(b) == 960)
prog = [=[
print('+')
a1 = [["this is a 'string' with several 'quotes'"]]
a2 = "'quotes'"
local a1 = [["this is a 'string' with several 'quotes'"]]
local a2 = "'quotes'"
assert(string.find(a1, a2) == 34)
print('+')
@ -164,12 +165,13 @@ print('+')
a1 = [==[temp = [[an arbitrary value]]; ]==]
assert(load(a1))()
assert(temp == 'an arbitrary value')
_G.temp = nil
-- long strings --
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
local b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
assert(string.len(b) == 960)
print('+')
a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789
local a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789
@ -199,19 +201,41 @@ x = 1
]=]
print('+')
x = nil
_G.x = nil
dostring(prog)
assert(x)
_G.x = nil
prog = nil
a = nil
b = nil
do -- reuse of long strings
-- get the address of a string
local function getadd (s) return string.format("%p", s) end
local s1 <const> = "01234567890123456789012345678901234567890123456789"
local s2 <const> = "01234567890123456789012345678901234567890123456789"
local s3 = "01234567890123456789012345678901234567890123456789"
local function foo() return s1 end
local function foo1() return s3 end
local function foo2()
return "01234567890123456789012345678901234567890123456789"
end
local a1 = getadd(s1)
assert(a1 == getadd(s2))
assert(a1 == getadd(foo()))
assert(a1 == getadd(foo1()))
assert(a1 == getadd(foo2()))
local sd = "0123456789" .. "0123456789012345678901234567890123456789"
assert(sd == s1 and getadd(sd) ~= a1)
end
-- testing line ends
prog = [[
a = 1 -- a comment
b = 2
local a = 1 -- a comment
local b = 2
x = [=[
@ -228,10 +252,11 @@ for _, n in pairs{"\n", "\r", "\n\r", "\r\n"} do
assert(dostring(prog) == nn)
assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n")
end
_G.x, _G.y = nil
-- testing comments and strings with long brackets
a = [==[]=]==]
local a = [==[]=]==]
assert(a == "]=")
a = [==[[===[[=[]]=][====[]]===]===]==]

View file

@ -37,7 +37,7 @@ end
f = nil
local f
x = 1
local x = 1
a = nil
load('local a = {}')()
@ -152,7 +152,7 @@ local dummy
local _ENV = (function (...) return ... end)(_G, dummy) -- {
do local _ENV = {assert=assert}; assert(true) end
mt = {_G = _G}
local mt = {_G = _G}
local foo,x
A = false -- "declare" A
do local _ENV = mt
@ -174,6 +174,8 @@ do local _ENV = {assert=assert, A=10};
end
assert(x==20)
A = nil
do -- constants
local a<const>, b, c<const> = 10, 20, 30
@ -187,6 +189,8 @@ do -- constants
checkro("y", "local x, y <const>, z = 10, 20, 30; x = 11; y = 12")
checkro("x", "local x <const>, y, z <const> = 10, 20, 30; x = 11")
checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
checkro("foo", "local foo <const> = 10; function foo() end")
checkro("foo", "local foo <const> = {}; function foo() end")
checkro("z", [[
local a, z <const>, b = 10;
@ -335,6 +339,49 @@ do
end
do
-- bug in 5.4.3: previous condition (calls cannot be tail in the
-- scope of to-be-closed variables) must be valid for tbc variables
-- created by 'for' loops.
local closed = false
local function foo ()
return function () return true end, 0, 0,
func2close(function () closed = true end)
end
local function tail() return closed end
local function foo1 ()
for k in foo() do return tail() end
end
assert(foo1() == false)
assert(closed == true)
end
do
-- bug in 5.4.4: 'break' may generate wrong 'close' instruction when
-- leaving a loop block.
local closed = false
local o1 = setmetatable({}, {__close=function() closed = true end})
local function test()
for k, v in next, {}, nil, o1 do
local function f() return k end -- create an upvalue
break
end
assert(closed)
end
test()
end
do print("testing errors in __close")
-- original error is in __close
@ -567,6 +614,28 @@ end
if rawget(_G, "T") then
do
-- bug in 5.4.3
-- 'lua_settop' may use a pointer to stack invalidated by 'luaF_close'
-- reduce stack size
collectgarbage(); collectgarbage(); collectgarbage()
-- force a stack reallocation
local function loop (n)
if n < 400 then loop(n + 1) end
end
-- close metamethod will reallocate the stack
local o = setmetatable({}, {__close = function () loop(0) end})
local script = [[toclose 2; settop 1; return 1]]
assert(T.testC(script, o) == script)
end
-- memory error inside closing function
local function foo ()
local y <close> = func2close(function () T.alloccount() end)
@ -644,7 +713,7 @@ if rawget(_G, "T") then
collectgarbage(); collectgarbage()
m = T.totalmem()
local m = T.totalmem()
collectgarbage("stop")
-- error in the first buffer allocation
@ -790,6 +859,65 @@ do
end
do
-- yielding inside closing metamethods while returning
-- (bug in 5.4.3)
local extrares -- result from extra yield (if any)
local function check (body, extra, ...)
local t = table.pack(...) -- expected returns
local co = coroutine.wrap(body)
if extra then
extrares = co() -- runs until first (extra) yield
end
local res = table.pack(co()) -- runs until yield inside '__close'
assert(res.n == 2 and res[2] == nil)
local res2 = table.pack(co()) -- runs until end of function
assert(res2.n == t.n)
for i = 1, #t do
if t[i] == "x" then
assert(res2[i] == res[1]) -- value that was closed
else
assert(res2[i] == t[i])
end
end
end
local function foo ()
local x <close> = func2close(coroutine.yield)
local extra <close> = func2close(function (self)
assert(self == extrares)
coroutine.yield(100)
end)
extrares = extra
return table.unpack{10, x, 30}
end
check(foo, true, 10, "x", 30)
assert(extrares == 100)
local function foo ()
local x <close> = func2close(coroutine.yield)
return
end
check(foo, false)
local function foo ()
local x <close> = func2close(coroutine.yield)
local y, z = 20, 30
return x
end
check(foo, false, "x")
local function foo ()
local x <close> = func2close(coroutine.yield)
local extra <close> = func2close(coroutine.yield)
return table.unpack({}, 1, 100) -- 100 nils
end
check(foo, true, table.unpack({}, 1, 100))
end
do
-- yielding inside closing metamethods after an error

View file

@ -94,6 +94,33 @@ RUN('echo "print(10)\nprint(2)\n" | lua > %s', out)
checkout("10\n2\n")
-- testing BOM
prepfile("\xEF\xBB\xBF")
RUN('lua %s > %s', prog, out)
checkout("")
prepfile("\xEF\xBB\xBFprint(3)")
RUN('lua %s > %s', prog, out)
checkout("3\n")
prepfile("\xEF\xBB\xBF# comment!!\nprint(3)")
RUN('lua %s > %s', prog, out)
checkout("3\n")
-- bad BOMs
prepfile("\xEF")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
prepfile("\xEF\xBB")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
prepfile("\xEFprint(3)")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
prepfile("\xEF\xBBprint(3)")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
-- test option '-'
RUN('echo "print(arg[1])" | lua - -h > %s', out)
checkout("-h\n")
@ -190,6 +217,11 @@ prepfile(("print(a); print(_G['%s'].x)"):format(prog), otherprog)
RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out)
checkout("1\n2\n15\n2\n15\n")
-- test explicit global names in -l
prepfile("print(str.upper'alo alo', m.max(10, 20))")
RUN("lua -l 'str=string' '-lm=math' -e 'print(m.sin(0))' %s > %s", prog, out)
checkout("0.0\nALO ALO\t20\n")
-- test 'arg' table
local a = [[
assert(#arg == 3 and arg[1] == 'a' and
@ -256,6 +288,34 @@ u2 = setmetatable({}, {__gc = function () error("ZYX") end})
RUN('lua -W %s 2> %s', prog, out)
checkprogout("ZYX)\nXYZ)\n")
-- bug since 5.2: finalizer called when closing a state could
-- subvert finalization order
prepfile[[
-- should be called last
print("creating 1")
setmetatable({}, {__gc = function () print(1) end})
print("creating 2")
setmetatable({}, {__gc = function ()
print("2")
print("creating 3")
-- this finalizer should not be called, as object will be
-- created after 'lua_close' has been called
setmetatable({}, {__gc = function () print(3) end})
print(collectgarbage()) -- cannot call collector here
os.exit(0, true)
end})
]]
RUN('lua -W %s > %s', prog, out)
checkout[[
creating 1
creating 2
2
creating 3
nil
1
]]
-- test many arguments
prepfile[[print(({...})[30])]]
@ -279,7 +339,7 @@ prepfile("a = [[b\nc\nd\ne]]\n=a")
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
checkprogout("b\nc\nd\ne\n\n")
prompt = "alo"
local prompt = "alo"
prepfile[[ --
a = 2
]]
@ -339,7 +399,7 @@ NoRun("error object is a table value", [[lua %s]], prog)
-- chunk broken in many lines
s = [=[ --
local s = [=[ --
function f ( x )
local a = [[
xuxu
@ -361,12 +421,10 @@ checkprogout("101\n13\t22\n\n")
prepfile[[#comment in 1st line without \n at the end]]
RUN('lua %s', prog)
prepfile[[#test line number when file starts with comment line
debug = require"debug"
print(debug.getinfo(1).currentline)
]]
-- first-line comment with binary file
prepfile("#comment\n" .. string.dump(load("print(3)")))
RUN('lua %s > %s', prog, out)
checkprogout('3\n')
checkout('3\n')
-- close Lua with an open file
prepfile(string.format([[io.output(%q); io.write('alo')]], out))

View file

@ -50,7 +50,7 @@ end
local msgf2i = "number.* has no integer representation"
-- float equality
function eq (a,b,limit)
local function eq (a,b,limit)
if not limit then
if floatbits >= 50 then limit = 1E-11
else limit = 1E-5
@ -62,7 +62,7 @@ end
-- equality with types
function eqT (a,b)
local function eqT (a,b)
return a == b and math.type(a) == math.type(b)
end
@ -83,7 +83,7 @@ end
do
local x = -1
local mz = 0/x -- minus zero
t = {[0] = 10, 20, 30, 40, 50}
local t = {[0] = 10, 20, 30, 40, 50}
assert(t[mz] == t[0] and t[-0] == t[0])
end
@ -849,6 +849,7 @@ do
math.randomseed(x, y) -- again should repeat the state
assert(math.random(0) == res)
-- keep the random seed for following tests
print(string.format("random seeds: %d, %d", x, y))
end
do -- test random for floats

View file

@ -9,6 +9,16 @@ local function checkerror (msg, f, ...)
end
local function check (t, na, nh)
if not T then return end
local a, h = T.querytab(t)
if a ~= na or h ~= nh then
print(na, nh, a, h)
assert(nil)
end
end
local a = {}
-- make sure table has lots of space in hash part
@ -20,6 +30,25 @@ for i=1,100 do
assert(#a == i)
end
do -- rehash moving elements from array to hash
local a = {}
for i = 1, 100 do a[i] = i end
check(a, 128, 0)
for i = 5, 95 do a[i] = nil end
check(a, 128, 0)
a.x = 1 -- force a re-hash
check(a, 4, 8)
for i = 1, 4 do assert(a[i] == i) end
for i = 5, 95 do assert(a[i] == nil) end
for i = 96, 100 do assert(a[i] == i) end
assert(a.x == 1)
end
-- testing ipairs
local x = 0
for k,v in ipairs{10,20,30;x=12} do
@ -43,6 +72,14 @@ assert(i == 4)
assert(type(ipairs{}) == 'function' and ipairs{} == ipairs{})
do -- overflow (must wrap-around)
local f = ipairs{}
local k, v = f({[math.mininteger] = 10}, math.maxinteger)
assert(k == math.mininteger and v == 10)
k, v = f({[math.mininteger] = 10}, k)
assert(k == nil)
end
if not T then
(Message or print)
('\n >>> testC not active: skipping tests for table sizes <<<\n')
@ -57,15 +94,6 @@ local function mp2 (n) -- minimum power of 2 >= n
end
local function check (t, na, nh)
local a, h = T.querytab(t)
if a ~= na or h ~= nh then
print(na, nh, a, h)
assert(nil)
end
end
-- testing C library sizes
do
local s = 0
@ -161,7 +189,7 @@ end
-- size tests for vararg
lim = 35
function foo (n, ...)
local function foo (n, ...)
local arg = {...}
check(arg, n, 0)
assert(select('#', ...) == n)
@ -499,6 +527,15 @@ do -- testing table library with metamethods
end
do -- testing overflow in table.insert (must wrap-around)
local t = setmetatable({},
{__len = function () return math.maxinteger end})
table.insert(t, 20)
local k, v = next(t)
assert(k == math.mininteger and v == 20)
end
if not T then
(Message or print)
('\n >>> testC not active: skipping tests for table library on non-tables <<<\n')
@ -764,4 +801,25 @@ for k,v in ipairs(a) do
end
assert(i == a.n)
-- testing yield inside __pairs
do
local t = setmetatable({10, 20, 30}, {__pairs = function (t)
local inc = coroutine.yield()
return function (t, i)
if i > 1 then return i - inc, t[i - inc] else return nil end
end, t, #t + 1
end})
local res = {}
local co = coroutine.wrap(function ()
for i,p in pairs(t) do res[#res + 1] = p end
end)
co() -- start coroutine
co(1) -- continue after yield
assert(res[1] == 30 and res[2] == 20 and res[3] == 10 and #res == 3)
end
print"OK"

View file

@ -9,12 +9,12 @@ local function checkerror (msg, f, ...)
end
function f(s, p)
local function f (s, p)
local i,e = string.find(s, p)
if i then return string.sub(s, i, e) end
end
a,b = string.find('', '') -- empty patterns are tricky
local a,b = string.find('', '') -- empty patterns are tricky
assert(a == 1 and b == 0);
a,b = string.find('alo', '')
assert(a == 1 and b == 0)
@ -88,7 +88,7 @@ assert(f("alo alo", "%C+") == "alo alo")
print('+')
function f1(s, p)
local function f1 (s, p)
p = string.gsub(p, "%%([0-9])", function (s)
return "%" .. (tonumber(s)+1)
end)
@ -113,7 +113,7 @@ local abc = string.char(range(0, 127)) .. string.char(range(128, 255));
assert(string.len(abc) == 256)
function strset (p)
local function strset (p)
local res = {s=''}
string.gsub(abc, p, function (c) res.s = res.s .. c end)
return res.s
@ -147,7 +147,7 @@ assert(string.gsub('
assert(string.gsub('alo úlo ', ' +$', '') == 'alo úlo') -- trim
assert(string.gsub(' alo alo ', '^%s*(.-)%s*$', '%1') == 'alo alo') -- double trim
assert(string.gsub('alo alo \n 123\n ', '%s+', ' ') == 'alo alo 123 ')
t = "abç d"
local t = "abç d"
a, b = string.gsub(t, '(.)', '%1@')
assert('@'..a == string.gsub(t, '', '@') and b == 5)
a, b = string.gsub('abçd', '(.)', '%0@', 2)
@ -184,6 +184,7 @@ do
local function setglobal (n,v) rawset(_G, n, v) end
string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal)
assert(_G.a=="roberto" and _G.roberto=="a")
_G.a = nil; _G.roberto = nil
end
function f(a,b) return string.gsub(a,'.',b) end
@ -195,20 +196,21 @@ assert(string.gsub("alo $a='x'$ novamente $return a$",
"$([^$]*)%$",
dostring) == "alo novamente x")
x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$",
local x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$",
"$([^$]*)%$", dostring)
assert(x == ' assim vai para ALO')
_G.a, _G.x = nil
t = {}
s = 'a alo jose joao'
r = string.gsub(s, '()(%w+)()', function (a,w,b)
assert(string.len(w) == b-a);
t[a] = b-a;
end)
local t = {}
local s = 'a alo jose joao'
local r = string.gsub(s, '()(%w+)()', function (a,w,b)
assert(string.len(w) == b-a);
t[a] = b-a;
end)
assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4)
function isbalanced (s)
local function isbalanced (s)
return not string.find(string.gsub(s, "%b()", ""), "[()]")
end
@ -251,7 +253,7 @@ if not _soft then
end
-- recursive nest of gsubs
function rev (s)
local function rev (s)
return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end)
end

View file

@ -20,7 +20,7 @@ end
checkerror("wrong number of arguments", table.insert, {}, 2, 3, 4)
local x,y,z,a,n
a = {}; lim = _soft and 200 or 2000
a = {}; local lim = _soft and 200 or 2000
for i=1, lim do a[i]=i end
assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim)
x = unpack(a)
@ -222,7 +222,7 @@ a = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
table.sort(a)
check(a)
function perm (s, n)
local function perm (s, n)
n = n or #s
if n == 1 then
local t = {unpack(s)}
@ -248,7 +248,7 @@ perm{1,2,3,3,5}
perm{1,2,3,4,5,6}
perm{2,2,3,3,5,6}
function timesort (a, n, func, msg, pre)
local function timesort (a, n, func, msg, pre)
local x = os.clock()
table.sort(a, func)
x = (os.clock() - x) * 1000
@ -257,7 +257,7 @@ function timesort (a, n, func, msg, pre)
check(a, func)
end
limit = 50000
local limit = 50000
if _soft then limit = 5000 end
a = {}
@ -274,7 +274,7 @@ for i=1,limit do
a[i] = math.random()
end
x = os.clock(); i=0
local x = os.clock(); local i = 0
table.sort(a, function(x,y) i=i+1; return y<x end)
x = (os.clock() - x) * 1000
print(string.format("Invert-sorting other %d elements in %.2f msec., with %i comparisons",
@ -289,18 +289,19 @@ timesort(a, limit, function(x,y) return nil end, "equal")
for i,v in pairs(a) do assert(v == false) end
A = {"álo", "\0first :-)", "alo", "then this one", "45", "and a new"}
table.sort(A)
check(A)
AA = {"álo", "\0first :-)", "alo", "then this one", "45", "and a new"}
table.sort(AA)
check(AA)
table.sort(A, function (x, y)
load(string.format("A[%q] = ''", x), "")()
table.sort(AA, function (x, y)
load(string.format("AA[%q] = ''", x), "")()
collectgarbage()
return x<y
end)
_G.AA = nil
tt = {__lt = function (a,b) return a.val < b.val end}
local tt = {__lt = function (a,b) return a.val < b.val end}
a = {}
for i=1,10 do a[i] = {val=math.random(100)}; setmetatable(a[i], tt); end
table.sort(a)

View file

@ -52,7 +52,7 @@ assert(("\000123456789"):sub(8) == "789")
-- testing string.find
assert(string.find("123456789", "345") == 3)
a,b = string.find("123456789", "345")
local a,b = string.find("123456789", "345")
assert(string.sub("123456789", a, b) == "345")
assert(string.find("1234567890123456789", "345", 3) == 3)
assert(string.find("1234567890123456789", "345", 4) == 13)
@ -192,7 +192,7 @@ do -- tests for '%p' format
end
end
x = '"ílo"\n\\'
local x = '"ílo"\n\\'
assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\')
assert(string.format('%q', "\0") == [["\0"]])
assert(load(string.format('return %q', x))() == x)
@ -202,13 +202,11 @@ assert(string.format("\0%c\0%c%x\0", string.byte("\xe4"), string.byte("b"), 140)
"\0\xe4\0b8c\0")
assert(string.format('') == "")
assert(string.format("%c",34)..string.format("%c",48)..string.format("%c",90)..string.format("%c",100) ==
string.format("%c%c%c%c", 34, 48, 90, 100))
string.format("%1c%-c%-1c%c", 34, 48, 90, 100))
assert(string.format("%s\0 is not \0%s", 'not be', 'be') == 'not be\0 is not \0be')
assert(string.format("%%%d %010d", 10, 23) == "%10 0000000023")
assert(tonumber(string.format("%f", 10.3)) == 10.3)
x = string.format('"%-50s"', 'a')
assert(#x == 52)
assert(string.sub(x, 1, 4) == '"a ')
assert(string.format('"%-50s"', 'a') == '"a' .. string.rep(' ', 49) .. '"')
assert(string.format("-%.20s.20s", string.rep("%", 2000)) ==
"-"..string.rep("%", 20)..".20s")
@ -237,7 +235,6 @@ end
assert(string.format("\0%s\0", "\0\0\1") == "\0\0\0\1\0")
checkerror("contains zeros", string.format, "%10s", "\0")
checkerror("cannot have modifiers", string.format, "%10q", "1")
-- format x tostring
assert(string.format("%s %s", nil, true) == "nil true")
@ -341,6 +338,26 @@ do print("testing 'format %a %A'")
end
-- testing some flags (all these results are required by ISO C)
assert(string.format("%#12o", 10) == " 012")
assert(string.format("%#10x", 100) == " 0x64")
assert(string.format("%#-17X", 100) == "0X64 ")
assert(string.format("%013i", -100) == "-000000000100")
assert(string.format("%2.5d", -100) == "-00100")
assert(string.format("%.u", 0) == "")
assert(string.format("%+#014.0f", 100) == "+000000000100.")
assert(string.format("%-16c", 97) == "a ")
assert(string.format("%+.3G", 1.5) == "+1.5")
assert(string.format("%.0s", "alo") == "")
assert(string.format("%.s", "alo") == "")
-- ISO C89 says that "The exponent always contains at least two digits",
-- but unlike ISO C99 it does not ensure that it contains "only as many
-- more digits as necessary".
assert(string.match(string.format("% 1.0E", 100), "^ 1E%+0+2$"))
assert(string.match(string.format("% .1g", 2^10), "^ 1e%+0+3$"))
-- errors in format
local function check (fmt, msg)
@ -348,13 +365,21 @@ local function check (fmt, msg)
end
local aux = string.rep('0', 600)
check("%100.3d", "too long")
check("%100.3d", "invalid conversion")
check("%1"..aux..".3d", "too long")
check("%1.100d", "too long")
check("%1.100d", "invalid conversion")
check("%10.1"..aux.."004d", "too long")
check("%t", "invalid conversion")
check("%"..aux.."d", "repeated flags")
check("%"..aux.."d", "too long")
check("%d %d", "no value")
check("%010c", "invalid conversion")
check("%.10c", "invalid conversion")
check("%0.34s", "invalid conversion")
check("%#i", "invalid conversion")
check("%3.1p", "invalid conversion")
check("%0.s", "invalid conversion")
check("%10q", "cannot have modifiers")
check("%F", "invalid conversion") -- useless and not in C89
assert(load("return 1\n--comment without ending EOL")() == 1)
@ -427,7 +452,7 @@ end
do
local f = string.gmatch("1 2 3 4 5", "%d+")
assert(f() == "1")
co = coroutine.wrap(f)
local co = coroutine.wrap(f)
assert(co() == "2")
end

View file

@ -35,7 +35,7 @@ print("\talignment: " .. align)
-- check errors in arguments
function checkerror (msg, f, ...)
local function checkerror (msg, f, ...)
local status, err = pcall(f, ...)
-- print(status, err, msg)
assert(not status and string.find(err, msg))

View file

@ -97,9 +97,15 @@ do -- error indication in utf8.len
assert(not a and b == p)
end
check("abc\xE3def", 4)
check("汉字\x80", #("汉字") + 1)
check("\xF4\x9F\xBF", 1)
check("\xF4\x9F\xBF\xBF", 1)
-- spurious continuation bytes
check("汉字\x80", #("汉字") + 1)
check("\x80hello", 1)
check("hel\x80lo", 4)
check("汉字\xBF", #("汉字") + 1)
check("\xBFhello", 1)
check("hel\xBFlo", 4)
end
-- errors in utf8.codes
@ -112,6 +118,16 @@ do
end
errorcodes("ab\xff")
errorcodes("\u{110000}")
errorcodes("in\x80valid")
errorcodes("\xbfinvalid")
errorcodes("αλφ\xBFα")
-- calling interation function with invalid arguments
local f = utf8.codes("")
assert(f("", 2) == nil)
assert(f("", -1) == nil)
assert(f("", math.mininteger) == nil)
end
-- error in initial position for offset
@ -214,7 +230,7 @@ do
check(s, {0x10000, 0x1FFFFF}, true)
end
x = "日本語a-4\0éó"
local x = "日本語a-4\0éó"
check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243})

View file

@ -3,13 +3,13 @@
print('testing vararg')
function f(a, ...)
local function f (a, ...)
local x = {n = select('#', ...), ...}
for i = 1, x.n do assert(a[i] == x[i]) end
return x.n
end
function c12 (...)
local function c12 (...)
assert(arg == _G.arg) -- no local 'arg'
local x = {...}; x.n = #x
local res = (x.n==2 and x[1] == 1 and x[2] == 2)
@ -17,7 +17,7 @@ function c12 (...)
return res, 2
end
function vararg (...) return {n = select('#', ...), ...} end
local function vararg (...) return {n = select('#', ...), ...} end
local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
@ -29,7 +29,7 @@ assert(vararg().n == 0)
assert(vararg(nil, nil).n == 2)
assert(c12(1,2)==55)
a,b = assert(call(c12, {1,2}))
local a,b = assert(call(c12, {1,2}))
assert(a == 55 and b == 2)
a = call(c12, {1,2;n=2})
assert(a == 55 and b == 2)
@ -49,7 +49,7 @@ function t:f (...) local arg = {...}; return self[...]+#arg end
assert(t:f(1,4) == 3 and t:f(2) == 11)
print('+')
lim = 20
local lim = 20
local i, a = 1, {}
while i <= lim do a[i] = i+0.3; i=i+1 end
@ -59,7 +59,7 @@ function f(a, b, c, d, ...)
more[lim-4] == lim+0.3 and not more[lim-3])
end
function g(a,b,c)
local function g (a,b,c)
assert(a == 1.3 and b == 2.3 and c == 3.3)
end
@ -76,7 +76,7 @@ print("+")
-- new-style varargs
function oneless (a, ...) return ... end
local function oneless (a, ...) return ... end
function f (n, a, ...)
local b
@ -99,8 +99,8 @@ assert(a==nil and b==nil and c==nil and d==nil and e==nil)
-- varargs for main chunks
f = load[[ return {...} ]]
x = f(2,3)
local f = load[[ return {...} ]]
local x = f(2,3)
assert(x[1] == 2 and x[2] == 3 and x[3] == undef)

View file

@ -52,7 +52,7 @@ if _soft then return 10 end
print "testing large programs (>64k)"
-- template to create a very big test file
prog = [[$
local prog = [[$
local a,b
@ -85,7 +85,7 @@ function b:xxx (a,b) return a+b end
assert(b:xxx(10, 12) == 22) -- pushself with non-constant index
b["xxx"] = undef
s = 0; n=0
local s = 0; local n=0
for a,b in pairs(b) do s=s+b; n=n+1 end
-- with 32-bit floats, exact value of 's' depends on summation order
assert(81800000.0 < s and s < 81860000 and n == 70001)
@ -93,7 +93,7 @@ assert(81800000.0 < s and s < 81860000 and n == 70001)
a = nil; b = nil
print'+'
function f(x) b=x end
local function f(x) b=x end
a = f{$3$} or 10
@ -118,7 +118,7 @@ local function sig (x)
return (x % 2 == 0) and '' or '-'
end
F = {
local F = {
function () -- $1$
for i=10,50009 do
io.write('a', i, ' = ', sig(i), 5+((i-10)/2), ',\n')
@ -138,14 +138,14 @@ function () -- $3$
end,
}
file = os.tmpname()
local file = os.tmpname()
io.output(file)
for s in string.gmatch(prog, "$([^$]+)") do
local n = tonumber(s)
if not n then io.write(s) else F[n]() end
end
io.close()
result = dofile(file)
local result = dofile(file)
assert(os.remove(file))
print'OK'
return result