| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065 |
- #include "jsi.h"
- #define LIST(h) jsP_newnode(J, AST_LIST, 0, h, 0, 0, 0)
- #define EXP0(x) jsP_newnode(J, EXP_ ## x, line, 0, 0, 0, 0)
- #define EXP1(x,a) jsP_newnode(J, EXP_ ## x, line, a, 0, 0, 0)
- #define EXP2(x,a,b) jsP_newnode(J, EXP_ ## x, line, a, b, 0, 0)
- #define EXP3(x,a,b,c) jsP_newnode(J, EXP_ ## x, line, a, b, c, 0)
- #define STM0(x) jsP_newnode(J, STM_ ## x, line, 0, 0, 0, 0)
- #define STM1(x,a) jsP_newnode(J, STM_ ## x, line, a, 0, 0, 0)
- #define STM2(x,a,b) jsP_newnode(J, STM_ ## x, line, a, b, 0, 0)
- #define STM3(x,a,b,c) jsP_newnode(J, STM_ ## x, line, a, b, c, 0)
- #define STM4(x,a,b,c,d) jsP_newnode(J, STM_ ## x, line, a, b, c, d)
- static js_Ast *expression(js_State *J, int notin);
- static js_Ast *assignment(js_State *J, int notin);
- 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);
- #define INCREC() if (++J->astdepth > JS_ASTLIMIT) jsP_error(J, "too much recursion")
- #define DECREC() --J->astdepth
- #define SAVEREC() int SAVE=J->astdepth
- #define POPREC() J->astdepth=SAVE
- 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);
- js_newsyntaxerror(J, buf);
- js_throw(J);
- }
- static void jsP_warning(js_State *J, const char *fmt, ...)
- {
- va_list ap;
- char buf[512];
- char msg[256];
- va_start(ap, fmt);
- vsnprintf(msg, sizeof msg, fmt, ap);
- va_end(ap);
- snprintf(buf, sizeof buf, "%s:%d: warning: %s", J->filename, J->lexline, msg);
- js_report(J, buf);
- }
- static js_Ast *jsP_newnode(js_State *J, enum js_AstType type, int line, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d)
- {
- js_Ast *node = js_malloc(J, sizeof *node);
- node->type = type;
- node->line = line;
- node->a = a;
- node->b = b;
- node->c = c;
- node->d = d;
- node->number = 0;
- node->string = NULL;
- node->jumps = NULL;
- node->casejump = 0;
- node->parent = NULL;
- if (a) a->parent = node;
- if (b) b->parent = node;
- if (c) c->parent = node;
- if (d) d->parent = node;
- node->gcnext = J->gcast;
- J->gcast = node;
- return node;
- }
- static js_Ast *jsP_list(js_Ast *head)
- {
- /* set parent pointers in list nodes */
- js_Ast *prev = head, *node = head->b;
- while (node) {
- node->parent = prev;
- prev = node;
- node = node->b;
- }
- return head;
- }
- static js_Ast *jsP_newstrnode(js_State *J, enum js_AstType type, const char *s)
- {
- js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0);
- node->string = s;
- return node;
- }
- static js_Ast *jsP_newnumnode(js_State *J, enum js_AstType type, double n)
- {
- js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0);
- node->number = n;
- return node;
- }
- static void jsP_freejumps(js_State *J, js_JumpList *node)
- {
- while (node) {
- js_JumpList *next = node->next;
- js_free(J, node);
- node = next;
- }
- }
- void jsP_freeparse(js_State *J)
- {
- js_Ast *node = J->gcast;
- while (node) {
- js_Ast *next = node->gcnext;
- jsP_freejumps(J, node->jumps);
- js_free(J, node);
- node = next;
- }
- J->gcast = NULL;
- }
- /* Lookahead */
- static void jsP_next(js_State *J)
- {
- J->lookahead = jsY_lex(J);
- }
- #define jsP_accept(J,x) (J->lookahead == x ? (jsP_next(J), 1) : 0)
- #define jsP_expect(J,x) if (!jsP_accept(J, x)) jsP_error(J, "unexpected token: %s (expected %s)", jsY_tokenstring(J->lookahead), jsY_tokenstring(x))
- static void semicolon(js_State *J)
- {
- if (J->lookahead == ';') {
- jsP_next(J);
- return;
- }
- if (J->newline || J->lookahead == '}' || J->lookahead == 0)
- return;
- jsP_error(J, "unexpected token: %s (expected ';')", jsY_tokenstring(J->lookahead));
- }
- /* Literals */
- static js_Ast *identifier(js_State *J)
- {
- js_Ast *a;
- if (J->lookahead == TK_IDENTIFIER) {
- a = jsP_newstrnode(J, AST_IDENTIFIER, J->text);
- jsP_next(J);
- return a;
- }
- jsP_error(J, "unexpected token: %s (expected identifier)", jsY_tokenstring(J->lookahead));
- }
- static js_Ast *identifieropt(js_State *J)
- {
- if (J->lookahead == TK_IDENTIFIER)
- return identifier(J);
- return NULL;
- }
- static js_Ast *identifiername(js_State *J)
- {
- if (J->lookahead == TK_IDENTIFIER || J->lookahead >= TK_BREAK) {
- js_Ast *a = jsP_newstrnode(J, AST_IDENTIFIER, J->text);
- jsP_next(J);
- return a;
- }
- jsP_error(J, "unexpected token: %s (expected identifier or keyword)", jsY_tokenstring(J->lookahead));
- }
- static js_Ast *arrayelement(js_State *J)
- {
- int line = J->lexline;
- if (J->lookahead == ',')
- return EXP0(ELISION);
- return assignment(J, 0);
- }
- static js_Ast *arrayliteral(js_State *J)
- {
- js_Ast *head, *tail;
- if (J->lookahead == ']')
- return NULL;
- head = tail = LIST(arrayelement(J));
- while (jsP_accept(J, ',')) {
- if (J->lookahead != ']')
- tail = tail->b = LIST(arrayelement(J));
- }
- return jsP_list(head);
- }
- static js_Ast *propname(js_State *J)
- {
- js_Ast *name;
- if (J->lookahead == TK_NUMBER) {
- name = jsP_newnumnode(J, EXP_NUMBER, J->number);
- jsP_next(J);
- } else if (J->lookahead == TK_STRING) {
- name = jsP_newstrnode(J, EXP_STRING, J->text);
- jsP_next(J);
- } else {
- name = identifiername(J);
- }
- return name;
- }
- static js_Ast *propassign(js_State *J)
- {
- js_Ast *name, *value, *arg, *body;
- int line = J->lexline;
- name = propname(J);
- if (J->lookahead != ':' && name->type == AST_IDENTIFIER) {
- if (!strcmp(name->string, "get")) {
- name = propname(J);
- jsP_expect(J, '(');
- jsP_expect(J, ')');
- body = funbody(J);
- return EXP3(PROP_GET, name, NULL, body);
- }
- if (!strcmp(name->string, "set")) {
- name = propname(J);
- jsP_expect(J, '(');
- arg = identifier(J);
- jsP_expect(J, ')');
- body = funbody(J);
- return EXP3(PROP_SET, name, LIST(arg), body);
- }
- }
- jsP_expect(J, ':');
- value = assignment(J, 0);
- return EXP2(PROP_VAL, name, value);
- }
- static js_Ast *objectliteral(js_State *J)
- {
- js_Ast *head, *tail;
- if (J->lookahead == '}')
- return NULL;
- head = tail = LIST(propassign(J));
- while (jsP_accept(J, ',')) {
- if (J->lookahead == '}')
- break;
- tail = tail->b = LIST(propassign(J));
- }
- return jsP_list(head);
- }
- /* Functions */
- static js_Ast *parameters(js_State *J)
- {
- js_Ast *head, *tail;
- if (J->lookahead == ')')
- return NULL;
- head = tail = LIST(identifier(J));
- while (jsP_accept(J, ',')) {
- tail = tail->b = LIST(identifier(J));
- }
- return jsP_list(head);
- }
- static js_Ast *fundec(js_State *J, int line)
- {
- js_Ast *a, *b, *c;
- a = identifier(J);
- jsP_expect(J, '(');
- b = parameters(J);
- jsP_expect(J, ')');
- c = funbody(J);
- return jsP_newnode(J, AST_FUNDEC, line, a, b, c, 0);
- }
- static js_Ast *funstm(js_State *J, int line)
- {
- js_Ast *a, *b, *c;
- a = identifier(J);
- jsP_expect(J, '(');
- b = parameters(J);
- jsP_expect(J, ')');
- c = funbody(J);
- /* rewrite function statement as "var X = function X() {}" */
- return STM1(VAR, LIST(EXP2(VAR, a, EXP3(FUN, a, b, c))));
- }
- static js_Ast *funexp(js_State *J, int line)
- {
- js_Ast *a, *b, *c;
- a = identifieropt(J);
- jsP_expect(J, '(');
- b = parameters(J);
- jsP_expect(J, ')');
- c = funbody(J);
- return EXP3(FUN, a, b, c);
- }
- /* Expressions */
- static js_Ast *primary(js_State *J)
- {
- js_Ast *a;
- int line = J->lexline;
- if (J->lookahead == TK_IDENTIFIER) {
- a = jsP_newstrnode(J, EXP_IDENTIFIER, J->text);
- jsP_next(J);
- return a;
- }
- if (J->lookahead == TK_STRING) {
- a = jsP_newstrnode(J, EXP_STRING, J->text);
- jsP_next(J);
- return a;
- }
- if (J->lookahead == TK_REGEXP) {
- a = jsP_newstrnode(J, EXP_REGEXP, J->text);
- a->number = J->number;
- jsP_next(J);
- return a;
- }
- if (J->lookahead == TK_NUMBER) {
- a = jsP_newnumnode(J, EXP_NUMBER, J->number);
- jsP_next(J);
- return a;
- }
- if (jsP_accept(J, TK_THIS)) return EXP0(THIS);
- if (jsP_accept(J, TK_NULL)) return EXP0(NULL);
- if (jsP_accept(J, TK_TRUE)) return EXP0(TRUE);
- if (jsP_accept(J, TK_FALSE)) return EXP0(FALSE);
- if (jsP_accept(J, '{')) {
- a = EXP1(OBJECT, objectliteral(J));
- jsP_expect(J, '}');
- return a;
- }
- if (jsP_accept(J, '[')) {
- a = EXP1(ARRAY, arrayliteral(J));
- jsP_expect(J, ']');
- return a;
- }
- if (jsP_accept(J, '(')) {
- a = expression(J, 0);
- jsP_expect(J, ')');
- return a;
- }
- jsP_error(J, "unexpected token in expression: %s", jsY_tokenstring(J->lookahead));
- }
- static js_Ast *arguments(js_State *J)
- {
- js_Ast *head, *tail;
- if (J->lookahead == ')')
- return NULL;
- head = tail = LIST(assignment(J, 0));
- while (jsP_accept(J, ',')) {
- tail = tail->b = LIST(assignment(J, 0));
- }
- return jsP_list(head);
- }
- static js_Ast *newexp(js_State *J)
- {
- js_Ast *a, *b;
- int line = J->lexline;
- if (jsP_accept(J, TK_NEW)) {
- a = memberexp(J);
- if (jsP_accept(J, '(')) {
- b = arguments(J);
- jsP_expect(J, ')');
- return EXP2(NEW, a, b);
- }
- return EXP1(NEW, a);
- }
- if (jsP_accept(J, TK_FUNCTION))
- return funexp(J, line);
- return primary(J);
- }
- static js_Ast *memberexp(js_State *J)
- {
- js_Ast *a = newexp(J);
- int line;
- SAVEREC();
- loop:
- INCREC();
- line = J->lexline;
- if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; }
- if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; }
- POPREC();
- return a;
- }
- static js_Ast *callexp(js_State *J)
- {
- js_Ast *a = newexp(J);
- int line;
- SAVEREC();
- loop:
- INCREC();
- line = J->lexline;
- if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; }
- if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; }
- if (jsP_accept(J, '(')) { a = EXP2(CALL, a, arguments(J)); jsP_expect(J, ')'); goto loop; }
- POPREC();
- return a;
- }
- static js_Ast *postfix(js_State *J)
- {
- js_Ast *a = callexp(J);
- int line = J->lexline;
- if (!J->newline && jsP_accept(J, TK_INC)) return EXP1(POSTINC, a);
- if (!J->newline && jsP_accept(J, TK_DEC)) return EXP1(POSTDEC, a);
- return a;
- }
- static js_Ast *unary(js_State *J)
- {
- js_Ast *a;
- int line = J->lexline;
- INCREC();
- if (jsP_accept(J, TK_DELETE)) a = EXP1(DELETE, unary(J));
- else if (jsP_accept(J, TK_VOID)) a = EXP1(VOID, unary(J));
- else if (jsP_accept(J, TK_TYPEOF)) a = EXP1(TYPEOF, unary(J));
- else if (jsP_accept(J, TK_INC)) a = EXP1(PREINC, unary(J));
- else if (jsP_accept(J, TK_DEC)) a = EXP1(PREDEC, unary(J));
- else if (jsP_accept(J, '+')) a = EXP1(POS, unary(J));
- else if (jsP_accept(J, '-')) a = EXP1(NEG, unary(J));
- else if (jsP_accept(J, '~')) a = EXP1(BITNOT, unary(J));
- else if (jsP_accept(J, '!')) a = EXP1(LOGNOT, unary(J));
- else a = postfix(J);
- DECREC();
- return a;
- }
- static js_Ast *multiplicative(js_State *J)
- {
- js_Ast *a = unary(J);
- int line;
- SAVEREC();
- loop:
- INCREC();
- line = J->lexline;
- if (jsP_accept(J, '*')) { a = EXP2(MUL, a, unary(J)); goto loop; }
- if (jsP_accept(J, '/')) { a = EXP2(DIV, a, unary(J)); goto loop; }
- if (jsP_accept(J, '%')) { a = EXP2(MOD, a, unary(J)); goto loop; }
- POPREC();
- return a;
- }
- static js_Ast *additive(js_State *J)
- {
- js_Ast *a = multiplicative(J);
- int line;
- SAVEREC();
- loop:
- INCREC();
- line = J->lexline;
- if (jsP_accept(J, '+')) { a = EXP2(ADD, a, multiplicative(J)); goto loop; }
- if (jsP_accept(J, '-')) { a = EXP2(SUB, a, multiplicative(J)); goto loop; }
- POPREC();
- return a;
- }
- static js_Ast *shift(js_State *J)
- {
- js_Ast *a = additive(J);
- int line;
- SAVEREC();
- loop:
- INCREC();
- line = J->lexline;
- if (jsP_accept(J, TK_SHL)) { a = EXP2(SHL, a, additive(J)); goto loop; }
- if (jsP_accept(J, TK_SHR)) { a = EXP2(SHR, a, additive(J)); goto loop; }
- if (jsP_accept(J, TK_USHR)) { a = EXP2(USHR, a, additive(J)); goto loop; }
- POPREC();
- return a;
- }
- static js_Ast *relational(js_State *J, int notin)
- {
- js_Ast *a = shift(J);
- int line;
- SAVEREC();
- loop:
- INCREC();
- line = J->lexline;
- if (jsP_accept(J, '<')) { a = EXP2(LT, a, shift(J)); goto loop; }
- if (jsP_accept(J, '>')) { a = EXP2(GT, a, shift(J)); goto loop; }
- if (jsP_accept(J, TK_LE)) { a = EXP2(LE, a, shift(J)); goto loop; }
- if (jsP_accept(J, TK_GE)) { a = EXP2(GE, a, shift(J)); goto loop; }
- if (jsP_accept(J, TK_INSTANCEOF)) { a = EXP2(INSTANCEOF, a, shift(J)); goto loop; }
- if (!notin && jsP_accept(J, TK_IN)) { a = EXP2(IN, a, shift(J)); goto loop; }
- POPREC();
- return a;
- }
- static js_Ast *equality(js_State *J, int notin)
- {
- js_Ast *a = relational(J, notin);
- int line;
- SAVEREC();
- loop:
- INCREC();
- line = J->lexline;
- if (jsP_accept(J, TK_EQ)) { a = EXP2(EQ, a, relational(J, notin)); goto loop; }
- if (jsP_accept(J, TK_NE)) { a = EXP2(NE, a, relational(J, notin)); goto loop; }
- if (jsP_accept(J, TK_STRICTEQ)) { a = EXP2(STRICTEQ, a, relational(J, notin)); goto loop; }
- if (jsP_accept(J, TK_STRICTNE)) { a = EXP2(STRICTNE, a, relational(J, notin)); goto loop; }
- POPREC();
- return a;
- }
- static js_Ast *bitand(js_State *J, int notin)
- {
- js_Ast *a = equality(J, notin);
- SAVEREC();
- int line = J->lexline;
- while (jsP_accept(J, '&')) {
- INCREC();
- a = EXP2(BITAND, a, equality(J, notin));
- line = J->lexline;
- }
- POPREC();
- return a;
- }
- static js_Ast *bitxor(js_State *J, int notin)
- {
- js_Ast *a = bitand(J, notin);
- SAVEREC();
- int line = J->lexline;
- while (jsP_accept(J, '^')) {
- INCREC();
- a = EXP2(BITXOR, a, bitand(J, notin));
- line = J->lexline;
- }
- POPREC();
- return a;
- }
- static js_Ast *bitor(js_State *J, int notin)
- {
- js_Ast *a = bitxor(J, notin);
- SAVEREC();
- int line = J->lexline;
- while (jsP_accept(J, '|')) {
- INCREC();
- a = EXP2(BITOR, a, bitxor(J, notin));
- line = J->lexline;
- }
- POPREC();
- return a;
- }
- static js_Ast *logand(js_State *J, int notin)
- {
- js_Ast *a = bitor(J, notin);
- int line = J->lexline;
- if (jsP_accept(J, TK_AND)) {
- INCREC();
- a = EXP2(LOGAND, a, logand(J, notin));
- DECREC();
- }
- return a;
- }
- static js_Ast *logor(js_State *J, int notin)
- {
- js_Ast *a = logand(J, notin);
- int line = J->lexline;
- if (jsP_accept(J, TK_OR)) {
- INCREC();
- a = EXP2(LOGOR, a, logor(J, notin));
- DECREC();
- }
- return a;
- }
- static js_Ast *conditional(js_State *J, int notin)
- {
- js_Ast *a = logor(J, notin);
- int line = J->lexline;
- if (jsP_accept(J, '?')) {
- js_Ast *b, *c;
- INCREC();
- b = assignment(J, 0);
- jsP_expect(J, ':');
- c = assignment(J, notin);
- DECREC();
- return EXP3(COND, a, b, c);
- }
- return a;
- }
- static js_Ast *assignment(js_State *J, int notin)
- {
- js_Ast *a = conditional(J, notin);
- int line = J->lexline;
- INCREC();
- if (jsP_accept(J, '=')) a = EXP2(ASS, a, assignment(J, notin));
- else if (jsP_accept(J, TK_MUL_ASS)) a = EXP2(ASS_MUL, a, assignment(J, notin));
- else if (jsP_accept(J, TK_DIV_ASS)) a = EXP2(ASS_DIV, a, assignment(J, notin));
- else if (jsP_accept(J, TK_MOD_ASS)) a = EXP2(ASS_MOD, a, assignment(J, notin));
- else if (jsP_accept(J, TK_ADD_ASS)) a = EXP2(ASS_ADD, a, assignment(J, notin));
- else if (jsP_accept(J, TK_SUB_ASS)) a = EXP2(ASS_SUB, a, assignment(J, notin));
- else if (jsP_accept(J, TK_SHL_ASS)) a = EXP2(ASS_SHL, a, assignment(J, notin));
- else if (jsP_accept(J, TK_SHR_ASS)) a = EXP2(ASS_SHR, a, assignment(J, notin));
- else if (jsP_accept(J, TK_USHR_ASS)) a = EXP2(ASS_USHR, a, assignment(J, notin));
- else if (jsP_accept(J, TK_AND_ASS)) a = EXP2(ASS_BITAND, a, assignment(J, notin));
- else if (jsP_accept(J, TK_XOR_ASS)) a = EXP2(ASS_BITXOR, a, assignment(J, notin));
- else if (jsP_accept(J, TK_OR_ASS)) a = EXP2(ASS_BITOR, a, assignment(J, notin));
- DECREC();
- return a;
- }
- static js_Ast *expression(js_State *J, int notin)
- {
- js_Ast *a = assignment(J, notin);
- SAVEREC();
- int line = J->lexline;
- while (jsP_accept(J, ',')) {
- INCREC();
- a = EXP2(COMMA, a, assignment(J, notin));
- line = J->lexline;
- }
- POPREC();
- return a;
- }
- /* Statements */
- static js_Ast *vardec(js_State *J, int notin)
- {
- js_Ast *a = identifier(J);
- int line = J->lexline;
- if (jsP_accept(J, '='))
- return EXP2(VAR, a, assignment(J, notin));
- return EXP1(VAR, a);
- }
- static js_Ast *vardeclist(js_State *J, int notin)
- {
- js_Ast *head, *tail;
- head = tail = LIST(vardec(J, notin));
- while (jsP_accept(J, ','))
- tail = tail->b = LIST(vardec(J, notin));
- return jsP_list(head);
- }
- static js_Ast *statementlist(js_State *J)
- {
- js_Ast *head, *tail;
- if (J->lookahead == '}' || J->lookahead == TK_CASE || J->lookahead == TK_DEFAULT)
- return NULL;
- head = tail = LIST(statement(J));
- while (J->lookahead != '}' && J->lookahead != TK_CASE && J->lookahead != TK_DEFAULT)
- tail = tail->b = LIST(statement(J));
- return jsP_list(head);
- }
- static js_Ast *caseclause(js_State *J)
- {
- js_Ast *a, *b;
- int line = J->lexline;
- if (jsP_accept(J, TK_CASE)) {
- a = expression(J, 0);
- jsP_expect(J, ':');
- b = statementlist(J);
- return STM2(CASE, a, b);
- }
- if (jsP_accept(J, TK_DEFAULT)) {
- jsP_expect(J, ':');
- a = statementlist(J);
- return STM1(DEFAULT, a);
- }
- jsP_error(J, "unexpected token in switch: %s (expected 'case' or 'default')", jsY_tokenstring(J->lookahead));
- }
- static js_Ast *caselist(js_State *J)
- {
- js_Ast *head, *tail;
- if (J->lookahead == '}')
- return NULL;
- head = tail = LIST(caseclause(J));
- while (J->lookahead != '}')
- tail = tail->b = LIST(caseclause(J));
- return jsP_list(head);
- }
- static js_Ast *block(js_State *J)
- {
- js_Ast *a;
- int line = J->lexline;
- jsP_expect(J, '{');
- a = statementlist(J);
- jsP_expect(J, '}');
- return STM1(BLOCK, a);
- }
- static js_Ast *forexpression(js_State *J, int end)
- {
- js_Ast *a = NULL;
- if (J->lookahead != end)
- a = expression(J, 0);
- jsP_expect(J, end);
- return a;
- }
- static js_Ast *forstatement(js_State *J, int line)
- {
- js_Ast *a, *b, *c, *d;
- jsP_expect(J, '(');
- if (jsP_accept(J, TK_VAR)) {
- a = vardeclist(J, 1);
- if (jsP_accept(J, ';')) {
- b = forexpression(J, ';');
- c = forexpression(J, ')');
- d = statement(J);
- return STM4(FOR_VAR, a, b, c, d);
- }
- if (jsP_accept(J, TK_IN)) {
- b = expression(J, 0);
- jsP_expect(J, ')');
- c = statement(J);
- return STM3(FOR_IN_VAR, a, b, c);
- }
- jsP_error(J, "unexpected token in for-var-statement: %s", jsY_tokenstring(J->lookahead));
- }
- if (J->lookahead != ';')
- a = expression(J, 1);
- else
- a = NULL;
- if (jsP_accept(J, ';')) {
- b = forexpression(J, ';');
- c = forexpression(J, ')');
- d = statement(J);
- return STM4(FOR, a, b, c, d);
- }
- if (jsP_accept(J, TK_IN)) {
- b = expression(J, 0);
- jsP_expect(J, ')');
- c = statement(J);
- return STM3(FOR_IN, a, b, c);
- }
- jsP_error(J, "unexpected token in for-statement: %s", jsY_tokenstring(J->lookahead));
- }
- static js_Ast *statement(js_State *J)
- {
- js_Ast *a, *b, *c, *d;
- js_Ast *stm;
- int line = J->lexline;
- INCREC();
- if (J->lookahead == '{') {
- stm = block(J);
- }
- else if (jsP_accept(J, TK_VAR)) {
- a = vardeclist(J, 0);
- semicolon(J);
- stm = STM1(VAR, a);
- }
- /* empty statement */
- else if (jsP_accept(J, ';')) {
- stm = STM0(EMPTY);
- }
- else if (jsP_accept(J, TK_IF)) {
- jsP_expect(J, '(');
- a = expression(J, 0);
- jsP_expect(J, ')');
- b = statement(J);
- if (jsP_accept(J, TK_ELSE))
- c = statement(J);
- else
- c = NULL;
- stm = STM3(IF, a, b, c);
- }
- else if (jsP_accept(J, TK_DO)) {
- a = statement(J);
- jsP_expect(J, TK_WHILE);
- jsP_expect(J, '(');
- b = expression(J, 0);
- jsP_expect(J, ')');
- semicolon(J);
- stm = STM2(DO, a, b);
- }
- else if (jsP_accept(J, TK_WHILE)) {
- jsP_expect(J, '(');
- a = expression(J, 0);
- jsP_expect(J, ')');
- b = statement(J);
- stm = STM2(WHILE, a, b);
- }
- else if (jsP_accept(J, TK_FOR)) {
- stm = forstatement(J, line);
- }
- else if (jsP_accept(J, TK_CONTINUE)) {
- a = identifieropt(J);
- semicolon(J);
- stm = STM1(CONTINUE, a);
- }
- else if (jsP_accept(J, TK_BREAK)) {
- a = identifieropt(J);
- semicolon(J);
- stm = STM1(BREAK, a);
- }
- else if (jsP_accept(J, TK_RETURN)) {
- if (J->lookahead != ';' && J->lookahead != '}' && J->lookahead != 0)
- a = expression(J, 0);
- else
- a = NULL;
- semicolon(J);
- stm = STM1(RETURN, a);
- }
- else if (jsP_accept(J, TK_WITH)) {
- jsP_expect(J, '(');
- a = expression(J, 0);
- jsP_expect(J, ')');
- b = statement(J);
- stm = STM2(WITH, a, b);
- }
- else if (jsP_accept(J, TK_SWITCH)) {
- jsP_expect(J, '(');
- a = expression(J, 0);
- jsP_expect(J, ')');
- jsP_expect(J, '{');
- b = caselist(J);
- jsP_expect(J, '}');
- stm = STM2(SWITCH, a, b);
- }
- else if (jsP_accept(J, TK_THROW)) {
- a = expression(J, 0);
- semicolon(J);
- stm = STM1(THROW, a);
- }
- else if (jsP_accept(J, TK_TRY)) {
- a = block(J);
- b = c = d = NULL;
- if (jsP_accept(J, TK_CATCH)) {
- jsP_expect(J, '(');
- b = identifier(J);
- jsP_expect(J, ')');
- c = block(J);
- }
- if (jsP_accept(J, TK_FINALLY)) {
- d = block(J);
- }
- if (!b && !d)
- jsP_error(J, "unexpected token in try: %s (expected 'catch' or 'finally')", jsY_tokenstring(J->lookahead));
- stm = STM4(TRY, a, b, c, d);
- }
- else if (jsP_accept(J, TK_DEBUGGER)) {
- semicolon(J);
- stm = STM0(DEBUGGER);
- }
- else if (jsP_accept(J, TK_FUNCTION)) {
- jsP_warning(J, "function statements are not standard");
- stm = funstm(J, line);
- }
- /* labelled statement or expression statement */
- else if (J->lookahead == TK_IDENTIFIER) {
- a = expression(J, 0);
- if (a->type == EXP_IDENTIFIER && jsP_accept(J, ':')) {
- a->type = AST_IDENTIFIER;
- b = statement(J);
- stm = STM2(LABEL, a, b);
- } else {
- semicolon(J);
- stm = a;
- }
- }
- /* expression statement */
- else {
- stm = expression(J, 0);
- semicolon(J);
- }
- DECREC();
- return stm;
- }
- /* Program */
- static js_Ast *scriptelement(js_State *J)
- {
- int line = J->lexline;
- if (jsP_accept(J, TK_FUNCTION))
- return fundec(J, line);
- return statement(J);
- }
- static js_Ast *script(js_State *J, int terminator)
- {
- js_Ast *head, *tail;
- if (J->lookahead == terminator)
- return NULL;
- head = tail = LIST(scriptelement(J));
- while (J->lookahead != terminator)
- tail = tail->b = LIST(scriptelement(J));
- return jsP_list(head);
- }
- static js_Ast *funbody(js_State *J)
- {
- js_Ast *a;
- jsP_expect(J, '{');
- a = script(J, '}');
- jsP_expect(J, '}');
- return a;
- }
- /* Constant folding */
- static int toint32(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 unsigned int touint32(double d)
- {
- return (unsigned int)toint32(d);
- }
- static int jsP_setnumnode(js_Ast *node, double x)
- {
- node->type = EXP_NUMBER;
- node->number = x;
- node->a = node->b = node->c = node->d = NULL;
- return 1;
- }
- static int jsP_foldconst(js_Ast *node)
- {
- double x, y;
- int a, b;
- if (node->type == AST_LIST) {
- while (node) {
- jsP_foldconst(node->a);
- node = node->b;
- }
- return 0;
- }
- if (node->type == EXP_NUMBER)
- return 1;
- a = node->a ? jsP_foldconst(node->a) : 0;
- b = node->b ? jsP_foldconst(node->b) : 0;
- if (node->c) jsP_foldconst(node->c);
- if (node->d) jsP_foldconst(node->d);
- if (a) {
- x = node->a->number;
- switch (node->type) {
- default: break;
- case EXP_NEG: return jsP_setnumnode(node, -x);
- case EXP_POS: return jsP_setnumnode(node, x);
- case EXP_BITNOT: return jsP_setnumnode(node, ~toint32(x));
- }
- if (b) {
- y = node->b->number;
- switch (node->type) {
- default: break;
- case EXP_MUL: return jsP_setnumnode(node, x * y);
- case EXP_DIV: return jsP_setnumnode(node, x / y);
- case EXP_MOD: return jsP_setnumnode(node, fmod(x, y));
- case EXP_ADD: return jsP_setnumnode(node, x + y);
- case EXP_SUB: return jsP_setnumnode(node, x - y);
- case EXP_SHL: return jsP_setnumnode(node, toint32(x) << (touint32(y) & 0x1F));
- case EXP_SHR: return jsP_setnumnode(node, toint32(x) >> (touint32(y) & 0x1F));
- case EXP_USHR: return jsP_setnumnode(node, touint32(x) >> (touint32(y) & 0x1F));
- case EXP_BITAND: return jsP_setnumnode(node, toint32(x) & toint32(y));
- case EXP_BITXOR: return jsP_setnumnode(node, toint32(x) ^ toint32(y));
- case EXP_BITOR: return jsP_setnumnode(node, toint32(x) | toint32(y));
- }
- }
- }
- return 0;
- }
- /* Main entry point */
- js_Ast *jsP_parse(js_State *J, const char *filename, const char *source)
- {
- js_Ast *p;
- jsY_initlex(J, filename, source);
- jsP_next(J);
- J->astdepth = 0;
- p = script(J, 0);
- if (p)
- jsP_foldconst(p);
- return p;
- }
- js_Ast *jsP_parsefunction(js_State *J, const char *filename, const char *params, const char *body)
- {
- js_Ast *p = NULL;
- int line = 0;
- if (params) {
- jsY_initlex(J, filename, params);
- jsP_next(J);
- J->astdepth = 0;
- p = parameters(J);
- }
- return EXP3(FUN, NULL, p, jsP_parse(J, filename, body));
- }
|