1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

[CS2] Remove unnecessary utility helper functions (#4526)

* Uncomment module test that was waiting for classes to be supported

* Rely on native indexOf

* Replace `bind` helper with native `bind` (no shortcut necessary)

* Update output

* Update modules class tests

* Remove helper for prototype extends

* Update docs to reflect removed extends operator

* Add shortcut for splice, like we have for slice
This commit is contained in:
Geoffrey Booth 2017-04-25 07:10:42 -07:00 committed by GitHub
parent 7e35c2c3da
commit 07ae1edb44
12 changed files with 70 additions and 96 deletions

View file

@ -1,6 +1,6 @@
## Prototypal Inheritance ## Prototypal Inheritance
In addition to supporting ES2015 classes, CoffeeScript provides a few shortcuts for working with prototypes. The `extends` operator can be used to create an inheritance chain between any pair of constructor functions, and `::` gives you quick access to an objects prototype: In addition to supporting ES2015 classes, CoffeeScript provides a shortcut for working with prototypes. The `::` operator gives you quick access to an objects prototype:
``` ```
codeFor('prototypes', '"one_two".dasherize()') codeFor('prototypes', '"one_two".dasherize()')

View file

@ -1,7 +1,7 @@
// Generated by CoffeeScript 2.0.0-beta1 // Generated by CoffeeScript 2.0.0-beta1
(function() { (function() {
var CoffeeScript, compile, runScripts, var CoffeeScript, compile, runScripts,
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; }; indexOf = [].indexOf;
CoffeeScript = require('./coffeescript'); CoffeeScript = require('./coffeescript');

View file

@ -1,7 +1,7 @@
// Generated by CoffeeScript 2.0.0-beta1 // Generated by CoffeeScript 2.0.0-beta1
(function() { (function() {
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, findDirectoryIndex, forkNode, fs, helpers, hidden, joinTimeout, makePrelude, mkdirp, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, removeSourceDir, silentUnlink, sourceCode, sources, spawn, timeLog, usage, useWinPathSep, version, wait, watch, watchDir, watchedDirs, writeJs, var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, findDirectoryIndex, forkNode, fs, helpers, hidden, joinTimeout, makePrelude, mkdirp, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, removeSourceDir, silentUnlink, sourceCode, sources, spawn, timeLog, usage, useWinPathSep, version, wait, watch, watchDir, watchedDirs, writeJs,
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; }; indexOf = [].indexOf;
fs = require('fs'); fs = require('fs');

View file

@ -783,8 +783,6 @@
return new Assign($1, $4, $2); return new Assign($1, $4, $2);
}), o('SimpleAssignable COMPOUND_ASSIGN TERMINATOR Expression', function() { }), o('SimpleAssignable COMPOUND_ASSIGN TERMINATOR Expression', function() {
return new Assign($1, $4, $2); return new Assign($1, $4, $2);
}), o('SimpleAssignable EXTENDS Expression', function() {
return new Extends($1, $3);
}) })
] ]
}; };

View file

@ -1,7 +1,7 @@
// Generated by CoffeeScript 2.0.0-beta1 // Generated by CoffeeScript 2.0.0-beta1
(function() { (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, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, REGEX_INVALID_ESCAPE, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_INVALID_ESCAPE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, UNICODE_CODE_POINT_ESCAPE, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, 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, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, REGEX_INVALID_ESCAPE, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_INVALID_ESCAPE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, UNICODE_CODE_POINT_ESCAPE, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, 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; }; indexOf = [].indexOf;
({Rewriter, INVERSES} = require('./rewriter')); ({Rewriter, INVERSES} = require('./rewriter'));

View file

@ -1,7 +1,8 @@
// Generated by CoffeeScript 2.0.0-beta1 // Generated by CoffeeScript 2.0.0-beta1
(function() { (function() {
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, Call, Class, Code, CodeFragment, Comment, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, TAB, THIS, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addLocationDataFn, compact, del, ends, extend, flatten, fragmentsToText, isLiteralArguments, isLiteralThis, isUnassignable, locationDataToString, merge, multident, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, utility, var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, Call, Class, Code, CodeFragment, Comment, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, TAB, THIS, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addLocationDataFn, compact, del, ends, extend, flatten, fragmentsToText, isLiteralArguments, isLiteralThis, isUnassignable, locationDataToString, merge, multident, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, utility,
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; }, splice = [].splice,
indexOf = [].indexOf,
slice = [].slice; slice = [].slice;
Error.stackTraceLimit = 2e308; Error.stackTraceLimit = 2e308;
@ -241,7 +242,7 @@
for (i = k = 0, len2 = children.length; k < len2; i = ++k) { for (i = k = 0, len2 = children.length; k < len2; i = ++k) {
child = children[i]; child = children[i];
if (match(child)) { if (match(child)) {
[].splice.apply(children, [i, i - i + 1].concat(ref2 = replacement(child, this))), ref2; splice.apply(children, [i, i - i + 1].concat(ref2 = replacement(child, this))), ref2;
return true; return true;
} else { } else {
if (child.replaceInContext(match, replacement)) { if (child.replaceInContext(match, replacement)) {
@ -341,7 +342,7 @@
for (i = j = fragments.length - 1; j >= 0; i = j += -1) { for (i = j = fragments.length - 1; j >= 0; i = j += -1) {
fragment = fragments[i]; fragment = fragments[i];
if (fragment.fragments) { if (fragment.fragments) {
[].splice.apply(fragments, [i, i - i + 1].concat(ref1 = this.expand(fragment.fragments))), ref1; splice.apply(fragments, [i, i - i + 1].concat(ref1 = this.expand(fragment.fragments))), ref1;
} }
} }
return fragments; return fragments;
@ -1830,7 +1831,7 @@
end++; end++;
} }
pushSlice(); pushSlice();
[].splice.apply(expressions, [i, i - i + 1].concat(exprs)), exprs; splice.apply(expressions, [i, i - i + 1].concat(exprs)), exprs;
i += exprs.length; i += exprs.length;
} else { } else {
if (initializerExpression = this.addInitializerExpression(expression)) { if (initializerExpression = this.addInitializerExpression(expression)) {
@ -1942,7 +1943,7 @@
for (j = ref1.length - 1; j >= 0; j += -1) { for (j = ref1.length - 1; j >= 0; j += -1) {
name = ref1[j]; name = ref1[j];
name = new Value(new ThisLiteral, [name]).compile(o); name = new Value(new ThisLiteral, [name]).compile(o);
results.push(new Literal(`${name} = ${utility('bind', o)}(${name}, this)`)); results.push(new Literal(`${name} = ${name}.bind(this)`));
} }
return results; return results;
}).call(this); }).call(this);
@ -2629,7 +2630,7 @@
to = "9e9"; to = "9e9";
} }
[valDef, valRef] = this.value.cache(o, LEVEL_LIST); [valDef, valRef] = this.value.cache(o, LEVEL_LIST);
answer = [].concat(this.makeCode(`[].splice.apply(${name}, [${fromDecl}, ${to}].concat(`), valDef, this.makeCode(")), "), valRef); answer = [].concat(this.makeCode(`${utility('splice', o)}.apply(${name}, [${fromDecl}, ${to}].concat(`), valDef, this.makeCode(")), "), valRef);
if (o.level > LEVEL_TOP) { if (o.level > LEVEL_TOP) {
return this.wrapInParentheses(answer); return this.wrapInParentheses(answer);
} else { } else {
@ -4180,23 +4181,20 @@
})(); })();
UTILITIES = { UTILITIES = {
extend: function(o) {
return `function(child, parent) { for (var key in parent) { if (${utility('hasProp', o)}.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); return child; }`;
},
bind: function() {
return 'function(fn, me){ return function(){ return fn.apply(me, arguments); }; }';
},
indexOf: function() {
return "[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }";
},
modulo: function() { modulo: function() {
return "function(a, b) { return (+a % (b = +b) + b) % b; }"; return 'function(a, b) { return (+a % (b = +b) + b) % b; }';
}, },
hasProp: function() { hasProp: function() {
return '{}.hasOwnProperty'; return '{}.hasOwnProperty';
}, },
indexOf: function() {
return '[].indexOf';
},
slice: function() { slice: function() {
return '[].slice'; return '[].slice';
},
splice: function() {
return '[].splice';
} }
}; };

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
// Generated by CoffeeScript 2.0.0-beta1 // Generated by CoffeeScript 2.0.0-beta1
(function() { (function() {
var BALANCED_PAIRS, CALL_CLOSERS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, generate, k, left, len, rite, var BALANCED_PAIRS, CALL_CLOSERS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, generate, k, left, len, rite,
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; }; indexOf = [].indexOf;
generate = function(tag, value, origin) { generate = function(tag, value, origin) {
var tok; var tok;

View file

@ -1,7 +1,7 @@
// Generated by CoffeeScript 2.0.0-beta1 // Generated by CoffeeScript 2.0.0-beta1
(function() { (function() {
var Scope, 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; }; indexOf = [].indexOf;
exports.Scope = Scope = class Scope { exports.Scope = Scope = class Scope {
constructor(parent, expressions, method, referencedVars) { constructor(parent, expressions, method, referencedVars) {

View file

@ -699,7 +699,6 @@ grammar =
INDENT Expression OUTDENT', -> new Assign $1, $4, $2 INDENT Expression OUTDENT', -> new Assign $1, $4, $2
o 'SimpleAssignable COMPOUND_ASSIGN TERMINATOR o 'SimpleAssignable COMPOUND_ASSIGN TERMINATOR
Expression', -> new Assign $1, $4, $2 Expression', -> new Assign $1, $4, $2
o 'SimpleAssignable EXTENDS Expression', -> new Extends $1, $3
] ]

View file

@ -1427,7 +1427,7 @@ exports.Class = class Class extends Base
proxyBoundMethods: (o) -> proxyBoundMethods: (o) ->
@ctor.thisAssignments = for name in @boundMethods by -1 @ctor.thisAssignments = for name in @boundMethods by -1
name = new Value(new ThisLiteral, [ name ]).compile o name = new Value(new ThisLiteral, [ name ]).compile o
new Literal "#{name} = #{utility 'bind', o}(#{name}, this)" new Literal "#{name} = #{name}.bind(this)"
null null
@ -1873,7 +1873,7 @@ exports.Assign = class Assign extends Base
if not expandedIdx and obj instanceof Splat if not expandedIdx and obj instanceof Splat
name = obj.name.unwrap().value name = obj.name.unwrap().value
obj = obj.unwrap() obj = obj.unwrap()
val = "#{olen} <= #{vvarText}.length ? #{ utility 'slice', o }.call(#{vvarText}, #{i}" val = "#{olen} <= #{vvarText}.length ? #{utility 'slice', o}.call(#{vvarText}, #{i}"
rest = olen - i - 1 rest = olen - i - 1
if rest isnt 0 if rest isnt 0
ivar = o.scope.freeVariable 'i', single: true ivar = o.scope.freeVariable 'i', single: true
@ -1972,7 +1972,7 @@ exports.Assign = class Assign extends Base
else else
to = "9e9" to = "9e9"
[valDef, valRef] = @value.cache o, LEVEL_LIST [valDef, valRef] = @value.cache o, LEVEL_LIST
answer = [].concat @makeCode("[].splice.apply(#{name}, [#{fromDecl}, #{to}].concat("), valDef, @makeCode(")), "), valRef answer = [].concat @makeCode("#{utility 'splice', o}.apply(#{name}, [#{fromDecl}, #{to}].concat("), valDef, @makeCode(")), "), valRef
if o.level > LEVEL_TOP then @wrapInParentheses answer else answer if o.level > LEVEL_TOP then @wrapInParentheses answer else answer
eachName: (iterator) -> eachName: (iterator) ->
@ -3109,49 +3109,13 @@ exports.If = class If extends Base
# --------- # ---------
UTILITIES = UTILITIES =
modulo: -> 'function(a, b) { return (+a % (b = +b) + b) % b; }'
# Correctly set up a prototype chain for inheritance, including a reference
# to the superclass for `super()` calls, and copies of any static properties.
extend: (o) -> "
function(child, parent) {
for (var key in parent) {
if (#{utility 'hasProp', o}.call(parent, key)) child[key] = parent[key];
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
return child;
}
"
# Create a function bound to the current value of "this".
bind: -> '
function(fn, me){
return function(){
return fn.apply(me, arguments);
};
}
'
# Discover if an item is in an array.
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;
}
"
modulo: -> """
function(a, b) { return (+a % (b = +b) + b) % b; }
"""
# Shortcuts to speed up the lookup time for native functions. # Shortcuts to speed up the lookup time for native functions.
hasProp: -> '{}.hasOwnProperty' hasProp: -> '{}.hasOwnProperty'
indexOf: -> '[].indexOf'
slice : -> '[].slice' slice : -> '[].slice'
splice : -> '[].splice'
# Levels indicate a node's position in the AST. Useful for knowing if # Levels indicate a node's position in the AST. Useful for knowing if
# parens are necessary or superfluous. # parens are necessary or superfluous.

View file

@ -433,47 +433,65 @@ test "export default predefined function", ->
export default foo;""" export default foo;"""
eq toJS(input), output eq toJS(input), output
# Uncomment this test once ES2015+ `class` support is added test "export default class", ->
input = """
export default class foo extends bar
baz: ->
console.log 'hello, world!'"""
output = """
var foo;
# test "export default class", -> export default foo = class foo extends bar {
# input = """ baz() {
# export default class foo extends bar return console.log('hello, world!');
# baz: -> }
# console.log 'hello, world!'"""
# output = """ };"""
# export default class foo extends bar { eq toJS(input), output
# baz: function {
# return console.log('hello, world!');
# }
# }"""
# eq toJS(input), output
# Very limited tests for now, testing that `export class foo` either compiles
# identically (ES2015+) or at least into some function, leaving the specifics
# vague in case the CoffeeScript `class` interpretation changes
test "export class", -> test "export class", ->
input = """ input = """
export class foo export class foo
baz: -> baz: ->
console.log 'hello, world!'""" console.log 'hello, world!'"""
output = toJS input output = """
ok /^export (var foo = class foo|var foo = \(function)/.test toJS input export var foo = class foo {
baz() {
return console.log('hello, world!');
}
};"""
eq toJS(input), output
test "export class that extends", -> test "export class that extends", ->
input = """ input = """
export class foo extends bar export class foo extends bar
baz: -> baz: ->
console.log 'hello, world!'""" console.log 'hello, world!'"""
output = toJS input output = """
ok /export var foo = class foo/.test(output) and \ export var foo = class foo extends bar {
not /var foo(;|,)/.test output baz() {
return console.log('hello, world!');
}
};"""
eq toJS(input), output
test "export default class that extends", -> test "export default class that extends", ->
input = """ input = """
export default class foo extends bar export default class foo extends bar
baz: -> baz: ->
console.log 'hello, world!'""" console.log 'hello, world!'"""
ok /export default foo = class foo/.test toJS input output = """
var foo;
export default foo = class foo extends bar {
baz() {
return console.log('hello, world!');
}
};"""
eq toJS(input), output
test "export default named member, within an object", -> test "export default named member, within an object", ->
input = "export { foo as default, bar }" input = "export { foo as default, bar }"