What's wrong
JavaScriptGenerator.GenerateMethod (Coder/Languages/JavaScriptGenerator.cs:417-472) writes a constructor in a fixed order. It writes constructor(...) {, then one this.<member> = <value>; per MemberInitialiser (:459-469), then the body. GenerateClassDeclaration writes class X extends Base whenever BaseType is set (:352-355). Nothing in the file ever writes super(...); grep super Coder/Languages/JavaScriptGenerator.cs finds nothing.
In JavaScript, a constructor in a derived class must call super(). It must do so before it touches this, and before it returns even when it does nothing. Without the call, constructing the class always throws. C++ and C# call the base's default constructor implicitly, so the same AST is correct in those targets and broken only in JavaScript.
Reproduction
var shape = new ClassDeclaration("Shape");
shape.Members.Add(new FieldDeclaration("name", "string") { InitialValue = new LiteralExpression<string>("shape") });
var circle = new ClassDeclaration("Circle") { BaseType = "Shape" };
circle.Members.Add(new FieldDeclaration("radius", "double"));
var ctor = new FunctionDeclaration("Circle") { Kind = FunctionKind.Constructor };
ctor.Parameters.Add(new Parameter("radius", "double"));
ctor.Initialisers.Add(new MemberInitialiser("radius") { Value = new VariableReference("radius") });
circle.Members.Add(ctor);
Console.WriteLine(new JavaScriptGenerator().Generate(new SourceFile("shapes") { Members = { shape, circle } }));
Generated:
class Shape {
name = "shape";
}
class Circle extends Shape {
radius;
constructor(radius) {
this.radius = radius;
}
}
I appended const c = new Circle(2); console.log(c.radius, c.name); and ran it with node 22:
ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
at new Circle (derived.mjs:8:9)
Expected: 2 shape. The C++ and C# output of the same AST constructs correctly, because both call Shape() implicitly.
Why it matters
No class with a base type and a constructor can be instantiated in the generated JavaScript. Removing the initialisers does not help, because a derived constructor that returns without calling super() throws too. There is no JavaScript toolchain test, so the failure is invisible in CI.
Suggested fix / acceptance criteria
- When the enclosing class has a
BaseType, the generator writes super(); as the first statement of the constructor, before any initialiser assignment. The AST has no way to pass arguments to the base constructor, so the argument-less call matches what C++ and C# do implicitly.
- If a
MemberInitialiser named after the base type is meant to carry base-constructor arguments (the C++ : Base(args) idiom), it should become super(args) rather than this.Base = ....
- Add a test that runs the output under node when node is on the path, like the other toolchain tests. At minimum, add a text test asserting that
super(); precedes this.radius = radius;.
What's wrong
JavaScriptGenerator.GenerateMethod(Coder/Languages/JavaScriptGenerator.cs:417-472) writes a constructor in a fixed order. It writesconstructor(...) {, then onethis.<member> = <value>;perMemberInitialiser(:459-469), then the body.GenerateClassDeclarationwritesclass X extends BasewheneverBaseTypeis set (:352-355). Nothing in the file ever writessuper(...);grep super Coder/Languages/JavaScriptGenerator.csfinds nothing.In JavaScript, a constructor in a derived class must call
super(). It must do so before it touchesthis, and before it returns even when it does nothing. Without the call, constructing the class always throws. C++ and C# call the base's default constructor implicitly, so the same AST is correct in those targets and broken only in JavaScript.Reproduction
Generated:
I appended
const c = new Circle(2); console.log(c.radius, c.name);and ran it with node 22:Expected:
2 shape. The C++ and C# output of the same AST constructs correctly, because both callShape()implicitly.Why it matters
No class with a base type and a constructor can be instantiated in the generated JavaScript. Removing the initialisers does not help, because a derived constructor that returns without calling
super()throws too. There is no JavaScript toolchain test, so the failure is invisible in CI.Suggested fix / acceptance criteria
BaseType, the generator writessuper();as the first statement of the constructor, before any initialiser assignment. The AST has no way to pass arguments to the base constructor, so the argument-less call matches what C++ and C# do implicitly.MemberInitialisernamed after the base type is meant to carry base-constructor arguments (the C++: Base(args)idiom), it should becomesuper(args)rather thanthis.Base = ....super();precedesthis.radius = radius;.