From d2b040418899d80f7b40502f85dd0981fb60c595 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sun, 18 Sep 2011 17:16:39 -0500 Subject: [PATCH] big whitespace / readability change. join top level block with extra newlines, and class definitions as well. --- lib/coffee-script/browser.js | 9 + lib/coffee-script/cake.js | 15 ++ lib/coffee-script/coffee-script.js | 17 ++ lib/coffee-script/command.js | 32 +++ lib/coffee-script/grammar.js | 9 + lib/coffee-script/helpers.js | 10 + lib/coffee-script/index.js | 2 + lib/coffee-script/lexer.js | 74 ++++++ lib/coffee-script/nodes.js | 373 ++++++++++++++++++++++++++++- lib/coffee-script/optparse.js | 14 ++ lib/coffee-script/repl.js | 32 +++ lib/coffee-script/rewriter.js | 32 +++ lib/coffee-script/scope.js | 18 ++ src/nodes.coffee | 8 +- 14 files changed, 643 insertions(+), 2 deletions(-) diff --git a/lib/coffee-script/browser.js b/lib/coffee-script/browser.js index c0e9670d..ec2e4793 100644 --- a/lib/coffee-script/browser.js +++ b/lib/coffee-script/browser.js @@ -1,16 +1,22 @@ (function() { var CoffeeScript, runScripts; + CoffeeScript = require('./coffee-script'); + CoffeeScript.require = require; + CoffeeScript.eval = function(code, options) { return eval(CoffeeScript.compile(code, options)); }; + CoffeeScript.run = function(code, options) { if (options == null) options = {}; options.bare = true; return Function(CoffeeScript.compile(code, options))(); }; + if (typeof window === "undefined" || window === null) return; + CoffeeScript.load = function(url, callback) { var xhr; xhr = new (window.ActiveXObject || XMLHttpRequest)('Microsoft.XMLHTTP'); @@ -29,6 +35,7 @@ }; return xhr.send(null); }; + runScripts = function() { var coffees, execute, index, length, s, scripts; scripts = document.getElementsByTagName('script'); @@ -57,9 +64,11 @@ })(); return null; }; + if (window.addEventListener) { addEventListener('DOMContentLoaded', runScripts, false); } else { attachEvent('onload', runScripts); } + }).call(this); diff --git a/lib/coffee-script/cake.js b/lib/coffee-script/cake.js index 40984f0c..a1d36939 100644 --- a/lib/coffee-script/cake.js +++ b/lib/coffee-script/cake.js @@ -1,14 +1,24 @@ (function() { var CoffeeScript, cakefileDirectory, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks; + fs = require('fs'); + path = require('path'); + helpers = require('./helpers'); + optparse = require('./optparse'); + CoffeeScript = require('./coffee-script'); + tasks = {}; + options = {}; + switches = []; + oparse = null; + helpers.extend(global, { task: function(name, description, action) { var _ref; @@ -29,6 +39,7 @@ return tasks[name].action(options); } }); + exports.run = function() { var arg, args, _i, _len, _ref, _results; global.__originalDirname = fs.realpathSync('.'); @@ -48,6 +59,7 @@ } return _results; }; + printTasks = function() { var desc, name, spaces, task; console.log(''); @@ -60,10 +72,12 @@ } if (switches.length) return console.log(oparse.help()); }; + missingTask = function(task) { console.log("No such task: \"" + task + "\""); return process.exit(1); }; + cakefileDirectory = function(dir) { var parent; if (path.existsSync(path.join(dir, 'Cakefile'))) return dir; @@ -71,4 +85,5 @@ if (parent !== dir) return cakefileDirectory(parent); throw new Error("Cakefile not found in " + (process.cwd())); }; + }).call(this); diff --git a/lib/coffee-script/coffee-script.js b/lib/coffee-script/coffee-script.js index 66429199..38ae9764 100644 --- a/lib/coffee-script/coffee-script.js +++ b/lib/coffee-script/coffee-script.js @@ -1,10 +1,15 @@ (function() { var Lexer, RESERVED, compile, fs, lexer, parser, path, _ref; var __hasProp = Object.prototype.hasOwnProperty; + fs = require('fs'); + path = require('path'); + _ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED; + parser = require('./parser').parser; + if (require.extensions) { require.extensions['.coffee'] = function(module, filename) { var content; @@ -18,9 +23,13 @@ return compile(content); }); } + exports.VERSION = '1.1.3-pre'; + exports.RESERVED = RESERVED; + exports.helpers = require('./helpers'); + exports.compile = compile = function(code, options) { if (options == null) options = {}; try { @@ -32,9 +41,11 @@ throw err; } }; + exports.tokens = function(code, options) { return lexer.tokenize(code, options); }; + exports.nodes = function(source, options) { if (typeof source === 'string') { return parser.parse(lexer.tokenize(source, options)); @@ -42,6 +53,7 @@ return parser.parse(source); } }; + exports.run = function(code, options) { var Module, mainModule; mainModule = require.main; @@ -57,6 +69,7 @@ return mainModule._compile(code, mainModule.filename); } }; + exports.eval = function(code, options) { var Module, Script, js, k, o, r, sandbox, v, _i, _len, _module, _ref2, _ref3, _require; if (options == null) options = {}; @@ -111,7 +124,9 @@ return eval(js); } }; + lexer = new Lexer; + parser.lexer = { lex: function() { var tag, _ref2; @@ -126,5 +141,7 @@ return ""; } }; + parser.yy = require('./nodes'); + }).call(this); diff --git a/lib/coffee-script/command.js b/lib/coffee-script/command.js index f81dabf8..1401a597 100644 --- a/lib/coffee-script/command.js +++ b/lib/coffee-script/command.js @@ -1,25 +1,42 @@ (function() { var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compileScript, compileScripts, compileStdio, contents, exec, forkNode, fs, helpers, lint, loadRequires, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, version, watch, writeJs, _ref; + fs = require('fs'); + path = require('path'); + helpers = require('./helpers'); + optparse = require('./optparse'); + CoffeeScript = require('./coffee-script'); + _ref = require('child_process'), spawn = _ref.spawn, exec = _ref.exec; + EventEmitter = require('events').EventEmitter; + helpers.extend(CoffeeScript, new EventEmitter); + printLine = function(line) { return process.stdout.write(line + '\n'); }; + printWarn = function(line) { return process.binding('stdio').writeError(line + '\n'); }; + BANNER = 'Usage: coffee [options] path/to/script.coffee\n\nIf called without options, `coffee` will run your script.'; + SWITCHES = [['-b', '--bare', 'compile without a top-level function wrapper'], ['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-e', '--eval', 'pass a string from the command line as input'], ['-h', '--help', 'display this help message'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling'], ['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint'], ['-n', '--nodes', 'print out the parse tree that the parser produces'], ['--nodejs [ARGS]', 'pass options directly to the "node" binary'], ['-o', '--output [DIR]', 'set the output directory for compiled JavaScript'], ['-p', '--print', 'print out the compiled JavaScript'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce'], ['-v', '--version', 'display the version number'], ['-w', '--watch', 'watch scripts for changes and rerun commands']]; + opts = {}; + sources = []; + contents = []; + optionParser = null; + exports.run = function() { parseOptions(); if (opts.nodejs) return forkNode(); @@ -36,6 +53,7 @@ process.execPath = require.main.filename; return compileScripts(); }; + compileScripts = function() { var base, compile, remaining_files, source, trackCompleteFiles, trackUnprocessedFiles, unprocessed, _i, _j, _len, _len2, _results; unprocessed = []; @@ -109,6 +127,7 @@ } return _results; }; + compileScript = function(file, input, base) { var o, options, t, task; o = opts; @@ -145,6 +164,7 @@ return process.exit(1); } }; + compileStdio = function() { var code, stdin; code = ''; @@ -156,11 +176,13 @@ return compileScript(null, code); }); }; + compileJoin = function() { var code; code = contents.join('\n'); return compileScript(opts.join, code, opts.join); }; + loadRequires = function() { var realFilename, req, _i, _len, _ref2; realFilename = module.filename; @@ -172,6 +194,7 @@ } return module.filename = realFilename; }; + watch = function(source, base) { return fs.watchFile(source, { persistent: true, @@ -186,6 +209,7 @@ }); }); }; + writeJs = function(source, js, base) { var baseDir, compile, dir, filename, jsPath, srcDir; filename = path.basename(source, path.extname(source)) + '.js'; @@ -211,6 +235,7 @@ } }); }; + lint = function(file, js) { var conf, jsl, printIt; printIt = function(buffer) { @@ -223,6 +248,7 @@ jsl.stdin.write(js); return jsl.stdin.end(); }; + printTokens = function(tokens) { var strings, tag, token, value; strings = (function() { @@ -237,6 +263,7 @@ })(); return printLine(strings.join(' ')); }; + parseOptions = function() { var o; optionParser = new optparse.OptionParser(SWITCHES, BANNER); @@ -246,12 +273,14 @@ o.print = !!(o.print || (o.eval || o.stdio && o.compile)); return sources = o.arguments; }; + compileOptions = function(filename) { return { filename: filename, bare: opts.bare }; }; + forkNode = function() { var args, nodeArgs; nodeArgs = opts.nodejs.split(/\s+/); @@ -263,10 +292,13 @@ customFds: [0, 1, 2] }); }; + usage = function() { return printLine((new optparse.OptionParser(SWITCHES, BANNER)).help()); }; + version = function() { return printLine("CoffeeScript version " + CoffeeScript.VERSION); }; + }).call(this); diff --git a/lib/coffee-script/grammar.js b/lib/coffee-script/grammar.js index 807837b2..5529c41d 100644 --- a/lib/coffee-script/grammar.js +++ b/lib/coffee-script/grammar.js @@ -1,7 +1,10 @@ (function() { var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap; + Parser = require('jison').Parser; + unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/; + o = function(patternString, action, options) { var match; patternString = patternString.replace(/\s{2,}/g, ' '); @@ -11,6 +14,7 @@ action = action.replace(/\b(?:Block\.wrap|extend)\b/g, 'yy.$&'); return [patternString, "$$ = " + action + ";", options]; }; + grammar = { Root: [ o('', function() { @@ -550,8 +554,11 @@ }) ] }; + operators = [['left', '.', '?.', '::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'DO', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF']]; + tokens = []; + for (name in grammar) { alternatives = grammar[name]; grammar[name] = (function() { @@ -570,10 +577,12 @@ return _results; })(); } + exports.parser = new Parser({ tokens: tokens.join(' '), bnf: grammar, operators: operators.reverse(), startSymbol: 'Root' }); + }).call(this); diff --git a/lib/coffee-script/helpers.js b/lib/coffee-script/helpers.js index 818cc4f4..038f7810 100644 --- a/lib/coffee-script/helpers.js +++ b/lib/coffee-script/helpers.js @@ -1,13 +1,16 @@ (function() { var extend, flatten; + exports.starts = function(string, literal, start) { return literal === string.substr(start, literal.length); }; + exports.ends = function(string, literal, back) { var len; len = literal.length; return literal === string.substr(string.length - len - (back || 0), len); }; + exports.compact = function(array) { var item, _i, _len, _results; _results = []; @@ -17,6 +20,7 @@ } return _results; }; + exports.count = function(string, substr) { var num, pos; num = pos = 0; @@ -26,9 +30,11 @@ } return num; }; + exports.merge = function(options, overrides) { return extend(extend({}, options), overrides); }; + extend = exports.extend = function(object, properties) { var key, val; for (key in properties) { @@ -37,6 +43,7 @@ } return object; }; + exports.flatten = flatten = function(array) { var element, flattened, _i, _len; flattened = []; @@ -50,13 +57,16 @@ } return flattened; }; + exports.del = function(obj, key) { var val; val = obj[key]; delete obj[key]; return val; }; + exports.last = function(array, back) { return array[array.length - (back || 0) - 1]; }; + }).call(this); diff --git a/lib/coffee-script/index.js b/lib/coffee-script/index.js index 38f7c1e9..5e6eba94 100644 --- a/lib/coffee-script/index.js +++ b/lib/coffee-script/index.js @@ -1,8 +1,10 @@ (function() { var key, val, _ref; + _ref = require('./coffee-script'); for (key in _ref) { val = _ref[key]; exports[key] = val; } + }).call(this); diff --git a/lib/coffee-script/lexer.js b/lib/coffee-script/lexer.js index 5267ffb3..c423201e 100644 --- a/lib/coffee-script/lexer.js +++ b/lib/coffee-script/lexer.js @@ -6,10 +6,15 @@ } return -1; }; + _ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES; + _ref2 = require('./helpers'), count = _ref2.count, starts = _ref2.starts, compact = _ref2.compact, last = _ref2.last; + exports.Lexer = Lexer = (function() { + function Lexer() {} + Lexer.prototype.tokenize = function(code, opts) { var i, tag; if (opts == null) opts = {}; @@ -32,6 +37,7 @@ if (opts.rewrite === false) return this.tokens; return (new Rewriter).rewrite(this.tokens); }; + Lexer.prototype.identifierToken = function() { var colon, forcedIdentifier, id, input, match, prev, tag, _ref3, _ref4; if (!(match = IDENTIFIER.exec(this.chunk))) return 0; @@ -104,6 +110,7 @@ if (colon) this.token(':', ':'); return input.length; }; + Lexer.prototype.numberToken = function() { var match, number; if (!(match = NUMBER.exec(this.chunk))) return 0; @@ -111,6 +118,7 @@ this.token('NUMBER', number); return number.length; }; + Lexer.prototype.stringToken = function() { var match, string; switch (this.chunk.charAt(0)) { @@ -132,6 +140,7 @@ this.line += count(string, '\n'); return string.length; }; + Lexer.prototype.heredocToken = function() { var doc, heredoc, match, quote; if (!(match = HEREDOC.exec(this.chunk))) return 0; @@ -151,6 +160,7 @@ this.line += count(heredoc, '\n'); return heredoc.length; }; + Lexer.prototype.commentToken = function() { var comment, here, match; if (!(match = this.chunk.match(COMMENT))) return 0; @@ -165,6 +175,7 @@ this.line += count(comment, '\n'); return comment.length; }; + Lexer.prototype.jsToken = function() { var match, script; if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) { @@ -173,6 +184,7 @@ this.token('JS', (script = match[0]).slice(1, -1)); return script.length; }; + Lexer.prototype.regexToken = function() { var length, match, prev, regex, _ref3; if (this.chunk.charAt(0) !== '/') return 0; @@ -190,6 +202,7 @@ this.token('REGEX', regex === '//' ? '/(?:)/' : regex); return regex.length; }; + Lexer.prototype.heregexToken = function(match) { var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref3, _ref4, _ref5, _ref6; heregex = match[0], body = match[1], flags = match[2]; @@ -224,6 +237,7 @@ this.token(')', ')'); return heregex.length; }; + Lexer.prototype.lineToken = function() { var diff, indent, match, noNewlines, prev, size; if (!(match = MULTI_DENT.exec(this.chunk))) return 0; @@ -258,6 +272,7 @@ this.indent = size; return indent.length; }; + Lexer.prototype.outdentToken = function(moveOut, noNewlines) { var dent, len; while (moveOut > 0) { @@ -287,6 +302,7 @@ } return this; }; + Lexer.prototype.whitespaceToken = function() { var match, nline, prev; if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) { @@ -300,6 +316,7 @@ return 0; } }; + Lexer.prototype.newlineToken = function() { while (this.value() === ';') { this.tokens.pop(); @@ -307,10 +324,12 @@ if (this.tag() !== 'TERMINATOR') this.token('TERMINATOR', '\n'); return this; }; + Lexer.prototype.suppressNewlines = function() { if (this.value() === '\\') this.tokens.pop(); return this; }; + Lexer.prototype.literalToken = function() { var match, prev, tag, value, _ref3, _ref4, _ref5, _ref6; if (match = OPERATOR.exec(this.chunk)) { @@ -371,6 +390,7 @@ this.token(tag, value); return value.length; }; + Lexer.prototype.sanitizeHeredoc = function(doc, options) { var attempt, herecomment, indent, match, _ref3; indent = options.indent, herecomment = options.herecomment; @@ -391,6 +411,7 @@ if (!herecomment) doc = doc.replace(/^\n/, ''); return doc; }; + Lexer.prototype.tagParameters = function() { var i, stack, tok, tokens; if (this.tag() !== ')') return this; @@ -417,9 +438,11 @@ } return this; }; + Lexer.prototype.closeIndentation = function() { return this.outdentToken(this.indent); }; + Lexer.prototype.balancedString = function(str, end) { var i, letter, match, prev, stack, _ref3; stack = [end]; @@ -447,6 +470,7 @@ } return this.error("missing " + (stack.pop()) + ", starting"); }; + Lexer.prototype.interpolateString = function(str, options) { var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _len, _ref3, _ref4, _ref5; if (options == null) options = {}; @@ -501,6 +525,7 @@ if (interpolated) this.token(')', ')'); return tokens; }; + Lexer.prototype.pair = function(tag) { var size, wanted; if (tag !== (wanted = last(this.ends))) { @@ -511,24 +536,30 @@ } return this.ends.pop(); }; + Lexer.prototype.token = function(tag, value) { return this.tokens.push([tag, value, this.line]); }; + Lexer.prototype.tag = function(index, tag) { var tok; return (tok = last(this.tokens, index)) && (tag ? tok[0] = tag : tok[0]); }; + Lexer.prototype.value = function(index, val) { var tok; return (tok = last(this.tokens, index)) && (val ? tok[1] = val : tok[1]); }; + Lexer.prototype.unfinished = function() { var _ref3; return LINE_CONTINUER.test(this.chunk) || ((_ref3 = this.tag()) === '\\' || _ref3 === '.' || _ref3 === '?.' || _ref3 === 'UNARY' || _ref3 === 'MATH' || _ref3 === '+' || _ref3 === '-' || _ref3 === 'SHIFT' || _ref3 === 'RELATION' || _ref3 === 'COMPARE' || _ref3 === 'LOGIC' || _ref3 === 'COMPOUND_ASSIGN' || _ref3 === 'THROW' || _ref3 === 'EXTENDS'); }; + Lexer.prototype.escapeLines = function(str, heredoc) { return str.replace(MULTILINER, heredoc ? '\\n' : ''); }; + Lexer.prototype.makeString = function(body, quote, heredoc) { if (!body) return quote + quote; body = body.replace(/\\([\s\S])/g, function(match, contents) { @@ -541,13 +572,19 @@ body = body.replace(RegExp("" + quote, "g"), '\\$&'); return quote + this.escapeLines(body, heredoc) + quote; }; + Lexer.prototype.error = function(message) { throw SyntaxError("" + message + " on line " + (this.line + 1)); }; + return Lexer; + })(); + JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super']; + COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when']; + COFFEE_ALIAS_MAP = { and: '&&', or: '||', @@ -559,6 +596,7 @@ on: 'true', off: 'false' }; + COFFEE_ALIASES = (function() { var _results; _results = []; @@ -567,39 +605,75 @@ } return _results; })(); + COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES); + RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf']; + JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED); + exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS); + IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/; + NUMBER = /^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i; + HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/; + OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/; + WHITESPACE = /^[^\n\S]+/; + COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/; + CODE = /^[-=]>/; + MULTI_DENT = /^(?:\n[^\n\S]*)+/; + SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/; + JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/; + REGEX = /^\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/[imgy]{0,4}(?!\w)/; + HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/; + HEREGEX_OMIT = /\s+(?:#.*)?/g; + MULTILINER = /\n/g; + HEREDOC_INDENT = /\n+([^\n\S]*)/g; + HEREDOC_ILLEGAL = /\*\//; + LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/; + TRAILING_SPACES = /\s+$/; + COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|=']; + UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO']; + LOGIC = ['&&', '||', '&', '|', '^']; + SHIFT = ['<<', '>>', '>>>']; + COMPARE = ['==', '!=', '<', '>', '<=', '>=']; + MATH = ['*', '/', '%']; + RELATION = ['IN', 'OF', 'INSTANCEOF']; + BOOL = ['TRUE', 'FALSE', 'NULL', 'UNDEFINED']; + NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', '++', '--', ']']; + NOT_SPACED_REGEX = NOT_REGEX.concat(')', '}', 'THIS', 'IDENTIFIER', 'STRING'); + CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER']; + INDEXABLE = CALLABLE.concat('NUMBER', 'BOOL'); + LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR']; + }).call(this); diff --git a/lib/coffee-script/nodes.js b/lib/coffee-script/nodes.js index e0ad77f7..970042f4 100644 --- a/lib/coffee-script/nodes.js +++ b/lib/coffee-script/nodes.js @@ -13,25 +13,36 @@ } return -1; }; + Scope = require('./scope').Scope; + RESERVED = require('./lexer').RESERVED; + _ref = require('./helpers'), compact = _ref.compact, flatten = _ref.flatten, extend = _ref.extend, merge = _ref.merge, del = _ref.del, starts = _ref.starts, ends = _ref.ends, last = _ref.last; + exports.extend = extend; + YES = function() { return true; }; + NO = function() { return false; }; + THIS = function() { return this; }; + NEGATE = function() { this.negated = !this.negated; return this; }; + exports.Base = Base = (function() { + function Base() {} + Base.prototype.compile = function(o, lvl) { var node; o = extend({}, o); @@ -44,6 +55,7 @@ return node.compileClosure(o); } }; + Base.prototype.compileClosure = function(o) { if (this.jumps() || this instanceof Throw) { throw SyntaxError('cannot use a pure statement in an expression.'); @@ -51,6 +63,7 @@ o.sharedScope = true; return Closure.wrap(this).compileNode(o); }; + Base.prototype.cache = function(o, level, reused) { var ref, sub; if (!this.isComplex()) { @@ -66,6 +79,7 @@ } } }; + Base.prototype.compileLoopReference = function(o, name) { var src, tmp; src = tmp = this.compile(o, LEVEL_LIST); @@ -74,6 +88,7 @@ } return [src, tmp]; }; + Base.prototype.makeReturn = function(res) { var me; me = this.unwrapAll(); @@ -83,6 +98,7 @@ return new Return(me); } }; + Base.prototype.contains = function(pred) { var contains; contains = false; @@ -94,11 +110,13 @@ }); return contains; }; + Base.prototype.containsType = function(type) { return this instanceof type || this.contains(function(node) { return node instanceof type; }); }; + Base.prototype.lastNonComment = function(list) { var i; i = list.length; @@ -107,6 +125,7 @@ } return null; }; + Base.prototype.toString = function(idt, name) { var tree; if (idt == null) idt = ''; @@ -118,6 +137,7 @@ }); return tree; }; + Base.prototype.eachChild = function(func) { var attr, child, _i, _j, _len, _len2, _ref2, _ref3; if (!this.children) return this; @@ -134,15 +154,18 @@ } return this; }; + Base.prototype.traverseChildren = function(crossScope, func) { return this.eachChild(function(child) { if (func(child) === false) return false; return child.traverseChildren(crossScope, func); }); }; + Base.prototype.invert = function() { return new Op('!', this); }; + Base.prototype.unwrapAll = function() { var node; node = this; @@ -151,34 +174,53 @@ } return node; }; + Base.prototype.children = []; + Base.prototype.isStatement = NO; + Base.prototype.jumps = NO; + Base.prototype.isComplex = YES; + Base.prototype.isChainable = NO; + Base.prototype.isAssignable = NO; + Base.prototype.unwrap = THIS; + Base.prototype.unfoldSoak = NO; + Base.prototype.assigns = NO; + return Base; + })(); + exports.Block = Block = (function() { + __extends(Block, Base); + function Block(nodes) { this.expressions = compact(flatten(nodes || [])); } + Block.prototype.children = ['expressions']; + Block.prototype.push = function(node) { this.expressions.push(node); return this; }; + Block.prototype.pop = function() { return this.expressions.pop(); }; + Block.prototype.unshift = function(node) { this.expressions.unshift(node); return this; }; + Block.prototype.unwrap = function() { if (this.expressions.length === 1) { return this.expressions[0]; @@ -186,9 +228,11 @@ return this; } }; + Block.prototype.isEmpty = function() { return !this.expressions.length; }; + Block.prototype.isStatement = function(o) { var exp, _i, _len, _ref2; _ref2 = this.expressions; @@ -198,6 +242,7 @@ } return false; }; + Block.prototype.jumps = function(o) { var exp, _i, _len, _ref2; _ref2 = this.expressions; @@ -206,6 +251,7 @@ if (exp.jumps(o)) return exp; } }; + Block.prototype.makeReturn = function(res) { var expr, len; len = this.expressions.length; @@ -221,6 +267,7 @@ } return this; }; + Block.prototype.compile = function(o, level) { if (o == null) o = {}; if (o.scope) { @@ -229,6 +276,7 @@ return this.compileRoot(o); } }; + Block.prototype.compileNode = function(o) { var code, codes, node, top, _i, _len, _ref2; this.tab = o.indent; @@ -249,7 +297,13 @@ codes.push(node.compile(o, LEVEL_LIST)); } } - if (top) return codes.join('\n'); + if (top) { + if (this.spaced) { + return '\n' + codes.join('\n\n') + '\n'; + } else { + return codes.join('\n'); + } + } code = codes.join(', ') || 'void 0'; if (codes.length > 1 && o.level >= LEVEL_LIST) { return "(" + code + ")"; @@ -257,11 +311,13 @@ return code; } }; + Block.prototype.compileRoot = function(o) { var code; o.indent = this.tab = o.bare ? '' : TAB; o.scope = new Scope(null, this, null); o.level = LEVEL_TOP; + this.spaced = true; code = this.compileWithDeclarations(o); if (o.bare) { return code; @@ -269,6 +325,7 @@ return "(function() {\n" + code + "\n}).call(this);\n"; } }; + Block.prototype.compileWithDeclarations = function(o) { var assigns, code, declars, exp, i, post, rest, scope, _len, _ref2; code = post = ''; @@ -301,17 +358,24 @@ } return code + post; }; + Block.wrap = function(nodes) { if (nodes.length === 1 && nodes[0] instanceof Block) return nodes[0]; return new Block(nodes); }; + return Block; + })(); + exports.Literal = Literal = (function() { + __extends(Literal, Base); + function Literal(value) { this.value = value; } + Literal.prototype.makeReturn = function() { if (this.isStatement()) { return this; @@ -319,17 +383,22 @@ return Literal.__super__.makeReturn.apply(this, arguments); } }; + Literal.prototype.isAssignable = function() { return IDENTIFIER.test(this.value); }; + Literal.prototype.isStatement = function() { var _ref2; return (_ref2 = this.value) === 'break' || _ref2 === 'continue' || _ref2 === 'debugger'; }; + Literal.prototype.isComplex = NO; + Literal.prototype.assigns = function(name) { return name === this.value; }; + Literal.prototype.jumps = function(o) { if (!this.isStatement()) return false; if (!(o && (o.loop || o.block && (this.value !== 'continue')))) { @@ -338,6 +407,7 @@ return false; } }; + Literal.prototype.compileNode = function(o) { var code, _ref2; code = this.isUndefined ? o.level >= LEVEL_ACCESS ? '(void 0)' : 'void 0' : this.value.reserved && ((_ref2 = "" + this.value) !== 'eval' && _ref2 !== 'arguments') ? "\"" + this.value + "\"" : this.value; @@ -347,20 +417,31 @@ return code; } }; + Literal.prototype.toString = function() { return ' "' + this.value + '"'; }; + return Literal; + })(); + exports.Return = Return = (function() { + __extends(Return, Base); + function Return(expr) { if (expr && !expr.unwrap().isUndefined) this.expression = expr; } + Return.prototype.children = ['expression']; + Return.prototype.isStatement = YES; + Return.prototype.makeReturn = THIS; + Return.prototype.jumps = THIS; + Return.prototype.compile = function(o, level) { var expr, _ref2; expr = (_ref2 = this.expression) != null ? _ref2.makeReturn() : void 0; @@ -370,13 +451,19 @@ return Return.__super__.compile.call(this, o, level); } }; + Return.prototype.compileNode = function(o) { return this.tab + ("return" + [this.expression ? " " + (this.expression.compile(o, LEVEL_PAREN)) : void 0] + ";"); }; + return Return; + })(); + exports.Value = Value = (function() { + __extends(Value, Base); + function Value(base, props, tag) { if (!props && base instanceof Value) return base; this.base = base; @@ -384,26 +471,34 @@ if (tag) this[tag] = true; return this; } + Value.prototype.children = ['base', 'properties']; + Value.prototype.add = function(props) { this.properties = this.properties.concat(props); return this; }; + Value.prototype.hasProperties = function() { return !!this.properties.length; }; + Value.prototype.isArray = function() { return !this.properties.length && this.base instanceof Arr; }; + Value.prototype.isComplex = function() { return this.hasProperties() || this.base.isComplex(); }; + Value.prototype.isAssignable = function() { return this.hasProperties() || this.base.isAssignable(); }; + Value.prototype.isSimpleNumber = function() { return this.base instanceof Literal && SIMPLENUM.test(this.base.value); }; + Value.prototype.isAtomic = function() { var node, _i, _len, _ref2; _ref2 = this.properties.concat(this.base); @@ -413,22 +508,28 @@ } return true; }; + Value.prototype.isStatement = function(o) { return !this.properties.length && this.base.isStatement(o); }; + Value.prototype.assigns = function(name) { return !this.properties.length && this.base.assigns(name); }; + Value.prototype.jumps = function(o) { return !this.properties.length && this.base.jumps(o); }; + Value.prototype.isObject = function(onlyGenerated) { if (this.properties.length) return false; return (this.base instanceof Obj) && (!onlyGenerated || this.base.generated); }; + Value.prototype.isSplice = function() { return last(this.properties) instanceof Slice; }; + Value.prototype.unwrap = function() { if (this.properties.length) { return this; @@ -436,6 +537,7 @@ return this.base; } }; + Value.prototype.cacheReference = function(o) { var base, bref, name, nref; name = last(this.properties); @@ -455,6 +557,7 @@ } return [base.add(name), new Value(bref || base.base, [nref || name])]; }; + Value.prototype.compileNode = function(o) { var code, prop, props, _i, _len; this.base.front = this.front; @@ -469,6 +572,7 @@ } return code; }; + Value.prototype.unfoldSoak = function(o) { var result; if (this.unfoldedSoak != null) return this.unfoldedSoak; @@ -498,25 +602,38 @@ }, this)(); return this.unfoldedSoak = result || false; }; + return Value; + })(); + exports.Comment = Comment = (function() { + __extends(Comment, Base); + function Comment(comment) { this.comment = comment; } + Comment.prototype.isStatement = YES; + Comment.prototype.makeReturn = THIS; + Comment.prototype.compileNode = function(o, level) { var code; code = '/*' + multident(this.comment, this.tab) + ("\n" + this.tab + "*/\n"); if ((level || o.level) === LEVEL_TOP) code = o.indent + code; return code; }; + return Comment; + })(); + exports.Call = Call = (function() { + __extends(Call, Base); + function Call(variable, args, soak) { this.args = args != null ? args : []; this.soak = soak; @@ -524,7 +641,9 @@ this.isSuper = variable === 'super'; this.variable = this.isSuper ? null : variable; } + Call.prototype.children = ['variable', 'args']; + Call.prototype.newInstance = function() { var base, _ref2; base = ((_ref2 = this.variable) != null ? _ref2.base : void 0) || this.variable; @@ -535,6 +654,7 @@ } return this; }; + Call.prototype.superReference = function(o) { var accesses, method, name; method = o.scope.method; @@ -552,6 +672,7 @@ return "" + name + ".__super__.constructor"; } }; + Call.prototype.unfoldSoak = function(o) { var call, ifn, left, list, rite, _i, _len, _ref2, _ref3; if (this.soak) { @@ -595,6 +716,7 @@ } return ifn; }; + Call.prototype.filterImplicitObjects = function(list) { var node, nodes, obj, prop, properties, _i, _j, _len, _len2, _ref2; nodes = []; @@ -619,6 +741,7 @@ } return nodes; }; + Call.prototype.compileNode = function(o) { var arg, args, code, _ref2; if ((_ref2 = this.variable) != null) _ref2.front = this.front; @@ -641,9 +764,11 @@ return (this.isNew ? 'new ' : '') + this.variable.compile(o, LEVEL_ACCESS) + ("(" + args + ")"); } }; + Call.prototype.compileSuper = function(args, o) { return "" + (this.superReference(o)) + ".call(this" + (args.length ? ', ' : '') + args + ")"; }; + Call.prototype.compileSplat = function(o, splatArgs) { var base, fun, idt, name, ref; if (this.isSuper) { @@ -669,28 +794,42 @@ } return "" + fun + ".apply(" + ref + ", " + splatArgs + ")"; }; + return Call; + })(); + exports.Extends = Extends = (function() { + __extends(Extends, Base); + function Extends(child, parent) { this.child = child; this.parent = parent; } + Extends.prototype.children = ['child', 'parent']; + Extends.prototype.compile = function(o) { return new Call(new Value(new Literal(utility('extends'))), [this.child, this.parent]).compile(o); }; + return Extends; + })(); + exports.Access = Access = (function() { + __extends(Access, Base); + function Access(name, tag) { this.name = name; this.name.asKey = true; this.soak = tag === 'soak'; } + Access.prototype.children = ['name']; + Access.prototype.compile = function(o) { var name; name = this.name.compile(o); @@ -700,32 +839,48 @@ return "[" + name + "]"; } }; + Access.prototype.isComplex = NO; + return Access; + })(); + exports.Index = Index = (function() { + __extends(Index, Base); + function Index(index) { this.index = index; } + Index.prototype.children = ['index']; + Index.prototype.compile = function(o) { return "[" + (this.index.compile(o, LEVEL_PAREN)) + "]"; }; + Index.prototype.isComplex = function() { return this.index.isComplex(); }; + return Index; + })(); + exports.Range = Range = (function() { + __extends(Range, Base); + Range.prototype.children = ['from', 'to']; + function Range(from, to, tag) { this.from = from; this.to = to; this.exclusive = tag === 'exclusive'; this.equals = this.exclusive ? '' : '='; } + Range.prototype.compileVariables = function(o) { var step, _ref2, _ref3, _ref4, _ref5; o = merge(o, { @@ -739,6 +894,7 @@ _ref5 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref5[0], this.toNum = _ref5[1]; if (this.stepVar) return this.stepNum = this.stepVar.match(SIMPLENUM); }; + Range.prototype.compileNode = function(o) { var cond, condPart, from, gt, idx, known, lt, stepPart, to, varPart, _ref2, _ref3; if (!this.fromVar) this.compileVariables(o); @@ -753,6 +909,7 @@ stepPart = this.stepVar ? "" + idx + " += " + this.stepVar : known ? from <= to ? "" + idx + "++" : "" + idx + "--" : "" + cond + " ? " + idx + "++ : " + idx + "--"; return "" + varPart + "; " + condPart + "; " + stepPart; }; + Range.prototype.compileArray = function(o) { var args, body, cond, hasArgs, i, idt, post, pre, range, result, vars, _i, _ref2, _ref3, _results; if (this.fromNum && this.toNum && Math.abs(this.fromNum - this.toNum) <= 20) { @@ -785,15 +942,22 @@ if (hasArgs(this.from) || hasArgs(this.to)) args = ', arguments'; return "(function() {" + pre + "\n" + idt + "for (" + body + ")" + post + "}).apply(this" + (args != null ? args : '') + ")"; }; + return Range; + })(); + exports.Slice = Slice = (function() { + __extends(Slice, Base); + Slice.prototype.children = ['range']; + function Slice(range) { this.range = range; Slice.__super__.constructor.call(this); } + Slice.prototype.compileNode = function(o) { var compiled, from, fromStr, to, toStr, _ref2; _ref2 = this.range, to = _ref2.to, from = _ref2.from; @@ -804,15 +968,22 @@ } return ".slice(" + fromStr + (toStr || '') + ")"; }; + return Slice; + })(); + exports.Obj = Obj = (function() { + __extends(Obj, Base); + function Obj(props, generated) { this.generated = generated != null ? generated : false; this.objects = this.properties = props || []; } + Obj.prototype.children = ['properties']; + Obj.prototype.compileNode = function(o) { var i, idt, indent, join, lastNoncom, node, obj, prop, props, _i, _len; props = this.properties; @@ -853,6 +1024,7 @@ return obj; } }; + Obj.prototype.assigns = function(name) { var prop, _i, _len, _ref2; _ref2 = this.properties; @@ -862,15 +1034,23 @@ } return false; }; + return Obj; + })(); + exports.Arr = Arr = (function() { + __extends(Arr, Base); + function Arr(objs) { this.objects = objs || []; } + Arr.prototype.children = ['objects']; + Arr.prototype.filterImplicitObjects = Call.prototype.filterImplicitObjects; + Arr.prototype.compileNode = function(o) { var code, obj, objs; if (!this.objects.length) return '[]'; @@ -892,6 +1072,7 @@ return "[" + code + "]"; } }; + Arr.prototype.assigns = function(name) { var obj, _i, _len, _ref2; _ref2 = this.objects; @@ -901,10 +1082,15 @@ } return false; }; + return Arr; + })(); + exports.Class = Class = (function() { + __extends(Class, Base); + function Class(variable, parent, body) { this.variable = variable; this.parent = parent; @@ -912,13 +1098,16 @@ this.boundFuncs = []; this.body.classBody = true; } + Class.prototype.children = ['variable', 'parent', 'body']; + Class.prototype.determineName = function() { var decl, tail; if (!this.variable) return null; decl = (tail = last(this.variable.properties)) ? tail instanceof Access && tail.name.value : this.variable.base.value; return decl && (decl = IDENTIFIER.test(decl) && decl); }; + Class.prototype.setContext = function(name) { return this.body.traverseChildren(false, function(node) { if (node.classBody) return false; @@ -930,6 +1119,7 @@ } }); }; + Class.prototype.addBoundFunctions = function(o) { var bvar, lhs, _i, _len, _ref2, _results; if (this.boundFuncs.length) { @@ -943,6 +1133,7 @@ return _results; } }; + Class.prototype.addProperties = function(node, name, o) { var assign, base, exprs, func, props; props = node.base.properties.slice(0); @@ -985,6 +1176,7 @@ }).call(this); return compact(exprs); }; + Class.prototype.walkBody = function(name, o) { return this.traverseChildren(false, __bind(function(child) { var exps, i, node, _len, _ref2; @@ -1001,6 +1193,7 @@ } }, this)); }; + Class.prototype.ensureConstructor = function(name) { if (!this.ctor) { this.ctor = new Code; @@ -1016,6 +1209,7 @@ this.ctor.klass = null; return this.ctor.noReturn = true; }; + Class.prototype.compileNode = function(o) { var decl, klass, lname, name; decl = this.determineName(); @@ -1025,6 +1219,7 @@ this.setContext(name); this.walkBody(name, o); this.ensureConstructor(name); + this.body.spaced = true; if (this.parent) { this.body.expressions.unshift(new Extends(lname, this.parent)); } @@ -1035,10 +1230,15 @@ if (this.variable) klass = new Assign(this.variable, klass); return klass.compile(o); }; + return Class; + })(); + exports.Assign = Assign = (function() { + __extends(Assign, Base); + function Assign(variable, value, context, options) { this.variable = variable; this.value = value; @@ -1046,16 +1246,21 @@ this.param = options && options.param; this.subpattern = options && options.subpattern; } + Assign.prototype.children = ['variable', 'value']; + Assign.prototype.isStatement = function(o) { return (o != null ? o.level : void 0) === LEVEL_TOP && (this.context != null) && __indexOf.call(this.context, "?") >= 0; }; + Assign.prototype.assigns = function(name) { return this[this.context === 'object' ? 'value' : 'variable'].assigns(name); }; + Assign.prototype.unfoldSoak = function(o) { return unfoldSoak(o, this, 'variable'); }; + Assign.prototype.compileNode = function(o) { var isValue, match, name, val, varBase, _ref2, _ref3, _ref4, _ref5; if (isValue = this.variable instanceof Value) { @@ -1093,6 +1298,7 @@ return "(" + val + ")"; } }; + Assign.prototype.compilePatternMatch = function(o) { var acc, assigns, code, i, idx, isObject, ivar, name, obj, objects, olen, ref, rest, splat, top, val, value, vvar, _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8; top = o.level === LEVEL_TOP; @@ -1190,12 +1396,14 @@ return "(" + code + ")"; } }; + Assign.prototype.compileConditional = function(o) { var left, rite, _ref2; _ref2 = this.variable.cacheReference(o), left = _ref2[0], rite = _ref2[1]; if (__indexOf.call(this.context, "?") >= 0) o.isExistentialEquals = true; return new Op(this.context.slice(0, -1), left, new Assign(rite, this.value, '=')).compile(o); }; + Assign.prototype.compileSplice = function(o) { var code, exclusive, from, fromDecl, fromRef, name, to, valDef, valRef, _ref2, _ref3, _ref4; _ref2 = this.variable.properties.pop().range, from = _ref2.from, to = _ref2.to, exclusive = _ref2.exclusive; @@ -1220,21 +1428,30 @@ return code; } }; + return Assign; + })(); + exports.Code = Code = (function() { + __extends(Code, Base); + function Code(params, body, tag) { this.params = params || []; this.body = body || new Block; this.bound = tag === 'boundfunc'; if (this.bound) this.context = 'this'; } + Code.prototype.children = ['params', 'body']; + Code.prototype.isStatement = function() { return !!this.ctor; }; + Code.prototype.jumps = NO; + Code.prototype.compileNode = function(o) { var code, exprs, i, idt, lit, p, param, ref, splats, v, val, vars, wasEmpty, _i, _j, _k, _len, _len2, _len3, _len4, _ref2, _ref3, _ref4, _ref5; o.scope = new Scope(o.scope, this.body, this); @@ -1313,24 +1530,33 @@ return code; } }; + Code.prototype.traverseChildren = function(crossScope, func) { if (crossScope) { return Code.__super__.traverseChildren.call(this, crossScope, func); } }; + return Code; + })(); + exports.Param = Param = (function() { + __extends(Param, Base); + function Param(name, value, splat) { this.name = name; this.value = value; this.splat = splat; } + Param.prototype.children = ['name', 'value']; + Param.prototype.compile = function(o) { return this.name.compile(o, LEVEL_LIST); }; + Param.prototype.asReference = function(o) { var node; if (this.reference) return this.reference; @@ -1345,21 +1571,31 @@ if (this.splat) node = new Splat(node); return this.reference = node; }; + Param.prototype.isComplex = function() { return this.name.isComplex(); }; + return Param; + })(); + exports.Splat = Splat = (function() { + __extends(Splat, Base); + Splat.prototype.children = ['name']; + Splat.prototype.isAssignable = YES; + function Splat(name) { this.name = name.compile ? name : new Literal(name); } + Splat.prototype.assigns = function(name) { return this.name.assigns(name); }; + Splat.prototype.compile = function(o) { if (this.index != null) { return this.compileParam(o); @@ -1367,9 +1603,11 @@ return this.name.compile(o); } }; + Splat.prototype.unwrap = function() { return this.name; }; + Splat.compileSplattedArray = function(o, list, apply) { var args, base, code, i, index, node, _len; index = -1; @@ -1403,16 +1641,24 @@ })(); return "[" + (base.join(', ')) + "].concat(" + (args.join(', ')) + ")"; }; + return Splat; + })(); + exports.While = While = (function() { + __extends(While, Base); + function While(condition, options) { this.condition = (options != null ? options.invert : void 0) ? condition.invert() : condition; this.guard = options != null ? options.guard : void 0; } + While.prototype.children = ['condition', 'guard', 'body']; + While.prototype.isStatement = YES; + While.prototype.makeReturn = function(res) { if (res) { return While.__super__.makeReturn.apply(this, arguments); @@ -1421,10 +1667,12 @@ return this; } }; + While.prototype.addBody = function(body) { this.body = body; return this; }; + While.prototype.jumps = function() { var expressions, node, _i, _len; expressions = this.body.expressions; @@ -1437,6 +1685,7 @@ } return false; }; + While.prototype.compileNode = function(o) { var body, code, rvar, set; o.indent += TAB; @@ -1462,11 +1711,16 @@ if (this.returns) code += "\n" + this.tab + "return " + rvar + ";"; return code; }; + return While; + })(); + exports.Op = Op = (function() { var CONVERSIONS, INVERSIONS; + __extends(Op, Base); + function Op(op, first, second, flip) { var call; if (op === 'in') return new In(first, second); @@ -1489,28 +1743,36 @@ this.flip = !!flip; return this; } + CONVERSIONS = { '==': '===', '!=': '!==', 'of': 'in' }; + INVERSIONS = { '!==': '===', '===': '!==' }; + Op.prototype.children = ['first', 'second']; + Op.prototype.isSimpleNumber = NO; + Op.prototype.isUnary = function() { return !this.second; }; + Op.prototype.isComplex = function() { var _ref2; return !(this.isUnary() && ((_ref2 = this.operator) === '+' || _ref2 === '-')) || this.first.isComplex(); }; + Op.prototype.isChainable = function() { var _ref2; return (_ref2 = this.operator) === '<' || _ref2 === '>' || _ref2 === '>=' || _ref2 === '<=' || _ref2 === '===' || _ref2 === '!=='; }; + Op.prototype.invert = function() { var allInvertable, curr, fst, op, _ref2; if (this.isChainable() && this.first.isChainable()) { @@ -1540,10 +1802,12 @@ return new Op('!', this); } }; + Op.prototype.unfoldSoak = function(o) { var _ref2; return ((_ref2 = this.operator) === '++' || _ref2 === '--' || _ref2 === 'delete') && unfoldSoak(o, this, 'first'); }; + Op.prototype.compileNode = function(o) { var code, isChain; isChain = this.isChainable() && this.first.isChainable(); @@ -1558,6 +1822,7 @@ return "(" + code + ")"; } }; + Op.prototype.compileChain = function(o) { var code, fst, shared, _ref2; _ref2 = this.first.second.cache(o), this.first.second = _ref2[0], shared = _ref2[1]; @@ -1565,6 +1830,7 @@ code = "" + fst + " " + (this.invert ? '&&' : '||') + " " + (shared.compile(o)) + " " + this.operator + " " + (this.second.compile(o, LEVEL_OP)); return "(" + code + ")"; }; + Op.prototype.compileExistence = function(o) { var fst, ref; if (this.first.isComplex()) { @@ -1578,6 +1844,7 @@ type: 'if' }).addElse(this.second).compile(o); }; + Op.prototype.compileUnary = function(o) { var op, parts, plusMinus; parts = [op = this.operator]; @@ -1592,19 +1859,28 @@ if (this.flip) parts.reverse(); return parts.join(''); }; + Op.prototype.toString = function(idt) { return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator); }; + return Op; + })(); + exports.In = In = (function() { + __extends(In, Base); + function In(object, array) { this.object = object; this.array = array; } + In.prototype.children = ['object', 'array']; + In.prototype.invert = NEGATE; + In.prototype.compileNode = function(o) { var hasSplat, obj, _i, _len, _ref2; if (this.array instanceof Value && this.array.isArray()) { @@ -1619,6 +1895,7 @@ } return this.compileLoopTest(o); }; + In.prototype.compileOrTest = function(o) { var cmp, cnj, i, item, ref, sub, tests, _ref2, _ref3; _ref2 = this.object.cache(o, LEVEL_OP), sub = _ref2[0], ref = _ref2[1]; @@ -1641,6 +1918,7 @@ return "(" + tests + ")"; } }; + In.prototype.compileLoopTest = function(o) { var code, ref, sub, _ref2; _ref2 = this.object.cache(o, LEVEL_LIST), sub = _ref2[0], ref = _ref2[1]; @@ -1653,30 +1931,41 @@ return "(" + code + ")"; } }; + In.prototype.toString = function(idt) { return In.__super__.toString.call(this, idt, this.constructor.name + (this.negated ? '!' : '')); }; + return In; + })(); + exports.Try = Try = (function() { + __extends(Try, Base); + function Try(attempt, error, recovery, ensure) { this.attempt = attempt; this.error = error; this.recovery = recovery; this.ensure = ensure; } + Try.prototype.children = ['attempt', 'recovery', 'ensure']; + Try.prototype.isStatement = YES; + Try.prototype.jumps = function(o) { var _ref2; return this.attempt.jumps(o) || ((_ref2 = this.recovery) != null ? _ref2.jumps(o) : void 0); }; + Try.prototype.makeReturn = function(res) { if (this.attempt) this.attempt = this.attempt.makeReturn(res); if (this.recovery) this.recovery = this.recovery.makeReturn(res); return this; }; + Try.prototype.compileNode = function(o) { var catchPart, ensurePart, errorPart, tryPart; o.indent += TAB; @@ -1686,29 +1975,47 @@ ensurePart = this.ensure ? " finally {\n" + (this.ensure.compile(o, LEVEL_TOP)) + "\n" + this.tab + "}" : ''; return "" + this.tab + "try {\n" + tryPart + "\n" + this.tab + "}" + (catchPart || '') + ensurePart; }; + return Try; + })(); + exports.Throw = Throw = (function() { + __extends(Throw, Base); + function Throw(expression) { this.expression = expression; } + Throw.prototype.children = ['expression']; + Throw.prototype.isStatement = YES; + Throw.prototype.jumps = NO; + Throw.prototype.makeReturn = THIS; + Throw.prototype.compileNode = function(o) { return this.tab + ("throw " + (this.expression.compile(o)) + ";"); }; + return Throw; + })(); + exports.Existence = Existence = (function() { + __extends(Existence, Base); + function Existence(expression) { this.expression = expression; } + Existence.prototype.children = ['expression']; + Existence.prototype.invert = NEGATE; + Existence.prototype.compileNode = function(o) { var cmp, cnj, code, _ref2; this.expression.front = this.front; @@ -1725,20 +2032,29 @@ return "(" + code + ")"; } }; + return Existence; + })(); + exports.Parens = Parens = (function() { + __extends(Parens, Base); + function Parens(body) { this.body = body; } + Parens.prototype.children = ['body']; + Parens.prototype.unwrap = function() { return this.body; }; + Parens.prototype.isComplex = function() { return this.body.isComplex(); }; + Parens.prototype.compileNode = function(o) { var bare, code, expr; expr = this.body.unwrap(); @@ -1754,10 +2070,15 @@ return "(" + code + ")"; } }; + return Parens; + })(); + exports.For = For = (function() { + __extends(For, While); + function For(body, source) { var _ref2; this.source = source.source, this.guard = source.guard, this.step = source.step, this.name = source.name, this.index = source.index; @@ -1780,7 +2101,9 @@ } this.returns = false; } + For.prototype.children = ['body', 'source', 'guard', 'step']; + For.prototype.compileNode = function(o) { var body, defPart, forPart, forVarPart, guardPart, idt1, index, ivar, lastJumps, lvar, name, namePart, ref, resultPart, returnResult, rvar, scope, source, stepPart, stepvar, svar, varPart, _ref2; body = Block.wrap([this.body]); @@ -1858,6 +2181,7 @@ if (body) body = '\n' + body + '\n'; return "" + defPart + (resultPart || '') + this.tab + "for (" + forPart + ") {" + guardPart + varPart + body + this.tab + "}" + (returnResult || ''); }; + For.prototype.pluckDirectCall = function(o, body) { var base, defs, expr, fn, idx, ref, val, _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7; defs = ''; @@ -1879,17 +2203,25 @@ } return defs; }; + return For; + })(); + exports.Switch = Switch = (function() { + __extends(Switch, Base); + function Switch(subject, cases, otherwise) { this.subject = subject; this.cases = cases; this.otherwise = otherwise; } + Switch.prototype.children = ['subject', 'cases', 'otherwise']; + Switch.prototype.isStatement = YES; + Switch.prototype.jumps = function(o) { var block, conds, _i, _len, _ref2, _ref3, _ref4; if (o == null) { @@ -1904,6 +2236,7 @@ } return (_ref4 = this.otherwise) != null ? _ref4.jumps(o) : void 0; }; + Switch.prototype.makeReturn = function(res) { var pair, _i, _len, _ref2, _ref3; _ref2 = this.cases; @@ -1917,6 +2250,7 @@ if ((_ref3 = this.otherwise) != null) _ref3.makeReturn(res); return this; }; + Switch.prototype.compileNode = function(o) { var block, body, code, cond, conditions, expr, i, idt1, idt2, _i, _len, _len2, _ref2, _ref3, _ref4, _ref5; idt1 = o.indent + TAB; @@ -1944,10 +2278,15 @@ } return code + this.tab + '}'; }; + return Switch; + })(); + exports.If = If = (function() { + __extends(If, Base); + function If(condition, body, options) { this.body = body; if (options == null) options = {}; @@ -1956,15 +2295,19 @@ this.isChain = false; this.soak = options.soak; } + If.prototype.children = ['condition', 'body', 'elseBody']; + If.prototype.bodyNode = function() { var _ref2; return (_ref2 = this.body) != null ? _ref2.unwrap() : void 0; }; + If.prototype.elseBodyNode = function() { var _ref2; return (_ref2 = this.elseBody) != null ? _ref2.unwrap() : void 0; }; + If.prototype.addElse = function(elseBody) { if (this.isChain) { this.elseBodyNode().addElse(elseBody); @@ -1974,14 +2317,17 @@ } return this; }; + If.prototype.isStatement = function(o) { var _ref2; return (o != null ? o.level : void 0) === LEVEL_TOP || this.bodyNode().isStatement(o) || ((_ref2 = this.elseBodyNode()) != null ? _ref2.isStatement(o) : void 0); }; + If.prototype.jumps = function(o) { var _ref2; return this.body.jumps(o) || ((_ref2 = this.elseBody) != null ? _ref2.jumps(o) : void 0); }; + If.prototype.compileNode = function(o) { if (this.isStatement(o)) { return this.compileStatement(o); @@ -1989,6 +2335,7 @@ return this.compileExpression(o); } }; + If.prototype.makeReturn = function(res) { if (res) { this.elseBody || (this.elseBody = new Block([new Literal('void 0')])); @@ -1997,6 +2344,7 @@ this.elseBody && (this.elseBody = new Block([this.elseBody.makeReturn(res)])); return this; }; + If.prototype.ensureBlock = function(node) { if (node instanceof Block) { return node; @@ -2004,6 +2352,7 @@ return new Block([node]); } }; + If.prototype.compileStatement = function(o) { var body, bodyc, child, cond, exeq, ifPart, _ref2; child = del(o, 'chainChild'); @@ -2026,6 +2375,7 @@ if (!this.elseBody) return ifPart; return ifPart + ' else ' + (this.isChain ? (o.indent = this.tab, o.chainChild = true, this.elseBody.unwrap().compile(o, LEVEL_TOP)) : "{\n" + (this.elseBody.compile(o, LEVEL_TOP)) + "\n" + this.tab + "}"); }; + If.prototype.compileExpression = function(o) { var alt, body, code, cond; cond = this.condition.compile(o, LEVEL_COND); @@ -2038,11 +2388,15 @@ return code; } }; + If.prototype.unfoldSoak = function() { return this.soak && this; }; + return If; + })(); + Closure = { wrap: function(expressions, statement, noReturn) { var args, call, func, mentionsArgs, meth; @@ -2070,6 +2424,7 @@ return (node instanceof Literal && node.value === 'this' && !node.asKey) || (node instanceof Code && node.bound); } }; + unfoldSoak = function(o, parent, name) { var ifn; if (!(ifn = parent[name].unfoldSoak(o))) return; @@ -2077,6 +2432,7 @@ ifn.body = new Value(parent); return ifn; }; + UTILITIES = { "extends": function() { return "function(child, parent) {\n for (var key in parent) { if (" + (utility('hasProp')) + ".call(parent, key)) child[key] = parent[key]; }\n function ctor() { this.constructor = child; }\n ctor.prototype = parent.prototype;\n child.prototype = new ctor;\n child.__super__ = parent.prototype;\n return child;\n}"; @@ -2094,26 +2450,41 @@ return 'Array.prototype.slice'; } }; + LEVEL_TOP = 1; + LEVEL_PAREN = 2; + LEVEL_LIST = 3; + LEVEL_COND = 4; + LEVEL_OP = 5; + LEVEL_ACCESS = 6; + TAB = ' '; + IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"; + IDENTIFIER = RegExp("^" + IDENTIFIER_STR + "$"); + SIMPLENUM = /^[+-]?\d+$/; + METHOD_DEF = RegExp("^(?:(" + IDENTIFIER_STR + ")\\.prototype(?:\\.(" + IDENTIFIER_STR + ")|\\[(\"(?:[^\\\\\"\\r\\n]|\\\\.)*\"|'(?:[^\\\\'\\r\\n]|\\\\.)*')\\]|\\[(0x[\\da-fA-F]+|\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\]))|(" + IDENTIFIER_STR + ")$"); + IS_STRING = /^['"]/; + utility = function(name) { var ref; ref = "__" + name; Scope.root.assign(ref, UTILITIES[name]()); return ref; }; + multident = function(code, tab) { code = code.replace(/\n/g, '$&' + tab); return code.replace(/\s+$/, ''); }; + }).call(this); diff --git a/lib/coffee-script/optparse.js b/lib/coffee-script/optparse.js index 92082411..6555fd71 100644 --- a/lib/coffee-script/optparse.js +++ b/lib/coffee-script/optparse.js @@ -1,10 +1,13 @@ (function() { var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments; + exports.OptionParser = OptionParser = (function() { + function OptionParser(rules, banner) { this.banner = banner; this.rules = buildRules(rules); } + OptionParser.prototype.parse = function(args) { var arg, i, isOption, matchedRule, options, rule, value, _i, _len, _len2, _ref; options = { @@ -40,6 +43,7 @@ } return options; }; + OptionParser.prototype.help = function() { var letPart, lines, rule, spaces, _i, _len, _ref; lines = []; @@ -54,12 +58,19 @@ } return "\n" + (lines.join('\n')) + "\n"; }; + return OptionParser; + })(); + LONG_FLAG = /^(--\w[\w\-]+)/; + SHORT_FLAG = /^(-\w)/; + MULTI_FLAG = /^-(\w{2,})/; + OPTIONAL = /\[(\w+(\*?))\]/; + buildRules = function(rules) { var tuple, _i, _len, _results; _results = []; @@ -70,6 +81,7 @@ } return _results; }; + buildRule = function(shortFlag, longFlag, description, options) { var match; if (options == null) options = {}; @@ -84,6 +96,7 @@ isList: !!(match && match[2]) }; }; + normalizeArguments = function(args) { var arg, l, match, result, _i, _j, _len, _len2, _ref; args = args.slice(0); @@ -102,4 +115,5 @@ } return result; }; + }).call(this); diff --git a/lib/coffee-script/repl.js b/lib/coffee-script/repl.js index 0a24e352..408de58a 100644 --- a/lib/coffee-script/repl.js +++ b/lib/coffee-script/repl.js @@ -1,29 +1,47 @@ (function() { var ACCESSOR, CoffeeScript, Module, REPL_PROMPT, REPL_PROMPT_CONTINUATION, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, g, getCompletions, inspect, nonContextGlobals, readline, repl, run, sandbox, stdin, stdout, _i, _len; + CoffeeScript = require('./coffee-script'); + readline = require('readline'); + inspect = require('util').inspect; + Script = require('vm').Script; + Module = require('module'); + REPL_PROMPT = 'coffee> '; + REPL_PROMPT_CONTINUATION = '......> '; + enableColours = false; + if (process.platform !== 'win32') { enableColours = !process.env.NODE_DISABLE_COLORS; } + stdin = process.openStdin(); + stdout = process.stdout; + error = function(err) { return stdout.write((err.stack || err.toString()) + '\n\n'); }; + backlog = ''; + sandbox = Script.createContext(); + nonContextGlobals = ['Buffer', 'console', 'process', 'setInterval', 'clearInterval', 'setTimeout', 'clearTimeout']; + for (_i = 0, _len = nonContextGlobals.length; _i < _len; _i++) { g = nonContextGlobals[_i]; sandbox[g] = global[g]; } + sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox; + run = function(buffer) { var code, returnValue, _; if (!buffer.toString().trim() && !backlog) { @@ -56,11 +74,15 @@ } return repl.prompt(); }; + ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/; + SIMPLEVAR = /\s*(\w*)$/i; + autocomplete = function(text) { return completeAttribute(text) || completeVariable(text) || [[], text]; }; + completeAttribute = function(text) { var all, completions, match, obj, prefix, val; if (match = text.match(ACCESSOR)) { @@ -74,6 +96,7 @@ return [completions, prefix]; } }; + completeVariable = function(text) { var completions, free, keywords, possibilities, r, vars, _ref; free = (_ref = text.match(SIMPLEVAR)) != null ? _ref[1] : void 0; @@ -94,6 +117,7 @@ return [completions, free]; } }; + getCompletions = function(prefix, candidates) { var el, _j, _len2, _results; _results = []; @@ -103,7 +127,9 @@ } return _results; }; + process.on('uncaughtException', error); + if (readline.createInterface.length < 3) { repl = readline.createInterface(stdin, autocomplete); stdin.on('data', function(buffer) { @@ -112,6 +138,7 @@ } else { repl = readline.createInterface(stdin, stdout, autocomplete); } + repl.on('attemptClose', function() { if (backlog) { backlog = ''; @@ -122,11 +149,16 @@ return repl.close(); } }); + repl.on('close', function() { process.stdout.write('\n'); return stdin.destroy(); }); + repl.on('line', run); + repl.setPrompt(REPL_PROMPT); + repl.prompt(); + }).call(this); diff --git a/lib/coffee-script/rewriter.js b/lib/coffee-script/rewriter.js index ed360e6c..478e4398 100644 --- a/lib/coffee-script/rewriter.js +++ b/lib/coffee-script/rewriter.js @@ -6,8 +6,11 @@ } return -1; }, __slice = Array.prototype.slice; + exports.Rewriter = (function() { + function Rewriter() {} + Rewriter.prototype.rewrite = function(tokens) { this.tokens = tokens; this.removeLeadingNewlines(); @@ -20,6 +23,7 @@ this.addImplicitParentheses(); return this.tokens; }; + Rewriter.prototype.scanTokens = function(block) { var i, token, tokens; tokens = this.tokens; @@ -29,6 +33,7 @@ } return true; }; + Rewriter.prototype.detectEnd = function(i, condition, action) { var levels, token, tokens, _ref, _ref2; tokens = this.tokens; @@ -47,6 +52,7 @@ } return i - 1; }; + Rewriter.prototype.removeLeadingNewlines = function() { var i, tag, _len, _ref; _ref = this.tokens; @@ -56,6 +62,7 @@ } if (i) return this.tokens.splice(0, i); }; + Rewriter.prototype.removeMidExpressionNewlines = function() { return this.scanTokens(function(token, i, tokens) { var _ref; @@ -66,6 +73,7 @@ return 0; }); }; + Rewriter.prototype.closeOpenCalls = function() { var action, condition; condition = function(token, i) { @@ -80,6 +88,7 @@ return 1; }); }; + Rewriter.prototype.closeOpenIndexes = function() { var action, condition; condition = function(token, i) { @@ -94,6 +103,7 @@ return 1; }); }; + Rewriter.prototype.addImplicitBraces = function() { var action, condition, stack, start, startIndent; stack = []; @@ -139,6 +149,7 @@ return 2; }); }; + Rewriter.prototype.addImplicitParentheses = function() { var action, noCall; noCall = false; @@ -179,6 +190,7 @@ return 2; }); }; + Rewriter.prototype.addImplicitIndentation = function() { return this.scanTokens(function(token, i, tokens) { var action, condition, indent, outdent, starter, tag, _ref, _ref2; @@ -215,6 +227,7 @@ return 1; }); }; + Rewriter.prototype.tagPostfixConditionals = function() { var condition; condition = function(token, i) { @@ -231,31 +244,50 @@ return 1; }); }; + Rewriter.prototype.indentation = function(token) { return [['INDENT', 2, token[2]], ['OUTDENT', 2, token[2]]]; }; + Rewriter.prototype.tag = function(i) { var _ref; return (_ref = this.tokens[i]) != null ? _ref[0] : void 0; }; + return Rewriter; + })(); + BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END']]; + exports.INVERSES = INVERSES = {}; + EXPRESSION_START = []; + EXPRESSION_END = []; + for (_i = 0, _len = BALANCED_PAIRS.length; _i < _len; _i++) { _ref = BALANCED_PAIRS[_i], left = _ref[0], rite = _ref[1]; EXPRESSION_START.push(INVERSES[rite] = left); EXPRESSION_END.push(INVERSES[left] = rite); } + EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END); + IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS']; + IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', 'SUPER', '@', '->', '=>', '[', '(', '{', '--', '++']; + IMPLICIT_UNSPACED_CALL = ['+', '-']; + IMPLICIT_BLOCK = ['->', '=>', '{', '[', ',']; + IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR']; + SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN']; + SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN']; + LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT']; + }).call(this); diff --git a/lib/coffee-script/scope.js b/lib/coffee-script/scope.js index e9842678..df1415ea 100644 --- a/lib/coffee-script/scope.js +++ b/lib/coffee-script/scope.js @@ -1,8 +1,12 @@ (function() { var Scope, extend, last, _ref; + _ref = require('./helpers'), extend = _ref.extend, last = _ref.last; + exports.Scope = Scope = (function() { + Scope.root = null; + function Scope(parent, expressions, method) { this.parent = parent; this.expressions = expressions; @@ -16,6 +20,7 @@ this.positions = {}; if (!this.parent) Scope.root = this; } + Scope.prototype.add = function(name, type, immediate) { var pos; if (this.shared && !immediate) return this.parent.add(name, type, immediate); @@ -28,21 +33,25 @@ }) - 1; } }; + Scope.prototype.find = function(name, options) { if (this.check(name, options)) return true; this.add(name, 'var'); return false; }; + Scope.prototype.parameter = function(name) { if (this.shared && this.parent.check(name, true)) return; return this.add(name, 'param'); }; + Scope.prototype.check = function(name, immediate) { var found, _ref2; found = !!this.type(name); if (found || immediate) return found; return !!((_ref2 = this.parent) != null ? _ref2.check(name) : void 0); }; + Scope.prototype.temporary = function(name, index) { if (name.length > 1) { return '_' + name + (index > 1 ? index : ''); @@ -50,6 +59,7 @@ return '_' + (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a'); } }; + Scope.prototype.type = function(name) { var v, _i, _len, _ref2; _ref2 = this.variables; @@ -59,6 +69,7 @@ } return null; }; + Scope.prototype.freeVariable = function(type) { var index, temp; index = 0; @@ -68,6 +79,7 @@ this.add(temp, 'var', true); return temp; }; + Scope.prototype.assign = function(name, value) { this.add(name, { value: value, @@ -75,9 +87,11 @@ }); return this.hasAssignments = true; }; + Scope.prototype.hasDeclarations = function() { return !!this.declaredVariables().length; }; + Scope.prototype.declaredVariables = function() { var realVars, tempVars, v, _i, _len, _ref2; realVars = []; @@ -91,6 +105,7 @@ } return realVars.sort().concat(tempVars.sort()); }; + Scope.prototype.assignedVariables = function() { var v, _i, _len, _ref2, _results; _ref2 = this.variables; @@ -101,6 +116,9 @@ } return _results; }; + return Scope; + })(); + }).call(this); diff --git a/src/nodes.coffee b/src/nodes.coffee index 9eae273e..a6b979d4 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -230,7 +230,11 @@ exports.Block = class Block extends Base codes.push if node.isStatement o then code else "#{@tab}#{code};" else codes.push node.compile o, LEVEL_LIST - return codes.join '\n' if top + if top + if @spaced + return '\n' + codes.join('\n\n') + '\n' + else + return codes.join '\n' code = codes.join(', ') or 'void 0' if codes.length > 1 and o.level >= LEVEL_LIST then "(#{code})" else code @@ -242,6 +246,7 @@ exports.Block = class Block extends Base o.indent = @tab = if o.bare then '' else TAB o.scope = new Scope null, this, null o.level = LEVEL_TOP + @spaced = yes code = @compileWithDeclarations o if o.bare then code else "(function() {\n#{code}\n}).call(this);\n" @@ -903,6 +908,7 @@ exports.Class = class Class extends Base @setContext name @walkBody name, o @ensureConstructor name + @body.spaced = yes @body.expressions.unshift new Extends lname, @parent if @parent @body.expressions.unshift @ctor unless @ctor instanceof Code @body.expressions.push lname