mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-14 01:07: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) {
|
||||
var src, tmp, _ref2;
|
||||
var src, tmp;
|
||||
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;
|
||||
}
|
||||
return [src, tmp];
|
||||
@@ -783,60 +783,39 @@
|
||||
this.equals = this.exclusive ? '' : '=';
|
||||
}
|
||||
Range.prototype.compileVariables = function(o) {
|
||||
var parts, _ref2, _ref3, _ref4;
|
||||
var step, _ref2, _ref3, _ref4, _ref5;
|
||||
o = merge(o, {
|
||||
top: true
|
||||
});
|
||||
_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];
|
||||
_ref4 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref4[0], this.toNum = _ref4[1];
|
||||
parts = [];
|
||||
if (this.from !== this.fromVar) {
|
||||
parts.push(this.from);
|
||||
if (step = del(o, 'step')) {
|
||||
_ref4 = step.cache(o, LEVEL_LIST), this.step = _ref4[0], this.stepVar = _ref4[1];
|
||||
}
|
||||
if (this.to !== this.toVar) {
|
||||
return parts.push(this.to);
|
||||
_ref5 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref5[0], this.toNum = _ref5[1];
|
||||
if (this.stepVar) {
|
||||
return this.stepNum = this.stepVar.match(SIMPLENUM);
|
||||
}
|
||||
};
|
||||
Range.prototype.compileNode = function(o) {
|
||||
var cond, condPart, idx, step, stepPart, stepvar, varPart;
|
||||
this.compileVariables(o);
|
||||
var cond, condPart, from, idx, known, stepPart, to, varPart, _ref2;
|
||||
if (!this.fromVar) {
|
||||
this.compileVariables(o);
|
||||
}
|
||||
if (!o.index) {
|
||||
return this.compileArray(o);
|
||||
}
|
||||
if (this.fromNum && this.toNum) {
|
||||
return this.compileSimple(o);
|
||||
}
|
||||
known = this.fromNum && this.toNum;
|
||||
idx = del(o, 'index');
|
||||
step = del(o, 'step');
|
||||
if (step) {
|
||||
stepvar = o.scope.freeVariable("step");
|
||||
varPart = "" + idx + " = " + this.from;
|
||||
if (this.to !== this.toVar) {
|
||||
varPart += ", " + this.to;
|
||||
}
|
||||
varPart = ("" + idx + " = " + this.from) + (this.to !== this.toVar ? ", " + this.to : '') + (step ? ", " + stepvar + " = " + (step.compile(o)) : '');
|
||||
cond = "" + this.fromVar + " <= " + this.toVar;
|
||||
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 + "--");
|
||||
if (this.step !== this.stepVar) {
|
||||
varPart += ", " + this.step;
|
||||
}
|
||||
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;
|
||||
};
|
||||
Range.prototype.compileArray = function(o) {
|
||||
@@ -858,7 +837,7 @@
|
||||
pre = "\n" + idt + result + " = [];";
|
||||
if (this.fromNum && this.toNum) {
|
||||
o.index = i;
|
||||
body = this.compileSimple(o);
|
||||
body = this.compileNode(o);
|
||||
} else {
|
||||
vars = ("" + i + " = " + this.from) + (this.to !== this.toVar ? ", " + this.to : '');
|
||||
cond = "" + this.fromVar + " <= " + this.toVar;
|
||||
@@ -1628,6 +1607,10 @@
|
||||
Op.prototype.isUnary = function() {
|
||||
return !this.second;
|
||||
};
|
||||
Op.prototype.isComplex = function() {
|
||||
var _ref2;
|
||||
return !(this.isUnary() && ((_ref2 = this.operator) === '+' || _ref2 === '-')) || this.first.isComplex();
|
||||
};
|
||||
Op.prototype.isChainable = function() {
|
||||
var _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.
|
||||
# But only if they need to be cached to avoid double evaluation.
|
||||
compileVariables: (o) ->
|
||||
o = merge(o, top: true)
|
||||
[@from, @fromVar] = @from.cache o, LEVEL_LIST
|
||||
[@to, @toVar] = @to.cache o, LEVEL_LIST
|
||||
[@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)]
|
||||
parts = []
|
||||
parts.push @from if @from isnt @fromVar
|
||||
parts.push @to if @to isnt @toVar
|
||||
o = merge o, top: true
|
||||
[@from, @fromVar] = @from.cache o, LEVEL_LIST
|
||||
[@to, @toVar] = @to.cache o, LEVEL_LIST
|
||||
[@step, @stepVar] = step.cache o, LEVEL_LIST if step = del o, 'step'
|
||||
[@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)]
|
||||
@stepNum = @stepVar.match(SIMPLENUM) if @stepVar
|
||||
|
||||
# When compiled normally, the range returns the contents of the *for loop*
|
||||
# needed to iterate over the values in the range. Used by comprehensions.
|
||||
compileNode: (o) ->
|
||||
@compileVariables o
|
||||
@compileVariables o unless @fromVar
|
||||
return @compileArray(o) unless o.index
|
||||
return @compileSimple(o) if @fromNum and @toNum
|
||||
|
||||
# Set up endpoints.
|
||||
known = @fromNum and @toNum
|
||||
idx = del o, 'index'
|
||||
step = del o, 'step'
|
||||
stepvar = o.scope.freeVariable "step" if step
|
||||
varPart = "#{idx} = #{@from}" + ( if @to isnt @toVar then ", #{@to}" else '' ) + if step then ", #{stepvar} = #{step.compile(o)}" else ''
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
condPart = "#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"
|
||||
stepPart = if step then "#{idx} += #{stepvar}" else "#{cond} ? #{idx}++ : #{idx}--"
|
||||
"#{varPart}; #{condPart}; #{stepPart}"
|
||||
|
||||
# Compile a simple range comprehension, with integers.
|
||||
compileSimple: (o) ->
|
||||
[from, to] = [+@fromNum, +@toNum]
|
||||
idx = del o, 'index'
|
||||
step = del o, 'step'
|
||||
stepvar = o.scope.freeVariable "step" if step
|
||||
varPart = "#{idx} = #{from}"
|
||||
varPart += ", #{stepvar} = #{step.compile(o)}" if step
|
||||
condPart = if from <= to then "#{idx} <#{@equals} #{to}" else "#{idx} >#{@equals} #{to}"
|
||||
stepPart = "#{idx} += #{stepvar}" if step
|
||||
stepPart = ( if from <= to then "#{idx}++" else "#{idx}--" ) if not step
|
||||
varPart = "#{idx} = #{@from}"
|
||||
varPart += ", #{@to}" if @to isnt @toVar
|
||||
varPart += ", #{@step}" if @step isnt @stepVar
|
||||
|
||||
# Generate the condition.
|
||||
condPart = if @stepNum
|
||||
condPart = if +@stepNum > 0 then "#{idx} <#{@equals} #{@toVar}" else "#{idx} >#{@equals} #{@toVar}"
|
||||
else if known
|
||||
[from, to] = [+@fromNum, +@toNum]
|
||||
condPart = if from <= to then "#{idx} <#{@equals} #{to}" else "#{idx} >#{@equals} #{to}"
|
||||
else
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
condPart = "#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"
|
||||
|
||||
# Generate the step.
|
||||
stepPart = if @stepVar
|
||||
"#{idx} += #{@stepVar}"
|
||||
else if known
|
||||
if from <= to then "#{idx}++" else "#{idx}--"
|
||||
else
|
||||
"#{cond} ? #{idx}++ : #{idx}--"
|
||||
|
||||
# The final loop body.
|
||||
"#{varPart}; #{condPart}; #{stepPart}"
|
||||
|
||||
|
||||
# When used as a value, expand the range into the equivalent array.
|
||||
compileArray: (o) ->
|
||||
@@ -680,7 +686,7 @@ exports.Range = class Range extends Base
|
||||
pre = "\n#{idt}#{result} = [];"
|
||||
if @fromNum and @toNum
|
||||
o.index = i
|
||||
body = @compileSimple o
|
||||
body = @compileNode o
|
||||
else
|
||||
vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
@@ -1222,9 +1228,7 @@ 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, @isExistentialEquals ) ->
|
||||
return new In first, second if op is 'in'
|
||||
if op is 'do'
|
||||
@@ -1257,6 +1261,9 @@ exports.Op = class Op extends Base
|
||||
|
||||
isUnary: ->
|
||||
not @second
|
||||
|
||||
isComplex: ->
|
||||
not (@isUnary() and (@operator in ['+', '-'])) or @first.isComplex()
|
||||
|
||||
# Am I capable of
|
||||
# [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)?
|
||||
|
||||
Reference in New Issue
Block a user