ref: 6b1906f3b53c3799dcef6e3e87e05a25ef7479c4
parent: 6d690be9690fc2fb705da5e7c7eb71318b5cc2ce
author: Tor Andersson <tor@ccxvii.net>
date: Tue Jan 14 19:36:22 EST 2014
Add for-in iterator.
--- a/jscompile.c
+++ b/jscompile.c
@@ -174,8 +174,8 @@
while (list) {
emit(J, F, OP_DUP);
emit(J, F, OP_NUMBER_X);
- cexp(J, F, list->a);
emit(J, F, i++);
+ cexp(J, F, list->a);
emit(J, F, OP_SETPROP);
emit(J, F, OP_POP);
list = list->b;
@@ -245,6 +245,35 @@
}
}
+static void cassignloop(JF, js_Ast *lhs)
+{
+ switch (lhs->type) {
+ case AST_IDENTIFIER:
+ emitstring(J, F, OP_SETVAR, lhs->string);
+ break;
+ case EXP_INDEX:
+ cexp(J, F, lhs->a);
+ cexp(J, F, lhs->b);
+ emit(J, F, OP_ROT3);
+ emit(J, F, OP_SETPROP);
+ 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);
+ break;
+ case EXP_CALL: /* host functions may return an assignable l-value */
+ cexp(J, F, lhs);
+ emit(J, F, OP_ROT3);
+ 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) {
@@ -596,15 +625,13 @@
break;
case STM_FOR:
- cexp(J, F, stm->a);
- emit(J, F, OP_POP);
- goto for_body;
-
case STM_FOR_VAR:
- cvarinit(J, F, stm->a);
- goto for_body;
-
- for_body:
+ if (stm->type == STM_FOR_VAR) {
+ cvarinit(J, F, stm->a);
+ } else {
+ cexp(J, F, stm->a);
+ emit(J, F, OP_POP);
+ }
loop = here(J, F);
cexp(J, F, stm->b);
end = jump(J, F, OP_JFALSE);
@@ -614,7 +641,25 @@
jumpto(J, F, OP_JUMP, loop);
label(J, F, end);
break;
- // for-in
+
+ case STM_FOR_IN:
+ case STM_FOR_IN_VAR:
+ cexp(J, F, stm->b);
+ emit(J, F, OP_UNDEF);
+ loop = here(J, F);
+ emit(J, F, OP_NEXTPROP);
+ end = jump(J, F, OP_JFALSE);
+ if (stm->type == STM_FOR_IN_VAR) {
+ if (stm->a->b)
+ jsC_error(J, stm->a->b, "more than one loop variable in for-in statement");
+ emitstring(J, F, OP_SETVAR, stm->a->a->a->string); /* stm(list(var-init(ident))) */
+ } else {
+ cassignloop(J, F, stm->a);
+ }
+ cstm(J, F, stm->c);
+ jumpto(J, F, OP_JUMP, loop);
+ label(J, F, end);
+ break;
// break
// continue
--- a/jscompile.h
+++ b/jscompile.h
@@ -6,6 +6,7 @@
OP_POP, /* A -- */
OP_DUP, /* A -- A A */
OP_DUP2, /* A B -- A B A B */
+ OP_ROT3, /* A B C -- C A B */
OP_DUP1ROT4, /* A B C -- C A B C */
OP_NUMBER_0, /* -- 0 */
@@ -36,6 +37,7 @@
OP_GETPROP, /* <obj> <name> -- <value> */
OP_SETPROP, /* <obj> <name> <value> -- <value> */
OP_DELPROP, /* <obj> <name> -- <success> */
+ OP_NEXTPROP, /* <obj> <name> -- <obj> <name+1> true || false */
OP_CALL, /* <thisvalue> <closure> <args...> -(numargs)- <returnvalue> */
OP_NEW, /* <closure> <args...> -(numargs)- <returnvalue> */
--- a/jsdump.c
+++ b/jsdump.c
@@ -15,7 +15,7 @@
"instanceof", "in", "shl", "shr", "ushr", "add", "sub", "mul", "div",
"mod", "cond", "ass", "ass_mul", "ass_div", "ass_mod", "ass_add",
"ass_sub", "ass_shl", "ass_shr", "ass_ushr", "ass_bitand",
- "ass_bitxor", "ass_bitor", "comma", "var_init", "block", "nop", "var",
+ "ass_bitxor", "ass_bitor", "comma", "varexp", "block", "nop", "var",
"if", "do_while", "while", "for", "for_var", "for_in", "for_in_var",
"continue", "break", "return", "with", "switch", "throw", "try",
"debugger", "label", "case", "default",
--- a/jsobject.c
+++ b/jsobject.c
@@ -20,22 +20,20 @@
static js_Property sentinel = { "", &sentinel, &sentinel, 0 };
-static js_Property undefined = { "", &sentinel, &sentinel, 0, { {0}, JS_TUNDEFINED } };
-
-static js_Property *newproperty(const char *key)
+static js_Property *newproperty(const char *name)
{
js_Property *node = malloc(sizeof(js_Property));
- node->key = strdup(key);
+ node->name = strdup(name);
node->left = node->right = &sentinel;
node->level = 1;
-// node->value = 0;
+ node->value.type = JS_TUNDEFINED;
return node;
}
-static js_Property *lookup(js_Property *node, const char *key)
+static js_Property *lookup(js_Property *node, const char *name)
{
while (node != &sentinel) {
- int c = strcmp(key, node->key);
+ int c = strcmp(name, node->name);
if (c == 0)
return node;
else if (c < 0)
@@ -73,14 +71,14 @@
return node;
}
-static js_Property *insert(js_Property *node, const char *key, js_Property **result)
+static js_Property *insert(js_Property *node, const char *name, js_Property **result)
{
if (node != &sentinel) {
- int c = strcmp(key, node->key);
+ int c = strcmp(name, node->name);
if (c < 0)
- node->left = insert(node->left, key, result);
+ node->left = insert(node->left, name, result);
else if (c > 0)
- node->right = insert(node->right, key, result);
+ node->right = insert(node->right, name, result);
else
return *result = node;
node = skew(node);
@@ -87,9 +85,48 @@
node = split(node);
return node;
}
- return *result = newproperty(key);
+ return *result = newproperty(name);
}
+static js_Property *lookupfirst(js_Property *node)
+{
+ while (node != &sentinel) {
+ if (node->left == &sentinel)
+ return node;
+ node = node->left;
+ }
+ return NULL;
+}
+
+static js_Property *lookupnext(js_Property *node, const char *name)
+{
+ js_Property *stack[100], *parent;
+ int top = 0;
+
+ stack[0] = NULL;
+ while (node != &sentinel) {
+ stack[++top] = node;
+ int c = strcmp(name, node->name);
+ if (c == 0)
+ goto found;
+ else if (c < 0)
+ node = node->left;
+ else
+ node = node->right;
+ }
+ return NULL;
+
+found:
+ if (node->right != &sentinel)
+ return lookupfirst(node->right);
+ parent = stack[--top];
+ while (parent && node == parent->right) {
+ node = parent;
+ parent = stack[--top];
+ }
+ return parent;
+}
+
js_Object *js_newobject(js_State *J)
{
js_Object *obj = malloc(sizeof(js_Object));
@@ -109,6 +146,16 @@
return result;
}
+js_Property *js_firstproperty(js_State *J, js_Object *obj)
+{
+ return lookupfirst(obj->properties);
+}
+
+js_Property *js_nextproperty(js_State *J, js_Object *obj, const char *name)
+{
+ return lookupnext(obj->properties, name);
+}
+
static void js_dumpvalue(js_State *J, js_Value v)
{
switch (v.type) {
@@ -127,7 +174,7 @@
{
if (node->left != &sentinel)
js_dumpproperty(J, node->left);
- printf("\t%s: ", node->key);
+ printf("\t%s: ", node->name);
js_dumpvalue(J, node->value);
printf(",\n");
if (node->right != &sentinel)
--- a/jsobject.h
+++ b/jsobject.h
@@ -27,7 +27,7 @@
struct js_Property
{
- char *key;
+ char *name;
js_Property *left, *right;
int level;
js_Value value;
@@ -45,7 +45,9 @@
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);
+js_Property *js_firstproperty(js_State *J, js_Object *obj);
+js_Property *js_nextproperty(js_State *J, js_Object *obj, const char *name);
+
void js_dumpobject(js_State *J, js_Object *obj);
#endif
--- a/jsrun.c
+++ b/jsrun.c
@@ -82,6 +82,18 @@
++top;
}
+int js_isundefined(js_State *J, int idx)
+{
+ idx += top;
+ return stack[idx].type == JS_TUNDEFINED;
+}
+
+int js_isstring(js_State *J, int idx)
+{
+ idx += top;
+ return stack[idx].type == JS_TSTRING;
+}
+
js_Value js_tovalue(js_State *J, int idx)
{
idx += top;
@@ -178,6 +190,15 @@
top += 2;
}
+void js_rot3(js_State *J)
+{
+ /* A B C -> C A B */
+ js_Value tmp = stack[top-1]; /* A B C (C) */
+ stack[top-1] = stack[top-2]; /* A B B */
+ stack[top-2] = stack[top-3]; /* A A B */
+ stack[top-3] = tmp; /* C A B */
+}
+
void js_rot3pop2(js_State *J)
{
/* A B C -> C */
@@ -192,6 +213,7 @@
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 */
+ ++top;
}
void js_trap(js_State *J)
@@ -219,6 +241,7 @@
case OP_POP: js_pop(J, 1); break;
case OP_DUP: js_dup(J); break;
case OP_DUP2: js_dup2(J); break;
+ case OP_ROT3: js_rot3(J); break;
case OP_DUP1ROT4: js_dup1rot4(J); break;
case OP_NUMBER_0: js_pushnumber(J, 0); break;
@@ -237,8 +260,16 @@
case OP_NEWOBJECT: js_pushobject(J, js_newobject(J)); break;
case OP_NEWARRAY: js_pushobject(J, js_newobject(J)); break;
- case OP_FUNDEC: js_pop(J, 1); break;
+ case OP_FUNDEC:
+ ref = js_setproperty(J, E, ST[*pc++]);
+// if (ref)
+// ref->value = js_toclosure(J, -1);
+ js_pop(J, 1);
+ break;
+
case OP_VARDEC: pc++; break;
+ ref = js_setproperty(J, E, ST[*pc++]);
+ break;
case OP_GETVAR:
ref = js_getproperty(J, E, ST[*pc++]);
@@ -285,6 +316,23 @@
break;
// OP_DELPROP
+
+ case OP_NEXTPROP:
+ obj = js_toobject(J, -2);
+ if (js_isundefined(J, -1))
+ ref = js_firstproperty(J, obj);
+ else
+ ref = js_nextproperty(J, obj, js_tostring(J, -1));
+ printf("nextprop -> %s\n", ref ? ref->name : "(end)");
+ if (ref) {
+ js_pop(J, 1);
+ js_pushstring(J, ref->name);
+ js_pushboolean(J, 1);
+ } else {
+ js_pop(J, 2);
+ js_pushboolean(J, 0);
+ }
+ break;
/* Unary expressions */