@ball-lang/compiler 1.71.0 → 1.71.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compiler.d.ts +7 -4
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +63 -21
- package/dist/compiler.js.map +1 -1
- package/package.json +1 -1
- package/src/compiler.ts +71 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ball-lang/compiler",
|
|
3
|
-
"version": "1.71.
|
|
3
|
+
"version": "1.71.1",
|
|
4
4
|
"description": "Ball → TypeScript compiler. Consumes a Ball protobuf Program and emits idiomatic TypeScript via ts-morph. The canonical TS compiler for Ball — lives in TS land so TS syntax knowledge doesn't leak into other languages.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
package/src/compiler.ts
CHANGED
|
@@ -2609,7 +2609,22 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
2609
2609
|
// Include inherited fields from the superclass chain so that
|
|
2610
2610
|
// references to inherited fields inside methods emit `this.name`
|
|
2611
2611
|
// instead of bare `name` (which would be undefined in JS).
|
|
2612
|
+
//
|
|
2613
|
+
// The walk also collects each ancestor level's own field SPECS (type +
|
|
2614
|
+
// inline initializer), not just the names: a named constructor builds its
|
|
2615
|
+
// instance with `Object.create`, which runs no constructor at all — so it
|
|
2616
|
+
// never runs the real `super()` that would otherwise execute the
|
|
2617
|
+
// superclass's inline field initializers as its own prologue. The seeding
|
|
2618
|
+
// loop in `buildNamedCtor` therefore has to reproduce the whole chain in
|
|
2619
|
+
// one flat pass, the way the Dart reference engine's constructor frame
|
|
2620
|
+
// recurses through `_invokeSuperConstructor` (#581).
|
|
2612
2621
|
const superclass = typeof meta["superclass"] === "string" ? meta["superclass"] : undefined;
|
|
2622
|
+
const inheritedLevels: Array<Array<{
|
|
2623
|
+
name: string;
|
|
2624
|
+
type: string;
|
|
2625
|
+
rawDartType: string;
|
|
2626
|
+
dartInitializer?: string;
|
|
2627
|
+
}>> = [];
|
|
2613
2628
|
if (superclass) {
|
|
2614
2629
|
const entryMod = this.program.modules.find(m => m.name === this.program.entryModule);
|
|
2615
2630
|
let sup: string | undefined = superclass;
|
|
@@ -2618,15 +2633,43 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
2618
2633
|
if (!supTd) break;
|
|
2619
2634
|
const supMeta: Struct = supTd.metadata ?? {};
|
|
2620
2635
|
const supFields = Array.isArray(supMeta["fields"]) ? supMeta["fields"] as any[] : [];
|
|
2636
|
+
const level: Array<{
|
|
2637
|
+
name: string;
|
|
2638
|
+
type: string;
|
|
2639
|
+
rawDartType: string;
|
|
2640
|
+
dartInitializer?: string;
|
|
2641
|
+
}> = [];
|
|
2621
2642
|
for (const sf of supFields) {
|
|
2622
|
-
if (sf?.name)
|
|
2643
|
+
if (!sf?.name) continue;
|
|
2644
|
+
fieldNames.add(sf.name);
|
|
2645
|
+
// Statics live as module-level consts, never on the instance.
|
|
2646
|
+
if (sf.is_static === true) continue;
|
|
2647
|
+
level.push({
|
|
2648
|
+
name: sf.name,
|
|
2649
|
+
type: typeof sf.type === "string" ? this.dartTypeToTs(sf.type) : "any",
|
|
2650
|
+
rawDartType: typeof sf.type === "string" ? sf.type : "",
|
|
2651
|
+
dartInitializer: typeof sf.initializer === "string" ? sf.initializer : undefined,
|
|
2652
|
+
});
|
|
2623
2653
|
}
|
|
2624
2654
|
if (supTd.descriptor?.field) {
|
|
2625
2655
|
for (const f of supTd.descriptor.field) fieldNames.add(f.name);
|
|
2626
2656
|
}
|
|
2657
|
+
// Descriptor fallback mirrors the own-class path above: only when the
|
|
2658
|
+
// ancestor carries no richer `metadata.fields` at all. A bare
|
|
2659
|
+
// descriptor field has no initializer, so it seeds nothing — it is
|
|
2660
|
+
// collected purely so the level list matches the name set.
|
|
2661
|
+
if (level.length === 0 && supTd.descriptor?.field) {
|
|
2662
|
+
for (const f of supTd.descriptor.field) {
|
|
2663
|
+
level.push({ name: f.name, type: "any", rawDartType: "" });
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
inheritedLevels.push(level);
|
|
2627
2667
|
sup = typeof supMeta["superclass"] === "string" ? supMeta["superclass"] : undefined;
|
|
2628
2668
|
}
|
|
2629
2669
|
}
|
|
2670
|
+
// Root ancestor first, matching Dart's superclass-initializes-before-
|
|
2671
|
+
// subclass ordering, so a subclass field that shadows an ancestor's wins.
|
|
2672
|
+
const inheritedProperties = inheritedLevels.slice().reverse().flat();
|
|
2630
2673
|
|
|
2631
2674
|
// Method-name set for `this.foo()` routing inside bodies.
|
|
2632
2675
|
// Exclude static fields — they're emitted as module-level consts
|
|
@@ -2702,17 +2745,18 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
2702
2745
|
ctors.push(this.buildCtor(fn, mMeta, fieldNames, hasExtends));
|
|
2703
2746
|
} else {
|
|
2704
2747
|
// Named constructors are static factory methods that return a new
|
|
2705
|
-
// instance.
|
|
2706
|
-
// them
|
|
2707
|
-
//
|
|
2708
|
-
// (
|
|
2748
|
+
// instance. Every (non-static) field declaration reachable from this
|
|
2749
|
+
// class goes with them — inherited ones first, then the class's own:
|
|
2750
|
+
// the instance is built with `Object.create`, which runs no field
|
|
2751
|
+
// initializer AND no real `super()`, so the builder has to seed each
|
|
2752
|
+
// default along the whole superclass chain itself (#564, #581).
|
|
2709
2753
|
methods.push(
|
|
2710
2754
|
this.buildNamedCtor(
|
|
2711
2755
|
fn,
|
|
2712
2756
|
mMeta,
|
|
2713
2757
|
fieldNames,
|
|
2714
2758
|
tsName,
|
|
2715
|
-
properties.filter((p) => !p.isStatic),
|
|
2759
|
+
[...inheritedProperties, ...properties.filter((p) => !p.isStatic)],
|
|
2716
2760
|
),
|
|
2717
2761
|
);
|
|
2718
2762
|
}
|
|
@@ -2943,10 +2987,13 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
2943
2987
|
* 0`), `this.`-formals (`Box.of(this.value)`), a plain body
|
|
2944
2988
|
* (`Bar.named(int x) { print(x); }`), or any combination. The instance comes
|
|
2945
2989
|
* from `Object.create(C.prototype)` so no user constructor runs, which means
|
|
2946
|
-
* the class's inline field initializers
|
|
2947
|
-
*
|
|
2948
|
-
*
|
|
2949
|
-
*
|
|
2990
|
+
* neither the class's inline field initializers nor the real `super()` that
|
|
2991
|
+
* would run the SUPERCLASS's inline initializers execute either: every
|
|
2992
|
+
* declared field reachable from this class — inherited ones first, then the
|
|
2993
|
+
* class's own — is seeded with its default FIRST (Dart's ordering — inline
|
|
2994
|
+
* field initializers, then the initializer list, then the body), and only
|
|
2995
|
+
* then do the constructor-specific writes land on top (#564, #581). The
|
|
2996
|
+
* caller (`emitClass`) supplies that whole-chain `classProperties` list.
|
|
2950
2997
|
*
|
|
2951
2998
|
* A `factory` named constructor is the one exception: by definition it
|
|
2952
2999
|
* returns some other object, so its body runs as the static method's own
|
|
@@ -2971,16 +3018,16 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
2971
3018
|
const bodyParts: string[] = [];
|
|
2972
3019
|
// Does the ctor have any field write of its own? Only WHETHER matters
|
|
2973
3020
|
// here; each value is resolved where the assignment is emitted, by
|
|
2974
|
-
// `resolveInitializerValue`.
|
|
2975
|
-
//
|
|
2976
|
-
//
|
|
2977
|
-
//
|
|
3021
|
+
// `resolveInitializerValue`. A `this.`-formal ALWAYS counts, whatever else
|
|
3022
|
+
// the initializer list holds: this used to also require
|
|
3023
|
+
// `initializers.length === 0`, so `Foo.named(this.x) : super(1)` — a
|
|
3024
|
+
// non-empty list with no `field` entry — took neither construct branch and
|
|
3025
|
+
// fell through to `return new Foo()`, silently dropping the formal (#582).
|
|
2978
3026
|
const thisParams = ctorParams.filter(p => p.isThis);
|
|
2979
3027
|
const hasFieldInitializers = initializers.some(
|
|
2980
3028
|
(i: any) => i?.kind === "field" && typeof i.name === "string",
|
|
2981
3029
|
);
|
|
2982
|
-
const hasCtorFieldWrites =
|
|
2983
|
-
hasFieldInitializers || (initializers.length === 0 && thisParams.length > 0);
|
|
3030
|
+
const hasCtorFieldWrites = hasFieldInitializers || thisParams.length > 0;
|
|
2984
3031
|
// A Dart `factory` returns some other object, so it is the ONE named
|
|
2985
3032
|
// constructor that must not synthesize an instance of its own class.
|
|
2986
3033
|
const isFactory = meta["is_factory"] === true;
|
|
@@ -3004,12 +3051,15 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
3004
3051
|
const allAssignments = [...assignments, ...thisAssignments];
|
|
3005
3052
|
bodyParts.push(`const __inst = Object.create(${className}.prototype);`);
|
|
3006
3053
|
// `Object.create` deliberately runs no constructor — which also means it
|
|
3007
|
-
// runs none of the class's inline field initializers
|
|
3008
|
-
//
|
|
3009
|
-
//
|
|
3010
|
-
//
|
|
3054
|
+
// runs none of the class's inline field initializers, and none of the
|
|
3055
|
+
// SUPERCLASS's either (a real `super()` would have). `classProperties`
|
|
3056
|
+
// is therefore the whole superclass chain root-first, then this class's
|
|
3057
|
+
// own fields. Seed each with the SAME default its class declaration
|
|
3058
|
+
// emits, before any constructor-specific write, exactly as Dart orders
|
|
3059
|
+
// them (inline initializers, then the initializer list, then the body).
|
|
3011
3060
|
// Without this a field the named constructor never mentions stayed
|
|
3012
|
-
// `undefined` forever (#564: `Init.viaList`'s `w`, `Baz.bare`'s `v
|
|
3061
|
+
// `undefined` forever (#564: `Init.viaList`'s `w`, `Baz.bare`'s `v`;
|
|
3062
|
+
// #581: every field declared by an ancestor).
|
|
3013
3063
|
for (const p of classProperties) {
|
|
3014
3064
|
const def = dartInitializerToTs(p.dartInitializer, p.type, p.rawDartType);
|
|
3015
3065
|
if (def !== undefined) bodyParts.push(`__inst.${p.name} = ${def};`);
|