diff --git a/lib/coffee-script/helpers.js b/lib/coffee-script/helpers.js index d7c3161a..ac39d003 100644 --- a/lib/coffee-script/helpers.js +++ b/lib/coffee-script/helpers.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.9.0 (function() { - var buildLocationData, extend, flatten, last, ref, repeat, syntaxErrorToString; + var buildLocationData, extend, flatten, ref, repeat, syntaxErrorToString; exports.starts = function(string, literal, start) { return literal === string.substr(start, literal.length); @@ -83,10 +83,6 @@ return val; }; - exports.last = last = function(array, back) { - return array[array.length - (back || 0) - 1]; - }; - exports.some = (ref = Array.prototype.some) != null ? ref : function(fn) { var e, i, len1; for (i = 0, len1 = this.length; i < len1; i++) { diff --git a/lib/coffee-script/lexer.js b/lib/coffee-script/lexer.js index 386a0726..fa2d4215 100644 --- a/lib/coffee-script/lexer.js +++ b/lib/coffee-script/lexer.js @@ -1,11 +1,11 @@ // Generated by CoffeeScript 1.9.0 (function() { - var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, key, last, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError, + var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError, 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; }; ref = require('./rewriter'), Rewriter = ref.Rewriter, INVERSES = ref.INVERSES; - ref1 = require('./helpers'), count = ref1.count, starts = ref1.starts, compact = ref1.compact, last = ref1.last, repeat = ref1.repeat, invertLiterate = ref1.invertLiterate, locationDataToString = ref1.locationDataToString, throwSyntaxError = ref1.throwSyntaxError; + ref1 = require('./helpers'), count = ref1.count, starts = ref1.starts, compact = ref1.compact, repeat = ref1.repeat, invertLiterate = ref1.invertLiterate, locationDataToString = ref1.locationDataToString, throwSyntaxError = ref1.throwSyntaxError; exports.Lexer = Lexer = (function() { function Lexer() {} @@ -64,7 +64,7 @@ }; Lexer.prototype.identifierToken = function() { - var colon, colonOffset, forcedIdentifier, id, idLength, input, match, poppedToken, prev, ref2, ref3, ref4, tag, tagToken; + var colon, colonOffset, forcedIdentifier, id, idLength, input, match, poppedToken, prev, ref2, ref3, ref4, ref5, tag, tagToken; if (!(match = IDENTIFIER.exec(this.chunk))) { return 0; } @@ -79,11 +79,12 @@ this.token('FROM', id); return id.length; } - forcedIdentifier = colon || (prev = last(this.tokens)) && (((ref2 = prev[0]) === '.' || ref2 === '?.' || ref2 === '::' || ref2 === '?::') || !prev.spaced && prev[0] === '@'); + ref2 = this.tokens, prev = ref2[ref2.length - 1]; + forcedIdentifier = colon || (prev != null) && (((ref3 = prev[0]) === '.' || ref3 === '?.' || ref3 === '::' || ref3 === '?::') || !prev.spaced && prev[0] === '@'); tag = 'IDENTIFIER'; if (!forcedIdentifier && (indexOf.call(JS_KEYWORDS, id) >= 0 || indexOf.call(COFFEE_KEYWORDS, id) >= 0)) { tag = id.toUpperCase(); - if (tag === 'WHEN' && (ref3 = this.tag(), indexOf.call(LINE_BREAK, ref3) >= 0)) { + if (tag === 'WHEN' && (ref4 = this.tag(), indexOf.call(LINE_BREAK, ref4) >= 0)) { tag = 'LEADING_WHEN'; } else if (tag === 'FOR') { this.seenFor = true; @@ -143,7 +144,7 @@ tagToken = this.token(tag, id, 0, idLength); tagToken.variable = !forcedIdentifier; if (poppedToken) { - ref4 = [poppedToken[2].first_line, poppedToken[2].first_column], tagToken[2].first_line = ref4[0], tagToken[2].first_column = ref4[1]; + ref5 = [poppedToken[2].first_line, poppedToken[2].first_column], tagToken[2].first_line = ref5[0], tagToken[2].first_column = ref5[1]; } if (colon) { colonOffset = input.lastIndexOf(':'); @@ -296,7 +297,7 @@ }; Lexer.prototype.regexToken = function() { - var body, closed, end, errorToken, flags, index, match, prev, ref2, ref3, regex, rparen, tokens; + var body, closed, end, errorToken, flags, index, match, prev, ref2, ref3, ref4, regex, rparen, tokens; switch (false) { case !(match = REGEX_ILLEGAL.exec(this.chunk)): this.error("regular expressions cannot begin with " + match[2], { @@ -312,13 +313,13 @@ isRegex: true }); index = regex.length; - prev = last(this.tokens); + ref2 = this.tokens, prev = ref2[ref2.length - 1]; if (prev) { - if (prev.spaced && (ref2 = prev[0], indexOf.call(CALLABLE, ref2) >= 0) && !prev.stringEnd && !prev.regexEnd) { + if (prev.spaced && (ref3 = prev[0], indexOf.call(CALLABLE, ref3) >= 0) && !prev.stringEnd && !prev.regexEnd) { if (!closed || POSSIBLY_DIVISION.test(regex)) { return 0; } - } else if (ref3 = prev[0], indexOf.call(NOT_REGEX, ref3) >= 0) { + } else if (ref4 = prev[0], indexOf.call(NOT_REGEX, ref4) >= 0) { return 0; } } @@ -449,11 +450,11 @@ }; Lexer.prototype.whitespaceToken = function() { - var match, nline, prev; + var match, nline, prev, ref2; if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) { return 0; } - prev = last(this.tokens); + ref2 = this.tokens, prev = ref2[ref2.length - 1]; if (prev) { prev[match ? 'spaced' : 'newLine'] = true; } @@ -482,7 +483,7 @@ }; Lexer.prototype.literalToken = function() { - var match, prev, ref2, ref3, ref4, ref5, tag, token, value; + var match, prev, ref2, ref3, ref4, ref5, ref6, tag, token, value; if (match = OPERATOR.exec(this.chunk)) { value = match[0]; if (CODE.test(value)) { @@ -492,12 +493,12 @@ value = this.chunk.charAt(0); } tag = value; - prev = last(this.tokens); + ref2 = this.tokens, prev = ref2[ref2.length - 1]; if (value === '=' && prev) { - if (!prev[1].reserved && (ref2 = prev[1], indexOf.call(JS_FORBIDDEN, ref2) >= 0)) { + if (!prev[1].reserved && (ref3 = prev[1], indexOf.call(JS_FORBIDDEN, ref3) >= 0)) { this.error("reserved word '" + prev[1] + "' can't be assigned", prev[2]); } - if ((ref3 = prev[1]) === '||' || ref3 === '&&') { + if ((ref4 = prev[1]) === '||' || ref4 === '&&') { prev[0] = 'COMPOUND_ASSIGN'; prev[1] += '='; return value.length; @@ -521,12 +522,12 @@ } else if (indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) { tag = 'LOGIC'; } else if (prev && !prev.spaced) { - if (value === '(' && (ref4 = prev[0], indexOf.call(CALLABLE, ref4) >= 0) && !prev.stringEnd && !prev.regexEnd) { + if (value === '(' && (ref5 = prev[0], indexOf.call(CALLABLE, ref5) >= 0) && !prev.stringEnd && !prev.regexEnd) { if (prev[0] === '?') { prev[0] = 'FUNC_EXIST'; } tag = 'CALL_START'; - } else if (value === '[' && (ref5 = prev[0], indexOf.call(INDEXABLE, ref5) >= 0)) { + } else if (value === '[' && (ref6 = prev[0], indexOf.call(INDEXABLE, ref6) >= 0)) { tag = 'INDEX_START'; switch (prev[0]) { case '?': @@ -706,19 +707,21 @@ }; Lexer.prototype.pair = function(tag) { - var ref2, wanted; - if (tag !== (wanted = (ref2 = last(this.ends)) != null ? ref2.tag : void 0)) { + var lastIndent, prev, ref2, ref3, wanted; + ref2 = this.ends, prev = ref2[ref2.length - 1]; + if (tag !== (wanted = prev != null ? prev.tag : void 0)) { if ('OUTDENT' !== wanted) { this.error("unmatched " + tag); } - this.outdentToken(last(this.indents), true); + ref3 = this.indents, lastIndent = ref3[ref3.length - 1]; + this.outdentToken(lastIndent, true); return this.pair(tag); } return this.ends.pop(); }; Lexer.prototype.getLineAndColumnFromChunk = function(offset) { - var column, lineCount, lines, string; + var column, lastLine, lineCount, ref2, string; if (offset === 0) { return [this.chunkLine, this.chunkColumn]; } @@ -730,8 +733,8 @@ lineCount = count(string, '\n'); column = this.chunkColumn; if (lineCount > 0) { - lines = string.split('\n'); - column = last(lines).length; + ref2 = string.split('\n'), lastLine = ref2[ref2.length - 1]; + column = lastLine.length; } else { column += string.length; } @@ -764,14 +767,16 @@ return token; }; - Lexer.prototype.tag = function(index, tag) { - var tok; - return (tok = last(this.tokens, index)) && (tag ? tok[0] = tag : tok[0]); + Lexer.prototype.tag = function() { + var ref2, token; + ref2 = this.tokens, token = ref2[ref2.length - 1]; + return token != null ? token[0] : void 0; }; - Lexer.prototype.value = function(index, val) { - var tok; - return (tok = last(this.tokens, index)) && (val ? tok[1] = val : tok[1]); + Lexer.prototype.value = function() { + var ref2, token; + ref2 = this.tokens, token = ref2[ref2.length - 1]; + return token != null ? token[1] : void 0; }; Lexer.prototype.unfinished = function() { diff --git a/lib/coffee-script/nodes.js b/lib/coffee-script/nodes.js index ecd0adb9..dfec6b78 100644 --- a/lib/coffee-script/nodes.js +++ b/lib/coffee-script/nodes.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.9.0 (function() { - var Access, Arr, Assign, Base, Block, Call, Class, Code, CodeFragment, Comment, Existence, Expansion, Extends, For, HEXNUM, IDENTIFIER, IS_REGEX, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, 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, isComplexOrAssignable, isLiteralArguments, isLiteralThis, last, locationDataToString, merge, multident, parseNum, ref1, ref2, some, starts, throwSyntaxError, unfoldSoak, utility, + var Access, Arr, Assign, Base, Block, Call, Class, Code, CodeFragment, Comment, Existence, Expansion, Extends, For, HEXNUM, IDENTIFIER, IS_REGEX, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, 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, isComplexOrAssignable, isLiteralArguments, isLiteralThis, locationDataToString, merge, multident, parseNum, ref1, ref2, some, starts, throwSyntaxError, unfoldSoak, utility, extend1 = 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; }, hasProp = {}.hasOwnProperty, 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; }, @@ -12,7 +12,7 @@ ref1 = require('./lexer'), RESERVED = ref1.RESERVED, STRICT_PROSCRIBED = ref1.STRICT_PROSCRIBED; - ref2 = require('./helpers'), compact = ref2.compact, flatten = ref2.flatten, extend = ref2.extend, merge = ref2.merge, del = ref2.del, starts = ref2.starts, ends = ref2.ends, last = ref2.last, some = ref2.some, addLocationDataFn = ref2.addLocationDataFn, locationDataToString = ref2.locationDataToString, throwSyntaxError = ref2.throwSyntaxError; + ref2 = require('./helpers'), compact = ref2.compact, flatten = ref2.flatten, extend = ref2.extend, merge = ref2.merge, del = ref2.del, starts = ref2.starts, ends = ref2.ends, some = ref2.some, addLocationDataFn = ref2.addLocationDataFn, locationDataToString = ref2.locationDataToString, throwSyntaxError = ref2.throwSyntaxError; exports.extend = extend; @@ -760,7 +760,9 @@ }; Value.prototype.isSplice = function() { - return last(this.properties) instanceof Slice; + var lastProp, ref3; + ref3 = this.properties, lastProp = ref3[ref3.length - 1]; + return lastProp instanceof Slice; }; Value.prototype.looksStatic = function(className) { @@ -777,8 +779,8 @@ }; Value.prototype.cacheReference = function(o) { - var base, bref, name, nref; - name = last(this.properties); + var base, bref, name, nref, ref3; + ref3 = this.properties, name = ref3[ref3.length - 1]; if (this.properties.length < 2 && !this.base.isComplex() && !(name != null ? name.isComplex() : void 0)) { return [this, this]; } @@ -1407,11 +1409,12 @@ Class.prototype.children = ['variable', 'parent', 'body']; Class.prototype.determineName = function() { - var decl, tail; + var decl, ref3, tail; if (!this.variable) { return null; } - decl = (tail = last(this.variable.properties)) ? tail instanceof Access && tail.name.value : this.variable.base.value; + ref3 = this.variable.properties, tail = ref3[ref3.length - 1]; + decl = tail ? tail instanceof Access && tail.name.value : this.variable.base.value; if (indexOf.call(STRICT_PROSCRIBED, decl) >= 0) { this.variable.error("class variable name may not be " + decl); } @@ -2127,7 +2130,7 @@ }; Splat.compileSplattedArray = function(o, list, apply) { - var args, base, compiledNode, concatPart, fragments, i, index, j, len1, node; + var args, base, compiledNode, concatPart, fragments, i, index, j, last, len1, node; index = -1; while ((node = list[++index]) && !(node instanceof Splat)) { continue; @@ -2166,7 +2169,8 @@ })(); base = list[0].joinFragmentArrays(base, ', '); concatPart = list[index].joinFragmentArrays(args, ', '); - return [].concat(list[0].makeCode("["), base, list[index].makeCode("].concat("), concatPart, (last(list)).makeCode(")")); + last = list[list.length - 1]; + return [].concat(list[0].makeCode("["), base, list[index].makeCode("].concat("), concatPart, last.makeCode(")")); }; return Splat; @@ -2767,10 +2771,10 @@ For.prototype.children = ['body', 'source', 'guard', 'step']; For.prototype.compileNode = function(o) { - var body, bodyFragments, compare, compareDown, declare, declareDown, defPart, defPartFragments, down, forPartFragments, guardPart, idt1, increment, index, ivar, kvar, kvarAssign, lastJumps, lvar, name, namePart, ref, ref3, ref4, resultPart, returnResult, rvar, scope, source, step, stepNum, stepVar, svar, varPart; + var body, bodyFragments, compare, compareDown, declare, declareDown, defPart, defPartFragments, down, forPartFragments, guardPart, idt1, increment, index, ivar, kvar, kvarAssign, last, lvar, name, namePart, ref, ref3, ref4, resultPart, returnResult, rvar, scope, source, step, stepNum, stepVar, svar, varPart; body = Block.wrap([this.body]); - lastJumps = (ref3 = last(body.expressions)) != null ? ref3.jumps() : void 0; - if (lastJumps && lastJumps instanceof Return) { + ref3 = body.expressions, last = ref3[ref3.length - 1]; + if ((last != null ? last.jumps() : void 0) instanceof Return) { this.returns = false; } source = this.range ? this.source.base : this.source; diff --git a/lib/coffee-script/scope.js b/lib/coffee-script/scope.js index 5cdeaf2b..6f6c6e5b 100644 --- a/lib/coffee-script/scope.js +++ b/lib/coffee-script/scope.js @@ -1,13 +1,11 @@ // Generated by CoffeeScript 1.9.0 (function() { - var Scope, extend, last, ref, + var Scope, 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; }; - ref = require('./helpers'), extend = ref.extend, last = ref.last; - exports.Scope = Scope = (function() { function Scope(parent, expressions, method, referencedVars) { - var ref1, ref2; + var ref, ref1; this.parent = parent; this.expressions = expressions; this.method = method; @@ -22,7 +20,7 @@ if (!this.parent) { this.utilities = {}; } - this.root = (ref1 = (ref2 = this.parent) != null ? ref2.root : void 0) != null ? ref1 : this; + this.root = (ref = (ref1 = this.parent) != null ? ref1.root : void 0) != null ? ref : this; } Scope.prototype.add = function(name, type, immediate) { @@ -40,8 +38,8 @@ }; Scope.prototype.namedMethod = function() { - var ref1; - if (((ref1 = this.method) != null ? ref1.name : void 0) || !this.parent) { + var ref; + if (((ref = this.method) != null ? ref.name : void 0) || !this.parent) { return this.method; } return this.parent.namedMethod(); @@ -63,8 +61,8 @@ }; Scope.prototype.check = function(name) { - var ref1; - return !!(this.type(name) || ((ref1 = this.parent) != null ? ref1.check(name) : void 0)); + var ref; + return !!(this.type(name) || ((ref = this.parent) != null ? ref.check(name) : void 0)); }; Scope.prototype.temporary = function(name, index, single) { @@ -79,10 +77,10 @@ }; Scope.prototype.type = function(name) { - var i, len, ref1, v; - ref1 = this.variables; - for (i = 0, len = ref1.length; i < len; i++) { - v = ref1[i]; + var i, len, ref, v; + ref = this.variables; + for (i = 0, len = ref.length; i < len; i++) { + v = ref[i]; if (v.name === name) { return v.type; } @@ -91,7 +89,7 @@ }; Scope.prototype.freeVariable = function(name, options) { - var index, ref1, temp; + var index, ref, temp; if (options == null) { options = {}; } @@ -103,7 +101,7 @@ } index++; } - if ((ref1 = options.reserve) != null ? ref1 : true) { + if ((ref = options.reserve) != null ? ref : true) { this.add(temp, 'var', true); } return temp; @@ -124,11 +122,11 @@ Scope.prototype.declaredVariables = function() { var v; return ((function() { - var i, len, ref1, results; - ref1 = this.variables; + var i, len, ref, results; + ref = this.variables; results = []; - for (i = 0, len = ref1.length; i < len; i++) { - v = ref1[i]; + for (i = 0, len = ref.length; i < len; i++) { + v = ref[i]; if (v.type === 'var') { results.push(v.name); } @@ -138,11 +136,11 @@ }; Scope.prototype.assignedVariables = function() { - var i, len, ref1, results, v; - ref1 = this.variables; + var i, len, ref, results, v; + ref = this.variables; results = []; - for (i = 0, len = ref1.length; i < len; i++) { - v = ref1[i]; + for (i = 0, len = ref.length; i < len; i++) { + v = ref[i]; if (v.type.assigned) { results.push(v.name + " = " + v.type.value); } diff --git a/src/helpers.coffee b/src/helpers.coffee index 4ab4f954..53f1bde2 100644 --- a/src/helpers.coffee +++ b/src/helpers.coffee @@ -62,9 +62,6 @@ exports.del = (obj, key) -> delete obj[key] val -# Gets the last item of an array(-like) object. -exports.last = last = (array, back) -> array[array.length - (back or 0) - 1] - # Typical Array::some exports.some = Array::some ? (fn) -> return true for e in this when fn e diff --git a/src/lexer.coffee b/src/lexer.coffee index ec273136..1f00ccd1 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -12,7 +12,7 @@ {Rewriter, INVERSES} = require './rewriter' # Import the helpers we need. -{count, starts, compact, last, repeat, invertLiterate, +{count, starts, compact, repeat, invertLiterate, locationDataToString, throwSyntaxError} = require './helpers' # The Lexer Class @@ -112,8 +112,9 @@ exports.Lexer = class Lexer if id is 'from' and @tag() is 'YIELD' @token 'FROM', id return id.length - forcedIdentifier = colon or - (prev = last @tokens) and (prev[0] in ['.', '?.', '::', '?::'] or + [..., prev] = @tokens + forcedIdentifier = colon or prev? and + (prev[0] in ['.', '?.', '::', '?::'] or not prev.spaced and prev[0] is '@') tag = 'IDENTIFIER' @@ -264,7 +265,7 @@ exports.Lexer = class Lexer [regex, body, closed] = match @validateEscapes regex, isRegex: yes index = regex.length - prev = last @tokens + [..., prev] = @tokens if prev if prev.spaced and prev[0] in CALLABLE and not prev.stringEnd and not prev.regexEnd return 0 if not closed or POSSIBLY_DIVISION.test regex @@ -372,7 +373,7 @@ exports.Lexer = class Lexer whitespaceToken: -> return 0 unless (match = WHITESPACE.exec @chunk) or (nline = @chunk.charAt(0) is '\n') - prev = last @tokens + [..., prev] = @tokens prev[if match then 'spaced' else 'newLine'] = true if prev if match then match[0].length else 0 @@ -400,7 +401,7 @@ exports.Lexer = class Lexer else value = @chunk.charAt 0 tag = value - prev = last @tokens + [..., prev] = @tokens if value is '=' and prev if not prev[1].reserved and prev[1] in JS_FORBIDDEN @error "reserved word '#{prev[1]}' can't be assigned", prev[2] @@ -596,14 +597,16 @@ exports.Lexer = class Lexer # Pairs up a closing token, ensuring that all listed pairs of tokens are # correctly balanced throughout the course of the token stream. pair: (tag) -> - unless tag is wanted = last(@ends)?.tag + [..., prev] = @ends + unless tag is wanted = prev?.tag @error "unmatched #{tag}" unless 'OUTDENT' is wanted # Auto-close INDENT to support syntax like this: # # el.click((event) -> # el.hide()) # - @outdentToken last(@indents), true + [..., lastIndent] = @indents + @outdentToken lastIndent, true return @pair tag @ends.pop() @@ -626,8 +629,8 @@ exports.Lexer = class Lexer column = @chunkColumn if lineCount > 0 - lines = string.split '\n' - column = last(lines).length + [..., lastLine] = string.split '\n' + column = lastLine.length else column += string.length @@ -662,13 +665,15 @@ exports.Lexer = class Lexer @tokens.push token token - # Peek at a tag in the current token stream. - tag: (index, tag) -> - (tok = last @tokens, index) and if tag then tok[0] = tag else tok[0] + # Peek at the last tag in the token stream. + tag: -> + [..., token] = @tokens + token?[0] - # Peek at a value in the current token stream. - value: (index, val) -> - (tok = last @tokens, index) and if val then tok[1] = val else tok[1] + # Peek at the last value in the token stream. + value: -> + [..., token] = @tokens + token?[1] # Are we in the midst of an unfinished expression? unfinished: -> diff --git a/src/nodes.coffee b/src/nodes.coffee index 7a6dcd81..a063cad2 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -9,7 +9,7 @@ Error.stackTraceLimit = Infinity {RESERVED, STRICT_PROSCRIBED} = require './lexer' # Import the helpers we plan to use. -{compact, flatten, extend, merge, del, starts, ends, last, some, +{compact, flatten, extend, merge, del, starts, ends, some, addLocationDataFn, locationDataToString, throwSyntaxError} = require './helpers' # Functions required by parser @@ -510,7 +510,8 @@ exports.Value = class Value extends Base (@base instanceof Obj) and (not onlyGenerated or @base.generated) isSplice: -> - last(@properties) instanceof Slice + [..., lastProp] = @properties + lastProp instanceof Slice looksStatic: (className) -> @base.value is className and @properties.length is 1 and @@ -525,7 +526,7 @@ exports.Value = class Value extends Base # We cache them separately for compiling complex expressions. # `a()[b()] ?= c` -> `(_base = a())[_name = b()] ? _base[_name] = c` cacheReference: (o) -> - name = last @properties + [..., name] = @properties if @properties.length < 2 and not @base.isComplex() and not name?.isComplex() return [this, this] # `a` `a.b` base = new Value @base, @properties[...-1] @@ -1006,7 +1007,8 @@ exports.Class = class Class extends Base # Figure out the appropriate name for the constructor function of this class. determineName: -> return null unless @variable - decl = if tail = last @variable.properties + [..., tail] = @variable.properties + decl = if tail tail instanceof Access and tail.name.value else @variable.base.value @@ -1540,7 +1542,8 @@ exports.Splat = class Splat extends Base base = (node.compileToFragments o, LEVEL_LIST for node in list[...index]) base = list[0].joinFragmentArrays base, ', ' concatPart = list[index].joinFragmentArrays args, ', ' - [].concat list[0].makeCode("["), base, list[index].makeCode("].concat("), concatPart, (last list).makeCode(")") + [..., last] = list + [].concat list[0].makeCode("["), base, list[index].makeCode("].concat("), concatPart, last.makeCode(")") #### Expansion @@ -1976,27 +1979,27 @@ exports.For = class For extends While # comprehensions. Some of the generated code can be shared in common, and # some cannot. compileNode: (o) -> - body = Block.wrap [@body] - lastJumps = last(body.expressions)?.jumps() - @returns = no if lastJumps and lastJumps instanceof Return - source = if @range then @source.base else @source - scope = o.scope - name = @name and (@name.compile o, LEVEL_LIST) if not @pattern - index = @index and (@index.compile o, LEVEL_LIST) + body = Block.wrap [@body] + [..., last] = body.expressions + @returns = no if last?.jumps() instanceof Return + source = if @range then @source.base else @source + scope = o.scope + name = @name and (@name.compile o, LEVEL_LIST) if not @pattern + index = @index and (@index.compile o, LEVEL_LIST) scope.find(name) if name and not @pattern scope.find(index) if index - rvar = scope.freeVariable 'results' if @returns - ivar = (@object and index) or scope.freeVariable 'i', single: true - kvar = (@range and name) or index or ivar - kvarAssign = if kvar isnt ivar then "#{kvar} = " else "" + rvar = scope.freeVariable 'results' if @returns + ivar = (@object and index) or scope.freeVariable 'i', single: true + kvar = (@range and name) or index or ivar + kvarAssign = if kvar isnt ivar then "#{kvar} = " else "" if @step and not @range [step, stepVar] = @cacheToCodeFragments @step.cache o, LEVEL_LIST, isComplexOrAssignable stepNum = stepVar.match NUMBER - name = ivar if @pattern - varPart = '' - guardPart = '' - defPart = '' - idt1 = @tab + TAB + name = ivar if @pattern + varPart = '' + guardPart = '' + defPart = '' + idt1 = @tab + TAB if @range forPartFragments = source.compileToFragments merge o, {index: ivar, name, @step, isComplex: isComplexOrAssignable} diff --git a/src/scope.litcoffee b/src/scope.litcoffee index dbdf26d0..e983a782 100644 --- a/src/scope.litcoffee +++ b/src/scope.litcoffee @@ -5,10 +5,6 @@ and has a reference to its parent enclosing scope. In this way, we know which variables are new and need to be declared with `var`, and which are shared with external scopes. -Import the helpers we plan to use. - - {extend, last} = require './helpers' - exports.Scope = class Scope Initialize a scope with its parent, for lookups up the chain, diff --git a/test/helpers.coffee b/test/helpers.coffee index 103049be..31c969f9 100644 --- a/test/helpers.coffee +++ b/test/helpers.coffee @@ -2,7 +2,7 @@ # ------- # pull the helpers from `CoffeeScript.helpers` into local variables -{starts, ends, repeat, compact, count, merge, extend, flatten, del, last, baseFileName} = CoffeeScript.helpers +{starts, ends, repeat, compact, count, merge, extend, flatten, del, baseFileName} = CoffeeScript.helpers # `starts` @@ -94,16 +94,6 @@ test "the `del` helper deletes a property from an object and returns the deleted ok 1 not of obj -# `last` - -test "the `last` helper returns the last item of an array-like object", -> - ary = [0, 1, 2, 3, 4] - eq 4, last(ary) - -test "the `last` helper allows one to specify an optional offset", -> - ary = [0, 1, 2, 3, 4] - eq 2, last(ary, 2) - # `baseFileName` test "the `baseFileName` helper returns the file name to write to", ->