finished porting changes
diff --git a/escodegen.js b/escodegen.js
index bd5424f..331a16c 100644
--- a/escodegen.js
+++ b/escodegen.js
@@ -715,11 +715,11 @@
                 return '//' + comment.value;
             } else {
                 // Always use LineTerminator
-                var comment = '//' + comment.value + '\n';
+                var result = '//' + comment.value;
                 if (!preserveBlankLines) {
-                    comment += '\n';
+                    result += '\n';
                 }
-                return comment;
+                return result;
             }
         }
         if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) {
@@ -841,6 +841,21 @@
         return result;
     }
 
+    function generateBlankLines(start, end, result) {
+        var j;
+
+        var newlineCount = 0;
+        for (j = start; j < end; j++) {
+            if (sourceCode[j] === '\n') {
+                newlineCount++;
+            }
+        }
+
+        for (j = 1; j < newlineCount; j++) {
+            result.push(newline);
+        }
+    }
+
     function parenthesize(text, current, should) {
         if (current < should) {
             return ['(', text, ')'];
@@ -1053,22 +1068,82 @@
     CodeGenerator.Statement = {
 
         BlockStatement: function (stmt, flags) {
+            var range, content;
             var result = ['{', newline], that = this;
 
             withIndent(function () {
+                // handle functions without any code
+                if (stmt.body.length === 0 && preserveBlankLines) {
+                    range = stmt.range;
+                    if (range[1] - range[0] > 2) {
+                        content = sourceCode.substring(range[0] + 1, range[1] - 1);
+                        if (content[0] === '\n') {
+                            result = ['{'];
+                        }
+                        result.push(content);
+                    }
+                }
+                
                 var i, iz, fragment, bodyFlags;
                 bodyFlags = S_TFFF;
                 if (flags & F_FUNC_BODY) {
                     bodyFlags |= F_DIRECTIVE_CTX;
                 }
+                
                 for (i = 0, iz = stmt.body.length; i < iz; ++i) {
+                    if (preserveBlankLines) {
+                        // handle spaces before the first line
+                        if (i === 0) {
+                            if (stmt.body[0].leadingComments) {
+                                range = stmt.body[0].leadingComments[0].extendedRange;
+                                content = sourceCode.substring(range[0], range[1]);
+                                if (content[0] === '\n') {
+                                    result = ['{'];
+                                }
+                            }
+                            if (!stmt.body[0].leadingComments) {
+                                generateBlankLines(stmt.range[0], stmt.body[0].range[0], result);
+                            }
+                        }
+
+                        // handle spaces between lines
+                        if (i > 0) {
+                            if (!stmt.body[i - 1].trailingComments  && !stmt.body[i].leadingComments) {
+                                generateBlankLines(stmt.body[i - 1].range[1], stmt.body[i].range[0], result);
+                            }
+                        }
+                    }
+                    
                     if (i === iz - 1) {
                         bodyFlags |= F_SEMICOLON_OPT;
                     }
-                    fragment = addIndent(that.generateStatement(stmt.body[i], bodyFlags));
+                    
+                    if (stmt.body[i].leadingComments && preserveBlankLines) {
+                        fragment = that.generateStatement(stmt.body[i], bodyFlags);
+                    } else {
+                        fragment = addIndent(that.generateStatement(stmt.body[i], bodyFlags));
+                    }
+                    
                     result.push(fragment);
                     if (!endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
-                        result.push(newline);
+                        if (preserveBlankLines && i < iz - 1) {
+                            // don't add a new line if there are leading coments
+                            // in the next statement
+                            if (!stmt.body[i + 1].leadingComments) {
+                                result.push(newline);
+                            }
+                        } else {
+                            result.push(newline);
+                        }
+                    }
+
+                    if (preserveBlankLines) {
+                        // handle spaces after the last line
+                        if (i === iz - 1) {
+                            if (!stmt.body[i].trailingComments) {
+                                generateBlankLines(stmt.body[i].range[1], stmt.range[1], result);
+                            }
+                        }
                     }
                 }
             });
@@ -1254,21 +1329,6 @@
             return result;
         },
 
-        BlankLines: function (start, end, result) {
-            var j;
-
-            var newlineCount = 0;
-            for (j = start; j < end; j++) {
-                if (sourceCode[j] === '\n') {
-                    newlineCount++;
-                }
-            }
-
-            for (j = 1; j < newlineCount; j++) {
-                result.push(newline);
-            }
-        },
-
         ImportDeclaration: function (stmt, flags) {
             // ES6: 15.2.1 valid import declarations:
             //     - import ImportClause FromClause ;
@@ -1618,10 +1678,42 @@
                 if (!safeConcatenation && i === iz - 1) {
                     bodyFlags |= F_SEMICOLON_OPT;
                 }
+
+                if (preserveBlankLines) {
+                    // handle spaces before the first line
+                    if (i === 0) {
+                        if (!stmt.body[0].leadingComments) {
+                            generateBlankLines(stmt.range[0], stmt.body[i].range[0], result);
+                        }
+                    }
+
+                    // handle spaces between lines
+                    if (i > 0) {
+                        if (!stmt.body[i - 1].trailingComments && !stmt.body[i].leadingComments) {
+                            generateBlankLines(stmt.body[i - 1].range[1], stmt.body[i].range[0], result);
+                        }
+                    }
+                }
+                
                 fragment = addIndent(this.generateStatement(stmt.body[i], bodyFlags));
                 result.push(fragment);
                 if (i + 1 < iz && !endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
-                    result.push(newline);
+                    if (preserveBlankLines) {
+                        if (!stmt.body[i + 1].leadingComments) {
+                            result.push(newline);
+                        }
+                    } else {
+                        result.push(newline);
+                    }
+                }
+
+                if (preserveBlankLines) {
+                    // handle spaces after the last line
+                    if (i === iz - 1) {
+                        if (!stmt.body[i].trailingComments) {
+                            generateBlankLines(stmt.body[i].range[1], stmt.range[1], result);
+                        }
+                    }
                 }
             }
             return result;
@@ -2401,6 +2493,8 @@
         directive = options.directive;
         parse = json ? null : options.parse;
         sourceMap = options.sourceMap;
+        sourceCode = options.sourceCode;
+        preserveBlankLines = options.format.preserveBlankLines && sourceCode !== null;
         extra = options;
 
         if (sourceMap) {
diff --git a/test/preserve-blank-lines.js b/test/preserve-blank-lines.js
new file mode 100644
index 0000000..ca3b730
--- /dev/null
+++ b/test/preserve-blank-lines.js
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2011-2013 Yusuke Suzuki <utatane.tea@gmail.com>
+ Copyright (C) 2014 Kevin Barabash <kevinb7@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+var fs = require('fs'),
+    esprima = require('esprima'),
+    escodegen = require('./loader'),
+    chai = require('chai'),
+    expect = chai.expect;
+
+function test(code, expected) {
+    var tree, actual, options, StringObject;
+
+    // alias, so that JSLint does not complain.
+    StringObject = String;
+
+    options = {
+        range: true,
+        tokens: true,
+        comment: true
+    };
+
+    tree = esprima.parse(code, options);
+    tree = escodegen.attachComments(tree, tree.comments, tree.tokens);
+
+    options = {
+        comment: true,
+        sourceCode: code,
+        format: {
+            preserveBlankLines: true
+        }
+    };
+
+    // for UNIX text comment
+    actual = escodegen.generate(tree, options);
+    expect(actual).to.be.equal(expected);
+}
+
+describe('preserve blank lines test', function () {
+    fs.readdirSync(__dirname + '/preserve-blank-lines').sort().forEach(function(file) {
+        var code, expected, p;
+        if (/\.js$/.test(file) && !/expected\.js$/.test(file)) {
+            it(file, function () {
+                p = file.replace(/\.js$/, '.expected.js');
+                code = fs.readFileSync(__dirname + '/preserve-blank-lines/' + file, 'utf-8');
+                expected = fs.readFileSync(__dirname + '/preserve-blank-lines/' + p, 'utf-8');
+                test(code, expected);
+            });
+        }
+    });
+});
+
+/* vim: set sw=4 ts=4 et tw=80 : */