diff --git a/lib/coffee-script/nodes.js b/lib/coffee-script/nodes.js index 1de96e11..d69f8526 100644 --- a/lib/coffee-script/nodes.js +++ b/lib/coffee-script/nodes.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.6.3 (function() { - var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, CodeFragment, Comment, Existence, Extends, For, IDENTIFIER, IDENTIFIER_STR, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, METHOD_DEF, NEGATE, NO, Obj, Op, Param, Parens, RESERVED, Range, Return, SIMPLENUM, STRICT_PROSCRIBED, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, addLocationDataFn, compact, del, ends, extend, flatten, fragmentsToText, last, locationDataToString, merge, multident, some, starts, throwSyntaxError, unfoldSoak, utility, _ref, _ref1, _ref2, _ref3, + var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, CodeFragment, Comment, Existence, Extends, For, HEXNUM, IDENTIFIER, IDENTIFIER_STR, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, METHOD_DEF, NEGATE, NO, NUMBER, Obj, Op, Param, Parens, RESERVED, Range, Return, SIMPLENUM, STRICT_PROSCRIBED, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, addLocationDataFn, compact, del, ends, extend, flatten, fragmentsToText, last, locationDataToString, merge, multident, parseNum, some, starts, throwSyntaxError, unfoldSoak, utility, _ref, _ref1, _ref2, _ref3, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, @@ -1094,9 +1094,9 @@ if (step = del(o, 'step')) { _ref6 = this.cacheToCodeFragments(step.cache(o, LEVEL_LIST)), this.step = _ref6[0], this.stepVar = _ref6[1]; } - _ref7 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref7[0], this.toNum = _ref7[1]; + _ref7 = [this.fromVar.match(NUMBER), this.toVar.match(NUMBER)], this.fromNum = _ref7[0], this.toNum = _ref7[1]; if (this.stepVar) { - return this.stepNum = this.stepVar.match(SIMPLENUM); + return this.stepNum = this.stepVar.match(NUMBER); } }; @@ -1120,7 +1120,7 @@ varPart += ", " + this.step; } _ref4 = ["" + idx + " <" + this.equals, "" + idx + " >" + this.equals], lt = _ref4[0], gt = _ref4[1]; - condPart = this.stepNum ? +this.stepNum > 0 ? "" + lt + " " + this.toVar : "" + gt + " " + this.toVar : known ? ((_ref5 = [+this.fromNum, +this.toNum], from = _ref5[0], to = _ref5[1], _ref5), from <= to ? "" + lt + " " + to : "" + gt + " " + to) : (cond = this.stepVar ? "" + this.stepVar + " > 0" : "" + this.fromVar + " <= " + this.toVar, "" + cond + " ? " + lt + " " + this.toVar + " : " + gt + " " + this.toVar); + condPart = this.stepNum ? parseNum(this.stepNum[0]) > 0 ? "" + lt + " " + this.toVar : "" + gt + " " + this.toVar : known ? ((_ref5 = [parseNum(this.fromNum[0]), parseNum(this.toNum[0])], from = _ref5[0], to = _ref5[1], _ref5), from <= to ? "" + lt + " " + to : "" + gt + " " + to) : (cond = this.stepVar ? "" + this.stepVar + " > 0" : "" + this.fromVar + " <= " + this.toVar, "" + cond + " ? " + lt + " " + this.toVar + " : " + gt + " " + this.toVar); stepPart = this.stepVar ? "" + idx + " += " + this.stepVar : known ? namedIndex ? from <= to ? "++" + idx : "--" + idx : from <= to ? "" + idx + "++" : "" + idx + "--" : namedIndex ? "" + cond + " ? ++" + idx + " : --" + idx : "" + cond + " ? " + idx + "++ : " + idx + "--"; if (namedIndex) { varPart = "" + idxName + " = " + varPart; @@ -2620,7 +2620,7 @@ kvarAssign = kvar !== ivar ? "" + kvar + " = " : ""; if (this.step && !this.range) { _ref5 = this.cacheToCodeFragments(this.step.cache(o, LEVEL_LIST)), step = _ref5[0], stepVar = _ref5[1]; - stepNum = stepVar.match(SIMPLENUM); + stepNum = stepVar.match(NUMBER); } if (this.pattern) { name = ivar; @@ -2648,7 +2648,7 @@ if (step !== stepVar) { defPart += "" + this.tab + step + ";\n"; } - if (!(this.step && stepNum && (down = +stepNum < 0))) { + if (!(this.step && stepNum && (down = parseNum(stepNum[0]) < 0))) { lvar = scope.freeVariable('len'); } declare = "" + kvarAssign + ivar + " = 0, " + lvar + " = " + svar + ".length"; @@ -3033,6 +3033,10 @@ SIMPLENUM = /^[+-]?\d+$/; + HEXNUM = /^[+-]?0x[\da-f]+/i; + + NUMBER = /^[+-]?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)$/i; + METHOD_DEF = RegExp("^(?:(" + IDENTIFIER_STR + ")\\.prototype(?:\\.(" + IDENTIFIER_STR + ")|\\[(\"(?:[^\\\\\"\\r\\n]|\\\\.)*\"|'(?:[^\\\\'\\r\\n]|\\\\.)*')\\]|\\[(0x[\\da-fA-F]+|\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\]))|(" + IDENTIFIER_STR + ")$"); IS_STRING = /^['"]/; @@ -3049,4 +3053,14 @@ return code.replace(/\s+$/, ''); }; + parseNum = function(x) { + if (x == null) { + return 0; + } else if (x.match(HEXNUM)) { + return parseInt(x, 16); + } else { + return parseFloat(x); + } + }; + }).call(this); diff --git a/src/nodes.coffee b/src/nodes.coffee index 1fd748d0..4240ad86 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -769,8 +769,8 @@ exports.Range = class Range extends Base [@fromC, @fromVar] = @cacheToCodeFragments @from.cache o, LEVEL_LIST [@toC, @toVar] = @cacheToCodeFragments @to.cache o, LEVEL_LIST [@step, @stepVar] = @cacheToCodeFragments step.cache o, LEVEL_LIST if step = del o, 'step' - [@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)] - @stepNum = @stepVar.match(SIMPLENUM) if @stepVar + [@fromNum, @toNum] = [@fromVar.match(NUMBER), @toVar.match(NUMBER)] + @stepNum = @stepVar.match(NUMBER) 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. @@ -790,9 +790,9 @@ exports.Range = class Range extends Base # Generate the condition. condPart = if @stepNum - if +@stepNum > 0 then "#{lt} #{@toVar}" else "#{gt} #{@toVar}" + if parseNum(@stepNum[0]) > 0 then "#{lt} #{@toVar}" else "#{gt} #{@toVar}" else if known - [from, to] = [+@fromNum, +@toNum] + [from, to] = [parseNum(@fromNum[0]), parseNum(@toNum[0])] if from <= to then "#{lt} #{to}" else "#{gt} #{to}" else cond = if @stepVar then "#{@stepVar} > 0" else "#{@fromVar} <= #{@toVar}" @@ -1863,7 +1863,7 @@ exports.For = class For extends While kvarAssign = if kvar isnt ivar then "#{kvar} = " else "" if @step and not @range [step, stepVar] = @cacheToCodeFragments @step.cache o, LEVEL_LIST - stepNum = stepVar.match SIMPLENUM + stepNum = stepVar.match NUMBER name = ivar if @pattern varPart = '' guardPart = '' @@ -1880,7 +1880,7 @@ exports.For = class For extends While namePart = "#{name} = #{svar}[#{kvar}]" if not @object defPart += "#{@tab}#{step};\n" if step isnt stepVar - lvar = scope.freeVariable 'len' unless @step and stepNum and down = (+stepNum < 0) + lvar = scope.freeVariable 'len' unless @step and stepNum and down = (parseNum(stepNum[0]) < 0) declare = "#{kvarAssign}#{ivar} = 0, #{lvar} = #{svar}.length" declareDown = "#{kvarAssign}#{ivar} = #{svar}.length - 1" compare = "#{ivar} < #{lvar}" @@ -2148,6 +2148,12 @@ TAB = ' ' IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*" IDENTIFIER = /// ^ #{IDENTIFIER_STR} $ /// SIMPLENUM = /^[+-]?\d+$/ +HEXNUM = /^[+-]?0x[\da-f]+/i +NUMBER = ///^[+-]?(?: + 0x[\da-f]+ | # hex + \d*\.?\d+ (?:e[+-]?\d+)? # decimal +)$///i + METHOD_DEF = /// ^ (?: @@ -2179,3 +2185,13 @@ utility = (name) -> multident = (code, tab) -> code = code.replace /\n/g, '$&' + tab code.replace /\s+$/, '' + +# Parse a number (+- decimal/hexadecimal) +# Examples: 0, -1, 1, 2e3, 2e-3, -0xfe, 0xfe +parseNum = (x) -> + if not x? + 0 + else if x.match HEXNUM + parseInt x, 16 + else + parseFloat x