ref: f77a6e7e8e367ed8a6360ac7a44cac28ff5ed3ee
parent: 8d5ace5e79b80c4446d994527f5e1d88bd77fa22
author: Tor Andersson <tor@ccxvii.net>
date: Tue Jan 14 13:17:06 EST 2014
Implement value stack and use it in the interpreter. We can now run simple programs that don't use function calls.
--- a/jscompile.c
+++ b/jscompile.c
@@ -45,10 +45,10 @@
{
// int i;
// for (i = 0; i < F->funlen; i++)
-// freefun(J, F->funlist[i]);
- free(F->funlist);
- free(F->numlist);
- free(F->strlist);
+// freefun(J, F->funtab[i]);
+ free(F->funtab);
+ free(F->numtab);
+ free(F->strtab);
free(F->code);
free(F);
}
@@ -68,9 +68,9 @@
{
if (F->funlen >= F->funcap) {
F->funcap = F->funcap ? F->funcap * 2 : 16;
- F->funlist = realloc(F->funlist, F->funcap * sizeof *F->funlist);
+ F->funtab = realloc(F->funtab, F->funcap * sizeof *F->funtab);
}
- F->funlist[F->funlen] = value;
+ F->funtab[F->funlen] = value;
return F->funlen++;
}
@@ -78,13 +78,13 @@
{
int i;
for (i = 0; i < F->numlen; i++)
- if (F->numlist[i] == value)
+ if (F->numtab[i] == value)
return i;
if (F->numlen >= F->numcap) {
F->numcap = F->numcap ? F->numcap * 2 : 16;
- F->numlist = realloc(F->numlist, F->numcap * sizeof *F->numlist);
+ F->numtab = realloc(F->numtab, F->numcap * sizeof *F->numtab);
}
- F->numlist[F->numlen] = value;
+ F->numtab[F->numlen] = value;
return F->numlen++;
}
@@ -92,26 +92,35 @@
{
int i;
for (i = 0; i < F->strlen; i++)
- if (!strcmp(F->strlist[i], value))
+ if (!strcmp(F->strtab[i], value))
return i;
if (F->strlen >= F->strcap) {
F->strcap = F->strcap ? F->strcap * 2 : 16;
- F->strlist = realloc(F->strlist, F->strcap * sizeof *F->strlist);
+ F->strtab = realloc(F->strtab, F->strcap * sizeof *F->strtab);
}
- F->strlist[F->strlen] = value;
+ F->strtab[F->strlen] = value;
return F->strlen++;
}
-static void emitfunction(JF, int opcode, js_Function *fun)
+static void emitfunction(JF, js_Function *fun)
{
- emit(J, F, opcode);
+ emit(J, F, OP_CLOSURE);
emit(J, F, addfunction(J, F, fun));
}
-static void emitnumber(JF, int opcode, double num)
+static void emitnumber(JF, double num)
{
- emit(J, F, opcode);
- emit(J, F, addnumber(J, F, num));
+ if (num == 0)
+ emit(J, F, OP_NUMBER_0);
+ else if (num == 1)
+ emit(J, F, OP_NUMBER_1);
+ else if (num == (short)num) {
+ emit(J, F, OP_NUMBER_X);
+ emit(J, F, (short)num);
+ } else {
+ emit(J, F, OP_NUMBER);
+ emit(J, F, addnumber(J, F, num));
+ }
}
static void emitstring(JF, int opcode, const char *str)
@@ -146,13 +155,13 @@
/* Expressions */
-static void unary(JF, js_Ast *exp, int opcode)
+static void cunary(JF, js_Ast *exp, int opcode)
{
cexp(J, F, exp->a);
emit(J, F, opcode);
}
-static void binary(JF, js_Ast *exp, int opcode)
+static void cbinary(JF, js_Ast *exp, int opcode)
{
cexp(J, F, exp->a);
cexp(J, F, exp->b);
@@ -163,9 +172,12 @@
{
int i = 0;
while (list) {
+ emit(J, F, OP_DUP);
+ emit(J, F, OP_NUMBER_X);
cexp(J, F, list->a);
- emit(J, F, OP_ARRAYPUT);
emit(J, F, i++);
+ emit(J, F, OP_SETPROP);
+ emit(J, F, OP_POP);
list = list->b;
}
}
@@ -176,15 +188,16 @@
js_Ast *kv = list->a;
if (kv->type == EXP_PROP_VAL) {
js_Ast *prop = kv->a;
- cexp(J, F, kv->b);
+ emit(J, F, OP_DUP);
if (prop->type == AST_IDENTIFIER || prop->type == AST_STRING)
- emitstring(J, F, OP_OBJECTPUT, prop->string);
- else if (prop->type == AST_STRING)
- emitstring(J, F, OP_OBJECTPUT, prop->string);
+ emitstring(J, F, OP_STRING, prop->string);
else if (prop->type == AST_NUMBER)
- emitnumber(J, F, OP_OBJECTPUT, prop->number);
+ emitnumber(J, F, prop->number);
else
jsC_error(J, list, "illegal property name in object initializer");
+ cexp(J, F, kv->b);
+ emit(J, F, OP_SETPROP);
+ emit(J, F, OP_POP);
}
// TODO: set, get
list = list->b;
@@ -202,40 +215,116 @@
return n;
}
-static void clval(JF, js_Ast *exp)
+static void cassign(JF, js_Ast *lhs, js_Ast *rhs)
{
- switch (exp->type) {
+ switch (lhs->type) {
case AST_IDENTIFIER:
- emitstring(J, F, OP_AVAR, exp->string);
+ cexp(J, F, rhs);
+ emitstring(J, F, OP_SETVAR, lhs->string);
break;
case EXP_INDEX:
- cexp(J, F, exp->a);
- cexp(J, F, exp->b);
- emit(J, F, OP_AINDEX);
+ cexp(J, F, lhs->a);
+ cexp(J, F, lhs->b);
+ cexp(J, F, rhs);
+ emit(J, F, OP_SETPROP);
break;
case EXP_MEMBER:
- cexp(J, F, exp->a);
- emitstring(J, F, OP_AMEMBER, exp->b->string);
+ cexp(J, F, lhs->a);
+ emitstring(J, F, OP_STRING, lhs->b->string);
+ cexp(J, F, rhs);
+ emit(J, F, OP_SETPROP);
break;
+ case EXP_CALL: /* host functions may return an assignable l-value */
+ cexp(J, F, lhs);
+ cexp(J, F, rhs);
+ emit(J, F, OP_SETPROP);
+ break;
+ default:
+ jsC_error(J, lhs, "invalid l-value in assignment");
+ break;
+ }
+}
+
+static void cassignop1(JF, js_Ast *lhs, int dup)
+{
+ switch (lhs->type) {
+ case AST_IDENTIFIER:
+ emitstring(J, F, OP_GETVAR, lhs->string);
+ if (dup) emit(J, F, OP_DUP);
+ break;
+ case EXP_INDEX:
+ cexp(J, F, lhs->a);
+ cexp(J, F, lhs->b);
+ emit(J, F, OP_DUP2);
+ emit(J, F, OP_GETPROP);
+ if (dup) emit(J, F, OP_DUP1ROT4);
+ break;
+ case EXP_MEMBER:
+ cexp(J, F, lhs->a);
+ emitstring(J, F, OP_STRING, lhs->b->string);
+ emit(J, F, OP_DUP2);
+ emit(J, F, OP_GETPROP);
+ if (dup) emit(J, F, OP_DUP1ROT4);
+ break;
+ case EXP_CALL: /* host functions may return an assignable l-value */
+ cexp(J, F, lhs);
+ emit(J, F, OP_DUP2);
+ emit(J, F, OP_GETPROP);
+ if (dup) emit(J, F, OP_DUP1ROT4);
+ break;
+ default:
+ jsC_error(J, lhs, "invalid l-value in assignment");
+ break;
+ }
+}
+
+static void cassignop2(JF, js_Ast *lhs)
+{
+ switch (lhs->type) {
+ case AST_IDENTIFIER:
+ emitstring(J, F, OP_SETVAR, lhs->string);
+ break;
+ case EXP_INDEX:
+ case EXP_MEMBER:
case EXP_CALL:
- /* host functions may return an assignable l-value */
- cexp(J, F, exp);
+ emit(J, F, OP_SETPROP);
break;
default:
- jsC_error(J, exp, "invalid l-value in assignment");
+ jsC_error(J, lhs, "invalid l-value in assignment");
break;
}
}
-static void assignop(JF, js_Ast *exp, int opcode)
+static void cassignop(JF, js_Ast *lhs, js_Ast *rhs, int opcode)
{
- clval(J, F, exp->a);
- emit(J, F, OP_LOAD);
- cexp(J, F, exp->b);
+ cassignop1(J, F, lhs, 0);
+ cexp(J, F, rhs);
emit(J, F, opcode);
- emit(J, F, OP_STORE);
+ cassignop2(J, F, lhs);
}
+static void cdelete(JF, js_Ast *exp)
+{
+ switch (exp->type) {
+ case AST_IDENTIFIER:
+ emitstring(J, F, OP_DELVAR, exp->string);
+ break;
+ case EXP_INDEX:
+ cexp(J, F, exp->a);
+ cexp(J, F, exp->b);
+ emit(J, F, OP_DELPROP);
+ break;
+ case EXP_MEMBER:
+ cexp(J, F, exp->a);
+ emitstring(J, F, OP_STRING, exp->b->string);
+ emit(J, F, OP_DELPROP);
+ break;
+ default:
+ jsC_error(J, exp, "invalid l-value in delete expression");
+ break;
+ }
+}
+
static void cvarinit(JF, js_Ast *list)
{
while (list) {
@@ -242,9 +331,7 @@
js_Ast *var = list->a;
if (var->b) {
cexp(J, F, var->b);
- emitstring(J, F, OP_AVAR, var->a->string);
- emit(J, F, OP_STORE);
- emit(J, F, OP_POP);
+ emitstring(J, F, OP_SETVAR, var->a->string);
}
list = list->b;
}
@@ -258,12 +345,13 @@
cexp(J, F, fun->a);
emit(J, F, OP_DUP);
cexp(J, F, fun->b);
- emit(J, F, OP_LOADINDEX);
+ emit(J, F, OP_GETPROP);
break;
case EXP_MEMBER:
cexp(J, F, fun->a);
emit(J, F, OP_DUP);
- emitstring(J, F, OP_LOADMEMBER, fun->b->string);
+ emitstring(J, F, OP_STRING, fun->b->string);
+ emit(J, F, OP_GETPROP);
break;
default:
emit(J, F, OP_THIS);
@@ -281,9 +369,8 @@
int n;
switch (exp->type) {
- case AST_IDENTIFIER: emitstring(J, F, OP_LOADVAR, exp->string); break;
- case AST_NUMBER: emitnumber(J, F, OP_NUMBER, exp->number); break;
case AST_STRING: emitstring(J, F, OP_STRING, exp->string); break;
+ case AST_NUMBER: emitnumber(J, F, exp->number); break;
case EXP_UNDEF: emit(J, F, OP_UNDEF); break;
case EXP_NULL: emit(J, F, OP_NULL); break;
case EXP_TRUE: emit(J, F, OP_TRUE); break;
@@ -300,15 +387,24 @@
carray(J, F, exp->a);
break;
+ case EXP_FUN:
+ emitfunction(J, F, newfun(J, exp->a, exp->b, exp->c));
+ break;
+
+ case AST_IDENTIFIER:
+ emitstring(J, F, OP_GETVAR, exp->string);
+ break;
+
case EXP_INDEX:
cexp(J, F, exp->a);
cexp(J, F, exp->b);
- emit(J, F, OP_LOADINDEX);
+ emit(J, F, OP_GETPROP);
break;
case EXP_MEMBER:
cexp(J, F, exp->a);
- emitstring(J, F, OP_LOADMEMBER, exp->b->string);
+ emitstring(J, F, OP_STRING, exp->b->string);
+ emit(J, F, OP_GETPROP);
break;
case EXP_CALL:
@@ -322,15 +418,40 @@
emit(J, F, n);
break;
- case EXP_FUN:
- emitfunction(J, F, OP_CLOSURE, newfun(J, exp->a, exp->b, exp->c));
+ case EXP_DELETE:
+ cdelete(J, F, exp->a);
break;
- case EXP_DELETE:
- clval(J, F, exp->a);
- emit(J, F, OP_DELETE);
+ case EXP_PREINC:
+ cassignop1(J, F, exp->a, 0);
+ emit(J, F, OP_NUMBER_1);
+ emit(J, F, OP_ADD);
+ cassignop2(J, F, exp->a);
break;
+ case EXP_PREDEC:
+ cassignop1(J, F, exp->a, 0);
+ emit(J, F, OP_NUMBER_1);
+ emit(J, F, OP_SUB);
+ cassignop2(J, F, exp->a);
+ break;
+
+ case EXP_POSTINC:
+ cassignop1(J, F, exp->a, 1);
+ emit(J, F, OP_NUMBER_1);
+ emit(J, F, OP_ADD);
+ cassignop2(J, F, exp->a);
+ emit(J, F, OP_POP);
+ break;
+
+ case EXP_POSTDEC:
+ cassignop1(J, F, exp->a, 1);
+ emit(J, F, OP_NUMBER_1);
+ emit(J, F, OP_SUB);
+ cassignop2(J, F, exp->a);
+ emit(J, F, OP_POP);
+ break;
+
case EXP_VOID:
cexp(J, F, exp->a);
emit(J, F, OP_POP);
@@ -337,57 +458,47 @@
emit(J, F, OP_UNDEF);
break;
- case EXP_TYPEOF: unary(J, F, exp, OP_TYPEOF); break;
- case EXP_POS: unary(J, F, exp, OP_POS); break;
- case EXP_NEG: unary(J, F, exp, OP_NEG); break;
- case EXP_BITNOT: unary(J, F, exp, OP_BITNOT); break;
- case EXP_LOGNOT: unary(J, F, exp, OP_LOGNOT); break;
+ case EXP_TYPEOF: cunary(J, F, exp, OP_TYPEOF); break;
+ case EXP_POS: cunary(J, F, exp, OP_POS); break;
+ case EXP_NEG: cunary(J, F, exp, OP_NEG); break;
+ case EXP_BITNOT: cunary(J, F, exp, OP_BITNOT); break;
+ case EXP_LOGNOT: cunary(J, F, exp, OP_LOGNOT); break;
- case EXP_PREINC: clval(J, F, exp->a); emit(J, F, OP_PREINC); break;
- case EXP_PREDEC: clval(J, F, exp->a); emit(J, F, OP_PREDEC); break;
- case EXP_POSTINC: clval(J, F, exp->a); emit(J, F, OP_POSTINC); break;
- case EXP_POSTDEC: clval(J, F, exp->a); emit(J, F, OP_POSTDEC); break;
+ case EXP_BITOR: cbinary(J, F, exp, OP_BITOR); break;
+ case EXP_BITXOR: cbinary(J, F, exp, OP_BITXOR); break;
+ case EXP_BITAND: cbinary(J, F, exp, OP_BITAND); break;
+ case EXP_EQ: cbinary(J, F, exp, OP_EQ); break;
+ case EXP_NE: cbinary(J, F, exp, OP_NE); break;
+ case EXP_STRICTEQ: cbinary(J, F, exp, OP_STRICTEQ); break;
+ case EXP_STRICTNE: cbinary(J, F, exp, OP_STRICTNE); break;
+ case EXP_LT: cbinary(J, F, exp, OP_LT); break;
+ case EXP_GT: cbinary(J, F, exp, OP_GT); break;
+ case EXP_LE: cbinary(J, F, exp, OP_LE); break;
+ case EXP_GE: cbinary(J, F, exp, OP_GE); break;
+ case EXP_INSTANCEOF: cbinary(J, F, exp, OP_INSTANCEOF); break;
+ case EXP_IN: cbinary(J, F, exp, OP_IN); break;
+ case EXP_SHL: cbinary(J, F, exp, OP_SHL); break;
+ case EXP_SHR: cbinary(J, F, exp, OP_SHR); break;
+ case EXP_USHR: cbinary(J, F, exp, OP_USHR); break;
+ case EXP_ADD: cbinary(J, F, exp, OP_ADD); break;
+ case EXP_SUB: cbinary(J, F, exp, OP_SUB); break;
+ case EXP_MUL: cbinary(J, F, exp, OP_MUL); break;
+ case EXP_DIV: cbinary(J, F, exp, OP_DIV); break;
+ case EXP_MOD: cbinary(J, F, exp, OP_MOD); break;
- case EXP_BITOR: binary(J, F, exp, OP_BITOR); break;
- case EXP_BITXOR: binary(J, F, exp, OP_BITXOR); break;
- case EXP_BITAND: binary(J, F, exp, OP_BITAND); break;
- case EXP_EQ: binary(J, F, exp, OP_EQ); break;
- case EXP_NE: binary(J, F, exp, OP_NE); break;
- case EXP_EQ3: binary(J, F, exp, OP_EQ3); break;
- case EXP_NE3: binary(J, F, exp, OP_NE3); break;
- case EXP_LT: binary(J, F, exp, OP_LT); break;
- case EXP_GT: binary(J, F, exp, OP_GT); break;
- case EXP_LE: binary(J, F, exp, OP_LE); break;
- case EXP_GE: binary(J, F, exp, OP_GE); break;
- case EXP_INSTANCEOF: binary(J, F, exp, OP_INSTANCEOF); break;
- case EXP_IN: binary(J, F, exp, OP_IN); break;
- case EXP_SHL: binary(J, F, exp, OP_SHL); break;
- case EXP_SHR: binary(J, F, exp, OP_SHR); break;
- case EXP_USHR: binary(J, F, exp, OP_USHR); break;
- case EXP_ADD: binary(J, F, exp, OP_ADD); break;
- case EXP_SUB: binary(J, F, exp, OP_SUB); break;
- case EXP_MUL: binary(J, F, exp, OP_MUL); break;
- case EXP_DIV: binary(J, F, exp, OP_DIV); break;
- case EXP_MOD: binary(J, F, exp, OP_MOD); break;
+ case EXP_ASS: cassign(J, F, exp->a, exp->b); break;
+ case EXP_ASS_MUL: cassignop(J, F, exp->a, exp->b, OP_MUL); break;
+ case EXP_ASS_DIV: cassignop(J, F, exp->a, exp->b, OP_DIV); break;
+ case EXP_ASS_MOD: cassignop(J, F, exp->a, exp->b, OP_MOD); break;
+ case EXP_ASS_ADD: cassignop(J, F, exp->a, exp->b, OP_ADD); break;
+ case EXP_ASS_SUB: cassignop(J, F, exp->a, exp->b, OP_SUB); break;
+ case EXP_ASS_SHL: cassignop(J, F, exp->a, exp->b, OP_SHL); break;
+ case EXP_ASS_SHR: cassignop(J, F, exp->a, exp->b, OP_SHR); break;
+ case EXP_ASS_USHR: cassignop(J, F, exp->a, exp->b, OP_USHR); break;
+ case EXP_ASS_BITAND: cassignop(J, F, exp->a, exp->b, OP_BITAND); break;
+ case EXP_ASS_BITXOR: cassignop(J, F, exp->a, exp->b, OP_BITXOR); break;
+ case EXP_ASS_BITOR: cassignop(J, F, exp->a, exp->b, OP_BITOR); break;
- case EXP_ASS:
- clval(J, F, exp->a);
- cexp(J, F, exp->b);
- emit(J, F, OP_STORE);
- break;
-
- case EXP_ASS_MUL: assignop(J, F, exp, OP_MUL); break;
- case EXP_ASS_DIV: assignop(J, F, exp, OP_DIV); break;
- case EXP_ASS_MOD: assignop(J, F, exp, OP_MOD); break;
- case EXP_ASS_ADD: assignop(J, F, exp, OP_ADD); break;
- case EXP_ASS_SUB: assignop(J, F, exp, OP_SUB); break;
- case EXP_ASS_SHL: assignop(J, F, exp, OP_SHL); break;
- case EXP_ASS_SHR: assignop(J, F, exp, OP_SHR); break;
- case EXP_ASS_USHR: assignop(J, F, exp, OP_USHR); break;
- case EXP_ASS_BITAND: assignop(J, F, exp, OP_BITAND); break;
- case EXP_ASS_BITXOR: assignop(J, F, exp, OP_BITXOR); break;
- case EXP_ASS_BITOR: assignop(J, F, exp, OP_BITOR); break;
-
case EXP_COMMA:
cexp(J, F, exp->a);
emit(J, F, OP_POP);
@@ -536,7 +647,7 @@
while (list) {
js_Ast *stm = list->a;
if (stm->type == AST_FUNDEC) {
- emitfunction(J, F, OP_CLOSURE, newfun(J, stm->a, stm->b, stm->c));
+ emitfunction(J, F, newfun(J, stm->a, stm->b, stm->c));
emitstring(J, F, OP_FUNDEC, stm->a->string);
}
list = list->b;
@@ -558,7 +669,7 @@
static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body)
{
if (name) {
- emitfunction(J, F, OP_CLOSURE, F);
+ emitfunction(J, F, F);
emitstring(J, F, OP_FUNDEC, name->string);
}
@@ -568,10 +679,8 @@
cstmlist(J, F, body);
}
- if (F->codelen == 0 || F->code[F->codelen - 1] != OP_RETURN) {
- emit(J, F, OP_UNDEF);
- emit(J, F, OP_RETURN);
- }
+ emit(J, F, OP_UNDEF);
+ emit(J, F, OP_RETURN);
}
int jsC_error(js_State *J, js_Ast *node, const char *fmt, ...)
--- a/jscompile.h
+++ b/jscompile.h
@@ -3,13 +3,19 @@
enum
{
- OP_POP,
- OP_DUP,
+ OP_POP, /* A -- */
+ OP_DUP, /* A -- A A */
+ OP_DUP2, /* A B -- A B A B */
+ OP_DUP1ROT4, /* A B C -- C A B C */
- OP_CLOSURE,
- OP_NUMBER,
- OP_STRING,
+ OP_NUMBER_0, /* -- 0 */
+ OP_NUMBER_1, /* -- 1 */
+ OP_NUMBER_X, /* -K- K */
+ OP_NUMBER, /* -N- <number> */
+ OP_STRING, /* -S- <string> */
+ OP_CLOSURE, /* -F- <closure> */
+
OP_UNDEF,
OP_NULL,
OP_TRUE,
@@ -17,33 +23,23 @@
OP_THIS,
OP_NEWARRAY,
- OP_ARRAYPUT,
OP_NEWOBJECT,
- OP_OBJECTPUT,
- OP_FUNDEC, /* <closure> -(name)- */
- OP_VARDEC, /* -(name)- */
+ OP_FUNDEC, /* <closure> -S- */
+ OP_VARDEC, /* -S- */
- OP_LOADVAR, /* -(name)- <value> */
- OP_LOADMEMBER, /* <obj> -(name)- <value> */
- OP_LOADINDEX, /* <obj> <idx> -- <value> */
+ OP_GETVAR, /* -S- <value> */
+ OP_SETVAR, /* <value> -S- <value> */
+ OP_DELVAR, /* -S- <success> */
- OP_AVAR, /* -(name)- <addr> */
- OP_AMEMBER, /* <obj> -(name)- <addr> */
- OP_AINDEX, /* <obj> <idx> -- <addr> */
+ OP_IN, /* <name> <obj> -- <exists?> */
+ OP_GETPROP, /* <obj> <name> -- <value> */
+ OP_SETPROP, /* <obj> <name> <value> -- <value> */
+ OP_DELPROP, /* <obj> <name> -- <success> */
- OP_LOAD, /* <addr> -- <addr> <value> */
- OP_STORE, /* <addr> <value> -- <value> */
-
OP_CALL, /* <thisvalue> <closure> <args...> -(numargs)- <returnvalue> */
OP_NEW, /* <closure> <args...> -(numargs)- <returnvalue> */
- OP_DELETE, /* <addr> -- <success> */
- OP_PREINC, /* <addr> -- <value+1> */
- OP_PREDEC, /* <addr> -- <value-1> */
- OP_POSTINC, /* <addr> -- <value> */
- OP_POSTDEC, /* <addr> -- <value> */
-
OP_VOID,
OP_TYPEOF,
OP_POS,
@@ -56,14 +52,12 @@
OP_BITAND,
OP_EQ,
OP_NE,
- OP_EQ3,
- OP_NE3,
+ OP_STRICTEQ,
+ OP_STRICTNE,
OP_LT,
OP_GT,
OP_LE,
OP_GE,
- OP_INSTANCEOF,
- OP_IN,
OP_SHL,
OP_SHR,
OP_USHR,
@@ -73,17 +67,20 @@
OP_DIV,
OP_MOD,
- OP_TRY,
- OP_THROW,
- OP_RETURN,
- OP_DEBUGGER,
+ OP_INSTANCEOF,
+ OP_THROW,
+ OP_TRY,
+ OP_CATCH,
+ OP_ENDCATCH,
OP_WITH,
OP_ENDWITH,
+ OP_DEBUGGER,
OP_JUMP,
OP_JTRUE,
OP_JFALSE,
+ OP_RETURN,
};
struct js_Function
@@ -94,13 +91,13 @@
short *code;
int codecap, codelen;
- js_Function **funlist;
+ js_Function **funtab;
int funcap, funlen;
- double *numlist;
+ double *numtab;
int numcap, numlen;
- const char **strlist;
+ const char **strtab;
int strcap, strlen;
js_Function *next; /* alloc list */
--- a/jsdump.c
+++ b/jsdump.c
@@ -1,7 +1,6 @@
#include "js.h"
#include "jsparse.h"
#include "jscompile.h"
-#include "jsvalue.h"
#include "jsobject.h"
#include <assert.h>
@@ -194,8 +193,8 @@
case EXP_BITAND: pbin(d, i, exp, " & "); break;
case EXP_EQ: pbin(d, i, exp, " == "); break;
case EXP_NE: pbin(d, i, exp, " != "); break;
- case EXP_EQ3: pbin(d, i, exp, " === "); break;
- case EXP_NE3: pbin(d, i, exp, " !== "); break;
+ case EXP_STRICTEQ: pbin(d, i, exp, " === "); break;
+ case EXP_STRICTNE: pbin(d, i, exp, " !== "); break;
case EXP_LT: pbin(d, i, exp, " < "); break;
case EXP_GT: pbin(d, i, exp, " > "); break;
case EXP_LE: pbin(d, i, exp, " <= "); break;
@@ -598,13 +597,13 @@
printf("function %p %s(%d)\n", F, F->name, F->numparams);
for (i = 0; i < F->funlen; i++)
- printf("\tfunction %p %s\n", F->funlist[i], F->funlist[i]->name);
+ printf("\tfunction %p %s\n", F->funtab[i], F->funtab[i]->name);
for (i = 0; i < F->strlen; i++) {
- ps("\tstring "); pstr(F->strlist[i]); ps("\n");
+ ps("\tstring "); pstr(F->strtab[i]); ps("\n");
}
// TODO: regexp
for (i = 0; i < F->numlen; i++)
- printf("\tnumber %.9g\n", F->numlist[i]);
+ printf("\tnumber %.9g\n", F->numtab[i]);
while (p < end) {
int c = *p++;
@@ -614,29 +613,27 @@
switch (c) {
case OP_CLOSURE:
- pc(' ');
- ps(F->funlist[*p++]->name);
+ ps(" f:");
+ ps(F->funtab[*p++]->name);
break;
case OP_NUMBER:
- printf(" %.9g", F->numlist[*p++]);
+ printf(" %.9g", F->numtab[*p++]);
break;
case OP_STRING:
pc(' ');
- pstr(F->strlist[*p++]);
+ pstr(F->strtab[*p++]);
break;
- case OP_OBJECTPUT:
case OP_FUNDEC:
case OP_VARDEC:
- case OP_LOADVAR:
- case OP_LOADMEMBER:
- case OP_AVAR:
- case OP_AMEMBER:
+ case OP_GETVAR:
+ case OP_SETVAR:
+ case OP_DELVAR:
pc(' ');
- ps(F->strlist[*p++]);
+ ps(F->strtab[*p++]);
break;
- case OP_ARRAYPUT:
+ case OP_NUMBER_X:
case OP_CALL:
case OP_NEW:
case OP_JUMP:
@@ -650,9 +647,9 @@
}
for (i = 0; i < F->funlen; i++) {
- if (F->funlist[i] != F) {
+ if (F->funtab[i] != F) {
nl();
- jsC_dumpfunction(J, F->funlist[i]);
+ jsC_dumpfunction(J, F->funtab[i]);
}
}
}
--- a/jslex.c
+++ b/jslex.c
@@ -525,7 +525,7 @@
case '=':
if (ACCEPT('=')) {
if (ACCEPT('='))
- return TK_EQ3;
+ return TK_STRICTEQ;
return TK_EQ;
}
return '=';
@@ -533,7 +533,7 @@
case '!':
if (ACCEPT('=')) {
if (ACCEPT('='))
- return TK_NE3;
+ return TK_STRICTNE;
return TK_NE;
}
return '!';
--- a/jslex.h
+++ b/jslex.h
@@ -12,8 +12,8 @@
TK_GE,
TK_EQ,
TK_NE,
- TK_EQ3,
- TK_NE3,
+ TK_STRICTEQ,
+ TK_STRICTNE,
TK_SHL,
TK_SHR,
TK_USHR,
--- a/jsobject.c
+++ b/jsobject.c
@@ -1,5 +1,4 @@
#include "js.h"
-#include "jsvalue.h"
#include "jsobject.h"
/*
@@ -21,6 +20,8 @@
static js_Property sentinel = { "", &sentinel, &sentinel, 0 };
+static js_Property undefined = { "", &sentinel, &sentinel, 0, { {0}, JS_TUNDEFINED } };
+
static js_Property *newproperty(const char *key)
{
js_Property *node = malloc(sizeof(js_Property));
@@ -116,11 +117,9 @@
case JS_TBOOLEAN: printf(v.u.boolean ? "true" : "false"); break;
case JS_TNUMBER: printf("%.9g", v.u.number); break;
case JS_TSTRING: printf("'%s'", v.u.string); break;
- case JS_TREGEXP: printf("/%s/", v.u.regexp.prog); break;
case JS_TOBJECT: printf("<object %p>", v.u.object); break;
case JS_TCLOSURE: printf("<closure %p>", v.u.closure); break;
case JS_TCFUNCTION: printf("<cfunction %p>", v.u.cfunction); break;
- case JS_TREFERENCE: printf("<reference %p>", v.u.reference); break;
}
}
--- a/jsobject.h
+++ b/jsobject.h
@@ -1,6 +1,30 @@
#ifndef js_object_h
#define js_object_h
+enum js_ValueType {
+ JS_TUNDEFINED,
+ JS_TNULL,
+ JS_TBOOLEAN,
+ JS_TNUMBER,
+ JS_TSTRING,
+ JS_TOBJECT,
+ JS_TCLOSURE,
+ JS_TCFUNCTION,
+};
+
+struct js_Value
+{
+ union {
+ int boolean;
+ double number;
+ const char *string;
+ js_Object *object;
+ js_Closure *closure;
+ js_CFunction *cfunction;
+ } u;
+ js_ValueType type;
+};
+
struct js_Property
{
char *key;
@@ -13,7 +37,7 @@
{
js_Property *properties;
js_Object *prototype;
- js_Object *parent;
+ js_Object *outer;
};
js_Object *js_newobject(js_State *J);
@@ -21,6 +45,7 @@
js_Property *js_setproperty(js_State *J, js_Object *obj, const char *name);
void js_deleteproperty(js_State *J, js_Object *obj, const char *name);
+void jsC_dumpvalue(js_State *J, js_Value v);
void js_dumpobject(js_State *J, js_Object *obj);
#endif
--- a/jsparse.c
+++ b/jsparse.c
@@ -458,8 +458,8 @@
loop:
if (accept(J, TK_EQ)) { a = EXP2(EQ, a, relational(J, notin)); goto loop; }
if (accept(J, TK_NE)) { a = EXP2(NE, a, relational(J, notin)); goto loop; }
- if (accept(J, TK_EQ3)) { a = EXP2(EQ3, a, relational(J, notin)); goto loop; }
- if (accept(J, TK_NE3)) { a = EXP2(NE3, a, relational(J, notin)); goto loop; }
+ if (accept(J, TK_STRICTEQ)) { a = EXP2(STRICTEQ, a, relational(J, notin)); goto loop; }
+ if (accept(J, TK_STRICTNE)) { a = EXP2(STRICTNE, a, relational(J, notin)); goto loop; }
return a;
}
--- a/jsparse.h
+++ b/jsparse.h
@@ -62,8 +62,8 @@
EXP_BITAND,
EXP_EQ,
EXP_NE,
- EXP_EQ3,
- EXP_NE3,
+ EXP_STRICTEQ,
+ EXP_STRICTNE,
EXP_LT,
EXP_GT,
EXP_LE,
--- a/jsrun.c
+++ b/jsrun.c
@@ -1,5 +1,4 @@
#include "js.h"
-#include "jsvalue.h"
#include "jsobject.h"
#include "jscompile.h"
#include "jsrun.h"
@@ -8,214 +7,453 @@
static js_Value stack[256];
static int top = 0;
-static inline int i32(double d)
+static inline double tointeger(double n)
{
+ double sign = n < 0 ? -1 : 1;
+ if (isnan(n)) return 0;
+ if (n == 0 || isinf(n)) return n;
+ return sign * floor(abs(n));
+}
+
+static inline int toint32(double n)
+{
double two32 = 4294967296.0;
double two31 = 2147483648.0;
- if (!isfinite(d) || d == 0)
+ if (!isfinite(n) || n == 0)
return 0;
- d = fmod(d, two32);
- d = d >= 0 ? floor(d) : ceil(d) + two32;
- if (d >= two31)
- return d - two32;
+ n = fmod(n, two32);
+ n = n >= 0 ? floor(n) : ceil(n) + two32;
+ if (n >= two31)
+ return n - two32;
else
- return d;
+ return n;
}
-static inline unsigned int u32(double d)
+static inline unsigned int touint32(double n)
{
- return i32(d);
+ return toint32(n);
}
-static inline void push(js_State *J, js_Value v)
+static void js_pushvalue(js_State *J, js_Value v)
{
- stack[top++] = v;
+ stack[top] = v;
+ ++top;
}
-static inline js_Value pop(js_State *J)
+void js_pushundefined(js_State *J)
{
- return stack[--top];
+ stack[top].type = JS_TUNDEFINED;
+ ++top;
}
-static inline js_Value peek(js_State *J)
+void js_pushnull(js_State *J)
{
- return stack[top-1];
+ stack[top].type = JS_TNULL;
+ ++top;
}
-static inline void pushnumber(js_State *J, double number)
+void js_pushboolean(js_State *J, int v)
{
- js_Value v;
- v.type = JS_TNUMBER;
- v.u.number = number;
- push(J, v);
+ stack[top].type = JS_TBOOLEAN;
+ stack[top].u.boolean = !!v;
+ ++top;
}
-static inline double popnumber(js_State *J)
+void js_pushnumber(js_State *J, double v)
{
- js_Value v = pop(J);
- if (v.type == JS_TNUMBER)
- return v.u.number;
- if (v.type == JS_TSTRING)
- return strtod(v.u.string, 0);
- return 0;
+ stack[top].type = JS_TNUMBER;
+ stack[top].u.number = v;
+ ++top;
}
-static inline void pushundefined(js_State *J)
+void js_pushstring(js_State *J, const char *v)
{
- js_Value v;
- v.type = JS_TUNDEFINED;
- push(J, v);
+ stack[top].type = JS_TSTRING;
+ stack[top].u.string = v;
+ ++top;
}
-static inline void pushnull(js_State *J)
+void js_pushobject(js_State *J, js_Object *v)
{
- js_Value v;
- v.type = JS_TNULL;
- push(J, v);
+ stack[top].type = JS_TOBJECT;
+ stack[top].u.object = v;
+ ++top;
}
-static inline void pushboolean(js_State *J, int boolean)
+js_Value js_tovalue(js_State *J, int idx)
{
- js_Value v;
- v.type = JS_TBOOLEAN;
- v.u.boolean = boolean;
- push(J, v);
+ idx += top;
+ return stack[idx];
}
-static inline int popboolean(js_State *J)
+int js_toboolean(js_State *J, int idx)
{
- js_Value v = pop(J);
- if (v.type == JS_TBOOLEAN)
- return v.u.boolean;
- if (v.type == JS_TNUMBER)
- return v.u.number != 0;
- return 0;
+ const char *s;
+ double n;
+ idx += top;
+ switch (stack[idx].type) {
+ case JS_TUNDEFINED: return 0;
+ case JS_TNULL: return 0;
+ case JS_TBOOLEAN: return stack[idx].u.boolean;
+ case JS_TNUMBER: n = stack[idx].u.number; return n != 0 || !isnan(n);
+ case JS_TSTRING: s = stack[idx].u.string; return s[0] != 0;
+ default: return 1;
+ }
}
-static inline void pushreference(js_State *J, js_Property *reference)
+double js_tonumber(js_State *J, int idx)
{
- js_Value v;
- v.type = JS_TREFERENCE;
- v.u.reference = reference;
- push(J, v);
+ idx += top;
+ switch (stack[idx].type) {
+ case JS_TUNDEFINED: return NAN;
+ case JS_TNULL: return 0;
+ case JS_TBOOLEAN: return stack[idx].u.boolean;
+ case JS_TNUMBER: return stack[idx].u.number;
+ case JS_TSTRING: return strtod(stack[idx].u.string, NULL);
+ default: return 0;
+ }
}
-static inline js_Property *popreference(js_State *J)
+double js_tointeger(js_State *J, int idx)
{
- js_Value v = pop(J);
- if (v.type == JS_TREFERENCE)
- return v.u.reference;
- return 0;
+ return toint32(js_tonumber(J, idx));
}
-static inline js_Property *peekreference(js_State *J)
+int js_toint32(js_State *J, int idx)
{
- js_Value v = peek(J);
- if (v.type == JS_TREFERENCE)
- return v.u.reference;
- return 0;
+ return toint32(js_tonumber(J, idx));
}
-#define UNARY(X) a = popnumber(J); pushnumber(J, X)
-#define BINARY(X) b = popnumber(J); a = popnumber(J); pushnumber(J, X)
+unsigned int js_touint32(js_State *J, int idx)
+{
+ return toint32(js_tonumber(J, idx));
+}
+const char *js_tostring(js_State *J, int idx)
+{
+ char buf[20];
+ idx += top;
+ switch (stack[idx].type) {
+ case JS_TUNDEFINED: return "undefined";
+ case JS_TNULL: return "null";
+ case JS_TBOOLEAN: return stack[idx].u.boolean ? "true" : "false";
+ case JS_TNUMBER: sprintf(buf, "%.9g", stack[idx].u.number); return js_intern(J, buf);
+ case JS_TSTRING: return stack[idx].u.string;
+ default: return "undefined";
+ }
+}
+
+js_Object *js_toobject(js_State *J, int idx)
+{
+ idx += top;
+ switch (stack[idx].type) {
+ case JS_TUNDEFINED: jsR_error(J, "TypeError");
+ case JS_TNULL: jsR_error(J, "TypeError");
+ case JS_TBOOLEAN: jsR_error(J, "new Boolean()");
+ case JS_TNUMBER: jsR_error(J, "new Number()");
+ case JS_TSTRING: jsR_error(J, "new String()");
+ case JS_TOBJECT: return stack[idx].u.object;
+ default: jsR_error(J, "TypeError");
+ }
+ return NULL;
+}
+
+void js_pop(js_State *J, int n)
+{
+ top -= n;
+}
+
+void js_dup(js_State *J)
+{
+ stack[top] = stack[top-1];
+ ++top;
+}
+
+void js_dup2(js_State *J)
+{
+ stack[top] = stack[top-2];
+ stack[top+1] = stack[top-1];
+ top += 2;
+}
+
+void js_rot3pop2(js_State *J)
+{
+ /* A B C -> C */
+ stack[top-3] = stack[top-1];
+ top -= 2;
+}
+
+void js_dup1rot4(js_State *J)
+{
+ /* A B C -> C A B C */
+ stack[top] = stack[top-1]; /* A B C C */
+ stack[top-1] = stack[top-2]; /* A B B C */
+ stack[top-2] = stack[top-3]; /* A A B C */
+ stack[top-3] = stack[top]; /* C A B C */
+}
+
+void js_trap(js_State *J)
+{
+}
+
static void runfun(js_State *J, js_Function *F, js_Object *E)
{
+ js_Function **FT = F->funtab;
+ double *NT = F->numtab;
+ const char **ST = F->strtab;
+ short *pcstart = F->code;
short *pc = F->code;
- int opcode, addr;
- js_Property *p;
- js_Value v;
- double a, b;
- const char *s;
+ int opcode, offset;
+ const char *str;
+ js_Object *obj;
+ js_Property *ref;
+ double x, y;
+ int b;
+
while (1) {
opcode = *pc++;
switch (opcode) {
- case OP_NUMBER:
- pushnumber(J, F->numlist[*pc++]);
- break;
+ case OP_POP: js_pop(J, 1); break;
+ case OP_DUP: js_dup(J); break;
+ case OP_DUP2: js_dup2(J); break;
+ case OP_DUP1ROT4: js_dup1rot4(J); break;
- case OP_LOADVAR:
- s = F->strlist[*pc++];
- p = js_getproperty(J, E, s);
- if (p)
- push(J, p->value);
+ case OP_NUMBER_0: js_pushnumber(J, 0); break;
+ case OP_NUMBER_1: js_pushnumber(J, 1); break;
+ case OP_NUMBER_X: js_pushnumber(J, *pc++); break;
+ case OP_NUMBER: js_pushnumber(J, NT[*pc++]); break;
+ case OP_STRING: js_pushstring(J, ST[*pc++]); break;
+ // case OP_CLOSURE: break;
+
+ case OP_UNDEF: js_pushundefined(J); break;
+ case OP_NULL: js_pushnull(J); break;
+ case OP_TRUE: js_pushboolean(J, 1); break;
+ case OP_FALSE: js_pushboolean(J, 0); break;
+ // case OP_THIS: break;
+
+ case OP_NEWOBJECT: js_pushobject(J, js_newobject(J)); break;
+ case OP_NEWARRAY: js_pushobject(J, js_newobject(J)); break;
+
+ // FUNDEC
+ // VARDEC
+
+ case OP_GETVAR:
+ ref = js_getproperty(J, E, ST[*pc++]);
+ if (ref)
+ js_pushvalue(J, ref->value);
else
- pushundefined(J);
+ js_pushundefined(J);
break;
- case OP_AVAR:
- s = F->strlist[*pc++];
- p = js_setproperty(J, E, s);
- pushreference(J, p);
+ case OP_SETVAR:
+ ref = js_setproperty(J, E, ST[*pc++]);
+ if (ref)
+ ref->value = js_tovalue(J, -1);
break;
- case OP_LOAD:
- p = peekreference(J);
- if (p)
- push(J, p->value);
+ // OP_DELVAR
+
+ case OP_IN:
+ str = js_tostring(J, -2);
+ obj = js_toobject(J, -1);
+ ref = js_getproperty(J, obj, str);
+ js_pop(J, 2);
+ js_pushboolean(J, ref != NULL);
+ break;
+
+ case OP_GETPROP:
+ obj = js_toobject(J, -2);
+ str = js_tostring(J, -1);
+ ref = js_getproperty(J, obj, str);
+ js_pop(J, 2);
+ if (ref)
+ js_pushvalue(J, ref->value);
else
- pushundefined(J);
+ js_pushundefined(J);
break;
- case OP_STORE:
- v = pop(J);
- p = popreference(J);
- if (p)
- p->value = v;
- push(J, v);
+ case OP_SETPROP:
+ obj = js_toobject(J, -3);
+ str = js_tostring(J, -2);
+ ref = js_setproperty(J, obj, str);
+ if (ref)
+ ref->value = js_tovalue(J, -1);
+ js_rot3pop2(J);
break;
- case OP_UNDEF: pushundefined(J); break;
- case OP_NULL: pushnull(J); break;
- case OP_TRUE: pushboolean(J, 1); break;
- case OP_FALSE: pushboolean(J, 0); break;
+ // OP_DELPROP
- case OP_POS: UNARY(a); break;
- case OP_NEG: UNARY(-a); break;
- case OP_BITNOT: UNARY(~i32(a)); break;
- case OP_LOGNOT: UNARY(!a); break;
+ /* Unary expressions */
- case OP_ADD: BINARY(a + b); break;
- case OP_SUB: BINARY(a - b); break;
- case OP_MUL: BINARY(a * b); break;
- case OP_DIV: BINARY(a / b); break;
- case OP_MOD: BINARY(fmod(a, b)); break;
- case OP_SHL: BINARY(i32(a) << (u32(b) & 0x1F)); break;
- case OP_SHR: BINARY(i32(a) >> (u32(b) & 0x1F)); break;
- case OP_USHR: BINARY(u32(a) >> (u32(b) & 0x1F)); break;
- case OP_BITAND: BINARY(i32(a) & i32(b)); break;
- case OP_BITXOR: BINARY(i32(a) ^ i32(b)); break;
- case OP_BITOR: BINARY(i32(a) | i32(b)); break;
+ case OP_POS:
+ x = js_tonumber(J, -1);
+ js_pop(J, 1);
+ js_pushnumber(J, x);
+ break;
- case OP_LT: BINARY(a < b); break;
- case OP_GT: BINARY(a > b); break;
- case OP_LE: BINARY(a <= b); break;
- case OP_GE: BINARY(a >= b); break;
- case OP_EQ: BINARY(a == b); break;
- case OP_NE: BINARY(a != b); break;
+ case OP_NEG:
+ x = js_tonumber(J, -1);
+ js_pop(J, 1);
+ js_pushnumber(J, -x);
+ break;
- case OP_JFALSE:
- addr = *pc++;
- if (!popboolean(J))
- pc = F->code + addr;
+ case OP_BITNOT:
+ x = js_tonumber(J, -1);
+ js_pop(J, 1);
+ js_pushnumber(J, ~toint32(x));
break;
- case OP_JTRUE:
- addr = *pc++;
- if (popboolean(J))
- pc = F->code + addr;
+ case OP_LOGNOT:
+ b = js_toboolean(J, -1);
+ js_pop(J, 1);
+ js_pushnumber(J, !b);
break;
+ /* Binary expressions */
+
+ case OP_ADD:
+ // TODO: check string concatenation
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushnumber(J, x + y);
+ break;
+
+ case OP_SUB:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushnumber(J, x - y);
+ break;
+
+ case OP_MUL:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushnumber(J, x * y);
+ break;
+
+ case OP_DIV:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushnumber(J, x / y);
+ break;
+
+ case OP_MOD:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushnumber(J, fmod(x, y));
+ break;
+
+ case OP_SHL:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushnumber(J, toint32(x) << (touint32(y) & 0x1F));
+ break;
+
+ case OP_SHR:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushnumber(J, toint32(x) >> (touint32(y) & 0x1F)); break;
+ break;
+
+ case OP_USHR:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushnumber(J, touint32(x) >> (touint32(y) & 0x1F)); break;
+ break;
+
+ case OP_BITAND:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushnumber(J, toint32(x) & toint32(y));
+ break;
+
+ case OP_BITXOR:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushnumber(J, toint32(x) ^ toint32(y));
+ break;
+
+ case OP_BITOR:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushnumber(J, toint32(x) | toint32(y));
+ break;
+
+ /* Relational expressions */
+
+ /* TODO: string comparisons */
+ case OP_LT:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushboolean(J, x < y);
+ break;
+ case OP_GT:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushboolean(J, x > y);
+ break;
+ case OP_LE:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushboolean(J, x <= y);
+ break;
+ case OP_GE:
+ x = js_tonumber(J, -2);
+ y = js_tonumber(J, -1);
+ js_pop(J, 2);
+ js_pushboolean(J, x >= y);
+ break;
+
+ // case OP_EQ:
+ // case OP_NE:
+ // case OP_STRICTEQ:
+ // case OP_STRICTNE:
+
+ /* Branching */
+
+ case OP_DEBUGGER:
+ js_trap(J);
+ break;
+
case OP_JUMP:
- pc = F->code + *pc;
+ pc = pcstart + *pc;
break;
- case OP_POP: pop(J); break;
- case OP_RETURN: return;
+ case OP_JTRUE:
+ offset = *pc++;
+ b = js_toboolean(J, -1);
+ js_pop(J, 1);
+ if (b)
+ pc = pcstart + offset;
+ break;
+ case OP_JFALSE:
+ offset = *pc++;
+ b = js_toboolean(J, -1);
+ js_pop(J, 1);
+ if (!b)
+ pc = pcstart + offset;
+ break;
+
+ case OP_RETURN:
+ return;
+
default:
fprintf(stderr, "illegal instruction: %d (pc=%d)\n", opcode, (int)(pc - F->code - 1));
return;
@@ -223,9 +461,22 @@
}
}
+void jsR_error(js_State *J, const char *message)
+{
+ fprintf(stderr, "runtime error: %s\n", message);
+ longjmp(J->jb, 1);
+}
+
void jsR_runfunction(js_State *J, js_Function *F)
{
js_Object *varenv = js_newobject(J);
+
+ if (setjmp(J->jb)) {
+ js_dumpobject(J, varenv);
+ return;
+ }
+
runfun(J, F, varenv);
+
js_dumpobject(J, varenv);
}
--- a/jsrun.h
+++ b/jsrun.h
@@ -1,6 +1,7 @@
#ifndef js_run_h
#define js_run_h
+void jsR_error(js_State *J, const char *message);
void jsR_runfunction(js_State *J, js_Function *F);
#endif
--- a/jsvalue.h
+++ /dev/null
@@ -1,37 +1,0 @@
-#ifndef js_value_h
-#define js_value_h
-
-enum js_ValueType {
- JS_TUNDEFINED,
- JS_TNULL,
- JS_TBOOLEAN,
- JS_TNUMBER,
- JS_TSTRING,
- JS_TREGEXP,
- JS_TOBJECT,
- JS_TCLOSURE,
- JS_TCFUNCTION,
- JS_TREFERENCE, /* l-value from aval/aindex/amember */
-};
-
-struct js_Value
-{
- union {
- int boolean;
- double number;
- const char *string;
- struct {
- const char *prog;
- unsigned char flags;
- } regexp;
- js_Object *object;
- js_Closure *closure;
- js_CFunction *cfunction;
- js_Property *reference;
- } u;
- js_ValueType type;
-};
-
-void jsC_dumpvalue(js_State *J, js_Value v);
-
-#endif