Split header into js.h public and jsi.h private. Start cleaning up

private function prefixes.
This commit is contained in:
Tor Andersson
2014-01-20 16:13:09 +01:00
parent 8aa0627557
commit 40a12fba0d
33 changed files with 437 additions and 416 deletions

137
js.h
View File

@@ -1,86 +1,93 @@
#ifndef js_h
#define js_h
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <setjmp.h>
#include <math.h>
#include <float.h>
/* 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

View File

@@ -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; }

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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; }

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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;

18
jsbuiltin.h Normal file
View File

@@ -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

View File

@@ -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 */

32
jsconf.h Normal file
View File

@@ -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

View File

@@ -1,4 +1,4 @@
#include "js.h"
#include "jsi.h"
#include "jsparse.h"
#include "jscompile.h"
#include "jsobject.h"

10
jsgc.c
View File

@@ -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);
}

135
jsi.h Normal file
View File

@@ -0,0 +1,135 @@
#ifndef jsi_h
#define jsi_h
#include "js.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <setjmp.h>
#include <math.h>
#include <float.h>
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

View File

@@ -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);

79
jslex.c
View File

@@ -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);
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -1,4 +1,4 @@
#include "js.h"
#include "jsi.h"
#include "jsparse.h"
static inline int i32(double d)

View File

@@ -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);

View File

@@ -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,

View File

@@ -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:

47
jsrun.c
View File

@@ -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);
}

77
jsrun.h
View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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 <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "js.h"
#include "jsutf.h"
#define uchar jsU_uchar

View File

@@ -1,4 +1,3 @@
#include "js.h"
#include "jsutf.h"
#define bsearch jsU_bsearch

View File

@@ -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);

2
main.c
View File

@@ -13,7 +13,7 @@ main(int argc, char **argv)
js_gc(J, 1);
}
js_close(J);
js_freestate(J);
return 0;
}