Skip to content

Commit 10ac313

Browse files
authored
fix inherited constructor invocation (#137)
1 parent 72527ff commit 10ac313

3 files changed

Lines changed: 92 additions & 8 deletions

File tree

evaluator/evaluator_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,79 @@ func TestInheritedProperties(t *testing.T) {
402402
}
403403
}
404404

405+
func TestInheritedConstructor(t *testing.T) {
406+
tests := []struct {
407+
name string
408+
input string
409+
expected int64
410+
}{
411+
{
412+
name: "parent constructor called when child has none",
413+
input: `
414+
class Animal {
415+
function constructor(legs) {
416+
this.legs = legs
417+
}
418+
}
419+
420+
class Dog extends Animal {
421+
}
422+
423+
d = Dog.new(4)
424+
d.legs
425+
`,
426+
expected: 4,
427+
},
428+
{
429+
name: "grandparent constructor called when child and parent have none",
430+
input: `
431+
class Animal {
432+
function constructor(legs) {
433+
this.legs = legs
434+
}
435+
}
436+
437+
class Mammal extends Animal {
438+
}
439+
440+
class Dog extends Mammal {
441+
}
442+
443+
d = Dog.new(4)
444+
d.legs
445+
`,
446+
expected: 4,
447+
},
448+
{
449+
name: "child constructor overrides parent",
450+
input: `
451+
class Animal {
452+
function constructor(legs) {
453+
this.legs = legs
454+
}
455+
}
456+
457+
class Dog extends Animal {
458+
function constructor(legs) {
459+
this.legs = legs * 2
460+
}
461+
}
462+
463+
d = Dog.new(4)
464+
d.legs
465+
`,
466+
expected: 8,
467+
},
468+
}
469+
470+
for _, tt := range tests {
471+
t.Run(tt.name, func(t *testing.T) {
472+
result := evaluate(tt.input)
473+
isNumberObject(t, result, tt.expected)
474+
})
475+
}
476+
}
477+
405478
func TestThisOutsideClass(t *testing.T) {
406479
tests := []struct {
407480
name string

object/class.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,19 @@ func (class *Class) Method(method string, args []Object) (Object, bool) {
3131
case "new":
3232
instance := &Instance{Class: class, Environment: NewEnclosedEnvironment(class.Environment)}
3333

34-
if ok := instance.Environment.Has("constructor"); ok {
35-
result := instance.Call("constructor", args, class.Name.Token)
34+
// Check for constructor in class and superclass chain
35+
currentClass := class
36+
for currentClass != nil {
37+
if constructor, ok := currentClass.Environment.Get("constructor"); ok {
38+
result := instance.callMethod(constructor.(*Function), args, class.Name.Token)
3639

37-
if result != nil && result.Type() == ERROR {
38-
return result, false
40+
if result != nil && result.Type() == ERROR {
41+
return result, false
42+
}
43+
44+
break
3945
}
46+
currentClass = currentClass.Super
4047
}
4148

4249
return instance, true

object/instance.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,20 @@ func (instance *Instance) Method(method string, args []Object) (Object, bool) {
3232
func (instance *Instance) Call(name string, arguments []Object, tok token.Token) Object {
3333
if function, ok := instance.Environment.Get(name); ok {
3434
if method, ok := function.(*Function); ok {
35-
methodEnvironment := createMethodEnvironment(method, arguments)
36-
methodScope := &Scope{Self: instance, Environment: methodEnvironment}
37-
38-
return evaluator(method.Body, methodScope)
35+
return instance.callMethod(method, arguments, tok)
3936
}
4037
}
4138

4239
return NewError("%d:%d: runtime error: unknown method '%s' on class %s", tok.Line, tok.Column, name, instance.Class.Name.Value)
4340
}
4441

42+
func (instance *Instance) callMethod(method *Function, arguments []Object, tok token.Token) Object {
43+
methodEnvironment := createMethodEnvironment(method, arguments)
44+
methodScope := &Scope{Self: instance, Environment: methodEnvironment}
45+
46+
return evaluator(method.Body, methodScope)
47+
}
48+
4549
func createMethodEnvironment(method *Function, arguments []Object) *Environment {
4650
env := NewEnclosedEnvironment(method.Scope.Environment)
4751

0 commit comments

Comments
 (0)