ref: 948d6a9fa86fa0e10f0a7674873ac08f0627a173
dir: /js-ast.c/
#include "js.h"
#include "js-ast.h"
js_Ast *jsP_newnode(js_State *J, int type, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d)
{
js_Ast *node = malloc(sizeof(js_Ast));
node->type = type;
node->line = J->line;
node->a = a;
node->b = b;
node->c = c;
node->d = d;
node->n = 0;
node->s = NULL;
node->next = J->ast;
J->ast = node;
return node;
}
js_Ast *jsP_newstrnode(js_State *J, int type, const char *s)
{
js_Ast *node = jsP_newnode(J, type, 0, 0, 0, 0);
node->s = s;
return node;
}
js_Ast *jsP_newnumnode(js_State *J, int type, double n)
{
js_Ast *node = jsP_newnode(J, type, 0, 0, 0, 0);
node->n = n;
return node;
}
void jsP_freeast(js_State *J)
{
js_Ast *node = J->ast;
while (node) {
js_Ast *next = node->next;
free(node);
node = next;
}
J->ast = NULL;
}
static const char *strast(int type)
{
switch (type) {
case AST_LIST: return "LIST";
case AST_IDENTIFIER: return "IDENTIFIER";
case AST_NUMBER: return "NUMBER";
case AST_STRING: return "STRING";
case AST_REGEXP: return "REGEXP";
case AST_INIT: return "INIT";
case EXP_NULL: return "NULL";
case EXP_TRUE: return "TRUE";
case EXP_FALSE: return "FALSE";
case EXP_THIS: return "THIS";
case EXP_ARRAY: return "ARRAY";
case EXP_OBJECT: return "OBJECT";
case EXP_PROP_VAL: return "PROP_VAL";
case EXP_PROP_GET: return "PROP_GET";
case EXP_PROP_SET: return "PROP_SET";
case EXP_INDEX: return "INDEX";
case EXP_MEMBER: return "MEMBER";
case EXP_NEW: return "new";
case EXP_CALL: return "CALL";
case EXP_FUNC: return "function";
case EXP_COND: return "?:";
case EXP_COMMA: return ",";
case EXP_DELETE: return "delete";
case EXP_VOID: return "void";
case EXP_TYPEOF: return "typeof";
case EXP_PREINC: return "PRE++";
case EXP_PREDEC: return "PRE--";
case EXP_POSTINC: return "POST++";
case EXP_POSTDEC: return "POST--";
case EXP_POS: return "+";
case EXP_NEG: return "-";
case EXP_BITNOT: return "~";
case EXP_LOGNOT: return "!";
case EXP_LOGOR: return "||";
case EXP_LOGAND: return "&&";
case EXP_BITOR: return "|";
case EXP_BITXOR: return "^";
case EXP_BITAND: return "&";
case EXP_EQ: return "==";
case EXP_NE: return "!=";
case EXP_EQ3: return "===";
case EXP_NE3: return "!==";
case EXP_LT: return "<";
case EXP_GT: return ">";
case EXP_LE: return "<=";
case EXP_GE: return ">=";
case EXP_INSTANCEOF: return "instanceof";
case EXP_IN: return "in";
case EXP_SHL: return "<<";
case EXP_SHR: return ">>";
case EXP_USHR: return ">>>";
case EXP_ADD: return "+";
case EXP_SUB: return "-";
case EXP_MUL: return "*";
case EXP_DIV: return "/";
case EXP_MOD: return "%";
case EXP_ASS: return "=";
case EXP_ASS_MUL: return "*=";
case EXP_ASS_DIV: return "/=";
case EXP_ASS_MOD: return "%=";
case EXP_ASS_ADD: return "+=";
case EXP_ASS_SUB: return "-=";
case EXP_ASS_SHL: return "<<=";
case EXP_ASS_SHR: return ">>=";
case EXP_ASS_USHR: return ">>>=";
case EXP_ASS_BITAND: return "&=";
case EXP_ASS_BITXOR: return "^=";
case EXP_ASS_BITOR: return "|=";
case STM_BLOCK: return "BLOCK";
case STM_FUNC: return "function-decl";
case STM_NOP: return "NOP";
case STM_VAR: return "var";
case STM_IF: return "if";
case STM_DO: return "do-while";
case STM_WHILE: return "while";
case STM_FOR: return "for";
case STM_FOR_VAR: return "for_var";
case STM_FOR_IN: return "for_in";
case STM_FOR_IN_VAR: return "for_in_var";
case STM_CONTINUE: return "continue";
case STM_BREAK: return "break";
case STM_RETURN: return "return";
case STM_WITH: return "with";
case STM_SWITCH: return "switch";
case STM_THROW: return "throw";
case STM_TRY: return "try";
case STM_LABEL: return "label";
case STM_CASE: return "case";
case STM_DEFAULT: return "default";
case STM_DEBUGGER: return "debugger";
default: return "(unknown)";
}
}
static void indent(int level)
{
while (level--)
putchar('\t');
}
static void printlist(js_Ast *n, int level, const char *sep)
{
while (n) {
printast(n->a, level);
n = n->b;
if (n)
fputs(sep, stdout);
}
}
void printblock(js_Ast *n, int level)
{
while (n) {
indent(level);
printast(n->a, level);
if (n->a->type < STM_BLOCK) // expression
putchar(';');
n = n->b;
if (n)
putchar('\n');
}
}
static void printstm(js_Ast *n, int level)
{
if (n->type == STM_BLOCK) {
printf(" {\n");
printblock(n->a, level + 1);
putchar('\n');
indent(level);
printf("}");
} else {
putchar('\n');
indent(level + 1);
printast(n, level + 1);
if (n->type < STM_BLOCK) // expression
putchar(';');
}
}
static void printunary(int level, js_Ast *n, const char *pre, const char *suf)
{
printf(pre);
printast(n, level);
printf(suf);
}
static void printbinary(int level, js_Ast *a, js_Ast *b, const char *op)
{
printf("(");
printast(a, level);
printf(" %s ", op);
printast(b, level);
printf(")");
}
void printast(js_Ast *n, int level)
{
switch (n->type) {
case AST_IDENTIFIER: printf("%s", n->s); return;
case AST_NUMBER: printf("%g", n->n); return;
case AST_STRING: printf("'%s'", n->s); return;
case AST_REGEXP: printf("/%s/", n->s); return;
case AST_LIST:
putchar('[');
printlist(n, level, " ");
putchar(']');
break;
case STM_BLOCK:
putchar('{');
putchar('\n');
printblock(n->a, level + 1);
putchar('\n');
indent(level);
putchar('}');
break;
case STM_FOR:
printf("for (");
printast(n->a, level); printf("; ");
printast(n->b, level); printf("; ");
printast(n->c, level); printf(")");
printstm(n->d, level);
break;
case STM_FOR_VAR:
printf("for (var ");
printlist(n->a, level, ", "); printf("; ");
printast(n->b, level); printf("; ");
printast(n->c, level); printf(")");
printstm(n->d, level);
break;
case STM_FOR_IN:
printf("for (");
printast(n->a, level); printf(" in ");
printast(n->b, level); printf(")");
printstm(n->c, level);
break;
case STM_FOR_IN_VAR:
printf("for (var ");
printlist(n->a, level, ", "); printf(" in ");
printast(n->b, level); printf(")");
printstm(n->c, level);
break;
case STM_NOP:
putchar(';');
break;
case STM_VAR:
printf("var ");
printlist(n->a, level, ", ");
putchar(';');
break;
case STM_IF:
printf("if (");
printast(n->a, level);
printf(")");
printstm(n->b, level);
if (n->c) {
putchar('\n');
indent(level);
printf("else");
printstm(n->c, level);
}
break;
case STM_DO:
printf("do");
printstm(n->a, level);
if (n->a->type == STM_BLOCK) {
putchar(' ');
} else {
putchar('\n');
indent(level);
}
printf("while (");
printast(n->b, level);
printf(");");
break;
case STM_WHILE:
printf("while (");
printast(n->a, level);
printf(")");
printstm(n->b, level);
break;
case STM_CONTINUE:
if (n->a) {
printf("continue ");
printast(n->a, level);
printf(";");
} else {
printf("continue;");
}
break;
case STM_BREAK:
if (n->a) {
printf("break ");
printast(n->a, level);
printf(";");
} else {
printf("break;");
}
break;
case STM_RETURN:
if (n->a) {
printf("return ");
printast(n->a, level);
printf(";");
} else {
printf("return;");
}
break;
case STM_THROW:
printf("throw ");
printast(n->a, level);
printf(";");
break;
case STM_SWITCH:
printf("switch (");
printast(n->a, level);
printf(")");
printstm(n->b, level);
break;
case STM_CASE:
printf("case ");
printast(n->a, level);
printf(":");
if (n->b) {
printf("\n");
printblock(n->b, level + 1);
}
break;
case STM_DEFAULT:
printf("default:");
if (n->a) {
printf("\n");
printblock(n->a, level + 1);
}
break;
case STM_LABEL:
printast(n->a, level);
printf(":");
printstm(n->b, level - 1);
break;
case STM_WITH:
printf("with (");
printast(n->a, level);
printf(")");
printstm(n->b, level);
break;
case STM_TRY:
printf("try");
printstm(n->a, level);
if (n->b && n->c) {
printf(" catch (");
printast(n->b, level);
printf(")");
printstm(n->c, level);
}
if (n->d) {
printf(" finally");
printstm(n->d, level);
}
break;
case STM_DEBUGGER:
printf("debugger");
break;
case AST_INIT:
printast(n->a, level);
if (n->b) {
printf(" = ");
printast(n->b, level);
}
break;
case STM_FUNC:
printf("function ");
printast(n->a, level);
printf("(");
printlist(n->b, level, ", ");
printf(")");
printstm(n->c, level);
break;
case EXP_FUNC:
printf("(function ");
if (n->a)
printast(n->a, level);
printf("(");
printlist(n->b, level, ", ");
printf(")");
printstm(n->c, level);
printf(")");
break;
case EXP_OBJECT:
printf("{ ");
printlist(n->a, level, ", ");
printf(" }");
break;
case EXP_PROP_VAL:
printast(n->a, level);
printf(": ");
printast(n->b, level);
break;
case EXP_ARRAY:
printf("[ ");
printlist(n->a, level, ", ");
printf(" ]");
break;
case EXP_NEW:
printf("(new ");
printast(n->a, level);
printf("(");
printlist(n->b, level, ", ");
printf("))");
break;
case EXP_CALL:
printf("(");
printast(n->a, level);
printf("(");
printlist(n->b, level, ", ");
printf("))");
break;
case EXP_MEMBER:
printf("(");
printast(n->a, level);
printf(".");
printast(n->b, level);
printf(")");
break;
case EXP_INDEX:
printf("(");
printast(n->a, level);
printf("[");
printast(n->b, level);
printf("])");
break;
case EXP_COND:
printf("(");
printast(n->a, level);
printf(" ? ");
printast(n->b, level);
printf(" : ");
printast(n->c, level);
printf(")");
break;
case EXP_NULL: printf("null"); break;
case EXP_TRUE: printf("true"); break;
case EXP_FALSE: printf("false"); break;
case EXP_THIS: printf("this"); break;
case EXP_DELETE: printunary(level, n->a, "(delete ", ")"); break;
case EXP_VOID: printunary(level, n->a, "(void ", ")"); break;
case EXP_TYPEOF: printunary(level, n->a, "(typeof ", ")"); break;
case EXP_PREINC: printunary(level, n->a, "(++", ")"); break;
case EXP_PREDEC: printunary(level, n->a, "(--", ")"); break;
case EXP_POSTINC: printunary(level, n->a, "(", "++)"); break;
case EXP_POSTDEC: printunary(level, n->a, "(", "--)"); break;
case EXP_POS: printunary(level, n->a, "(+", ")"); break;
case EXP_NEG: printunary(level, n->a, "(-", ")"); break;
case EXP_BITNOT: printunary(level, n->a, "(~", ")"); break;
case EXP_LOGNOT: printunary(level, n->a, "(!", ")"); break;
case EXP_COMMA: printbinary(level, n->a, n->b, ","); break;
case EXP_LOGOR: printbinary(level, n->a, n->b, "||"); break;
case EXP_LOGAND: printbinary(level, n->a, n->b, "&&"); break;
case EXP_BITOR: printbinary(level, n->a, n->b, "|"); break;
case EXP_BITXOR: printbinary(level, n->a, n->b, "^"); break;
case EXP_BITAND: printbinary(level, n->a, n->b, "&"); break;
case EXP_EQ: printbinary(level, n->a, n->b, "=="); break;
case EXP_NE: printbinary(level, n->a, n->b, "!="); break;
case EXP_EQ3: printbinary(level, n->a, n->b, "==="); break;
case EXP_NE3: printbinary(level, n->a, n->b, "!=="); break;
case EXP_LT: printbinary(level, n->a, n->b, "<"); break;
case EXP_GT: printbinary(level, n->a, n->b, ">"); break;
case EXP_LE: printbinary(level, n->a, n->b, "<="); break;
case EXP_GE: printbinary(level, n->a, n->b, ">="); break;
case EXP_INSTANCEOF: printbinary(level, n->a, n->b, "instanceof"); break;
case EXP_IN: printbinary(level, n->a, n->b, "in"); break;
case EXP_SHL: printbinary(level, n->a, n->b, "<<"); break;
case EXP_SHR: printbinary(level, n->a, n->b, ">>"); break;
case EXP_USHR: printbinary(level, n->a, n->b, ">>>"); break;
case EXP_ADD: printbinary(level, n->a, n->b, "+"); break;
case EXP_SUB: printbinary(level, n->a, n->b, "-"); break;
case EXP_MUL: printbinary(level, n->a, n->b, "*"); break;
case EXP_DIV: printbinary(level, n->a, n->b, "/"); break;
case EXP_MOD: printbinary(level, n->a, n->b, "%"); break;
case EXP_ASS: printbinary(level, n->a, n->b, "="); break;
case EXP_ASS_MUL: printbinary(level, n->a, n->b, "*="); break;
case EXP_ASS_DIV: printbinary(level, n->a, n->b, "/="); break;
case EXP_ASS_MOD: printbinary(level, n->a, n->b, "%="); break;
case EXP_ASS_ADD: printbinary(level, n->a, n->b, "+="); break;
case EXP_ASS_SUB: printbinary(level, n->a, n->b, "-="); break;
case EXP_ASS_SHL: printbinary(level, n->a, n->b, "<<="); break;
case EXP_ASS_SHR: printbinary(level, n->a, n->b, ">>="); break;
case EXP_ASS_USHR: printbinary(level, n->a, n->b, ">>>="); break;
case EXP_ASS_BITAND: printbinary(level, n->a, n->b, "&="); break;
case EXP_ASS_BITXOR: printbinary(level, n->a, n->b, "^="); break;
case EXP_ASS_BITOR: printbinary(level, n->a, n->b, "|="); break;
default:
printf("(%s", strast(n->type));
if (n->a) { putchar(' '); printast(n->a, level); }
if (n->b) { putchar(' '); printast(n->b, level); }
if (n->c) { putchar(' '); printast(n->c, level); }
if (n->d) { putchar(' '); printast(n->d, level); }
putchar(')');
break;
}
}