Fix for #1216 ?= compilation
This commit is contained in:
parent
d4d027159f
commit
2212e959ac
28
lib/nodes.js
28
lib/nodes.js
|
@ -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;
|
||||
}
|
||||
return new If(new Existence(fst), ref, {
|
||||
type: 'if'
|
||||
}).addElse(this.second).compile(o);
|
||||
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 {
|
||||
|
|
|
@ -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,7 +1316,10 @@ exports.Op = class Op extends Base
|
|||
else
|
||||
fst = @first
|
||||
ref = fst
|
||||
new If(new Existence(fst), ref, type: 'if').addElse(@second).compile o
|
||||
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**.
|
||||
compileUnary: (o) ->
|
||||
|
@ -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"
|
||||
else
|
||||
"typeof #{code} !== \"undefined\" && #{code} !== null"
|
||||
[cmp, cnj] = if @negated then ['===', '||'] else ['!==', '&&']
|
||||
"typeof #{code} #{cmp} \"undefined\" #{cnj} #{code} #{cmp} 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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
'''
|
||||
|
|
Loading…
Reference in New Issue