mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-14 09:17:55 -05:00
Issue #1356 ... range comprehension optimization when a step is present.
This commit is contained in:
67
lib/nodes.js
67
lib/nodes.js
@@ -68,9 +68,9 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
Base.prototype.compileLoopReference = function(o, name) {
|
Base.prototype.compileLoopReference = function(o, name) {
|
||||||
var src, tmp, _ref2;
|
var src, tmp;
|
||||||
src = tmp = this.compile(o, LEVEL_LIST);
|
src = tmp = this.compile(o, LEVEL_LIST);
|
||||||
if (!((-Infinity < (_ref2 = +src) && _ref2 < Infinity) || IDENTIFIER.test(src) && o.scope.check(src, true))) {
|
if (!((-Infinity < +src && +src < Infinity) || IDENTIFIER.test(src) && o.scope.check(src, true))) {
|
||||||
src = "" + (tmp = o.scope.freeVariable(name)) + " = " + src;
|
src = "" + (tmp = o.scope.freeVariable(name)) + " = " + src;
|
||||||
}
|
}
|
||||||
return [src, tmp];
|
return [src, tmp];
|
||||||
@@ -783,60 +783,39 @@
|
|||||||
this.equals = this.exclusive ? '' : '=';
|
this.equals = this.exclusive ? '' : '=';
|
||||||
}
|
}
|
||||||
Range.prototype.compileVariables = function(o) {
|
Range.prototype.compileVariables = function(o) {
|
||||||
var parts, _ref2, _ref3, _ref4;
|
var step, _ref2, _ref3, _ref4, _ref5;
|
||||||
o = merge(o, {
|
o = merge(o, {
|
||||||
top: true
|
top: true
|
||||||
});
|
});
|
||||||
_ref2 = this.from.cache(o, LEVEL_LIST), this.from = _ref2[0], this.fromVar = _ref2[1];
|
_ref2 = this.from.cache(o, LEVEL_LIST), this.from = _ref2[0], this.fromVar = _ref2[1];
|
||||||
_ref3 = this.to.cache(o, LEVEL_LIST), this.to = _ref3[0], this.toVar = _ref3[1];
|
_ref3 = this.to.cache(o, LEVEL_LIST), this.to = _ref3[0], this.toVar = _ref3[1];
|
||||||
_ref4 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref4[0], this.toNum = _ref4[1];
|
if (step = del(o, 'step')) {
|
||||||
parts = [];
|
_ref4 = step.cache(o, LEVEL_LIST), this.step = _ref4[0], this.stepVar = _ref4[1];
|
||||||
if (this.from !== this.fromVar) {
|
|
||||||
parts.push(this.from);
|
|
||||||
}
|
}
|
||||||
if (this.to !== this.toVar) {
|
_ref5 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref5[0], this.toNum = _ref5[1];
|
||||||
return parts.push(this.to);
|
if (this.stepVar) {
|
||||||
|
return this.stepNum = this.stepVar.match(SIMPLENUM);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Range.prototype.compileNode = function(o) {
|
Range.prototype.compileNode = function(o) {
|
||||||
var cond, condPart, idx, step, stepPart, stepvar, varPart;
|
var cond, condPart, from, idx, known, stepPart, to, varPart, _ref2;
|
||||||
this.compileVariables(o);
|
if (!this.fromVar) {
|
||||||
|
this.compileVariables(o);
|
||||||
|
}
|
||||||
if (!o.index) {
|
if (!o.index) {
|
||||||
return this.compileArray(o);
|
return this.compileArray(o);
|
||||||
}
|
}
|
||||||
if (this.fromNum && this.toNum) {
|
known = this.fromNum && this.toNum;
|
||||||
return this.compileSimple(o);
|
|
||||||
}
|
|
||||||
idx = del(o, 'index');
|
idx = del(o, 'index');
|
||||||
step = del(o, 'step');
|
varPart = "" + idx + " = " + this.from;
|
||||||
if (step) {
|
if (this.to !== this.toVar) {
|
||||||
stepvar = o.scope.freeVariable("step");
|
varPart += ", " + this.to;
|
||||||
}
|
}
|
||||||
varPart = ("" + idx + " = " + this.from) + (this.to !== this.toVar ? ", " + this.to : '') + (step ? ", " + stepvar + " = " + (step.compile(o)) : '');
|
if (this.step !== this.stepVar) {
|
||||||
cond = "" + this.fromVar + " <= " + this.toVar;
|
varPart += ", " + this.step;
|
||||||
condPart = "" + cond + " ? " + idx + " <" + this.equals + " " + this.toVar + " : " + idx + " >" + this.equals + " " + this.toVar;
|
|
||||||
stepPart = step ? "" + idx + " += " + stepvar : "" + cond + " ? " + idx + "++ : " + idx + "--";
|
|
||||||
return "" + varPart + "; " + condPart + "; " + stepPart;
|
|
||||||
};
|
|
||||||
Range.prototype.compileSimple = function(o) {
|
|
||||||
var condPart, from, idx, step, stepPart, stepvar, to, varPart, _ref2;
|
|
||||||
_ref2 = [+this.fromNum, +this.toNum], from = _ref2[0], to = _ref2[1];
|
|
||||||
idx = del(o, 'index');
|
|
||||||
step = del(o, 'step');
|
|
||||||
if (step) {
|
|
||||||
stepvar = o.scope.freeVariable("step");
|
|
||||||
}
|
|
||||||
varPart = "" + idx + " = " + from;
|
|
||||||
if (step) {
|
|
||||||
varPart += ", " + stepvar + " = " + (step.compile(o));
|
|
||||||
}
|
|
||||||
condPart = from <= to ? "" + idx + " <" + this.equals + " " + to : "" + idx + " >" + this.equals + " " + to;
|
|
||||||
if (step) {
|
|
||||||
stepPart = "" + idx + " += " + stepvar;
|
|
||||||
}
|
|
||||||
if (!step) {
|
|
||||||
stepPart = (from <= to ? "" + idx + "++" : "" + idx + "--");
|
|
||||||
}
|
}
|
||||||
|
condPart = this.stepNum ? condPart = +this.stepNum > 0 ? "" + idx + " <" + this.equals + " " + this.toVar : "" + idx + " >" + this.equals + " " + this.toVar : known ? ((_ref2 = [+this.fromNum, +this.toNum], from = _ref2[0], to = _ref2[1], _ref2), condPart = from <= to ? "" + idx + " <" + this.equals + " " + to : "" + idx + " >" + this.equals + " " + to) : (cond = "" + this.fromVar + " <= " + this.toVar, condPart = "" + cond + " ? " + idx + " <" + this.equals + " " + this.toVar + " : " + idx + " >" + this.equals + " " + this.toVar);
|
||||||
|
stepPart = this.stepVar ? "" + idx + " += " + this.stepVar : known ? from <= to ? "" + idx + "++" : "" + idx + "--" : "" + cond + " ? " + idx + "++ : " + idx + "--";
|
||||||
return "" + varPart + "; " + condPart + "; " + stepPart;
|
return "" + varPart + "; " + condPart + "; " + stepPart;
|
||||||
};
|
};
|
||||||
Range.prototype.compileArray = function(o) {
|
Range.prototype.compileArray = function(o) {
|
||||||
@@ -858,7 +837,7 @@
|
|||||||
pre = "\n" + idt + result + " = [];";
|
pre = "\n" + idt + result + " = [];";
|
||||||
if (this.fromNum && this.toNum) {
|
if (this.fromNum && this.toNum) {
|
||||||
o.index = i;
|
o.index = i;
|
||||||
body = this.compileSimple(o);
|
body = this.compileNode(o);
|
||||||
} else {
|
} else {
|
||||||
vars = ("" + i + " = " + this.from) + (this.to !== this.toVar ? ", " + this.to : '');
|
vars = ("" + i + " = " + this.from) + (this.to !== this.toVar ? ", " + this.to : '');
|
||||||
cond = "" + this.fromVar + " <= " + this.toVar;
|
cond = "" + this.fromVar + " <= " + this.toVar;
|
||||||
@@ -1628,6 +1607,10 @@
|
|||||||
Op.prototype.isUnary = function() {
|
Op.prototype.isUnary = function() {
|
||||||
return !this.second;
|
return !this.second;
|
||||||
};
|
};
|
||||||
|
Op.prototype.isComplex = function() {
|
||||||
|
var _ref2;
|
||||||
|
return !(this.isUnary() && ((_ref2 = this.operator) === '+' || _ref2 === '-')) || this.first.isComplex();
|
||||||
|
};
|
||||||
Op.prototype.isChainable = function() {
|
Op.prototype.isChainable = function() {
|
||||||
var _ref2;
|
var _ref2;
|
||||||
return (_ref2 = this.operator) === '<' || _ref2 === '>' || _ref2 === '>=' || _ref2 === '<=' || _ref2 === '===' || _ref2 === '!==';
|
return (_ref2 = this.operator) === '<' || _ref2 === '>' || _ref2 === '>=' || _ref2 === '<=' || _ref2 === '===' || _ref2 === '!==';
|
||||||
|
|||||||
@@ -632,41 +632,47 @@ exports.Range = class Range extends Base
|
|||||||
# Compiles the range's source variables -- where it starts and where it ends.
|
# Compiles the range's source variables -- where it starts and where it ends.
|
||||||
# But only if they need to be cached to avoid double evaluation.
|
# But only if they need to be cached to avoid double evaluation.
|
||||||
compileVariables: (o) ->
|
compileVariables: (o) ->
|
||||||
o = merge(o, top: true)
|
o = merge o, top: true
|
||||||
[@from, @fromVar] = @from.cache o, LEVEL_LIST
|
[@from, @fromVar] = @from.cache o, LEVEL_LIST
|
||||||
[@to, @toVar] = @to.cache o, LEVEL_LIST
|
[@to, @toVar] = @to.cache o, LEVEL_LIST
|
||||||
[@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)]
|
[@step, @stepVar] = step.cache o, LEVEL_LIST if step = del o, 'step'
|
||||||
parts = []
|
[@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)]
|
||||||
parts.push @from if @from isnt @fromVar
|
@stepNum = @stepVar.match(SIMPLENUM) if @stepVar
|
||||||
parts.push @to if @to isnt @toVar
|
|
||||||
|
|
||||||
# When compiled normally, the range returns the contents of the *for loop*
|
# When compiled normally, the range returns the contents of the *for loop*
|
||||||
# needed to iterate over the values in the range. Used by comprehensions.
|
# needed to iterate over the values in the range. Used by comprehensions.
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
@compileVariables o
|
@compileVariables o unless @fromVar
|
||||||
return @compileArray(o) unless o.index
|
return @compileArray(o) unless o.index
|
||||||
return @compileSimple(o) if @fromNum and @toNum
|
|
||||||
|
# Set up endpoints.
|
||||||
|
known = @fromNum and @toNum
|
||||||
idx = del o, 'index'
|
idx = del o, 'index'
|
||||||
step = del o, 'step'
|
varPart = "#{idx} = #{@from}"
|
||||||
stepvar = o.scope.freeVariable "step" if step
|
varPart += ", #{@to}" if @to isnt @toVar
|
||||||
varPart = "#{idx} = #{@from}" + ( if @to isnt @toVar then ", #{@to}" else '' ) + if step then ", #{stepvar} = #{step.compile(o)}" else ''
|
varPart += ", #{@step}" if @step isnt @stepVar
|
||||||
cond = "#{@fromVar} <= #{@toVar}"
|
|
||||||
condPart = "#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"
|
# Generate the condition.
|
||||||
stepPart = if step then "#{idx} += #{stepvar}" else "#{cond} ? #{idx}++ : #{idx}--"
|
condPart = if @stepNum
|
||||||
"#{varPart}; #{condPart}; #{stepPart}"
|
condPart = if +@stepNum > 0 then "#{idx} <#{@equals} #{@toVar}" else "#{idx} >#{@equals} #{@toVar}"
|
||||||
|
else if known
|
||||||
# Compile a simple range comprehension, with integers.
|
[from, to] = [+@fromNum, +@toNum]
|
||||||
compileSimple: (o) ->
|
condPart = if from <= to then "#{idx} <#{@equals} #{to}" else "#{idx} >#{@equals} #{to}"
|
||||||
[from, to] = [+@fromNum, +@toNum]
|
else
|
||||||
idx = del o, 'index'
|
cond = "#{@fromVar} <= #{@toVar}"
|
||||||
step = del o, 'step'
|
condPart = "#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"
|
||||||
stepvar = o.scope.freeVariable "step" if step
|
|
||||||
varPart = "#{idx} = #{from}"
|
# Generate the step.
|
||||||
varPart += ", #{stepvar} = #{step.compile(o)}" if step
|
stepPart = if @stepVar
|
||||||
condPart = if from <= to then "#{idx} <#{@equals} #{to}" else "#{idx} >#{@equals} #{to}"
|
"#{idx} += #{@stepVar}"
|
||||||
stepPart = "#{idx} += #{stepvar}" if step
|
else if known
|
||||||
stepPart = ( if from <= to then "#{idx}++" else "#{idx}--" ) if not step
|
if from <= to then "#{idx}++" else "#{idx}--"
|
||||||
|
else
|
||||||
|
"#{cond} ? #{idx}++ : #{idx}--"
|
||||||
|
|
||||||
|
# The final loop body.
|
||||||
"#{varPart}; #{condPart}; #{stepPart}"
|
"#{varPart}; #{condPart}; #{stepPart}"
|
||||||
|
|
||||||
|
|
||||||
# When used as a value, expand the range into the equivalent array.
|
# When used as a value, expand the range into the equivalent array.
|
||||||
compileArray: (o) ->
|
compileArray: (o) ->
|
||||||
@@ -680,7 +686,7 @@ exports.Range = class Range extends Base
|
|||||||
pre = "\n#{idt}#{result} = [];"
|
pre = "\n#{idt}#{result} = [];"
|
||||||
if @fromNum and @toNum
|
if @fromNum and @toNum
|
||||||
o.index = i
|
o.index = i
|
||||||
body = @compileSimple o
|
body = @compileNode o
|
||||||
else
|
else
|
||||||
vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
|
vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
|
||||||
cond = "#{@fromVar} <= #{@toVar}"
|
cond = "#{@fromVar} <= #{@toVar}"
|
||||||
@@ -1222,9 +1228,7 @@ exports.While = class While extends Base
|
|||||||
# Simple Arithmetic and logical operations. Performs some conversion from
|
# Simple Arithmetic and logical operations. Performs some conversion from
|
||||||
# CoffeeScript operations into their JavaScript equivalents.
|
# CoffeeScript operations into their JavaScript equivalents.
|
||||||
exports.Op = class Op extends Base
|
exports.Op = class Op extends Base
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
constructor: (op, first, second, flip, @isExistentialEquals ) ->
|
constructor: (op, first, second, flip, @isExistentialEquals ) ->
|
||||||
return new In first, second if op is 'in'
|
return new In first, second if op is 'in'
|
||||||
if op is 'do'
|
if op is 'do'
|
||||||
@@ -1257,6 +1261,9 @@ exports.Op = class Op extends Base
|
|||||||
|
|
||||||
isUnary: ->
|
isUnary: ->
|
||||||
not @second
|
not @second
|
||||||
|
|
||||||
|
isComplex: ->
|
||||||
|
not (@isUnary() and (@operator in ['+', '-'])) or @first.isComplex()
|
||||||
|
|
||||||
# Am I capable of
|
# Am I capable of
|
||||||
# [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)?
|
# [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)?
|
||||||
|
|||||||
Reference in New Issue
Block a user