ref: b595422da9eb0260f2457cbf30e3a5f69de76029
parent: 56042de82bbb4f4cee4fbb1e352a45d3acf134b2
author: Tor Andersson <[email protected]>
date: Thu Jan 16 22:03:10 EST 2014
Add object property accessor functions to public API.
--- a/jsobject.h
+++ b/jsobject.h
@@ -79,6 +79,7 @@
/* jsproperty.c */
js_Object *jsR_newobject(js_State *J, js_Class type);
+js_Property *jsR_getownproperty(js_State *J, js_Object *obj, const char *name);
js_Property *jsR_getproperty(js_State *J, js_Object *obj, const char *name);
js_Property *jsR_setproperty(js_State *J, js_Object *obj, const char *name);
js_Property *jsR_nextproperty(js_State *J, js_Object *obj, const char *name);
--- a/jsproperty.c
+++ b/jsproperty.c
@@ -142,9 +142,20 @@
return obj;
}
-js_Property *jsR_getproperty(js_State *J, js_Object *obj, const char *name)
+js_Property *jsR_getownproperty(js_State *J, js_Object *obj, const char *name)
{
return lookup(obj->properties, name);
+}
+
+js_Property *jsR_getproperty(js_State *J, js_Object *obj, const char *name)
+{
+ do {
+ js_Property *ref = lookup(obj->properties, name);
+ if (ref)
+ return ref;
+ obj = obj->prototype;
+ } while (obj);
+ return NULL;
}
js_Property *jsR_setproperty(js_State *J, js_Object *obj, const char *name)
--- a/jsrun.c
+++ b/jsrun.c
@@ -5,22 +5,12 @@
#include "jsrun.h"
#include "jsstate.h"
+static void jsR_run(js_State *J, js_Function *F, js_Environment *E);
+
static js_Value stack[256];
static int top = 0;
static int bot = 0;
-static void jsR_run(js_State *J, js_Function *F, js_Environment *E);
-
-static void js_dumpstack(js_State *J)
-{
- int i;
- for (i = 0; i < top; ++i) {
- printf("stack %d: ", i);
- js_dumpvalue(J, stack[i]);
- putchar('\n');
- }
-}
-
static inline double tointeger(double n)
{
double sign = n < 0 ? -1 : 1;
@@ -50,6 +40,15 @@
return toint32(n);
}
+/* Push and read stack values stack */
+
+static int stackidx(js_State *J, int idx)
+{
+ if (idx < 0)
+ return top + idx;
+ return bot + idx;
+}
+
static void js_pushvalue(js_State *J, js_Value v)
{
stack[top] = v;
@@ -123,13 +122,6 @@
js_pushobject(J, jsR_newcfunction(J, v));
}
-static int stackidx(js_State *J, int idx)
-{
- if (idx < 0)
- return top + idx;
- return bot + idx;
-}
-
int js_isundefined(js_State *J, int idx)
{
idx = stackidx(J, idx);
@@ -172,14 +164,17 @@
return jsR_toobject(J, &stack[idx]);
}
+/* Stack manipulation */
+
void js_pop(js_State *J, int n)
{
top -= n;
}
-void js_dup(js_State *J)
+void js_dup(js_State *J, int idx)
{
- stack[top] = stack[top-1];
+ idx = stackidx(J, idx);
+ stack[top] = stack[idx];
++top;
}
@@ -224,12 +219,106 @@
++top;
}
-void js_trap(js_State *J)
+/* Global and object property accessors */
+
+void js_getglobal(js_State *J, const char *name)
{
- fprintf(stderr, "trap!\n");
- js_dumpstack(J);
+ js_Property *ref = jsR_getproperty(J, J->G, name);
+ if (ref)
+ js_pushvalue(J, ref->value);
+ else
+ js_pushundefined(J);
}
+void js_setglobal(js_State *J, const char *name)
+{
+ js_Property *ref = jsR_setproperty(J, J->G, name);
+ if (ref)
+ ref->value = js_tovalue(J, -1);
+ js_pop(J, 1);
+}
+
+void js_getownproperty(js_State *J, int idx, const char *name)
+{
+ js_Object *obj = js_toobject(J, idx);
+ js_Property *ref = jsR_getownproperty(J, obj, name);
+ if (ref)
+ js_pushvalue(J, ref->value);
+ else
+ js_pushundefined(J);
+}
+
+void js_getproperty(js_State *J, int idx, const char *name)
+{
+ js_Object *obj = js_toobject(J, idx);
+ js_Property *ref = jsR_getproperty(J, obj, name);
+ if (ref)
+ js_pushvalue(J, ref->value);
+ else
+ js_pushundefined(J);
+}
+
+void js_setproperty(js_State *J, int idx, const char *name)
+{
+ js_Object *obj = js_toobject(J, idx);
+ js_Property *ref = jsR_setproperty(J, obj, name);
+ if (ref)
+ ref->value = js_tovalue(J, -1);
+ js_pop(J, 1);
+}
+
+int js_nextproperty(js_State *J, int idx)
+{
+ js_Object *obj = js_toobject(J, idx);
+ js_Property *ref = jsR_nextproperty(J, obj, js_tostring(J, -1));
+ js_pop(J, 1);
+ if (ref) {
+ js_pushliteral(J, ref->name);
+ js_pushvalue(J, ref->value);
+ return 1;
+ }
+ return 0;
+}
+
+/* Environment records */
+
+js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment *outer)
+{
+ js_Environment *E = malloc(sizeof *E);
+ E->outer = outer;
+ E->variables = vars;
+ return E;
+}
+
+static js_Property *js_decvar(js_State *J, js_Environment *E, const char *name)
+{
+ return jsR_setproperty(J, E->variables, name);
+}
+
+static js_Property *js_getvar(js_State *J, js_Environment *E, const char *name)
+{
+ do {
+ js_Property *ref = jsR_getproperty(J, E->variables, name);
+ if (ref)
+ return ref;
+ E = E->outer;
+ } while (E);
+ return NULL;
+}
+
+static js_Property *js_setvar(js_State *J, js_Environment *E, const char *name)
+{
+ do {
+ js_Property *ref = jsR_getproperty(J, E->variables, name);
+ if (ref)
+ return ref;
+ E = E->outer;
+ } while (E);
+ return jsR_setproperty(J, J->G, name);
+}
+
+/* Function calls */
+
static void jsR_callfunction(js_State *J, int n, js_Function *F, js_Environment *scope)
{
js_Environment *E;
@@ -275,6 +364,23 @@
bot = savebot;
}
+/* Main interpreter loop */
+
+void js_dumpstack(js_State *J)
+{
+ int i;
+ for (i = 0; i < top; ++i) {
+ printf("stack %d: ", i);
+ js_dumpvalue(J, stack[i]);
+ putchar('\n');
+ }
+}
+
+void js_trap(js_State *J)
+{
+ fprintf(stderr, "trap!\n");
+}
+
static void jsR_run(js_State *J, js_Function *F, js_Environment *E)
{
js_Function **FT = F->funtab;
@@ -294,7 +400,7 @@
opcode = *pc++;
switch (opcode) {
case OP_POP: js_pop(J, 1); break;
- case OP_DUP: js_dup(J); break;
+ case OP_DUP: js_dup(J, -1); break;
case OP_DUP2: js_dup2(J); break;
case OP_ROT2: js_rot2(J); break;
case OP_ROT3: js_rot3(J); break;
@@ -315,7 +421,7 @@
case OP_TRUE: js_pushboolean(J, 1); break;
case OP_FALSE: js_pushboolean(J, 0); break;
- case OP_THIS: js_pushobject(J, js_toobject(J, 0)); break;
+ case OP_THIS: js_dup(J, 0); break;
case OP_GLOBAL: js_pushobject(J, J->G); break;
case OP_FUNDEC:
@@ -355,8 +461,11 @@
break;
case OP_GETPROP:
- obj = js_toobject(J, -2);
str = js_tostring(J, -1);
+ js_pop(J, 1);
+ js_getproperty(J, -1, str);
+
+ obj = js_toobject(J, -2);
ref = jsR_getproperty(J, obj, str);
js_pop(J, 2);
if (ref)
@@ -581,14 +690,6 @@
}
}
-js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment *outer)
-{
- js_Environment *E = malloc(sizeof *E);
- E->outer = outer;
- E->variables = vars;
- return E;
-}
-
int jsR_loadstring(js_State *J, const char *filename, const char *source, js_Environment *E)
{
js_Ast *P;
@@ -605,42 +706,6 @@
js_pushobject(J, jsR_newfunction(J, F, E));
return 0;
-}
-
-void js_setglobal(js_State *J, const char *name)
-{
- js_Property *ref = jsR_setproperty(J, J->G, name);
- ref->value = js_tovalue(J, -1);
- js_pop(J, 1);
-}
-
-js_Property *js_decvar(js_State *J, js_Environment *E, const char *name)
-{
- return jsR_setproperty(J, E->variables, name);
-}
-
-js_Property *js_getvar(js_State *J, js_Environment *E, const char *name)
-{
- while (E) {
- js_Property *ref = jsR_getproperty(J, E->variables, name);
- if (ref)
- return ref;
- E = E->outer;
- }
- return NULL;
-}
-
-js_Property *js_setvar(js_State *J, js_Environment *E, const char *name)
-{
- while (1) {
- js_Property *ref = jsR_getproperty(J, E->variables, name);
- if (ref)
- return ref;
- if (!E->outer)
- break;
- E = E->outer;
- }
- return jsR_setproperty(J, E->variables, name);
}
void jsR_error(js_State *J, const char *fmt, ...)
--- a/jsrun.h
+++ b/jsrun.h
@@ -7,19 +7,19 @@
js_Object *variables;
};
-void js_setglobal(js_State *J, const char *name);
-
js_Environment *jsR_newenvironment(js_State *J, js_Object *variables, js_Environment *outer);
-js_Property *js_decvar(js_State *J, js_Environment *E, const char *name);
-js_Property *js_getvar(js_State *J, js_Environment *E, const char *name);
-js_Property *js_setvar(js_State *J, js_Environment *E, const char *name);
int jsR_loadstring(js_State *J, const char *filename, const char *source, js_Environment *E);
-void jsR_runfunction(js_State *J, js_Function *F);
-
void js_call(js_State *J, int n);
+void js_getglobal(js_State *J, const char *name);
+void js_setglobal(js_State *J, const char *name);
+void js_getownproperty(js_State *J, int idx, const char *name);
+void js_getproperty(js_State *J, int idx, const char *name);
+void js_setproperty(js_State *J, int idx, const char *name);
+int js_nextproperty(js_State *J, int idx);
+
void js_pushglobal(js_State *J);
void js_pushundefined(js_State *J);
void js_pushnull(js_State *J);
@@ -29,13 +29,16 @@
void js_newobject(js_State *J);
void js_newarray(js_State *J);
void js_pushcfunction(js_State *J, js_CFunction v);
+
int js_isundefined(js_State *J, int idx);
int js_isstring(js_State *J, int idx);
+
int js_toboolean(js_State *J, int idx);
double js_tonumber(js_State *J, int idx);
double js_tointeger(js_State *J, int idx);
const char *js_tostring(js_State *J, int idx);
+
void js_pop(js_State *J, int n);
-void js_dup(js_State *J);
+void js_dup(js_State *J, int idx);
#endif
--- a/jsstate.c
+++ b/jsstate.c
@@ -89,10 +89,13 @@
static int jsB_eval(js_State *J, int argc)
{
const char *s;
+
if (!js_isstring(J, -1))
return 1;
- // FIXME: need the real environment!
+ // FIXME: use the real environment
+ // FIXME: return value if eval string is an expression
+
s = js_tostring(J, -1);
if (jsR_loadstring(J, "(eval)", s, J->GE))
jsR_error(J, "SyntaxError (eval)");
--- a/jsvalue.c
+++ b/jsvalue.c
@@ -85,7 +85,7 @@
return jsR_tostring(J, &vv);
}
}
- return NULL;
+ return "undefined";
}
js_Object *jsR_toobject(js_State *J, const js_Value *v)
@@ -98,5 +98,5 @@
case JS_TSTRING: return jsR_newstring(J, v->u.string);
case JS_TOBJECT: return v->u.object;
}
- return NULL;
+ jsR_error(J, "TypeError (ToObject)");
}