diff --git a/js.h b/js.h index 8b9757a..a28fe96 100644 --- a/js.h +++ b/js.h @@ -10,15 +10,21 @@ #include typedef struct js_State js_State; + typedef struct js_StringNode js_StringNode; typedef struct js_Ast js_Ast; +typedef enum js_ValueType js_ValueType; +typedef struct js_Value js_Value; +typedef struct js_RegExp js_RegExp; +typedef struct js_Object js_Object; +typedef struct js_Function js_Function; +typedef int (*js_CFunction)(js_State *J); + #define JS_REGEXP_G 1 #define JS_REGEXP_I 2 #define JS_REGEXP_M 4 -typedef int (*js_CFunction)(js_State *J); - js_State *js_newstate(void); void js_close(js_State *J); diff --git a/jscompile.c b/jscompile.c new file mode 100644 index 0000000..a444b9d --- /dev/null +++ b/jscompile.c @@ -0,0 +1,450 @@ +#include "js.h" +#include "jsparse.h" +#include "jscompile.h" +#include "jsrun.h" +#include "jsstate.h" + +#define cexp js_cexp /* collision with math.h */ + +#define JF js_State *J, js_Function *F + +static void cexp(JF, js_Ast *exp); +static void cstmlist(JF, js_Ast *list); + +static int consteq(js_Value a, js_Value b) +{ + if (a.type != b.type) + return 0; + if (a.type == JS_TNUMBER) + return a.u.number == b.u.number; + else + return a.u.p == b.u.p; +} + +static int addconst(JF, js_Value v) +{ + int i; + + for (i = 0; i < F->klen; i++) { + if (consteq(F->klist[i], v)) { + return i; + } + } + + if (F->klen >= F->kcap) { + F->kcap *= 2; + F->klist = realloc(F->klist, F->kcap * sizeof(js_Value)); + } + + F->klist[F->klen] = v; + return F->klen++; +} + +static void emit(JF, int value) +{ + if (F->len >= F->cap) { + F->cap *= 2; + F->code = realloc(F->code, F->cap); + } + + F->code[F->len++] = value; +} + +static void emitnumber(JF, int opcode, double n) +{ + js_Value v; + v.type = JS_TNUMBER; + v.u.number = n; + emit(J, F, opcode); + emit(J, F, addconst(J, F, v)); +} + +static void emitstring(JF, int opcode, const char *s) +{ + js_Value v; + v.type = JS_TSTRING; + v.u.string = s; + emit(J, F, opcode); + emit(J, F, addconst(J, F, v)); +} + +static void unary(JF, js_Ast *exp, int opcode) +{ + cexp(J, F, exp->a); + emit(J, F, opcode); +} + +static void binary(JF, js_Ast *exp, int opcode) +{ + cexp(J, F, exp->a); + cexp(J, F, exp->b); + emit(J, F, opcode); +} + +static void carray(JF, js_Ast *list) +{ + while (list) { + cexp(J, F, list->a); + emit(J, F, OP_ARRAYPUT); + list = list->b; + } +} + +static void cobject(JF, js_Ast *list) +{ + while (list) { + js_Ast *kv = list->a; + if (kv->type == EXP_PROP_VAL) { + js_Ast *prop = kv->a; + cexp(J, F, kv->b); + if (prop->type == AST_IDENTIFIER || prop->type == AST_STRING) + emitstring(J, F, OP_OBJECTPUT, prop->string); + else if (prop->type == AST_NUMBER) + emitnumber(J, F, OP_OBJECTPUT, prop->number); + else + jsC_error(J, list, "illegal property name in object initializer"); + } + // TODO: set, get + list = list->b; + } +} + +static int cargs(JF, js_Ast *list) +{ + int n = 0; + while (list) { + cexp(J, F, list->a); + list = list->b; + n++; + } + return n; +} + +static void clval(JF, js_Ast *exp) +{ + switch (exp->type) { + case AST_IDENTIFIER: + emitstring(J, F, OP_VAR, exp->string); + break; + case EXP_INDEX: + cexp(J, F, exp->a); + cexp(J, F, exp->b); + emit(J, F, OP_INDEX); + break; + case EXP_MEMBER: + cexp(J, F, exp->a); + emitstring(J, F, OP_MEMBER, exp->b->string); + break; + default: + jsC_error(J, exp, "invalid l-value in assignment"); + break; + } +} + +static void assignop(JF, js_Ast *exp, int opcode) +{ + clval(J, F, exp->a); + emit(J, F, OP_DUPLOAD); + cexp(J, F, exp->b); + emit(J, F, opcode); + emit(J, F, OP_STORE); +} + +static void cexp(JF, js_Ast *exp) +{ + int n; + + switch (exp->type) { + case AST_IDENTIFIER: + emitstring(J, F, OP_VAR, exp->string); + emit(J, F, OP_LOAD); + break; + + case AST_NUMBER: emitnumber(J, F, OP_CONST, exp->number); break; + case AST_STRING: emitstring(J, F, OP_CONST, exp->string); break; + case EXP_UNDEF: emit(J, F, OP_UNDEF); break; + case EXP_NULL: emit(J, F, OP_NULL); break; + case EXP_TRUE: emit(J, F, OP_TRUE); break; + case EXP_FALSE: emit(J, F, OP_FALSE); break; + case EXP_THIS: emit(J, F, OP_THIS); break; + + case EXP_OBJECT: + emit(J, F, OP_OBJECT); + cobject(J, F, exp->a); + break; + + case EXP_ARRAY: + emit(J, F, OP_ARRAY); + carray(J, F, exp->a); + break; + + case EXP_INDEX: + cexp(J, F, exp->a); + cexp(J, F, exp->b); + emit(J, F, OP_INDEX); + emit(J, F, OP_LOAD); + break; + + case EXP_MEMBER: + cexp(J, F, exp->a); + emitstring(J, F, OP_MEMBER, exp->b->string); + emit(J, F, OP_LOAD); + break; + + case EXP_CALL: + cexp(J, F, exp->a); + n = cargs(J, F, exp->b); + emit(J, F, OP_CALL); + emit(J, F, n); + break; + + case EXP_NEW: + cexp(J, F, exp->a); + n = cargs(J, F, exp->b); + emit(J, F, OP_NEW); + emit(J, F, n); + break; + + case EXP_VOID: + cexp(J, F, exp->a); + emit(J, F, OP_POP); + emit(J, F, OP_UNDEF); + break; + + case EXP_TYPEOF: unary(J, F, exp, OP_TYPEOF); break; + case EXP_POS: unary(J, F, exp, OP_POS); break; + case EXP_NEG: unary(J, F, exp, OP_NEG); break; + case EXP_BITNOT: unary(J, F, exp, OP_BITNOT); break; + case EXP_LOGNOT: unary(J, F, exp, OP_LOGNOT); break; + + case EXP_PREINC: clval(J, F, exp->a); emit(J, F, OP_PREINC); break; + case EXP_PREDEC: clval(J, F, exp->a); emit(J, F, OP_PREDEC); break; + case EXP_POSTINC: clval(J, F, exp->a); emit(J, F, OP_POSTINC); break; + case EXP_POSTDEC: clval(J, F, exp->a); emit(J, F, OP_POSTDEC); break; + + case EXP_LOGOR: binary(J, F, exp, OP_LOGOR); break; + case EXP_LOGAND: binary(J, F, exp, OP_LOGAND); break; + case EXP_BITOR: binary(J, F, exp, OP_BITOR); break; + case EXP_BITXOR: binary(J, F, exp, OP_BITXOR); break; + case EXP_BITAND: binary(J, F, exp, OP_BITAND); break; + case EXP_EQ: binary(J, F, exp, OP_EQ); break; + case EXP_NE: binary(J, F, exp, OP_NE); break; + case EXP_EQ3: binary(J, F, exp, OP_EQ3); break; + case EXP_NE3: binary(J, F, exp, OP_NE3); break; + case EXP_LT: binary(J, F, exp, OP_LT); break; + case EXP_GT: binary(J, F, exp, OP_GT); break; + case EXP_LE: binary(J, F, exp, OP_LE); break; + case EXP_GE: binary(J, F, exp, OP_GE); break; + case EXP_INSTANCEOF: binary(J, F, exp, OP_INSTANCEOF); break; + case EXP_IN: binary(J, F, exp, OP_IN); break; + case EXP_SHL: binary(J, F, exp, OP_SHL); break; + case EXP_SHR: binary(J, F, exp, OP_SHR); break; + case EXP_USHR: binary(J, F, exp, OP_USHR); break; + case EXP_ADD: binary(J, F, exp, OP_ADD); break; + case EXP_SUB: binary(J, F, exp, OP_SUB); break; + case EXP_MUL: binary(J, F, exp, OP_MUL); break; + case EXP_DIV: binary(J, F, exp, OP_DIV); break; + case EXP_MOD: binary(J, F, exp, OP_MOD); break; + + case EXP_ASS: + clval(J, F, exp->a); + cexp(J, F, exp->b); + emit(J, F, OP_STORE); + break; + + case EXP_ASS_MUL: assignop(J, F, exp, OP_MUL); break; + case EXP_ASS_DIV: assignop(J, F, exp, OP_DIV); break; + case EXP_ASS_MOD: assignop(J, F, exp, OP_MOD); break; + case EXP_ASS_ADD: assignop(J, F, exp, OP_ADD); break; + case EXP_ASS_SUB: assignop(J, F, exp, OP_SUB); break; + case EXP_ASS_SHL: assignop(J, F, exp, OP_SHL); break; + case EXP_ASS_SHR: assignop(J, F, exp, OP_SHR); break; + case EXP_ASS_USHR: assignop(J, F, exp, OP_USHR); break; + case EXP_ASS_BITAND: assignop(J, F, exp, OP_BITAND); break; + case EXP_ASS_BITXOR: assignop(J, F, exp, OP_BITXOR); break; + case EXP_ASS_BITOR: assignop(J, F, exp, OP_BITOR); break; + + case EXP_COMMA: + cexp(J, F, exp->a); + emit(J, F, OP_POP); + cexp(J, F, exp->b); + break; + + default: + jsC_error(J, exp, "unknown expression"); + } +} + +static void cvardec(JF, js_Ast *vardec) +{ + if (vardec->b) + cexp(J, F, vardec->b); + else + emit(J, F, OP_UNDEF); + emitstring(J, F, OP_DEFVAR, vardec->a->string); +} + +static void cvardeclist(JF, js_Ast *list) +{ + while (list) { + cvardec(J, F, list->a); + list = list->b; + } +} + +static int emitjump(JF, int opcode) +{ + int addr = F->len + 1; + emit(J, F, opcode); + emit(J, F, 0); + emit(J, F, 0); + return addr; +} + +static void emitlabel(JF, int addr) +{ + int dest = F->len; + F->code[addr+0] = (dest >> 8) & 0xFF; + F->code[addr+1] = (dest) & 0xFF; +} + +static void cstm(JF, js_Ast *stm) +{ + int lelse, lend; + + switch (stm->type) { + case STM_BLOCK: + cstmlist(J, F, stm->a); + break; + + case STM_NOP: + break; + + case STM_VAR: + cvardeclist(J, F, stm->a); + break; + + case STM_IF: + cexp(J, F, stm->a); + lelse = emitjump(J, F, OP_JFALSE); + cstm(J, F, stm->b); + emitlabel(J, F, lelse); + if (stm->c) { + lend = emitjump(J, F, OP_JUMP); + cstm(J, F, stm->c); + emitlabel(J, F, lend); + } + break; + + case STM_RETURN: + if (stm->a) + cexp(J, F, stm->a); + else + emit(J, F, OP_UNDEF); + emit(J, F, OP_RETURN); + break; + + case STM_WITH: + cexp(J, F, stm->a); + emit(J, F, OP_PUSHWITH); + cstm(J, F, stm->b); + emit(J, F, OP_POPWITH); + break; + + // switch + // throw, try + // label + + case STM_THROW: + cexp(J, F, stm->a); + emit(J, F, OP_THROW); + break; + + case STM_DEBUGGER: + emit(J, F, OP_DEBUGGER); + break; + + default: + cexp(J, F, stm); + emit(J, F, OP_POP); + break; + } +} + +static void cstmlist(JF, js_Ast *list) +{ + while (list) { + cstm(J, F, list->a); + list = list->b; + } +} + +static js_Function *newfun(js_State *J) +{ + js_Function *F = malloc(sizeof(js_Function)); + + F->cap = 256; + F->len = 0; + F->code = malloc(F->cap); + + F->kcap = 16; + F->klen = 0; + F->klist = malloc(F->kcap * sizeof(js_Value)); + + F->next = J->fun; + J->fun = F; + + return F; +} + +static void freefun(js_State *J, js_Function *F) +{ + free(F->klist); + free(F->code); + free(F); +} + +void jsC_freecompile(js_State *J) +{ + js_Function *F = J->fun; + while (F) { + js_Function *next = F->next; + freefun(J, F); + F = next; + } + J->fun = NULL; +} + +int jsC_error(js_State *J, js_Ast *node, const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: error: ", J->filename, node->line); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + + longjmp(J->jb, 1); + return 0; +} + +js_Function *jsC_compile(js_State *J, js_Ast *prog) +{ + js_Function *F; + + if (setjmp(J->jb)) { + jsC_freecompile(J); + return NULL; + } + + F = newfun(J); + cstmlist(J, F, prog); + + emit(J, F, OP_UNDEF); + emit(J, F, OP_RETURN); + + J->fun = NULL; + return F; +} + diff --git a/jscompile.h b/jscompile.h new file mode 100644 index 0000000..08a7bb3 --- /dev/null +++ b/jscompile.h @@ -0,0 +1,97 @@ +#ifndef js_compile_h +#define js_compile_h + +enum +{ + OP_CONST, + OP_UNDEF, + OP_NULL, + OP_TRUE, + OP_FALSE, + OP_THIS, + + OP_ARRAY, + OP_ARRAYPUT, + OP_OBJECT, + OP_OBJECTPUT, + + OP_DEFVAR, + OP_VAR, + OP_INDEX, + OP_MEMBER, + OP_LOAD, + OP_DUPLOAD, + OP_STORE, + + OP_CALL, + OP_NEW, + OP_CLOSURE, + + OP_DELETE, + OP_VOID, + OP_TYPEOF, + OP_PREINC, + OP_POSTINC, + OP_PREDEC, + OP_POSTDEC, + OP_POS, + OP_NEG, + OP_BITNOT, + OP_LOGNOT, + + OP_LOGOR, + OP_LOGAND, + OP_BITOR, + OP_BITXOR, + OP_BITAND, + OP_EQ, + OP_NE, + OP_EQ3, + OP_NE3, + OP_LT, + OP_GT, + OP_LE, + OP_GE, + OP_INSTANCEOF, + OP_IN, + OP_SHL, + OP_SHR, + OP_USHR, + OP_ADD, + OP_SUB, + OP_MUL, + OP_DIV, + OP_MOD, + + OP_JUMP, + OP_JTRUE, + OP_JFALSE, + + OP_TRY, + OP_THROW, + OP_RETURN, + OP_PUSHWITH, + OP_POPWITH, + OP_DEBUGGER, + + OP_POP, +}; + +struct js_Function +{ + unsigned char *code; + int cap, len; + + js_Value *klist; + int kcap, klen; + + js_Function *next; +}; + +js_Function *jsC_compile(js_State *J, js_Ast *prog); +void jsC_freecompile(js_State *J); +int jsC_error(js_State *J, js_Ast *node, const char *fmt, ...); +void jsC_dumpvalue(js_State *J, js_Value v); +void jsC_dumpfunction(js_State *J, js_Function *fun); + +#endif diff --git a/jsdump.c b/jsdump.c index abfa4c5..95df38b 100644 --- a/jsdump.c +++ b/jsdump.c @@ -1,9 +1,11 @@ #include "js.h" #include "jsparse.h" +#include "jscompile.h" +#include "jsrun.h" #include -static const char *stype[] = { +static const char *astname[] = { "list", "ident", "number", "string", "regexp", "undef", "null", "true", "false", "this", "array", "object", "prop_val", "prop_get", "prop_set", "index", "member", "call", "new", "funexp", "delete", "void", "typeof", @@ -15,8 +17,21 @@ static const char *stype[] = { "ass_ushr", "ass_bitand", "ass_bitxor", "ass_bitor", "comma", "var-init", "block", "fundec", "nop", "var", "if", "do-while", "while", "for", "for-var", "for-in", "for-in-var", "continue", "break", - "return", "with", "switch", "throw", "try", "label", "case", "default", - "debugger", + "return", "with", "switch", "throw", "try", "debugger", "label", + "case", "default", +}; + +static const char *opname[] = { + "const", "undef", "null", "true", "false", "this", + "array", "arrayput", + "object", "objectput", + "defvar", "var", "index", "member", "load", "dupload", "store", "call", "new", + "closure", "delete", "void", "typeof", "preinc", "postinc", "predec", + "postdec", "pos", "neg", "bitnot", "lognot", "logor", "logand", + "bitor", "bitxor", "bitand", "eq", "ne", "eq3", "ne3", "lt", "gt", + "le", "ge", "instanceof", "in", "shl", "shr", "ushr", "add", "sub", + "mul", "div", "mod", "jump", "jtrue", "jfalse", "try", "throw", + "return", "pushwith", "popwith", "debugger", "pop", }; static void pstmlist(int d, js_Ast *list); @@ -499,7 +514,7 @@ void jsP_dumpsyntax(js_State *J, js_Ast *prog) pstmlist(-1, prog); else { pstm(0, prog); - pc('\n'); + nl(); } } @@ -520,7 +535,7 @@ static void snode(int d, js_Ast *node) } pc('('); - ps(stype[node->type]); + ps(astname[node->type]); switch (node->type) { case AST_IDENTIFIER: pc(' '); ps(node->string); break; case AST_STRING: pc(' '); pstr(node->string); break; @@ -561,11 +576,11 @@ static void sblock(int d, js_Ast *list) snode(d+1, list->a); list = list->b; if (list) { - pc('\n'); + nl(); in(d+1); } } - pc('\n'); in(d); pc(']'); + nl(); in(d); pc(']'); } void jsP_dumplist(js_State *J, js_Ast *prog) @@ -574,5 +589,65 @@ void jsP_dumplist(js_State *J, js_Ast *prog) sblock(0, prog); else snode(0, prog); - pc('\n'); + nl(); +} + +void jsC_dumpvalue(js_State *J, js_Value v) +{ + switch (v.type) { + case JS_TUNDEFINED: ps("undefined"); break; + case JS_TNULL: ps("null"); break; + case JS_TBOOLEAN: ps(v.u.boolean ? "true" : "false"); break; + case JS_TNUMBER: printf("%.9g", v.u.number); break; + case JS_TSTRING: pstr(v.u.string); break; + case JS_TREGEXP: printf("", v.u.p); break; + case JS_TOBJECT: printf("", v.u.p); break; + + case JS_TFUNCTION: printf("", v.u.p); break; + case JS_TCFUNCTION: printf("", v.u.p); break; + case JS_TCLOSURE: printf("", v.u.p); break; + case JS_TARGUMENTS: printf("", v.u.p); break; + + case JS_TOBJSLOT: printf("", v.u.p); break; + } +} + +void jsC_dumpfunction(js_State *J, js_Function *fun) +{ + unsigned char *p = fun->code; + unsigned char *end = fun->code + fun->len; + int dest; + + printf("function with %d constants\n", fun->klen); + + while (p < end) { + int c = *p++; + + printf("%04d: ", (int)(p - fun->code) - 1); + ps(opname[c]); + + switch (c) { + case OP_CONST: + case OP_OBJECTPUT: + case OP_DEFVAR: + case OP_VAR: + case OP_MEMBER: + pc(' '); + jsC_dumpvalue(J, fun->klist[*p++]); + break; + case OP_CALL: + case OP_NEW: + printf(" %d", *p++); + break; + case OP_JUMP: + case OP_JTRUE: + case OP_JFALSE: + dest = (*p++) << 8; + dest += (*p++); + printf(" %d", dest); + break; + } + + nl(); + } } diff --git a/jsload.c b/jsload.c index 3752f45..2e5702a 100644 --- a/jsload.c +++ b/jsload.c @@ -1,13 +1,22 @@ #include "js.h" #include "jsparse.h" +#include "jscompile.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) { - jsP_optimize(J, prog); -// jsP_dumpsyntax(J, 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; } diff --git a/jsparse.h b/jsparse.h index ecbf463..44c5d86 100644 --- a/jsparse.h +++ b/jsparse.h @@ -114,10 +114,11 @@ enum STM_SWITCH, STM_THROW, STM_TRY, + STM_DEBUGGER, + STM_LABEL, STM_CASE, STM_DEFAULT, - STM_DEBUGGER, }; js_Ast *jsP_parse(js_State *J, const char *filename, const char *source); diff --git a/jsrun.c b/jsrun.c new file mode 100644 index 0000000..0852824 --- /dev/null +++ b/jsrun.c @@ -0,0 +1,149 @@ +#include "js.h" +#include "jscompile.h" +#include "jsrun.h" +#include "jsstate.h" + +static js_Value stack[256]; +static int top = 0; + +static inline int i32(double d) +{ + double two32 = 4294967296.0; + double two31 = 2147483648.0; + + if (!isfinite(d) || d == 0) + return 0; + + d = fmod(d, two32); + d = d >= 0 ? floor(d) : ceil(d) + two32; + if (d >= two31) + return d - two32; + else + return d; +} + +static inline unsigned int u32(double d) +{ + return i32(d); +} + +static inline void push(js_State *J, js_Value v) +{ + stack[top++] = v; +} + +static inline js_Value pop(js_State *J) +{ + return stack[--top]; +} + +static inline void pushnumber(js_State *J, double number) +{ + js_Value v; + v.type = JS_TNUMBER; + v.u.number = number; + push(J, v); +} + +static inline double popnumber(js_State *J) +{ + js_Value v = pop(J); + if (v.type == JS_TNUMBER) + return v.u.number; + if (v.type == JS_TSTRING) + return strtod(v.u.string, 0); + return 0; +} + +static inline void pushundefined(js_State *J) +{ + js_Value v; + v.type = JS_TUNDEFINED; + push(J, v); +} + +static inline void pushnull(js_State *J) +{ + js_Value v; + v.type = JS_TNULL; + push(J, v); +} + +static inline void pushboolean(js_State *J, int boolean) +{ + js_Value v; + v.type = JS_TBOOLEAN; + v.u.boolean = boolean; + push(J, v); +} + +static inline int popboolean(js_State *J) +{ + js_Value v = pop(J); + if (v.type == JS_TBOOLEAN) + return v.u.boolean; + return 0; +} + +static void dumpstack(js_State *J) +{ + int i; + for (i = 0; i < top; i++) { + printf("stack %d: ", i); + jsC_dumpvalue(J, stack[i]); + putchar('\n'); + } +} + +#define UNARY(X) a = popnumber(J); pushnumber(J, X) +#define BINARY(X) b = popnumber(J); a = popnumber(J); pushnumber(J, X) + +static void runfun(js_State *J, js_Function *F) +{ + unsigned char *pc = F->code; + int opcode, i; + double a, b; + + while (1) { + opcode = *pc++; + switch (opcode) { + case OP_CONST: + i = *pc++; + push(J, F->klist[i]); + break; + + case OP_UNDEF: pushundefined(J); break; + case OP_NULL: pushnull(J); break; + case OP_TRUE: pushboolean(J, 1); break; + case OP_FALSE: pushboolean(J, 0); break; + + case OP_POS: UNARY(a); break; + case OP_NEG: UNARY(-a); break; + case OP_BITNOT: UNARY(~i32(a)); break; + + case OP_ADD: BINARY(a + b); break; + case OP_SUB: BINARY(a - b); break; + case OP_MUL: BINARY(a * b); break; + case OP_DIV: BINARY(a / b); break; + case OP_MOD: BINARY(fmod(a, b)); break; + case OP_SHL: BINARY(i32(a) << (u32(b) & 0x1F)); break; + case OP_SHR: BINARY(i32(a) >> (u32(b) & 0x1F)); break; + case OP_USHR: BINARY(u32(a) >> (u32(b) & 0x1F)); break; + case OP_BITAND: BINARY(i32(a) & i32(b)); break; + case OP_BITXOR: BINARY(i32(a) ^ i32(b)); break; + case OP_BITOR: BINARY(i32(a) | i32(b)); break; + + case OP_RETURN: return; + + default: + fprintf(stderr, "illegal instruction: %d\n", opcode); + return; + } + } +} + +void jsR_runfunction(js_State *J, js_Function *F) +{ + runfun(J, F); + dumpstack(J); +} diff --git a/jsrun.h b/jsrun.h new file mode 100644 index 0000000..a0d2f8b --- /dev/null +++ b/jsrun.h @@ -0,0 +1,35 @@ +#ifndef js_run_h +#define js_run_h + +enum js_ValueType { + JS_TUNDEFINED, + JS_TNULL, + JS_TBOOLEAN, + JS_TNUMBER, + JS_TSTRING, + JS_TREGEXP, + JS_TOBJECT, + + JS_TFUNCTION, + JS_TCFUNCTION, + JS_TCLOSURE, + JS_TARGUMENTS, + + JS_TOBJSLOT, +}; + +struct js_Value +{ + union { + double number; + const char *string; + int boolean; + void *p; + } u; + int flag; + js_ValueType type; +}; + +void jsR_runfunction(js_State *J, js_Function *F); + +#endif diff --git a/jsstate.h b/jsstate.h index 19a5167..092f3c3 100644 --- a/jsstate.h +++ b/jsstate.h @@ -23,6 +23,9 @@ struct js_State double number; js_Ast *ast; /* list of allocated nodes to free after parsing */ + /* compiler */ + js_Function *fun; /* list of allocated functions to free on errors */ + int strict; };