Skip to content

Commit cf2772a

Browse files
instance-bound methods preserve the original function length
jashkenas/coffeescript#2489
1 parent 2bcfd12 commit cf2772a

File tree

8 files changed

+73
-22
lines changed

8 files changed

+73
-22
lines changed

lib/coffee-script/compiler.js

+29-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/coffee-script/functional-helpers.js

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/coffee-script/nodes.js

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/coffee-script/parser.js

+4-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/compiler.coffee

+16-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{any, concat, concatMap, difference, foldl1, map, nub, owns, union} = require './functional-helpers'
1+
{any, concat, concatMap, difference, divMod, foldl1, map, nub, owns, union} = require './functional-helpers'
22
{beingDeclared, usedAsExpression, envEnrichments} = require './helpers'
33
CS = require './nodes'
44
JS = require './js-nodes'
@@ -361,12 +361,14 @@ class exports.Compiler
361361
block.body.unshift stmt new JS.AssignmentExpression '=', ctorRef, compile @ctor.expression
362362
block.body.unshift ctor
363363

364-
if @boundMembers? and @boundMembers.length > 0
364+
if @boundMembers.length > 0
365365
instance = genSym 'instance'
366-
for memberName in @boundMembers
366+
for protoAssignOp in @boundMembers
367+
memberName = protoAssignOp.assignee.data.toString()
368+
ps = (genSym() for _ in protoAssignOp.expression.parameters)
367369
member = memberAccess new JS.ThisExpression, memberName
368370
protoMember = memberAccess (memberAccess name, 'prototype'), memberName
369-
fn = new JS.FunctionExpression null, [], new JS.BlockStatement [
371+
fn = new JS.FunctionExpression null, ps, new JS.BlockStatement [
370372
stmt new JS.CallExpression (memberAccess protoMember, 'apply'), [instance, new JS.Identifier 'arguments']
371373
]
372374
ctor.body.body.unshift stmt new JS.AssignmentExpression '=', member, fn
@@ -651,7 +653,15 @@ class exports.Compiler
651653
generateSymbols = do ->
652654

653655
generatedSymbols = {}
654-
format = (pre, counter) -> "#{pre}$#{counter or ''}"
656+
format = (pre, counter) ->
657+
if pre
658+
"#{pre}$#{counter or ''}"
659+
else
660+
if counter < 26
661+
String.fromCharCode 0x61 + counter
662+
else
663+
[div, mod] = divMod counter, 26
664+
(format pre, div - 1) + format pre, mod
655665

656666
generateName = (node, {usedSymbols, nsCounters}) ->
657667
if owns generatedSymbols, node.uniqueId
@@ -696,5 +706,5 @@ class exports.Compiler
696706
jsAST = walk.call ast, (-> (rules[@className] ? defaultRule).apply this, arguments), [], [], options
697707
generateSymbols jsAST,
698708
declaredSymbols: []
699-
usedSymbols: collectIdentifiers jsAST
709+
usedSymbols: jsReserved[..]
700710
nsCounters: {}

src/functional-helpers.coffee

+6
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,9 @@
3636
@flip = (fn) -> (b, a) -> fn.call this, a, b
3737

3838
@owns = do (hop = {}.hasOwnProperty) -> (a, b) -> hop.call a, b
39+
40+
@divMod = (a, b) ->
41+
c = a % b
42+
mod = if c < 0 then c + b else c
43+
div = Math.floor a / b
44+
[div, mod]

src/grammar.pegjs

+4-4
Original file line numberDiff line numberDiff line change
@@ -511,14 +511,14 @@ class
511511
name = name ? name[1] : null;
512512
parent = parent ? parent[3] : null;
513513
var boundMembers = [];
514-
var stmts = body.block.statements;
514+
var stmts = body.block != null ? body.block.statements : [];
515515
for(var i = 0, l = stmts.length; i < l; ++i) {
516516
var m = stmts[i];
517517
if(m.instanceof(CS.Constructor)) {
518518
ctor = m;
519519
stmts.splice(i, 1); --i; --l;
520520
} else if(m.instanceof(CS.ClassProtoAssignOp) && m.expression.instanceof(CS.BoundFunction)) {
521-
boundMembers.push(m.assignee.data.toString());
521+
boundMembers.push(m);
522522
}
523523
}
524524
return new CS.Class(name, parent, ctor, body.block, boundMembers).r(raw).p(line, column);
@@ -613,7 +613,7 @@ switch
613613

614614

615615
functionLiteral
616-
= params:("(" _ parameterList _ ")" _)? arrow:("->" / "=>") body:functionBody? {
616+
= params:("(" _ parameterList? _ ")" _)? arrow:("->" / "=>") body:functionBody? {
617617
if(!body) body = {block: null, raw: ''};
618618
var raw =
619619
(params ? params[0] + params[1] + params[2].raw + params[3] + params[4] + params[5] : '') +
@@ -624,7 +624,7 @@ functionLiteral
624624
case '=>': constructor = CS.BoundFunction; break;
625625
default: throw new Error('parsed function arrow ("' + arrow + '") not associated with a constructor');
626626
}
627-
params = params ? params[2].list : [];
627+
params = params && params[2] ? params[2].list : [];
628628
return new constructor(params, body.block).r(raw).p(line, column);
629629
}
630630
functionBody

src/nodes.coffee

+2-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ createNodes
144144
ArrayInitialiser: [['members']] # :: [ArrayInitialiserMembers] -> ArrayInitialiser
145145
ObjectInitialiser: [['members']] # :: [ObjectInitialiserMember] -> ObjectInitialiser
146146
ObjectInitialiserMember: [['key', 'expression']] # :: ObjectInitialiserKeys -> Exprs -> ObjectInitialiserMember
147-
Class: [['nameAssignee', 'parent', 'ctor', 'block', 'boundMembers']] # :: Maybe Assignable -> Maybe Exprs -> Maybe Exprs -> Maybe Exprs -> [string] -> Class
147+
Class: [['nameAssignee', 'parent', 'ctor', 'block', 'boundMembers']] # :: Maybe Assignable -> Maybe Exprs -> Maybe Exprs -> Maybe Exprs -> [ClassProtoAssignOp] -> Class
148148
Constructor: [['expression']] # :: Exprs -> Constructor
149149
Functions: [ ['parameters', 'block'],
150150
Function: null # :: [Parameters] -> Maybe Exprs -> Function
@@ -261,6 +261,7 @@ handleLists SwitchCase, ['conditions']
261261
Block.wrap = (s) -> new Block(if s? then [s] else []).r(s.raw).p(s.line, s.column)
262262

263263
Class::initialise = ->
264+
@boundMembers ?= []
264265
@name = new GenSym 'class'
265266
if @nameAssignee?
266267
# TODO: factor this out, as it's useful elsewhere: short object literal members, NFEs from assignee, etc.

0 commit comments

Comments
 (0)