ref: 56042de82bbb4f4cee4fbb1e352a45d3acf134b2
parent: e01b4d02c0312f6ddc5b03adb78ed806d1eb22bb
author: Tor Andersson <tor@ccxvii.net>
date: Thu Jan 16 16:36:54 EST 2014
Fix the shape of the outer API a bit. Implement eval.
--- a/js.h
+++ b/js.h
@@ -41,8 +41,10 @@
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 */
--- a/jscompile.c
+++ b/jscompile.c
@@ -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 @@
longjmp(J->jb, 1);
}
-void jsC_freecompile(js_State *J)
+static void jsC_freecompile(js_State *J)
{
js_Function *F = J->fun;
while (F) {
--- a/jscompile.h
+++ b/jscompile.h
@@ -109,8 +109,6 @@
};
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);
--- a/jsload.c
+++ /dev/null
@@ -1,70 +1,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;
-}
--- a/jsrun.c
+++ b/jsrun.c
@@ -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 @@
++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 @@
++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 @@
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 @@
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 @@
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);
@@ -630,18 +654,4 @@
fprintf(stderr, "\n");
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);
}
--- a/jsrun.h
+++ b/jsrun.h
@@ -14,8 +14,13 @@
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);
--- a/jsstate.c
+++ b/jsstate.c
@@ -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 @@
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);
@@ -22,6 +109,9 @@
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");
--- a/main.c
+++ b/main.c
@@ -8,10 +8,8 @@
J = js_newstate();
- for (i = 1; i < argc; ++i) {
- js_loadfile(J, argv[i]);
- // js_run(J);
- }
+ for (i = 1; i < argc; ++i)
+ js_dofile(J, argv[i]);
js_close(J);