@ball-lang/compiler 1.5.9 → 1.6.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 +25 -0
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +71 -3
- package/dist/compiler.js.map +1 -1
- package/dist/preamble.d.ts.map +1 -1
- package/dist/preamble.js +35 -2
- package/dist/preamble.js.map +1 -1
- package/package.json +1 -1
- package/src/compiler.ts +71 -3
- package/src/preamble.ts +35 -2
package/dist/compiler.d.ts
CHANGED
|
@@ -49,6 +49,18 @@ export declare class BallCompiler {
|
|
|
49
49
|
* the block's statements and pop it afterward.
|
|
50
50
|
*/
|
|
51
51
|
private renameStack;
|
|
52
|
+
/**
|
|
53
|
+
* Stack of `std.label` names currently enclosing the statement being
|
|
54
|
+
* compiled (see `emitLabelStmt`/`emitGotoStmt`). A `std.label` lowers to a
|
|
55
|
+
* labelled `while (true) { ... break name; }`, and a nested `std.goto`
|
|
56
|
+
* targeting one of these names lowers to `continue name;` — TS (unlike
|
|
57
|
+
* Dart's `continue` targeting a switch case, or C++'s real `goto`) only
|
|
58
|
+
* allows `continue`/`break` to target an *enclosing* labelled loop, so this
|
|
59
|
+
* only supports backward jumps to a label the goto is lexically inside of.
|
|
60
|
+
* A `goto` to any other name fails loud at compile time (see `emitGotoStmt`)
|
|
61
|
+
* rather than silently emitting invalid or wrong-behaving TS.
|
|
62
|
+
*/
|
|
63
|
+
private activeGotoLabels;
|
|
52
64
|
constructor(program: Program);
|
|
53
65
|
/** Compile to TS source. */
|
|
54
66
|
compile(options?: CompileOptions): string;
|
|
@@ -112,6 +124,19 @@ export declare class BallCompiler {
|
|
|
112
124
|
private emitForStmt;
|
|
113
125
|
private emitForInStmt;
|
|
114
126
|
private emitWhileStmt;
|
|
127
|
+
/**
|
|
128
|
+
* `std.label(name, body)` — a named jump target that `std.goto(label)`
|
|
129
|
+
* re-enters. TS has no real `goto`, so this lowers to a labelled
|
|
130
|
+
* `while (true)` loop: running the body once and falling off the end
|
|
131
|
+
* (the common case, and the only shape a `goto` targeting it can
|
|
132
|
+
* restart) matches Ball's "run once, or re-run from the top on goto"
|
|
133
|
+
* semantics, with `break name;` after the body covering the fall-off
|
|
134
|
+
* case exactly as the Dart compiler's switch-based simulation does.
|
|
135
|
+
* See `activeGotoLabels` for why only backward jumps are supported.
|
|
136
|
+
*/
|
|
137
|
+
private emitLabelStmt;
|
|
138
|
+
/** `std.goto(label)` — see `emitLabelStmt` and `activeGotoLabels`. */
|
|
139
|
+
private emitGotoStmt;
|
|
115
140
|
private emitDoWhileStmt;
|
|
116
141
|
private emitTryStmt;
|
|
117
142
|
private emitAssignStmt;
|
package/dist/compiler.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAMV,MAAM,EACN,OAAO,EAIR,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAQD,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAElC,+CAA+C;IAC/C,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,KAAK,CAAK;IAElB,4EAA4E;IAC5E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAE/C,sEAAsE;IACtE,OAAO,CAAC,YAAY,CAA0B;IAE9C,mEAAmE;IACnE,OAAO,CAAC,kBAAkB,CAA0B;IAEpD,mEAAmE;IACnE,OAAO,CAAC,mBAAmB,CAA0B;IAErD,0EAA0E;IAC1E,OAAO,CAAC,uBAAuB,CAA0B;IAEzD;0EACsE;IACtE,OAAO,CAAC,uBAAuB,CAA0B;IAEzD;;;;OAIG;IACH,OAAO,CAAC,uBAAuB,CAA0B;IAEzD,8EAA8E;IAC9E,OAAO,CAAC,gBAAgB,CAAqB;IAE7C,8EAA8E;IAC9E,OAAO,CAAC,sBAAsB,CAA0B;IAExD,yEAAyE;IACzE,OAAO,CAAC,gBAAgB,CAA0B;IAElD,4DAA4D;IAC5D,OAAO,CAAC,aAAa,CAA0C;IAE/D;;;OAGG;IACH,OAAO,CAAC,iBAAiB,CAA0B;IAEnD;;;;;OAKG;IACH,OAAO,CAAC,WAAW,CAA6B;
|
|
1
|
+
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"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"}
|
package/dist/compiler.js
CHANGED
|
@@ -58,6 +58,18 @@ export class BallCompiler {
|
|
|
58
58
|
* the block's statements and pop it afterward.
|
|
59
59
|
*/
|
|
60
60
|
renameStack = [];
|
|
61
|
+
/**
|
|
62
|
+
* Stack of `std.label` names currently enclosing the statement being
|
|
63
|
+
* compiled (see `emitLabelStmt`/`emitGotoStmt`). A `std.label` lowers to a
|
|
64
|
+
* labelled `while (true) { ... break name; }`, and a nested `std.goto`
|
|
65
|
+
* targeting one of these names lowers to `continue name;` — TS (unlike
|
|
66
|
+
* Dart's `continue` targeting a switch case, or C++'s real `goto`) only
|
|
67
|
+
* allows `continue`/`break` to target an *enclosing* labelled loop, so this
|
|
68
|
+
* only supports backward jumps to a label the goto is lexically inside of.
|
|
69
|
+
* A `goto` to any other name fails loud at compile time (see `emitGotoStmt`)
|
|
70
|
+
* rather than silently emitting invalid or wrong-behaving TS.
|
|
71
|
+
*/
|
|
72
|
+
activeGotoLabels = [];
|
|
61
73
|
constructor(program) {
|
|
62
74
|
this.program = program;
|
|
63
75
|
}
|
|
@@ -2688,7 +2700,7 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
2688
2700
|
const kinds = new Set([
|
|
2689
2701
|
"if", "for", "for_in", "for_each", "while", "do_while", "try",
|
|
2690
2702
|
"return", "break", "continue", "labeled", "throw", "rethrow",
|
|
2691
|
-
"assign", "switch", "switch_expr",
|
|
2703
|
+
"assign", "switch", "switch_expr", "label", "goto",
|
|
2692
2704
|
]);
|
|
2693
2705
|
if (!kinds.has(call.function))
|
|
2694
2706
|
return false;
|
|
@@ -2742,6 +2754,12 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
2742
2754
|
this.emitStatementOrExpression(body, false);
|
|
2743
2755
|
break;
|
|
2744
2756
|
}
|
|
2757
|
+
case "label":
|
|
2758
|
+
this.emitLabelStmt(call);
|
|
2759
|
+
break;
|
|
2760
|
+
case "goto":
|
|
2761
|
+
this.emitGotoStmt(call);
|
|
2762
|
+
break;
|
|
2745
2763
|
case "throw": {
|
|
2746
2764
|
const v = field(call, "value");
|
|
2747
2765
|
if (v) {
|
|
@@ -3008,6 +3026,44 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
3008
3026
|
this.depth--;
|
|
3009
3027
|
this.writeln(`}`);
|
|
3010
3028
|
}
|
|
3029
|
+
/**
|
|
3030
|
+
* `std.label(name, body)` — a named jump target that `std.goto(label)`
|
|
3031
|
+
* re-enters. TS has no real `goto`, so this lowers to a labelled
|
|
3032
|
+
* `while (true)` loop: running the body once and falling off the end
|
|
3033
|
+
* (the common case, and the only shape a `goto` targeting it can
|
|
3034
|
+
* restart) matches Ball's "run once, or re-run from the top on goto"
|
|
3035
|
+
* semantics, with `break name;` after the body covering the fall-off
|
|
3036
|
+
* case exactly as the Dart compiler's switch-based simulation does.
|
|
3037
|
+
* See `activeGotoLabels` for why only backward jumps are supported.
|
|
3038
|
+
*/
|
|
3039
|
+
emitLabelStmt(call) {
|
|
3040
|
+
const name = stringField(call, "name");
|
|
3041
|
+
const body = field(call, "body");
|
|
3042
|
+
if (!name || !body) {
|
|
3043
|
+
throw new Error("std.label requires a string \"name\" and a \"body\"");
|
|
3044
|
+
}
|
|
3045
|
+
this.activeGotoLabels.push(name);
|
|
3046
|
+
this.writeln(`${name}: while (true) {`);
|
|
3047
|
+
this.depth++;
|
|
3048
|
+
this.emitStatementOrExpression(body, false);
|
|
3049
|
+
this.writeln(`break ${name};`);
|
|
3050
|
+
this.depth--;
|
|
3051
|
+
this.writeln(`}`);
|
|
3052
|
+
this.activeGotoLabels.pop();
|
|
3053
|
+
}
|
|
3054
|
+
/** `std.goto(label)` — see `emitLabelStmt` and `activeGotoLabels`. */
|
|
3055
|
+
emitGotoStmt(call) {
|
|
3056
|
+
const label = stringField(call, "label");
|
|
3057
|
+
if (!label)
|
|
3058
|
+
throw new Error('std.goto requires a string "label"');
|
|
3059
|
+
if (!this.activeGotoLabels.includes(label)) {
|
|
3060
|
+
throw new Error(`std.goto("${label}") is not inside its own std.label("${label}", ...) body — ` +
|
|
3061
|
+
"the TS compiler only supports goto as a backward jump that restarts an " +
|
|
3062
|
+
"enclosing label (mirrors a labelled loop); forward jumps and jumps to a " +
|
|
3063
|
+
"sibling label are not supported (#226).");
|
|
3064
|
+
}
|
|
3065
|
+
this.writeln(`continue ${label};`);
|
|
3066
|
+
}
|
|
3011
3067
|
emitDoWhileStmt(call) {
|
|
3012
3068
|
const cond = field(call, "condition");
|
|
3013
3069
|
const body = field(call, "body");
|
|
@@ -3513,7 +3569,15 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
3513
3569
|
this.currentClassName !== undefined &&
|
|
3514
3570
|
this.currentClassFields.has(fa.field) &&
|
|
3515
3571
|
!this.currentClassMethodNames.has(fa.field);
|
|
3516
|
-
const
|
|
3572
|
+
const rawObj = isSelfRef || isSuperFieldRef ? "this" : this.expr(fa.object);
|
|
3573
|
+
// A bare numeric-literal receiver (e.g. `0`, `-4`, `123n`) parses as the
|
|
3574
|
+
// start of a float literal when immediately followed by `.field` —
|
|
3575
|
+
// `0.isNegative` is `SyntaxError: Identifier cannot follow number`.
|
|
3576
|
+
// Parenthesize whenever the compiled object text IS (not merely
|
|
3577
|
+
// contains) such a token; a double literal already compiles through
|
|
3578
|
+
// `new BallDouble(...)` and a negated int through `__ball_negate(...)`,
|
|
3579
|
+
// so both are already safe — only the bare-token case needs this.
|
|
3580
|
+
const obj = /^-?\d+n?$/.test(rawObj) ? `(${rawObj})` : rawObj;
|
|
3517
3581
|
const f = fa.field;
|
|
3518
3582
|
if (f === "length")
|
|
3519
3583
|
return `${obj}.length`;
|
|
@@ -3878,7 +3942,7 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
3878
3942
|
case "bitwise_not": return `__ball_bitnot(${this.expr(fg("value", "arg0"))})`;
|
|
3879
3943
|
case "left_shift": return `__ball_shl(${this.expr(fg("left", "value", "arg0"))}, ${this.expr(fg("right", "other", "arg1"))})`;
|
|
3880
3944
|
case "right_shift": return `__ball_shr(${this.expr(fg("left", "value", "arg0"))}, ${this.expr(fg("right", "other", "arg1"))})`;
|
|
3881
|
-
case "unsigned_right_shift": return
|
|
3945
|
+
case "unsigned_right_shift": return `__ball_ushr(${this.expr(fg("left", "value", "arg0"))}, ${this.expr(fg("right", "other", "arg1"))})`;
|
|
3882
3946
|
case "integer_divide":
|
|
3883
3947
|
return `__ball_divide(${this.expr(f.get("left"))}, ${this.expr(f.get("right"))})`;
|
|
3884
3948
|
case "concat": return bin("+");
|
|
@@ -4639,6 +4703,10 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
4639
4703
|
case "list_length": return `${this.expr(f.get("list"))}.length`;
|
|
4640
4704
|
case "list_filter": return `${this.expr(f.get("list"))}.filter(${this.expr(f.get("function") ?? f.get("callback") ?? f.get("value"))})`;
|
|
4641
4705
|
case "list_map": return `${this.expr(f.get("list"))}.map(${this.expr(f.get("function") ?? f.get("callback") ?? f.get("value"))})`;
|
|
4706
|
+
// No-seed combine (Dart's Iterable.reduce): starts at the first
|
|
4707
|
+
// element, folds from the second; empty list throws (matches JS
|
|
4708
|
+
// Array.prototype.reduce with no initialValue).
|
|
4709
|
+
case "list_reduce": return `${this.expr(f.get("list"))}.reduce(${this.expr(f.get("function") ?? f.get("callback") ?? f.get("value"))})`;
|
|
4642
4710
|
case "list_sort": {
|
|
4643
4711
|
const l = this.expr(f.get("list"));
|
|
4644
4712
|
const cmp = f.get("comparator") ?? f.get("function") ?? f.get("value");
|