diff --git a/lib/coffee-script/lexer.js b/lib/coffee-script/lexer.js index 5a078c83..fe5bd6f9 100644 --- a/lib/coffee-script/lexer.js +++ b/lib/coffee-script/lexer.js @@ -813,7 +813,7 @@ COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES); - RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf', 'implements', 'interface', 'package', 'private', 'protected', 'public', 'static']; + RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', 'implements', 'interface', 'package', 'private', 'protected', 'public', 'static']; STRICT_PROSCRIBED = ['arguments', 'eval', 'yield*']; diff --git a/lib/coffee-script/nodes.js b/lib/coffee-script/nodes.js index 36e59ea9..f9eeb9a4 100644 --- a/lib/coffee-script/nodes.js +++ b/lib/coffee-script/nodes.js @@ -1,8 +1,8 @@ // Generated by CoffeeScript 1.8.0 (function() { var Access, Arr, Assign, Base, Block, Call, Class, Code, CodeFragment, Comment, Existence, Expansion, Extends, For, HEXNUM, IDENTIFIER, IDENTIFIER_STR, IS_REGEX, 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, isLiteralArguments, isLiteralThis, last, locationDataToString, merge, multident, parseNum, some, starts, throwSyntaxError, unfoldSoak, utility, _ref, _ref1, - __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; }, + __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; }, __slice = [].slice; @@ -3145,9 +3145,13 @@ utility = function(name) { var ref; - ref = "__" + name; - Scope.root.assign(ref, UTILITIES[name]()); - return ref; + if (name in Scope.root.utilities) { + return Scope.root.utilities[name]; + } else { + ref = Scope.root.freeVariable("_" + name); + Scope.root.assign(ref, UTILITIES[name]()); + return Scope.root.utilities[name] = ref; + } }; multident = function(code, tab) { diff --git a/lib/coffee-script/scope.js b/lib/coffee-script/scope.js index 75fc7eb4..2ffb641d 100644 --- a/lib/coffee-script/scope.js +++ b/lib/coffee-script/scope.js @@ -21,6 +21,7 @@ ]; this.positions = {}; if (!this.parent) { + this.utilities = {}; Scope.root = this; } } diff --git a/src/lexer.coffee b/src/lexer.coffee index 5a462e47..058fbcf7 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -718,9 +718,8 @@ COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat COFFEE_ALIASES # to avoid having a JavaScript error at runtime. RESERVED = [ 'case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum' - 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind' - '__indexOf', 'implements', 'interface', 'package', 'private', 'protected' - 'public', 'static' + 'export', 'import', 'native', 'implements', 'interface', 'package', 'private' + 'protected', 'public', 'static' ] STRICT_PROSCRIBED = ['arguments', 'eval', 'yield*'] diff --git a/src/nodes.coffee b/src/nodes.coffee index 20ff9e90..d624b700 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -2260,9 +2260,12 @@ IS_REGEX = /^\// # Helper for ensuring that utility functions are assigned at the top level. utility = (name) -> - ref = "__#{name}" - Scope.root.assign ref, UTILITIES[name]() - ref + if name of Scope.root.utilities + Scope.root.utilities[name] + else + ref = Scope.root.freeVariable "_#{name}" + Scope.root.assign ref, UTILITIES[name]() + Scope.root.utilities[name] = ref multident = (code, tab) -> code = code.replace /\n/g, '$&' + tab diff --git a/src/scope.litcoffee b/src/scope.litcoffee index 132dc078..ab813ece 100644 --- a/src/scope.litcoffee +++ b/src/scope.litcoffee @@ -24,7 +24,9 @@ and therefore should be avoided when generating variables. constructor: (@parent, @expressions, @method, @referencedVars) -> @variables = [{name: 'arguments', type: 'arguments'}] @positions = {} - Scope.root = this unless @parent + unless @parent + @utilities = {} + Scope.root = this Adds a new variable or overrides an existing one. diff --git a/test/assignment.coffee b/test/assignment.coffee index 9753d3da..0ede9867 100644 --- a/test/assignment.coffee +++ b/test/assignment.coffee @@ -437,3 +437,23 @@ test "#1500: Assignment to variables similar to generated variables", -> eq 1, scope.a doesNotThrow -> CoffeeScript.compile '(@_slice...) ->' + +test "Assignment to variables similar to helper functions", -> + f = (__slice...) -> __slice + arrayEq [1, 2, 3], f 1, 2, 3 + eq 'undefined', typeof __slice1 + + class A + class B extends A + __extends = 3 + __hasProp = 4 + value: 5 + method: (__bind, __bind1) => [__bind, __bind1, __extends, __hasProp, @value] + {method} = new B + arrayEq [1, 2, 3, 4, 5], method 1, 2 + + __modulo = -1 %% 3 + eq 2, __modulo + + __indexOf = [1, 2, 3] + ok 2 in __indexOf