ref: dd149b98bd600ce2673d9123bacbafa6b58080af
parent: d28346577753a99119c9a19b7020e7edc91c44be
author: Tor Andersson <tor.andersson@artifex.com>
date: Fri Dec 2 09:54:27 EST 2022
Split debug printing of bytecode etc into "pp" tool.
--- a/Makefile
+++ b/Makefile
@@ -63,16 +63,17 @@
static: $(OUT)/libmujs.a
shared: $(OUT)/libmujs.$(SO_EXT)
-astnames.h: jsparse.h
- grep -E '(AST|EXP|STM)_' jsparse.h | sed 's/^[^A-Z]*\(AST_\)*/"/;s/,.*/",/' | tr A-Z a-z > $@
+astnames.h: jsi.h
+ grep -E '\<(AST|EXP|STM)_' jsi.h | sed 's/^[^A-Z]*\(AST_\)*/"/;s/,.*/",/' | tr A-Z a-z > $@
-opnames.h: jscompile.h
- grep -E 'OP_' jscompile.h | sed 's/^[^A-Z]*OP_/"/;s/,.*/",/' | tr A-Z a-z > $@
+opnames.h: jsi.h
+ grep -E '\<OP_' jsi.h | sed 's/^[^A-Z]*OP_/"/;s/,.*/",/' | tr A-Z a-z > $@
+
one.c: $(SRCS)
ls $(SRCS) | awk '{print "#include \""$$1"\""}' > $@
-jsdump.c: astnames.h opnames.h
+pp.c: astnames.h opnames.h
$(OUT)/%.o: %.c $(HDRS)
@ mkdir -p $(@D)
--- a/jscompile.c
+++ b/jscompile.c
@@ -775,7 +775,7 @@
break;
default:
- jsC_error(J, exp, "unknown expression: (%s)", jsP_aststring(exp->type));
+ jsC_error(J, exp, "unknown expression type");
}
}
--- a/jsdump.c
+++ /dev/null
@@ -1,939 +1,0 @@
-#include "jsi.h"
-
-#include "utf.h"
-
-#include <assert.h>
-
-static const char *astname[] = {
-#include "astnames.h"
-NULL
-};
-
-static const char *opname[] = {
-#include "opnames.h"
-NULL
-};
-
-static int minify = 0;
-
-const char *jsP_aststring(enum js_AstType type)
-{
- if (type < nelem(astname)-1)
- return astname[type];
- return "<unknown>";
-}
-
-const char *jsC_opcodestring(enum js_OpCode opcode)
-{
- if (opcode < nelem(opname)-1)
- return opname[opcode];
- return "<unknown>";
-}
-
-static int prec(enum js_AstType type)
-{
- switch (type) {
- case AST_IDENTIFIER:
- case EXP_IDENTIFIER:
- case EXP_NUMBER:
- case EXP_STRING:
- case EXP_REGEXP:
- case EXP_UNDEF:
- case EXP_NULL:
- case EXP_TRUE:
- case EXP_FALSE:
- case EXP_THIS:
- case EXP_ARRAY:
- case EXP_OBJECT:
- return 170;
-
- case EXP_FUN:
- case EXP_INDEX:
- case EXP_MEMBER:
- case EXP_CALL:
- case EXP_NEW:
- return 160;
-
- case EXP_POSTINC:
- case EXP_POSTDEC:
- return 150;
-
- case EXP_DELETE:
- case EXP_VOID:
- case EXP_TYPEOF:
- case EXP_PREINC:
- case EXP_PREDEC:
- case EXP_POS:
- case EXP_NEG:
- case EXP_BITNOT:
- case EXP_LOGNOT:
- return 140;
-
- case EXP_MOD:
- case EXP_DIV:
- case EXP_MUL:
- return 130;
-
- case EXP_SUB:
- case EXP_ADD:
- return 120;
-
- case EXP_USHR:
- case EXP_SHR:
- case EXP_SHL:
- return 110;
-
- case EXP_IN:
- case EXP_INSTANCEOF:
- case EXP_GE:
- case EXP_LE:
- case EXP_GT:
- case EXP_LT:
- return 100;
-
- case EXP_STRICTNE:
- case EXP_STRICTEQ:
- case EXP_NE:
- case EXP_EQ:
- return 90;
-
- case EXP_BITAND: return 80;
- case EXP_BITXOR: return 70;
- case EXP_BITOR: return 60;
- case EXP_LOGAND: return 50;
- case EXP_LOGOR: return 40;
-
- case EXP_COND:
- return 30;
-
- case EXP_ASS:
- case EXP_ASS_MUL:
- case EXP_ASS_DIV:
- case EXP_ASS_MOD:
- case EXP_ASS_ADD:
- case EXP_ASS_SUB:
- case EXP_ASS_SHL:
- case EXP_ASS_SHR:
- case EXP_ASS_USHR:
- case EXP_ASS_BITAND:
- case EXP_ASS_BITXOR:
- case EXP_ASS_BITOR:
- return 20;
-
-#define COMMA 15
-
- case EXP_COMMA:
- return 10;
-
- default:
- return 0;
- }
-}
-
-static void pc(int c)
-{
- putchar(c);
-}
-
-static void ps(const char *s)
-{
- fputs(s, stdout);
-}
-
-static void pn(int n)
-{
- printf("%d", n);
-}
-
-static void in(int d)
-{
- if (minify < 1)
- while (d-- > 0)
- putchar('\t');
-}
-
-static void nl(void)
-{
- if (minify < 2)
- putchar('\n');
-}
-
-static void sp(void)
-{
- if (minify < 1)
- putchar(' ');
-}
-
-static void comma(void)
-{
- putchar(',');
- sp();
-}
-
-/* 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) {
- assert(list->type == AST_LIST);
- pexpi(d, COMMA, list->a);
- list = list->b;
- if (list)
- comma();
- }
-}
-
-static void parray(int d, js_Ast *list)
-{
- pc('[');
- while (list) {
- assert(list->type == AST_LIST);
- pexpi(d, COMMA, list->a);
- list = list->b;
- if (list)
- comma();
- }
- pc(']');
-}
-
-static void pobject(int d, js_Ast *list)
-{
- pc('{');
- if (list) {
- nl();
- in(d+1);
- }
- while (list) {
- js_Ast *kv = list->a;
- assert(list->type == AST_LIST);
- switch (kv->type) {
- default: break;
- case EXP_PROP_VAL:
- pexpi(d+1, COMMA, kv->a);
- pc(':'); sp();
- pexpi(d+1, COMMA, kv->b);
- break;
- case EXP_PROP_GET:
- ps("get ");
- pexpi(d+1, COMMA, kv->a);
- ps("()"); sp(); pc('{'); nl();
- pstmlist(d+1, kv->c);
- in(d+1); pc('}');
- break;
- case EXP_PROP_SET:
- ps("set ");
- pexpi(d+1, COMMA, kv->a);
- pc('(');
- pargs(d+1, kv->b);
- pc(')'); sp(); pc('{'); nl();
- pstmlist(d+1, kv->c);
- in(d+1); pc('}');
- break;
- }
- list = list->b;
- if (list) {
- pc(',');
- nl();
- in(d+1);
- } else {
- nl();
- in(d);
- }
- }
- pc('}');
-}
-
-static void pstr(const char *s)
-{
- static const char *HEX = "0123456789ABCDEF";
- Rune c;
- pc(minify ? '\'' : '"');
- while (*s) {
- s += chartorune(&c, s);
- switch (c) {
- case '\'': ps("\\'"); break;
- case '"': ps("\\\""); break;
- case '\\': ps("\\\\"); break;
- case '\b': ps("\\b"); break;
- case '\f': ps("\\f"); break;
- case '\n': ps("\\n"); break;
- case '\r': ps("\\r"); break;
- case '\t': ps("\\t"); break;
- default:
- if (c < ' ' || c > 127) {
- ps("\\u");
- pc(HEX[(c>>12)&15]);
- pc(HEX[(c>>8)&15]);
- pc(HEX[(c>>4)&15]);
- pc(HEX[c&15]);
- } else {
- pc(c); break;
- }
- }
- }
- pc(minify ? '\'' : '"');
-}
-
-static void pregexp(const char *prog, int flags)
-{
- pc('/');
- while (*prog) {
- if (*prog == '/')
- pc('\\');
- pc(*prog);
- ++prog;
- }
- pc('/');
- if (flags & JS_REGEXP_G) pc('g');
- if (flags & JS_REGEXP_I) pc('i');
- if (flags & JS_REGEXP_M) pc('m');
-}
-
-static void pbin(int d, int p, js_Ast *exp, const char *op)
-{
- pexpi(d, p, exp->a);
- sp();
- ps(op);
- sp();
- pexpi(d, p, exp->b);
-}
-
-static void puna(int d, int p, js_Ast *exp, const char *pre, const char *suf)
-{
- ps(pre);
- pexpi(d, p, exp->a);
- ps(suf);
-}
-
-static void pexpi(int d, int p, js_Ast *exp)
-{
- int tp, paren;
-
- if (!exp) return;
-
- tp = prec(exp->type);
- paren = 0;
- if (tp < p) {
- pc('(');
- paren = 1;
- }
- p = tp;
-
- switch (exp->type) {
- case AST_IDENTIFIER: ps(exp->string); break;
- case EXP_IDENTIFIER: ps(exp->string); break;
- case EXP_NUMBER: printf("%.9g", exp->number); break;
- case EXP_STRING: pstr(exp->string); break;
- case EXP_REGEXP: pregexp(exp->string, exp->number); break;
-
- case EXP_UNDEF: 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, p, exp, "delete ", ""); break;
- case EXP_VOID: puna(d, p, exp, "void ", ""); break;
- case EXP_TYPEOF: puna(d, p, exp, "typeof ", ""); break;
- case EXP_PREINC: puna(d, p, exp, "++", ""); break;
- case EXP_PREDEC: puna(d, p, exp, "--", ""); break;
- case EXP_POSTINC: puna(d, p, exp, "", "++"); break;
- case EXP_POSTDEC: puna(d, p, exp, "", "--"); break;
- case EXP_POS: puna(d, p, exp, "+", ""); break;
- case EXP_NEG: puna(d, p, exp, "-", ""); break;
- case EXP_BITNOT: puna(d, p, exp, "~", ""); break;
- case EXP_LOGNOT: puna(d, p, exp, "!", ""); break;
-
- case EXP_LOGOR: pbin(d, p, exp, "||"); break;
- case EXP_LOGAND: pbin(d, p, exp, "&&"); break;
- case EXP_BITOR: pbin(d, p, exp, "|"); break;
- case EXP_BITXOR: pbin(d, p, exp, "^"); break;
- case EXP_BITAND: pbin(d, p, exp, "&"); break;
- case EXP_EQ: pbin(d, p, exp, "=="); break;
- case EXP_NE: pbin(d, p, exp, "!="); break;
- case EXP_STRICTEQ: pbin(d, p, exp, "==="); break;
- case EXP_STRICTNE: pbin(d, p, exp, "!=="); break;
- case EXP_LT: pbin(d, p, exp, "<"); break;
- case EXP_GT: pbin(d, p, exp, ">"); break;
- case EXP_LE: pbin(d, p, exp, "<="); break;
- case EXP_GE: pbin(d, p, exp, ">="); break;
- case EXP_IN: pbin(d, p, exp, "in"); break;
- case EXP_SHL: pbin(d, p, exp, "<<"); break;
- case EXP_SHR: pbin(d, p, exp, ">>"); break;
- case EXP_USHR: pbin(d, p, exp, ">>>"); break;
- case EXP_ADD: pbin(d, p, exp, "+"); break;
- case EXP_SUB: pbin(d, p, exp, "-"); break;
- case EXP_MUL: pbin(d, p, exp, "*"); break;
- case EXP_DIV: pbin(d, p, exp, "/"); break;
- case EXP_MOD: pbin(d, p, exp, "%"); break;
- case EXP_ASS: pbin(d, p, exp, "="); break;
- case EXP_ASS_MUL: pbin(d, p, exp, "*="); break;
- case EXP_ASS_DIV: pbin(d, p, exp, "/="); break;
- case EXP_ASS_MOD: pbin(d, p, exp, "%="); break;
- case EXP_ASS_ADD: pbin(d, p, exp, "+="); break;
- case EXP_ASS_SUB: pbin(d, p, exp, "-="); break;
- case EXP_ASS_SHL: pbin(d, p, exp, "<<="); break;
- case EXP_ASS_SHR: pbin(d, p, exp, ">>="); break;
- case EXP_ASS_USHR: pbin(d, p, exp, ">>>="); break;
- case EXP_ASS_BITAND: pbin(d, p, exp, "&="); break;
- case EXP_ASS_BITXOR: pbin(d, p, exp, "^="); break;
- case EXP_ASS_BITOR: pbin(d, p, exp, "|="); break;
-
- case EXP_INSTANCEOF:
- pexpi(d, p, exp->a);
- ps(" instanceof ");
- pexpi(d, p, exp->b);
- break;
-
- case EXP_COMMA:
- pexpi(d, p, exp->a);
- pc(','); sp();
- pexpi(d, p, exp->b);
- break;
-
- case EXP_COND:
- pexpi(d, p, exp->a);
- sp(); pc('?'); sp();
- pexpi(d, p, exp->b);
- sp(); pc(':'); sp();
- pexpi(d, p, exp->c);
- break;
-
- case EXP_INDEX:
- pexpi(d, p, exp->a);
- pc('[');
- pexpi(d, 0, exp->b);
- pc(']');
- break;
-
- case EXP_MEMBER:
- pexpi(d, p, exp->a);
- pc('.');
- pexpi(d, 0, exp->b);
- break;
-
- case EXP_CALL:
- pexpi(d, p, exp->a);
- pc('(');
- pargs(d, exp->b);
- pc(')');
- break;
-
- case EXP_NEW:
- ps("new ");
- pexpi(d, p, exp->a);
- pc('(');
- pargs(d, exp->b);
- pc(')');
- break;
-
- case EXP_FUN:
- if (p == 0) pc('(');
- ps("function ");
- pexpi(d, 0, exp->a);
- pc('(');
- pargs(d, exp->b);
- pc(')'); sp(); pc('{'); nl();
- pstmlist(d, exp->c);
- in(d); pc('}');
- if (p == 0) pc(')');
- break;
-
- default:
- ps("<UNKNOWN>");
- break;
- }
-
- if (paren) pc(')');
-}
-
-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) {
- sp(); pc('='); sp();
- 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)
- comma();
- }
-}
-
-static void pblock(int d, js_Ast *block)
-{
- assert(block->type == STM_BLOCK);
- pc('{'); nl();
- pstmlist(d, block->a);
- in(d); pc('}');
-}
-
-static void pstmh(int d, js_Ast *stm)
-{
- if (stm->type == STM_BLOCK) {
- sp();
- pblock(d, stm);
- } else {
- nl();
- 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); pc(':'); nl();
- pstmlist(d, stm->b);
- }
- if (stm->type == STM_DEFAULT) {
- in(d); ps("default:"); nl();
- 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 AST_FUNDEC:
- ps("function ");
- pexp(d, stm->a);
- pc('(');
- pargs(d, stm->b);
- pc(')'); sp(); pc('{'); nl();
- pstmlist(d, stm->c);
- in(d); pc('}');
- break;
-
- case STM_EMPTY:
- pc(';');
- break;
-
- case STM_VAR:
- ps("var ");
- pvarlist(d, stm->a);
- pc(';');
- break;
-
- case STM_IF:
- ps("if"); sp(); pc('('); pexp(d, stm->a); pc(')');
- pstmh(d, stm->b);
- if (stm->c) {
- nl(); in(d); ps("else");
- pstmh(d, stm->c);
- }
- break;
-
- case STM_DO:
- ps("do");
- pstmh(d, stm->a);
- nl();
- in(d); ps("while"); sp(); pc('('); pexp(d, stm->b); pc(')'); pc(';');
- break;
-
- case STM_WHILE:
- ps("while"); sp(); pc('('); pexp(d, stm->a); pc(')');
- pstmh(d, stm->b);
- break;
-
- case STM_FOR:
- ps("for"); sp(); pc('(');
- pexp(d, stm->a); pc(';'); sp();
- pexp(d, stm->b); pc(';'); sp();
- pexp(d, stm->c); pc(')');
- pstmh(d, stm->d);
- break;
- case STM_FOR_VAR:
- ps("for"); sp(); ps("(var ");
- pvarlist(d, stm->a); pc(';'); sp();
- pexp(d, stm->b); pc(';'); sp();
- pexp(d, stm->c); pc(')');
- pstmh(d, stm->d);
- break;
- case STM_FOR_IN:
- ps("for"); sp(); pc('(');
- pexp(d, stm->a); ps(" in ");
- pexp(d, stm->b); pc(')');
- pstmh(d, stm->c);
- break;
- case STM_FOR_IN_VAR:
- ps("for"); sp(); ps("(var ");
- pvarlist(d, stm->a); ps(" in ");
- pexp(d, stm->b); pc(')');
- pstmh(d, stm->c);
- break;
-
- case STM_CONTINUE:
- ps("continue");
- if (stm->a) {
- pc(' '); pexp(d, stm->a);
- }
- pc(';');
- break;
-
- case STM_BREAK:
- ps("break");
- if (stm->a) {
- pc(' '); pexp(d, stm->a);
- }
- pc(';');
- break;
-
- case STM_RETURN:
- ps("return");
- if (stm->a) {
- pc(' '); pexp(d, stm->a);
- }
- pc(';');
- break;
-
- case STM_WITH:
- ps("with"); sp(); pc('('); pexp(d, stm->a); pc(')');
- pstmh(d, stm->b);
- break;
-
- case STM_SWITCH:
- ps("switch"); sp(); pc('(');
- pexp(d, stm->a);
- pc(')'); sp(); pc('{'); nl();
- pcaselist(d, stm->b);
- in(d); pc('}');
- break;
-
- case STM_THROW:
- ps("throw "); pexp(d, stm->a); pc(';');
- break;
-
- case STM_TRY:
- ps("try");
- if (minify && stm->a->type != STM_BLOCK)
- pc(' ');
- pstmh(d, stm->a);
- if (stm->b && stm->c) {
- nl(); in(d); ps("catch"); sp(); pc('('); pexp(d, stm->b); pc(')');
- pstmh(d, stm->c);
- }
- if (stm->d) {
- nl(); in(d); ps("finally");
- pstmh(d, stm->d);
- }
- break;
-
- case STM_LABEL:
- pexp(d, stm->a); pc(':'); sp(); pstm(d, stm->b);
- break;
-
- case STM_DEBUGGER:
- ps("debugger");
- pc(';');
- 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, int dominify)
-{
- minify = dominify;
- if (prog) {
- if (prog->type == AST_LIST)
- pstmlist(-1, prog);
- else {
- pstm(0, prog);
- nl();
- }
- }
- if (minify > 1)
- putchar('\n');
-}
-
-/* S-expression list representation */
-
-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(astname[node->type]);
- pc(':');
- pn(node->line);
- switch (node->type) {
- default: break;
- case AST_IDENTIFIER: pc(' '); ps(node->string); break;
- case EXP_IDENTIFIER: pc(' '); ps(node->string); break;
- case EXP_STRING: pc(' '); pstr(node->string); break;
- case EXP_REGEXP: pc(' '); pregexp(node->string, node->number); break;
- case EXP_NUMBER: printf(" %.9g", node->number); break;
- case STM_BLOCK: afun = sblock; break;
- case AST_FUNDEC: case EXP_FUN: cfun = sblock; break;
- case EXP_PROP_GET: cfun = sblock; break;
- case EXP_PROP_SET: 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) {
- nl();
- in(d+1);
- }
- }
- nl(); in(d); pc(']');
-}
-
-void jsP_dumplist(js_State *J, js_Ast *prog)
-{
- minify = 0;
- if (prog) {
- if (prog->type == AST_LIST)
- sblock(0, prog);
- else
- snode(0, prog);
- nl();
- }
-}
-
-/* Compiled code */
-
-void jsC_dumpfunction(js_State *J, js_Function *F)
-{
- js_Instruction *p = F->code;
- js_Instruction *end = F->code + F->codelen;
- char *s;
- double n;
- int i;
-
- minify = 0;
-
- printf("%s(%d)\n", F->name, F->numparams);
- if (F->strict) printf("\tstrict\n");
- if (F->lightweight) printf("\tlightweight\n");
- if (F->arguments) printf("\targuments\n");
- printf("\tsource %s:%d\n", F->filename, F->line);
- for (i = 0; i < F->funlen; ++i)
- printf("\tfunction %d %s\n", i, F->funtab[i]->name);
- for (i = 0; i < F->varlen; ++i)
- printf("\tlocal %d %s\n", i + 1, F->vartab[i]);
-
- printf("{\n");
- while (p < end) {
- int ln = *p++;
- int c = *p++;
-
- printf("%5d(%3d): ", (int)(p - F->code) - 2, ln);
- ps(opname[c]);
-
- switch (c) {
- case OP_INTEGER:
- printf(" %ld", (long)((*p++) - 32768));
- break;
- case OP_NUMBER:
- memcpy(&n, p, sizeof(n));
- p += sizeof(n) / sizeof(*p);
- printf(" %.9g", n);
- break;
- case OP_STRING:
- memcpy(&s, p, sizeof(s));
- p += sizeof(s) / sizeof(*p);
- pc(' ');
- pstr(s);
- break;
- case OP_NEWREGEXP:
- pc(' ');
- memcpy(&s, p, sizeof(s));
- p += sizeof(s) / sizeof(*p);
- pregexp(s, *p++);
- break;
-
- case OP_GETVAR:
- case OP_HASVAR:
- case OP_SETVAR:
- case OP_DELVAR:
- case OP_GETPROP_S:
- case OP_SETPROP_S:
- case OP_DELPROP_S:
- case OP_CATCH:
- memcpy(&s, p, sizeof(s));
- p += sizeof(s) / sizeof(*p);
- pc(' ');
- ps(s);
- break;
-
- case OP_GETLOCAL:
- case OP_SETLOCAL:
- case OP_DELLOCAL:
- printf(" %s", F->vartab[*p++ - 1]);
- break;
-
- case OP_CLOSURE:
- case OP_CALL:
- case OP_NEW:
- case OP_JUMP:
- case OP_JTRUE:
- case OP_JFALSE:
- case OP_JCASE:
- case OP_TRY:
- printf(" %ld", (long)*p++);
- break;
- }
-
- nl();
- }
- printf("}\n");
-
- for (i = 0; i < F->funlen; ++i) {
- if (F->funtab[i] != F) {
- printf("function %d ", i);
- jsC_dumpfunction(J, F->funtab[i]);
- }
- }
-}
-
-/* Runtime values */
-
-void js_dumpvalue(js_State *J, js_Value v)
-{
- minify = 0;
- 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_TSHRSTR: printf("'%s'", v.u.shrstr); break;
- case JS_TLITSTR: printf("'%s'", v.u.litstr); break;
- case JS_TMEMSTR: printf("'%s'", v.u.memstr->p); break;
- case JS_TOBJECT:
- if (v.u.object == J->G) {
- printf("[Global]");
- break;
- }
- switch (v.u.object->type) {
- case JS_COBJECT: printf("[Object %p]", (void*)v.u.object); break;
- case JS_CARRAY: printf("[Array %p]", (void*)v.u.object); break;
- case JS_CFUNCTION:
- printf("[Function %p, %s, %s:%d]",
- (void*)v.u.object,
- v.u.object->u.f.function->name,
- v.u.object->u.f.function->filename,
- v.u.object->u.f.function->line);
- break;
- case JS_CSCRIPT: printf("[Script %s]", v.u.object->u.f.function->filename); break;
- case JS_CCFUNCTION: printf("[CFunction %s]", v.u.object->u.c.name); break;
- case JS_CBOOLEAN: printf("[Boolean %d]", v.u.object->u.boolean); break;
- case JS_CNUMBER: printf("[Number %g]", v.u.object->u.number); break;
- case JS_CSTRING: printf("[String'%s']", v.u.object->u.s.string); break;
- case JS_CERROR: printf("[Error]"); break;
- case JS_CARGUMENTS: printf("[Arguments %p]", (void*)v.u.object); break;
- case JS_CITERATOR: printf("[Iterator %p]", (void*)v.u.object); break;
- case JS_CUSERDATA:
- printf("[Userdata %s %p]", v.u.object->u.user.tag, v.u.object->u.user.data);
- break;
- default: printf("[Object %p]", (void*)v.u.object); break;
- }
- break;
- }
-}
-
-static void js_dumpproperty(js_State *J, js_Property *node)
-{
- minify = 0;
- if (node->left->level)
- js_dumpproperty(J, node->left);
- printf("\t%s: ", node->name);
- js_dumpvalue(J, node->value);
- printf(",\n");
- if (node->right->level)
- js_dumpproperty(J, node->right);
-}
-
-void js_dumpobject(js_State *J, js_Object *obj)
-{
- minify = 0;
- printf("{\n");
- if (obj->properties->level)
- js_dumpproperty(J, obj->properties);
- printf("}\n");
-}
--- a/jsi.h
+++ b/jsi.h
@@ -483,10 +483,6 @@
void jsV_unflattenarray(js_State *J, js_Object *obj);
void jsV_growarray(js_State *J, js_Object *obj);
-/* jsdump.c */
-void js_dumpobject(js_State *J, js_Object *obj);
-void js_dumpvalue(js_State *J, js_Value v);
-
/* Lexer */
enum
@@ -706,10 +702,6 @@
js_Ast *jsP_parse(js_State *J, const char *filename, const char *source);
void jsP_freeparse(js_State *J);
-const char *jsP_aststring(enum js_AstType type);
-void jsP_dumpsyntax(js_State *J, js_Ast *prog, int minify);
-void jsP_dumplist(js_State *J, js_Ast *prog);
-
/* Compiler */
enum js_OpCode
@@ -846,8 +838,6 @@
js_Function *jsC_compilefunction(js_State *J, js_Ast *prog);
js_Function *jsC_compilescript(js_State *J, js_Ast *prog, int default_strict);
-const char *jsC_opcodestring(enum js_OpCode opcode);
-void jsC_dumpfunction(js_State *J, js_Function *fun);
/* Builtins */
--- a/jsrun.c
+++ b/jsrun.c
@@ -1455,29 +1455,50 @@
/* Main interpreter loop */
-static void jsR_dumpstack(js_State *J)
+static void js_dumpvalue(js_State *J, js_Value v)
{
- int i;
- printf("stack {\n");
- for (i = 0; i < TOP; ++i) {
- putchar(i == BOT ? '>' : ' ');
- printf("%4d: ", i);
- js_dumpvalue(J, STACK[i]);
- putchar('\n');
+ 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_TSHRSTR: printf("'%s'", v.u.shrstr); break;
+ case JS_TLITSTR: printf("'%s'", v.u.litstr); break;
+ case JS_TMEMSTR: printf("'%s'", v.u.memstr->p); break;
+ case JS_TOBJECT:
+ if (v.u.object == J->G) {
+ printf("[Global]");
+ break;
+ }
+ switch (v.u.object->type) {
+ case JS_COBJECT: printf("[Object %p]", (void*)v.u.object); break;
+ case JS_CARRAY: printf("[Array %p]", (void*)v.u.object); break;
+ case JS_CFUNCTION:
+ printf("[Function %p, %s, %s:%d]",
+ (void*)v.u.object,
+ v.u.object->u.f.function->name,
+ v.u.object->u.f.function->filename,
+ v.u.object->u.f.function->line);
+ break;
+ case JS_CSCRIPT: printf("[Script %s]", v.u.object->u.f.function->filename); break;
+ case JS_CCFUNCTION: printf("[CFunction %s]", v.u.object->u.c.name); break;
+ case JS_CBOOLEAN: printf("[Boolean %d]", v.u.object->u.boolean); break;
+ case JS_CNUMBER: printf("[Number %g]", v.u.object->u.number); break;
+ case JS_CSTRING: printf("[String'%s']", v.u.object->u.s.string); break;
+ case JS_CERROR: printf("[Error]"); break;
+ case JS_CARGUMENTS: printf("[Arguments %p]", (void*)v.u.object); break;
+ case JS_CITERATOR: printf("[Iterator %p]", (void*)v.u.object); break;
+ case JS_CUSERDATA:
+ printf("[Userdata %s %p]", v.u.object->u.user.tag, v.u.object->u.user.data);
+ break;
+ default: printf("[Object %p]", (void*)v.u.object); break;
+ }
+ break;
}
- printf("}\n");
}
-static void jsR_dumpenvironment(js_State *J, js_Environment *E, int d)
+static void js_stacktrace(js_State *J)
{
- printf("scope %d ", d);
- js_dumpobject(J, E->variables);
- if (E->outer)
- jsR_dumpenvironment(J, E->outer, d+1);
-}
-
-void js_stacktrace(js_State *J)
-{
int n;
printf("stack trace:\n");
for (n = J->tracetop; n >= 0; --n) {
@@ -1494,15 +1515,22 @@
}
}
-void js_trap(js_State *J, int pc)
+static void js_dumpstack(js_State *J)
{
- if (pc > 0) {
- js_Function *F = STACK[BOT-1].u.object->u.f.function;
- printf("trap at %d in function ", pc);
- jsC_dumpfunction(J, F);
+ int i;
+ printf("stack {\n");
+ for (i = 0; i < TOP; ++i) {
+ putchar(i == BOT ? '>' : ' ');
+ printf("%4d: ", i);
+ js_dumpvalue(J, STACK[i]);
+ putchar('\n');
}
- jsR_dumpstack(J);
- jsR_dumpenvironment(J, J->E, 0);
+ printf("}\n");
+}
+
+void js_trap(js_State *J, int pc)
+{
+ js_dumpstack(J);
js_stacktrace(J);
}
--- a/one.c
+++ b/one.c
@@ -4,7 +4,6 @@
#include "jscompile.c"
#include "jsdate.c"
#include "jsdtoa.c"
-#include "jsdump.c"
#include "jserror.c"
#include "jsfunction.c"
#include "jsgc.c"
--- a/pp.c
+++ b/pp.c
@@ -6,26 +6,885 @@
*/
#include <stdio.h>
+#include <assert.h>
#include "jsi.h"
+#include "utf.h"
-static void js_ppstring(js_State *J, const char *filename, const char *source, int minify)
+static const char *astname[] = {
+#include "astnames.h"
+NULL
+};
+
+static const char *opname[] = {
+#include "opnames.h"
+NULL
+};
+
+static int format = 0;
+static int minify = 0;
+
+static void pc(int c)
{
+ putchar(c);
+}
+
+static void ps(const char *s)
+{
+ fputs(s, stdout);
+}
+
+static void in(int d)
+{
+ if (minify < 1)
+ while (d-- > 0)
+ putchar('\t');
+}
+
+static void nl(void)
+{
+ if (minify < 2)
+ putchar('\n');
+}
+
+static void sp(void)
+{
+ if (minify < 1)
+ putchar(' ');
+}
+
+static void comma(void)
+{
+ putchar(',');
+ sp();
+}
+
+static void pstr(const char *s)
+{
+ static const char *HEX = "0123456789ABCDEF";
+ Rune c;
+ pc(minify ? '\'' : '"');
+ while (*s) {
+ s += chartorune(&c, s);
+ switch (c) {
+ case '\'': ps("\\'"); break;
+ case '"': ps("\\\""); break;
+ case '\\': ps("\\\\"); break;
+ case '\b': ps("\\b"); break;
+ case '\f': ps("\\f"); break;
+ case '\n': ps("\\n"); break;
+ case '\r': ps("\\r"); break;
+ case '\t': ps("\\t"); break;
+ default:
+ if (c < ' ' || c > 127) {
+ ps("\\u");
+ pc(HEX[(c>>12)&15]);
+ pc(HEX[(c>>8)&15]);
+ pc(HEX[(c>>4)&15]);
+ pc(HEX[c&15]);
+ } else {
+ pc(c); break;
+ }
+ }
+ }
+ pc(minify ? '\'' : '"');
+}
+
+static void pregexp(const char *prog, int flags)
+{
+ pc('/');
+ while (*prog) {
+ if (*prog == '/')
+ pc('\\');
+ pc(*prog);
+ ++prog;
+ }
+ pc('/');
+ if (flags & JS_REGEXP_G) pc('g');
+ if (flags & JS_REGEXP_I) pc('i');
+ if (flags & JS_REGEXP_M) pc('m');
+}
+
+/* Bytecode */
+
+static void jsC_dumpfunction(js_State *J, js_Function *F)
+{
+ js_Instruction *p = F->code;
+ js_Instruction *end = F->code + F->codelen;
+ char *s;
+ double n;
+ int i;
+
+ printf("%s(%d)\n", F->name, F->numparams);
+ if (F->strict) printf("\tstrict\n");
+ if (F->lightweight) printf("\tlightweight\n");
+ if (F->arguments) printf("\targuments\n");
+ printf("\tsource %s:%d\n", F->filename, F->line);
+ for (i = 0; i < F->funlen; ++i)
+ printf("\tfunction %d %s\n", i, F->funtab[i]->name);
+ for (i = 0; i < F->varlen; ++i)
+ printf("\tlocal %d %s\n", i + 1, F->vartab[i]);
+
+ printf("{\n");
+ while (p < end) {
+ int ln = *p++;
+ int c = *p++;
+
+ printf("%5d(%3d): ", (int)(p - F->code) - 2, ln);
+ ps(opname[c]);
+
+ switch (c) {
+ case OP_INTEGER:
+ printf(" %ld", (long)((*p++) - 32768));
+ break;
+ case OP_NUMBER:
+ memcpy(&n, p, sizeof(n));
+ p += sizeof(n) / sizeof(*p);
+ printf(" %.9g", n);
+ break;
+ case OP_STRING:
+ memcpy(&s, p, sizeof(s));
+ p += sizeof(s) / sizeof(*p);
+ pc(' ');
+ pstr(s);
+ break;
+ case OP_NEWREGEXP:
+ pc(' ');
+ memcpy(&s, p, sizeof(s));
+ p += sizeof(s) / sizeof(*p);
+ pregexp(s, *p++);
+ break;
+
+ case OP_GETVAR:
+ case OP_HASVAR:
+ case OP_SETVAR:
+ case OP_DELVAR:
+ case OP_GETPROP_S:
+ case OP_SETPROP_S:
+ case OP_DELPROP_S:
+ case OP_CATCH:
+ memcpy(&s, p, sizeof(s));
+ p += sizeof(s) / sizeof(*p);
+ pc(' ');
+ ps(s);
+ break;
+
+ case OP_GETLOCAL:
+ case OP_SETLOCAL:
+ case OP_DELLOCAL:
+ printf(" %s", F->vartab[*p++ - 1]);
+ break;
+
+ case OP_CLOSURE:
+ case OP_CALL:
+ case OP_NEW:
+ case OP_JUMP:
+ case OP_JTRUE:
+ case OP_JFALSE:
+ case OP_JCASE:
+ case OP_TRY:
+ printf(" %ld", (long)*p++);
+ break;
+ }
+
+ putchar('\n');
+ }
+ printf("}\n");
+
+ for (i = 0; i < F->funlen; ++i) {
+ if (F->funtab[i] != F) {
+ printf("function %d ", i);
+ jsC_dumpfunction(J, F->funtab[i]);
+ }
+ }
+}
+
+/* Pretty-printed Javascript syntax */
+
+static int prec(enum js_AstType type)
+{
+ switch (type) {
+ case AST_IDENTIFIER:
+ case EXP_IDENTIFIER:
+ case EXP_NUMBER:
+ case EXP_STRING:
+ case EXP_REGEXP:
+ case EXP_UNDEF:
+ case EXP_NULL:
+ case EXP_TRUE:
+ case EXP_FALSE:
+ case EXP_THIS:
+ case EXP_ARRAY:
+ case EXP_OBJECT:
+ return 170;
+
+ case EXP_FUN:
+ case EXP_INDEX:
+ case EXP_MEMBER:
+ case EXP_CALL:
+ case EXP_NEW:
+ return 160;
+
+ case EXP_POSTINC:
+ case EXP_POSTDEC:
+ return 150;
+
+ case EXP_DELETE:
+ case EXP_VOID:
+ case EXP_TYPEOF:
+ case EXP_PREINC:
+ case EXP_PREDEC:
+ case EXP_POS:
+ case EXP_NEG:
+ case EXP_BITNOT:
+ case EXP_LOGNOT:
+ return 140;
+
+ case EXP_MOD:
+ case EXP_DIV:
+ case EXP_MUL:
+ return 130;
+
+ case EXP_SUB:
+ case EXP_ADD:
+ return 120;
+
+ case EXP_USHR:
+ case EXP_SHR:
+ case EXP_SHL:
+ return 110;
+
+ case EXP_IN:
+ case EXP_INSTANCEOF:
+ case EXP_GE:
+ case EXP_LE:
+ case EXP_GT:
+ case EXP_LT:
+ return 100;
+
+ case EXP_STRICTNE:
+ case EXP_STRICTEQ:
+ case EXP_NE:
+ case EXP_EQ:
+ return 90;
+
+ case EXP_BITAND: return 80;
+ case EXP_BITXOR: return 70;
+ case EXP_BITOR: return 60;
+ case EXP_LOGAND: return 50;
+ case EXP_LOGOR: return 40;
+
+ case EXP_COND:
+ return 30;
+
+ case EXP_ASS:
+ case EXP_ASS_MUL:
+ case EXP_ASS_DIV:
+ case EXP_ASS_MOD:
+ case EXP_ASS_ADD:
+ case EXP_ASS_SUB:
+ case EXP_ASS_SHL:
+ case EXP_ASS_SHR:
+ case EXP_ASS_USHR:
+ case EXP_ASS_BITAND:
+ case EXP_ASS_BITXOR:
+ case EXP_ASS_BITOR:
+ return 20;
+
+#define COMMA 15
+
+ case EXP_COMMA:
+ return 10;
+
+ default:
+ return 0;
+ }
+}
+
+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) {
+ assert(list->type == AST_LIST);
+ pexpi(d, COMMA, list->a);
+ list = list->b;
+ if (list)
+ comma();
+ }
+}
+
+static void parray(int d, js_Ast *list)
+{
+ pc('[');
+ while (list) {
+ assert(list->type == AST_LIST);
+ pexpi(d, COMMA, list->a);
+ list = list->b;
+ if (list)
+ comma();
+ }
+ pc(']');
+}
+
+static void pobject(int d, js_Ast *list)
+{
+ pc('{');
+ if (list) {
+ nl();
+ in(d+1);
+ }
+ while (list) {
+ js_Ast *kv = list->a;
+ assert(list->type == AST_LIST);
+ switch (kv->type) {
+ default: break;
+ case EXP_PROP_VAL:
+ pexpi(d+1, COMMA, kv->a);
+ pc(':'); sp();
+ pexpi(d+1, COMMA, kv->b);
+ break;
+ case EXP_PROP_GET:
+ ps("get ");
+ pexpi(d+1, COMMA, kv->a);
+ ps("()"); sp(); pc('{'); nl();
+ pstmlist(d+1, kv->c);
+ in(d+1); pc('}');
+ break;
+ case EXP_PROP_SET:
+ ps("set ");
+ pexpi(d+1, COMMA, kv->a);
+ pc('(');
+ pargs(d+1, kv->b);
+ pc(')'); sp(); pc('{'); nl();
+ pstmlist(d+1, kv->c);
+ in(d+1); pc('}');
+ break;
+ }
+ list = list->b;
+ if (list) {
+ pc(',');
+ nl();
+ in(d+1);
+ } else {
+ nl();
+ in(d);
+ }
+ }
+ pc('}');
+}
+
+static void pbin(int d, int p, js_Ast *exp, const char *op)
+{
+ pexpi(d, p, exp->a);
+ sp();
+ ps(op);
+ sp();
+ pexpi(d, p, exp->b);
+}
+
+static void puna(int d, int p, js_Ast *exp, const char *pre, const char *suf)
+{
+ ps(pre);
+ pexpi(d, p, exp->a);
+ ps(suf);
+}
+
+static void pexpi(int d, int p, js_Ast *exp)
+{
+ int tp, paren;
+
+ if (!exp) return;
+
+ tp = prec(exp->type);
+ paren = 0;
+ if (tp < p) {
+ pc('(');
+ paren = 1;
+ }
+ p = tp;
+
+ switch (exp->type) {
+ case AST_IDENTIFIER: ps(exp->string); break;
+ case EXP_IDENTIFIER: ps(exp->string); break;
+ case EXP_NUMBER: printf("%.9g", exp->number); break;
+ case EXP_STRING: pstr(exp->string); break;
+ case EXP_REGEXP: pregexp(exp->string, exp->number); break;
+
+ case EXP_UNDEF: 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, p, exp, "delete ", ""); break;
+ case EXP_VOID: puna(d, p, exp, "void ", ""); break;
+ case EXP_TYPEOF: puna(d, p, exp, "typeof ", ""); break;
+ case EXP_PREINC: puna(d, p, exp, "++", ""); break;
+ case EXP_PREDEC: puna(d, p, exp, "--", ""); break;
+ case EXP_POSTINC: puna(d, p, exp, "", "++"); break;
+ case EXP_POSTDEC: puna(d, p, exp, "", "--"); break;
+ case EXP_POS: puna(d, p, exp, "+", ""); break;
+ case EXP_NEG: puna(d, p, exp, "-", ""); break;
+ case EXP_BITNOT: puna(d, p, exp, "~", ""); break;
+ case EXP_LOGNOT: puna(d, p, exp, "!", ""); break;
+
+ case EXP_LOGOR: pbin(d, p, exp, "||"); break;
+ case EXP_LOGAND: pbin(d, p, exp, "&&"); break;
+ case EXP_BITOR: pbin(d, p, exp, "|"); break;
+ case EXP_BITXOR: pbin(d, p, exp, "^"); break;
+ case EXP_BITAND: pbin(d, p, exp, "&"); break;
+ case EXP_EQ: pbin(d, p, exp, "=="); break;
+ case EXP_NE: pbin(d, p, exp, "!="); break;
+ case EXP_STRICTEQ: pbin(d, p, exp, "==="); break;
+ case EXP_STRICTNE: pbin(d, p, exp, "!=="); break;
+ case EXP_LT: pbin(d, p, exp, "<"); break;
+ case EXP_GT: pbin(d, p, exp, ">"); break;
+ case EXP_LE: pbin(d, p, exp, "<="); break;
+ case EXP_GE: pbin(d, p, exp, ">="); break;
+ case EXP_IN: pbin(d, p, exp, "in"); break;
+ case EXP_SHL: pbin(d, p, exp, "<<"); break;
+ case EXP_SHR: pbin(d, p, exp, ">>"); break;
+ case EXP_USHR: pbin(d, p, exp, ">>>"); break;
+ case EXP_ADD: pbin(d, p, exp, "+"); break;
+ case EXP_SUB: pbin(d, p, exp, "-"); break;
+ case EXP_MUL: pbin(d, p, exp, "*"); break;
+ case EXP_DIV: pbin(d, p, exp, "/"); break;
+ case EXP_MOD: pbin(d, p, exp, "%"); break;
+ case EXP_ASS: pbin(d, p, exp, "="); break;
+ case EXP_ASS_MUL: pbin(d, p, exp, "*="); break;
+ case EXP_ASS_DIV: pbin(d, p, exp, "/="); break;
+ case EXP_ASS_MOD: pbin(d, p, exp, "%="); break;
+ case EXP_ASS_ADD: pbin(d, p, exp, "+="); break;
+ case EXP_ASS_SUB: pbin(d, p, exp, "-="); break;
+ case EXP_ASS_SHL: pbin(d, p, exp, "<<="); break;
+ case EXP_ASS_SHR: pbin(d, p, exp, ">>="); break;
+ case EXP_ASS_USHR: pbin(d, p, exp, ">>>="); break;
+ case EXP_ASS_BITAND: pbin(d, p, exp, "&="); break;
+ case EXP_ASS_BITXOR: pbin(d, p, exp, "^="); break;
+ case EXP_ASS_BITOR: pbin(d, p, exp, "|="); break;
+
+ case EXP_INSTANCEOF:
+ pexpi(d, p, exp->a);
+ ps(" instanceof ");
+ pexpi(d, p, exp->b);
+ break;
+
+ case EXP_COMMA:
+ pexpi(d, p, exp->a);
+ pc(','); sp();
+ pexpi(d, p, exp->b);
+ break;
+
+ case EXP_COND:
+ pexpi(d, p, exp->a);
+ sp(); pc('?'); sp();
+ pexpi(d, p, exp->b);
+ sp(); pc(':'); sp();
+ pexpi(d, p, exp->c);
+ break;
+
+ case EXP_INDEX:
+ pexpi(d, p, exp->a);
+ pc('[');
+ pexpi(d, 0, exp->b);
+ pc(']');
+ break;
+
+ case EXP_MEMBER:
+ pexpi(d, p, exp->a);
+ pc('.');
+ pexpi(d, 0, exp->b);
+ break;
+
+ case EXP_CALL:
+ pexpi(d, p, exp->a);
+ pc('(');
+ pargs(d, exp->b);
+ pc(')');
+ break;
+
+ case EXP_NEW:
+ ps("new ");
+ pexpi(d, p, exp->a);
+ pc('(');
+ pargs(d, exp->b);
+ pc(')');
+ break;
+
+ case EXP_FUN:
+ if (p == 0) pc('(');
+ ps("function ");
+ pexpi(d, 0, exp->a);
+ pc('(');
+ pargs(d, exp->b);
+ pc(')'); sp(); pc('{'); nl();
+ pstmlist(d, exp->c);
+ in(d); pc('}');
+ if (p == 0) pc(')');
+ break;
+
+ default:
+ ps("<UNKNOWN>");
+ break;
+ }
+
+ if (paren) pc(')');
+}
+
+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) {
+ sp(); pc('='); sp();
+ 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)
+ comma();
+ }
+}
+
+static void pblock(int d, js_Ast *block)
+{
+ assert(block->type == STM_BLOCK);
+ pc('{'); nl();
+ pstmlist(d, block->a);
+ in(d); pc('}');
+}
+
+static void pstmh(int d, js_Ast *stm)
+{
+ if (stm->type == STM_BLOCK) {
+ sp();
+ pblock(d, stm);
+ } else {
+ nl();
+ 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); pc(':'); nl();
+ pstmlist(d, stm->b);
+ }
+ if (stm->type == STM_DEFAULT) {
+ in(d); ps("default:"); nl();
+ 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 AST_FUNDEC:
+ ps("function ");
+ pexp(d, stm->a);
+ pc('(');
+ pargs(d, stm->b);
+ pc(')'); sp(); pc('{'); nl();
+ pstmlist(d, stm->c);
+ in(d); pc('}');
+ break;
+
+ case STM_EMPTY:
+ pc(';');
+ break;
+
+ case STM_VAR:
+ ps("var ");
+ pvarlist(d, stm->a);
+ pc(';');
+ break;
+
+ case STM_IF:
+ ps("if"); sp(); pc('('); pexp(d, stm->a); pc(')');
+ pstmh(d, stm->b);
+ if (stm->c) {
+ nl(); in(d); ps("else");
+ pstmh(d, stm->c);
+ }
+ break;
+
+ case STM_DO:
+ ps("do");
+ pstmh(d, stm->a);
+ nl();
+ in(d); ps("while"); sp(); pc('('); pexp(d, stm->b); pc(')'); pc(';');
+ break;
+
+ case STM_WHILE:
+ ps("while"); sp(); pc('('); pexp(d, stm->a); pc(')');
+ pstmh(d, stm->b);
+ break;
+
+ case STM_FOR:
+ ps("for"); sp(); pc('(');
+ pexp(d, stm->a); pc(';'); sp();
+ pexp(d, stm->b); pc(';'); sp();
+ pexp(d, stm->c); pc(')');
+ pstmh(d, stm->d);
+ break;
+ case STM_FOR_VAR:
+ ps("for"); sp(); ps("(var ");
+ pvarlist(d, stm->a); pc(';'); sp();
+ pexp(d, stm->b); pc(';'); sp();
+ pexp(d, stm->c); pc(')');
+ pstmh(d, stm->d);
+ break;
+ case STM_FOR_IN:
+ ps("for"); sp(); pc('(');
+ pexp(d, stm->a); ps(" in ");
+ pexp(d, stm->b); pc(')');
+ pstmh(d, stm->c);
+ break;
+ case STM_FOR_IN_VAR:
+ ps("for"); sp(); ps("(var ");
+ pvarlist(d, stm->a); ps(" in ");
+ pexp(d, stm->b); pc(')');
+ pstmh(d, stm->c);
+ break;
+
+ case STM_CONTINUE:
+ ps("continue");
+ if (stm->a) {
+ pc(' '); pexp(d, stm->a);
+ }
+ pc(';');
+ break;
+
+ case STM_BREAK:
+ ps("break");
+ if (stm->a) {
+ pc(' '); pexp(d, stm->a);
+ }
+ pc(';');
+ break;
+
+ case STM_RETURN:
+ ps("return");
+ if (stm->a) {
+ pc(' '); pexp(d, stm->a);
+ }
+ pc(';');
+ break;
+
+ case STM_WITH:
+ ps("with"); sp(); pc('('); pexp(d, stm->a); pc(')');
+ pstmh(d, stm->b);
+ break;
+
+ case STM_SWITCH:
+ ps("switch"); sp(); pc('(');
+ pexp(d, stm->a);
+ pc(')'); sp(); pc('{'); nl();
+ pcaselist(d, stm->b);
+ in(d); pc('}');
+ break;
+
+ case STM_THROW:
+ ps("throw "); pexp(d, stm->a); pc(';');
+ break;
+
+ case STM_TRY:
+ ps("try");
+ if (minify && stm->a->type != STM_BLOCK)
+ pc(' ');
+ pstmh(d, stm->a);
+ if (stm->b && stm->c) {
+ nl(); in(d); ps("catch"); sp(); pc('('); pexp(d, stm->b); pc(')');
+ pstmh(d, stm->c);
+ }
+ if (stm->d) {
+ nl(); in(d); ps("finally");
+ pstmh(d, stm->d);
+ }
+ break;
+
+ case STM_LABEL:
+ pexp(d, stm->a); pc(':'); sp(); pstm(d, stm->b);
+ break;
+
+ case STM_DEBUGGER:
+ ps("debugger");
+ pc(';');
+ 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;
+ }
+}
+
+static void jsP_dumpsyntax(js_State *J, js_Ast *prog)
+{
+ if (prog) {
+ if (prog->type == AST_LIST)
+ pstmlist(-1, prog);
+ else {
+ pstm(0, prog);
+ nl();
+ }
+ }
+ if (minify > 1)
+ putchar('\n');
+}
+
+/* S-expression list representation */
+
+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(astname[node->type]);
+ switch (node->type) {
+ default: break;
+ case AST_IDENTIFIER: pc(' '); ps(node->string); break;
+ case EXP_IDENTIFIER: pc(' '); ps(node->string); break;
+ case EXP_STRING: pc(' '); pstr(node->string); break;
+ case EXP_REGEXP: pc(' '); pregexp(node->string, node->number); break;
+ case EXP_NUMBER: printf(" %.9g", node->number); break;
+ case STM_BLOCK: afun = sblock; break;
+ case AST_FUNDEC: case EXP_FUN: cfun = sblock; break;
+ case EXP_PROP_GET: cfun = sblock; break;
+ case EXP_PROP_SET: 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) {
+ nl();
+ in(d+1);
+ }
+ }
+ nl(); in(d); pc(']');
+}
+
+static void jsP_dumplist(js_State *J, js_Ast *prog)
+{
+ if (prog) {
+ if (prog->type == AST_LIST)
+ sblock(0, prog);
+ else
+ snode(0, prog);
+ nl();
+ }
+}
+
+static void js_ppstring(js_State *J, const char *filename, const char *source)
+{
js_Ast *P;
+ js_Function *F;
+
if (js_try(J)) {
jsP_freeparse(J);
js_throw(J);
}
+
P = jsP_parse(J, filename, source);
- if (minify > 2)
+ F = jsC_compilescript(J, P, J->default_strict);
+
+ switch (format) {
+ case 0:
+ jsP_dumpsyntax(J, P);
+ break;
+ case 1:
jsP_dumplist(J, P);
- else
- jsP_dumpsyntax(J, P, minify);
+ break;
+ case 2:
+ jsC_dumpfunction(J, F);
+ break;
+ }
+
jsP_freeparse(J);
js_endtry(J);
}
-void js_ppfile(js_State *J, const char *filename, int minify)
+static void js_ppfile(js_State *J, const char *filename)
{
FILE * volatile f = NULL;
char * volatile s = NULL;
@@ -67,7 +926,7 @@
s[n] = 0; /* zero-terminate string containing file data */
- js_ppstring(J, filename, s, minify);
+ js_ppstring(J, filename, s);
js_endtry(J);
js_free(J, s);
@@ -74,7 +933,7 @@
fclose(f);
}
-static void js_tryppfile(js_State *J, const char *file, int minify)
+static void js_tryppfile(js_State *J, const char *file)
{
if (js_try(J)) {
js_report(J, js_trystring(J, -1, "Error"));
@@ -81,7 +940,7 @@
js_pop(J, 1);
return;
}
- js_ppfile(J, file, minify);
+ js_ppfile(J, file);
js_endtry(J);
}
@@ -89,20 +948,29 @@
main(int argc, char **argv)
{
js_State *J;
- int minify = 0;
int i;
+ if (argc < 2) {
+ fprintf(stderr, "usage: mujs-pp [-m | -mm | -s | -c] input.js\n");
+ fprintf(stderr, " -m\tminify output\n");
+ fprintf(stderr, " -mm\tminify output more\n");
+ fprintf(stderr, " -s\tprint syntax tree\n");
+ fprintf(stderr, " -c\tprint bytecode\n");
+ }
+
J = js_newstate(NULL, NULL, 0);
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-m"))
- minify = 1;
+ format = 0, minify = 1;
else if (!strcmp(argv[i], "-mm"))
- minify = 2;
+ format = 0, minify = 2;
else if (!strcmp(argv[i], "-s"))
- minify = 3;
+ format = 1, minify = 0;
+ else if (!strcmp(argv[i], "-c"))
+ format = 2, minify = 0;
else
- js_tryppfile(J, argv[i], minify);
+ js_tryppfile(J, argv[i]);
}
js_gc(J, 0);