ref: 8aa062755760b61f9131a0411e9125bafddc0a4f
parent: 3c58fa90c8fd063c7ccb00a85a7e238ae2788a73
author: Tor Andersson <tor@ccxvii.net>
date: Sun Jan 19 19:13:47 EST 2014
Add Error builtin objects and exception stack.
--- a/js.h
+++ b/js.h
@@ -40,10 +40,8 @@
js_State *js_newstate(void);
void js_close(js_State *J);
-int js_error(js_State *J, const char *fmt, ...);
-
-int js_loadstring(js_State *J, const char *source);
-int js_loadfile(js_State *J, const char *filename);
+void js_loadstring(js_State *J, const char *source);
+void js_loadfile(js_State *J, const char *filename);
int js_dostring(js_State *J, const char *source);
int js_dofile(js_State *J, const char *filename);
@@ -71,6 +69,18 @@
void jsB_initboolean(js_State *J);
void jsB_initnumber(js_State *J);
void jsB_initstring(js_State *J);
+void jsB_initerror(js_State *J);
void jsB_initmath(js_State *J);
+
+JS_NORETURN void js_throw(js_State *J);
+JS_NORETURN void js_error(js_State *J, const char *fmt, ...) __printflike(2,3);
+
+JS_NORETURN void jsR_throwError(js_State *J, const char *message);
+JS_NORETURN void jsR_throwEvalError(js_State *J, const char *message);
+JS_NORETURN void jsR_throwRangeError(js_State *J, const char *message);
+JS_NORETURN void jsR_throwReferenceError(js_State *J, const char *message);
+JS_NORETURN void jsR_throwSyntaxError(js_State *J, const char *message);
+JS_NORETURN void jsR_throwTypeError(js_State *J, const char *message);
+JS_NORETURN void jsR_throwURIError(js_State *J, const char *message);
#endif
--- a/jsbboolean.c
+++ b/jsbboolean.c
@@ -18,7 +18,7 @@
static int Bp_toString(js_State *J, int n)
{
js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CBOOLEAN) jsR_error(J, "TypeError");
+ if (self->type != JS_CBOOLEAN) jsR_throwTypeError(J, "not a boolean");
js_pushliteral(J, self->u.boolean ? "true" : "false");
return 1;
}
@@ -26,7 +26,7 @@
static int Bp_valueOf(js_State *J, int n)
{
js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CBOOLEAN) jsR_error(J, "TypeError");
+ if (self->type != JS_CBOOLEAN) jsR_throwTypeError(J, "not a boolean");
js_pushboolean(J, self->u.boolean);
return 1;
}
--- /dev/null
+++ b/jsberror.c
@@ -1,0 +1,86 @@
+#include "js.h"
+#include "jsobject.h"
+#include "jsrun.h"
+#include "jsstate.h"
+
+static int Ep_toString(js_State *J, int n)
+{
+ js_getproperty(J, 0, "name");
+ js_pushliteral(J, ": ");
+ jsR_concat(J);
+ js_getproperty(J, 0, "message");
+ jsR_concat(J);
+ return 1;
+}
+
+#define STRSTR(X) #X
+#define STR(X) STRSTR(X)
+
+#define DECL(NAME) \
+ static int jsB_new_##NAME(js_State *J, int n) { \
+ js_pushobject(J, jsR_newobject(J, JS_CERROR, J->NAME##_prototype)); \
+ if (n > 0) { \
+ js_pushstring(J, js_tostring(J, 0)); \
+ js_setproperty(J, -2, "message"); \
+ } \
+ return 1; \
+ } \
+ static int jsB_##NAME(js_State *J, int n) { \
+ js_pushobject(J, jsR_newobject(J, JS_CERROR, J->NAME##_prototype)); \
+ if (n > 1) { \
+ js_pushstring(J, js_tostring(J, 1)); \
+ js_setproperty(J, -2, "message"); \
+ } \
+ return 1; \
+ } \
+ static void jsB_init##NAME(js_State *J) { \
+ js_pushobject(J, jsR_newcconstructor(J, jsB_##NAME, jsB_new_##NAME)); \
+ { \
+ jsB_propn(J, "length", 1); \
+ js_pushobject(J, J->NAME##_prototype); \
+ { \
+ js_copy(J, -2); \
+ js_setproperty(J, -2, "constructor"); \
+ jsB_props(J, "name", STR(NAME)); \
+ jsB_props(J, "message", "an error has occurred"); \
+ jsB_propf(J, "toString", Ep_toString, 0); \
+ } \
+ js_setproperty(J, -2, "prototype"); \
+ } \
+ js_setglobal(J, STR(NAME)); \
+ } \
+ void jsR_throw##NAME(js_State *J, const char *message) { \
+ js_pushobject(J, jsR_newobject(J, JS_CERROR, J->NAME##_prototype)); \
+ js_pushstring(J, message); \
+ js_setproperty(J, -2, "message"); \
+ js_throw(J); \
+ } \
+
+DECL(Error);
+DECL(EvalError);
+DECL(RangeError);
+DECL(ReferenceError);
+DECL(SyntaxError);
+DECL(TypeError);
+DECL(URIError);
+
+void jsB_initerror(js_State *J)
+{
+ jsB_initError(J);
+ jsB_initEvalError(J);
+ jsB_initRangeError(J);
+ jsB_initReferenceError(J);
+ jsB_initSyntaxError(J);
+ jsB_initTypeError(J);
+ jsB_initURIError(J);
+}
+
+void js_error(js_State *J, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[256];
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof buf, fmt, ap);
+ va_end(ap);
+ jsR_throwError(J, buf);
+}
--- a/jsbfunction.c
+++ b/jsbfunction.c
@@ -20,7 +20,7 @@
int i, n;
if (!js_iscallable(J, 0))
- jsR_error(J, "TypeError");
+ jsR_throwTypeError(J, "not a function");
if (self->type == JS_CFUNCTION || self->type == JS_CSCRIPT) {
js_Function *F = self->u.f.function;
@@ -52,7 +52,7 @@
char name[20];
if (!js_iscallable(J, 0))
- jsR_error(J, "TypeError: not a function");
+ jsR_throwTypeError(J, "not a function");
js_copy(J, 0);
js_copy(J, 1);
@@ -75,7 +75,7 @@
int i;
if (!js_iscallable(J, 0))
- jsR_error(J, "TypeError: not a function");
+ jsR_throwTypeError(J, "not a function");
js_copy(J, 0);
js_copy(J, 1);
--- a/jsbnumber.c
+++ b/jsbnumber.c
@@ -18,7 +18,7 @@
static int Np_valueOf(js_State *J, int n)
{
js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CNUMBER) jsR_error(J, "TypeError");
+ if (self->type != JS_CNUMBER) jsR_throwTypeError(J, "not a number");
js_pushnumber(J, self->u.number);
return 1;
}
@@ -26,7 +26,7 @@
static int Np_toString(js_State *J, int n)
{
js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CNUMBER) jsR_error(J, "TypeError");
+ if (self->type != JS_CNUMBER) jsR_throwTypeError(J, "not a number");
js_pushliteral(J, jsR_stringfromnumber(J, self->u.number));
return 1;
}
@@ -36,7 +36,7 @@
char buf[40];
js_Object *self = js_toobject(J, 0);
int width = js_tonumber(J, 1);
- if (self->type != JS_CNUMBER) jsR_error(J, "TypeError");
+ if (self->type != JS_CNUMBER) jsR_throwTypeError(J, "not a number");
sprintf(buf, "%.*f", width, self->u.number);
js_pushstring(J, buf);
return 1;
@@ -47,7 +47,7 @@
char buf[40];
js_Object *self = js_toobject(J, 0);
int width = js_tonumber(J, 1);
- if (self->type != JS_CNUMBER) jsR_error(J, "TypeError");
+ if (self->type != JS_CNUMBER) jsR_throwTypeError(J, "not a number");
sprintf(buf, "%.*e", width, self->u.number);
js_pushstring(J, buf);
return 1;
@@ -58,7 +58,7 @@
char buf[40];
js_Object *self = js_toobject(J, 0);
int width = js_tonumber(J, 1);
- if (self->type != JS_CNUMBER) jsR_error(J, "TypeError");
+ if (self->type != JS_CNUMBER) jsR_throwTypeError(J, "not a number");
sprintf(buf, "%.*g", width, self->u.number);
js_pushstring(J, buf);
return 1;
--- a/jsbstring.c
+++ b/jsbstring.c
@@ -19,7 +19,7 @@
static int Sp_toString(js_State *J, int n)
{
js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CSTRING) jsR_error(J, "TypeError");
+ if (self->type != JS_CSTRING) jsR_throwTypeError(J, "not a string");
js_pushliteral(J, self->u.string);
return 1;
}
@@ -27,7 +27,7 @@
static int Sp_valueOf(js_State *J, int n)
{
js_Object *self = js_toobject(J, 0);
- if (self->type != JS_CSTRING) jsR_error(J, "TypeError");
+ if (self->type != JS_CSTRING) jsR_throwTypeError(J, "not a string");
js_pushliteral(J, self->u.string);
return 1;
}
--- a/jsbuiltin.c
+++ b/jsbuiltin.c
@@ -24,16 +24,10 @@
static int jsB_eval(js_State *J, int argc)
{
- const char *s;
-
if (!js_isstring(J, -1))
return 1;
-
- s = js_tostring(J, -1);
- if (jsR_loadscript(J, "(eval)", s))
- jsR_error(J, "SyntaxError (eval)");
-
- js_copy(J, 0); /* copy this */
+ jsR_loadscript(J, "(eval)", js_tostring(J, -1));
+ js_copy(J, 0);
js_call(J, 0);
return 1;
}
@@ -85,6 +79,12 @@
js_setproperty(J, -2, name);
}
+void jsB_props(js_State *J, const char *name, const char *string)
+{
+ js_pushliteral(J, string);
+ js_setproperty(J, -2, name);
+}
+
void jsB_init(js_State *J)
{
/* Create the prototype objects here, before the constructors */
@@ -95,6 +95,15 @@
J->Number_prototype = jsR_newobject(J, JS_CNUMBER, J->Object_prototype);
J->String_prototype = jsR_newobject(J, JS_CSTRING, J->Object_prototype);
+ /* All the native error types */
+ J->Error_prototype = jsR_newobject(J, JS_CERROR, J->Object_prototype);
+ J->EvalError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
+ J->RangeError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
+ J->ReferenceError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
+ J->SyntaxError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
+ J->TypeError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
+ J->URIError_prototype = jsR_newobject(J, JS_CERROR, J->Error_prototype);
+
/* Create the constructors and fill out the prototype objects */
jsB_initobject(J);
jsB_initarray(J);
@@ -102,6 +111,7 @@
jsB_initboolean(J);
jsB_initnumber(J);
jsB_initstring(J);
+ jsB_initerror(J);
jsB_initmath(J);
--- a/jscompile.c
+++ b/jscompile.c
@@ -742,25 +742,20 @@
int jsC_error(js_State *J, js_Ast *node, const char *fmt, ...)
{
va_list ap;
+ char buf[512];
+ char msgbuf[256];
- fprintf(stderr, "%s:%d: error: ", J->filename, node->line);
va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
+ vsnprintf(msgbuf, 256, fmt, ap);
va_end(ap);
- fprintf(stderr, "\n");
- longjmp(J->jb, 1);
+ snprintf(buf, 256, "%s:%d: ", J->filename, node->line);
+ strcat(buf, msgbuf);
+
+ jsR_throwSyntaxError(J, buf);
}
js_Function *jsC_compile(js_State *J, js_Ast *prog)
{
- js_Function *F;
-
- if (setjmp(J->jb))
- return NULL;
-
- F = newfun(J, NULL, NULL, prog);
-
- J->fun = NULL;
- return F;
+ return newfun(J, NULL, NULL, prog);
}
--- a/jsdump.c
+++ b/jsdump.c
@@ -683,6 +683,7 @@
case JS_CBOOLEAN: printf("boolean(%d)", v.u.object->u.boolean); break;
case JS_CNUMBER: printf("number(%g)", v.u.object->u.number); break;
case JS_CSTRING: printf("string('%s')", v.u.object->u.string); break;
+ case JS_CERROR: printf("error()"); break;
default: printf("<unknown %p>", v.u.object); break;
}
break;
--- a/jsparse.c
+++ b/jsparse.c
@@ -852,14 +852,17 @@
int jsP_error(js_State *J, const char *fmt, ...)
{
va_list ap;
+ char buf[512];
+ char msgbuf[256];
- fprintf(stderr, "%s:%d: error: ", J->filename, J->lexline);
va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
+ vsnprintf(msgbuf, 256, fmt, ap);
va_end(ap);
- fprintf(stderr, "\n");
- longjmp(J->jb, 1);
+ snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline);
+ strcat(buf, msgbuf);
+
+ jsR_throwSyntaxError(J, buf);
}
js_Ast *jsP_parse(js_State *J, const char *filename, const char *source)
@@ -867,11 +870,6 @@
js_Ast *p, *last;
jsP_initlex(J, filename, source);
-
- if (setjmp(J->jb)) {
- jsP_freeparse(J);
- return NULL;
- }
next(J);
p = script(J);
--- a/jsparse.h
+++ b/jsparse.h
@@ -121,6 +121,7 @@
const char *string;
js_Ast *gcnext; /* next in alloc list */
};
+
js_Ast *jsP_parse(js_State *J, const char *filename, const char *source);
void jsP_optimize(js_State *J, js_Ast *prog);
void jsP_freeparse(js_State *J);
--- a/jsrun.c
+++ b/jsrun.c
@@ -394,10 +394,10 @@
int rv = F(J, n + 1);
if (rv) {
js_Value v = js_tovalue(J, -1);
- js_pop(J, TOP - BOT + 1);
+ TOP = --BOT; /* pop down to below function */
js_pushvalue(J, v);
} else {
- js_pop(J, TOP - BOT + 1);
+ TOP = --BOT; /* pop down to below function */
js_pushundefined(J);
}
}
@@ -414,7 +414,7 @@
else if (obj->type == JS_CCFUNCTION)
jsR_callcfunction(J, n, obj->u.c.function);
else
- jsR_error(J, "TypeError (not a function)");
+ jsR_throwTypeError(J, "not a function");
BOT = savebot;
}
@@ -449,6 +449,33 @@
js_call(J, n);
}
+/* Exceptions */
+
+void js_savetry(js_State *J, short *pc)
+{
+ if (J->trylen == JS_TRYLIMIT)
+ js_error(J, "exception stack overflow");
+ J->trybuf[J->trylen].E = J->E;
+ J->trybuf[J->trylen].top = J->top;
+ J->trybuf[J->trylen].bot = J->bot;
+ J->trybuf[J->trylen].pc = pc;
+}
+
+void js_throw(js_State *J)
+{
+ if (J->trylen > 0) {
+ js_Value v = js_tovalue(J, -1);
+ --J->trylen;
+ J->E = J->trybuf[J->trylen].E;
+ J->top = J->trybuf[J->trylen].top;
+ J->bot = J->trybuf[J->trylen].bot;
+ js_pushvalue(J, v);
+ longjmp(J->trybuf[J->trylen].buf, 1);
+ }
+ fprintf(stderr, "libjs: uncaught exception!\n");
+ abort();
+}
+
/* Main interpreter loop */
void jsR_dumpstack(js_State *J)
@@ -546,7 +573,7 @@
if (ref)
js_pushvalue(J, ref->value);
else
- jsR_error(J, "ReferenceError (%s)", str);
+ jsR_throwReferenceError(J, str);
break;
case OP_SETVAR:
@@ -783,40 +810,26 @@
return;
default:
- fprintf(stderr, "illegal instruction: %d (pc=%d)\n", opcode, (int)(pc - F->code - 1));
- return;
+ js_error(J, "illegal instruction: %d (pc=%d)", opcode, (int)(pc - F->code - 1));
}
}
}
-int jsR_loadscript(js_State *J, const char *filename, const char *source)
+void jsR_loadscript(js_State *J, const char *filename, const char *source)
{
js_Ast *P;
js_Function *F;
- // TODO: push exception stack
+ if (js_try(J)) {
+ jsP_freeparse(J);
+ js_throw(J);
+ }
P = jsP_parse(J, filename, source);
- if (!P) return 1;
jsP_optimize(J, P);
F = jsC_compile(J, P);
-
jsP_freeparse(J);
- if (!F) return 1;
-
js_newscript(J, F);
- return 0;
-}
-void jsR_error(js_State *J, const char *fmt, ...)
-{
- va_list ap;
-
- fprintf(stderr, "runtime error: ");
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fprintf(stderr, "\n");
-
- longjmp(J->jb, 1);
+ js_endtry(J);
}
--- a/jsrun.h
+++ b/jsrun.h
@@ -14,10 +14,11 @@
void jsB_init(js_State *J);
void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n);
void jsB_propn(js_State *J, const char *name, double number);
+void jsB_props(js_State *J, const char *name, const char *string);
js_Environment *jsR_newenvironment(js_State *J, js_Object *variables, js_Environment *outer);
js_Object *jsR_newcconstructor(js_State *J, js_CFunction cfunction, js_CFunction cconstructor);
-int jsR_loadscript(js_State *J, const char *filename, const char *source);
+void jsR_loadscript(js_State *J, const char *filename, const char *source);
void jsR_error(js_State *J, const char *fmt, ...);
void js_pushobject(js_State *J, js_Object *v);
js_Object *js_toobject(js_State *J, int idx);
@@ -74,6 +75,8 @@
double js_tointeger(js_State *J, int idx);
int js_toint32(js_State *J, int idx);
unsigned int js_touint32(js_State *J, int idx);
+short js_toint16(js_State *J, int idx);
+unsigned short js_touint16(js_State *J, int idx);
void js_pop(js_State *J, int n);
void js_dup(js_State *J);
--- a/jsstate.c
+++ b/jsstate.c
@@ -3,12 +3,12 @@
#include "jsrun.h"
#include "jsstate.h"
-int js_loadstring(js_State *J, const char *source)
+void js_loadstring(js_State *J, const char *source)
{
- return jsR_loadscript(J, "(string)", source);
+ jsR_loadscript(J, "(string)", source);
}
-int js_loadfile(js_State *J, const char *filename)
+void js_loadfile(js_State *J, const char *filename)
{
FILE *f;
char *s;
@@ -16,12 +16,12 @@
f = fopen(filename, "r");
if (!f) {
- return js_error(J, "cannot open file: '%s'", filename);
+ js_error(J, "cannot open file: '%s'", filename);
}
if (fseek(f, 0, SEEK_END) < 0) {
fclose(f);
- return js_error(J, "cannot seek in file: '%s'", filename);
+ js_error(J, "cannot seek in file: '%s'", filename);
}
n = ftell(f);
fseek(f, 0, SEEK_SET);
@@ -29,7 +29,7 @@
s = malloc(n + 1); /* add space for string terminator */
if (!s) {
fclose(f);
- return js_error(J, "cannot allocate storage for file contents: '%s'", filename);
+ js_error(J, "cannot allocate storage for file contents: '%s'", filename);
}
t = fread(s, 1, n, f);
@@ -36,42 +36,50 @@
if (t != n) {
free(s);
fclose(f);
- return js_error(J, "cannot read data from file: '%s'", filename);
+ js_error(J, "cannot read data from file: '%s'", filename);
}
s[n] = 0; /* zero-terminate string containing file data */
- t = jsR_loadscript(J, filename, s);
+ if (js_try(J)) {
+ free(s);
+ fclose(f);
+ js_throw(J);
+ }
+ jsR_loadscript(J, filename, s);
+
free(s);
fclose(f);
- return t;
+ js_endtry(J);
}
int js_dostring(js_State *J, const char *source)
{
- int rv = js_loadstring(J, source);
- if (!rv) {
- if (setjmp(J->jb))
- return 1;
- js_pushglobal(J);
- js_call(J, 0);
- js_pop(J, 1);
+ if (js_try(J)) {
+ fprintf(stderr, "libjs: %s\n", js_tostring(J, -1));
+ return 1;
}
- return rv;
+ js_loadstring(J, source);
+ js_pushglobal(J);
+ js_call(J, 0);
+ js_pop(J, 1);
+ js_endtry(J);
+ return 0;
}
int js_dofile(js_State *J, const char *filename)
{
- int rv = js_loadfile(J, filename);
- if (!rv) {
- if (setjmp(J->jb))
- return 1;
- js_pushglobal(J);
- js_call(J, 0);
- js_pop(J, 1);
+ if (js_try(J)) {
+ fprintf(stderr, "libjs: %s\n", js_tostring(J, -1));
+ return 1;
}
- return rv;
+ js_loadfile(J, filename);
+ js_pushglobal(J);
+ js_call(J, 0);
+ js_pop(J, 1);
+ js_endtry(J);
+ return 0;
}
js_State *js_newstate(void)
@@ -87,19 +95,4 @@
jsB_init(J);
return J;
-}
-
-int js_error(js_State *J, const char *fmt, ...)
-{
- va_list ap;
-
- fprintf(stderr, "error: ");
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- fprintf(stderr, "\n");
-
- return 0;
}
--- a/jsstate.h
+++ b/jsstate.h
@@ -4,12 +4,32 @@
#include "jsobject.h" /* for js_Value */
#define JS_STACKSIZE 256
+#define JS_TRYLIMIT 64
#define JS_GCLIMIT 10000 /* run gc cycle every N allocations */
-struct js_State
+void js_savetry(js_State *J, short *pc);
+
+#define js_trypc(J, PC) \
+ (js_savetry(J, PC), setjmp(J->trybuf[J->trylen++].buf))
+
+#define js_try(J) \
+ (js_savetry(J, NULL), setjmp(J->trybuf[J->trylen++].buf))
+
+#define js_endtry(J) \
+ (--J->trylen)
+
+typedef struct js_Jumpbuf js_Jumpbuf;
+
+struct js_Jumpbuf
{
- jmp_buf jb; /* setjmp buffer for error handling in parser */
+ jmp_buf buf;
+ js_Environment *E;
+ int top, bot;
+ short *pc;
+};
+struct js_State
+{
js_StringNode *strings;
/* input */
@@ -31,11 +51,9 @@
js_Ast *gcast; /* list of allocated nodes to free after parsing */
/* compiler */
- js_Function *fun; /* list of allocated functions to free on errors */
-
int strict;
- /* runtime */
+ /* runtime environment */
js_Object *Object_prototype;
js_Object *Array_prototype;
js_Object *Function_prototype;
@@ -43,6 +61,14 @@
js_Object *Number_prototype;
js_Object *String_prototype;
+ js_Object *Error_prototype;
+ js_Object *EvalError_prototype;
+ js_Object *RangeError_prototype;
+ js_Object *ReferenceError_prototype;
+ js_Object *SyntaxError_prototype;
+ js_Object *TypeError_prototype;
+ js_Object *URIError_prototype;
+
js_Object *G;
js_Environment *E;
@@ -52,6 +78,10 @@
js_Environment *gcenv;
js_Function *gcfun;
js_Object *gcobj;
+
+ /* exception stack */
+ int trylen;
+ js_Jumpbuf trybuf[JS_TRYLIMIT];
/* execution stack */
int top, bot;
--- a/jsvalue.c
+++ b/jsvalue.c
@@ -76,7 +76,7 @@
return vv;
}
}
- jsR_error(J, "TypeError (ToPrimitive)");
+ jsR_throwTypeError(J, "cannot convert object to primitive");
}
int jsR_toboolean(js_State *J, const js_Value *v)
@@ -129,14 +129,14 @@
js_Object *jsR_toobject(js_State *J, const js_Value *v)
{
switch (v->type) {
- case JS_TUNDEFINED: jsR_error(J, "TypeError (ToObject(undefined))");
- case JS_TNULL: jsR_error(J, "TypeError (ToObject(null))");
+ case JS_TUNDEFINED: jsR_throwTypeError(J, "cannot convert undefined to object");
+ case JS_TNULL: jsR_throwTypeError(J, "cannot convert null to object");
case JS_TBOOLEAN: return jsR_newboolean(J, v->u.boolean);
case JS_TNUMBER: return jsR_newnumber(J, v->u.number);
case JS_TSTRING: return jsR_newstring(J, v->u.string);
case JS_TOBJECT: return v->u.object;
}
- jsR_error(J, "TypeError (ToObject)");
+ jsR_throwTypeError(J, "cannot convert value to object");
}
void jsR_concat(js_State *J)