Keep the current environment scope chain in the js_State struct.

Create script (global/eval code) functions without a scope (they're
not closures) and run them with js_eval so they can execute with the
current scope chain.

Normal functions still have a scope and are run with js_call.
This commit is contained in:
Tor Andersson
2014-01-17 14:58:03 +01:00
parent 2a027a1b21
commit f6c5c56b44
5 changed files with 51 additions and 32 deletions

55
jsrun.c
View File

@@ -5,7 +5,7 @@
#include "jsrun.h"
#include "jsstate.h"
static void jsR_run(js_State *J, js_Function *F, js_Environment *E);
static void jsR_run(js_State *J, js_Function *F);
static js_Value stack[256];
static int top = 0;
@@ -296,13 +296,14 @@ js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment
return E;
}
static js_Property *js_decvar(js_State *J, js_Environment *E, const char *name)
static js_Property *js_decvar(js_State *J, const char *name)
{
return jsR_setproperty(J, E->variables, name);
return jsR_setproperty(J, J->E->variables, name);
}
static js_Property *js_getvar(js_State *J, js_Environment *E, const char *name)
static js_Property *js_getvar(js_State *J, const char *name)
{
js_Environment *E = J->E;
do {
js_Property *ref = jsR_getproperty(J, E->variables, name);
if (ref)
@@ -312,8 +313,9 @@ static js_Property *js_getvar(js_State *J, js_Environment *E, const char *name)
return NULL;
}
static js_Property *js_setvar(js_State *J, js_Environment *E, const char *name)
static js_Property *js_setvar(js_State *J, const char *name)
{
js_Environment *E = J->E;
do {
js_Property *ref = jsR_getproperty(J, E->variables, name);
if (ref)
@@ -327,20 +329,23 @@ static js_Property *js_setvar(js_State *J, js_Environment *E, const char *name)
static void jsR_callfunction(js_State *J, int n, js_Function *F, js_Environment *scope)
{
js_Environment *E;
js_Environment *saveE;
int i;
E = jsR_newenvironment(J, jsR_newobject(J, JS_COBJECT), scope);
saveE = J->E;
J->E = jsR_newenvironment(J, jsR_newobject(J, JS_COBJECT), scope);
for (i = 0; i < n; i++) {
js_Property *ref = js_decvar(J, E, F->params[i]);
js_Property *ref = js_decvar(J, F->params[i]);
if (i < n)
ref->value = js_tovalue(J, i + 1);
}
js_pop(J, n);
jsR_run(J, F, E);
jsR_run(J, F);
js_rot3pop2(J);
J->E = saveE;
}
static void jsR_callcfunction(js_State *J, int n, js_CFunction F)
@@ -370,6 +375,20 @@ void js_call(js_State *J, int n)
bot = savebot;
}
void js_eval(js_State *J)
{
js_Object *obj = js_toobject(J, -2);
int savebot = bot;
bot = top - 1;
if (obj->type == JS_CFUNCTION) {
jsR_run(J, obj->function);
js_rot3pop2(J);
}
else
jsR_error(J, "TypeError (not a script)");
bot = savebot;
}
/* Main interpreter loop */
void js_dumpstack(js_State *J)
@@ -387,7 +406,7 @@ void js_trap(js_State *J)
fprintf(stderr, "trap!\n");
}
static void jsR_run(js_State *J, js_Function *F, js_Environment *E)
static void jsR_run(js_State *J, js_Function *F)
{
js_Function **FT = F->funtab;
double *NT = F->numtab;
@@ -418,7 +437,7 @@ static void jsR_run(js_State *J, js_Function *F, js_Environment *E)
case OP_NUMBER: js_pushnumber(J, NT[*pc++]); break;
case OP_STRING: js_pushliteral(J, ST[*pc++]); break;
case OP_CLOSURE: js_pushobject(J, jsR_newfunction(J, FT[*pc++], E)); break;
case OP_CLOSURE: js_pushobject(J, jsR_newfunction(J, FT[*pc++], J->E)); break;
case OP_NEWOBJECT: js_newobject(J); break;
case OP_NEWARRAY: js_newarray(J); break;
@@ -431,19 +450,19 @@ static void jsR_run(js_State *J, js_Function *F, js_Environment *E)
case OP_GLOBAL: js_pushobject(J, J->G); break;
case OP_FUNDEC:
ref = js_decvar(J, E, ST[*pc++]);
ref = js_decvar(J, ST[*pc++]);
if (ref)
ref->value = js_tovalue(J, -1);
js_pop(J, 1);
break;
case OP_VARDEC:
ref = js_decvar(J, E, ST[*pc++]);
ref = js_decvar(J, ST[*pc++]);
break;
case OP_GETVAR:
str = ST[*pc++];
ref = js_getvar(J, E, str);
ref = js_getvar(J, str);
if (ref)
js_pushvalue(J, ref->value);
else
@@ -451,7 +470,7 @@ static void jsR_run(js_State *J, js_Function *F, js_Environment *E)
break;
case OP_SETVAR:
ref = js_setvar(J, E, ST[*pc++]);
ref = js_setvar(J, ST[*pc++]);
if (ref)
ref->value = js_tovalue(J, -1);
break;
@@ -710,7 +729,7 @@ static void jsR_run(js_State *J, js_Function *F, js_Environment *E)
}
}
int jsR_loadstring(js_State *J, const char *filename, const char *source, js_Environment *E)
int jsR_loadscript(js_State *J, const char *filename, const char *source)
{
js_Ast *P;
js_Function *F;
@@ -724,7 +743,7 @@ int jsR_loadstring(js_State *J, const char *filename, const char *source, js_Env
jsP_freeparse(J);
if (!F) return 1;
js_pushobject(J, jsR_newfunction(J, F, E));
js_pushobject(J, jsR_newfunction(J, F, NULL));
return 0;
}

View File

@@ -9,9 +9,10 @@ struct js_Environment
js_Environment *jsR_newenvironment(js_State *J, js_Object *variables, js_Environment *outer);
int jsR_loadstring(js_State *J, const char *filename, const char *source, js_Environment *E);
int jsR_loadscript(js_State *J, const char *filename, const char *source);
void js_call(js_State *J, int n);
void js_eval(js_State *J);
void js_getglobal(js_State *J, const char *name);
void js_setglobal(js_State *J, const char *name);

View File

@@ -5,7 +5,7 @@
int js_loadstring(js_State *J, const char *source)
{
return jsR_loadstring(J, "(string)", source, J->GE);
return jsR_loadscript(J, "(string)", source);
}
int js_loadfile(js_State *J, const char *filename)
@@ -41,7 +41,7 @@ int js_loadfile(js_State *J, const char *filename)
s[n] = 0; /* zero-terminate string containing file data */
t = jsR_loadstring(J, filename, s, J->GE);
t = jsR_loadscript(J, filename, s);
free(s);
fclose(f);
@@ -54,8 +54,8 @@ int js_dostring(js_State *J, const char *source)
if (!rv) {
if (setjmp(J->jb))
return 1;
js_pushglobal(J);
js_call(J, 0);
js_dup(J, 0);
js_eval(J);
js_pop(J, 1);
}
return rv;
@@ -67,8 +67,8 @@ int js_dofile(js_State *J, const char *filename)
if (!rv) {
if (setjmp(J->jb))
return 1;
js_pushglobal(J);
js_call(J, 0);
js_dup(J, 0);
js_eval(J);
js_pop(J, 1);
}
return rv;
@@ -93,15 +93,14 @@ static int jsB_eval(js_State *J, int argc)
if (!js_isstring(J, -1))
return 1;
// 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))
if (jsR_loadscript(J, "(eval)", s))
jsR_error(J, "SyntaxError (eval)");
js_pushglobal(J);
js_call(J, 0);
js_dup(J, 0); /* copy this */
js_eval(J); /* call with current scope chain */
return 1;
}
@@ -111,7 +110,7 @@ js_State *js_newstate(void)
memset(J, 0, sizeof(*J));
J->G = jsR_newobject(J, JS_COBJECT);
J->GE = jsR_newenvironment(J, J->G, NULL);
J->E = jsR_newenvironment(J, J->G, NULL);
js_pushcfunction(J, jsB_eval);
js_setglobal(J, "eval");

View File

@@ -30,7 +30,7 @@ struct js_State
/* runtime */
js_Object *G;
js_Environment *GE;
js_Environment *E;
};

View File

@@ -5,7 +5,7 @@ js_Value jsR_toprimitive(js_State *J, const js_Value *v, int preferred)
{
js_Object *obj;
if (v->type != JS_COBJECT)
if (v->type != JS_TOBJECT)
return *v;
obj = v->u.object;