mirror of
https://github.com/ccxvii/mujs.git
synced 2026-02-06 01:41:37 +08:00
Add repr() function to shell, and use it in the REPL.
This commit is contained in:
@@ -71,7 +71,7 @@ static void Fp_toString(js_State *J)
|
||||
if (i > 0) js_putc(J, &sb, ',');
|
||||
js_puts(J, &sb, F->vartab[i]);
|
||||
}
|
||||
js_puts(J, &sb, ") { ... }");
|
||||
js_puts(J, &sb, ") { [byte code] }");
|
||||
js_putc(J, &sb, 0);
|
||||
|
||||
js_pushstring(J, sb->s);
|
||||
@@ -85,14 +85,14 @@ static void Fp_toString(js_State *J)
|
||||
|
||||
js_puts(J, &sb, "function ");
|
||||
js_puts(J, &sb, self->u.c.name);
|
||||
js_puts(J, &sb, "() { ... }");
|
||||
js_puts(J, &sb, "() { [native code] }");
|
||||
js_putc(J, &sb, 0);
|
||||
|
||||
js_pushstring(J, sb->s);
|
||||
js_endtry(J);
|
||||
js_free(J, sb);
|
||||
} else {
|
||||
js_pushliteral(J, "function () { ... }");
|
||||
js_pushliteral(J, "function () { }");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
6
jslex.c
6
jslex.c
@@ -117,9 +117,15 @@ int jsY_isnewline(int c)
|
||||
return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;
|
||||
}
|
||||
|
||||
#ifndef isalpha
|
||||
#define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
|
||||
#endif
|
||||
#ifndef isdigit
|
||||
#define isdigit(c) (c >= '0' && c <= '9')
|
||||
#endif
|
||||
#ifndef ishex
|
||||
#define ishex(c) ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
|
||||
#endif
|
||||
|
||||
static int jsY_isidentifierstart(int c)
|
||||
{
|
||||
|
||||
270
jsrepr.c
Normal file
270
jsrepr.c
Normal file
@@ -0,0 +1,270 @@
|
||||
#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, ", ");
|
||||
js_getindex(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;
|
||||
}
|
||||
15
main.c
15
main.c
@@ -199,6 +199,11 @@ static void jsB_quit(js_State *J)
|
||||
exit(js_tonumber(J, 1));
|
||||
}
|
||||
|
||||
static void jsB_repr(js_State *J)
|
||||
{
|
||||
js_repr(J, 1);
|
||||
}
|
||||
|
||||
static const char *require_js =
|
||||
"function require(name) {\n"
|
||||
"var cache = require.cache;\n"
|
||||
@@ -220,7 +225,7 @@ static const char *stacktrace_js =
|
||||
|
||||
static int eval_print(js_State *J, const char *source)
|
||||
{
|
||||
if (js_ploadstring(J, "[string]", source)) {
|
||||
if (js_ploadstring(J, "[stdin]", source)) {
|
||||
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
|
||||
js_pop(J, 1);
|
||||
return 1;
|
||||
@@ -231,8 +236,9 @@ static int eval_print(js_State *J, const char *source)
|
||||
js_pop(J, 1);
|
||||
return 1;
|
||||
}
|
||||
if (js_isdefined(J, -1))
|
||||
printf("%s\n", js_trystring(J, -1, "can't convert to string"));
|
||||
if (js_isdefined(J, -1)) {
|
||||
printf("%s\n", js_tryrepr(J, -1, "can't convert to string"));
|
||||
}
|
||||
js_pop(J, 1);
|
||||
return 0;
|
||||
}
|
||||
@@ -316,6 +322,9 @@ main(int argc, char **argv)
|
||||
js_newcfunction(J, jsB_readline, "readline", 0);
|
||||
js_setglobal(J, "readline");
|
||||
|
||||
js_newcfunction(J, jsB_repr, "repr", 0);
|
||||
js_setglobal(J, "repr");
|
||||
|
||||
js_newcfunction(J, jsB_quit, "quit", 1);
|
||||
js_setglobal(J, "quit");
|
||||
|
||||
|
||||
4
mujs.h
4
mujs.h
@@ -215,6 +215,10 @@ int js_strictequal(js_State *J);
|
||||
int js_instanceof(js_State *J);
|
||||
const char *js_typeof(js_State *J, int idx);
|
||||
|
||||
void js_repr(js_State *J, int idx);
|
||||
const char *js_torepr(js_State *J, int idx);
|
||||
const char *js_tryrepr(js_State *J, int idx, const char *error);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user