Skip to content

Commit b4391a7

Browse files
class refactoring part 3: external constructors
1 parent 817dbde commit b4391a7

File tree

6 files changed

+141
-47
lines changed

6 files changed

+141
-47
lines changed

lib/coffee-script/compiler.js

Lines changed: 14 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/coffee-script/nodes.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/coffee-script/parser.js

Lines changed: 90 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/compiler.coffee

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -345,21 +345,23 @@ class exports.Compiler
345345
else fn
346346
]
347347

348-
[CS.Class, ({nameAssignee, parent, name, block}) ->
348+
[CS.Class, ({nameAssignee, parent, name, ctor, block, compile}) ->
349349
args = []
350350
params = []
351351
parentRef = genSym 'super'
352352
block = forceBlock block
353353

354-
# TODO: make this nicer somehow
355-
for fd in block.body when fd.instanceof JS.FunctionDeclaration
356-
ctor = fd
357-
ctor.id = name
358-
break
359354
unless ctor?
360-
block.body.unshift ctor = new JS.FunctionDeclaration name, [], new JS.BlockStatement []
361-
362-
if @boundMembers.length
355+
ctor = new JS.FunctionDeclaration name, [], new JS.BlockStatement []
356+
ctor.id = name
357+
# handle external constructors
358+
if @ctor? and not @ctor.expression.instanceof CS.Functions
359+
ctorRef = genSym 'externalCtor'
360+
ctor.body.body.push makeReturn new JS.CallExpression (memberAccess ctorRef, 'apply'), [new JS.ThisExpression, new JS.Identifier 'arguments']
361+
block.body.unshift stmt new JS.AssignmentExpression '=', ctorRef, compile @ctor.expression
362+
block.body.unshift ctor
363+
364+
if @boundMembers? and @boundMembers.length > 0
363365
instance = genSym 'instance'
364366
for memberName in @boundMembers
365367
member = memberAccess new JS.ThisExpression, memberName
@@ -390,7 +392,6 @@ class exports.Compiler
390392
if @expression.instanceof CS.Functions
391393
new JS.FunctionDeclaration tmpName, expression.params, forceBlock expression.body
392394
else
393-
# TODO: support external ctors
394395
new JS.FunctionDeclaration tmpName, [], new JS.BlockStatement []
395396
]
396397
[CS.ClassProtoAssignOp, ({assignee, expression, compile}) ->

src/grammar.pegjs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -504,17 +504,24 @@ loop
504504

505505
class
506506
= CLASS name:(_ Assignable)? parent:(_ EXTENDS _ (functionLiteral / assignmentExpression))? body:classBody {
507+
var ctor = null;
507508
var raw = 'class' + (name ? name[0] + name[1].raw : '') +
508509
(parent ? parent[0] + 'parent' + parent[2] + parent[3].raw : '') +
509510
body.raw;
510511
name = name ? name[1] : null;
511512
parent = parent ? parent[3] : null;
512-
var boundMembers = foldl(function(memo, m) {
513-
if(m.instanceof(CS.ClassProtoAssignOp) && m.expression.instanceof(CS.BoundFunction))
514-
return memo.concat(m.assignee.data.toString());
515-
return memo;
516-
}, [], body.block.statements);
517-
return new CS.Class(name, parent, body.block, boundMembers).r(raw).p(line, column);
513+
var boundMembers = [];
514+
var stmts = body.block.statements;
515+
for(var i = 0, l = stmts.length; i < l; ++i) {
516+
var m = stmts[i];
517+
if(m.instanceof(CS.Constructor)) {
518+
ctor = m;
519+
stmts.splice(i, 1); --i; --l;
520+
} else if(m.instanceof(CS.ClassProtoAssignOp) && m.expression.instanceof(CS.BoundFunction)) {
521+
boundMembers.push(m.assignee.data.toString());
522+
}
523+
}
524+
return new CS.Class(name, parent, ctor, body.block, boundMembers).r(raw).p(line, column);
518525
}
519526
classBody
520527
= ws:_ t:TERMINDENT b:classBlock d:DEDENT { return {block: b, raw: ws + t + b.raw + d}; }
@@ -531,12 +538,20 @@ class
531538
}
532539
classStatement
533540
= classProtoAssignment
541+
/ constructor
534542
/ expression
543+
constructor
544+
= key:ObjectInitialiserKeys ws0:_ ":" ws1:_ e:expression {
545+
if(!key.instanceof(CS.String, CS.Identifier) || key.data !== 'constructor') return null;
546+
var raw = key.raw + ws0 + ":" + ws1 + e.raw;
547+
if(e.instanceof(CS.BoundFunction))
548+
e = new CS.Function(e.parameters, e.block).r(e.raw).p(e.line, e.column);
549+
return new CS.Constructor(e).r(raw).p(line, column);
550+
}
535551
classProtoAssignment
536552
= key:ObjectInitialiserKeys ws0:_ ":" ws1:_ e:expression {
553+
if(key.data === 'constructor') return null;
537554
var raw = key.raw + ws0 + ":" + ws1 + e.raw;
538-
if(key.instanceof(CS.String, CS.Identifier) && key.data === 'constructor')
539-
return new CS.Constructor(e).r(raw).p(line, column);
540555
return new CS.ClassProtoAssignOp(key, e).r(raw).p(line, column);
541556
}
542557

src/nodes.coffee

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,15 @@ createNodes
136136
ForIn: [['valAssignee', 'keyAssignee', 'expression', 'step', 'filterExpr', 'block']] # :: Assignable -> Maybe Assignable -> Exprs -> Exprs -> Maybe Exprs -> Maybe Exprs -> ForIn
137137
ForOf: [['isOwn', 'keyAssignee', 'valAssignee', 'expression', 'filterExpr', 'block']] # :: bool -> Assignable -> Maybe Assignable -> Exprs -> Maybe Exprs -> Maybe Exprs -> ForOf
138138
Switch: [['expression', 'cases', 'elseBlock']] # :: Maybe Exprs -> [SwitchCase] -> Maybe Exprs -> Switch
139-
# TODO: test/consequent
139+
# TODO: tests/consequent
140140
SwitchCase: [['conditions', 'block']] # :: [Exprs] -> Maybe Expr -> SwitchCase
141141
Try: [['block', 'catchAssignee', 'catchBlock', 'finallyBlock']] # :: Exprs -> Maybe Assignable -> Maybe Exprs -> Maybe Exprs -> Try
142142
While: [['condition', 'block']] # :: Exprs -> Maybe Exprs -> While
143143

144144
ArrayInitialiser: [['members']] # :: [ArrayInitialiserMembers] -> ArrayInitialiser
145145
ObjectInitialiser: [['members']] # :: [ObjectInitialiserMember] -> ObjectInitialiser
146146
ObjectInitialiserMember: [['key', 'expression']] # :: ObjectInitialiserKeys -> Exprs -> ObjectInitialiserMember
147-
Class: [['nameAssignee', 'parent', 'block', 'boundMembers']] # :: Maybe Assignable -> Maybe Exprs -> Maybe Exprs -> [string] -> Class
147+
Class: [['nameAssignee', 'parent', 'ctor', 'block', 'boundMembers']] # :: Maybe Assignable -> Maybe Exprs -> Maybe Exprs -> Maybe Exprs -> [string] -> Class
148148
Constructor: [['expression']] # :: Exprs -> Constructor
149149
Functions: [ ['parameters', 'block'],
150150
Function: null # :: [Parameters] -> Maybe Exprs -> Function

0 commit comments

Comments
 (0)