diff --git a/jscompile.c b/jscompile.c index 8162029..5a18a27 100644 --- a/jscompile.c +++ b/jscompile.c @@ -197,15 +197,18 @@ static void cobject(JF, js_Ast *list) if (kv->type == EXP_PROP_VAL) { js_Ast *prop = kv->a; emit(J, F, OP_DUP); - if (prop->type == AST_IDENTIFIER || prop->type == AST_STRING) - emitstring(J, F, OP_STRING, prop->string); - else if (prop->type == AST_NUMBER) + if (prop->type == AST_IDENTIFIER || prop->type == AST_STRING) { + cexp(J, F, kv->b); + emitstring(J, F, OP_SETPROPS, prop->string); + emit(J, F, OP_POP); + } else if (prop->type == AST_NUMBER) { emitnumber(J, F, prop->number); - else + cexp(J, F, kv->b); + emit(J, F, OP_SETPROP); + emit(J, F, OP_POP); + } 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); + } } else { // TODO: set/get jsC_error(J, kv, "property setters and getters are not implemented"); @@ -240,9 +243,8 @@ static void cassign(JF, js_Ast *lhs, js_Ast *rhs) break; case EXP_MEMBER: cexp(J, F, lhs->a); - emitstring(J, F, OP_STRING, lhs->b->string); cexp(J, F, rhs); - emit(J, F, OP_SETPROP); + emitstring(J, F, OP_SETPROPS, lhs->b->string); break; default: jsC_error(J, lhs, "invalid l-value in assignment"); @@ -276,9 +278,8 @@ static void cassignforin(JF, js_Ast *stm) break; case EXP_MEMBER: cexp(J, F, lhs->a); - emitstring(J, F, OP_STRING, lhs->b->string); - emit(J, F, OP_ROT3); - emit(J, F, OP_SETPROP); + emit(J, F, OP_ROT2); + emitstring(J, F, OP_SETPROPS, lhs->b->string); emit(J, F, OP_POP); break; default: @@ -303,10 +304,9 @@ static void cassignop1(JF, js_Ast *lhs, int dup) 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); + emit(J, F, OP_DUP); + emitstring(J, F, OP_GETPROPS, lhs->b->string); + if (dup) emit(J, F, OP_DUP1ROT3); break; default: jsC_error(J, lhs, "invalid l-value in assignment"); @@ -321,9 +321,9 @@ static void cassignop2(JF, js_Ast *lhs) emitstring(J, F, OP_SETVAR, lhs->string); break; case EXP_INDEX: + break; case EXP_MEMBER: - case EXP_CALL: - emit(J, F, OP_SETPROP); + emitstring(J, F, OP_SETPROPS, lhs->b->string); break; default: jsC_error(J, lhs, "invalid l-value in assignment"); @@ -352,8 +352,7 @@ static void cdelete(JF, js_Ast *exp) break; case EXP_MEMBER: cexp(J, F, exp->a); - emitstring(J, F, OP_STRING, exp->b->string); - emit(J, F, OP_DELPROP); + emitstring(J, F, OP_DELPROPS, exp->b->string); break; default: jsC_error(J, exp, "invalid l-value in delete expression"); @@ -375,8 +374,7 @@ static void ccall(JF, js_Ast *fun, js_Ast *args) case EXP_MEMBER: cexp(J, F, fun->a); emit(J, F, OP_DUP); - emitstring(J, F, OP_STRING, fun->b->string); - emit(J, F, OP_GETPROP); + emitstring(J, F, OP_GETPROPS, fun->b->string); emit(J, F, OP_ROT2); break; default: @@ -429,8 +427,7 @@ static void cexp(JF, js_Ast *exp) case EXP_MEMBER: cexp(J, F, exp->a); - emitstring(J, F, OP_STRING, exp->b->string); - emit(J, F, OP_GETPROP); + emitstring(J, F, OP_GETPROPS, exp->b->string); break; case EXP_CALL: diff --git a/jscompile.h b/jscompile.h index 2ed9a7d..ea71eb5 100644 --- a/jscompile.h +++ b/jscompile.h @@ -13,6 +13,7 @@ enum js_OpCode OP_ROT3, /* A B C -- C A B */ OP_ROT2POP1, /* A B -- B */ OP_ROT3POP2, /* A B C -- C */ + OP_DUP1ROT3, /* A B -- B A B */ OP_DUP1ROT4, /* A B C -- C A B C */ OP_NUMBER_0, /* -- 0 */ @@ -41,9 +42,13 @@ enum js_OpCode OP_DELVAR, /* -S- */ OP_IN, /* -- */ + OP_GETPROP, /* -- */ + OP_GETPROPS, /* -S- */ OP_SETPROP, /* -- */ + OP_SETPROPS, /* -S- */ OP_DELPROP, /* -- */ + OP_DELPROPS, /* -S- */ OP_ITERATOR, /* -- */ OP_NEXTITER, /* -- true || false */ diff --git a/jsdump.c b/jsdump.c index 6d43fee..0b8dafe 100644 --- a/jsdump.c +++ b/jsdump.c @@ -648,6 +648,9 @@ void jsC_dumpfunction(js_State *J, js_Function *F) case OP_GETVAR: case OP_SETVAR: case OP_DELVAR: + case OP_GETPROPS: + case OP_SETPROPS: + case OP_DELPROPS: pc(' '); ps(F->strtab[*p++]); break; diff --git a/jsrun.c b/jsrun.c index d58efcd..dc96825 100644 --- a/jsrun.c +++ b/jsrun.c @@ -215,6 +215,15 @@ void js_rot3pop2(js_State *J) TOP -= 2; } +void js_dup1rot3(js_State *J) +{ + /* A B -> B A B */ + STACK[TOP] = STACK[TOP-1]; /* A B B */ + STACK[TOP-1] = STACK[TOP-2]; /* A A B */ + STACK[TOP-2] = STACK[TOP]; /* B A B */ + ++TOP; +} + void js_dup1rot4(js_State *J) { /* A B C -> C A B C */ @@ -526,6 +535,7 @@ static void jsR_run(js_State *J, js_Function *F) case OP_ROT3: js_rot3(J); break; case OP_ROT2POP1: js_rot2pop1(J); break; case OP_ROT3POP2: js_rot3pop2(J); break; + case OP_DUP1ROT3: js_dup1rot3(J); break; case OP_DUP1ROT4: js_dup1rot4(J); break; case OP_NUMBER_0: js_pushnumber(J, 0); break; @@ -596,6 +606,19 @@ static void jsR_run(js_State *J, js_Function *F) js_pushundefined(J); break; + case OP_GETPROPS: + str = ST[*pc++]; + js_getproperty(J, -1, str); + + obj = js_toobject(J, -2); + ref = jsV_getproperty(J, obj, str); + js_pop(J, 2); + if (ref) + js_pushvalue(J, ref->value); + else + js_pushundefined(J); + break; + case OP_SETPROP: obj = js_toobject(J, -3); str = js_tostring(J, -2); @@ -605,7 +628,17 @@ static void jsR_run(js_State *J, js_Function *F) js_rot3pop2(J); break; + case OP_SETPROPS: + str = ST[*pc++]; + obj = js_toobject(J, -2); + ref = jsV_setproperty(J, obj, str); + if (ref) + ref->value = js_tovalue(J, -1); + js_rot2pop1(J); + break; + // OP_DELPROP + // OP_DELPROPS case OP_ITERATOR: obj = jsV_newiterator(J, js_toobject(J, -1));