From 40a12fba0dd5bef0dfcdf3067ea021d3a221faf4 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 20 Jan 2014 16:13:09 +0100 Subject: [PATCH] Split header into js.h public and jsi.h private. Start cleaning up private function prefixes. --- js.h | 137 ++++++++++++++++++++++++++------------------------ jsbarray.c | 5 +- jsbboolean.c | 5 +- jsberror.c | 9 ++-- jsbfunction.c | 5 +- jsbmath.c | 5 +- jsbnumber.c | 5 +- jsbobject.c | 5 +- jsbstring.c | 5 +- jsbuiltin.c | 7 ++- jsbuiltin.h | 18 +++++++ jscompile.c | 3 +- jsconf.h | 32 ++++++++++++ jsdump.c | 2 +- jsgc.c | 10 ++-- jsi.h | 135 +++++++++++++++++++++++++++++++++++++++++++++++++ jsintern.c | 19 ++++--- jslex.c | 79 +++++++++++++++++------------ jslex.h | 9 ++-- jsobject.c | 3 +- jsobject.h | 18 +++---- jsoptim.c | 2 +- jsparse.c | 66 ++++++++++++------------ jsparse.h | 4 +- jsproperty.c | 3 +- jsrun.c | 47 +++++------------ jsrun.h | 77 +--------------------------- jsstate.c | 30 ++++++++--- jsstate.h | 91 --------------------------------- jsutf.c | 3 +- jsutftype.c | 1 - jsvalue.c | 11 ++-- main.c | 2 +- 33 files changed, 437 insertions(+), 416 deletions(-) create mode 100644 jsbuiltin.h create mode 100644 jsconf.h create mode 100644 jsi.h delete mode 100644 jsstate.h diff --git a/js.h b/js.h index 17b1d21..c5466ff 100644 --- a/js.h +++ b/js.h @@ -1,86 +1,93 @@ #ifndef js_h #define js_h -#include -#include -#include -#include -#include -#include -#include -#include - -/* noreturn is a GCC extension */ -#ifdef __GNUC__ -#define JS_NORETURN __attribute__((noreturn)) -#else -#ifdef _MSC_VER -#define JS_NORETURN __declspec(noreturn) -#else -#define JS_NORETURN -#endif -#endif - -/* GCC can do type checking of printf strings */ -#ifndef __printflike -#if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7 -#define __printflike(fmtarg, firstvararg) \ - __attribute__((__format__ (__printf__, fmtarg, firstvararg))) -#else -#define __printflike(fmtarg, firstvararg) -#endif -#endif +#include "jsconf.h" typedef struct js_State js_State; +typedef int (*js_CFunction)(js_State *J, int argc); -#define JS_REGEXP_G 1 -#define JS_REGEXP_I 2 -#define JS_REGEXP_M 4 +/* Basic functions */ js_State *js_newstate(void); -void js_close(js_State *J); +void js_freestate(js_State *J); -void js_loadstring(js_State *J, const char *source); -void 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); void js_gc(js_State *J, int report); -/* binding API: TODO: move from jsrun.h */ - -typedef int (*js_CFunction)(js_State *J, int argc); - -/* private */ - -typedef struct js_Ast js_Ast; -typedef struct js_Environment js_Environment; -typedef struct js_Function js_Function; -typedef struct js_Object js_Object; -typedef struct js_StringNode js_StringNode; - const char *js_intern(js_State *J, const char *s); -void js_printstrings(js_State *J); -void js_freestrings(js_State *J); -void jsB_initobject(js_State *J); -void jsB_initarray(js_State *J); -void jsB_initfunction(js_State *J); -void jsB_initboolean(js_State *J); -void jsB_initnumber(js_State *J); -void jsB_initstring(js_State *J); -void jsB_initerror(js_State *J); -void jsB_initmath(js_State *J); +/* Push a new Error object with the formatted message and throw it */ +JS_NORETURN void js_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); + +/* Property attribute flags */ +enum { + JS_READONLY = 1, + JS_DONTENUM = 2, + JS_DONTDELETE = 4, +}; JS_NORETURN void js_throw(js_State *J); -JS_NORETURN void js_error(js_State *J, const char *fmt, ...) __printflike(2,3); -JS_NORETURN void jsR_throwError(js_State *J, const char *message); -JS_NORETURN void jsR_throwEvalError(js_State *J, const char *message); -JS_NORETURN void jsR_throwRangeError(js_State *J, const char *message); -JS_NORETURN void jsR_throwReferenceError(js_State *J, const char *message); -JS_NORETURN void jsR_throwSyntaxError(js_State *J, const char *message); -JS_NORETURN void jsR_throwTypeError(js_State *J, const char *message); -JS_NORETURN void jsR_throwURIError(js_State *J, const char *message); +void js_loadstring(js_State *J, const char *filename, const char *source); +void js_loadfile(js_State *J, const char *filename); + +void js_call(js_State *J, int n); +void js_construct(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); +void js_cfgproperty(js_State *J, int idx, const char *name, int atts); +void js_delproperty(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); +void js_pushboolean(js_State *J, int v); +void js_pushnumber(js_State *J, double v); +void js_pushstring(js_State *J, const char *v); +void js_pushliteral(js_State *J, const char *v); + +void js_newobject(js_State *J); +void js_newarray(js_State *J); +void js_newcfunction(js_State *J, js_CFunction fun, int length); + +int js_isundefined(js_State *J, int idx); +int js_isnull(js_State *J, int idx); +int js_isboolean(js_State *J, int idx); +int js_isnumber(js_State *J, int idx); +int js_isstring(js_State *J, int idx); +int js_isprimitive(js_State *J, int idx); +int js_isobject(js_State *J, int idx); +int js_iscallable(js_State *J, int idx); + +int js_toboolean(js_State *J, int idx); +double js_tonumber(js_State *J, int idx); +const char *js_tostring(js_State *J, int idx); + +double js_tointeger(js_State *J, int idx); +int js_toint32(js_State *J, int idx); +unsigned int js_touint32(js_State *J, int idx); +short js_toint16(js_State *J, int idx); +unsigned short js_touint16(js_State *J, int idx); + +int js_gettop(js_State *J); +void js_settop(js_State *J, int idx); +void js_pop(js_State *J, int n); +void js_copy(js_State *J, int idx); +void js_remove(js_State *J, int idx); +void js_insert(js_State *J, int idx); +void js_replace(js_State* J, int idx); + +void js_concat(js_State *J); +int js_compare(js_State *J); +int js_equal(js_State *J); +int js_strictequal(js_State *J); #endif diff --git a/jsbarray.c b/jsbarray.c index 367ae8b..42f61a9 100644 --- a/jsbarray.c +++ b/jsbarray.c @@ -1,7 +1,6 @@ -#include "js.h" +#include "jsi.h" #include "jsobject.h" -#include "jsrun.h" -#include "jsstate.h" +#include "jsbuiltin.h" static int jsB_Array(js_State *J, int n) { return 0; } static int jsB_new_Array(js_State *J, int n) { return 0; } diff --git a/jsbboolean.c b/jsbboolean.c index 9dcad12..ce3edad 100644 --- a/jsbboolean.c +++ b/jsbboolean.c @@ -1,7 +1,6 @@ -#include "js.h" +#include "jsi.h" #include "jsobject.h" -#include "jsrun.h" -#include "jsstate.h" +#include "jsbuiltin.h" static int jsB_new_Boolean(js_State *J, int n) { diff --git a/jsberror.c b/jsberror.c index 95e5ef8..d1d99a7 100644 --- a/jsberror.c +++ b/jsberror.c @@ -1,15 +1,14 @@ -#include "js.h" +#include "jsi.h" #include "jsobject.h" -#include "jsrun.h" -#include "jsstate.h" +#include "jsbuiltin.h" static int Ep_toString(js_State *J, int n) { js_getproperty(J, 0, "name"); js_pushliteral(J, ": "); - jsR_concat(J); + js_concat(J); js_getproperty(J, 0, "message"); - jsR_concat(J); + js_concat(J); return 1; } diff --git a/jsbfunction.c b/jsbfunction.c index 081b327..db85a80 100644 --- a/jsbfunction.c +++ b/jsbfunction.c @@ -1,8 +1,7 @@ -#include "js.h" +#include "jsi.h" #include "jscompile.h" #include "jsobject.h" -#include "jsrun.h" -#include "jsstate.h" +#include "jsbuiltin.h" static int jsB_new_Function(js_State *J, int n) { return 0; } static int jsB_Function(js_State *J, int n) { return 0; } diff --git a/jsbmath.c b/jsbmath.c index cf566d1..4c71292 100644 --- a/jsbmath.c +++ b/jsbmath.c @@ -1,7 +1,6 @@ -#include "js.h" +#include "jsi.h" #include "jsobject.h" -#include "jsrun.h" -#include "jsstate.h" +#include "jsbuiltin.h" static int Math_abs(js_State *J, int nargs) { return js_pushnumber(J, abs(js_tonumber(J, 1))), 1; diff --git a/jsbnumber.c b/jsbnumber.c index 2e78d8b..7ad88d9 100644 --- a/jsbnumber.c +++ b/jsbnumber.c @@ -1,7 +1,6 @@ -#include "js.h" +#include "jsi.h" #include "jsobject.h" -#include "jsrun.h" -#include "jsstate.h" +#include "jsbuiltin.h" static int jsB_new_Number(js_State *J, int n) { diff --git a/jsbobject.c b/jsbobject.c index 23109b5..17ce18c 100644 --- a/jsbobject.c +++ b/jsbobject.c @@ -1,7 +1,6 @@ -#include "js.h" +#include "jsi.h" #include "jsobject.h" -#include "jsrun.h" -#include "jsstate.h" +#include "jsbuiltin.h" static int jsB_new_Object(js_State *J, int n) { diff --git a/jsbstring.c b/jsbstring.c index be26491..73c65e4 100644 --- a/jsbstring.c +++ b/jsbstring.c @@ -1,7 +1,6 @@ -#include "js.h" +#include "jsi.h" #include "jsobject.h" -#include "jsrun.h" -#include "jsstate.h" +#include "jsbuiltin.h" #include "jsutf.h" static int jsB_new_String(js_State *J, int n) diff --git a/jsbuiltin.c b/jsbuiltin.c index d13173b..3ebde53 100644 --- a/jsbuiltin.c +++ b/jsbuiltin.c @@ -1,7 +1,6 @@ -#include "js.h" +#include "jsi.h" #include "jsobject.h" -#include "jsrun.h" -#include "jsstate.h" +#include "jsbuiltin.h" static int jsB_print(js_State *J, int argc) { @@ -26,7 +25,7 @@ static int jsB_eval(js_State *J, int argc) { if (!js_isstring(J, -1)) return 1; - jsR_loadscript(J, "(eval)", js_tostring(J, -1)); + js_loadstring(J, "(eval)", js_tostring(J, -1)); js_copy(J, 0); js_call(J, 0); return 1; diff --git a/jsbuiltin.h b/jsbuiltin.h new file mode 100644 index 0000000..16ecabf --- /dev/null +++ b/jsbuiltin.h @@ -0,0 +1,18 @@ +#ifndef js_builtin_h +#define js_builtin_h + +void jsB_init(js_State *J); +void jsB_initobject(js_State *J); +void jsB_initarray(js_State *J); +void jsB_initfunction(js_State *J); +void jsB_initboolean(js_State *J); +void jsB_initnumber(js_State *J); +void jsB_initstring(js_State *J); +void jsB_initerror(js_State *J); +void jsB_initmath(js_State *J); + +void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n); +void jsB_propn(js_State *J, const char *name, double number); +void jsB_props(js_State *J, const char *name, const char *string); + +#endif diff --git a/jscompile.c b/jscompile.c index 3106277..a74f076 100644 --- a/jscompile.c +++ b/jscompile.c @@ -1,7 +1,6 @@ -#include "js.h" +#include "jsi.h" #include "jsparse.h" #include "jscompile.h" -#include "jsstate.h" #define cexp js_cexp /* collision with math.h */ diff --git a/jsconf.h b/jsconf.h new file mode 100644 index 0000000..89c17c6 --- /dev/null +++ b/jsconf.h @@ -0,0 +1,32 @@ +#ifndef js_conf_h +#define js_conf_h + +#define JS_STACKSIZE 256 /* value stack size */ +#define JS_MINSTACK 20 /* at least this much available when entering a function */ +#define JS_TRYLIMIT 64 /* exception stack size */ +#define JS_GCLIMIT 10000 /* run gc cycle every N allocations */ + +/* noreturn is a GCC extension */ +#ifdef __GNUC__ +#define JS_NORETURN __attribute__((noreturn)) +#else +#ifdef _MSC_VER +#define JS_NORETURN __declspec(noreturn) +#else +#define JS_NORETURN +#endif +#endif + +/* GCC can do type checking of printf strings */ +#ifdef __printflike +#define JS_PRINTFLIKE __printflike +#else +#if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7 +#define JS_PRINTFLIKE(fmtarg, firstvararg) \ + __attribute__((__format__ (__printf__, fmtarg, firstvararg))) +#else +#define JS_PRINTFLIKE(fmtarg, firstvararg) +#endif +#endif + +#endif diff --git a/jsdump.c b/jsdump.c index 0a33195..f3c68bc 100644 --- a/jsdump.c +++ b/jsdump.c @@ -1,4 +1,4 @@ -#include "js.h" +#include "jsi.h" #include "jsparse.h" #include "jscompile.h" #include "jsobject.h" diff --git a/jsgc.c b/jsgc.c index 23f8a02..4ba1669 100644 --- a/jsgc.c +++ b/jsgc.c @@ -1,8 +1,7 @@ -#include "js.h" +#include "jsi.h" #include "jscompile.h" #include "jsobject.h" #include "jsrun.h" -#include "jsstate.h" static void jsG_markobject(js_State *J, int mark, js_Object *obj); @@ -147,7 +146,7 @@ void js_gc(js_State *J, int report) genv, nenv, gfun, nfun, gobj, nobj); } -void js_close(js_State *J) +void js_freestate(js_State *J) { js_Function *fun, *nextfun; js_Object *obj, *nextobj; @@ -160,8 +159,9 @@ void js_close(js_State *J) for (obj = J->gcobj; obj; obj = nextobj) nextobj = obj->gcnext, jsG_freeobject(J, obj); - js_freestrings(J); + jsS_freestrings(J); - free(J->buf.text); + free(J->lexbuf.text); + free(J->stack); free(J); } diff --git a/jsi.h b/jsi.h new file mode 100644 index 0000000..c68cf69 --- /dev/null +++ b/jsi.h @@ -0,0 +1,135 @@ +#ifndef jsi_h +#define jsi_h + +#include "js.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +enum { JS_REGEXP_G = 1, JS_REGEXP_I = 2, JS_REGEXP_M = 4 }; /* RegExp flags */ + +enum { JS_HNONE, JS_HNUMBER, JS_HSTRING }; /* Hint to ToPrimitive() */ + +typedef struct js_Value js_Value; +typedef struct js_Object js_Object; + +typedef struct js_Ast js_Ast; +typedef struct js_Function js_Function; +typedef struct js_Environment js_Environment; + +typedef struct js_StringNode js_StringNode; +void jsS_dumpstrings(js_State *J); +void jsS_freestrings(js_State *J); + +JS_NORETURN void jsR_throwError(js_State *J, const char *message); +JS_NORETURN void jsR_throwEvalError(js_State *J, const char *message); +JS_NORETURN void jsR_throwRangeError(js_State *J, const char *message); +JS_NORETURN void jsR_throwReferenceError(js_State *J, const char *message); +JS_NORETURN void jsR_throwSyntaxError(js_State *J, const char *message); +JS_NORETURN void jsR_throwTypeError(js_State *J, const char *message); +JS_NORETURN void jsR_throwURIError(js_State *J, const char *message); + +js_Object *jsR_newcconstructor(js_State *J, js_CFunction cfunction, js_CFunction cconstructor); + +const char *jsR_stringfromnumber(js_State *J, double number); +double jsR_numberfromstring(js_State *J, const char *string); + +void js_newfunction(js_State *J, js_Function *function, js_Environment *scope); +void js_newscript(js_State *J, js_Function *function); +void js_dup(js_State *J); +void js_rot(js_State *J, int n); +void js_rot2(js_State *J); +void js_rot3(js_State *J); + +/* Exception handling */ + +typedef struct js_Jumpbuf js_Jumpbuf; + +struct js_Jumpbuf +{ + jmp_buf buf; + js_Environment *E; + int top, bot; + short *pc; +}; + +void js_savetry(js_State *J, short *pc); + +#define js_trypc(J, PC) \ + (js_savetry(J, PC), setjmp(J->trybuf[J->trylen++].buf)) + +#define js_try(J) \ + (js_savetry(J, NULL), setjmp(J->trybuf[J->trylen++].buf)) + +#define js_endtry(J) \ + (--J->trylen) + +/* State struct */ + +struct js_State +{ + js_StringNode *strings; + + /* parser input source */ + const char *filename; + const char *source; + int line; + + /* lexer state */ + struct { char *text; size_t len, cap; } lexbuf; + int lexline; + int lexchar; + int lasttoken; + int newline; + + /* parser state */ + int lookahead; + const char *text; + double number; + js_Ast *gcast; /* list of allocated nodes to free after parsing */ + + /* compiler state */ + int strict; + + /* runtime environment */ + js_Object *Object_prototype; + js_Object *Array_prototype; + js_Object *Function_prototype; + js_Object *Boolean_prototype; + js_Object *Number_prototype; + js_Object *String_prototype; + + js_Object *Error_prototype; + js_Object *EvalError_prototype; + js_Object *RangeError_prototype; + js_Object *ReferenceError_prototype; + js_Object *SyntaxError_prototype; + js_Object *TypeError_prototype; + js_Object *URIError_prototype; + + js_Object *G; + js_Environment *E; + + /* execution stack */ + int top, bot; + js_Value *stack; + + /* garbage collector list */ + int gcmark; + int gccounter; + js_Environment *gcenv; + js_Function *gcfun; + js_Object *gcobj; + + /* exception stack */ + int trylen; + js_Jumpbuf trybuf[JS_TRYLIMIT]; +}; + +#endif diff --git a/jsintern.c b/jsintern.c index 547c897..e0a12f0 100644 --- a/jsintern.c +++ b/jsintern.c @@ -1,5 +1,4 @@ -#include "js.h" -#include "jsstate.h" +#include "jsi.h" /* Use an AA-tree to quickly look up interned strings. */ @@ -66,26 +65,26 @@ static js_StringNode *insert(js_StringNode *node, const char *string, const char return newstringnode(string, result); } -static void printstringnode(js_StringNode *node, int level) +static void dumpstringnode(js_StringNode *node, int level) { int i; if (node->left != &sentinel) - printstringnode(node->left, level + 1); + dumpstringnode(node->left, level + 1); printf("%d: ", node->level); for (i = 0; i < level; ++i) putchar('\t'); printf("'%s'\n", node->string); if (node->right != &sentinel) - printstringnode(node->right, level + 1); + dumpstringnode(node->right, level + 1); } -void js_printstrings(js_State *J) +void jsS_dumpstrings(js_State *J) { js_StringNode *root = J->strings; - printf("--- string dump ---\n"); + printf("interned strings {\n"); if (root && root != &sentinel) - printstringnode(root, 0); - printf("---\n"); + dumpstringnode(root, 1); + printf("}\n"); } static void js_freestringnode(js_State *J, js_StringNode *node) @@ -95,7 +94,7 @@ static void js_freestringnode(js_State *J, js_StringNode *node) free(node); } -void js_freestrings(js_State *J) +void jsS_freestrings(js_State *J) { if (J->strings && J->strings != &sentinel) js_freestringnode(J, J->strings); diff --git a/jslex.c b/jslex.c index ca97fa1..daa0579 100644 --- a/jslex.c +++ b/jslex.c @@ -1,10 +1,27 @@ -#include "js.h" +#include "jsi.h" #include "jslex.h" -#include "jsstate.h" #include "jsutf.h" #define nelem(a) (sizeof (a) / sizeof (a)[0]) +JS_NORETURN static int jsY_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); + +static int jsY_error(js_State *J, const char *fmt, ...) +{ + va_list ap; + char buf[512]; + char msgbuf[256]; + + va_start(ap, fmt); + vsnprintf(msgbuf, 256, fmt, ap); + va_end(ap); + + snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline); + strcat(buf, msgbuf); + + jsR_throwSyntaxError(J, buf); +} + static const char *tokenstring[] = { "(end-of-file)", "'\\x01'", "'\\x02'", "'\\x03'", "'\\x04'", "'\\x05'", "'\\x06'", "'\\x07'", @@ -48,7 +65,7 @@ static const char *tokenstring[] = { "'void'", "'while'", "'with'", }; -const char *jsP_tokenstring(int token) +const char *jsY_tokenstring(int token) { if (token >= 0 && token < nelem(tokenstring)) if (tokenstring[token]) @@ -135,7 +152,7 @@ static inline int tohex(int c) #define PEEK (J->lexchar) #define NEXT() next(J) #define ACCEPT(x) (PEEK == x ? (NEXT(), 1) : 0) -#define EXPECT(x) (ACCEPT(x) || (jsP_error(J, "expected '%c'", x), 0)) +#define EXPECT(x) (ACCEPT(x) || (jsY_error(J, "expected '%c'", x), 0)) static void next(js_State *J) { @@ -164,33 +181,33 @@ static void unescape(js_State *J) return; } error: - jsP_error(J, "unexpected escape sequence"); + jsY_error(J, "unexpected escape sequence"); } } static void textinit(js_State *J) { - if (!J->buf.text) { - J->buf.cap = 4096; - J->buf.text = malloc(J->buf.cap); + if (!J->lexbuf.text) { + J->lexbuf.cap = 4096; + J->lexbuf.text = malloc(J->lexbuf.cap); } - J->buf.len = 0; + J->lexbuf.len = 0; } static inline void textpush(js_State *J, Rune c) { int n = runelen(c); - if (J->buf.len + n > J->buf.cap) { - J->buf.cap = J->buf.cap * 2; - J->buf.text = realloc(J->buf.text, J->buf.cap); + if (J->lexbuf.len + n > J->lexbuf.cap) { + J->lexbuf.cap = J->lexbuf.cap * 2; + J->lexbuf.text = realloc(J->lexbuf.text, J->lexbuf.cap); } - J->buf.len += runetochar(J->buf.text + J->buf.len, &c); + J->lexbuf.len += runetochar(J->lexbuf.text + J->lexbuf.len, &c); } static inline char *textend(js_State *J) { textpush(J, 0); - return J->buf.text; + return J->lexbuf.text; } static inline void lexlinecomment(js_State *J) @@ -218,7 +235,7 @@ static inline double lexhex(js_State *J) { double n = 0; if (!ishex(PEEK)) - return jsP_error(J, "malformed hexadecimal number"); + return jsY_error(J, "malformed hexadecimal number"); while (ishex(PEEK)) { n = n * 16 + tohex(PEEK); NEXT(); @@ -230,7 +247,7 @@ static inline double lexinteger(js_State *J) { double n = 0; if (!isdec(PEEK)) - return jsP_error(J, "malformed number"); + return jsY_error(J, "malformed number"); while (isdec(PEEK)) { n = n * 10 + (PEEK - '0'); NEXT(); @@ -272,7 +289,7 @@ static inline int lexnumber(js_State *J) return TK_NUMBER; } if (isdec(PEEK)) - return jsP_error(J, "number with leading zero"); + return jsY_error(J, "number with leading zero"); n = 0; if (ACCEPT('.')) n += lexfraction(J); @@ -290,7 +307,7 @@ static inline int lexnumber(js_State *J) } if (isidentifierstart(PEEK)) - return jsP_error(J, "number with letter suffix"); + return jsY_error(J, "number with letter suffix"); J->number = n; return TK_NUMBER; @@ -346,10 +363,10 @@ static inline int lexstring(js_State *J) while (PEEK != q) { if (PEEK == 0 || PEEK == '\n') - return jsP_error(J, "string not terminated"); + return jsY_error(J, "string not terminated"); if (ACCEPT('\\')) { if (lexescape(J)) - return jsP_error(J, "malformed escape sequence"); + return jsY_error(J, "malformed escape sequence"); } else { textpush(J, PEEK); NEXT(); @@ -387,7 +404,6 @@ static int lexregexp(js_State *J) { const char *s; int g, m, i; - int c; /* already consumed initial '/' */ @@ -396,11 +412,11 @@ static int lexregexp(js_State *J) /* regexp body */ while (PEEK != '/') { if (PEEK == 0 || PEEK == '\n') { - return jsP_error(J, "regular expression not terminated"); + return jsY_error(J, "regular expression not terminated"); } else if (ACCEPT('\\')) { textpush(J, '\\'); if (PEEK == 0 || PEEK == '\n') - return jsP_error(J, "regular expression not terminated"); + return jsY_error(J, "regular expression not terminated"); textpush(J, PEEK); NEXT(); } else { @@ -415,16 +431,15 @@ static int lexregexp(js_State *J) /* regexp flags */ g = i = m = 0; - c = PEEK; while (isidentifierpart(PEEK)) { if (ACCEPT('g')) ++g; else if (ACCEPT('i')) ++i; else if (ACCEPT('m')) ++m; - else return jsP_error(J, "illegal flag in regular expression: %c", PEEK); + else return jsY_error(J, "illegal flag in regular expression: %c", PEEK); } if (g > 1 || i > 1 || m > 1) - return jsP_error(J, "duplicated flag in regular expression"); + return jsY_error(J, "duplicated flag in regular expression"); J->text = js_intern(J, s); J->number = 0; @@ -471,7 +486,7 @@ static int lex(js_State *J) continue; } else if (ACCEPT('*')) { if (lexcomment(J)) - return jsP_error(J, "multi-line comment not terminated"); + return jsY_error(J, "multi-line comment not terminated"); continue; } else if (isregexpcontext(J->lasttoken)) { return lexregexp(J); @@ -621,16 +636,16 @@ static int lex(js_State *J) textend(J); - return findkeyword(J, J->buf.text); + return findkeyword(J, J->lexbuf.text); } if (PEEK >= 0x20 && PEEK <= 0x7E) - return jsP_error(J, "unexpected character: '%c'", PEEK); - return jsP_error(J, "unexpected character: \\u%04X", PEEK); + return jsY_error(J, "unexpected character: '%c'", PEEK); + return jsY_error(J, "unexpected character: \\u%04X", PEEK); } } -void jsP_initlex(js_State *J, const char *filename, const char *source) +void jsY_initlex(js_State *J, const char *filename, const char *source) { J->filename = filename; J->source = source; @@ -639,7 +654,7 @@ void jsP_initlex(js_State *J, const char *filename, const char *source) next(J); /* load first lookahead character */ } -int jsP_lex(js_State *J) +int jsY_lex(js_State *J) { return J->lasttoken = lex(J); } diff --git a/jslex.h b/jslex.h index 4d2da30..95538b9 100644 --- a/jslex.h +++ b/jslex.h @@ -66,12 +66,9 @@ enum TK_WITH, }; -const char *jsP_tokenstring(int token); +const char *jsY_tokenstring(int token); -void jsP_initlex(js_State *J, const char *filename, const char *source); -int jsP_lex(js_State *J); - -JS_NORETURN int jsP_error(js_State *J, const char *fmt, ...); -void jsP_warning(js_State *J, const char *fmt, ...); +void jsY_initlex(js_State *J, const char *filename, const char *source); +int jsY_lex(js_State *J); #endif diff --git a/jsobject.c b/jsobject.c index 7081a62..77f8c13 100644 --- a/jsobject.c +++ b/jsobject.c @@ -1,8 +1,7 @@ -#include "js.h" +#include "jsi.h" #include "jscompile.h" #include "jsobject.h" #include "jsrun.h" -#include "jsstate.h" #include "jsutf.h" static js_Object *jsR_newfunction(js_State *J, js_Function *function, js_Environment *scope) diff --git a/jsobject.h b/jsobject.h index b62368f..f42b07a 100644 --- a/jsobject.h +++ b/jsobject.h @@ -2,9 +2,8 @@ #define js_object_h typedef enum js_Type js_Type; -typedef struct js_Value js_Value; - typedef enum js_Class js_Class; + typedef struct js_Property js_Property; enum js_Type { @@ -31,12 +30,6 @@ enum js_Class { JS_CMATH, }; -enum { - JS_HNONE, - JS_HNUMBER, - JS_HSTRING, -}; - struct js_Value { js_Type type; @@ -79,6 +72,13 @@ struct js_Property js_Value value; }; +js_Value js_tovalue(js_State *J, int idx); +js_Value js_toprimitive(js_State *J, int idx, int hint); +js_Object *js_toobject(js_State *J, int idx); + +void js_pushvalue(js_State *J, js_Value v); +void js_pushobject(js_State *J, js_Object *v); + /* jsvalue.c */ int jsR_toboolean(js_State *J, const js_Value *v); double jsR_tonumber(js_State *J, const js_Value *v); @@ -105,6 +105,4 @@ js_Object *js_toobject(js_State *J, int idx); void js_dumpobject(js_State *J, js_Object *obj); void js_dumpvalue(js_State *J, js_Value v); -JS_NORETURN void jsR_error(js_State *J, const char *fmt, ...); - #endif diff --git a/jsoptim.c b/jsoptim.c index fd8a648..06f0819 100644 --- a/jsoptim.c +++ b/jsoptim.c @@ -1,4 +1,4 @@ -#include "js.h" +#include "jsi.h" #include "jsparse.h" static inline int i32(double d) diff --git a/jsparse.c b/jsparse.c index 7ea621d..4f3e59b 100644 --- a/jsparse.c +++ b/jsparse.c @@ -1,7 +1,6 @@ -#include "js.h" +#include "jsi.h" #include "jslex.h" #include "jsparse.h" -#include "jsstate.h" #define nelem(a) (sizeof (a) / sizeof (a)[0]) @@ -18,7 +17,7 @@ #define STM3(x,a,b,c) jsP_newnode(J, STM_ ## x, a, b, c, 0) #define STM4(x,a,b,c,d) jsP_newnode(J, STM_ ## x, a, b, c, d) -#define TOKSTR jsP_tokenstring(J->lookahead) +#define TOKSTR jsY_tokenstring(J->lookahead) static js_Ast *expression(js_State *J, int notin); static js_Ast *assignment(js_State *J, int notin); @@ -26,6 +25,34 @@ static js_Ast *memberexp(js_State *J); static js_Ast *statement(js_State *J); static js_Ast *funbody(js_State *J); +JS_NORETURN static void jsP_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); + +static void jsP_error(js_State *J, const char *fmt, ...) +{ + va_list ap; + char buf[512]; + char msgbuf[256]; + + va_start(ap, fmt); + vsnprintf(msgbuf, 256, fmt, ap); + va_end(ap); + + snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline); + strcat(buf, msgbuf); + + jsR_throwSyntaxError(J, buf); +} + +static void jsP_warning(js_State *J, const char *fmt, ...) +{ + va_list ap; + fprintf(stderr, "%s:%d: warning: ", J->filename, J->lexline); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + js_Ast *jsP_newnode(js_State *J, int type, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d) { js_Ast *node = malloc(sizeof(js_Ast)); @@ -74,7 +101,7 @@ void jsP_freeparse(js_State *J) static inline void next(js_State *J) { - J->lookahead = jsP_lex(J); + J->lookahead = jsY_lex(J); } static inline int accept(js_State *J, int t) @@ -90,7 +117,7 @@ static inline void expect(js_State *J, int t) { if (accept(J, t)) return; - jsP_error(J, "unexpected token: %s (expected %s)", TOKSTR, jsP_tokenstring(t)); + jsP_error(J, "unexpected token: %s (expected %s)", TOKSTR, jsY_tokenstring(t)); } static void semicolon(js_State *J) @@ -838,38 +865,11 @@ static js_Ast *funbody(js_State *J) return a; } -void jsP_warning(js_State *J, const char *fmt, ...) -{ - va_list ap; - - fprintf(stderr, "%s:%d: warning: ", J->filename, J->lexline); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, "\n"); -} - -int jsP_error(js_State *J, const char *fmt, ...) -{ - va_list ap; - char buf[512]; - char msgbuf[256]; - - va_start(ap, fmt); - vsnprintf(msgbuf, 256, fmt, ap); - va_end(ap); - - snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline); - strcat(buf, msgbuf); - - jsR_throwSyntaxError(J, buf); -} - js_Ast *jsP_parse(js_State *J, const char *filename, const char *source) { js_Ast *p, *last; - jsP_initlex(J, filename, source); + jsY_initlex(J, filename, source); next(J); p = script(J); diff --git a/jsparse.h b/jsparse.h index 55ca56c..58c7c22 100644 --- a/jsparse.h +++ b/jsparse.h @@ -1,7 +1,9 @@ #ifndef js_parse_h #define js_parse_h -enum +typedef enum js_AstType js_AstType; + +enum js_AstType { AST_LIST, AST_FUNDEC, diff --git a/jsproperty.c b/jsproperty.c index 6b761db..5077097 100644 --- a/jsproperty.c +++ b/jsproperty.c @@ -1,6 +1,5 @@ -#include "js.h" +#include "jsi.h" #include "jsobject.h" -#include "jsstate.h" /* Use an AA-tree to quickly look up properties in objects: diff --git a/jsrun.c b/jsrun.c index d0bec3c..309af22 100644 --- a/jsrun.c +++ b/jsrun.c @@ -1,9 +1,7 @@ -#include "js.h" -#include "jsobject.h" -#include "jsparse.h" +#include "jsi.h" #include "jscompile.h" +#include "jsobject.h" #include "jsrun.h" -#include "jsstate.h" static void jsR_run(js_State *J, js_Function *F); @@ -42,7 +40,7 @@ static inline unsigned int touint32(double n) #define TOP (J->top) #define BOT (J->bot) -static void js_pushvalue(js_State *J, js_Value v) +void js_pushvalue(js_State *J, js_Value v) { STACK[TOP] = v; ++TOP; @@ -127,7 +125,7 @@ int js_iscallable(js_State *J, int idx) return 0; } -const char *js_typeof(js_State *J, int idx) +static const char *js_typeof(js_State *J, int idx) { switch (stackidx(J, idx)->type) { case JS_TUNDEFINED: return "undefined"; @@ -708,7 +706,7 @@ static void jsR_run(js_State *J, js_Function *F) /* Additive operators */ case OP_ADD: - jsR_concat(J); + js_concat(J); break; case OP_SUB: @@ -743,19 +741,19 @@ static void jsR_run(js_State *J, js_Function *F) /* Relational operators */ - case OP_LT: b = jsR_compare(J); js_pushboolean(J, b < 0); break; - case OP_GT: b = jsR_compare(J); js_pushboolean(J, b > 0); break; - case OP_LE: b = jsR_compare(J); js_pushboolean(J, b <= 0); break; - case OP_GE: b = jsR_compare(J); js_pushboolean(J, b >= 0); break; + case OP_LT: b = js_compare(J); js_pushboolean(J, b < 0); break; + case OP_GT: b = js_compare(J); js_pushboolean(J, b > 0); break; + case OP_LE: b = js_compare(J); js_pushboolean(J, b <= 0); break; + case OP_GE: b = js_compare(J); js_pushboolean(J, b >= 0); break; // OP_INSTANCEOF /* Equality */ - case OP_EQ: b = jsR_equal(J); js_pushboolean(J, b); break; - case OP_NE: b = jsR_equal(J); js_pushboolean(J, !b); break; - case OP_STRICTEQ: b = jsR_strictequal(J); js_pushboolean(J, b); break; - case OP_STRICTNE: b = jsR_strictequal(J); js_pushboolean(J, !b); break; + case OP_EQ: b = js_equal(J); js_pushboolean(J, b); break; + case OP_NE: b = js_equal(J); js_pushboolean(J, !b); break; + case OP_STRICTEQ: b = js_strictequal(J); js_pushboolean(J, b); break; + case OP_STRICTNE: b = js_strictequal(J); js_pushboolean(J, !b); break; /* Binary bitwise operators */ @@ -814,22 +812,3 @@ static void jsR_run(js_State *J, js_Function *F) } } } - -void jsR_loadscript(js_State *J, const char *filename, const char *source) -{ - js_Ast *P; - js_Function *F; - - if (js_try(J)) { - jsP_freeparse(J); - js_throw(J); - } - - P = jsP_parse(J, filename, source); - jsP_optimize(J, P); - F = jsC_compile(J, P); - jsP_freeparse(J); - js_newscript(J, F); - - js_endtry(J); -} diff --git a/jsrun.h b/jsrun.h index 291e13d..e1e04a7 100644 --- a/jsrun.h +++ b/jsrun.h @@ -1,6 +1,8 @@ #ifndef js_run_h #define js_run_h +js_Environment *jsR_newenvironment(js_State *J, js_Object *variables, js_Environment *outer); + struct js_Environment { js_Environment *outer; @@ -10,79 +12,4 @@ struct js_Environment int gcmark; }; -/* private */ -void jsB_init(js_State *J); -void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n); -void jsB_propn(js_State *J, const char *name, double number); -void jsB_props(js_State *J, const char *name, const char *string); - -js_Environment *jsR_newenvironment(js_State *J, js_Object *variables, js_Environment *outer); -js_Object *jsR_newcconstructor(js_State *J, js_CFunction cfunction, js_CFunction cconstructor); -void jsR_loadscript(js_State *J, const char *filename, const char *source); -void jsR_error(js_State *J, const char *fmt, ...); -void js_pushobject(js_State *J, js_Object *v); -js_Object *js_toobject(js_State *J, int idx); -js_Value js_toprimitive(js_State *J, int idx, int hint); -js_Value js_tovalue(js_State *J, int idx); -void jsR_concat(js_State *J); -int jsR_compare(js_State *J); -int jsR_equal(js_State *J); -int jsR_strictequal(js_State *J); - -const char *jsR_stringfromnumber(js_State *J, double number); -double jsR_numberfromstring(js_State *J, const char *string); - -/* public */ - -void js_call(js_State *J, int n); -void js_construct(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); -void js_pushboolean(js_State *J, int v); -void js_pushnumber(js_State *J, double v); -void js_pushliteral(js_State *J, const char *v); -void js_pushstring(js_State *J, const char *v); - -void js_newobject(js_State *J); -void js_newarray(js_State *J); -void js_newfunction(js_State *J, js_Function *function, js_Environment *scope); -void js_newscript(js_State *J, js_Function *function); -void js_newcfunction(js_State *J, js_CFunction fun, int length); - -const char *js_typeof(js_State *J, int idx); -int js_isundefined(js_State *J, int idx); -int js_isnull(js_State *J, int idx); -int js_isboolean(js_State *J, int idx); -int js_isnumber(js_State *J, int idx); -int js_isstring(js_State *J, int idx); -int js_isprimitive(js_State *J, int idx); -int js_isobject(js_State *J, int idx); -int js_iscallable(js_State *J, int idx); - -int js_toboolean(js_State *J, int idx); -double js_tonumber(js_State *J, int idx); -const char *js_tostring(js_State *J, int idx); - -double js_tointeger(js_State *J, int idx); -int js_toint32(js_State *J, int idx); -unsigned int js_touint32(js_State *J, int idx); -short js_toint16(js_State *J, int idx); -unsigned short js_touint16(js_State *J, int idx); - -void js_pop(js_State *J, int n); -void js_dup(js_State *J); -void js_copy(js_State *J, int idx); -void js_rot(js_State *J, int n); -void js_rot2(js_State *J); -void js_rot3(js_State *J); - #endif diff --git a/jsstate.c b/jsstate.c index 012bf7d..9b0b061 100644 --- a/jsstate.c +++ b/jsstate.c @@ -1,11 +1,27 @@ -#include "js.h" +#include "jsi.h" +#include "jsparse.h" +#include "jscompile.h" #include "jsobject.h" #include "jsrun.h" -#include "jsstate.h" +#include "jsbuiltin.h" -void js_loadstring(js_State *J, const char *source) +void js_loadstring(js_State *J, const char *filename, const char *source) { - jsR_loadscript(J, "(string)", source); + js_Ast *P; + js_Function *F; + + if (js_try(J)) { + jsP_freeparse(J); + js_throw(J); + } + + P = jsP_parse(J, filename, source); + jsP_optimize(J, P); + F = jsC_compile(J, P); + jsP_freeparse(J); + js_newscript(J, F); + + js_endtry(J); } void js_loadfile(js_State *J, const char *filename) @@ -47,7 +63,7 @@ void js_loadfile(js_State *J, const char *filename) js_throw(J); } - jsR_loadscript(J, filename, s); + js_loadstring(J, filename, s); free(s); fclose(f); @@ -60,7 +76,7 @@ int js_dostring(js_State *J, const char *source) fprintf(stderr, "libjs: %s\n", js_tostring(J, -1)); return 1; } - js_loadstring(J, source); + js_loadstring(J, "(string)", source); js_pushglobal(J); js_call(J, 0); js_pop(J, 1); @@ -87,6 +103,8 @@ js_State *js_newstate(void) js_State *J = malloc(sizeof *J); memset(J, 0, sizeof(*J)); + J->stack = malloc(JS_STACKSIZE * sizeof *J->stack); + J->gcmark = 1; J->G = jsR_newobject(J, JS_COBJECT, NULL); diff --git a/jsstate.h b/jsstate.h deleted file mode 100644 index f9fe7d7..0000000 --- a/jsstate.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef js_state_h -#define js_state_h - -#include "jsobject.h" /* for js_Value */ - -#define JS_STACKSIZE 256 -#define JS_TRYLIMIT 64 -#define JS_GCLIMIT 10000 /* run gc cycle every N allocations */ - -void js_savetry(js_State *J, short *pc); - -#define js_trypc(J, PC) \ - (js_savetry(J, PC), setjmp(J->trybuf[J->trylen++].buf)) - -#define js_try(J) \ - (js_savetry(J, NULL), setjmp(J->trybuf[J->trylen++].buf)) - -#define js_endtry(J) \ - (--J->trylen) - -typedef struct js_Jumpbuf js_Jumpbuf; - -struct js_Jumpbuf -{ - jmp_buf buf; - js_Environment *E; - int top, bot; - short *pc; -}; - -struct js_State -{ - js_StringNode *strings; - - /* input */ - const char *filename; - const char *source; - int line; - - /* lexer */ - struct { char *text; size_t len, cap; } buf; - int lexline; - int lexchar; - int lasttoken; - int newline; - - /* parser */ - int lookahead; - const char *text; - double number; - js_Ast *gcast; /* list of allocated nodes to free after parsing */ - - /* compiler */ - int strict; - - /* runtime environment */ - js_Object *Object_prototype; - js_Object *Array_prototype; - js_Object *Function_prototype; - js_Object *Boolean_prototype; - js_Object *Number_prototype; - js_Object *String_prototype; - - js_Object *Error_prototype; - js_Object *EvalError_prototype; - js_Object *RangeError_prototype; - js_Object *ReferenceError_prototype; - js_Object *SyntaxError_prototype; - js_Object *TypeError_prototype; - js_Object *URIError_prototype; - - js_Object *G; - js_Environment *E; - - /* garbage collector list */ - int gcmark; - int gccounter; - js_Environment *gcenv; - js_Function *gcfun; - js_Object *gcobj; - - /* exception stack */ - int trylen; - js_Jumpbuf trybuf[JS_TRYLIMIT]; - - /* execution stack */ - int top, bot; - js_Value stack[JS_STACKSIZE]; -}; - -#endif diff --git a/jsutf.c b/jsutf.c index 156c61b..462f5f5 100644 --- a/jsutf.c +++ b/jsutf.c @@ -11,10 +11,9 @@ * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ -#include +#include #include -#include "js.h" #include "jsutf.h" #define uchar jsU_uchar diff --git a/jsutftype.c b/jsutftype.c index 39145a6..69b96b5 100644 --- a/jsutftype.c +++ b/jsutftype.c @@ -1,4 +1,3 @@ -#include "js.h" #include "jsutf.h" #define bsearch jsU_bsearch diff --git a/jsvalue.c b/jsvalue.c index de31dc9..efe3990 100644 --- a/jsvalue.c +++ b/jsvalue.c @@ -1,6 +1,5 @@ -#include "js.h" +#include "jsi.h" #include "jsobject.h" -#include "jsrun.h" const char *jsR_stringfromnumber(js_State *J, double n) { @@ -139,7 +138,7 @@ js_Object *jsR_toobject(js_State *J, const js_Value *v) jsR_throwTypeError(J, "cannot convert value to object"); } -void jsR_concat(js_State *J) +void js_concat(js_State *J) { js_Value va = js_toprimitive(J, -2, JS_HNONE); js_Value vb = js_toprimitive(J, -1, JS_HNONE); @@ -160,7 +159,7 @@ void jsR_concat(js_State *J) } } -int jsR_compare(js_State *J) +int js_compare(js_State *J) { js_Value va = js_toprimitive(J, -2, JS_HNUMBER); js_Value vb = js_toprimitive(J, -1, JS_HNUMBER); @@ -174,7 +173,7 @@ int jsR_compare(js_State *J) } } -int jsR_equal(js_State *J) +int js_equal(js_State *J) { js_Value va = js_tovalue(J, -2); js_Value vb = js_tovalue(J, -1); @@ -211,7 +210,7 @@ retry: return 0; } -int jsR_strictequal(js_State *J) +int js_strictequal(js_State *J) { js_Value va = js_tovalue(J, -2); js_Value vb = js_tovalue(J, -1); diff --git a/main.c b/main.c index cbbecf8..449d1c4 100644 --- a/main.c +++ b/main.c @@ -13,7 +13,7 @@ main(int argc, char **argv) js_gc(J, 1); } - js_close(J); + js_freestate(J); return 0; }