Add js_Object with js_Property binary search tree.

Use object to represent a variable record and implement variable
loading and storing in the interpreter.
This commit is contained in:
Tor Andersson
2014-01-13 21:32:33 +01:00
parent 89310461e8
commit a4cc139e1c
9 changed files with 505 additions and 241 deletions
+8 -7
View File
@@ -11,15 +11,16 @@
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);
typedef struct js_Ast js_Ast;
typedef struct js_Closure js_Closure;
typedef struct js_Function js_Function;
typedef struct js_Object js_Object;
typedef struct js_Property js_Property;
typedef struct js_RegExp js_RegExp;
typedef struct js_StringNode js_StringNode;
typedef struct js_Value js_Value;
#define JS_REGEXP_G 1
#define JS_REGEXP_I 2
+128 -132
View File
@@ -1,15 +1,13 @@
#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 js_Function *newfun(js_State *J, js_Ast *name, js_Ast *params, js_Ast *body);
static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body);
static void cexp(JF, js_Ast *exp);
static void cstmlist(JF, js_Ast *list);
@@ -23,109 +21,131 @@ static int listlen(js_Ast *list)
return n;
}
static int consteq(js_Value a, js_Value b)
static js_Function *newfun(js_State *J, js_Ast *name, js_Ast *params, js_Ast *body)
{
if (a.type != b.type) return 0;
if (a.type == JS_TNUMBER) return a.u.number == b.u.number;
if (a.type == JS_TSTRING) return a.u.string == b.u.string;
return a.u.p == b.u.p;
js_Function *F = malloc(sizeof *F);
memset(F, 0, sizeof *F);
F->name = name ? name->string : "<anonymous>";
F->numparams = listlen(params);
F->codecap = 256;
F->codelen = 0;
F->code = malloc(F->codecap * sizeof *F->code);
F->next = J->fun;
J->fun = F;
cfunbody(J, F, name, params, body);
return F;
}
static int addconst(JF, js_Value v)
static void freefun(js_State *J, js_Function *F)
{
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++;
// int i;
// for (i = 0; i < F->funlen; i++)
// freefun(J, F->funlist[i]);
free(F->funlist);
free(F->numlist);
free(F->strlist);
free(F->code);
free(F);
}
/* Emit opcodes, constants and jumps */
static void emit(JF, int value)
{
if (F->len >= F->cap) {
F->cap *= 2;
F->code = realloc(F->code, F->cap);
if (F->codelen >= F->codecap) {
F->codecap *= 2;
F->code = realloc(F->code, F->codecap * sizeof *F->code);
}
F->code[F->codelen++] = value;
}
F->code[F->len++] = value;
static int addfunction(JF, js_Function *value)
{
if (F->funlen >= F->funcap) {
F->funcap = F->funcap ? F->funcap * 2 : 16;
F->funlist = realloc(F->funlist, F->funcap * sizeof *F->funlist);
}
F->funlist[F->funlen] = value;
return F->funlen++;
}
static int addnumber(JF, double value)
{
int i;
for (i = 0; i < F->numlen; i++)
if (F->numlist[i] == value)
return i;
if (F->numlen >= F->numcap) {
F->numcap = F->numcap ? F->numcap * 2 : 16;
F->numlist = realloc(F->numlist, F->numcap * sizeof *F->numlist);
}
F->numlist[F->numlen] = value;
return F->numlen++;
}
static int addstring(JF, const char *value)
{
int i;
for (i = 0; i < F->strlen; i++)
if (!strcmp(F->strlist[i], value))
return i;
if (F->strlen >= F->strcap) {
F->strcap = F->strcap ? F->strcap * 2 : 16;
F->strlist = realloc(F->strlist, F->strcap * sizeof *F->strlist);
}
F->strlist[F->strlen] = value;
return F->strlen++;
}
static void emitfunction(JF, int opcode, js_Function *fun)
{
js_Value v;
v.type = JS_TFUNCTION;
v.u.function = fun;
emit(J, F, opcode);
emit(J, F, addconst(J, F, v));
emit(J, F, addfunction(J, F, fun));
}
static void emitnumber(JF, int opcode, double n)
static void emitnumber(JF, int opcode, double num)
{
js_Value v;
v.type = JS_TNUMBER;
v.u.number = n;
emit(J, F, opcode);
emit(J, F, addconst(J, F, v));
emit(J, F, addnumber(J, F, num));
}
static void emitstring(JF, int opcode, const char *s)
static void emitstring(JF, int opcode, const char *str)
{
js_Value v;
v.type = JS_TSTRING;
v.u.string = s;
emit(J, F, opcode);
emit(J, F, addconst(J, F, v));
}
static void emitname(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));
emit(J, F, addstring(J, F, str));
}
static int here(JF)
{
return F->len;
}
static void labelto(JF, int inst, int dest)
{
F->code[inst+0] = (dest >> 8) & 0xFF;
F->code[inst+1] = (dest) & 0xFF;
}
static void label(JF, int inst)
{
labelto(J, F, inst, here(J, F));
return F->codelen;
}
static int jump(JF, int opcode)
{
int inst = F->len + 1;
int inst = F->codelen + 1;
emit(J, F, opcode);
emit(J, F, 0);
emit(J, F, 0);
return inst;
}
static void jumpto(JF, int opcode, int dest)
{
labelto(J, F, jump(J, F, opcode), dest);
emit(J, F, opcode);
emit(J, F, dest);
}
static void label(JF, int inst)
{
F->code[inst] = F->codelen;
}
/* Expressions */
static void unary(JF, js_Ast *exp, int opcode)
{
cexp(J, F, exp->a);
@@ -141,9 +161,11 @@ static void binary(JF, js_Ast *exp, int opcode)
static void carray(JF, js_Ast *list)
{
int i = 0;
while (list) {
cexp(J, F, list->a);
emit(J, F, OP_ARRAYPUT);
emit(J, F, i++);
list = list->b;
}
}
@@ -156,7 +178,7 @@ static void cobject(JF, js_Ast *list)
js_Ast *prop = kv->a;
cexp(J, F, kv->b);
if (prop->type == AST_IDENTIFIER || prop->type == AST_STRING)
emitname(J, F, OP_OBJECTPUT, prop->string);
emitstring(J, F, OP_OBJECTPUT, prop->string);
else if (prop->type == AST_STRING)
emitstring(J, F, OP_OBJECTPUT, prop->string);
else if (prop->type == AST_NUMBER)
@@ -184,7 +206,7 @@ static void clval(JF, js_Ast *exp)
{
switch (exp->type) {
case AST_IDENTIFIER:
emitname(J, F, OP_AVAR, exp->string);
emitstring(J, F, OP_AVAR, exp->string);
break;
case EXP_INDEX:
cexp(J, F, exp->a);
@@ -193,7 +215,7 @@ static void clval(JF, js_Ast *exp)
break;
case EXP_MEMBER:
cexp(J, F, exp->a);
emitname(J, F, OP_AMEMBER, exp->b->string);
emitstring(J, F, OP_AMEMBER, exp->b->string);
break;
case EXP_CALL:
/* host functions may return an assignable l-value */
@@ -214,6 +236,20 @@ static void assignop(JF, js_Ast *exp, int opcode)
emit(J, F, OP_STORE);
}
static void cvarinit(JF, js_Ast *list)
{
while (list) {
js_Ast *var = list->a;
if (var->b) {
cexp(J, F, var->b);
emitstring(J, F, OP_AVAR, var->a->string);
emit(J, F, OP_STORE);
emit(J, F, OP_POP);
}
list = list->b;
}
}
static void ccall(JF, js_Ast *fun, js_Ast *args)
{
int n;
@@ -227,7 +263,7 @@ static void ccall(JF, js_Ast *fun, js_Ast *args)
case EXP_MEMBER:
cexp(J, F, fun->a);
emit(J, F, OP_DUP);
emitname(J, F, OP_LOADMEMBER, fun->b->string);
emitstring(J, F, OP_LOADMEMBER, fun->b->string);
break;
default:
emit(J, F, OP_THIS);
@@ -245,9 +281,9 @@ static void cexp(JF, js_Ast *exp)
int n;
switch (exp->type) {
case AST_IDENTIFIER: emitname(J, F, OP_LOADVAR, exp->string); break;
case AST_NUMBER: emitnumber(J, F, OP_CONST, exp->number); break;
case AST_STRING: emitstring(J, F, OP_CONST, exp->string); break;
case AST_IDENTIFIER: emitstring(J, F, OP_LOADVAR, exp->string); break;
case AST_NUMBER: emitnumber(J, F, OP_NUMBER, exp->number); break;
case AST_STRING: emitstring(J, F, OP_STRING, 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;
@@ -272,7 +308,7 @@ static void cexp(JF, js_Ast *exp)
case EXP_MEMBER:
cexp(J, F, exp->a);
emitname(J, F, OP_LOADMEMBER, exp->b->string);
emitstring(J, F, OP_LOADMEMBER, exp->b->string);
break;
case EXP_CALL:
@@ -393,19 +429,7 @@ static void cexp(JF, js_Ast *exp)
}
}
static void cvarinit(JF, js_Ast *list)
{
while (list) {
js_Ast *var = list->a;
if (var->b) {
cexp(J, F, var->b);
emitname(J, F, OP_AVAR, var->a->string);
emit(J, F, OP_STORE);
emit(J, F, OP_POP);
}
list = list->b;
}
}
/* Statements */
static void cstm(JF, js_Ast *stm)
{
@@ -505,13 +529,15 @@ static void cstmlist(JF, js_Ast *list)
}
}
/* Declarations and programs */
static void cfundecs(JF, js_Ast *list)
{
while (list) {
js_Ast *stm = list->a;
if (stm->type == AST_FUNDEC) {
emitfunction(J, F, OP_CLOSURE, newfun(J, stm->a, stm->b, stm->c));
emitname(J, F, OP_FUNDEC, stm->a->string);
emitstring(J, F, OP_FUNDEC, stm->a->string);
}
list = list->b;
}
@@ -520,7 +546,7 @@ static void cfundecs(JF, js_Ast *list)
static void cvardecs(JF, js_Ast *node)
{
if (node->type == EXP_VAR) {
emitname(J, F, OP_VARDEC, node->a->string);
emitstring(J, F, OP_VARDEC, node->a->string);
} else if (node->type != EXP_FUN && node->type != AST_FUNDEC) {
if (node->a) cvardecs(J, F, node->a);
if (node->b) cvardecs(J, F, node->b);
@@ -533,7 +559,7 @@ static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body)
{
if (name) {
emitfunction(J, F, OP_CLOSURE, F);
emitname(J, F, OP_FUNDEC, name->string);
emitstring(J, F, OP_FUNDEC, name->string);
}
if (body) {
@@ -542,53 +568,12 @@ static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body)
cstmlist(J, F, body);
}
if (F->len == 0 || F->code[F->len - 1] != OP_RETURN) {
if (F->codelen == 0 || F->code[F->codelen - 1] != OP_RETURN) {
emit(J, F, OP_UNDEF);
emit(J, F, OP_RETURN);
}
}
static js_Function *newfun(js_State *J, js_Ast *name, js_Ast *params, js_Ast *body)
{
js_Function *F = malloc(sizeof(js_Function));
F->name = name ? name->string : "<anonymous>";
F->numparams = listlen(params);
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;
cfunbody(J, F, name, params, body);
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;
@@ -603,6 +588,17 @@ int jsC_error(js_State *J, js_Ast *node, const char *fmt, ...)
return 0;
}
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;
}
js_Function *jsC_compile(js_State *J, js_Ast *prog)
{
js_Function *F;
+16 -8
View File
@@ -7,7 +7,9 @@ enum
OP_DUP,
OP_CLOSURE,
OP_CONST,
OP_NUMBER,
OP_STRING,
OP_UNDEF,
OP_NULL,
OP_TRUE,
@@ -23,12 +25,12 @@ enum
OP_VARDEC, /* -(name)- */
OP_LOADVAR, /* -(name)- <value> */
OP_LOADINDEX, /* <obj> <idx> -- <value> */
OP_LOADMEMBER, /* <obj> -(name)- <value> */
OP_LOADINDEX, /* <obj> <idx> -- <value> */
OP_AVAR, /* -(name)- <addr> */
OP_AINDEX, /* <obj> <idx> -- <addr> */
OP_AMEMBER, /* <obj> -(name)- <addr> */
OP_AINDEX, /* <obj> <idx> -- <addr> */
OP_LOAD, /* <addr> -- <addr> <value> */
OP_STORE, /* <addr> <value> -- <value> */
@@ -89,13 +91,19 @@ struct js_Function
const char *name;
int numparams;
unsigned char *code;
int cap, len;
short *code;
int codecap, codelen;
js_Value *klist;
int kcap, klen;
js_Function **funlist;
int funcap, funlen;
js_Function *next;
double *numlist;
int numcap, numlen;
const char **strlist;
int strcap, strlen;
js_Function *next; /* alloc list */
};
js_Function *jsC_compile(js_State *J, js_Ast *prog);
+48 -48
View File
@@ -1,7 +1,8 @@
#include "js.h"
#include "jsparse.h"
#include "jscompile.h"
#include "jsrun.h"
#include "jsvalue.h"
#include "jsobject.h"
#include <assert.h>
@@ -25,12 +26,6 @@ static const char *opname[] = {
#include "opnames.h"
};
static void pstmlist(int d, js_Ast *list);
static void pexpi(int d, int i, js_Ast *exp);
static void pstm(int d, js_Ast *stm);
static void slist(int d, js_Ast *list);
static void sblock(int d, js_Ast *list);
static inline void pc(int c)
{
putchar(c);
@@ -52,6 +47,14 @@ static inline void nl(void)
putchar('\n');
}
/* Pretty-printed Javascript syntax */
static void pstmlist(int d, js_Ast *list);
static void pexpi(int d, int i, js_Ast *exp);
static void pstm(int d, js_Ast *stm);
static void slist(int d, js_Ast *list);
static void sblock(int d, js_Ast *list);
static void pargs(int d, js_Ast *list)
{
while (list) {
@@ -509,6 +512,8 @@ void jsP_dumpsyntax(js_State *J, js_Ast *prog)
}
}
/* S-expression list representation */
static void snode(int d, js_Ast *node)
{
void (*afun)(int,js_Ast*) = snode;
@@ -583,76 +588,71 @@ void jsP_dumplist(js_State *J, js_Ast *prog)
nl();
}
void jsC_dumpvalue(js_State *J, js_Value v)
/* Compiled code */
void jsC_dumpfunction(js_State *J, js_Function *F)
{
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("<regexp %p>", v.u.p); break;
case JS_TOBJECT: printf("<object %p>", v.u.p); break;
case JS_TFUNCTION: printf("<function %p>", v.u.function); break;
case JS_TCFUNCTION: printf("<cfunction %p>", v.u.p); break;
case JS_TCLOSURE: printf("<closure %p>", v.u.p); break;
case JS_TARGUMENTS: printf("<arguments %p>", v.u.p); break;
case JS_TOBJSLOT: printf("<objslot %p>", 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;
short *p = F->code;
short *end = F->code + F->codelen;
int i, dest;
printf("function %p, %s, %d parameters, %d constants\n",
fun, fun->name, fun->numparams, fun->klen);
printf("function %p %s(%d)\n", F, F->name, F->numparams);
for (i = 0; i < F->funlen; i++)
printf("\tfunction %p %s\n", F->funlist[i], F->funlist[i]->name);
for (i = 0; i < F->strlen; i++) {
ps("\tstring "); pstr(F->strlist[i]); ps("\n");
}
// TODO: regexp
for (i = 0; i < F->numlen; i++)
printf("\tnumber %.9g\n", F->numlist[i]);
while (p < end) {
int c = *p++;
printf("%04d: ", (int)(p - fun->code) - 1);
printf("%04d: ", (int)(p - F->code) - 1);
ps(opname[c]);
switch (c) {
case OP_CONST:
case OP_CLOSURE:
pc(' ');
ps(F->funlist[*p++]->name);
break;
case OP_NUMBER:
printf(" %.9g", F->numlist[*p++]);
break;
case OP_STRING:
pc(' ');
pstr(F->strlist[*p++]);
break;
case OP_OBJECTPUT:
case OP_VARDEC:
case OP_FUNDEC:
case OP_VARDEC:
case OP_LOADVAR:
case OP_LOADMEMBER:
case OP_AVAR:
case OP_AMEMBER:
case OP_CLOSURE:
pc(' ');
jsC_dumpvalue(J, fun->klist[*p++]);
ps(F->strlist[*p++]);
break;
case OP_ARRAYPUT:
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);
printf(" %d", *p++);
break;
}
nl();
}
for (i = 0; i < fun->klen; i++) {
if (fun->klist[i].type == JS_TFUNCTION) {
if (fun->klist[i].u.function != fun) {
nl();
jsC_dumpfunction(J, fun->klist[i].u.function);
}
for (i = 0; i < F->funlen; i++) {
if (F->funlist[i] != F) {
nl();
jsC_dumpfunction(J, F->funlist[i]);
}
}
}
+144
View File
@@ -0,0 +1,144 @@
#include "js.h"
#include "jsvalue.h"
#include "jsobject.h"
/*
Use an AA-tree to quickly look up properties in objects:
The level of every leaf node is one.
The level of every left child is one less than its parent.
The level of every right child is equal or one less than its parent.
The level of every right grandchild is less than its grandparent.
Every node of level greater than one has two children.
A link where the child's level is equal to that of its parent is called a horizontal link.
Individual right horizontal links are allowed, but consecutive ones are forbidden.
Left horizontal links are forbidden.
skew() fixes left horizontal links.
split() fixes consecutive right horizontal links.
*/
static js_Property sentinel = { "", &sentinel, &sentinel, 0 };
static js_Property *newproperty(const char *key)
{
js_Property *node = malloc(sizeof(js_Property));
node->key = strdup(key);
node->left = node->right = &sentinel;
node->level = 1;
// node->value = 0;
return node;
}
static js_Property *lookup(js_Property *node, const char *key)
{
while (node != &sentinel) {
int c = strcmp(key, node->key);
if (c == 0)
return node;
else if (c < 0)
node = node->left;
else
node = node->right;
}
return NULL;
}
static inline js_Property *skew(js_Property *node)
{
if (node->level != 0) {
if (node->left->level == node->level) {
js_Property *save = node;
node = node->left;
save->left = node->right;
node->right = save;
}
node->right = skew(node->right);
}
return node;
}
static inline js_Property *split(js_Property *node)
{
if (node->level != 0 && node->right->right->level == node->level) {
js_Property *save = node;
node = node->right;
save->right = node->left;
node->left = save;
node->level++;
node->right = split(node->right);
}
return node;
}
static js_Property *insert(js_Property *node, const char *key, js_Property **result)
{
if (node != &sentinel) {
int c = strcmp(key, node->key);
if (c < 0)
node->left = insert(node->left, key, result);
else if (c > 0)
node->right = insert(node->right, key, result);
else
return *result = node;
node = skew(node);
node = split(node);
return node;
}
return *result = newproperty(key);
}
js_Object *js_newobject(js_State *J)
{
js_Object *obj = malloc(sizeof(js_Object));
obj->properties = &sentinel;
return obj;
}
js_Property *js_getproperty(js_State *J, js_Object *obj, const char *name)
{
return lookup(obj->properties, name);
}
js_Property *js_setproperty(js_State *J, js_Object *obj, const char *name)
{
js_Property *result;
obj->properties = insert(obj->properties, name, &result);
return result;
}
static void js_dumpvalue(js_State *J, js_Value v)
{
switch (v.type) {
case JS_TUNDEFINED: printf("undefined"); break;
case JS_TNULL: printf("null"); break;
case JS_TBOOLEAN: printf(v.u.boolean ? "true" : "false"); break;
case JS_TNUMBER: printf("%.9g", v.u.number); break;
case JS_TSTRING: printf("'%s'", v.u.string); break;
case JS_TREGEXP: printf("/%s/", v.u.regexp.prog); break;
case JS_TOBJECT: printf("<object %p>", v.u.object); break;
case JS_TCLOSURE: printf("<closure %p>", v.u.closure); break;
case JS_TCFUNCTION: printf("<cfunction %p>", v.u.cfunction); break;
case JS_TREFERENCE: printf("<reference %p>", v.u.reference); break;
}
}
static void js_dumpproperty(js_State *J, js_Property *node)
{
if (node->left != &sentinel)
js_dumpproperty(J, node->left);
printf("\t%s: ", node->key);
js_dumpvalue(J, node->value);
printf(",\n");
if (node->right != &sentinel)
js_dumpproperty(J, node->right);
}
void js_dumpobject(js_State *J, js_Object *obj)
{
printf("{\n");
if (obj->properties != &sentinel)
js_dumpproperty(J, obj->properties);
printf("}\n");
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef js_object_h
#define js_object_h
struct js_Property
{
char *key;
js_Property *left, *right;
int level;
js_Value value;
};
struct js_Object
{
js_Property *properties;
js_Object *prototype;
js_Object *parent;
};
js_Object *js_newobject(js_State *J);
js_Property *js_getproperty(js_State *J, js_Object *obj, const char *name);
js_Property *js_setproperty(js_State *J, js_Object *obj, const char *name);
void js_deleteproperty(js_State *J, js_Object *obj, const char *name);
void js_dumpobject(js_State *J, js_Object *obj);
#endif
+98 -16
View File
@@ -1,4 +1,6 @@
#include "js.h"
#include "jsvalue.h"
#include "jsobject.h"
#include "jscompile.h"
#include "jsrun.h"
#include "jsstate.h"
@@ -37,6 +39,11 @@ static inline js_Value pop(js_State *J)
return stack[--top];
}
static inline js_Value peek(js_State *J)
{
return stack[top-1];
}
static inline void pushnumber(js_State *J, double number)
{
js_Value v;
@@ -82,34 +89,83 @@ static inline int popboolean(js_State *J)
js_Value v = pop(J);
if (v.type == JS_TBOOLEAN)
return v.u.boolean;
if (v.type == JS_TNUMBER)
return v.u.number != 0;
return 0;
}
static void dumpstack(js_State *J)
static inline void pushreference(js_State *J, js_Property *reference)
{
int i;
for (i = 0; i < top; i++) {
printf("stack %d: ", i);
jsC_dumpvalue(J, stack[i]);
putchar('\n');
}
js_Value v;
v.type = JS_TREFERENCE;
v.u.reference = reference;
push(J, v);
}
static inline js_Property *popreference(js_State *J)
{
js_Value v = pop(J);
if (v.type == JS_TREFERENCE)
return v.u.reference;
return 0;
}
static inline js_Property *peekreference(js_State *J)
{
js_Value v = peek(J);
if (v.type == JS_TREFERENCE)
return v.u.reference;
return 0;
}
#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)
static void runfun(js_State *J, js_Function *F, js_Object *E)
{
unsigned char *pc = F->code;
int opcode, i;
short *pc = F->code;
int opcode, addr;
js_Property *p;
js_Value v;
double a, b;
const char *s;
while (1) {
opcode = *pc++;
switch (opcode) {
case OP_CONST:
i = *pc++;
push(J, F->klist[i]);
case OP_NUMBER:
pushnumber(J, F->numlist[*pc++]);
break;
case OP_LOADVAR:
s = F->strlist[*pc++];
p = js_getproperty(J, E, s);
if (p)
push(J, p->value);
else
pushundefined(J);
break;
case OP_AVAR:
s = F->strlist[*pc++];
p = js_setproperty(J, E, s);
pushreference(J, p);
break;
case OP_LOAD:
p = peekreference(J);
if (p)
push(J, p->value);
else
pushundefined(J);
break;
case OP_STORE:
v = pop(J);
p = popreference(J);
if (p)
p->value = v;
push(J, v);
break;
case OP_UNDEF: pushundefined(J); break;
@@ -120,6 +176,7 @@ static void runfun(js_State *J, js_Function *F)
case OP_POS: UNARY(a); break;
case OP_NEG: UNARY(-a); break;
case OP_BITNOT: UNARY(~i32(a)); break;
case OP_LOGNOT: UNARY(!a); break;
case OP_ADD: BINARY(a + b); break;
case OP_SUB: BINARY(a - b); break;
@@ -133,10 +190,34 @@ static void runfun(js_State *J, js_Function *F)
case OP_BITXOR: BINARY(i32(a) ^ i32(b)); break;
case OP_BITOR: BINARY(i32(a) | i32(b)); break;
case OP_LT: BINARY(a < b); break;
case OP_GT: BINARY(a > b); break;
case OP_LE: BINARY(a <= b); break;
case OP_GE: BINARY(a >= b); break;
case OP_EQ: BINARY(a == b); break;
case OP_NE: BINARY(a != b); break;
case OP_JFALSE:
addr = *pc++;
if (!popboolean(J))
pc = F->code + addr;
break;
case OP_JTRUE:
addr = *pc++;
if (popboolean(J))
pc = F->code + addr;
break;
case OP_JUMP:
pc = F->code + *pc;
break;
case OP_POP: pop(J); break;
case OP_RETURN: return;
default:
fprintf(stderr, "illegal instruction: %d\n", opcode);
fprintf(stderr, "illegal instruction: %d (pc=%d)\n", opcode, (int)(pc - F->code - 1));
return;
}
}
@@ -144,6 +225,7 @@ static void runfun(js_State *J, js_Function *F)
void jsR_runfunction(js_State *J, js_Function *F)
{
runfun(J, F);
dumpstack(J);
js_Object *varenv = js_newobject(J);
runfun(J, F, varenv);
js_dumpobject(J, varenv);
}
-30
View File
@@ -1,36 +1,6 @@
#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;
js_Function *function;
void *p;
} u;
int flag;
js_ValueType type;
};
void jsR_runfunction(js_State *J, js_Function *F);
#endif
+37
View File
@@ -0,0 +1,37 @@
#ifndef js_value_h
#define js_value_h
enum js_ValueType {
JS_TUNDEFINED,
JS_TNULL,
JS_TBOOLEAN,
JS_TNUMBER,
JS_TSTRING,
JS_TREGEXP,
JS_TOBJECT,
JS_TCLOSURE,
JS_TCFUNCTION,
JS_TREFERENCE, /* l-value from aval/aindex/amember */
};
struct js_Value
{
union {
int boolean;
double number;
const char *string;
struct {
const char *prog;
unsigned char flags;
} regexp;
js_Object *object;
js_Closure *closure;
js_CFunction *cfunction;
js_Property *reference;
} u;
js_ValueType type;
};
void jsC_dumpvalue(js_State *J, js_Value v);
#endif