mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-02 17:28:30 +00:00
Make improvements
- Add hierarchical auto-completion to redbean's repl - Fetch latest localtime() and strftime() from Eggert - Shave a few milliseconds off redbean start latency - Fix redbean repl with multi-line statements - Make the Lua unix module code more elegant - Harden Lua data structure serialization
This commit is contained in:
parent
d57b81aac7
commit
6a145a9262
44 changed files with 2987 additions and 1941 deletions
4
third_party/lua/cosmo.h
vendored
4
third_party/lua/cosmo.h
vendored
|
@ -8,8 +8,8 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
char *LuaFormatStack(lua_State *) dontdiscard;
|
||||
int LuaCallWithTrace(lua_State *, int, int, lua_State *);
|
||||
int LuaEncodeJsonData(lua_State *, char **, int, char *, int);
|
||||
int LuaEncodeLuaData(lua_State *, char **, int, char *, int);
|
||||
int LuaEncodeJsonData(lua_State *, char **, char *, int);
|
||||
int LuaEncodeLuaData(lua_State *, char **, char *, int);
|
||||
int LuaEncodeUrl(lua_State *);
|
||||
int LuaParseUrl(lua_State *);
|
||||
int LuaPushHeader(lua_State *, struct HttpMessage *, char *, int);
|
||||
|
|
3
third_party/lua/ldo.c
vendored
3
third_party/lua/ldo.c
vendored
|
@ -27,6 +27,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ldo_c
|
||||
#define LUA_CORE
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "third_party/lua/lapi.h"
|
||||
#include "third_party/lua/ldebug.h"
|
||||
|
@ -148,7 +149,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
|
|||
lua_unlock(L);
|
||||
g->panic(L); /* call panic function (last chance to jump out) */
|
||||
}
|
||||
abort();
|
||||
__die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
73
third_party/lua/lrepl.c
vendored
73
third_party/lua/lrepl.c
vendored
|
@ -29,15 +29,18 @@
|
|||
#include "libc/alg/alg.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/linenoise/linenoise.h"
|
||||
#include "third_party/lua/cosmo.h"
|
||||
#include "third_party/lua/lauxlib.h"
|
||||
#include "third_party/lua/lprefix.h"
|
||||
#include "third_party/lua/lrepl.h"
|
||||
|
@ -87,37 +90,74 @@ static const char *g_historypath;
|
|||
#endif
|
||||
|
||||
|
||||
static void lua_readline_addcompletion (linenoiseCompletions *c, const char *s) {
|
||||
char **p, *t;
|
||||
static void lua_readline_addcompletion (linenoiseCompletions *c, char *s) {
|
||||
char **p;
|
||||
if ((p = realloc(c->cvec, (c->len + 1) * sizeof(*p)))) {
|
||||
c->cvec = p;
|
||||
if ((t = strdup(s))) {
|
||||
c->cvec[c->len++] = t;
|
||||
}
|
||||
c->cvec[c->len++] = s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void lua_readline_completions (const char *p, linenoiseCompletions *c) {
|
||||
int i;
|
||||
bool found;
|
||||
lua_State *L;
|
||||
const char *name;
|
||||
for (i = 0; i < ARRAYLEN(kKeywordHints); ++i) {
|
||||
if (startswithi(kKeywordHints[i], p)) {
|
||||
lua_readline_addcompletion(c, kKeywordHints[i]);
|
||||
}
|
||||
}
|
||||
char *a, *b, *component;
|
||||
|
||||
// start searching globals
|
||||
L = globalL;
|
||||
lua_pushglobaltable(L);
|
||||
|
||||
// traverse parent objects
|
||||
// split foo.bar and foo:bar
|
||||
a = p;
|
||||
b = strpbrk(a, ".:");
|
||||
while (b) {
|
||||
component = strndup(a, b - a);
|
||||
found = false;
|
||||
lua_pushnil(L); // search key
|
||||
while (lua_next(L, -2)) {
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
name = lua_tostring(L, -2);
|
||||
if (!strcmp(name, component)) {
|
||||
lua_remove(L, -3); // remove table
|
||||
lua_remove(L, -2); // remove key
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1); // pop value
|
||||
}
|
||||
free(component);
|
||||
if (!found) {
|
||||
lua_pop(L, 1); // pop table
|
||||
return;
|
||||
}
|
||||
a = b + 1;
|
||||
b = strpbrk(a, ".:");
|
||||
}
|
||||
|
||||
// search final object
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
name = lua_tostring(L, -2);
|
||||
if (startswithi(name, p)) {
|
||||
lua_readline_addcompletion(c, name);
|
||||
while (lua_next(L, -2)) {
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
name = lua_tostring(L, -2);
|
||||
if (startswithi(name, a)) {
|
||||
lua_readline_addcompletion(c, xasprintf("%.*s%s", a - p, p, name));
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
for (i = 0; i < ARRAYLEN(kKeywordHints); ++i) {
|
||||
if (startswithi(kKeywordHints[i], p)) {
|
||||
lua_readline_addcompletion(c, xstrdup(kKeywordHints[i]));
|
||||
}
|
||||
}
|
||||
if (lua_repl_completions_callback) {
|
||||
lua_repl_completions_callback(p, c);
|
||||
}
|
||||
|
@ -191,7 +231,7 @@ static ssize_t pushline (lua_State *L, int firstline) {
|
|||
prmt = strdup(get_prompt(L, firstline));
|
||||
lua_pop(L, 1); /* remove prompt */
|
||||
LUA_REPL_UNLOCK;
|
||||
rc = linenoiseEdit(lua_repl_linenoise, 0, &b, !firstline || lua_repl_blocking);
|
||||
rc = linenoiseEdit(lua_repl_linenoise, prmt, &b, !firstline || lua_repl_blocking);
|
||||
free(prmt);
|
||||
if (rc != -1) {
|
||||
if (b && *b) {
|
||||
|
@ -207,6 +247,9 @@ static ssize_t pushline (lua_State *L, int firstline) {
|
|||
LUA_REPL_LOCK;
|
||||
rc = b ? 1 : -1;
|
||||
}
|
||||
if (!(rc == -1 && errno == EAGAIN)) {
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
if (rc == -1 || (!rc && !b)) {
|
||||
return rc;
|
||||
}
|
||||
|
|
2
third_party/lua/ltests.c
vendored
2
third_party/lua/ltests.c
vendored
|
@ -1724,7 +1724,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
|
|||
lua_error(L1);
|
||||
}
|
||||
else if EQ("abort") {
|
||||
abort();
|
||||
__die();
|
||||
}
|
||||
else if EQ("throw") {
|
||||
#if defined(__cplusplus)
|
||||
|
|
2
third_party/lua/lua.main.c
vendored
2
third_party/lua/lua.main.c
vendored
|
@ -324,7 +324,6 @@ static void doREPL (lua_State *L) {
|
|||
progname = oldprogname;
|
||||
return;
|
||||
}
|
||||
lua_writeline();
|
||||
if (status == LUA_OK)
|
||||
status = lua_runchunk(L, 0, LUA_MULTRET);
|
||||
if (status == LUA_OK) {
|
||||
|
@ -335,7 +334,6 @@ static void doREPL (lua_State *L) {
|
|||
}
|
||||
lua_freerepl();
|
||||
lua_settop(L, 0); /* clear stack */
|
||||
lua_writeline();
|
||||
progname = oldprogname;
|
||||
}
|
||||
|
||||
|
|
2
third_party/lua/lua.mk
vendored
2
third_party/lua/lua.mk
vendored
|
@ -77,7 +77,7 @@ o/$(MODE)/third_party/lua/lua.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/third_party/lua/.lua/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/third_party/lua/.lua/.symtab
|
||||
|
||||
o//third_party/lua/lgc.o: \
|
||||
|
|
14
third_party/lua/luaencodejsondata.c
vendored
14
third_party/lua/luaencodejsondata.c
vendored
|
@ -25,8 +25,8 @@
|
|||
#include "third_party/lua/lauxlib.h"
|
||||
#include "third_party/lua/lua.h"
|
||||
|
||||
int LuaEncodeJsonData(lua_State *L, char **buf, int level, char *numformat,
|
||||
int idx) {
|
||||
static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
||||
char *numformat, int idx) {
|
||||
char *s;
|
||||
bool isarray;
|
||||
size_t tbllen, z;
|
||||
|
@ -93,7 +93,7 @@ int LuaEncodeJsonData(lua_State *L, char **buf, int level, char *numformat,
|
|||
for (size_t i = 1; i <= tbllen; i++) {
|
||||
if (i > 1) appendw(buf, ',');
|
||||
lua_rawgeti(L, -1, i); // table/-2, value/-1
|
||||
LuaEncodeJsonData(L, buf, level - 1, numformat, -1);
|
||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
|
@ -121,7 +121,7 @@ int LuaEncodeJsonData(lua_State *L, char **buf, int level, char *numformat,
|
|||
lua_remove(L, -1); // remove copied key: tab/-3, key/-2, val/-1
|
||||
}
|
||||
appendw(buf, '"' | ':' << 010);
|
||||
LuaEncodeJsonData(L, buf, level - 1, numformat, -1);
|
||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1);
|
||||
lua_pop(L, 1); // table/-2, key/-1
|
||||
}
|
||||
// stack: table/-1, as the key was popped by lua_next
|
||||
|
@ -137,3 +137,9 @@ int LuaEncodeJsonData(lua_State *L, char **buf, int level, char *numformat,
|
|||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
int LuaEncodeJsonData(lua_State *L, char **buf, char *numformat, int idx) {
|
||||
int rc;
|
||||
rc = LuaEncodeJsonDataImpl(L, buf, 64, numformat, idx);
|
||||
return rc;
|
||||
}
|
||||
|
|
118
third_party/lua/luaencodeluadata.c
vendored
118
third_party/lua/luaencodeluadata.c
vendored
|
@ -16,42 +16,98 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/lua/cosmo.h"
|
||||
#include "third_party/lua/lauxlib.h"
|
||||
#include "third_party/lua/lua.h"
|
||||
|
||||
int LuaEncodeLuaData(lua_State *L, char **buf, int level, char *numformat,
|
||||
int idx) {
|
||||
struct Visited {
|
||||
int n;
|
||||
void **p;
|
||||
};
|
||||
|
||||
static bool PushVisit(struct Visited *visited, void *p) {
|
||||
int i;
|
||||
for (i = 0; i < visited->n; ++i) {
|
||||
if (visited->p[i] == p) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
visited->p = xrealloc(visited->p, ++visited->n * sizeof(*visited->p));
|
||||
visited->p[visited->n - 1] = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void PopVisit(struct Visited *visited) {
|
||||
assert(visited->n > 0);
|
||||
--visited->n;
|
||||
}
|
||||
|
||||
static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
|
||||
char *numformat, int idx,
|
||||
struct Visited *visited) {
|
||||
char *s;
|
||||
int ktype;
|
||||
bool didcomma;
|
||||
lua_Integer i;
|
||||
int ktype, vtype;
|
||||
size_t tbllen, buflen, slen;
|
||||
char ibuf[21], fmt[] = "%.14g";
|
||||
if (level > 0) {
|
||||
switch (lua_type(L, idx)) {
|
||||
|
||||
case LUA_TNIL:
|
||||
appendw(buf, READ32LE("nil"));
|
||||
return 0;
|
||||
|
||||
case LUA_TSTRING:
|
||||
s = lua_tolstring(L, idx, &slen);
|
||||
EscapeLuaString(s, slen, buf);
|
||||
return 0;
|
||||
|
||||
case LUA_TFUNCTION:
|
||||
appendf(buf, "\"func@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TUSERDATA:
|
||||
appendf(buf, "\"udata@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
appendf(buf, "\"light@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
|
||||
case LUA_TTHREAD:
|
||||
appendf(buf, "\"thread@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
|
||||
case LUA_TUSERDATA:
|
||||
if (luaL_callmeta(L, idx, "__repr")) {
|
||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||
s = lua_tolstring(L, -1, &slen);
|
||||
appendd(buf, s, slen);
|
||||
} else {
|
||||
appendf(buf, "[[error %s returned a %s value]]", "__repr",
|
||||
luaL_typename(L, -1));
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return 0;
|
||||
}
|
||||
if (luaL_callmeta(L, idx, "__tostring")) {
|
||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||
s = lua_tolstring(L, -1, &slen);
|
||||
EscapeLuaString(s, slen, buf);
|
||||
} else {
|
||||
appendf(buf, "[[error %s returned a %s value]]", "__tostring",
|
||||
luaL_typename(L, -1));
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return 0;
|
||||
}
|
||||
appendf(buf, "\"udata@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
|
||||
case LUA_TNUMBER:
|
||||
if (lua_isinteger(L, idx)) {
|
||||
appendd(buf, ibuf,
|
||||
|
@ -69,11 +125,13 @@ int LuaEncodeLuaData(lua_State *L, char **buf, int level, char *numformat,
|
|||
fmt[4] = *numformat;
|
||||
break;
|
||||
default:
|
||||
return luaL_error(L, "numformat string not allowed");
|
||||
luaL_error(L, "numformat string not allowed");
|
||||
unreachable;
|
||||
}
|
||||
appendf(buf, fmt, lua_tonumber(L, idx));
|
||||
}
|
||||
return 0;
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
if (lua_toboolean(L, idx)) {
|
||||
appendw(buf, READ32LE("true"));
|
||||
|
@ -81,26 +139,47 @@ int LuaEncodeLuaData(lua_State *L, char **buf, int level, char *numformat,
|
|||
appendw(buf, READ64LE("false\0\0"));
|
||||
}
|
||||
return 0;
|
||||
|
||||
case LUA_TTABLE:
|
||||
i = 0;
|
||||
didcomma = false;
|
||||
appendw(buf, '{');
|
||||
lua_pushvalue(L, idx);
|
||||
lua_pushnil(L); // push the first key
|
||||
while (lua_next(L, -2) != 0) {
|
||||
while (lua_next(L, -2)) {
|
||||
++i;
|
||||
ktype = lua_type(L, -2);
|
||||
if (i++ > 0) appendw(buf, ',');
|
||||
vtype = lua_type(L, -1);
|
||||
if (ktype != LUA_TNUMBER || lua_tointeger(L, -2) != i) {
|
||||
appendw(buf, '[');
|
||||
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
||||
LuaEncodeLuaData(L, buf, level - 1, numformat, -1);
|
||||
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
|
||||
appendw(buf, ']' | '=' << 010);
|
||||
if (PushVisit(visited, lua_touserdata(L, -2))) {
|
||||
if (i > 1) appendw(buf, ',' | ' ' << 8);
|
||||
didcomma = true;
|
||||
appendw(buf, '[');
|
||||
LuaEncodeLuaDataImpl(L, buf, level - 1, numformat, -2, visited);
|
||||
appendw(buf, ']' | '=' << 010);
|
||||
PopVisit(visited);
|
||||
} else {
|
||||
// TODO: Strange Lua data structure, do nothing.
|
||||
lua_pop(L, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (PushVisit(visited, lua_touserdata(L, -1))) {
|
||||
if (!didcomma && i > 1) appendw(buf, ',' | ' ' << 8);
|
||||
LuaEncodeLuaDataImpl(L, buf, level - 1, numformat, -1, visited);
|
||||
PopVisit(visited);
|
||||
} else {
|
||||
// TODO: Strange Lua data structure, do nothing.
|
||||
lua_pop(L, 1);
|
||||
continue;
|
||||
}
|
||||
LuaEncodeLuaData(L, buf, level - 1, numformat, -1);
|
||||
lua_pop(L, 1); // table/-2, key/-1
|
||||
}
|
||||
lua_pop(L, 1); // table
|
||||
// stack: table/-1, as the key was popped by lua_next
|
||||
appendw(buf, '}');
|
||||
return 0;
|
||||
|
||||
default:
|
||||
luaL_error(L, "can't serialize value of this type");
|
||||
unreachable;
|
||||
|
@ -110,3 +189,12 @@ int LuaEncodeLuaData(lua_State *L, char **buf, int level, char *numformat,
|
|||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
int LuaEncodeLuaData(lua_State *L, char **buf, char *numformat, int idx) {
|
||||
int rc;
|
||||
struct Visited visited = {0};
|
||||
rc = LuaEncodeLuaDataImpl(L, buf, 64, numformat, idx, &visited);
|
||||
assert(!visited.n);
|
||||
free(visited.p);
|
||||
return rc;
|
||||
}
|
||||
|
|
2
third_party/lua/luaformatstack.c
vendored
2
third_party/lua/luaformatstack.c
vendored
|
@ -28,7 +28,7 @@ dontdiscard char *LuaFormatStack(lua_State *L) {
|
|||
for (i = 1; i <= top; i++) {
|
||||
if (i > 1) appendw(&b, '\n');
|
||||
appendf(&b, "\t%d\t%s\t", i, luaL_typename(L, i));
|
||||
LuaEncodeLuaData(L, &b, 64, "g", -1);
|
||||
LuaEncodeLuaData(L, &b, "g", i);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue