@ball-lang/compiler 1.6.1 → 1.6.3
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.map +1 -1
- package/dist/compiler.js +34 -6
- package/dist/compiler.js.map +1 -1
- package/dist/preamble.d.ts.map +1 -1
- package/dist/preamble.js +32 -4
- package/dist/preamble.js.map +1 -1
- package/package.json +1 -1
- package/src/compiler.ts +35 -6
- package/src/preamble.ts +32 -4
package/dist/preamble.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preamble.d.ts","sourceRoot":"","sources":["../src/preamble.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"preamble.d.ts","sourceRoot":"","sources":["../src/preamble.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB,QA+4C/B,CAAC"}
|
package/dist/preamble.js
CHANGED
|
@@ -110,7 +110,15 @@ class BallObject extends BallMap {
|
|
|
110
110
|
// (e.g. 42.0 not 42). Used by the compiled Dart engine's _toDouble.
|
|
111
111
|
class BallDouble {
|
|
112
112
|
readonly value: number;
|
|
113
|
-
|
|
113
|
+
// Collapse nested wrapping (new BallDouble(new BallDouble(x))) down to the
|
|
114
|
+
// innermost raw number instead of storing a BallDouble-holding-a-BallDouble.
|
|
115
|
+
// This can legitimately arise now that string_to_double's OWN compiled
|
|
116
|
+
// form already wraps its result (#222): the self-hosted engine's Dart
|
|
117
|
+
// source explicitly does BallDouble(double.parse(s)) to make the parse
|
|
118
|
+
// result double-preserving, which — once double.parse (string_to_double)
|
|
119
|
+
// started wrapping on its own — would otherwise double-wrap. Unwrapping
|
|
120
|
+
// here is idempotent for every other caller, since v is a plain number.
|
|
121
|
+
constructor(v: number) { this.value = v instanceof BallDouble ? v.value : v; }
|
|
114
122
|
valueOf(): number { return this.value; }
|
|
115
123
|
get isNaN(): boolean { return Number.isNaN(this.value); }
|
|
116
124
|
get isFinite(): boolean { return Number.isFinite(this.value); }
|
|
@@ -244,6 +252,13 @@ function __ball_to_string(v: any): string {
|
|
|
244
252
|
}
|
|
245
253
|
return '{' + parts.join(', ') + '}';
|
|
246
254
|
}
|
|
255
|
+
if (v instanceof Set) {
|
|
256
|
+
// A Set is a plain object from typeof's perspective (falls through to
|
|
257
|
+
// the generic branch below, which reads Object.keys — always [] for a
|
|
258
|
+
// Set's internal slots), so every Set printed as the empty "{}" no
|
|
259
|
+
// matter its contents until this dedicated case was added (#219).
|
|
260
|
+
return '{' + [...v].map(__ball_to_string).join(', ') + '}';
|
|
261
|
+
}
|
|
247
262
|
if (typeof v === 'object' && !Array.isArray(v)) {
|
|
248
263
|
// StringBuffer-like objects
|
|
249
264
|
if (v['__buffer__'] && Array.isArray(v['__buffer__'])) {
|
|
@@ -296,10 +311,13 @@ function __ball_to_int(v: any): any {
|
|
|
296
311
|
return t;
|
|
297
312
|
}
|
|
298
313
|
|
|
299
|
-
|
|
314
|
+
// Returns a BallDouble (not a bare number) so a whole-valued result (e.g.
|
|
315
|
+
// double.parse('7.0')) still prints "7.0", not "7" — JS numbers erase the
|
|
316
|
+
// int/double distinction that the wrapper exists to preserve (#67/#222).
|
|
317
|
+
function __ball_parse_double(s: string): BallDouble {
|
|
300
318
|
const n = parseFloat(s);
|
|
301
319
|
if (Number.isNaN(n)) throw new Error('FormatException: ' + s);
|
|
302
|
-
return n;
|
|
320
|
+
return new BallDouble(n);
|
|
303
321
|
}
|
|
304
322
|
|
|
305
323
|
function __ball_double_to_string(n: number): string {
|
|
@@ -307,6 +325,16 @@ function __ball_double_to_string(n: number): string {
|
|
|
307
325
|
return n.toString();
|
|
308
326
|
}
|
|
309
327
|
|
|
328
|
+
// num.toStringAsFixed(digits). JS Number.prototype.toFixed drops the sign of
|
|
329
|
+
// -0 (returns "0.00" not "-0.00"); Dart's toStringAsFixed keeps it, matching
|
|
330
|
+
// the -0 handling __ball_to_string/BallDouble.toString already do.
|
|
331
|
+
function __ball_to_fixed(v: any, digits: any): string {
|
|
332
|
+
const n = Number(v);
|
|
333
|
+
const s = n.toFixed(digits);
|
|
334
|
+
if (n === 0 && 1 / n === -Infinity && !s.startsWith('-')) return '-' + s;
|
|
335
|
+
return s;
|
|
336
|
+
}
|
|
337
|
+
|
|
310
338
|
// Polymorphic concat / merge used for std.list_concat. The encoder emits
|
|
311
339
|
// list_concat both for Dart list concat AND for Map.addAll(...) (encoded as
|
|
312
340
|
// m = list_concat(m, other)). Arrays concat positionally; plain objects
|
|
@@ -805,7 +833,7 @@ function __ball_cascade(target: any, ops: any[]): any {
|
|
|
805
833
|
if (!_ballNp.toDouble) _ballNp.toDouble = function () { return Number(this); };
|
|
806
834
|
if (!_ballNp.clamp) _ballNp.clamp = function (lo: any, hi: any) { const n = Number(this); return n < lo ? lo : n > hi ? hi : n; };
|
|
807
835
|
if (!_ballNp.compareTo) _ballNp.compareTo = function (other: any) { const a = Number(this), b = Number(other); return a < b ? -1 : a > b ? 1 : 0; };
|
|
808
|
-
if (!_ballNp.toStringAsFixed) _ballNp.toStringAsFixed = function (digits: any) { return
|
|
836
|
+
if (!_ballNp.toStringAsFixed) _ballNp.toStringAsFixed = function (digits: any) { return __ball_to_fixed(this, digits); };
|
|
809
837
|
if (!_ballNp.remainder) _ballNp.remainder = function (other: any) { return Number(this) % Number(other); };
|
|
810
838
|
|
|
811
839
|
// Object.prototype polyfills — used by the compiled engine when
|
package/dist/preamble.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preamble.js","sourceRoot":"","sources":["../src/preamble.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"preamble.js","sourceRoot":"","sources":["../src/preamble.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+4C5C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ball-lang/compiler",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
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
|
@@ -3100,7 +3100,16 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
3100
3100
|
const name = this.resolveVarName(rawName);
|
|
3101
3101
|
// Track this declaration in the current scope.
|
|
3102
3102
|
this.scopeDeclaredVars.add(name);
|
|
3103
|
-
|
|
3103
|
+
// The encoder marks "no initializer" with a reference to the sentinel
|
|
3104
|
+
// name __no_init__ (rather than omitting `value`) — e.g. `int? maybe;`.
|
|
3105
|
+
// Left uncaught, this compiles to `let maybe = __no_init__;`, which
|
|
3106
|
+
// resolves to the runtime preamble's OWN __no_init__ Symbol (used
|
|
3107
|
+
// internally by the compiled self-hosted engine) instead of leaving
|
|
3108
|
+
// `maybe` genuinely undefined, so a later `??=` never fires (#225).
|
|
3109
|
+
// Mirrors the same check already applied to for-loop init bindings
|
|
3110
|
+
// in renderForInit.
|
|
3111
|
+
const isNoInit = stmt.let.value?.reference?.name === "__no_init__";
|
|
3112
|
+
if (stmt.let.value !== undefined && !isNoInit) {
|
|
3104
3113
|
this.writeln(`${kw} ${name} = ${this.expr(stmt.let.value)};`);
|
|
3105
3114
|
} else {
|
|
3106
3115
|
this.writeln(`${kw} ${name};`);
|
|
@@ -4592,7 +4601,17 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
4592
4601
|
} else if (fd.value) {
|
|
4593
4602
|
elems.push(fd.value);
|
|
4594
4603
|
}
|
|
4595
|
-
} else if (
|
|
4604
|
+
} else if (
|
|
4605
|
+
// A `<T>{}` empty-typed-set-literal (e.g. `<int>{}`) carries its
|
|
4606
|
+
// type argument as a field literally named "type_args" (the
|
|
4607
|
+
// encoder's current single-word convention, NOT the older
|
|
4608
|
+
// MessageCreation-level "__type_args__" cosmetic marker checked
|
|
4609
|
+
// elsewhere in this file). Excluding only "__type_args__" left
|
|
4610
|
+
// it falling through to this generic branch and being pushed in
|
|
4611
|
+
// as a bogus set ELEMENT (`<int>{}` -> `new Set(['int'])`
|
|
4612
|
+
// instead of an empty Set, #219).
|
|
4613
|
+
fd.name !== "__type_args__" && fd.name !== "__const__" && fd.name !== "type_args"
|
|
4614
|
+
) {
|
|
4596
4615
|
elems.push(fd.value);
|
|
4597
4616
|
}
|
|
4598
4617
|
}
|
|
@@ -5029,7 +5048,11 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
5029
5048
|
}
|
|
5030
5049
|
// Type ops
|
|
5031
5050
|
case "type_literal": {
|
|
5032
|
-
|
|
5051
|
+
// The encoder's canonical field is "type" (matches the Dart compiler's
|
|
5052
|
+
// _stringFieldValue(f, 'type')) — a type literal's stored value is
|
|
5053
|
+
// Type.toString() (e.g. 'int', 'List<dynamic>'), so this just needs to
|
|
5054
|
+
// evaluate to that string; == and interpolation follow for free.
|
|
5055
|
+
const v = f.get("type") ?? f.get("value") ?? f.get("name");
|
|
5033
5056
|
return v ? this.expr(v) : "null";
|
|
5034
5057
|
}
|
|
5035
5058
|
default: {
|
|
@@ -5099,7 +5122,7 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
5099
5122
|
case "to_string_as_fixed": {
|
|
5100
5123
|
const v = this.expr(fg("value", "arg0")!);
|
|
5101
5124
|
const d = this.expr(fg("digits", "arg1", "right")!);
|
|
5102
|
-
return `(
|
|
5125
|
+
return `__ball_to_fixed(${v}, ${d})`;
|
|
5103
5126
|
}
|
|
5104
5127
|
// num.{round,floor,ceil,truncate}ToDouble() → double (issue #100).
|
|
5105
5128
|
// Wrap in BallDouble so a whole result renders `4.0`, not `4`.
|
|
@@ -6376,8 +6399,14 @@ function dartInitializerToTs(
|
|
|
6376
6399
|
return defaultInitializer(tsType, rawDartType);
|
|
6377
6400
|
}
|
|
6378
6401
|
const s = dartInit.trim();
|
|
6379
|
-
// Already a JS-compatible literal: string, number, bool, null,
|
|
6380
|
-
|
|
6402
|
+
// Already a JS-compatible literal: string, number, bool, null, list.
|
|
6403
|
+
// A non-empty Dart list literal (e.g. `[10, 20, 30]`) is valid JS array
|
|
6404
|
+
// syntax as-is — this used to only match the EMPTY `[]` case, so a field
|
|
6405
|
+
// like `var widgets = [10, 20, 30];` fell through to defaultInitializer
|
|
6406
|
+
// (which has no type info to fall back on when the field's declared type
|
|
6407
|
+
// was inferred rather than explicit) and silently dropped to no
|
|
6408
|
+
// initializer at all, i.e. undefined/null (#220).
|
|
6409
|
+
if (/^(?:null|true|false|'.*'|".*"|-?\d+(?:\.\d+)?|\[[\s\S]*\])$/.test(s)) {
|
|
6381
6410
|
return s;
|
|
6382
6411
|
}
|
|
6383
6412
|
// Dart `{}` can mean either an empty Map or an empty Set depending
|
package/src/preamble.ts
CHANGED
|
@@ -110,7 +110,15 @@ class BallObject extends BallMap {
|
|
|
110
110
|
// (e.g. 42.0 not 42). Used by the compiled Dart engine's _toDouble.
|
|
111
111
|
class BallDouble {
|
|
112
112
|
readonly value: number;
|
|
113
|
-
|
|
113
|
+
// Collapse nested wrapping (new BallDouble(new BallDouble(x))) down to the
|
|
114
|
+
// innermost raw number instead of storing a BallDouble-holding-a-BallDouble.
|
|
115
|
+
// This can legitimately arise now that string_to_double's OWN compiled
|
|
116
|
+
// form already wraps its result (#222): the self-hosted engine's Dart
|
|
117
|
+
// source explicitly does BallDouble(double.parse(s)) to make the parse
|
|
118
|
+
// result double-preserving, which — once double.parse (string_to_double)
|
|
119
|
+
// started wrapping on its own — would otherwise double-wrap. Unwrapping
|
|
120
|
+
// here is idempotent for every other caller, since v is a plain number.
|
|
121
|
+
constructor(v: number) { this.value = v instanceof BallDouble ? v.value : v; }
|
|
114
122
|
valueOf(): number { return this.value; }
|
|
115
123
|
get isNaN(): boolean { return Number.isNaN(this.value); }
|
|
116
124
|
get isFinite(): boolean { return Number.isFinite(this.value); }
|
|
@@ -244,6 +252,13 @@ function __ball_to_string(v: any): string {
|
|
|
244
252
|
}
|
|
245
253
|
return '{' + parts.join(', ') + '}';
|
|
246
254
|
}
|
|
255
|
+
if (v instanceof Set) {
|
|
256
|
+
// A Set is a plain object from typeof's perspective (falls through to
|
|
257
|
+
// the generic branch below, which reads Object.keys — always [] for a
|
|
258
|
+
// Set's internal slots), so every Set printed as the empty "{}" no
|
|
259
|
+
// matter its contents until this dedicated case was added (#219).
|
|
260
|
+
return '{' + [...v].map(__ball_to_string).join(', ') + '}';
|
|
261
|
+
}
|
|
247
262
|
if (typeof v === 'object' && !Array.isArray(v)) {
|
|
248
263
|
// StringBuffer-like objects
|
|
249
264
|
if (v['__buffer__'] && Array.isArray(v['__buffer__'])) {
|
|
@@ -296,10 +311,13 @@ function __ball_to_int(v: any): any {
|
|
|
296
311
|
return t;
|
|
297
312
|
}
|
|
298
313
|
|
|
299
|
-
|
|
314
|
+
// Returns a BallDouble (not a bare number) so a whole-valued result (e.g.
|
|
315
|
+
// double.parse('7.0')) still prints "7.0", not "7" — JS numbers erase the
|
|
316
|
+
// int/double distinction that the wrapper exists to preserve (#67/#222).
|
|
317
|
+
function __ball_parse_double(s: string): BallDouble {
|
|
300
318
|
const n = parseFloat(s);
|
|
301
319
|
if (Number.isNaN(n)) throw new Error('FormatException: ' + s);
|
|
302
|
-
return n;
|
|
320
|
+
return new BallDouble(n);
|
|
303
321
|
}
|
|
304
322
|
|
|
305
323
|
function __ball_double_to_string(n: number): string {
|
|
@@ -307,6 +325,16 @@ function __ball_double_to_string(n: number): string {
|
|
|
307
325
|
return n.toString();
|
|
308
326
|
}
|
|
309
327
|
|
|
328
|
+
// num.toStringAsFixed(digits). JS Number.prototype.toFixed drops the sign of
|
|
329
|
+
// -0 (returns "0.00" not "-0.00"); Dart's toStringAsFixed keeps it, matching
|
|
330
|
+
// the -0 handling __ball_to_string/BallDouble.toString already do.
|
|
331
|
+
function __ball_to_fixed(v: any, digits: any): string {
|
|
332
|
+
const n = Number(v);
|
|
333
|
+
const s = n.toFixed(digits);
|
|
334
|
+
if (n === 0 && 1 / n === -Infinity && !s.startsWith('-')) return '-' + s;
|
|
335
|
+
return s;
|
|
336
|
+
}
|
|
337
|
+
|
|
310
338
|
// Polymorphic concat / merge used for std.list_concat. The encoder emits
|
|
311
339
|
// list_concat both for Dart list concat AND for Map.addAll(...) (encoded as
|
|
312
340
|
// m = list_concat(m, other)). Arrays concat positionally; plain objects
|
|
@@ -805,7 +833,7 @@ function __ball_cascade(target: any, ops: any[]): any {
|
|
|
805
833
|
if (!_ballNp.toDouble) _ballNp.toDouble = function () { return Number(this); };
|
|
806
834
|
if (!_ballNp.clamp) _ballNp.clamp = function (lo: any, hi: any) { const n = Number(this); return n < lo ? lo : n > hi ? hi : n; };
|
|
807
835
|
if (!_ballNp.compareTo) _ballNp.compareTo = function (other: any) { const a = Number(this), b = Number(other); return a < b ? -1 : a > b ? 1 : 0; };
|
|
808
|
-
if (!_ballNp.toStringAsFixed) _ballNp.toStringAsFixed = function (digits: any) { return
|
|
836
|
+
if (!_ballNp.toStringAsFixed) _ballNp.toStringAsFixed = function (digits: any) { return __ball_to_fixed(this, digits); };
|
|
809
837
|
if (!_ballNp.remainder) _ballNp.remainder = function (other: any) { return Number(this) % Number(other); };
|
|
810
838
|
|
|
811
839
|
// Object.prototype polyfills — used by the compiled engine when
|