lots'o'fixes in the output routines; still a looong way to go.
authorMihai Bazon <mihai@bazon.net>
Thu, 16 Aug 2012 16:54:37 +0000 (19:54 +0300)
committerMihai Bazon <mihai@bazon.net>
Thu, 16 Aug 2012 18:36:16 +0000 (21:36 +0300)
lib/ast.js
lib/node.js
lib/output.js
lib/parse.js

index c5be5f6..f66853e 100644 (file)
@@ -60,7 +60,7 @@ Used for bodies of FUNCTION/TRY/CATCH/THROW/SWITCH.",
 /* -----[ loops ]----- */
 
 var AST_LabeledStatement = DEFNODE("LabeledStatement", "label statement", {
-    
+
 });
 
 var AST_Statement = DEFNODE("Statement", "body", {
@@ -177,7 +177,7 @@ var AST_Finally = DEFNODE("Finally", "body", {
 
 /* -----[ VAR/CONST ]----- */
 
-var AST_Definitions = DEFNODE("Definitions", "definitions", {
+var AST_Definitions = DEFNODE("Definitions", "definitions inline", {
 });
 
 var AST_Var = DEFNODE("Var", null, {
@@ -230,7 +230,7 @@ var AST_Binary = DEFNODE("Binary", "left operator right", {
 var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", {
 });
 
-var AST_Assign = DEFNODE("Assign", null, {
+var AST_Assign = DEFNODE("Assign", "left operator right", {
 
 }, AST_Binary);
 
index 9dba3c1..6986749 100755 (executable)
     var ast = parse(fs.readFileSync(filename, "utf8"));
     console.timeEnd("parse");
 
+    var stream = OutputStream({ beautify: true });
+    ast.print(stream);
+    console.log(stream.get());
+
     // console.time("walk");
     // var w = new TreeWalker(function(node){
     //     console.log(node.TYPE + " [ start: " + node.start.line + ":" + node.start.col + ", end: " + node.end.line + ":" + node.end.col + "] " + node.name);
index 52ab39d..c581fa8 100644 (file)
@@ -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();
     });
 });
index fdf44ce..260c411 100644 (file)
@@ -866,6 +866,9 @@ function parse($TEXT, exigent_mode) {
             init = is("keyword", "var")
                 ? (next(), var_(true))
                 : expression(true, true);
+            if (init instanceof AST_Var) {
+                init.inline = true;
+            }
             if (is("operator", "in")) {
                 if (init instanceof AST_Var && init.definitions.length > 1)
                     croak("Only one variable declaration allowed in for..in loop");