diff options
Diffstat (limited to 'lib/output.js')
-rw-r--r-- | lib/output.js | 226 |
1 files changed, 151 insertions, 75 deletions
diff --git a/lib/output.js b/lib/output.js index 52ab39d6..c581fa87 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1,4 +1,5 @@ function OutputStream(options) { + options = defaults(options, { indent_start : 0, indent_level : 4, @@ -78,10 +79,13 @@ function OutputStream(options) { var might_need_space = false; function print(str) { + str = String(str); if (might_need_space) { var ch = str.charAt(0); - if ((is_identifier_char(last_char()) && (is_identifier_char(ch) || ch == "\\")) - || (/[\+\-]$/.test(OUTPUT) && /^[\+\-]/.test(str))) + if ((is_identifier_char(last_char()) + && (is_identifier_char(ch) || ch == "\\")) + || + (/[\+\-]$/.test(OUTPUT) && /^[\+\-]/.test(str))) { OUTPUT += " "; current_col++; @@ -91,7 +95,11 @@ function OutputStream(options) { might_need_space = false; var a = str.split(/\r?\n/), n = a.length; current_line += n; - current_col += a[n - 1].length; + if (n == 1) { + current_col = a[n - 1].length; + } else { + current_col += a[n - 1].length; + } current_pos += str.length; OUTPUT += str; }; @@ -117,7 +125,7 @@ function OutputStream(options) { return ret; } : function(col, cont) { return cont() }; - var newline = options.indent ? function() { + var newline = options.beautify ? function() { print("\n"); } : noop; @@ -132,7 +140,6 @@ function OutputStream(options) { with_indent(next_indent(), function(){ ret = cont(); }); - newline(); indent(); print("}"); return ret; @@ -140,7 +147,9 @@ function OutputStream(options) { function with_parens(cont) { print("("); - var ret = with_indent(current_col, cont); + //XXX: still nice to have that for argument lists + //var ret = with_indent(current_col, cont); + var ret = cont(); print(")"); return ret; }; @@ -166,6 +175,7 @@ function OutputStream(options) { space(); }; + var stack = []; return { get : function() { return OUTPUT }, indent : indent, @@ -174,6 +184,7 @@ function OutputStream(options) { space : space, comma : comma, colon : colon, + semicolon : semicolon, print_name : function(name) { print(make_name(name)) }, print_string : function(str) { print(encode_string(str)) }, with_indent : with_indent, @@ -183,51 +194,67 @@ function OutputStream(options) { options : function() { return options }, line : function() { return current_line }, col : function() { return current_col }, - pos : function() { return current_pos } + pos : function() { return current_pos }, + push_node : function(node) { stack.push(node) }, + pop_node : function() { return stack.pop() }, + stack : function() { return stack }, + parent : function() { return stack[stack.length - 2] } }; }; /* -----[ code generators ]----- */ -(function(DEF){ - DEF(AST_Directive, function(self, output){ +(function(DEFPRINT){ + DEFPRINT(AST_Directive, function(self, output){ output.print_string(self.value); }); - DEF(AST_Debugger, function(self, output){ + DEFPRINT(AST_Debugger, function(self, output){ output.print_string("debugger"); }); - DEF(AST_Parenthesized, function(self, output){ + DEFPRINT(AST_Parenthesized, function(self, output){ output.with_parens(function(){ self.expression.print(output); }); }); - DEF(AST_Bracketed, function(self, output){ - output.with_block(function(){ + DEFPRINT(AST_Bracketed, function(self, output){ + if (self.body.length > 0) output.with_block(function(){ self.body.forEach(function(stmt){ output.indent(); stmt.print(output); + output.newline(); }); }); + else output.print("{}"); }); /* -----[ statements ]----- */ - DEF(AST_LabeledStatement, function(self, output){ + DEFPRINT(AST_Statement, function(self, output){ + if (self.body instanceof AST_Node) { + self.body.print(output); + output.semicolon(); + } else { + self.body.forEach(function(stmt){ + stmt.print(output); + output.newline(); + }); + } + }); + DEFPRINT(AST_LabeledStatement, function(self, output){ output.print(self.label + ":"); output.space(); self.statement.print(output); }); - DEF(AST_SimpleStatement, function(self, output){ + DEFPRINT(AST_SimpleStatement, function(self, output){ self.body.print(output); output.semicolon(); }); - DEF(AST_BlockStatement, function(self, output){ + DEFPRINT(AST_BlockStatement, function(self, output){ AST_Bracketed.prototype.print.call(self, output); }); - DEF(AST_EmptyStatement, function(self, output){ - // do nothing here? - // output.semicolon(); + DEFPRINT(AST_EmptyStatement, function(self, output){ + output.semicolon(); }); - DEF(AST_Do, function(self, output){ + DEFPRINT(AST_Do, function(self, output){ output.print("do"); output.space(); self.body.print(output); @@ -236,20 +263,32 @@ function OutputStream(options) { self.condition.print(output); self.semicolon(); }); - DEF(AST_For, function(self, output){ + DEFPRINT(AST_For, function(self, output){ output.print("for"); output.space(); output.with_parens(function(){ - self.init.print(output); - output.semicolon(); - self.condition.print(output); - output.semicolon(); - self.step.print(output); + if (self.init) { + self.init.print(output); + output.semicolon(); + output.space(); + } else { + output.semicolon(); + } + if (self.condition) { + self.condition.print(output); + output.semicolon(); + output.space(); + } else { + output.semicolon(); + } + if (self.step) { + self.step.print(output); + } }); output.space(); self.body.print(output); }); - DEF(AST_ForIn, function(self, output){ + DEFPRINT(AST_ForIn, function(self, output){ output.print("for"); output.space(); output.with_parens(function(){ @@ -264,7 +303,7 @@ function OutputStream(options) { output.space(); self.body.print(output); }); - DEF(AST_With, function(self, output){ + DEFPRINT(AST_With, function(self, output){ output.print("with"); output.space(); output.with_parens(function(){ @@ -274,12 +313,11 @@ function OutputStream(options) { self.body.print(output); }); /* -----[ functions ]----- */ - DEF(AST_Lambda, function(self, output){ + DEFPRINT(AST_Lambda, function(self, output){ output.print("function"); output.space(); if (self.name) { self.name.print(output); - output.space(); } output.with_parens(function(){ self.argnames.forEach(function(arg, i){ @@ -294,32 +332,32 @@ function OutputStream(options) { AST_Exit.DEFMETHOD("_do_print", function(output, kind){ output.print(kind); output.space(); - self.value.print(output); + this.value.print(output); output.semicolon(); }); - DEF(AST_Return, function(self, output){ + DEFPRINT(AST_Return, function(self, output){ self._do_print(output, "return"); }); - DEF(AST_Throw, function(self, output){ + DEFPRINT(AST_Throw, function(self, output){ self._do_print(output, "throw"); }); /* -----[ loop control ]----- */ AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){ output.print(kind); - if (self.label) { + if (this.label) { output.space(); - self.label.print(output); + this.label.print(output); } output.semicolon(); }); - DEF(AST_Break, function(self, output){ + DEFPRINT(AST_Break, function(self, output){ self._do_print(output, "break"); }); - DEF(AST_Continue, function(self, output){ + DEFPRINT(AST_Continue, function(self, output){ self._do_print(output, "continue"); }); /* -----[ if ]----- */ - DEF(AST_If, function(self, output){ + DEFPRINT(AST_If, function(self, output){ output.print("if"); output.space(); output.with_parens(function(){ @@ -333,7 +371,7 @@ function OutputStream(options) { } }); /* -----[ switch ]----- */ - DEF(AST_Switch, function(self, output){ + DEFPRINT(AST_Switch, function(self, output){ output.print("switch"); output.space(); output.with_parens(function(){ @@ -343,18 +381,18 @@ function OutputStream(options) { self.body.print(output); }); AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){ - self.body.forEach(function(stmt){ + this.body.forEach(function(stmt){ output.indent(); stmt.print(output); output.newline(); }); }); - DEF(AST_Default, function(self, output){ + DEFPRINT(AST_Default, function(self, output){ output.print("default:"); output.newline(); self._do_print_body(output); }); - DEF(AST_Case, function(self, output){ + DEFPRINT(AST_Case, function(self, output){ output.print("case"); output.space(); self.expression.print(output); @@ -363,7 +401,7 @@ function OutputStream(options) { self._do_print_body(output); }); /* -----[ exceptions ]----- */ - DEF(AST_Try, function(self, output){ + DEFPRINT(AST_Try, function(self, output){ output.print("try"); output.space(); self.btry.print(output); @@ -376,12 +414,12 @@ function OutputStream(options) { self.bfinally.print(output); } }); - DEF(AST_Catch, function(self, output){ + DEFPRINT(AST_Catch, function(self, output){ output.print("catch"); output.space(); self.body.print(output); }); - DEF(AST_Finally, function(self, output){ + DEFPRINT(AST_Finally, function(self, output){ output.print("finally"); output.space(); self.body.print(output); @@ -390,19 +428,19 @@ function OutputStream(options) { AST_Definitions.DEFMETHOD("_do_print", function(output, kind){ output.print(kind); output.space(); - self.definitions.forEach(function(def, i){ - if (i) output.space(); + this.definitions.forEach(function(def, i){ + if (i) output.comma(); def.print(output); }); - output.semicolon(); + if (!this.inline) output.semicolon(); }); - DEF(AST_Var, function(self, output){ + DEFPRINT(AST_Var, function(self, output){ self._do_print(output, "var"); }); - DEF(AST_Const, function(self, output){ + DEFPRINT(AST_Const, function(self, output){ self._do_print(output, "const"); }); - DEF(AST_VarDef, function(self, output){ + DEFPRINT(AST_VarDef, function(self, output){ self.name.print(output); if (self.value) { output.space(); @@ -412,7 +450,7 @@ function OutputStream(options) { } }); /* -----[ other expressions ]----- */ - DEF(AST_Call, function(self, output){ + DEFPRINT(AST_Call, function(self, output){ self.expression.print(output); output.with_parens(function(){ self.args.forEach(function(arg, i){ @@ -421,41 +459,74 @@ function OutputStream(options) { }); }); }); - DEF(AST_New, function(self, output){ + DEFPRINT(AST_New, function(self, output){ output.print("new"); output.space(); AST_Call.prototype.print.call(self, output); }); - DEF(AST_Seq, function(self, output){ + DEFPRINT(AST_Seq, function(self, output){ self.first.print(output); output.comma(); self.second.print(output); }); - DEF(AST_Dot, function(self, output){ + DEFPRINT(AST_Dot, function(self, output){ self.expression.print(output); output.print("."); output.print_name(self.property); }); - DEF(AST_Sub, function(self, output){ + DEFPRINT(AST_Sub, function(self, output){ self.expression.print(output); output.print("["); self.property.print(output); output.print("]"); }); - DEF(AST_UnaryPrefix, function(self, output){ + DEFPRINT(AST_UnaryPrefix, function(self, output){ output.print(self.operator); self.expression.print(output); }); - DEF(AST_UnaryPostfix, function(self, output){ + DEFPRINT(AST_UnaryPostfix, function(self, output){ self.expression.print(output); output.print(self.operator); }); - DEF(AST_Binary, function(self, output){ - self.left.print(output); - output.print(self.operator); - self.right.print(output); + AST_Binary.DEFMETHOD("_do_print", function(output){ + this.left.print(output); + output.space(); + output.print(this.operator); + output.space(); + this.right.print(output); + }); + DEFPRINT(AST_Binary, function(self, output){ + var p = output.parent(); + if (p instanceof AST_Binary) { + var po = p.operator, pp = PRECEDENCE[po]; + var so = self.operator, sp = PRECEDENCE[so]; + if (pp > sp + || (pp == sp + && self === p.right + && !(so == po && + (so == "*" || + so == "&&" || + so == "||")))) { + output.with_parens(function(){ + self._do_print(output); + }); + return; + } + } + self._do_print(output); + }); + // XXX: this is quite similar as for AST_Binary, except for the parens. + DEFPRINT(AST_Assign, function(self, output){ + var p = output.parent(); + if (p instanceof AST_Binary) { + output.with_parens(function(){ + self._do_print(output); + }); + return; + } + self._do_print(output); }); - DEF(AST_Conditional, function(self, output){ + DEFPRINT(AST_Conditional, function(self, output){ self.condition.print(output); output.space(); output.print("?"); @@ -465,7 +536,7 @@ function OutputStream(options) { self.alternative.print(output); }); /* -----[ literals ]----- */ - DEF(AST_Array, function(self, output){ + DEFPRINT(AST_Array, function(self, output){ output.with_square(function(){ self.elements.forEach(function(exp, i){ if (i) output.comma(); @@ -473,41 +544,44 @@ function OutputStream(options) { }); }); }); - DEF(AST_Object, function(self, output){ - output.with_block(function(){ + DEFPRINT(AST_Object, function(self, output){ + if (self.properties.length > 0) output.with_block(function(){ self.properties.forEach(function(prop, i){ if (i) output.comma(); + output.indent(); prop.print(output); + output.newline(); }); }); + else output.print("{}"); }); - DEF(AST_ObjectKeyVal, function(self, output){ + DEFPRINT(AST_ObjectKeyVal, function(self, output){ output.print_name(self.key); output.colon(); self.value.print(output); }); - DEF(AST_ObjectSetter, function(self, output){ + DEFPRINT(AST_ObjectSetter, function(self, output){ throw "not yet done"; }); - DEF(AST_ObjectGetter, function(self, output){ + DEFPRINT(AST_ObjectGetter, function(self, output){ throw "not yet done"; }); - DEF(AST_Symbol, function(self, output){ + DEFPRINT(AST_Symbol, function(self, output){ output.print_name(self.name); }); - DEF(AST_This, function(self, output){ + DEFPRINT(AST_This, function(self, output){ output.print("this"); }); - DEF(AST_Label, function(self, output){ + DEFPRINT(AST_Label, function(self, output){ output.print_name(self.name); }); - DEF(AST_Constant, function(self, output){ + DEFPRINT(AST_Constant, function(self, output){ output.print(self.getValue()); }); - DEF(AST_String, function(self, output){ + DEFPRINT(AST_String, function(self, output){ output.print_string(self.getValue()); }); - DEF(AST_RegExp, function(self, output){ + DEFPRINT(AST_RegExp, function(self, output){ output.print("/"); output.print(self.pattern); output.print("/"); @@ -515,6 +589,8 @@ function OutputStream(options) { }); })(function DEF(nodetype, generator) { nodetype.DEFMETHOD("print", function(stream){ + stream.push_node(this); generator(this, stream); + stream.pop_node(); }); }); |