aboutsummaryrefslogtreecommitdiff
path: root/lib/output.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/output.js')
-rw-r--r--lib/output.js226
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();
});
});