mirror of
https://github.com/ccxvii/mujs.git
synced 2026-09-22 15:13:35 +08:00
Fix the shape of the outer API a bit. Implement eval.
This commit is contained in:
@@ -41,8 +41,10 @@ void js_close(js_State *J);
|
||||
|
||||
int js_error(js_State *J, const char *fmt, ...);
|
||||
|
||||
int js_loadstring(js_State *J, const char *s);
|
||||
int js_loadstring(js_State *J, const char *source);
|
||||
int js_loadfile(js_State *J, const char *filename);
|
||||
int js_dostring(js_State *J, const char *source);
|
||||
int js_dofile(js_State *J, const char *filename);
|
||||
|
||||
/* binding API: TODO: move from jsrun.h */
|
||||
|
||||
|
||||
+3
-1
@@ -7,6 +7,8 @@
|
||||
|
||||
#define JF js_State *J, js_Function *F
|
||||
|
||||
JS_NORETURN int jsC_error(js_State *J, js_Ast *node, const char *fmt, ...);
|
||||
|
||||
static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body);
|
||||
static void cexp(JF, js_Ast *exp);
|
||||
static void cstmlist(JF, js_Ast *list);
|
||||
@@ -754,7 +756,7 @@ int jsC_error(js_State *J, js_Ast *node, const char *fmt, ...)
|
||||
longjmp(J->jb, 1);
|
||||
}
|
||||
|
||||
void jsC_freecompile(js_State *J)
|
||||
static void jsC_freecompile(js_State *J)
|
||||
{
|
||||
js_Function *F = J->fun;
|
||||
while (F) {
|
||||
|
||||
@@ -109,8 +109,6 @@ struct js_Function
|
||||
};
|
||||
|
||||
js_Function *jsC_compile(js_State *J, js_Ast *prog);
|
||||
void jsC_freecompile(js_State *J);
|
||||
JS_NORETURN int jsC_error(js_State *J, js_Ast *node, const char *fmt, ...);
|
||||
|
||||
void jsC_dumpfunction(js_State *J, js_Function *fun);
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#include "js.h"
|
||||
#include "jsparse.h"
|
||||
#include "jscompile.h"
|
||||
#include "jsobject.h"
|
||||
#include "jsrun.h"
|
||||
|
||||
static int jsP_loadstring(js_State *J, const char *filename, const char *source)
|
||||
{
|
||||
js_Ast *prog = jsP_parse(J, filename, source);
|
||||
if (prog) {
|
||||
js_Function *fun;
|
||||
jsP_optimize(J, prog);
|
||||
//jsP_dumpsyntax(J, prog);
|
||||
//jsP_dumplist(J, prog);
|
||||
fun = jsC_compile(J, prog);
|
||||
if (fun) {
|
||||
jsC_dumpfunction(J, fun);
|
||||
jsR_runfunction(J, fun);
|
||||
}
|
||||
jsC_freecompile(J);
|
||||
jsP_freeparse(J);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int js_loadstring(js_State *J, const char *source)
|
||||
{
|
||||
return jsP_loadstring(J, "(string)", source);
|
||||
}
|
||||
|
||||
int js_loadfile(js_State *J, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
char *s;
|
||||
int n, t;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (!f) {
|
||||
return js_error(J, "cannot open file: '%s'", filename);
|
||||
}
|
||||
|
||||
if (fseek(f, 0, SEEK_END) < 0) {
|
||||
fclose(f);
|
||||
return js_error(J, "cannot seek in file: '%s'", filename);
|
||||
}
|
||||
n = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
s = malloc(n + 1); /* add space for string terminator */
|
||||
if (!s) {
|
||||
fclose(f);
|
||||
return js_error(J, "cannot allocate storage for file contents: '%s'", filename);
|
||||
}
|
||||
|
||||
t = fread(s, 1, n, f);
|
||||
if (t != n) {
|
||||
free(s);
|
||||
fclose(f);
|
||||
return js_error(J, "cannot read data from file: '%s'", filename);
|
||||
}
|
||||
|
||||
s[n] = 0; /* zero-terminate string containing file data */
|
||||
|
||||
t = jsP_loadstring(J, filename, s);
|
||||
|
||||
free(s);
|
||||
fclose(f);
|
||||
return t;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "js.h"
|
||||
#include "jsobject.h"
|
||||
#include "jsparse.h"
|
||||
#include "jscompile.h"
|
||||
#include "jsrun.h"
|
||||
#include "jsstate.h"
|
||||
@@ -88,7 +89,7 @@ void js_pushstring(js_State *J, const char *v)
|
||||
++top;
|
||||
}
|
||||
|
||||
void jsR_pushliteral(js_State *J, const char *v)
|
||||
void js_pushliteral(js_State *J, const char *v)
|
||||
{
|
||||
stack[top].type = JS_TSTRING;
|
||||
stack[top].u.string = v;
|
||||
@@ -102,6 +103,11 @@ void js_pushobject(js_State *J, js_Object *v)
|
||||
++top;
|
||||
}
|
||||
|
||||
void js_pushglobal(js_State *J)
|
||||
{
|
||||
js_pushobject(J, J->G);
|
||||
}
|
||||
|
||||
void js_newobject(js_State *J)
|
||||
{
|
||||
js_pushobject(J, jsR_newobject(J, JS_COBJECT));
|
||||
@@ -298,7 +304,7 @@ static void jsR_run(js_State *J, js_Function *F, js_Environment *E)
|
||||
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: jsR_pushliteral(J, ST[*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_NEWOBJECT: js_newobject(J); break;
|
||||
@@ -378,7 +384,7 @@ static void jsR_run(js_State *J, js_Function *F, js_Environment *E)
|
||||
ref = jsR_nextproperty(J, obj, js_tostring(J, -1));
|
||||
if (ref) {
|
||||
js_pop(J, 1);
|
||||
jsR_pushliteral(J, ref->name);
|
||||
js_pushliteral(J, ref->name);
|
||||
js_pushboolean(J, 1);
|
||||
} else {
|
||||
js_pop(J, 2);
|
||||
@@ -583,6 +589,24 @@ js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment
|
||||
return E;
|
||||
}
|
||||
|
||||
int jsR_loadstring(js_State *J, const char *filename, const char *source, js_Environment *E)
|
||||
{
|
||||
js_Ast *P;
|
||||
js_Function *F;
|
||||
|
||||
// TODO: push exception stack
|
||||
|
||||
P = jsP_parse(J, filename, source);
|
||||
if (!P) return 1;
|
||||
jsP_optimize(J, P);
|
||||
F = jsC_compile(J, P);
|
||||
jsP_freeparse(J);
|
||||
if (!F) return 1;
|
||||
|
||||
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);
|
||||
@@ -631,17 +655,3 @@ void jsR_error(js_State *J, const char *fmt, ...)
|
||||
|
||||
longjmp(J->jb, 1);
|
||||
}
|
||||
|
||||
void jsR_runfunction(js_State *J, js_Function *F)
|
||||
{
|
||||
if (setjmp(J->jb)) {
|
||||
js_dumpobject(J, J->G);
|
||||
return;
|
||||
}
|
||||
|
||||
js_pushobject(J, J->G); /* initial "this" */
|
||||
jsR_run(J, F, J->GE);
|
||||
|
||||
js_dumpobject(J, J->G);
|
||||
js_dumpstack(J);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,13 @@ 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_pushglobal(js_State *J);
|
||||
void js_pushundefined(js_State *J);
|
||||
void js_pushnull(js_State *J);
|
||||
void js_pushboolean(js_State *J, int v);
|
||||
|
||||
@@ -3,6 +3,77 @@
|
||||
#include "jsrun.h"
|
||||
#include "jsstate.h"
|
||||
|
||||
int js_loadstring(js_State *J, const char *source)
|
||||
{
|
||||
return jsR_loadstring(J, "(string)", source, J->GE);
|
||||
}
|
||||
|
||||
int js_loadfile(js_State *J, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
char *s;
|
||||
int n, t;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (!f) {
|
||||
return js_error(J, "cannot open file: '%s'", filename);
|
||||
}
|
||||
|
||||
if (fseek(f, 0, SEEK_END) < 0) {
|
||||
fclose(f);
|
||||
return js_error(J, "cannot seek in file: '%s'", filename);
|
||||
}
|
||||
n = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
s = malloc(n + 1); /* add space for string terminator */
|
||||
if (!s) {
|
||||
fclose(f);
|
||||
return js_error(J, "cannot allocate storage for file contents: '%s'", filename);
|
||||
}
|
||||
|
||||
t = fread(s, 1, n, f);
|
||||
if (t != n) {
|
||||
free(s);
|
||||
fclose(f);
|
||||
return js_error(J, "cannot read data from file: '%s'", filename);
|
||||
}
|
||||
|
||||
s[n] = 0; /* zero-terminate string containing file data */
|
||||
|
||||
t = jsR_loadstring(J, filename, s, J->GE);
|
||||
|
||||
free(s);
|
||||
fclose(f);
|
||||
return t;
|
||||
}
|
||||
|
||||
int js_dostring(js_State *J, const char *source)
|
||||
{
|
||||
int rv = js_loadstring(J, source);
|
||||
if (!rv) {
|
||||
if (setjmp(J->jb))
|
||||
return 1;
|
||||
js_pushglobal(J);
|
||||
js_call(J, 0);
|
||||
js_pop(J, 1);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
int js_dofile(js_State *J, const char *filename)
|
||||
{
|
||||
int rv = js_loadfile(J, filename);
|
||||
if (!rv) {
|
||||
if (setjmp(J->jb))
|
||||
return 1;
|
||||
js_pushglobal(J);
|
||||
js_call(J, 0);
|
||||
js_pop(J, 1);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int jsB_print(js_State *J, int argc)
|
||||
{
|
||||
int i;
|
||||
@@ -15,6 +86,22 @@ static int jsB_print(js_State *J, int argc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jsB_eval(js_State *J, int argc)
|
||||
{
|
||||
const char *s;
|
||||
if (!js_isstring(J, -1))
|
||||
return 1;
|
||||
|
||||
// FIXME: need the real environment!
|
||||
s = js_tostring(J, -1);
|
||||
if (jsR_loadstring(J, "(eval)", s, J->GE))
|
||||
jsR_error(J, "SyntaxError (eval)");
|
||||
|
||||
js_pushglobal(J);
|
||||
js_call(J, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
js_State *js_newstate(void)
|
||||
{
|
||||
js_State *J = malloc(sizeof *J);
|
||||
@@ -23,6 +110,9 @@ js_State *js_newstate(void)
|
||||
J->G = jsR_newobject(J, JS_COBJECT);
|
||||
J->GE = jsR_newenvironment(J, J->G, NULL);
|
||||
|
||||
js_pushcfunction(J, jsB_eval);
|
||||
js_setglobal(J, "eval");
|
||||
|
||||
js_pushcfunction(J, jsB_print);
|
||||
js_setglobal(J, "print");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user