ref: 9db2fce3a21165cda44ad16a1a0ede81246b52fd
parent: 7e40d3fefd100aa948fa1ed8bf900fea73d4df9c
author: Tor Andersson <tor.andersson@artifex.com>
date: Fri Jan 10 14:50:01 EST 2014
Add proper pretty-printing functions. jsP_dumpsyntax to print as javascript. jsP_dumplist to print as s-expressions.
--- a/js.h
+++ b/js.h
@@ -11,6 +11,7 @@
typedef struct js_State js_State;
typedef struct js_StringNode js_StringNode;
+typedef struct js_Ast js_Ast;
typedef int (*js_CFunction)(js_State *J);
--- /dev/null
+++ b/jsdump.c
@@ -1,0 +1,570 @@
+#include "js.h"
+#include "jsparse.h"
+
+#include <assert.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);
+}
+
+static inline void ps(const char *s)
+{
+ fputs(s, stdout);
+}
+
+static inline void in(int d)
+{
+ while (d-- > 0)
+ putchar('\t');
+}
+
+static inline void nl(void)
+{
+ putchar('\n');
+}
+
+static void pargs(int d, js_Ast *list)
+{
+ while (list) {
+ assert(list->type == AST_LIST);
+ pexpi(d, 0, list->a);
+ list = list->b;
+ if (list)
+ ps(", ");
+ }
+}
+
+static void parray(int d, js_Ast *list)
+{
+ ps("[");
+ while (list) {
+ assert(list->type == AST_LIST);
+ pexpi(d, 0, list->a);
+ list = list->b;
+ if (list)
+ ps(", ");
+ }
+ ps("]");
+}
+
+static void pobject(int d, js_Ast *list)
+{
+ ps("{");
+ while (list) {
+ js_Ast *kv = list->a;
+ assert(list->type == AST_LIST);
+ switch (kv->type) {
+ case EXP_PROP_VAL:
+ pexpi(d, 0, kv->a);
+ ps(": ");
+ pexpi(d, 0, kv->b);
+ break;
+ case EXP_PROP_GET:
+ ps("get ");
+ pexpi(d, 0, kv->a);
+ ps("() {\n");
+ pstmlist(d, kv->b);
+ in(d); ps("}");
+ break;
+ case EXP_PROP_SET:
+ ps("set ");
+ pexpi(d, 0, kv->a);
+ ps("(");
+ pexpi(d, 0, kv->b);
+ ps(") {\n");
+ pstmlist(d, kv->c);
+ in(d); ps("}");
+ break;
+ }
+ list = list->b;
+ if (list)
+ ps(", ");
+ }
+ ps("}");
+}
+
+static void pstr(const char *s)
+{
+ pc('"');
+ while (*s) {
+ if (*s == '"')
+ ps("\\\"");
+ else
+ pc(*s);
+ ++s;
+ }
+ pc('"');
+}
+
+static void pbin(int d, int i, js_Ast *exp, const char *op)
+{
+ if (i) pc('(');
+ pexpi(d, 1, exp->a);
+ ps(op);
+ pexpi(d, 1, exp->b);
+ if (i) pc(')');
+}
+
+static void puna(int d, int i, js_Ast *exp, const char *pre, const char *suf)
+{
+ if (i) pc('(');
+ ps(pre);
+ pexpi(d, 1, exp->a);
+ ps(suf);
+ if (i) pc(')');
+}
+
+static void pexpi(int d, int i, js_Ast *exp)
+{
+ switch (exp->type) {
+ case AST_IDENTIFIER: ps(exp->string); break;
+ case AST_NUMBER: printf("%.9g", exp->number); break;
+ case AST_STRING: pstr(exp->string); break;
+ case AST_REGEXP: pc('/'); ps(exp->string); pc('/'); break;
+
+ case EXP_NULL: ps("null"); break;
+ case EXP_TRUE: ps("true"); break;
+ case EXP_FALSE: ps("false"); break;
+ case EXP_THIS: ps("this"); break;
+
+ case EXP_OBJECT: pobject(d, exp->a); break;
+ case EXP_ARRAY: parray(d, exp->a); break;
+
+ case EXP_DELETE: puna(d, i, exp, "delete ", ""); break;
+ case EXP_VOID: puna(d, i, exp, "void ", ""); break;
+ case EXP_TYPEOF: puna(d, i, exp, "typeof ", ""); break;
+ case EXP_PREINC: puna(d, i, exp, "++", ""); break;
+ case EXP_PREDEC: puna(d, i, exp, "--", ""); break;
+ case EXP_POSTINC: puna(d, i, exp, "", "++"); break;
+ case EXP_POSTDEC: puna(d, i, exp, "", "--"); break;
+ case EXP_POS: puna(d, i, exp, "+", ""); break;
+ case EXP_NEG: puna(d, i, exp, "-", ""); break;
+ case EXP_BITNOT: puna(d, i, exp, "~", ""); break;
+ case EXP_LOGNOT: puna(d, i, exp, "!", ""); break;
+
+ case EXP_LOGOR: pbin(d, i, exp, " || "); break;
+ case EXP_LOGAND: pbin(d, i, exp, " && "); break;
+ case EXP_BITOR: pbin(d, i, exp, " | "); break;
+ case EXP_BITXOR: pbin(d, i, exp, " ^ "); break;
+ case EXP_BITAND: pbin(d, i, exp, " & "); break;
+ case EXP_EQ: pbin(d, i, exp, " == "); break;
+ case EXP_NE: pbin(d, i, exp, " != "); break;
+ case EXP_EQ3: pbin(d, i, exp, " === "); break;
+ case EXP_NE3: pbin(d, i, exp, " !== "); break;
+ case EXP_LT: pbin(d, i, exp, " < "); break;
+ case EXP_GT: pbin(d, i, exp, " > "); break;
+ case EXP_LE: pbin(d, i, exp, " <= "); break;
+ case EXP_GE: pbin(d, i, exp, " >= "); break;
+ case EXP_INSTANCEOF: pbin(d, i, exp, " instanceof "); break;
+ case EXP_IN: pbin(d, i, exp, " in "); break;
+ case EXP_SHL: pbin(d, i, exp, " << "); break;
+ case EXP_SHR: pbin(d, i, exp, " >> "); break;
+ case EXP_USHR: pbin(d, i, exp, " >>> "); break;
+ case EXP_ADD: pbin(d, i, exp, " + "); break;
+ case EXP_SUB: pbin(d, i, exp, " - "); break;
+ case EXP_MUL: pbin(d, i, exp, " * "); break;
+ case EXP_DIV: pbin(d, i, exp, " / "); break;
+ case EXP_MOD: pbin(d, i, exp, " % "); break;
+ case EXP_ASS: pbin(d, i, exp, " = "); break;
+ case EXP_ASS_MUL: pbin(d, i, exp, " *= "); break;
+ case EXP_ASS_DIV: pbin(d, i, exp, " /= "); break;
+ case EXP_ASS_MOD: pbin(d, i, exp, " %= "); break;
+ case EXP_ASS_ADD: pbin(d, i, exp, " += "); break;
+ case EXP_ASS_SUB: pbin(d, i, exp, " -= "); break;
+ case EXP_ASS_SHL: pbin(d, i, exp, " <<= "); break;
+ case EXP_ASS_SHR: pbin(d, i, exp, " >>= "); break;
+ case EXP_ASS_USHR: pbin(d, i, exp, " >>>= "); break;
+ case EXP_ASS_BITAND: pbin(d, i, exp, " &= "); break;
+ case EXP_ASS_BITXOR: pbin(d, i, exp, " ^= "); break;
+ case EXP_ASS_BITOR: pbin(d, i, exp, " |= "); break;
+
+ case EXP_COMMA: pbin(d, 1, exp, ", "); break;
+
+ case EXP_COND:
+ if (i) pc('(');
+ pexpi(d, 1, exp->a);
+ ps(" ? ");
+ pexpi(d, 1, exp->b);
+ ps(" : ");
+ pexpi(d, 1, exp->c);
+ if (i) pc(')');
+ break;
+
+ case EXP_INDEX:
+ if (i) pc('(');
+ pexpi(d, 1, exp->a);
+ pc('[');
+ pexpi(d, 0, exp->b);
+ pc(']');
+ if (i) pc(')');
+ break;
+
+ case EXP_MEMBER:
+ if (i) pc('(');
+ pexpi(d, 1, exp->a);
+ pc('.');
+ pexpi(d, 1, exp->b);
+ if (i) pc(')');
+ break;
+
+ case EXP_CALL:
+ if (i) pc('(');
+ pexpi(d, 1, exp->a);
+ pc('(');
+ pargs(d, exp->b);
+ pc(')');
+ if (i) pc(')');
+ break;
+
+ case EXP_NEW:
+ if (i) pc('(');
+ ps("new ");
+ pexpi(d, 1, exp->a);
+ pc('(');
+ pargs(d, exp->b);
+ pc(')');
+ if (i) pc(')');
+ break;
+
+ case EXP_FUNC:
+ ps("(function ");
+ if (exp->a) pexpi(d, 1, exp->a);
+ pc('(');
+ pargs(d, exp->b);
+ ps(") {\n");
+ pstmlist(d, exp->c);
+ in(d); ps("})");
+ break;
+
+ default:
+ ps("<UNKNOWN>");
+ break;
+ }
+}
+
+static void pexp(int d, js_Ast *exp)
+{
+ pexpi(d, 0, exp);
+}
+
+static void pvar(int d, js_Ast *var)
+{
+ assert(var->type == EXP_VAR);
+ pexp(d, var->a);
+ if (var->b) {
+ ps(" = ");
+ pexp(d, var->b);
+ }
+}
+
+static void pvarlist(int d, js_Ast *list)
+{
+ while (list) {
+ assert(list->type == AST_LIST);
+ pvar(d, list->a);
+ list = list->b;
+ if (list)
+ ps(", ");
+ }
+}
+
+static void pblock(int d, js_Ast *block)
+{
+ assert(block->type == STM_BLOCK);
+ in(d); ps("{\n");
+ pstmlist(d, block->a);
+ in(d); pc('}');
+}
+
+static void pstmh(int d, js_Ast *stm)
+{
+ if (stm->type == STM_BLOCK)
+ pblock(d, stm);
+ else
+ pstm(d+1, stm);
+}
+
+static void pcaselist(int d, js_Ast *list)
+{
+ while (list) {
+ js_Ast *stm = list->a;
+ if (stm->type == STM_CASE) {
+ in(d); ps("case "); pexp(d, stm->a); ps(":\n");
+ pstmlist(d, stm->b);
+ }
+ if (stm->type == STM_DEFAULT) {
+ in(d); ps("default:\n");
+ pstmlist(d, stm->a);
+ }
+ list = list->b;
+ }
+}
+
+static void pstm(int d, js_Ast *stm)
+{
+ if (stm->type == STM_BLOCK) {
+ pblock(d, stm);
+ return;
+ }
+
+ in(d);
+
+ switch (stm->type) {
+ case STM_FUNC:
+ ps("function ");
+ pexpi(d, 1, stm->a);
+ pc('(');
+ pargs(d, stm->b);
+ ps(")\n");
+ in(d); ps("{\n");
+ pstmlist(d, stm->c);
+ in(d); ps("}");
+ break;
+
+ case STM_NOP:
+ pc(';');
+ break;
+
+ case STM_VAR:
+ ps("var ");
+ pvarlist(d, stm->a);
+ ps(";");
+ break;
+
+ case STM_IF:
+ ps("if ("); pexp(d, stm->a); ps(")\n");
+ pstmh(d, stm->b);
+ if (stm->c) {
+ nl(); in(d); ps("else\n");
+ pstmh(d, stm->c);
+ }
+ break;
+
+ case STM_DO:
+ ps("do\n");
+ pstmh(d, stm->a);
+ nl();
+ in(d); ps("while ("); pexp(d, stm->b); ps(");");
+ break;
+
+ case STM_WHILE:
+ ps("while ("); pexp(d, stm->a); ps(")\n");
+ pstmh(d, stm->b);
+ break;
+
+ case STM_FOR:
+ ps("for (");
+ pexp(d, stm->a); ps("; ");
+ pexp(d, stm->b); ps("; ");
+ pexp(d, stm->c); ps(")\n");
+ pstmh(d, stm->d);
+ break;
+ case STM_FOR_VAR:
+ ps("for (var ");
+ pvarlist(d, stm->a); ps("; ");
+ pexp(d, stm->b); ps("; ");
+ pexp(d, stm->c); ps(")\n");
+ pstmh(d, stm->d);
+ break;
+ case STM_FOR_IN:
+ ps("for (");
+ pexp(d, stm->a); ps(" in ");
+ pexp(d, stm->b); ps(")\n");
+ pstmh(d, stm->c);
+ break;
+ case STM_FOR_IN_VAR:
+ ps("for (var ");
+ pvarlist(d, stm->a); ps(" in ");
+ pexp(d, stm->b); ps(")\n");
+ pstmh(d, stm->c);
+ break;
+
+ case STM_CONTINUE:
+ if (stm->a) {
+ ps("continue "); pexp(d, stm->a); ps(";");
+ } else {
+ ps("continue;");
+ }
+ break;
+
+ case STM_BREAK:
+ if (stm->a) {
+ ps("break "); pexp(d, stm->a); ps(";");
+ } else {
+ ps("break;");
+ }
+ break;
+
+ case STM_RETURN:
+ if (stm->a) {
+ ps("return "); pexp(d, stm->a); ps(";");
+ } else {
+ ps("return;");
+ }
+ break;
+
+ case STM_WITH:
+ ps("with ("); pexp(d, stm->a); ps(")\n");
+ pblock(d, stm->b);
+ break;
+
+ case STM_SWITCH:
+ ps("switch (");
+ pexp(d, stm->a);
+ ps(")\n");
+ in(d); ps("{\n");
+ pcaselist(d, stm->b);
+ in(d); ps("}");
+ break;
+
+ case STM_THROW:
+ ps("throw "); pexp(d, stm->a); ps(";");
+ break;
+
+ case STM_TRY:
+ ps("try\n");
+ pstmh(d, stm->a);
+ if (stm->b && stm->c) {
+ nl(); in(d); ps("catch ("); pexp(d, stm->b); ps(")\n");
+ pstmh(d, stm->c);
+ }
+ if (stm->d) {
+ nl(); in(d); ps("finally\n");
+ pstmh(d, stm->d);
+ }
+ break;
+
+ case STM_LABEL:
+ pexp(d, stm->a); ps(": "); pstm(d, stm->b);
+ break;
+
+ case STM_DEBUGGER:
+ ps("debugger;");
+ break;
+
+ default:
+ pexp(d, stm); pc(';');
+ }
+}
+
+static void pstmlist(int d, js_Ast *list)
+{
+ while (list) {
+ assert(list->type == AST_LIST);
+ pstm(d+1, list->a);
+ nl();
+ list = list->b;
+ }
+}
+
+void jsP_dumpsyntax(js_State *J, js_Ast *prog)
+{
+ if (prog->type == AST_LIST)
+ pstmlist(-1, prog);
+ else {
+ pstm(0, prog);
+ pc('\n');
+ }
+}
+
+static const char *stype[] = {
+ "list", "ident", "number", "string", "regexp", "null",
+ "true", "false", "this", "array", "object",
+ "prop_val", "prop_get", "prop_set", "index",
+ "member", "call", "new", "funexp", "delete",
+ "void", "typeof", "preinc", "predec", "postinc",
+ "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", "cond",
+ "ass", "ass_mul", "ass_div", "ass_mod", "ass_add",
+ "ass_sub", "ass_shl", "ass_shr", "ass_ushr",
+ "ass_bitand", "ass_bitxor", "ass_bitor", "comma",
+ "var", "block", "fundec", "nop", "var", "if",
+ "do", "while", "for", "for_var", "for_in",
+ "for_in_var", "continue", "break", "return",
+ "with", "switch", "throw", "try", "label",
+ "case", "default", "debugger",
+};
+
+static void snode(int d, js_Ast *node)
+{
+ void (*afun)(int,js_Ast*) = snode;
+ void (*bfun)(int,js_Ast*) = snode;
+ void (*cfun)(int,js_Ast*) = snode;
+ void (*dfun)(int,js_Ast*) = snode;
+
+ if (!node) {
+ return;
+ }
+
+ if (node->type == AST_LIST) {
+ slist(d, node);
+ return;
+ }
+
+ pc('(');
+ ps(stype[node->type]);
+ switch (node->type) {
+ case AST_IDENTIFIER: pc(' '); ps(node->string); break;
+ case AST_STRING: pc(' '); pstr(node->string); break;
+ case AST_REGEXP: printf(" /%s/", node->string); break;
+ case AST_NUMBER: printf(" %.9g", node->number); break;
+ case STM_BLOCK: afun = sblock; break;
+ case STM_FUNC: case EXP_FUNC: cfun = sblock; break;
+ case STM_SWITCH: bfun = sblock; break;
+ case STM_CASE: bfun = sblock; break;
+ case STM_DEFAULT: afun = sblock; break;
+ }
+ if (node->a) { pc(' '); afun(d, node->a); }
+ if (node->b) { pc(' '); bfun(d, node->b); }
+ if (node->c) { pc(' '); cfun(d, node->c); }
+ if (node->d) { pc(' '); dfun(d, node->d); }
+ pc(')');
+}
+
+static void slist(int d, js_Ast *list)
+{
+ pc('[');
+ while (list) {
+ assert(list->type == AST_LIST);
+ snode(d, list->a);
+ list = list->b;
+ if (list)
+ pc(' ');
+ }
+ pc(']');
+}
+
+static void sblock(int d, js_Ast *list)
+{
+ ps("[\n");
+ in(d+1);
+ while (list) {
+ assert(list->type == AST_LIST);
+ snode(d+1, list->a);
+ list = list->b;
+ if (list) {
+ pc('\n');
+ in(d+1);
+ }
+ }
+ pc('\n'); in(d); pc(']');
+}
+
+void jsP_dumplist(js_State *J, js_Ast *prog)
+{
+ if (prog->type == AST_LIST)
+ sblock(0, prog);
+ else
+ snode(0, prog);
+ pc('\n');
+}
--- a/jsload.c
+++ b/jsload.c
@@ -5,8 +5,9 @@
{
js_Ast *prog = jsP_parse(J, filename, source);
if (prog) {
- jsP_foldconstants(J, prog);
- jsP_pretty(J, prog);
+ jsP_optimize(J, prog);
+ jsP_dumpsyntax(J, prog);
+ jsP_dumplist(J, prog);
jsP_freeparse(J);
return 0;
}
--- a/jsoptim.c
+++ b/jsoptim.c
@@ -79,7 +79,7 @@
return 0;
}
-void jsP_foldconstants(js_State *J, js_Ast *prog)
+void jsP_optimize(js_State *J, js_Ast *prog)
{
double x;
foldnumber(prog, &x);
--- a/jsparse.h
+++ b/jsparse.h
@@ -1,8 +1,6 @@
#ifndef js_parse_h
#define js_parse_h
-typedef struct js_Ast js_Ast;
-
struct js_Ast
{
int type;
@@ -124,7 +122,8 @@
js_Ast *jsP_parse(js_State *J, const char *filename, const char *source);
void jsP_freeparse(js_State *J);
-void jsP_foldconstants(js_State *J, js_Ast *prog);
-void jsP_pretty(js_State *J, js_Ast *prog);
+void jsP_optimize(js_State *J, js_Ast *prog);
+void jsP_dumpsyntax(js_State *J, js_Ast *prog);
+void jsP_dumplist(js_State *J, js_Ast *prog);
#endif
--- a/jspretty.c
+++ /dev/null
@@ -1,518 +1,0 @@
-#include "js.h"
-#include "jsparse.h"
-
-static void printast(js_Ast *n, int level);
-
-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 EXP_VAR: return "VAR";
- 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);
- }
-}
-
-static 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(")");
-}
-
-static void printast(js_Ast *n, int level)
-{
- switch (n->type) {
- case AST_IDENTIFIER: printf("%s", n->string); return;
- case AST_NUMBER: printf("%g", n->number); return;
- case AST_STRING: printf("'%s'", n->string); return;
- case AST_REGEXP: printf("/%s/", n->string); 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 EXP_VAR:
- printast(n->a, level);
- if (n->b) {
- printf(" = ");
- printast(n->b, level);
- }
- 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(") {\n");
- printblock(n->b, level);
- putchar('\n');
- indent(level);
- printf("}");
- 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 STM_FUNC:
- printf("function ");
- printast(n->a, level);
- printf("(");
- printlist(n->b, level, ", ");
- printf(")\n");
- indent(level);
- printf("{\n");
- printblock(n->c, level + 1);
- printf("\n");
- indent(level);
- printf("}");
- break;
-
- case EXP_FUNC:
- printf("(function ");
- if (n->a)
- printast(n->a, level);
- printf("(");
- printlist(n->b, level, ", ");
- printf(") {\n");
- printblock(n->c, level + 1);
- printf("\n");
- indent(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;
- }
-}
-
-void jsP_pretty(js_State *J, js_Ast *prog)
-{
- printblock(prog, 0);
- putchar('\n');
-}
--- a/jsstate.h
+++ b/jsstate.h
@@ -1,8 +1,6 @@
#ifndef js_state_h
#define js_state_h
-typedef struct js_Ast js_Ast;
-
struct js_State
{
jmp_buf jb; /* setjmp buffer for error handling in parser */