From 9df3e6a538e22b69809ae722f2bd057304f2b9fa Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sat, 7 Aug 2010 08:02:16 -0400 Subject: [PATCH] first step towards requiring #{ ... } interpolation -- removing naked interps from the compiler. --- Cakefile | 28 +-- documentation/coffee/cake_tasks.coffee | 2 +- documentation/coffee/interpolation.coffee | 2 +- .../coffee/interpolation_expression.coffee | 2 +- lib/cake.js | 6 +- lib/coffee-script.js | 2 +- lib/command.js | 10 +- lib/grammar.js | 4 +- lib/lexer.js | 24 +-- lib/nodes.js | 186 ++++++++--------- lib/optparse.js | 6 +- lib/rewriter.js | 2 +- lib/scope.js | 2 +- src/cake.coffee | 6 +- src/coffee-script.coffee | 2 +- src/command.coffee | 10 +- src/grammar.coffee | 4 +- src/lexer.coffee | 25 ++- src/nodes.coffee | 192 +++++++++--------- src/optparse.coffee | 6 +- src/repl.coffee | 2 +- src/rewriter.coffee | 2 +- src/scope.coffee | 2 +- test/test_classes.coffee | 10 +- test/test_heredocs.coffee | 6 +- test/test_pattern_matching.coffee | 6 +- test/test_regexp_interpolation.coffee | 10 +- test/test_string_interpolation.coffee | 25 +-- 28 files changed, 284 insertions(+), 300 deletions(-) diff --git a/Cakefile b/Cakefile index 77c7c4db..9273c3bf 100644 --- a/Cakefile +++ b/Cakefile @@ -16,25 +16,25 @@ run = (args) -> # Log a message with a color. log = (message, color, explanation) -> - puts "#color#message#reset #{explanation or ''}" + puts color + message + reset + ' ' + (explanation or '') option '-p', '--prefix [DIR]', 'set the installation prefix for `cake install`' task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options) -> base = options.prefix or '/usr/local' - lib = "#base/lib/coffee-script" - bin = "#base/bin" + lib = "#{base}/lib/coffee-script" + bin = "#{base}/bin" node = "~/.node_libraries/coffee-script" - puts "Installing CoffeeScript to #lib" - puts "Linking to #node" - puts "Linking 'coffee' to #bin/coffee" + puts "Installing CoffeeScript to #{lib}" + puts "Linking to #{node}" + puts "Linking 'coffee' to #{bin}/coffee" exec([ - "mkdir -p #lib #bin" - "cp -rf bin lib LICENSE README package.json src #lib" - "ln -sf #lib/bin/coffee #bin/coffee" - "ln -sf #lib/bin/cake #bin/cake" + "mkdir -p #{lib} #{bin}" + "cp -rf bin lib LICENSE README package.json src #{lib}" + "ln -sf #{lib}/bin/coffee #{bin}/coffee" + "ln -sf #{lib}/bin/cake #{bin}/cake" "mkdir -p ~/.node_libraries" - "ln -sf #lib/lib #node" + "ln -sf #{lib}/lib #{node}" ].join(' && '), (err, stdout, stderr) -> if err then print stderr else log 'done', green ) @@ -103,9 +103,9 @@ task 'test', 'run the CoffeeScript language test suite', -> } process.on 'exit', -> time = ((new Date - startTime) / 1000).toFixed(2) - message = "passed #passedTests tests in #time seconds#reset" + message = "passed #{passedTests} tests in #{time} seconds#{reset}" if failedTests - log "failed #failedTests and #message", red + log "failed #{failedTests} and #{message}", red else log message, green fs.readdir 'test', (err, files) -> @@ -117,4 +117,4 @@ task 'test', 'run the CoffeeScript language test suite', -> CoffeeScript.run code.toString(), {fileName} catch err failedTests += 1 - log "failed #fileName", red, '\n' + err.stack.toString() + log "failed #{fileName}", red, '\n' + err.stack.toString() diff --git a/documentation/coffee/cake_tasks.coffee b/documentation/coffee/cake_tasks.coffee index 04089ff8..0dd914af 100644 --- a/documentation/coffee/cake_tasks.coffee +++ b/documentation/coffee/cake_tasks.coffee @@ -6,4 +6,4 @@ task 'build:parser', 'rebuild the Jison parser', -> require 'jison' code = require('./lib/grammar').parser.generate() dir = options.output or 'lib' - fs.writeFile "#dir/parser.js", code \ No newline at end of file + fs.writeFile "#{dir}/parser.js", code \ No newline at end of file diff --git a/documentation/coffee/interpolation.coffee b/documentation/coffee/interpolation.coffee index df3571d0..de02de4b 100644 --- a/documentation/coffee/interpolation.coffee +++ b/documentation/coffee/interpolation.coffee @@ -1,2 +1,2 @@ author = "Wittgenstein" -quote = "A picture is a fact. -- #author" \ No newline at end of file +quote = "A picture is a fact. -- #{author}" \ No newline at end of file diff --git a/documentation/coffee/interpolation_expression.coffee b/documentation/coffee/interpolation_expression.coffee index 1baa482a..49332cd4 100644 --- a/documentation/coffee/interpolation_expression.coffee +++ b/documentation/coffee/interpolation_expression.coffee @@ -1,6 +1,6 @@ sentence = "#{ 22 / 7 } is a decent approximation of π" sep = "[.\\/\\- ]" -dates = /\d+#sep\d+#sep\d+/g +dates = /\d+#{sep}\d+#{sep}\d+/g diff --git a/lib/cake.js b/lib/cake.js index 0ca9f6f8..9fb7fa10 100755 --- a/lib/cake.js +++ b/lib/cake.js @@ -70,15 +70,15 @@ } return _b; })().join('') : ''; - desc = task.description ? ("# " + task.description) : ''; - puts("cake " + name + spaces + " " + desc); + desc = task.description ? ("# " + (task.description)) : ''; + puts(("cake " + (name) + (spaces) + " " + (desc))); } if (switches.length) { return puts(oparse.help()); } }; missingTask = function(task) { - puts("No such task: \"" + task + "\""); + puts(("No such task: \"" + (task) + "\"")); return process.exit(1); }; })(); diff --git a/lib/coffee-script.js b/lib/coffee-script.js index 47c3d94d..6d613841 100644 --- a/lib/coffee-script.js +++ b/lib/coffee-script.js @@ -23,7 +23,7 @@ return (parser.parse(lexer.tokenize(code))).compile(options); } catch (err) { if (options.fileName) { - err.message = ("In " + options.fileName + ", " + err.message); + err.message = ("In " + (options.fileName) + ", " + (err.message)); } throw err; } diff --git a/lib/command.js b/lib/command.js index f7809023..6d1235a3 100644 --- a/lib/command.js +++ b/lib/command.js @@ -58,7 +58,7 @@ compile = function(source, topLevel) { return path.exists(source, function(exists) { if (!(exists)) { - throw new Error("File not found: " + source); + throw new Error(("File not found: " + (source))); } return fs.stat(source, function(err, stats) { if (stats.isDirectory()) { @@ -155,12 +155,12 @@ } return fs.writeFile(jsPath, js, function(err) { if (options.compile && options.watch) { - return puts("Compiled " + source); + return puts(("Compiled " + (source))); } }); }; return path.exists(dir, function(exists) { - return exists ? compile() : exec(("mkdir -p " + dir), compile); + return exists ? compile() : exec(("mkdir -p " + (dir)), compile); }); }; lint = function(js) { @@ -184,7 +184,7 @@ _f = [token[0], token[1].toString().replace(/\n/, '\\n')]; tag = _f[0]; value = _f[1]; - return "[" + tag + " " + value + "]"; + return "[" + (tag) + " " + (value) + "]"; })()); } return _b; @@ -213,7 +213,7 @@ return process.exit(0); }; version = function() { - puts("CoffeeScript version " + CoffeeScript.VERSION); + puts(("CoffeeScript version " + (CoffeeScript.VERSION))); return process.exit(0); }; })(); diff --git a/lib/grammar.js b/lib/grammar.js index 61dc8ff6..949f9116 100644 --- a/lib/grammar.js +++ b/lib/grammar.js @@ -8,8 +8,8 @@ if (!(action)) { return [patternString, '$$ = $1;', options]; } - action = (match = (action + '').match(unwrap)) ? match[1] : ("(" + action + "())"); - return [patternString, ("$$ = " + action + ";"), options]; + action = (match = (action + '').match(unwrap)) ? match[1] : ("(" + (action) + "())"); + return [patternString, ("$$ = " + (action) + ";"), options]; }; grammar = { Root: [ diff --git a/lib/lexer.js b/lib/lexer.js index 4223fb4c..62677b3e 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -89,7 +89,7 @@ if (include(JS_FORBIDDEN, id)) { if (forcedIdentifier) { tag = 'STRING'; - id = ("\"" + id + "\""); + id = ("\"" + (id) + "\""); if (forcedIdentifier === 'accessor') { close_index = true; if (this.tag() !== '@') { @@ -146,7 +146,7 @@ doc = this.sanitizeHeredoc(match[2] || match[4], { quote: quote }); - this.interpolateString(("" + quote + doc + quote), { + this.interpolateString(quote + doc + quote, { heredoc: true }); this.line += count(match[1], "\n"); @@ -204,11 +204,11 @@ return '\\' + escaped; }); this.tokens = this.tokens.concat([['(', '('], ['NEW', 'new'], ['IDENTIFIER', 'RegExp'], ['CALL_START', '(']]); - this.interpolateString(("\"" + str + "\""), { + this.interpolateString(("\"" + (str) + "\""), { escapeQuotes: true }); if (flags) { - this.tokens.splice(this.tokens.length, 0, [',', ','], ['STRING', ("\"" + flags + "\"")]); + this.tokens.splice(this.tokens.length, 0, [',', ','], ['STRING', ("\"" + (flags) + "\"")]); } this.tokens.splice(this.tokens.length, 0, [')', ')'], [')', ')']); } else { @@ -377,7 +377,7 @@ if (options.herecomment) { return doc; } - return doc.replace(MULTILINER, "\\n").replace(new RegExp(options.quote, 'g'), ("\\" + options.quote)); + return doc.replace(MULTILINER, "\\n").replace(new RegExp(options.quote, 'g'), ("\\" + (options.quote))); }; Lexer.prototype.tagParameters = function() { var _d, i, tok; @@ -405,7 +405,7 @@ return this.outdentToken(this.indent); }; Lexer.prototype.identifierError = function(word) { - throw new Error(("SyntaxError: Reserved word \"" + word + "\" on line " + (this.line + 1))); + throw new Error(("SyntaxError: Reserved word \"" + (word) + "\" on line " + (this.line + 1))); }; Lexer.prototype.assignmentError = function() { throw new Error(("SyntaxError: Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned")); @@ -476,21 +476,21 @@ interp = ("this." + (interp.substring(1))); } if (pi < i) { - tokens.push(['STRING', ("" + quote + (str.substring(pi, i)) + quote)]); + tokens.push(['STRING', quote + str.substring(pi, i) + quote]); } tokens.push(['IDENTIFIER', interp]); i += group.length - 1; pi = i + 1; } else if ((expr = this.balancedString(str.substring(i), [['#{', '}']]))) { if (pi < i) { - tokens.push(['STRING', ("" + quote + (str.substring(pi, i)) + quote)]); + tokens.push(['STRING', quote + str.substring(pi, i) + quote]); } inner = expr.substring(2, expr.length - 1); if (inner.length) { if (options.heredoc) { inner = inner.replace(new RegExp('\\\\' + quote, 'g'), quote); } - nested = lexer.tokenize(("(" + inner + ")"), { + nested = lexer.tokenize(("(" + (inner) + ")"), { line: this.line }); _f = nested; @@ -501,7 +501,7 @@ nested.pop(); tokens.push(['TOKENS', nested]); } else { - tokens.push(['STRING', ("" + quote + quote)]); + tokens.push(['STRING', quote + quote]); } i += expr.length - 1; pi = i + 1; @@ -509,7 +509,7 @@ i += 1; } if (pi < i && pi < str.length - 1) { - tokens.push(['STRING', ("" + quote + (str.substring(pi, i)) + quote)]); + tokens.push(['STRING', quote + str.substring(pi, i) + quote]); } if (!(tokens[0][0] === 'STRING')) { tokens.unshift(['STRING', '""']); @@ -528,7 +528,7 @@ this.tokens = this.tokens.concat(value); } else if (tag === 'STRING' && options.escapeQuotes) { escaped = value.substring(1, value.length - 1).replace(/"/g, '\\"'); - this.token(tag, ("\"" + escaped + "\"")); + this.token(tag, ("\"" + (escaped) + "\"")); } else { this.token(tag, value); } diff --git a/lib/nodes.js b/lib/nodes.js index a4404653..f64ef318 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -228,16 +228,16 @@ code = this.compileWithDeclarations(o); code = code.replace(TRAILING_WHITESPACE, ''); code = code.replace(DOUBLE_PARENS, '($1)'); - return o.noWrap ? code : ("(function() {\n" + code + "\n})();\n"); + return o.noWrap ? code : ("(function() {\n" + (code) + "\n})();\n"); }; Expressions.prototype.compileWithDeclarations = function(o) { var code; code = this.compileNode(o); if (o.scope.hasAssignments(this)) { - code = ("" + (this.tab) + "var " + (o.scope.compiledAssignments()) + ";\n" + code); + code = ("" + (this.tab) + "var " + (o.scope.compiledAssignments()) + ";\n" + (code)); } if (!o.globals && o.scope.hasDeclarations(this)) { - code = ("" + (this.tab) + "var " + (o.scope.compiledDeclarations()) + ";\n" + code); + code = ("" + (this.tab) + "var " + (o.scope.compiledDeclarations()) + ";\n" + (code)); } return code; }; @@ -247,7 +247,7 @@ compiledNode = node.compile(merge(o, { top: true })); - return node.isStatement() ? compiledNode : ("" + (this.idt()) + compiledNode + ";"); + return node.isStatement() ? compiledNode : ("" + (this.idt()) + (compiledNode) + ";"); }; return Expressions; })(); @@ -275,10 +275,10 @@ var end, idt; idt = this.isStatement() ? this.idt() : ''; end = this.isStatement() ? ';' : ''; - return "" + idt + this.value + end; + return idt + this.value + end; }; LiteralNode.prototype.toString = function(idt) { - return " \"" + this.value + "\""; + return '"' + this.value + '"'; }; return LiteralNode; })(); @@ -398,7 +398,7 @@ o.chainRoot = o.chainRoot || this; baseline = this.base.compile(o); if (this.hasProperties() && (this.base instanceof ObjectNode || this.isNumber())) { - baseline = ("(" + baseline + ")"); + baseline = ("(" + (baseline) + ")"); } complete = (this.last = baseline); _c = props; @@ -413,10 +413,10 @@ return n instanceof CallNode; }) && i === 0) { temp = o.scope.freeVariable(); - complete = ("(" + (baseline = temp) + " = (" + complete + "))"); + complete = ("(" + (baseline = temp) + " = (" + (complete) + "))"); } if (i === 0 && this.isStart(o)) { - complete = ("typeof " + complete + " === \"undefined\" || " + baseline); + complete = ("typeof " + (complete) + " === \"undefined\" || " + (baseline)); } return complete += this.SOAK + (baseline += prop.compile(o)); } else { @@ -427,7 +427,7 @@ } }).call(this); } - return op && this.wrapped ? ("(" + complete + ")") : complete; + return op && this.wrapped ? ("(" + (complete) + ")") : complete; }; return ValueNode; })(); @@ -446,8 +446,8 @@ }; CommentNode.prototype.compileNode = function(o) { var sep; - sep = ("\n" + this.tab); - return "" + this.tab + "/*" + sep + (this.lines.join(sep)) + "\n" + this.tab + "*/"; + sep = '\n' + this.tab; + return "" + (this.tab) + "/*#" + (sep + this.lines.join(sep)) + "\n" + (this.tab) + "*/"; }; return CommentNode; })(); @@ -478,7 +478,7 @@ methname = o.scope.method.name; return (meth = (function() { if (o.scope.method.proto) { - return "" + (o.scope.method.proto) + ".__superClass__." + methname; + return "" + (o.scope.method.proto) + ".__superClass__." + (methname); } else if (methname) { return "" + (methname) + ".__superClass__.constructor"; } else { @@ -505,12 +505,12 @@ } return _e; }).call(this).join(', '); - compilation = this.isSuper ? this.compileSuper(args, o) : ("" + (this.prefix()) + (this.variable.compile(o)) + "(" + args + ")"); + compilation = this.isSuper ? this.compileSuper(args, o) : ("" + (this.prefix()) + (this.variable.compile(o)) + "(" + (args) + ")"); } - return o.operation && this.wrapped ? ("(" + compilation + ")") : compilation; + return o.operation && this.wrapped ? ("(" + (compilation) + ")") : compilation; }; CallNode.prototype.compileSuper = function(args, o) { - return "" + (this.superReference(o)) + ".call(this" + (args.length ? ', ' : '') + args + ")"; + return "" + (this.superReference(o)) + ".call(this" + (args.length ? ', ' : '') + (args) + ")"; }; CallNode.prototype.compileSplat = function(o) { var meth, obj, temp; @@ -519,13 +519,13 @@ if (obj.match(/\(/)) { temp = o.scope.freeVariable(); obj = temp; - meth = ("(" + temp + " = " + (this.variable.source) + ")" + (this.variable.last)); + meth = ("(" + (temp) + " = " + (this.variable.source) + ")" + (this.variable.last)); } if (this.isNew) { utility('extends'); - return "(function() {\n" + (this.idt(1)) + "var ctor = function(){};\n" + (this.idt(1)) + "__extends(ctor, " + meth + ");\n" + (this.idt(1)) + "return " + (meth) + ".apply(new ctor, " + (this.compileSplatArguments(o)) + ");\n" + this.tab + "}).call(this)"; + return "(function() {\n" + (this.idt(1)) + "var ctor = function(){};\n" + (this.idt(1)) + "__extends(ctor, " + (meth) + ");\n" + (this.idt(1)) + "return " + (meth) + ".apply(new ctor, " + (this.compileSplatArguments(o)) + ");\n" + (this.tab) + "}).call(this)"; } else { - return "" + (this.prefix()) + (meth) + ".apply(" + obj + ", " + (this.compileSplatArguments(o)) + ")"; + return "" + (this.prefix()) + (meth) + ".apply(" + (obj) + ", " + (this.compileSplatArguments(o)) + ")"; } }; return CallNode; @@ -560,7 +560,7 @@ var name, namePart; name = this.name.compile(o); o.chainRoot.wrapped = o.chainRoot.wrapped || this.soakNode; - namePart = name.match(IS_STRING) ? ("[" + name + "]") : ("." + name); + namePart = name.match(IS_STRING) ? ("[" + (name) + "]") : ("." + (name)); return this.prototype + namePart; }; return AccessorNode; @@ -578,7 +578,7 @@ o.chainRoot.wrapped = o.chainRoot.wrapped || this.soakNode; idx = this.index.compile(o); prefix = this.proto ? '.prototype' : ''; - return "" + prefix + "[" + idx + "]"; + return "" + (prefix) + "[" + (idx) + "]"; }; return IndexNode; })(); @@ -630,12 +630,12 @@ } idx = del(o, 'index'); step = del(o, 'step'); - vars = ("" + idx + " = " + this.fromVar); - intro = ("(" + this.fromVar + " <= " + this.toVar + " ? " + idx); - compare = ("" + intro + " <" + this.equals + " " + this.toVar + " : " + idx + " >" + this.equals + " " + this.toVar + ")"); + vars = ("" + (idx) + " = " + (this.fromVar)); + intro = ("(" + (this.fromVar) + " <= " + (this.toVar) + " ? " + (idx)); + compare = ("" + (intro) + " <" + (this.equals) + " " + (this.toVar) + " : " + (idx) + " >" + (this.equals) + " " + (this.toVar) + ")"); stepPart = step ? step.compile(o) : '1'; - incr = step ? ("" + idx + " += " + stepPart) : ("" + intro + " += " + stepPart + " : " + idx + " -= " + stepPart + ")"); - return "" + vars + "; " + compare + "; " + incr; + incr = step ? ("" + (idx) + " += " + (stepPart)) : ("" + (intro) + " += " + (stepPart) + " : " + (idx) + " -= " + (stepPart) + ")"); + return "" + (vars) + "; " + (compare) + "; " + (incr); }; RangeNode.prototype.compileSimple = function(o) { var _b, from, idx, step, to; @@ -644,8 +644,8 @@ to = _b[1]; idx = del(o, 'index'); step = del(o, 'step'); - step = step && ("" + idx + " += " + (step.compile(o))); - return from <= to ? ("" + idx + " = " + from + "; " + idx + " <" + this.equals + " " + to + "; " + (step || ("" + idx + "++"))) : ("" + idx + " = " + from + "; " + idx + " >" + this.equals + " " + to + "; " + (step || ("" + idx + "--"))); + step = step && ("" + (idx) + " += " + (step.compile(o))); + return from <= to ? ("" + (idx) + " = " + (from) + "; " + (idx) + " <" + (this.equals) + " " + (to) + "; " + (step || ("" + (idx) + "++"))) : ("" + (idx) + " = " + (from) + "; " + (idx) + " >" + (this.equals) + " " + (to) + "; " + (step || ("" + (idx) + "--"))); }; RangeNode.prototype.compileArray = function(o) { var _b, _c, body, clause, i, idt, post, pre, range, result, vars; @@ -671,11 +671,11 @@ o.index = i; body = this.compileSimple(o); } else { - clause = ("" + this.fromVar + " <= " + this.toVar + " ?"); - body = ("var " + i + " = " + this.fromVar + "; " + clause + " " + i + " <" + this.equals + " " + this.toVar + " : " + i + " >" + this.equals + " " + this.toVar + "; " + clause + " " + i + " += 1 : " + i + " -= 1"); + clause = ("" + (this.fromVar) + " <= " + (this.toVar) + " ?"); + body = ("var " + (i) + " = " + (this.fromVar) + "; " + (clause) + " " + (i) + " <" + (this.equals) + " " + (this.toVar) + " : " + (i) + " >" + (this.equals) + " " + (this.toVar) + "; " + (clause) + " " + (i) + " += 1 : " + (i) + " -= 1"); } - post = ("{ " + (result) + ".push(" + i + "); }\n" + (idt) + "return " + result + ";\n" + o.indent); - return "(function() {" + (pre) + "\n" + (idt) + "for (" + body + ")" + post + "}).call(this)"; + post = ("{ " + (result) + ".push(" + (i) + "); }\n" + (idt) + "return " + (result) + ";\n" + (o.indent)); + return "(function() {" + (pre) + "\n" + (idt) + "for (" + (body) + ")" + (post) + "}).call(this)"; }; return RangeNode; })(); @@ -692,7 +692,7 @@ from = this.range.from.compile(o); to = this.range.to.compile(o); plusPart = this.range.exclusive ? '' : ' + 1'; - return ".slice(" + from + ", " + to + plusPart + ")"; + return ".slice(" + (from) + ", " + (to) + (plusPart) + ")"; }; return SliceNode; })(); @@ -739,7 +739,7 @@ }).call(this); props = props.join(''); inner = props ? '\n' + props + '\n' + this.idt() : ''; - return "{" + inner + "}"; + return '{' + inner + '}'; }; return ObjectNode; })(); @@ -766,15 +766,15 @@ if (obj instanceof SplatNode) { return this.compileSplatLiteral(o); } else if (obj instanceof CommentNode) { - objects.push("\n" + code + "\n" + o.indent); + objects.push(("\n" + (code) + "\n" + (o.indent))); } else if (i === this.objects.length - 1) { objects.push(code); } else { - objects.push("" + code + ", "); + objects.push(("" + (code) + ", ")); } } objects = objects.join(''); - return indexOf(objects, '\n') >= 0 ? ("[\n" + (this.idt(1)) + objects + "\n" + this.tab + "]") : ("[" + objects + "]"); + return indexOf(objects, '\n') >= 0 ? ("[\n" + (this.idt(1)) + (objects) + "\n" + (this.tab) + "]") : ("[" + (objects) + "]"); }; return ArrayNode; })(); @@ -839,7 +839,7 @@ if (constructor.body.empty()) { constructor.body.push(new ReturnNode(literal('this'))); } - constructor.body.unshift(literal(("this." + (pname) + " = function(){ return " + (className) + ".prototype." + (pname) + ".apply(" + me + ", arguments); }"))); + constructor.body.unshift(literal(("this." + (pname) + " = function(){ return " + (className) + ".prototype." + (pname) + ".apply(" + (me) + ", arguments); }"))); } if (pvar) { access = prop.context === 'this' ? pvar.base.properties[0] : new AccessorNode(pvar, 'prototype'); @@ -849,7 +849,7 @@ props.push(prop); } if (me) { - constructor.body.unshift(literal("" + me + " = this")); + constructor.body.unshift(literal(("" + (me) + " = this"))); } construct = this.idt() + (new AssignNode(this.variable, constructor)).compile(merge(o, { sharedScope: constScope @@ -857,7 +857,7 @@ props = !props.empty() ? '\n' + props.compile(o) : ''; extension = extension ? '\n' + this.idt() + extension.compile(o) + ';' : ''; returns = this.returns ? '\n' + new ReturnNode(this.variable).compile(o) : ''; - return "" + construct + extension + props + returns; + return construct + extension + props + returns; }; return ClassNode; })(); @@ -913,22 +913,22 @@ } val = this.value.compile(o); if (this.context === 'object') { - return ("" + name + ": " + val); + return ("" + (name) + ": " + (val)); } if (!(this.isValue() && (this.variable.hasProperties() || this.variable.namespaced))) { o.scope.find(name); } - val = ("" + name + " = " + val); + val = ("" + (name) + " = " + (val)); if (stmt) { - return ("" + this.tab + val + ";"); + return ("" + (this.tab) + (val) + ";"); } - return top ? val : ("(" + val + ")"); + return top ? val : ("(" + (val) + ")"); }; AssignNode.prototype.compilePatternMatch = function(o) { var _b, _c, _d, accessClass, assigns, code, i, idx, isString, obj, oindex, olength, splat, val, valVar, value; valVar = o.scope.freeVariable(); value = this.value.isStatement() ? ClosureNode.wrap(this.value) : this.value; - assigns = [("" + this.tab + valVar + " = " + (value.compile(o)) + ";")]; + assigns = [("" + (this.tab) + (valVar) + " = " + (value.compile(o)) + ";")]; o.top = true; o.asStatement = true; splat = false; @@ -975,7 +975,7 @@ from = range.from.compile(o); to = range.to.compile(o) + ' - ' + from + plus; val = this.value.compile(o); - return "" + (name) + ".splice.apply(" + name + ", [" + from + ", " + to + "].concat(" + val + "))"; + return "" + (name) + ".splice.apply(" + (name) + ", [" + (from) + ", " + (to) + "].concat(" + (val) + "))"; }; return AssignNode; })(); @@ -1049,11 +1049,11 @@ (o.scope.parameter(param)); } code = this.body.expressions.length ? ("\n" + (this.body.compileWithDeclarations(o)) + "\n") : ''; - func = ("function(" + (params.join(', ')) + ") {" + code + (code && this.tab) + "}"); + func = ("function(" + (params.join(', ')) + ") {" + (code) + (code && this.tab) + "}"); if (this.bound) { - return ("" + (utility('bind')) + "(" + func + ", this)"); + return ("" + (utility('bind')) + "(" + (func) + ", this)"); } - return top ? ("(" + func + ")") : func; + return top ? ("(" + (func) + ")") : func; }; CodeNode.prototype.topSensitive = function() { return true; @@ -1074,7 +1074,7 @@ } return _b; }).call(this).join(''); - return "\n" + idt + children; + return '\n' + idt + children; }; return CodeNode; })(); @@ -1093,7 +1093,7 @@ return this.value.compile(o); }; ParamNode.prototype.toString = function(idt) { - return this.attach ? (literal("@" + this.name)).toString(idt) : this.value.toString(idt); + return this.attach ? (literal('@' + this.name)).toString(idt) : this.value.toString(idt); }; return ParamNode; })(); @@ -1121,8 +1121,8 @@ len = o.scope.freeVariable(); o.scope.assign(len, "arguments.length"); variadic = o.scope.freeVariable(); - o.scope.assign(variadic, ("" + len + " >= " + this.arglength)); - end = this.trailings.length ? (", " + len + " - " + (this.trailings.length)) : null; + o.scope.assign(variadic, len + ' >= ' + this.arglength); + end = this.trailings.length ? (", " + (len) + " - " + (this.trailings.length)) : null; _b = this.trailings; for (idx = 0, _c = _b.length; idx < _c; idx++) { trailing = _b[idx]; @@ -1132,15 +1132,15 @@ assign.value = trailing; } pos = this.trailings.length - idx; - o.scope.assign(trailing.compile(o), ("arguments[" + variadic + " ? " + len + " - " + pos + " : " + (this.index + idx) + "]")); + o.scope.assign(trailing.compile(o), ("arguments[" + (variadic) + " ? " + (len) + " - " + (pos) + " : " + (this.index + idx) + "]")); } } - return "" + name + " = " + (utility('slice')) + ".call(arguments, " + this.index + end + ")"; + return "" + (name) + " = " + (utility('slice')) + ".call(arguments, " + (this.index) + (end) + ")"; }; SplatNode.prototype.compileValue = function(o, name, index, trailings) { var trail; - trail = trailings ? (", " + (name) + ".length - " + trailings) : ''; - return "" + (utility('slice')) + ".call(" + name + ", " + index + trail + ")"; + trail = trailings ? (", " + (name) + ".length - " + (trailings)) : ''; + return "" + (utility('slice')) + ".call(" + (name) + ", " + (index) + (trail) + ")"; }; SplatNode.compileSplattedArray = function(list, o) { var _b, _c, arg, args, code, i, last, prev; @@ -1152,16 +1152,16 @@ prev = args[(last = args.length - 1)]; if (!(arg instanceof SplatNode)) { if (prev && starts(prev, '[') && ends(prev, ']')) { - args[last] = ("" + (prev.substr(0, prev.length - 1)) + ", " + code + "]"); + args[last] = ("" + (prev.substr(0, prev.length - 1)) + ", " + (code) + "]"); continue; } else if (prev && starts(prev, '.concat([') && ends(prev, '])')) { - args[last] = ("" + (prev.substr(0, prev.length - 2)) + ", " + code + "])"); + args[last] = ("" + (prev.substr(0, prev.length - 2)) + ", " + (code) + "])"); continue; } else { - code = ("[" + code + "]"); + code = ("[" + (code) + "]"); } } - args.push(i === 0 ? code : (".concat(" + code + ")")); + args.push(i === 0 ? code : (".concat(" + (code) + ")")); } return args.join(''); }; @@ -1205,19 +1205,19 @@ set = ''; if (!(top)) { rvar = o.scope.freeVariable(); - set = ("" + this.tab + rvar + " = [];\n"); + set = ("" + (this.tab) + (rvar) + " = [];\n"); if (this.body) { this.body = PushNode.wrap(rvar, this.body); } } - pre = ("" + set + (this.tab) + "while (" + cond + ")"); + pre = ("" + (set) + (this.tab) + "while (" + (cond) + ")"); if (this.guard) { this.body = Expressions.wrap([new IfNode(this.guard, this.body)]); } this.returns ? (post = '\n' + new ReturnNode(literal(rvar)).compile(merge(o, { indent: this.idt() }))) : (post = ''); - return "" + pre + " {\n" + (this.body.compile(o)) + "\n" + this.tab + "}" + post; + return "" + (pre) + " {\n" + (this.body.compile(o)) + "\n" + (this.tab) + "}" + (post); }; return WhileNode; })(); @@ -1278,7 +1278,7 @@ first = _c[0]; second = _c[1]; shared = _c[2]; - return "(" + first + ") && (" + shared + " " + this.operator + " " + second + ")"; + return "(" + (first) + ") && (" + (shared) + " " + (this.operator) + " " + (second) + ")"; }; OpNode.prototype.compileAssignment = function(o) { var _b, first, firstVar, second; @@ -1293,9 +1293,9 @@ o.scope.find(first); } if (this.operator === '?=') { - return ("" + first + " = " + (ExistenceNode.compileTest(o, literal(firstVar))) + " ? " + firstVar + " : " + second); + return ("" + (first) + " = " + (ExistenceNode.compileTest(o, literal(firstVar))) + " ? " + (firstVar) + " : " + (second)); } - return "" + first + " = " + firstVar + " " + (this.operator.substr(0, 2)) + " " + second; + return "" + (first) + " = " + (firstVar) + " " + (this.operator.substr(0, 2)) + " " + (second); }; OpNode.prototype.compileExistence = function(o) { var _b, first, second, test; @@ -1303,7 +1303,7 @@ first = _b[0]; second = _b[1]; test = ExistenceNode.compileTest(o, this.first); - return "" + test + " ? " + first + " : " + second; + return "" + (test) + " ? " + (first) + " : " + (second); }; OpNode.prototype.compileUnary = function(o) { var parts, space; @@ -1360,7 +1360,7 @@ i = _c[0]; l = _c[1]; prefix = this.obj1 !== this.obj2 ? this.obj1 + '; ' : ''; - return "(function(){ " + (prefix) + "for (var " + i + "=0, " + l + "=" + (this.arr1) + ".length; " + i + "<" + l + "; " + i + "++) { if (" + (this.arr2) + "[" + i + "] === " + this.obj2 + ") return true; } return false; }).call(this)"; + return "(function(){ " + (prefix) + "for (var " + (i) + "=0, " + (l) + "=" + (this.arr1) + ".length; " + (i) + "<" + (l) + "; " + (i) + "++) { if (" + (this.arr2) + "[" + (i) + "] === " + (this.obj2) + ") return true; } return false; }).call(this)"; }; return InNode; })(); @@ -1393,9 +1393,9 @@ o.top = true; attemptPart = this.attempt.compile(o); errorPart = this.error ? (" (" + (this.error.compile(o)) + ") ") : ' '; - catchPart = this.recovery ? (" catch" + errorPart + "{\n" + (this.recovery.compile(o)) + "\n" + this.tab + "}") : ''; - finallyPart = (this.ensure || '') && ' finally {\n' + this.ensure.compile(merge(o)) + ("\n" + this.tab + "}"); - return "" + (this.tab) + "try {\n" + attemptPart + "\n" + this.tab + "}" + catchPart + finallyPart; + catchPart = this.recovery ? (" catch" + (errorPart) + "{\n" + (this.recovery.compile(o)) + "\n" + (this.tab) + "}") : ''; + finallyPart = (this.ensure || '') && ' finally {\n' + this.ensure.compile(merge(o)) + ("\n" + (this.tab) + "}"); + return "" + (this.tab) + "try {\n" + (attemptPart) + "\n" + (this.tab) + "}" + (catchPart) + (finallyPart); }; return TryNode; })(); @@ -1460,13 +1460,13 @@ top = del(o, 'top'); code = this.expression.compile(o); if (this.isStatement()) { - return (top ? ("" + this.tab + code + ";") : code); + return (top ? this.tab + code + ';' : code); } l = code.length; if (code.substr(l - 1, 1) === ';') { code = code.substr(o, l - 1); } - return this.expression instanceof AssignNode ? code : ("(" + code + ")"); + return this.expression instanceof AssignNode ? code : ("(" + (code) + ")"); }; return ParentheticalNode; })(); @@ -1556,25 +1556,25 @@ })); } else { svar = scope.freeVariable(); - sourcePart = ("" + svar + " = " + (this.source.compile(o)) + ";"); + sourcePart = ("" + (svar) + " = " + (this.source.compile(o)) + ";"); if (this.pattern) { - namePart = new AssignNode(this.name, literal("" + svar + "[" + ivar + "]")).compile(merge(o, { + namePart = new AssignNode(this.name, literal(("" + (svar) + "[" + (ivar) + "]"))).compile(merge(o, { indent: this.idt(1), top: true })) + '\n'; } else { if (name) { - namePart = ("" + name + " = " + svar + "[" + ivar + "]"); + namePart = ("" + (name) + " = " + (svar) + "[" + (ivar) + "]"); } } if (!(this.object)) { lvar = scope.freeVariable(); - stepPart = this.step ? ("" + ivar + " += " + (this.step.compile(o))) : ("" + ivar + "++"); - forPart = ("" + ivar + " = 0, " + lvar + " = " + (svar) + ".length; " + ivar + " < " + lvar + "; " + stepPart); + stepPart = this.step ? ("" + (ivar) + " += " + (this.step.compile(o))) : ("" + (ivar) + "++"); + forPart = ("" + (ivar) + " = 0, " + (lvar) + " = " + (svar) + ".length; " + (ivar) + " < " + (lvar) + "; " + (stepPart)); } } - sourcePart = (rvar ? ("" + rvar + " = []; ") : '') + sourcePart; - sourcePart = sourcePart ? ("" + this.tab + sourcePart + "\n" + this.tab) : this.tab; + sourcePart = (rvar ? ("" + (rvar) + " = []; ") : '') + sourcePart; + sourcePart = sourcePart ? ("" + (this.tab) + (sourcePart) + "\n" + (this.tab)) : this.tab; returnResult = this.compileReturnValue(rvar, o); if (!(topLevel)) { body = PushNode.wrap(rvar, body); @@ -1582,27 +1582,27 @@ this.guard ? (body = Expressions.wrap([new IfNode(this.guard, body)])) : null; if (codeInBody) { if (namePart) { - body.unshift(literal("var " + namePart)); + body.unshift(literal(("var " + (namePart)))); } if (index) { - body.unshift(literal("var " + index + " = " + ivar)); + body.unshift(literal(("var " + (index) + " = " + (ivar)))); } body = ClosureNode.wrap(body, true); } else { - varPart = (namePart || '') && (this.pattern ? namePart : ("" + (this.idt(1)) + namePart + ";\n")); + varPart = (namePart || '') && (this.pattern ? namePart : ("" + (this.idt(1)) + (namePart) + ";\n")); } if (this.object) { - forPart = ("" + ivar + " in " + svar); + forPart = ("" + (ivar) + " in " + (svar)); if (!(this.raw)) { - guardPart = ("\n" + (this.idt(1)) + "if (!" + (utility('hasProp')) + ".call(" + svar + ", " + ivar + ")) continue;"); + guardPart = ("\n" + (this.idt(1)) + "if (!" + (utility('hasProp')) + ".call(" + (svar) + ", " + (ivar) + ")) continue;"); } } body = body.compile(merge(o, { indent: this.idt(1), top: true })); - vars = range ? name : ("" + name + ", " + ivar); - return "" + (sourcePart) + "for (" + forPart + ") {" + guardPart + "\n" + varPart + body + "\n" + this.tab + "}" + returnResult; + vars = range ? name : ("" + (name) + ", " + (ivar)); + return "" + (sourcePart) + "for (" + (forPart) + ") {" + (guardPart) + "\n" + (varPart) + (body) + "\n" + (this.tab) + "}" + (returnResult); }; return ForNode; })(); @@ -1713,22 +1713,22 @@ ifDent = child ? '' : this.idt(); comDent = child ? this.idt() : ''; body = this.body.compile(o); - ifPart = ("" + (ifDent) + "if (" + (this.compileCondition(condO)) + ") {\n" + body + "\n" + this.tab + "}"); + ifPart = ("" + (ifDent) + "if (" + (this.compileCondition(condO)) + ") {\n" + (body) + "\n" + (this.tab) + "}"); if (!(this.elseBody)) { return ifPart; } elsePart = this.isChain ? ' else ' + this.elseBodyNode().compile(merge(o, { indent: this.idt(), chainChild: true - })) : (" else {\n" + (this.elseBody.compile(o)) + "\n" + this.tab + "}"); - return "" + ifPart + elsePart; + })) : (" else {\n" + (this.elseBody.compile(o)) + "\n" + (this.tab) + "}"); + return "" + (ifPart) + (elsePart); }; IfNode.prototype.compileTernary = function(o) { var elsePart, ifPart; o.operation = true; ifPart = this.condition.compile(o) + ' ? ' + this.bodyNode().compile(o); elsePart = this.elseBody ? this.elseBodyNode().compile(o) : 'null'; - return "" + ifPart + " : " + elsePart; + return "" + (ifPart) + " : " + (elsePart); }; return IfNode; })(); @@ -1786,7 +1786,7 @@ }; utility = function(name) { var ref; - ref = ("__" + name); + ref = ("__" + (name)); Scope.root.assign(ref, UTILITIES[name]); return ref; }; diff --git a/lib/optparse.js b/lib/optparse.js index 839439f0..a3b7efd2 100755 --- a/lib/optparse.js +++ b/lib/optparse.js @@ -27,7 +27,7 @@ } } if (isOption && !matchedRule) { - throw new Error("unrecognized option: " + arg); + throw new Error(("unrecognized option: " + (arg))); } if (!isOption) { options.arguments = args.slice(i, args.length); @@ -40,7 +40,7 @@ var _a, _b, _c, _d, i, letPart, lines, rule, spaces; lines = ['Available options:']; if (this.banner) { - lines.unshift("" + this.banner + "\n"); + lines.unshift(("" + (this.banner) + "\n")); } _b = this.rules; for (_a = 0, _c = _b.length; _a < _c; _a++) { @@ -54,7 +54,7 @@ return _d; })().join('') : ''; letPart = rule.shortFlag ? rule.shortFlag + ', ' : ' '; - lines.push(" " + letPart + rule.longFlag + spaces + rule.description); + lines.push(' ' + letPart + rule.longFlag + spaces + rule.description); } return "\n" + (lines.join('\n')) + "\n"; }; diff --git a/lib/rewriter.js b/lib/rewriter.js index 4d921fd8..025ded1b 100644 --- a/lib/rewriter.js +++ b/lib/rewriter.js @@ -313,7 +313,7 @@ if (unclosed.length) { open = unclosed[0]; line = openLine[open] + 1; - throw new Error("unclosed " + open + " on line " + line); + throw new Error(("unclosed " + (open) + " on line " + (line))); } }; Rewriter.prototype.rewriteClosingParens = function() { diff --git a/lib/scope.js b/lib/scope.js index 44db0477..7c66cd6a 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -92,7 +92,7 @@ for (key in _b) { if (!__hasProp.call(_b, key)) continue; val = _b[key]; - val.assigned ? _a.push("" + key + " = " + val.value) : null; + val.assigned ? _a.push(("" + (key) + " = " + (val.value))) : null; } return _a; }; diff --git a/src/cake.coffee b/src/cake.coffee index a36512d7..24bc248d 100644 --- a/src/cake.coffee +++ b/src/cake.coffee @@ -59,11 +59,11 @@ printTasks = -> for all name, task of tasks spaces = 20 - name.length spaces = if spaces > 0 then (' ' for i in [0..spaces]).join('') else '' - desc = if task.description then "# #task.description" else '' - puts "cake #name#spaces #desc" + desc = if task.description then "# #{task.description}" else '' + puts "cake #{name}#{spaces} #{desc}" puts oparse.help() if switches.length # Print an error and exit when attempting to all an undefined task. missingTask = (task) -> - puts "No such task: \"#task\"" + puts "No such task: \"#{task}\"" process.exit 1 diff --git a/src/coffee-script.coffee b/src/coffee-script.coffee index 5a3d83de..c0d15c77 100644 --- a/src/coffee-script.coffee +++ b/src/coffee-script.coffee @@ -34,7 +34,7 @@ exports.compile = compile = (code, options) -> try (parser.parse lexer.tokenize code).compile options catch err - err.message = "In #options.fileName, #err.message" if options.fileName + err.message = "In #{options.fileName}, #{err.message}" if options.fileName throw err # Tokenize a string of CoffeeScript code, and return the array of tokens. diff --git a/src/command.coffee b/src/command.coffee index ade16b29..fd7d2716 100644 --- a/src/command.coffee +++ b/src/command.coffee @@ -71,7 +71,7 @@ compileScripts = -> base = source compile = (source, topLevel) -> path.exists source, (exists) -> - throw new Error "File not found: #source" unless exists + throw new Error "File not found: #{source}" unless exists fs.stat source, (err, stats) -> if stats.isDirectory() fs.readdir source, (err, files) -> @@ -131,9 +131,9 @@ writeJs = (source, js, base) -> compile = -> js = ' ' if js.length <= 0 fs.writeFile jsPath, js, (err) -> - puts "Compiled #source" if options.compile and options.watch + puts "Compiled #{source}" if options.compile and options.watch path.exists dir, (exists) -> - if exists then compile() else exec "mkdir -p #dir", compile + if exists then compile() else exec "mkdir -p #{dir}", compile # Pipe compiled JS through JSLint (requires a working `jsl` command), printing # any errors or warnings that arise. @@ -149,7 +149,7 @@ lint = (js) -> printTokens = (tokens) -> strings = for token in tokens [tag, value] = [token[0], token[1].toString().replace(/\n/, '\\n')] - "[#tag #value]" + "[#{tag} #{value}]" puts strings.join(' ') # Use the [OptionParser module](optparse.html) to extract all options from @@ -175,5 +175,5 @@ usage = -> # Print the `--version` message and exit. version = -> - puts "CoffeeScript version #CoffeeScript.VERSION" + puts "CoffeeScript version #{CoffeeScript.VERSION}" process.exit 0 diff --git a/src/grammar.coffee b/src/grammar.coffee index 97edb7d8..31dddf4f 100644 --- a/src/grammar.coffee +++ b/src/grammar.coffee @@ -32,8 +32,8 @@ unwrap = /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/ # previous nonterminal. o = (patternString, action, options) -> return [patternString, '$$ = $1;', options] unless action - action = if match = (action + '').match(unwrap) then match[1] else "(#action())" - [patternString, "$$ = #action;", options] + action = if match = (action + '').match(unwrap) then match[1] else "(#{action}())" + [patternString, "$$ = #{action};", options] # Grammatical Rules # ----------------- diff --git a/src/lexer.coffee b/src/lexer.coffee index 57c83b10..6852b6c3 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -91,7 +91,7 @@ exports.Lexer = class Lexer if include(JS_FORBIDDEN, id) if forcedIdentifier tag = 'STRING' - id = "\"#id\"" + id = "\"#{id}\"" if forcedIdentifier is 'accessor' close_index = true @tokens.pop() if @tag() isnt '@' @@ -131,7 +131,7 @@ exports.Lexer = class Lexer return false unless match = @chunk.match(HEREDOC) quote = match[1].substr 0, 1 doc = @sanitizeHeredoc match[2] or match[4], {quote} - @interpolateString "#quote#doc#quote", heredoc: yes + @interpolateString quote + doc + quote, heredoc: yes @line += count match[1], "\n" @i += match[1].length true @@ -169,8 +169,8 @@ exports.Lexer = class Lexer str = regex.substring(1).split('/')[0] str = str.replace REGEX_ESCAPE, (escaped) -> '\\' + escaped @tokens = @tokens.concat [['(', '('], ['NEW', 'new'], ['IDENTIFIER', 'RegExp'], ['CALL_START', '(']] - @interpolateString "\"#str\"", escapeQuotes: yes - @tokens.splice @tokens.length, 0, [',', ','], ['STRING', "\"#flags\""] if flags + @interpolateString "\"#{str}\"", escapeQuotes: yes + @tokens.splice @tokens.length, 0, [',', ','], ['STRING', "\"#{flags}\""] if flags @tokens.splice @tokens.length, 0, [')', ')'], [')', ')'] else @token 'REGEX', regex @@ -318,7 +318,7 @@ exports.Lexer = class Lexer doc = doc.replace(new RegExp("^" +indent, 'gm'), '') return doc if options.herecomment doc.replace(MULTILINER, "\\n") - .replace(new RegExp(options.quote, 'g'), "\\#options.quote") + .replace(new RegExp(options.quote, 'g'), "\\#{options.quote}") # A source of ambiguity in our grammar used to be parameter lists in function # definitions versus argument lists in function calls. Walk backwards, tagging @@ -343,7 +343,7 @@ exports.Lexer = class Lexer # The error for when you try to use a forbidden word in JavaScript as # an identifier. identifierError: (word) -> - throw new Error "SyntaxError: Reserved word \"#word\" on line #{@line + 1}" + throw new Error "SyntaxError: Reserved word \"#{word}\" on line #{@line + 1}" # The error for when you try to assign to a reserved word in JavaScript, # like "function" or "default". @@ -385,7 +385,6 @@ exports.Lexer = class Lexer # [ECMA Harmony's interpolation syntax](http://wiki.ecmascript.org/doku.php?id=strawman:string_interpolation) # for substitution of bare variables as well as arbitrary expressions. # - # "Hello #name." # "Hello #{name.capitalize()}." # # If it encounters an interpolation, this method will recursively create a @@ -406,25 +405,25 @@ exports.Lexer = class Lexer else if match = str.substring(i).match INTERPOLATION [group, interp] = match interp = "this.#{ interp.substring(1) }" if starts interp, '@' - tokens.push ['STRING', "#quote#{ str.substring(pi, i) }#quote"] if pi < i + tokens.push ['STRING', quote + str.substring(pi, i) + quote] if pi < i tokens.push ['IDENTIFIER', interp] i += group.length - 1 pi = i + 1 else if (expr = @balancedString str.substring(i), [['#{', '}']]) - tokens.push ['STRING', "#quote#{ str.substring(pi, i) }#quote"] if pi < i + tokens.push ['STRING', quote + str.substring(pi, i) + quote] if pi < i inner = expr.substring(2, expr.length - 1) if inner.length inner = inner.replace new RegExp('\\\\' + quote, 'g'), quote if options.heredoc - nested = lexer.tokenize "(#inner)", line: @line + nested = lexer.tokenize "(#{inner})", line: @line (tok[0] = ')') for tok, idx in nested when tok[0] is 'CALL_END' nested.pop() tokens.push ['TOKENS', nested] else - tokens.push ['STRING', "#quote#quote"] + tokens.push ['STRING', quote + quote] i += expr.length - 1 pi = i + 1 i += 1 - tokens.push ['STRING', "#quote#{ str.substring(pi, i) }#quote"] if pi < i and pi < str.length - 1 + tokens.push ['STRING', quote + str.substring(pi, i) + quote] if pi < i and pi < str.length - 1 tokens.unshift ['STRING', '""'] unless tokens[0][0] is 'STRING' interpolated = tokens.length > 1 @token '(', '(' if interpolated @@ -434,7 +433,7 @@ exports.Lexer = class Lexer @tokens = @tokens.concat value else if tag is 'STRING' and options.escapeQuotes escaped = value.substring(1, value.length - 1).replace(/"/g, '\\"') - @token tag, "\"#escaped\"" + @token tag, "\"#{escaped}\"" else @token tag, value @token '+', '+' if i < tokens.length - 1 diff --git a/src/nodes.coffee b/src/nodes.coffee index a3ae6919..d6e94512 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -206,14 +206,14 @@ exports.Expressions = class Expressions extends BaseNode code = @compileWithDeclarations(o) code = code.replace(TRAILING_WHITESPACE, '') code = code.replace(DOUBLE_PARENS, '($1)') - if o.noWrap then code else "(function() {\n#code\n})();\n" + if o.noWrap then code else "(function() {\n#{code}\n})();\n" # Compile the expressions body for the contents of a function, with # declarations of all inner variables pushed up to the top. compileWithDeclarations: (o) -> code = @compileNode(o) - code = "#{@tab}var #{o.scope.compiledAssignments()};\n#code" if o.scope.hasAssignments(this) - code = "#{@tab}var #{o.scope.compiledDeclarations()};\n#code" if not o.globals and o.scope.hasDeclarations(this) + code = "#{@tab}var #{o.scope.compiledAssignments()};\n#{code}" if o.scope.hasAssignments(this) + code = "#{@tab}var #{o.scope.compiledDeclarations()};\n#{code}" if not o.globals and o.scope.hasDeclarations(this) code # Compiles a single expression within the expressions body. If we need to @@ -222,7 +222,7 @@ exports.Expressions = class Expressions extends BaseNode compileExpression: (node, o) -> @tab = o.indent compiledNode = node.compile merge o, top: true - if node.isStatement() then compiledNode else "#{@idt()}#compiledNode;" + if node.isStatement() then compiledNode else "#{@idt()}#{compiledNode};" # Wrap up the given nodes as an **Expressions**, unless it already happens # to be one. @@ -253,10 +253,10 @@ exports.LiteralNode = class LiteralNode extends BaseNode compileNode: (o) -> idt = if @isStatement() then @idt() else '' end = if @isStatement() then ';' else '' - "#idt#@value#end" + idt + @value + end toString: (idt) -> - " \"#@value\"" + '"' + @value + '"' #### ReturnNode @@ -365,7 +365,7 @@ exports.ValueNode = class ValueNode extends BaseNode props = if only then @properties[0...@properties.length - 1] else @properties o.chainRoot or= this baseline = @base.compile o - baseline = "(#baseline)" if @hasProperties() and (@base instanceof ObjectNode or @isNumber()) + baseline = "(#{baseline})" if @hasProperties() and (@base instanceof ObjectNode or @isNumber()) complete = @last = baseline for prop, i in props @@ -373,8 +373,8 @@ exports.ValueNode = class ValueNode extends BaseNode if prop.soakNode if @base instanceof CallNode or @base.contains((n) -> n instanceof CallNode) and i is 0 temp = o.scope.freeVariable() - complete = "(#{ baseline = temp } = (#complete))" - complete = "typeof #complete === \"undefined\" || #baseline" if i is 0 and @isStart(o) + complete = "(#{ baseline = temp } = (#{complete}))" + complete = "typeof #{complete} === \"undefined\" || #{baseline}" if i is 0 and @isStart(o) complete += @SOAK + (baseline += prop.compile(o)) else part = prop.compile(o) @@ -382,7 +382,7 @@ exports.ValueNode = class ValueNode extends BaseNode complete += part @last = part - if op and @wrapped then "(#complete)" else complete + if op and @wrapped then "(#{complete})" else complete #### CommentNode @@ -399,8 +399,8 @@ exports.CommentNode = class CommentNode extends BaseNode this compileNode: (o) -> - sep = "\n#@tab" - "#@tab/*#sep#{ @lines.join(sep) }\n#@tab*/" + sep = '\n' + @tab + "#{@tab}/*##{sep + @lines.join(sep) }\n#{@tab}*/" #### CallNode @@ -431,7 +431,7 @@ exports.CallNode = class CallNode extends BaseNode superReference: (o) -> methname = o.scope.method.name meth = if o.scope.method.proto - "#{o.scope.method.proto}.__superClass__.#methname" + "#{o.scope.method.proto}.__superClass__.#{methname}" else if methname "#{methname}.__superClass__.constructor" else throw new Error "cannot call super on an anonymous function." @@ -444,13 +444,13 @@ exports.CallNode = class CallNode extends BaseNode unless compilation args = (arg.compile(o) for arg in @args).join(', ') compilation = if @isSuper then @compileSuper(args, o) - else "#{@prefix()}#{@variable.compile(o)}(#args)" - if o.operation and @wrapped then "(#compilation)" else compilation + else "#{@prefix()}#{@variable.compile(o)}(#{args})" + if o.operation and @wrapped then "(#{compilation})" else compilation # `super()` is converted into a call against the superclass's implementation # of the current function. compileSuper: (args, o) -> - "#{@superReference(o)}.call(this#{ if args.length then ', ' else '' }#args)" + "#{@superReference(o)}.call(this#{ if args.length then ', ' else '' }#{args})" # If you call a function with a splat, it's converted into a JavaScript # `.apply()` call to allow an array of arguments to be passed. @@ -462,18 +462,18 @@ exports.CallNode = class CallNode extends BaseNode if obj.match(/\(/) temp = o.scope.freeVariable() obj = temp - meth = "(#temp = #{ @variable.source })#{ @variable.last }" + meth = "(#{temp} = #{ @variable.source })#{ @variable.last }" if @isNew utility 'extends' """ (function() { #{@idt(1)}var ctor = function(){}; - #{@idt(1)}__extends(ctor, #meth); + #{@idt(1)}__extends(ctor, #{meth}); #{@idt(1)}return #{meth}.apply(new ctor, #{ @compileSplatArguments(o) }); - #@tab}).call(this) + #{@tab}}).call(this) """ else - "#{@prefix()}#{meth}.apply(#obj, #{ @compileSplatArguments(o) })" + "#{@prefix()}#{meth}.apply(#{obj}, #{ @compileSplatArguments(o) })" #### ExtendsNode @@ -508,7 +508,7 @@ exports.AccessorNode = class AccessorNode extends BaseNode compileNode: (o) -> name = @name.compile o o.chainRoot.wrapped or= @soakNode - namePart = if name.match(IS_STRING) then "[#name]" else ".#name" + namePart = if name.match(IS_STRING) then "[#{name}]" else ".#{name}" @prototype + namePart #### IndexNode @@ -525,7 +525,7 @@ exports.IndexNode = class IndexNode extends BaseNode o.chainRoot.wrapped or= @soakNode idx = @index.compile o prefix = if @proto then '.prototype' else '' - "#prefix[#idx]" + "#{prefix}[#{idx}]" #### RangeNode @@ -560,23 +560,23 @@ exports.RangeNode = class RangeNode extends BaseNode return @compileSimple(o) if @fromNum and @toNum idx = del o, 'index' step = del o, 'step' - vars = "#idx = #@fromVar" - intro = "(#@fromVar <= #@toVar ? #idx" - compare = "#intro <#@equals #@toVar : #idx >#@equals #@toVar)" + vars = "#{idx} = #{@fromVar}" + intro = "(#{@fromVar} <= #{@toVar} ? #{idx}" + compare = "#{intro} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar})" stepPart = if step then step.compile(o) else '1' - incr = if step then "#idx += #stepPart" else "#intro += #stepPart : #idx -= #stepPart)" - "#vars; #compare; #incr" + incr = if step then "#{idx} += #{stepPart}" else "#{intro} += #{stepPart} : #{idx} -= #{stepPart})" + "#{vars}; #{compare}; #{incr}" # Compile a simple range comprehension, with integers. compileSimple: (o) -> [from, to] = [parseInt(@fromNum, 10), parseInt(@toNum, 10)] idx = del o, 'index' step = del o, 'step' - step and= "#idx += #{step.compile(o)}" + step and= "#{idx} += #{step.compile(o)}" if from <= to - "#idx = #from; #idx <#@equals #to; #{step or "#idx++"}" + "#{idx} = #{from}; #{idx} <#{@equals} #{to}; #{step or "#{idx}++"}" else - "#idx = #from; #idx >#@equals #to; #{step or "#idx--"}" + "#{idx} = #{from}; #{idx} >#{@equals} #{to}; #{step or "#{idx}--"}" # When used as a value, expand the range into the equivalent array. compileArray: (o) -> @@ -593,10 +593,10 @@ exports.RangeNode = class RangeNode extends BaseNode o.index = i body = @compileSimple o else - clause = "#@fromVar <= #@toVar ?" - body = "var #i = #@fromVar; #clause #i <#@equals #@toVar : #i >#@equals #@toVar; #clause #i += 1 : #i -= 1" - post = "{ #{result}.push(#i); }\n#{idt}return #result;\n#o.indent" - "(function() {#{pre}\n#{idt}for (#body)#post}).call(this)" + clause = "#{@fromVar} <= #{@toVar} ?" + body = "var #{i} = #{@fromVar}; #{clause} #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{clause} #{i} += 1 : #{i} -= 1" + post = "{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}" + "(function() {#{pre}\n#{idt}for (#{body})#{post}}).call(this)" #### SliceNode @@ -614,7 +614,7 @@ exports.SliceNode = class SliceNode extends BaseNode from = @range.from.compile(o) to = @range.to.compile(o) plusPart = if @range.exclusive then '' else ' + 1' - ".slice(#from, #to#plusPart)" + ".slice(#{from}, #{to}#{plusPart})" #### ObjectNode @@ -640,7 +640,7 @@ exports.ObjectNode = class ObjectNode extends BaseNode indent + prop.compile(o) + join props = props.join('') inner = if props then '\n' + props + '\n' + @idt() else '' - "{#inner}" + '{' + inner + '}' #### ArrayNode @@ -663,16 +663,16 @@ exports.ArrayNode = class ArrayNode extends BaseNode if obj instanceof SplatNode return @compileSplatLiteral o else if obj instanceof CommentNode - objects.push "\n#code\n#o.indent" + objects.push "\n#{code}\n#{o.indent}" else if i is @objects.length - 1 objects.push code else - objects.push "#code, " + objects.push "#{code}, " objects = objects.join('') if indexOf(objects, '\n') >= 0 - "[\n#{@idt(1)}#objects\n#@tab]" + "[\n#{@idt(1)}#{objects}\n#{@tab}]" else - "[#objects]" + "[#{objects}]" #### ClassNode @@ -729,19 +729,19 @@ exports.ClassNode = class ClassNode extends BaseNode me or= constScope.freeVariable() pname = pvar.compile(o) constructor.body.push new ReturnNode literal 'this' if constructor.body.empty() - constructor.body.unshift literal "this.#{pname} = function(){ return #{className}.prototype.#{pname}.apply(#me, arguments); }" + constructor.body.unshift literal "this.#{pname} = function(){ return #{className}.prototype.#{pname}.apply(#{me}, arguments); }" if pvar access = if prop.context is 'this' then pvar.base.properties[0] else new AccessorNode(pvar, 'prototype') val = new ValueNode(@variable, [access]) prop = new AssignNode(val, func) props.push prop - constructor.body.unshift literal "#me = this" if me + constructor.body.unshift literal "#{me} = this" if me construct = @idt() + (new AssignNode(@variable, constructor)).compile(merge o, {sharedScope: constScope}) + ';' props = if !props.empty() then '\n' + props.compile(o) else '' extension = if extension then '\n' + @idt() + extension.compile(o) + ';' else '' returns = if @returns then '\n' + new ReturnNode(@variable).compile(o) else '' - "#construct#extension#props#returns" + construct + extension + props + returns #### AssignNode @@ -790,11 +790,11 @@ exports.AssignNode = class AssignNode extends BaseNode @value.name = last if last.match(IDENTIFIER) @value.proto = proto if proto val = @value.compile o - return "#name: #val" if @context is 'object' + return "#{name}: #{val}" if @context is 'object' o.scope.find name unless @isValue() and (@variable.hasProperties() or @variable.namespaced) - val = "#name = #val" - return "#@tab#val;" if stmt - if top then val else "(#val)" + val = "#{name} = #{val}" + return "#{@tab}#{val};" if stmt + if top then val else "(#{val})" # Brief implementation of recursive pattern matching, when assigning array or # object literals to a value. Peeks at their properties to assign inner names. @@ -803,7 +803,7 @@ exports.AssignNode = class AssignNode extends BaseNode compilePatternMatch: (o) -> valVar = o.scope.freeVariable() value = if @value.isStatement() then ClosureNode.wrap(@value) else @value - assigns = ["#@tab#valVar = #{ value.compile(o) };"] + assigns = ["#{@tab}#{valVar} = #{ value.compile(o) };"] o.top = true o.asStatement = true splat = false @@ -843,7 +843,7 @@ exports.AssignNode = class AssignNode extends BaseNode from = range.from.compile(o) to = range.to.compile(o) + ' - ' + from + plus val = @value.compile(o) - "#{name}.splice.apply(#name, [#from, #to].concat(#val))" + "#{name}.splice.apply(#{name}, [#{from}, #{to}].concat(#{val}))" #### CodeNode @@ -899,9 +899,9 @@ exports.CodeNode = class CodeNode extends BaseNode @body.makeReturn() unless empty (o.scope.parameter(param)) for param in params code = if @body.expressions.length then "\n#{ @body.compileWithDeclarations(o) }\n" else '' - func = "function(#{ params.join(', ') }) {#code#{ code and @tab }}" - return "#{utility('bind')}(#func, this)" if @bound - if top then "(#func)" else func + func = "function(#{ params.join(', ') }) {#{code}#{ code and @tab }}" + return "#{utility('bind')}(#{func}, this)" if @bound + if top then "(#{func})" else func topSensitive: -> true @@ -913,7 +913,7 @@ exports.CodeNode = class CodeNode extends BaseNode toString: (idt) -> idt or= '' children = (child.toString(idt + TAB) for child in @collectChildren()).join('') - "\n#idt#children" + '\n' + idt + children #### ParamNode @@ -932,7 +932,7 @@ exports.ParamNode = class ParamNode extends BaseNode @value.compile o toString: (idt) -> - if @attach then (literal "@#@name").toString idt else @value.toString idt + if @attach then (literal '@' + @name).toString idt else @value.toString idt #### SplatNode @@ -960,22 +960,22 @@ exports.SplatNode = class SplatNode extends BaseNode len = o.scope.freeVariable() o.scope.assign len, "arguments.length" variadic = o.scope.freeVariable() - o.scope.assign variadic, "#len >= #@arglength" - end = if @trailings.length then ", #len - #{@trailings.length}" + o.scope.assign variadic, len + ' >= ' + @arglength + end = if @trailings.length then ", #{len} - #{@trailings.length}" for trailing, idx in @trailings if trailing.attach assign = trailing.assign trailing = literal o.scope.freeVariable() assign.value = trailing pos = @trailings.length - idx - o.scope.assign(trailing.compile(o), "arguments[#variadic ? #len - #pos : #{@index + idx}]") - "#name = #{utility('slice')}.call(arguments, #@index#end)" + o.scope.assign(trailing.compile(o), "arguments[#{variadic} ? #{len} - #{pos} : #{@index + idx}]") + "#{name} = #{utility('slice')}.call(arguments, #{@index}#{end})" # A compiling a splat as a destructuring assignment means slicing arguments # from the right-hand-side's corresponding array. compileValue: (o, name, index, trailings) -> - trail = if trailings then ", #{name}.length - #trailings" else '' - "#{utility 'slice'}.call(#name, #index#trail)" + trail = if trailings then ", #{name}.length - #{trailings}" else '' + "#{utility 'slice'}.call(#{name}, #{index}#{trail})" # Utility function that converts arbitrary number of elements, mixed with # splats, to a proper array @@ -986,14 +986,14 @@ exports.SplatNode = class SplatNode extends BaseNode prev = args[last = args.length - 1] if not (arg instanceof SplatNode) if prev and starts(prev, '[') and ends(prev, ']') - args[last] = "#{prev.substr(0, prev.length - 1)}, #code]" + args[last] = "#{prev.substr(0, prev.length - 1)}, #{code}]" continue else if prev and starts(prev, '.concat([') and ends(prev, '])') - args[last] = "#{prev.substr(0, prev.length - 2)}, #code])" + args[last] = "#{prev.substr(0, prev.length - 2)}, #{code}])" continue else - code = "[#code]" - args.push(if i is 0 then code else ".concat(#code)") + code = "[#{code}]" + args.push(if i is 0 then code else ".concat(#{code})") args.join('') #### WhileNode @@ -1036,15 +1036,15 @@ exports.WhileNode = class WhileNode extends BaseNode set = '' unless top rvar = o.scope.freeVariable() - set = "#@tab#rvar = [];\n" + set = "#{@tab}#{rvar} = [];\n" @body = PushNode.wrap(rvar, @body) if @body - pre = "#set#{@tab}while (#cond)" + pre = "#{set}#{@tab}while (#{cond})" @body = Expressions.wrap([new IfNode(@guard, @body)]) if @guard if @returns post = '\n' + new ReturnNode(literal(rvar)).compile(merge(o, indent: @idt())) else post = '' - "#pre {\n#{ @body.compile(o) }\n#@tab}#post" + "#{pre} {\n#{ @body.compile(o) }\n#{@tab}}#{post}" #### OpNode @@ -1103,7 +1103,7 @@ exports.OpNode = class OpNode extends BaseNode shared = @first.unwrap().second [@first.second, shared] = shared.compileReference(o) if shared.containsType CallNode [first, second, shared] = [@first.compile(o), @second.compile(o), shared.compile(o)] - "(#first) && (#shared #@operator #second)" + "(#{first}) && (#{shared} #{@operator} #{second})" # When compiling a conditional assignment, take care to ensure that the # operands are only evaluated once, even though we have to reference them @@ -1112,15 +1112,15 @@ exports.OpNode = class OpNode extends BaseNode [first, firstVar] = @first.compileReference o, precompile: yes, assignment: yes second = @second.compile o o.scope.find(first) if first.match(IDENTIFIER) - return "#first = #{ ExistenceNode.compileTest(o, literal(firstVar)) } ? #firstVar : #second" if @operator is '?=' - "#first = #firstVar #{ @operator.substr(0, 2) } #second" + return "#{first} = #{ ExistenceNode.compileTest(o, literal(firstVar)) } ? #{firstVar} : #{second}" if @operator is '?=' + "#{first} = #{firstVar} #{ @operator.substr(0, 2) } #{second}" # If this is an existence operator, we delegate to `ExistenceNode.compileTest` # to give us the safe references for the variables. compileExistence: (o) -> [first, second] = [@first.compile(o), @second.compile(o)] test = ExistenceNode.compileTest(o, @first) - "#test ? #first : #second" + "#{test} ? #{first} : #{second}" # Compile a unary **OpNode**. compileUnary: (o) -> @@ -1153,7 +1153,7 @@ exports.InNode = class InNode extends BaseNode [@arr1, @arr2] = @array.compileReference o, precompile: yes [i, l] = [o.scope.freeVariable(), o.scope.freeVariable()] prefix = if @obj1 isnt @obj2 then @obj1 + '; ' else '' - "(function(){ #{prefix}for (var #i=0, #l=#{@arr1}.length; #i<#l; #i++) { if (#{@arr2}[#i] === #@obj2) return true; } return false; }).call(this)" + "(function(){ #{prefix}for (var #{i}=0, #{l}=#{@arr1}.length; #{i}<#{l}; #{i}++) { if (#{@arr2}[#{i}] === #{@obj2}) return true; } return false; }).call(this)" #### TryNode @@ -1178,9 +1178,9 @@ exports.TryNode = class TryNode extends BaseNode o.top = true attemptPart = @attempt.compile(o) errorPart = if @error then " (#{ @error.compile(o) }) " else ' ' - catchPart = if @recovery then " catch#errorPart{\n#{ @recovery.compile(o) }\n#@tab}" else '' - finallyPart = (@ensure or '') and ' finally {\n' + @ensure.compile(merge(o)) + "\n#@tab}" - "#{@tab}try {\n#attemptPart\n#@tab}#catchPart#finallyPart" + catchPart = if @recovery then " catch#{errorPart}{\n#{ @recovery.compile(o) }\n#{@tab}}" else '' + finallyPart = (@ensure or '') and ' finally {\n' + @ensure.compile(merge(o)) + "\n#{@tab}}" + "#{@tab}try {\n#{attemptPart}\n#{@tab}}#{catchPart}#{finallyPart}" #### ThrowNode @@ -1249,10 +1249,10 @@ exports.ParentheticalNode = class ParentheticalNode extends BaseNode top = del o, 'top' code = @expression.compile(o) if @isStatement() - return (if top then "#@tab#code;" else code) + return (if top then @tab + code + ';' else code) l = code.length code = code.substr(o, l-1) if code.substr(l-1, 1) is ';' - if @expression instanceof AssignNode then code else "(#code)" + if @expression instanceof AssignNode then code else "(#{code})" #### ForNode @@ -1317,34 +1317,34 @@ exports.ForNode = class ForNode extends BaseNode forPart = source.compile merge o, index: ivar, step: @step else svar = scope.freeVariable() - sourcePart = "#svar = #{ @source.compile(o) };" + sourcePart = "#{svar} = #{ @source.compile(o) };" if @pattern - namePart = new AssignNode(@name, literal("#svar[#ivar]")).compile(merge o, {indent: @idt(1), top: true}) + '\n' + namePart = new AssignNode(@name, literal("#{svar}[#{ivar}]")).compile(merge o, {indent: @idt(1), top: true}) + '\n' else - namePart = "#name = #svar[#ivar]" if name + namePart = "#{name} = #{svar}[#{ivar}]" if name unless @object lvar = scope.freeVariable() - stepPart = if @step then "#ivar += #{ @step.compile(o) }" else "#ivar++" - forPart = "#ivar = 0, #lvar = #{svar}.length; #ivar < #lvar; #stepPart" - sourcePart = (if rvar then "#rvar = []; " else '') + sourcePart - sourcePart = if sourcePart then "#@tab#sourcePart\n#@tab" else @tab + stepPart = if @step then "#{ivar} += #{ @step.compile(o) }" else "#{ivar}++" + forPart = "#{ivar} = 0, #{lvar} = #{svar}.length; #{ivar} < #{lvar}; #{stepPart}" + sourcePart = (if rvar then "#{rvar} = []; " else '') + sourcePart + sourcePart = if sourcePart then "#{@tab}#{sourcePart}\n#{@tab}" else @tab returnResult = @compileReturnValue(rvar, o) body = PushNode.wrap(rvar, body) unless topLevel if @guard body = Expressions.wrap([new IfNode(@guard, body)]) if codeInBody - body.unshift literal "var #namePart" if namePart - body.unshift literal "var #index = #ivar" if index + body.unshift literal "var #{namePart}" if namePart + body.unshift literal "var #{index} = #{ivar}" if index body = ClosureNode.wrap(body, true) else - varPart = (namePart or '') and (if @pattern then namePart else "#{@idt(1)}#namePart;\n") + varPart = (namePart or '') and (if @pattern then namePart else "#{@idt(1)}#{namePart};\n") if @object - forPart = "#ivar in #svar" - guardPart = "\n#{@idt(1)}if (!#{utility('hasProp')}.call(#svar, #ivar)) continue;" unless @raw + forPart = "#{ivar} in #{svar}" + guardPart = "\n#{@idt(1)}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" unless @raw body = body.compile(merge(o, {indent: @idt(1), top: true})) - vars = if range then name else "#name, #ivar" - "#{sourcePart}for (#forPart) {#guardPart\n#varPart#body\n#@tab}#returnResult" + vars = if range then name else "#{name}, #{ivar}" + "#{sourcePart}for (#{forPart}) {#{guardPart}\n#{varPart}#{body}\n#{@tab}}#{returnResult}" #### IfNode @@ -1435,20 +1435,20 @@ exports.IfNode = class IfNode extends BaseNode ifDent = if child then '' else @idt() comDent = if child then @idt() else '' body = @body.compile(o) - ifPart = "#{ifDent}if (#{ @compileCondition(condO) }) {\n#body\n#@tab}" + ifPart = "#{ifDent}if (#{ @compileCondition(condO) }) {\n#{body}\n#{@tab}}" return ifPart unless @elseBody elsePart = if @isChain ' else ' + @elseBodyNode().compile(merge(o, {indent: @idt(), chainChild: true})) else - " else {\n#{ @elseBody.compile(o) }\n#@tab}" - "#ifPart#elsePart" + " else {\n#{ @elseBody.compile(o) }\n#{@tab}}" + "#{ifPart}#{elsePart}" # Compile the IfNode as a ternary operator. compileTernary: (o) -> o.operation = true ifPart = @condition.compile(o) + ' ? ' + @bodyNode().compile(o) elsePart = if @elseBody then @elseBodyNode().compile(o) else 'null' - "#ifPart : #elsePart" + "#{ifPart} : #{elsePart}" # Faux-Nodes # ---------- @@ -1559,6 +1559,6 @@ literal = (name) -> # Helper for ensuring that utility functions are assigned at the top level. utility = (name) -> - ref = "__#name" + ref = "__#{name}" Scope.root.assign ref, UTILITIES[name] ref diff --git a/src/optparse.coffee b/src/optparse.coffee index afe67af4..a3234422 100644 --- a/src/optparse.coffee +++ b/src/optparse.coffee @@ -33,7 +33,7 @@ exports.OptionParser = class OptionParser options[rule.name] = if rule.hasArgument then args[i += 1] else true matchedRule = yes break - throw new Error "unrecognized option: #arg" if isOption and not matchedRule + throw new Error "unrecognized option: #{arg}" if isOption and not matchedRule if not isOption options.arguments = args[i...args.length] break @@ -43,12 +43,12 @@ exports.OptionParser = class OptionParser # of the valid options, for `--help` and such. help: -> lines = ['Available options:'] - lines.unshift "#@banner\n" if @banner + lines.unshift "#{@banner}\n" if @banner for rule in @rules spaces = 15 - rule.longFlag.length spaces = if spaces > 0 then (' ' for i in [0..spaces]).join('') else '' letPart = if rule.shortFlag then rule.shortFlag + ', ' else ' ' - lines.push " #letPart#rule.longFlag#spaces#rule.description" + lines.push ' ' + letPart + rule.longFlag + spaces + rule.description "\n#{ lines.join('\n') }\n" # Helpers diff --git a/src/repl.coffee b/src/repl.coffee index 233e1f3e..772e9a79 100644 --- a/src/repl.coffee +++ b/src/repl.coffee @@ -2,7 +2,7 @@ # and evaluates it. Good for simple tests, or poking around the **Node.js** API. # Using it looks like this: # -# coffee> puts "#num bottles of beer" for num in [99..1] +# coffee> puts "#{num} bottles of beer" for num in [99..1] # Require the **coffee-script** module to get access to the compiler. CoffeeScript = require './coffee-script' diff --git a/src/rewriter.coffee b/src/rewriter.coffee index c2cf550c..cca80cde 100644 --- a/src/rewriter.coffee +++ b/src/rewriter.coffee @@ -254,7 +254,7 @@ exports.Rewriter = class Rewriter if unclosed.length open = unclosed[0] line = openLine[open] + 1 - throw new Error "unclosed #open on line #line" + throw new Error "unclosed #{open} on line #{line}" # We'd like to support syntax like this: # diff --git a/src/scope.coffee b/src/scope.coffee index c414eade..d7f412ff 100644 --- a/src/scope.coffee +++ b/src/scope.coffee @@ -80,7 +80,7 @@ exports.Scope = class Scope # Return the list of assignments that are supposed to be made at the top # of this scope. assignedVariables: -> - "#key = #val.value" for key, val of @variables when val.assigned + "#{key} = #{val.value}" for key, val of @variables when val.assigned # Compile the JavaScript for all of the variable declarations in this scope. compiledDeclarations: -> diff --git a/test/test_classes.coffee b/test/test_classes.coffee index 9b707fab..1f2bf5c7 100644 --- a/test/test_classes.coffee +++ b/test/test_classes.coffee @@ -1,10 +1,10 @@ # Test classes with a four-level inheritance chain. class Base func: (string) -> - "zero/#string" + "zero/#{string}" @static: (string) -> - "static/#string" + "static/#{string}" class FirstChild extends Base func: (string) -> @@ -56,7 +56,7 @@ Base = -> Base::func = (string) -> 'zero/' + string Base::['func-func'] = (string) -> - "dynamic-#string" + "dynamic-#{string}" FirstChild = -> FirstChild extends Base @@ -137,7 +137,7 @@ class Dog @name = name bark: => - "#@name woofs!" + "#{@name} woofs!" spark = new Dog('Spark') fido = new Dog('Fido') @@ -164,7 +164,7 @@ class Connection [@one, @two, @three] = [one, two, three] out: -> - "#@one-#@two-#@three" + "#{@one}-#{@two}-#{@three}" list = [3, 2, 1] conn = new Connection list... diff --git a/test/test_heredocs.coffee b/test/test_heredocs.coffee index e54fd7a7..767b9a74 100644 --- a/test/test_heredocs.coffee +++ b/test/test_heredocs.coffee @@ -55,17 +55,17 @@ ok a is 'more"than"one"quote' val = 10 a = """ - basic heredoc #val + basic heredoc #{val} on two lines """ b = ''' - basic heredoc #val + basic heredoc #{val} on two lines ''' ok a is "basic heredoc 10\non two lines" -ok b is "basic heredoc \#val\non two lines" +ok b is "basic heredoc \#{val}\non two lines" a = '''here's an apostrophe''' diff --git a/test/test_pattern_matching.coffee b/test/test_pattern_matching.coffee index b089a3d3..9757bf8b 100644 --- a/test/test_pattern_matching.coffee +++ b/test/test_pattern_matching.coffee @@ -119,7 +119,7 @@ persons = { Christopher: { name: "Stan" } } -join1 = "#key: #name" for key, { name } of persons +join1 = "#{key}: #{name}" for key, { name } of persons deepEqual join1, ["George: Bob", "Bob: Alice", "Christopher: Stan"] @@ -129,11 +129,11 @@ persons = [ { name: "Stan", parent: { name: "Christopher" } } ] -join2 = "#parent: #name" for { name, parent: { name: parent } } in persons +join2 = "#{parent}: #{name}" for { name, parent: { name: parent } } in persons deepEqual join1, join2 persons = [['Bob', ['George']], ['Alice', ['Bob']], ['Stan', ['Christopher']]] -join3 = "#parent: #name" for [name, [parent]] in persons +join3 = "#{parent}: #{name}" for [name, [parent]] in persons deepEqual join2, join3 diff --git a/test/test_regexp_interpolation.coffee b/test/test_regexp_interpolation.coffee index d55e162d..95b921cb 100644 --- a/test/test_regexp_interpolation.coffee +++ b/test/test_regexp_interpolation.coffee @@ -4,17 +4,17 @@ name = 'Moe' ok not not '"Moe"'.match(/^"#{name}"$/i) ok '"Moe!"'.match(/^"#{name}"$/i) is null -ok not not 'Moe'.match(/^#name$/) -ok 'Moe!'.match(/^#name/) +ok not not 'Moe'.match(/^#{name}$/) +ok 'Moe!'.match(/^#{name}/) -ok 'Moe!'.match(/#{"#{"#{"#name"}"}"}/imgy) +ok 'Moe!'.match(/#{"#{"#{"#{name}"}"}"}/imgy) ok '$a$b$c'.match(/\$A\$B\$C/i) a = 1 b = 2 c = 3 -ok '123'.match(/#a#b#c/i) +ok '123'.match(/#{a}#{b}#{c}/i) [a, b, c] = [1, 2, /\d+/] -ok (/#a#b#c$/i).toString() is '/12/\\d+/$/i' +ok (/#{a}#{b}#{c}$/i).toString() is '/12/\\d+/$/i' diff --git a/test/test_string_interpolation.coffee b/test/test_string_interpolation.coffee index 8f85ae7e..e4c9d6e1 100644 --- a/test/test_string_interpolation.coffee +++ b/test/test_string_interpolation.coffee @@ -1,45 +1,31 @@ hello = 'Hello' world = 'World' -ok '#hello #world!' is '#hello #world!' ok '#{hello} #{world}!' is '#{hello} #{world}!' -ok "#hello #world!" is 'Hello World!' ok "#{hello} #{world}!" is 'Hello World!' -ok "[#hello#world]" is '[HelloWorld]' ok "[#{hello}#{world}]" is '[HelloWorld]' -ok "#hello##world" is 'Hello#World' ok "#{hello}##{world}" is 'Hello#World' ok "Hello #{ 1 + 2 } World" is 'Hello 3 World' -ok "#hello #{ 1 + 2 } #world" is "Hello 3 World" +ok "#{hello} #{ 1 + 2 } #{world}" is "Hello 3 World" [s, t, r, i, n, g] = ['s', 't', 'r', 'i', 'n', 'g'] -ok "#s#t#r#i#n#g" is 'string' ok "#{s}#{t}#{r}#{i}#{n}#{g}" is 'string' -ok "\#s\#t\#r\#i\#n\#g" is '#s#t#r#i#n#g' -ok "\\#s\\#t\\#r\\#i\\#n\\#g" is '\\s\\t\\r\\i\\n\\g' ok "\#{s}\#{t}\#{r}\#{i}\#{n}\#{g}" is '#{s}#{t}#{r}#{i}#{n}#{g}' -ok "\#string" is '#string' ok "\#{string}" is '#{string}' -ok "\#Escaping first" is '#Escaping first' ok "\#{Escaping} first" is '#{Escaping} first' -ok "Escaping \#in middle" is 'Escaping #in middle' ok "Escaping \#{in} middle" is 'Escaping #{in} middle' -ok "Escaping \#last" is 'Escaping #last' ok "Escaping \#{last}" is 'Escaping #{last}' ok "##" is '##' ok "#{}" is '' ok "#{}A#{} #{} #{}B#{}" is 'A B' -ok "\\\\\##" is '\\\\\##' ok "\\\#{}" is '\\#{}' -ok "I won #20 last night." is 'I won #20 last night.' ok "I won ##{20} last night." is 'I won #20 last night.' -ok "I won ##20 last night." is 'I won ##20 last night.' ok "I won ##{'#20'} last night." is 'I won ##20 last night.' @@ -54,8 +40,8 @@ ok "values: #{list.join ' '}" is 'values: 0 1 2 3 4 5 6 7 8 9' obj = { name: 'Joe' - hi: -> "Hello #@name." - cya: -> "Hello #@name.".replace('Hello','Goodbye') + hi: -> "Hello #{@name}." + cya: -> "Hello #{@name}.".replace('Hello','Goodbye') } ok obj.hi() is "Hello Joe." ok obj.cya() is "Goodbye Joe." @@ -65,10 +51,9 @@ ok "With #{"quotes"}" is 'With quotes' ok 'With #{"quotes"}' is 'With #{"quotes"}' ok "Where is #{obj["name"] + '?'}" is 'Where is Joe?' -ok "Where is #obj.name?" is 'Where is Joe?' ok "Where is #{"the nested #{obj["name"]}"}?" is 'Where is the nested Joe?' -ok "Hello #{world ? "#hello"}" is 'Hello World' +ok "Hello #{world ? "#{hello}"}" is 'Hello World' ok "Hello #{"#{"#{obj["name"]}" + '!'}"}" is 'Hello Joe!' @@ -82,7 +67,7 @@ ok a is "Hello Joe" a = 1 b = 2 c = 3 -ok "#a#b#c" is '123' +ok "#{a}#{b}#{c}" is '123' result = null