From 26de26f88fe0f84e432ccd9eaea637a75fdf5740 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Fri, 1 Oct 2010 20:52:23 -0400 Subject: [PATCH] conditionals with no alternative now evaluate to 'undefined' instead of 'null' --- lib/browser.js | 4 ++-- lib/cake.js | 2 +- lib/command.js | 8 ++++---- lib/lexer.js | 2 +- lib/nodes.js | 20 ++++++++++---------- lib/rewriter.js | 4 ++-- lib/scope.js | 4 ++-- src/nodes.coffee | 3 ++- test/test_existence.coffee | 14 +++++++------- test/test_if.coffee | 2 +- 10 files changed, 32 insertions(+), 31 deletions(-) diff --git a/lib/browser.js b/lib/browser.js index c0c9bcdf..42e4d077 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -18,7 +18,7 @@ xhr.overrideMimeType('text/plain'); } xhr.onreadystatechange = function() { - return xhr.readyState === 4 ? CoffeeScript.run(xhr.responseText, options) : null; + return xhr.readyState === 4 ? CoffeeScript.run(xhr.responseText, options) : undefined; }; return xhr.send(null); }; @@ -30,7 +30,7 @@ var script = _ref[_i]; return script.type === 'text/coffeescript' ? (script.src ? CoffeeScript.load(script.src) : setTimeout(function() { return CoffeeScript.run(script.innerHTML); - })) : null; + })) : undefined; })(); } return null; diff --git a/lib/cake.js b/lib/cake.js index d0c6ae5e..e8ad2b9b 100755 --- a/lib/cake.js +++ b/lib/cake.js @@ -65,7 +65,7 @@ desc = task.description ? ("# " + (task.description)) : ''; puts("cake " + (name) + (spaces) + " " + (desc)); } - return switches.length ? puts(oparse.help()) : null; + return switches.length ? puts(oparse.help()) : undefined; }; missingTask = function(task) { puts("No such task: \"" + (task) + "\""); diff --git a/lib/command.js b/lib/command.js index 3ae24ffb..fcc90317 100644 --- a/lib/command.js +++ b/lib/command.js @@ -77,7 +77,7 @@ fs.readFile(source, function(err, code) { return compileScript(source, code.toString(), base); }); - return opts.watch ? watch(source, base) : null; + return opts.watch ? watch(source, base) : undefined; } }); }); @@ -115,7 +115,7 @@ } else { t.output = CoffeeScript.compile(t.input, t.options); CoffeeScript.emit('success', task); - return o.print ? print(t.output) : (o.compile ? writeJs(t.file, t.output, base) : (o.lint ? lint(t.output) : null)); + return o.print ? print(t.output) : (o.compile ? writeJs(t.file, t.output, base) : (o.lint ? lint(t.output) : undefined)); } } catch (err) { CoffeeScript.emit('failure', err, task); @@ -134,7 +134,7 @@ code = ''; stdin = process.openStdin(); stdin.on('data', function(buffer) { - return buffer ? code += buffer.toString() : null; + return buffer ? code += buffer.toString() : undefined; }); return stdin.on('end', function() { return compileScript('stdio', code); @@ -168,7 +168,7 @@ js = ' '; } return fs.writeFile(jsPath, js, function(err) { - return opts.compile && opts.watch ? puts("Compiled " + (source)) : null; + return opts.compile && opts.watch ? puts("Compiled " + (source)) : undefined; }); }; return path.exists(dir, function(exists) { diff --git a/lib/lexer.js b/lib/lexer.js index 4fa08bb0..51efdfe2 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -294,7 +294,7 @@ } this.i += value.length; prev = last(this.tokens); - spaced = ((prev != null) ? prev.spaced : null); + spaced = ((prev != null) ? prev.spaced : undefined); tag = value; if (value === '=') { if (include(JS_FORBIDDEN, val = this.value())) { diff --git a/lib/nodes.js b/lib/nodes.js index 228584cc..1ee05a2f 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -55,7 +55,7 @@ return [compiled, reference]; } }).call(this); - if (((options != null) ? options.precompile : null)) { + if (((options != null) ? options.precompile : undefined)) { for (i = 0, _len = pair.length; i < _len; i++) { node = pair[i]; (pair[i] = node.compile(o)); @@ -146,7 +146,7 @@ if (func(child) === false) { return false; } - return child instanceof BaseNode && (crossScope || !(child instanceof CodeNode)) ? child.traverseChildren(crossScope, func) : null; + return child instanceof BaseNode && (crossScope || !(child instanceof CodeNode)) ? child.traverseChildren(crossScope, func) : undefined; }); }; BaseNode.prototype["class"] = 'BaseNode'; @@ -344,7 +344,7 @@ ValueNode.prototype.cacheReference = function(o) { var base, bref, name, nref; name = last(this.properties); - if (!this.base.isComplex() && this.properties.length < 2 && !((name != null) ? name.isComplex() : null)) { + if (!this.base.isComplex() && this.properties.length < 2 && !((name != null) ? name.isComplex() : undefined)) { return [this, this]; } base = new ValueNode(this.base, this.properties.slice(0, -1)); @@ -1132,7 +1132,7 @@ }; CodeNode.prototype.topSensitive = YES; CodeNode.prototype.traverseChildren = function(crossScope, func) { - return crossScope ? CodeNode.__super__.traverseChildren.call(this, crossScope, func) : null; + return crossScope ? CodeNode.__super__.traverseChildren.call(this, crossScope, func) : undefined; }; return CodeNode; })(); @@ -1189,7 +1189,7 @@ o.scope.assign(len, "arguments.length"); variadic = o.scope.freeVariable('result'); o.scope.assign(variadic, len + ' >= ' + this.arglength); - end = this.trailings.length ? (", " + (len) + " - " + (this.trailings.length)) : null; + end = this.trailings.length ? (", " + (len) + " - " + (this.trailings.length)) : undefined; _ref2 = this.trailings; for (idx = 0, _len = _ref2.length; idx < _len; idx++) { trailing = _ref2[idx]; @@ -1237,14 +1237,14 @@ exports.WhileNode = (function() { WhileNode = function(condition, opts) { WhileNode.__super__.constructor.call(this); - if (((opts != null) ? opts.invert : null)) { + if (((opts != null) ? opts.invert : undefined)) { if (condition instanceof OpNode) { condition = new ParentheticalNode(condition); } condition = new OpNode('!', condition); } this.condition = condition; - this.guard = ((opts != null) ? opts.guard : null); + this.guard = ((opts != null) ? opts.guard : undefined); return this; }; __extends(WhileNode, BaseNode); @@ -1774,11 +1774,11 @@ IfNode.prototype.topSensitive = YES; IfNode.prototype.bodyNode = function() { var _ref2; - return (((_ref2 = this.body) != null) ? _ref2.unwrap() : null); + return (((_ref2 = this.body) != null) ? _ref2.unwrap() : undefined); }; IfNode.prototype.elseBodyNode = function() { var _ref2; - return (((_ref2 = this.elseBody) != null) ? _ref2.unwrap() : null); + return (((_ref2 = this.elseBody) != null) ? _ref2.unwrap() : undefined); }; IfNode.prototype.addElse = function(elseBody, statement) { if (this.isChain) { @@ -1849,7 +1849,7 @@ this.elseBodyNode().tags.operation = true; } ifPart = this.condition.compile(o) + ' ? ' + this.bodyNode().compile(o); - elsePart = this.elseBody ? this.elseBodyNode().compile(o) : 'null'; + elsePart = this.elseBody ? this.elseBodyNode().compile(o) : 'undefined'; code = ("" + (ifPart) + " : " + (elsePart)); return this.tags.operation ? ("(" + (code) + ")") : code; }; diff --git a/lib/rewriter.js b/lib/rewriter.js index 40df3ef0..582f0fb9 100644 --- a/lib/rewriter.js +++ b/lib/rewriter.js @@ -263,7 +263,7 @@ return ('TERMINATOR' === (_ref = token[0]) || 'INDENT' === _ref); }; action = function(token, i) { - return token[0] !== 'INDENT' ? (original[0] = 'POST_' + original[0]) : null; + return token[0] !== 'INDENT' ? (original[0] = 'POST_' + original[0]) : undefined; }; this.detectEnd(i + 1, condition, action); return 1; @@ -345,7 +345,7 @@ } debt[mtag] += 1; val = [oppos, mtag === 'INDENT' ? match[1] : oppos]; - if ((((_ref2 = this.tokens[i + 2]) != null) ? _ref2[0] === mtag : null)) { + if ((((_ref2 = this.tokens[i + 2]) != null) ? _ref2[0] === mtag : undefined)) { this.tokens.splice(i + 3, 0, val); stack.push(match); } else { diff --git a/lib/scope.js b/lib/scope.js index 7b91d525..82b1eb1c 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -59,10 +59,10 @@ Scope.prototype.check = function(name, options) { var _ref2, immediate; immediate = Object.prototype.hasOwnProperty.call(this.variables, name); - if (immediate || ((options != null) ? options.immediate : null)) { + if (immediate || ((options != null) ? options.immediate : undefined)) { return immediate; } - return !!(((_ref2 = this.parent) != null) ? _ref2.check(name) : null); + return !!(((_ref2 = this.parent) != null) ? _ref2.check(name) : undefined); }; Scope.prototype.temporary = function(type, index) { return type.length > 1 ? '_' + type + (index > 1 ? index : '') : '_' + (index + parseInt(type, 36)).toString(36).replace(/\d/g, 'a'); diff --git a/src/nodes.coffee b/src/nodes.coffee index 95b7e7e7..35ea4318 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -459,6 +459,7 @@ exports.CallNode = class CallNode extends BaseNode else "#{name}.__super__.constructor" + # Soaked chained invocations unfold into if/else ternary structures. unfoldSoak: (o) -> call = this list = [] @@ -1585,7 +1586,7 @@ exports.IfNode = class IfNode extends BaseNode @bodyNode().tags.operation = @condition.tags.operation = yes @elseBodyNode().tags.operation = yes if @elseBody ifPart = @condition.compile(o) + ' ? ' + @bodyNode().compile(o) - elsePart = if @elseBody then @elseBodyNode().compile(o) else 'null' + elsePart = if @elseBody then @elseBodyNode().compile(o) else 'undefined' code = "#{ifPart} : #{elsePart}" if @tags.operation then "(#{code})" else code diff --git a/test/test_existence.coffee b/test/test_existence.coffee index 6a859068..4c617aa3 100644 --- a/test/test_existence.coffee +++ b/test/test_existence.coffee @@ -44,7 +44,7 @@ eq obj?.prop, "hello" eq obj?['prop'], "hello" eq obj.prop?.length, 5 eq obj?.prop?['length'], 5 -eq obj?.prop?.non?.existent?.property, null +eq obj?.prop?.non?.existent?.property, undefined # Soaks and caches method calls as well. @@ -52,13 +52,13 @@ arr = ["--", "----"] eq arr.pop()?.length, 4 eq arr.pop()?.length, 2 -eq arr.pop()?.length, null -eq arr.pop()?.length?.non?.existent()?.property, null +eq arr.pop()?.length, undefined +eq arr.pop()?.length?.non?.existent()?.property, undefined # Soaks method calls safely. value = null -eq value?.toString().toLowerCase(), null +eq value?.toString().toLowerCase(), undefined value = 10 eq value?.toString().toLowerCase(), '10' @@ -78,7 +78,7 @@ ok counter is 3 ident = (obj) -> obj -eq ident(non?.existent().method()), null, 'soaks inner values' +eq ident(non?.existent().method()), undefined, 'soaks inner values' # Soaks constructor invocations. @@ -94,7 +94,7 @@ ok a is 1 ok not value?.property?, 'safely checks existence on soaks' -eq nothing?.value, null, 'safely calls values off of non-existent variables' +eq nothing?.value, undefined, 'safely calls values off of non-existent variables' # Assign to the result of an exsitential operation with a minus. @@ -132,7 +132,7 @@ ok (maybe_close 'string', 41)?() is undefined eq 2?(3), undefined #726 -eq calendar?[Date()], null +eq calendar?[Date()], undefined #733 a = b: {c: null} diff --git a/test/test_if.coffee b/test/test_if.coffee index f50dd270..fae31936 100644 --- a/test/test_if.coffee +++ b/test/test_if.coffee @@ -66,7 +66,7 @@ ok result is undefined func = -> return if false then callback() -ok func() is null +ok func() is undefined func = -> return unless false then 100 else -100