diff --git a/lib/coffee-script/nodes.js b/lib/coffee-script/nodes.js index 3ea11357..388cf415 100644 --- a/lib/coffee-script/nodes.js +++ b/lib/coffee-script/nodes.js @@ -302,19 +302,41 @@ }; Block.prototype.compileRoot = function(o) { - var code, hasReturn; - o.indent = this.tab = o.bare ? '' : TAB; + var code, e, exp, hasReturn, i, prelude, preludeExps, rest; + o.indent = ""; o.scope = new Scope(null, this, null); o.level = LEVEL_TOP; this.spaced = true; - code = this.compileWithDeclarations(o); + prelude = ""; hasReturn = false; this.traverseChildren(false, function(e) { if (e instanceof Return) hasReturn = true; return !hasReturn; }); - if ((o.bare || o.scope.variables.length <= 1) && !hasReturn) return code; - return "(function() {\n" + code + "\n}).call(this);\n"; + if (hasReturn || !o.bare) { + preludeExps = (function() { + var _len, _ref2, _results; + _ref2 = this.expressions; + _results = []; + for (i = 0, _len = _ref2.length; i < _len; i++) { + exp = _ref2[i]; + e = exp.unwrap(); + if (!(e instanceof Comment || e instanceof Literal)) break; + _results.push(exp); + } + return _results; + }).call(this); + rest = this.expressions.slice(preludeExps.length); + this.expressions = preludeExps; + if (preludeExps.length) prelude = "" + (this.compileNode(o)) + "\n\n"; + this.expressions = rest; + o.indent = TAB; + } + code = this.compileWithDeclarations(o); + if (hasReturn || (!o.bare && o.scope.variables.length > 1)) { + return "" + prelude + "(function() {\n" + code + "\n}).call(this);\n"; + } + return prelude + code; }; Block.prototype.compileWithDeclarations = function(o) { diff --git a/src/nodes.coffee b/src/nodes.coffee index 39cf991c..59ed81b0 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -243,18 +243,32 @@ exports.Block = class Block extends Base # It would be better not to generate them in the first place, but for now, # clean up obvious double-parentheses. compileRoot: (o) -> - o.indent = @tab = if o.bare then '' else TAB + o.indent = "" o.scope = new Scope null, this, null o.level = LEVEL_TOP @spaced = yes - code = @compileWithDeclarations o + prelude = "" hasReturn = no @traverseChildren no, (e) -> hasReturn = yes if e instanceof Return !hasReturn + if hasReturn or not o.bare + preludeExps = for exp, i in @expressions + e = exp.unwrap() + break unless e instanceof Comment or e instanceof Literal + exp + rest = @expressions[preludeExps.length...] + @expressions = preludeExps + prelude = "#{@compileNode o}\n\n" if preludeExps.length + @expressions = rest + # We assume that we will need the safety wrapper. + # This is our best guess without actually compiling. + o.indent = TAB + code = @compileWithDeclarations o # the `1` below accounts for `arguments`, always "in scope" - return code if (o.bare or o.scope.variables.length <= 1) and not hasReturn - "(function() {\n#{code}\n}).call(this);\n" + if hasReturn or (not o.bare and o.scope.variables.length > 1) + return "#{prelude}(function() {\n#{code}\n}).call(this);\n" + prelude + code # Compile the expressions body for the contents of a function, with # declarations of all inner variables pushed up to the top.