Skip to content

Commit c0e1f23

Browse files
committed
Merge pull request #3785 from lydell/super
Allow super in methods with dynamic names
2 parents 04b30a6 + ee8f889 commit c0e1f23

File tree

3 files changed

+129
-45
lines changed

3 files changed

+129
-45
lines changed

lib/coffee-script/nodes.js

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

src/nodes.coffee

+30-23
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ exports.Value = class Value extends Base
513513
last(@properties) instanceof Slice
514514

515515
looksStatic: (className) ->
516-
@base.value is className and @properties.length and
516+
@base.value is className and @properties.length is 1 and
517517
@properties[0].name?.value isnt 'prototype'
518518

519519
# The value can be unwrapped as its inner node, if there are no attached
@@ -614,10 +614,21 @@ exports.Call = class Call extends Base
614614
superReference: (o) ->
615615
method = o.scope.namedMethod()
616616
if method?.klass
617-
accesses = [new Access(new Literal '__super__')]
617+
{klass, name, variable} = method
618+
if klass.isComplex()
619+
bref = new Literal o.scope.parent.freeVariable 'base'
620+
base = new Value new Parens new Assign bref, klass
621+
variable.base = base
622+
variable.properties.splice 0, klass.properties.length
623+
if name.isComplex() or (name instanceof Index and name.index.isAssignable())
624+
nref = new Literal o.scope.parent.freeVariable 'name'
625+
name = new Index new Assign nref, name.index
626+
variable.properties.pop()
627+
variable.properties.push name
628+
accesses = [new Access new Literal '__super__']
618629
accesses.push new Access new Literal 'constructor' if method.static
619-
accesses.push new Access new Literal method.name
620-
(new Value (new Literal method.klass), accesses).compile o
630+
accesses.push if nref? then new Index nref else name
631+
(new Value bref ? klass, accesses).compile o
621632
else if method?.ctor
622633
"#{method.name}.__super__.constructor"
623634
else
@@ -1011,7 +1022,6 @@ exports.Class = class Class extends Base
10111022
if node instanceof Literal and node.value is 'this'
10121023
node.value = name
10131024
else if node instanceof Code
1014-
node.klass = name
10151025
node.context = name if node.bound
10161026

10171027
# Ensure that all functions bound to the instance are proxied in the
@@ -1162,21 +1172,28 @@ exports.Assign = class Assign extends Base
11621172
return @compileSplice o if @variable.isSplice()
11631173
return @compileConditional o if @context in ['||=', '&&=', '?=']
11641174
return @compileSpecialMath o if @context in ['**=', '//=', '%%=']
1165-
compiledName = @variable.compileToFragments o, LEVEL_LIST
1166-
name = fragmentsToText compiledName
1175+
if @value instanceof Code
1176+
if @value.static
1177+
@value.klass = @variable.base
1178+
@value.name = @variable.properties[0]
1179+
@value.variable = @variable
1180+
else if @variable.properties?.length >= 2
1181+
[properties..., prototype, name] = @variable.properties
1182+
if prototype.name?.value is 'prototype'
1183+
@value.klass = new Value @variable.base, properties
1184+
@value.name = name
1185+
@value.variable = @variable
11671186
unless @context
11681187
varBase = @variable.unwrapAll()
11691188
unless varBase.isAssignable()
11701189
@variable.error "\"#{@variable.compile o}\" cannot be assigned"
11711190
unless varBase.hasProperties?()
11721191
if @param
1173-
o.scope.add name, 'var'
1192+
o.scope.add varBase.value, 'var'
11741193
else
1175-
o.scope.find name
1176-
if @value instanceof Code and match = METHOD_DEF.exec name
1177-
@value.klass = match[1] if match[2]
1178-
@value.name = match[3] ? match[4] ? match[5]
1194+
o.scope.find varBase.value
11791195
val = @value.compileToFragments o, LEVEL_LIST
1196+
compiledName = @variable.compileToFragments o, LEVEL_LIST
11801197
return (compiledName.concat @makeCode(": "), val) if @context is 'object'
11811198
answer = compiledName.concat @makeCode(" #{ @context or '=' } "), val
11821199
if o.level <= LEVEL_LIST then answer else @wrapInBraces answer
@@ -2237,24 +2254,14 @@ LEVEL_ACCESS = 6 # ...[0]
22372254
# Tabs are two spaces for pretty printing.
22382255
TAB = ' '
22392256

2240-
IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"
2241-
IDENTIFIER = /// ^ #{IDENTIFIER_STR} $ ///
2257+
IDENTIFIER = /// ^ (?!\d) [$\w\x7f-\uffff]+ $ ///
22422258
SIMPLENUM = /^[+-]?\d+$/
22432259
HEXNUM = /^[+-]?0x[\da-f]+/i
22442260
NUMBER = ///^[+-]?(?:
22452261
0x[\da-f]+ | # hex
22462262
\d*\.?\d+ (?:e[+-]?\d+)? # decimal
22472263
)$///i
22482264

2249-
METHOD_DEF = /// ^
2250-
(#{IDENTIFIER_STR})
2251-
(\.prototype)?
2252-
(?: \.(#{IDENTIFIER_STR})
2253-
| \[("(?:[^\\"\r\n]|\\.)*"|'(?:[^\\'\r\n]|\\.)*')\]
2254-
| \[(0x[\da-fA-F]+ | \d*\.?\d+ (?:[eE][+-]?\d+)?)\]
2255-
)
2256-
$ ///
2257-
22582265
# Is a literal value a string/regex?
22592266
IS_STRING = /^['"]/
22602267
IS_REGEX = /^\//

test/classes.coffee

+62
Original file line numberDiff line numberDiff line change
@@ -828,3 +828,65 @@ test "#3232: super in static methods (not object-assigned)", ->
828828

829829
ok Bar.baz()
830830
ok Bar.qux()
831+
832+
test "#1392 calling `super` in methods defined on namespaced classes", ->
833+
class Base
834+
m: -> 5
835+
n: -> 4
836+
namespace =
837+
A: ->
838+
B: ->
839+
namespace.A extends Base
840+
841+
namespace.A::m = -> super
842+
eq 5, (new namespace.A).m()
843+
namespace.B::m = namespace.A::m
844+
namespace.A::m = null
845+
eq 5, (new namespace.B).m()
846+
847+
count = 0
848+
getNamespace = -> count++; namespace
849+
getNamespace().A::n = -> super
850+
eq 4, (new namespace.A).n()
851+
eq 1, count
852+
853+
class C
854+
@a: ->
855+
@a extends Base
856+
@a::m = -> super
857+
eq 5, (new C.a).m()
858+
859+
test "dynamic method names and super", ->
860+
class Base
861+
@m: -> 6
862+
m: -> 5
863+
n: -> 4
864+
A = ->
865+
A extends Base
866+
867+
m = 'm'
868+
A::[m] = -> super
869+
m = 'n'
870+
eq 5, (new A).m()
871+
872+
name = -> count++; 'n'
873+
874+
count = 0
875+
A::[name()] = -> super
876+
eq 4, (new A).n()
877+
eq 1, count
878+
879+
m = 'm'
880+
count = 0
881+
class B extends Base
882+
@[name()] = -> super
883+
@::[m] = -> super
884+
b = new B
885+
m = 'n'
886+
eq 6, B.m()
887+
eq 5, b.m()
888+
eq 1, count
889+
890+
class C extends B
891+
m: -> super
892+
eq 5, (new C).m()

0 commit comments

Comments
 (0)