#include "jsi.h"#include "jslex.h"#include "jsparse.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); return NULL;} 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; } return 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; } return 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(UNDEF); 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; } return 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();Lines 1–500 of 1069. Load more
#include "jsi.h" #include "jslex.h" #include "jsparse.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); return NULL; } 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; } return 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; } return 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(UNDEF); 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; } return 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();