Fix for #1216 ?= compilation

This commit is contained in:
Gerald Lewis 2011-05-10 19:20:10 -04:00
parent d4d027159f
commit 2212e959ac
3 changed files with 68 additions and 17 deletions

View File

@ -7,7 +7,12 @@
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
}, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
}, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __indexOf = Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) {
if (this[i] === item) return i;
}
return -1;
};
Scope = require('./scope').Scope;
_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;
@ -1281,7 +1286,7 @@
Assign.prototype.compileConditional = function(o) {
var left, rite, _ref2;
_ref2 = this.variable.cacheReference(o), left = _ref2[0], rite = _ref2[1];
return new Op(this.context.slice(0, -1), left, new Assign(rite, this.value, '=')).compile(o);
return new Op(this.context.slice(0, -1), left, new Assign(rite, this.value, '='), void 0, __indexOf.call(this.context, "?") >= 0).compile(o);
};
Assign.prototype.compileSplice = function(o) {
var code, exclusive, from, fromDecl, fromRef, name, to, valDef, valRef, _ref2, _ref3, _ref4;
@ -1579,8 +1584,9 @@
exports.Op = Op = (function() {
var CONVERSIONS, INVERSIONS;
__extends(Op, Base);
function Op(op, first, second, flip) {
function Op(op, first, second, flip, isExistentialEquals) {
var call;
this.isExistentialEquals = isExistentialEquals;
if (op === 'in') {
return new In(first, second);
}
@ -1693,9 +1699,15 @@
fst = this.first;
ref = fst;
}
if (this.isExistentialEquals) {
return new If(new Existence(fst).invert(), this.second, {
type: 'if'
}).compile(o);
} else {
return new If(new Existence(fst), ref, {
type: 'if'
}).addElse(this.second).compile(o);
}
};
Op.prototype.compileUnary = function(o) {
var op, parts;
@ -1829,9 +1841,9 @@
Existence.prototype.children = ['expression'];
Existence.prototype.invert = NEGATE;
Existence.prototype.compileNode = function(o) {
var code, sym;
var cmp, cnj, code, _ref2;
code = this.expression.compile(o, LEVEL_OP);
code = IDENTIFIER.test(code) && !o.scope.check(code) ? this.negated ? "typeof " + code + " === \"undefined\" || " + code + " === null" : "typeof " + code + " !== \"undefined\" && " + code + " !== null" : (sym = this.negated ? '==' : '!=', "" + code + " " + sym + " null");
code = IDENTIFIER.test(code) && !o.scope.check(code) ? ((_ref2 = this.negated ? ['===', '||'] : ['!==', '&&'], cmp = _ref2[0], cnj = _ref2[1], _ref2), "typeof " + code + " " + cmp + " \"undefined\" " + cnj + " " + code + " " + cmp + " null") : "" + code + " " + (this.negated ? '==' : '!=') + " null";
if (o.level <= LEVEL_COND) {
return code;
} else {

View File

@ -1009,7 +1009,7 @@ exports.Assign = class Assign extends Base
# more than once.
compileConditional: (o) ->
[left, rite] = @variable.cacheReference o
new Op(@context.slice(0, -1), left, new Assign(rite, @value, '=')).compile o
new Op(@context.slice(0, -1), left, new Assign(rite, @value, '='), undefined, "?" in @context ).compile o
# Compile the assignment from an array splice literal, using JavaScript's
# `Array#splice` method.
@ -1218,7 +1218,10 @@ exports.While = class While extends Base
# Simple Arithmetic and logical operations. Performs some conversion from
# CoffeeScript operations into their JavaScript equivalents.
exports.Op = class Op extends Base
constructor: (op, first, second, flip) ->
constructor: (op, first, second, flip, @isExistentialEquals ) ->
return new In first, second if op is 'in'
if op is 'do'
call = new Call first, first.params or []
@ -1313,6 +1316,9 @@ exports.Op = class Op extends Base
else
fst = @first
ref = fst
if @isExistentialEquals
new If(new Existence(fst).invert(), @second, type: 'if').compile o
else
new If(new Existence(fst), ref, type: 'if').addElse(@second).compile o
# Compile a unary **Op**.
@ -1426,13 +1432,11 @@ exports.Existence = class Existence extends Base
compileNode: (o) ->
code = @expression.compile o, LEVEL_OP
code = if IDENTIFIER.test(code) and not o.scope.check code
if @negated
"typeof #{code} === \"undefined\" || #{code} === null"
[cmp, cnj] = if @negated then ['===', '||'] else ['!==', '&&']
"typeof #{code} #{cmp} \"undefined\" #{cnj} #{code} #{cmp} null"
else
"typeof #{code} !== \"undefined\" && #{code} !== null"
else
sym = if @negated then '==' else '!='
"#{code} #{sym} null"
# do not use strict equality here; it will break existing code
"#{code} #{if @negated then '==' else '!='} null"
if o.level <= LEVEL_COND then code else "(#{code})"
#### Parens

View File

@ -268,3 +268,38 @@ test "existential assignment", ->
eq nonce, c
d ?= nonce
eq nonce, d
test "#1216 ?= compilation", ->
c = (s) -> CoffeeScript.compile( s, {bare:true} )
# ?= with locally scoped var defined
eq c('a = 0; a ?= b'),
'''var a;
a = 0;
if (a == null) {
a = b;
};'''
# ?= with locally scoped var not defined
eq c('a ?= b'),
'''if (typeof a === "undefined" || a === null) {
a = b;
};'''
# ? with locally scoped var defined
eq c('a = 0; return unless a?'),
'''
var a;
a = 0;
if (a == null) {
return;
}
'''
# ? with locally scoped var not defined
eq c('return unless a?'),
'''
if (typeof a === "undefined" || a === null) {
return;
}
'''