eBookReaderSwitch/mupdf/thirdparty/mujs/jsrepr.c

272 lines
5.6 KiB
C

#include "jsi.h"
#include "jslex.h"
#include "jsvalue.h"
#include "jsbuiltin.h"
static void reprvalue(js_State *J, js_Buffer **sb);
static void reprnum(js_State *J, js_Buffer **sb, double n)
{
char buf[40];
if (n == 0 && signbit(n))
js_puts(J, sb, "-0");
else
js_puts(J, sb, jsV_numbertostring(J, buf, n));
}
static void reprstr(js_State *J, js_Buffer **sb, const char *s)
{
static const char *HEX = "0123456789ABCDEF";
Rune c;
js_putc(J, sb, '"');
while (*s) {
s += chartorune(&c, s);
switch (c) {
case '"': js_puts(J, sb, "\\\""); break;
case '\\': js_puts(J, sb, "\\\\"); break;
case '\b': js_puts(J, sb, "\\b"); break;
case '\f': js_puts(J, sb, "\\f"); break;
case '\n': js_puts(J, sb, "\\n"); break;
case '\r': js_puts(J, sb, "\\r"); break;
case '\t': js_puts(J, sb, "\\t"); break;
default:
if (c < ' ' || c > 127) {
js_puts(J, sb, "\\u");
js_putc(J, sb, HEX[(c>>12)&15]);
js_putc(J, sb, HEX[(c>>8)&15]);
js_putc(J, sb, HEX[(c>>4)&15]);
js_putc(J, sb, HEX[c&15]);
} else {
js_putc(J, sb, c); break;
}
}
}
js_putc(J, sb, '"');
}
#ifndef isalpha
#define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
#endif
#ifndef isdigit
#define isdigit(c) (c >= '0' && c <= '9')
#endif
static void reprident(js_State *J, js_Buffer **sb, const char *name)
{
const char *p = name;
if (isdigit(*p))
while (isdigit(*p))
++p;
else if (isalpha(*p) || *p == '_')
while (isdigit(*p) || isalpha(*p) || *p == '_')
++p;
if (p > name && *p == 0)
js_puts(J, sb, name);
else
reprstr(J, sb, name);
}
static void reprobject(js_State *J, js_Buffer **sb)
{
const char *key;
int i, n;
n = js_gettop(J) - 1;
for (i = 0; i < n; ++i) {
if (js_isobject(J, i)) {
if (js_toobject(J, i) == js_toobject(J, -1)) {
js_puts(J, sb, "{}");
return;
}
}
}
n = 0;
js_putc(J, sb, '{');
js_pushiterator(J, -1, 1);
while ((key = js_nextiterator(J, -1))) {
if (n++ > 0)
js_puts(J, sb, ", ");
reprident(J, sb, key);
js_puts(J, sb, ": ");
js_getproperty(J, -2, key);
reprvalue(J, sb);
js_pop(J, 1);
}
js_pop(J, 1);
js_putc(J, sb, '}');
}
static void reprarray(js_State *J, js_Buffer **sb)
{
int n, i;
n = js_gettop(J) - 1;
for (i = 0; i < n; ++i) {
if (js_isobject(J, i)) {
if (js_toobject(J, i) == js_toobject(J, -1)) {
js_puts(J, sb, "[]");
return;
}
}
}
js_putc(J, sb, '[');
n = js_getlength(J, -1);
for (i = 0; i < n; ++i) {
if (i > 0)
js_puts(J, sb, ", ");
if (js_hasindex(J, -1, i)) {
reprvalue(J, sb);
js_pop(J, 1);
}
}
js_putc(J, sb, ']');
}
static void reprfun(js_State *J, js_Buffer **sb, js_Function *fun)
{
int i;
js_puts(J, sb, "function ");
js_puts(J, sb, fun->name);
js_putc(J, sb, '(');
for (i = 0; i < fun->numparams; ++i) {
if (i > 0)
js_puts(J, sb, ", ");
js_puts(J, sb, fun->vartab[i]);
}
js_puts(J, sb, ") { [byte code] }");
}
static void reprvalue(js_State *J, js_Buffer **sb)
{
if (js_isundefined(J, -1))
js_puts(J, sb, "undefined");
else if (js_isnull(J, -1))
js_puts(J, sb, "null");
else if (js_isboolean(J, -1))
js_puts(J, sb, js_toboolean(J, -1) ? "true" : "false");
else if (js_isnumber(J, -1))
reprnum(J, sb, js_tonumber(J, -1));
else if (js_isstring(J, -1))
reprstr(J, sb, js_tostring(J, -1));
else if (js_isobject(J, -1)) {
js_Object *obj = js_toobject(J, -1);
switch (obj->type) {
default:
reprobject(J, sb);
break;
case JS_CARRAY:
reprarray(J, sb);
break;
case JS_CFUNCTION:
case JS_CSCRIPT:
reprfun(J, sb, obj->u.f.function);
break;
case JS_CCFUNCTION:
js_puts(J, sb, "function ");
js_puts(J, sb, obj->u.c.name);
js_puts(J, sb, "() { [native code] }");
break;
case JS_CBOOLEAN:
js_puts(J, sb, "(new Boolean(");
js_puts(J, sb, obj->u.boolean ? "true" : "false");
js_puts(J, sb, "))");
break;
case JS_CNUMBER:
js_puts(J, sb, "(new Number(");
reprnum(J, sb, obj->u.number);
js_puts(J, sb, "))");
break;
case JS_CSTRING:
js_puts(J, sb, "(new String(");
reprstr(J, sb, obj->u.s.string);
js_puts(J, sb, "))");
break;
case JS_CREGEXP:
js_putc(J, sb, '/');
js_puts(J, sb, obj->u.r.source);
js_putc(J, sb, '/');
if (obj->u.r.flags & JS_REGEXP_G) js_putc(J, sb, 'g');
if (obj->u.r.flags & JS_REGEXP_I) js_putc(J, sb, 'i');
if (obj->u.r.flags & JS_REGEXP_M) js_putc(J, sb, 'm');
break;
case JS_CDATE:
js_puts(J, sb, "(new Date(");
fmtnum(J, sb, obj->u.number);
js_puts(J, sb, "))");
break;
case JS_CERROR:
js_puts(J, sb, "(new ");
js_getproperty(J, -1, "name");
js_puts(J, sb, js_tostring(J, -1));
js_pop(J, 1);
js_putc(J, sb, '(');
js_getproperty(J, -1, "message");
reprstr(J, sb, js_tostring(J, -1));
js_pop(J, 1);
js_puts(J, sb, "))");
break;
case JS_CMATH:
js_puts(J, sb, "Math");
break;
case JS_CJSON:
js_puts(J, sb, "JSON");
break;
case JS_CITERATOR:
js_puts(J, sb, "[iterator ");
break;
case JS_CUSERDATA:
js_puts(J, sb, "[userdata ");
js_puts(J, sb, obj->u.user.tag);
js_putc(J, sb, ']');
break;
}
}
}
void js_repr(js_State *J, int idx)
{
js_Buffer *sb = NULL;
int savebot;
if (js_try(J)) {
js_free(J, sb);
js_throw(J);
}
js_copy(J, idx);
savebot = J->bot;
J->bot = J->top - 1;
reprvalue(J, &sb);
J->bot = savebot;
js_pop(J, 1);
js_putc(J, &sb, 0);
js_pushstring(J, sb ? sb->s : "undefined");
js_endtry(J);
js_free(J, sb);
}
const char *js_torepr(js_State *J, int idx)
{
js_repr(J, idx);
js_replace(J, idx < 0 ? idx-1 : idx);
return js_tostring(J, idx);
}
const char *js_tryrepr(js_State *J, int idx, const char *error)
{
const char *s;
if (js_try(J)) {
js_pop(J, 1);
return error;
}
s = js_torepr(J, idx);
js_endtry(J);
return s;
}