@ball-lang/compiler 1.5.4 → 1.5.6
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 +117 -4
- package/dist/compiler.js.map +1 -1
- package/dist/preamble.d.ts.map +1 -1
- package/dist/preamble.js +43 -4
- package/dist/preamble.js.map +1 -1
- package/package.json +1 -1
- package/src/compiler.ts +109 -4
- package/src/preamble.ts +43 -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,QAk1C/B,CAAC"}
|
package/dist/preamble.js
CHANGED
|
@@ -133,8 +133,14 @@ class BallDouble {
|
|
|
133
133
|
|
|
134
134
|
// Arithmetic helpers that propagate BallDouble through operations.
|
|
135
135
|
// If either operand is BallDouble, the result is BallDouble (preserving .0).
|
|
136
|
+
//
|
|
137
|
+
// Operator-overload dispatch checks for __op_X__ methods (TRAILING double
|
|
138
|
+
// underscore) — this MUST match the Dart encoder's canonical operator naming
|
|
139
|
+
// (_canonicalOperatorName in dart/encoder/lib/encoder.dart), which always
|
|
140
|
+
// emits a trailing __. A single-underscore lookup (__op_mul) never matches,
|
|
141
|
+
// so overloaded operators silently fall through to raw JS arithmetic (#205).
|
|
136
142
|
function __ball_mul(a: any, b: any): any {
|
|
137
|
-
if (a != null && typeof a === 'object' && typeof a.
|
|
143
|
+
if (a != null && typeof a === 'object' && typeof a.__op_mul__ === 'function') return a.__op_mul__(b);
|
|
138
144
|
if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) * __to_bigint(b));
|
|
139
145
|
const av = a instanceof BallDouble ? a.value : a;
|
|
140
146
|
const bv = b instanceof BallDouble ? b.value : b;
|
|
@@ -142,7 +148,7 @@ function __ball_mul(a: any, b: any): any {
|
|
|
142
148
|
return (a instanceof BallDouble || b instanceof BallDouble) ? new BallDouble(r) : r;
|
|
143
149
|
}
|
|
144
150
|
function __ball_add(a: any, b: any): any {
|
|
145
|
-
if (a != null && typeof a === 'object' && typeof a.
|
|
151
|
+
if (a != null && typeof a === 'object' && typeof a.__op_add__ === 'function') return a.__op_add__(b);
|
|
146
152
|
if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) + __to_bigint(b));
|
|
147
153
|
const av = a instanceof BallDouble ? a.value : a;
|
|
148
154
|
const bv = b instanceof BallDouble ? b.value : b;
|
|
@@ -150,7 +156,7 @@ function __ball_add(a: any, b: any): any {
|
|
|
150
156
|
return (a instanceof BallDouble || b instanceof BallDouble) ? new BallDouble(r) : r;
|
|
151
157
|
}
|
|
152
158
|
function __ball_sub(a: any, b: any): any {
|
|
153
|
-
if (a != null && typeof a === 'object' && typeof a.
|
|
159
|
+
if (a != null && typeof a === 'object' && typeof a.__op_sub__ === 'function') return a.__op_sub__(b);
|
|
154
160
|
if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) - __to_bigint(b));
|
|
155
161
|
const av = a instanceof BallDouble ? a.value : a;
|
|
156
162
|
const bv = b instanceof BallDouble ? b.value : b;
|
|
@@ -160,7 +166,7 @@ function __ball_sub(a: any, b: any): any {
|
|
|
160
166
|
|
|
161
167
|
// Dart equality: NaN != NaN, BallDouble value comparison, null == undefined.
|
|
162
168
|
function __ball_eq(a: any, b: any): boolean {
|
|
163
|
-
if (a != null && typeof a === 'object' && typeof a.
|
|
169
|
+
if (a != null && typeof a === 'object' && typeof a.__op_eq__ === 'function') return a.__op_eq__(b);
|
|
164
170
|
if (typeof a === 'bigint' || typeof b === 'bigint') {
|
|
165
171
|
if (typeof a === 'bigint' && typeof b === 'bigint') return a === b;
|
|
166
172
|
if (typeof a === 'bigint' && typeof b === 'number') return a === BigInt(b);
|
|
@@ -178,6 +184,39 @@ function __ball_eq(a: any, b: any): boolean {
|
|
|
178
184
|
return a === b;
|
|
179
185
|
}
|
|
180
186
|
|
|
187
|
+
// Relational operator-overload dispatch (less-than/greater-than/etc.),
|
|
188
|
+
// matching the __op_add__-style convention above. Unlike arithmetic,
|
|
189
|
+
// relational comparisons had NO overload attempt at all before #205 — every
|
|
190
|
+
// overloaded Vec2 < x etc. compiled straight to raw JS comparison.
|
|
191
|
+
function __ball_lt(a: any, b: any): any {
|
|
192
|
+
if (a != null && typeof a === 'object' && typeof a.__op_lt__ === 'function') return a.__op_lt__(b);
|
|
193
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) < __to_bigint(b);
|
|
194
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
195
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
196
|
+
return av < bv;
|
|
197
|
+
}
|
|
198
|
+
function __ball_gt(a: any, b: any): any {
|
|
199
|
+
if (a != null && typeof a === 'object' && typeof a.__op_gt__ === 'function') return a.__op_gt__(b);
|
|
200
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) > __to_bigint(b);
|
|
201
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
202
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
203
|
+
return av > bv;
|
|
204
|
+
}
|
|
205
|
+
function __ball_le(a: any, b: any): any {
|
|
206
|
+
if (a != null && typeof a === 'object' && typeof a.__op_le__ === 'function') return a.__op_le__(b);
|
|
207
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) <= __to_bigint(b);
|
|
208
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
209
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
210
|
+
return av <= bv;
|
|
211
|
+
}
|
|
212
|
+
function __ball_ge(a: any, b: any): any {
|
|
213
|
+
if (a != null && typeof a === 'object' && typeof a.__op_ge__ === 'function') return a.__op_ge__(b);
|
|
214
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) >= __to_bigint(b);
|
|
215
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
216
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
217
|
+
return av >= bv;
|
|
218
|
+
}
|
|
219
|
+
|
|
181
220
|
function __ball_to_string(v: any): string {
|
|
182
221
|
if (v === null || v === undefined) return 'null';
|
|
183
222
|
if (typeof v === 'bigint') return v.toString();
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAk1C5C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ball-lang/compiler",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.6",
|
|
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
|
@@ -4245,10 +4245,13 @@ function __isUnknownFnError(e: any): boolean {
|
|
|
4245
4245
|
if (l && r) return `!__ball_eq(${this.expr(l)}, ${this.expr(r)})`;
|
|
4246
4246
|
return `!__ball_eq(${this.expr(fg("left", "value", "arg0")!)}, ${this.expr(fg("right", "other", "arg1")!)})`;
|
|
4247
4247
|
}
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
case "
|
|
4248
|
+
// Relational comparisons route through __ball_lt/__ball_gt/__ball_le/__ball_ge
|
|
4249
|
+
// so operator-overloaded types (e.g. a class defining `<`) dispatch to
|
|
4250
|
+
// their `__op_lt__`-style method instead of raw JS comparison (#205).
|
|
4251
|
+
case "less_than": return `__ball_lt(${this.expr(fg("left", "value", "arg0")!)}, ${this.expr(fg("right", "other", "arg1")!)})`;
|
|
4252
|
+
case "greater_than": return `__ball_gt(${this.expr(fg("left", "value", "arg0")!)}, ${this.expr(fg("right", "other", "arg1")!)})`;
|
|
4253
|
+
case "lte": return `__ball_le(${this.expr(fg("left", "value", "arg0")!)}, ${this.expr(fg("right", "other", "arg1")!)})`;
|
|
4254
|
+
case "gte": return `__ball_ge(${this.expr(fg("left", "value", "arg0")!)}, ${this.expr(fg("right", "other", "arg1")!)})`;
|
|
4252
4255
|
// Logical
|
|
4253
4256
|
case "and": return bin("&&");
|
|
4254
4257
|
case "or": return bin("||");
|
|
@@ -5870,6 +5873,12 @@ const KNOWN_PATTERN_KINDS = new Set([
|
|
|
5870
5873
|
"ConstPattern", "VarPattern", "var", "WildcardPattern", "wildcard", "_",
|
|
5871
5874
|
"ListPattern", "RestPattern", "rest", "record", "RecordPattern",
|
|
5872
5875
|
"LogicalOrPattern", "CastPattern", "NullCheckPattern", "NullAssertPattern",
|
|
5876
|
+
// MapPattern/LogicalAndPattern/ObjectPattern/RelationalPattern were missing
|
|
5877
|
+
// (#206, #207) — every pattern kind the encoder can emit (see
|
|
5878
|
+
// dart/encoder/lib/encoder.dart's `_encodePattern`) must be listed here, or
|
|
5879
|
+
// it falls to the legacy cosmetic-text parser, which cannot round-trip
|
|
5880
|
+
// `final`-bound entries and other structured shapes.
|
|
5881
|
+
"MapPattern", "LogicalAndPattern", "ObjectPattern", "RelationalPattern",
|
|
5873
5882
|
]);
|
|
5874
5883
|
|
|
5875
5884
|
/** Generate a JS type-check condition for a Dart type name against `subject`.
|
|
@@ -5960,6 +5969,102 @@ function compileStructuredPattern(
|
|
|
5960
5969
|
}
|
|
5961
5970
|
return undefined;
|
|
5962
5971
|
}
|
|
5972
|
+
case "LogicalAndPattern": {
|
|
5973
|
+
// `p1 && p2` matches only if BOTH alternatives match against the SAME
|
|
5974
|
+
// subject (Dart's guard-combinator syntax, e.g. `int n && > 0`). Mirrors
|
|
5975
|
+
// LogicalOrPattern but ANDs the conditions instead of ORing them; bindings
|
|
5976
|
+
// from both sides are unioned (in practice the right operand of a
|
|
5977
|
+
// relational combinator binds nothing). Falls through (undefined) if
|
|
5978
|
+
// either operand isn't structured.
|
|
5979
|
+
const left = fields.get("left");
|
|
5980
|
+
const right = fields.get("right");
|
|
5981
|
+
if (left && right) {
|
|
5982
|
+
const lr = compileStructuredPattern(left, subject, exprFn);
|
|
5983
|
+
const rr = compileStructuredPattern(right, subject, exprFn);
|
|
5984
|
+
if (lr && rr) {
|
|
5985
|
+
return {
|
|
5986
|
+
condition: `(${lr.condition} && ${rr.condition})`,
|
|
5987
|
+
bindings: [...lr.bindings, ...rr.bindings],
|
|
5988
|
+
};
|
|
5989
|
+
}
|
|
5990
|
+
}
|
|
5991
|
+
return undefined;
|
|
5992
|
+
}
|
|
5993
|
+
case "RelationalPattern": {
|
|
5994
|
+
// `== x` / `!= x` / `> x` / `< x` / `>= x` / `<= x` as a standalone
|
|
5995
|
+
// (or LogicalAndPattern-combined) pattern. Numeric comparisons require
|
|
5996
|
+
// BOTH the subject and operand to be `num` (mirrors engine_std.dart's
|
|
5997
|
+
// `_matchRelationalPattern`) — a non-numeric subject simply fails to
|
|
5998
|
+
// match rather than throwing.
|
|
5999
|
+
const op = fields.get("operator")?.literal?.stringValue;
|
|
6000
|
+
const operandExpr = fields.get("operand");
|
|
6001
|
+
if (!op || !operandExpr) return { condition: "true", bindings: [] };
|
|
6002
|
+
const operandStr = exprFn(operandExpr);
|
|
6003
|
+
if (op === "==") return { condition: `__ball_eq(${subject}, ${operandStr})`, bindings: [] };
|
|
6004
|
+
if (op === "!=") return { condition: `(!__ball_eq(${subject}, ${operandStr}))`, bindings: [] };
|
|
6005
|
+
const isNum = (v: string) => `(typeof (${v}) === 'number' || (${v}) instanceof BallDouble)`;
|
|
6006
|
+
const numVal = (v: string) => `((${v}) instanceof BallDouble ? (${v}).value : (${v}))`;
|
|
6007
|
+
return {
|
|
6008
|
+
condition: `(${isNum(subject)} && ${isNum(operandStr)} && (${numVal(subject)} ${op} ${numVal(operandStr)}))`,
|
|
6009
|
+
bindings: [],
|
|
6010
|
+
};
|
|
6011
|
+
}
|
|
6012
|
+
case "MapPattern": {
|
|
6013
|
+
// `{'key': subpattern, ...}`. Ball maps compile to a plain JS object for
|
|
6014
|
+
// the common `map_create` path (bracket access, e.g. `{'k': 7}`) but to a
|
|
6015
|
+
// native `Map` for the `typed_map` path (`<K,V>{}` / `Map()`) — both
|
|
6016
|
+
// representations must match. A Ball Set compiles to a native `Set`
|
|
6017
|
+
// (set_create), which IS `typeof 'object'` and not an array, so it must
|
|
6018
|
+
// be explicitly excluded (issue #178's "MapPattern must exclude Set").
|
|
6019
|
+
// Extra keys beyond the ones listed are fine (unlike RecordPattern's
|
|
6020
|
+
// exact-arity rule) — mirrors engine_std.dart's 'map' case.
|
|
6021
|
+
const entries = fields.get("entries")?.literal?.listValue?.elements ?? [];
|
|
6022
|
+
const conds: string[] = [
|
|
6023
|
+
`(typeof ${subject} === 'object' && ${subject} !== null && !Array.isArray(${subject}) && !(${subject} instanceof Set))`,
|
|
6024
|
+
];
|
|
6025
|
+
const binds: Array<{ varName: string; expr: string }> = [];
|
|
6026
|
+
for (const entry of entries) {
|
|
6027
|
+
const ef = mcFields(entry);
|
|
6028
|
+
const keyExpr = ef.get("key");
|
|
6029
|
+
const valuePattern = ef.get("value");
|
|
6030
|
+
if (!keyExpr) continue;
|
|
6031
|
+
const keyStr = exprFn(keyExpr);
|
|
6032
|
+
conds.push(`(${subject} instanceof Map ? ${subject}.has(${keyStr}) : (${keyStr} in ${subject}))`);
|
|
6033
|
+
if (valuePattern) {
|
|
6034
|
+
const valueExpr = `(${subject} instanceof Map ? ${subject}.get(${keyStr}) : ${subject}[${keyStr}])`;
|
|
6035
|
+
const sub = compileStructuredPattern(valuePattern, valueExpr, exprFn);
|
|
6036
|
+
if (sub) {
|
|
6037
|
+
if (sub.condition !== "true") conds.push(sub.condition);
|
|
6038
|
+
binds.push(...sub.bindings);
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
}
|
|
6042
|
+
return { condition: conds.join(" && "), bindings: binds };
|
|
6043
|
+
}
|
|
6044
|
+
case "ObjectPattern": {
|
|
6045
|
+
// `Type(field: subpattern, ...)` matches by TYPE (reusing the same
|
|
6046
|
+
// instanceof/`__type__` gate CastPattern relies on via typeCheckCondition)
|
|
6047
|
+
// plus each named field's GETTER against its sub-pattern — field access,
|
|
6048
|
+
// not positional arity (mirrors engine_std.dart's 'object' case, which
|
|
6049
|
+
// reads `objMap[fieldName]` rather than requiring an exact key set).
|
|
6050
|
+
const typeName = fields.get("type")?.literal?.stringValue;
|
|
6051
|
+
const objFields = fields.get("fields")?.literal?.listValue?.elements ?? [];
|
|
6052
|
+
const conds: string[] = [];
|
|
6053
|
+
if (typeName) conds.push(typeCheckCondition(typeName, subject));
|
|
6054
|
+
const binds: Array<{ varName: string; expr: string }> = [];
|
|
6055
|
+
for (const of_ of objFields) {
|
|
6056
|
+
const ofFields = mcFields(of_);
|
|
6057
|
+
const fieldName = ofFields.get("name")?.literal?.stringValue;
|
|
6058
|
+
const fieldPattern = ofFields.get("pattern");
|
|
6059
|
+
if (!fieldName || !fieldPattern) continue;
|
|
6060
|
+
const sub = compileStructuredPattern(fieldPattern, `${subject}.${fieldName}`, exprFn);
|
|
6061
|
+
if (sub) {
|
|
6062
|
+
if (sub.condition !== "true") conds.push(sub.condition);
|
|
6063
|
+
binds.push(...sub.bindings);
|
|
6064
|
+
}
|
|
6065
|
+
}
|
|
6066
|
+
return { condition: conds.length > 0 ? conds.join(" && ") : "true", bindings: binds };
|
|
6067
|
+
}
|
|
5963
6068
|
case "CastPattern": {
|
|
5964
6069
|
// A cast pattern (subpat as T) ASSERTS the runtime type — it matches
|
|
5965
6070
|
// structurally (like its sub-pattern) but THROWS on a mismatch (Dart
|
package/src/preamble.ts
CHANGED
|
@@ -133,8 +133,14 @@ class BallDouble {
|
|
|
133
133
|
|
|
134
134
|
// Arithmetic helpers that propagate BallDouble through operations.
|
|
135
135
|
// If either operand is BallDouble, the result is BallDouble (preserving .0).
|
|
136
|
+
//
|
|
137
|
+
// Operator-overload dispatch checks for __op_X__ methods (TRAILING double
|
|
138
|
+
// underscore) — this MUST match the Dart encoder's canonical operator naming
|
|
139
|
+
// (_canonicalOperatorName in dart/encoder/lib/encoder.dart), which always
|
|
140
|
+
// emits a trailing __. A single-underscore lookup (__op_mul) never matches,
|
|
141
|
+
// so overloaded operators silently fall through to raw JS arithmetic (#205).
|
|
136
142
|
function __ball_mul(a: any, b: any): any {
|
|
137
|
-
if (a != null && typeof a === 'object' && typeof a.
|
|
143
|
+
if (a != null && typeof a === 'object' && typeof a.__op_mul__ === 'function') return a.__op_mul__(b);
|
|
138
144
|
if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) * __to_bigint(b));
|
|
139
145
|
const av = a instanceof BallDouble ? a.value : a;
|
|
140
146
|
const bv = b instanceof BallDouble ? b.value : b;
|
|
@@ -142,7 +148,7 @@ function __ball_mul(a: any, b: any): any {
|
|
|
142
148
|
return (a instanceof BallDouble || b instanceof BallDouble) ? new BallDouble(r) : r;
|
|
143
149
|
}
|
|
144
150
|
function __ball_add(a: any, b: any): any {
|
|
145
|
-
if (a != null && typeof a === 'object' && typeof a.
|
|
151
|
+
if (a != null && typeof a === 'object' && typeof a.__op_add__ === 'function') return a.__op_add__(b);
|
|
146
152
|
if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) + __to_bigint(b));
|
|
147
153
|
const av = a instanceof BallDouble ? a.value : a;
|
|
148
154
|
const bv = b instanceof BallDouble ? b.value : b;
|
|
@@ -150,7 +156,7 @@ function __ball_add(a: any, b: any): any {
|
|
|
150
156
|
return (a instanceof BallDouble || b instanceof BallDouble) ? new BallDouble(r) : r;
|
|
151
157
|
}
|
|
152
158
|
function __ball_sub(a: any, b: any): any {
|
|
153
|
-
if (a != null && typeof a === 'object' && typeof a.
|
|
159
|
+
if (a != null && typeof a === 'object' && typeof a.__op_sub__ === 'function') return a.__op_sub__(b);
|
|
154
160
|
if (typeof a === 'bigint' || typeof b === 'bigint') return __i64_wrap(__to_bigint(a) - __to_bigint(b));
|
|
155
161
|
const av = a instanceof BallDouble ? a.value : a;
|
|
156
162
|
const bv = b instanceof BallDouble ? b.value : b;
|
|
@@ -160,7 +166,7 @@ function __ball_sub(a: any, b: any): any {
|
|
|
160
166
|
|
|
161
167
|
// Dart equality: NaN != NaN, BallDouble value comparison, null == undefined.
|
|
162
168
|
function __ball_eq(a: any, b: any): boolean {
|
|
163
|
-
if (a != null && typeof a === 'object' && typeof a.
|
|
169
|
+
if (a != null && typeof a === 'object' && typeof a.__op_eq__ === 'function') return a.__op_eq__(b);
|
|
164
170
|
if (typeof a === 'bigint' || typeof b === 'bigint') {
|
|
165
171
|
if (typeof a === 'bigint' && typeof b === 'bigint') return a === b;
|
|
166
172
|
if (typeof a === 'bigint' && typeof b === 'number') return a === BigInt(b);
|
|
@@ -178,6 +184,39 @@ function __ball_eq(a: any, b: any): boolean {
|
|
|
178
184
|
return a === b;
|
|
179
185
|
}
|
|
180
186
|
|
|
187
|
+
// Relational operator-overload dispatch (less-than/greater-than/etc.),
|
|
188
|
+
// matching the __op_add__-style convention above. Unlike arithmetic,
|
|
189
|
+
// relational comparisons had NO overload attempt at all before #205 — every
|
|
190
|
+
// overloaded Vec2 < x etc. compiled straight to raw JS comparison.
|
|
191
|
+
function __ball_lt(a: any, b: any): any {
|
|
192
|
+
if (a != null && typeof a === 'object' && typeof a.__op_lt__ === 'function') return a.__op_lt__(b);
|
|
193
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) < __to_bigint(b);
|
|
194
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
195
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
196
|
+
return av < bv;
|
|
197
|
+
}
|
|
198
|
+
function __ball_gt(a: any, b: any): any {
|
|
199
|
+
if (a != null && typeof a === 'object' && typeof a.__op_gt__ === 'function') return a.__op_gt__(b);
|
|
200
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) > __to_bigint(b);
|
|
201
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
202
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
203
|
+
return av > bv;
|
|
204
|
+
}
|
|
205
|
+
function __ball_le(a: any, b: any): any {
|
|
206
|
+
if (a != null && typeof a === 'object' && typeof a.__op_le__ === 'function') return a.__op_le__(b);
|
|
207
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) <= __to_bigint(b);
|
|
208
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
209
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
210
|
+
return av <= bv;
|
|
211
|
+
}
|
|
212
|
+
function __ball_ge(a: any, b: any): any {
|
|
213
|
+
if (a != null && typeof a === 'object' && typeof a.__op_ge__ === 'function') return a.__op_ge__(b);
|
|
214
|
+
if (typeof a === 'bigint' || typeof b === 'bigint') return __to_bigint(a) >= __to_bigint(b);
|
|
215
|
+
const av = a instanceof BallDouble ? a.value : a;
|
|
216
|
+
const bv = b instanceof BallDouble ? b.value : b;
|
|
217
|
+
return av >= bv;
|
|
218
|
+
}
|
|
219
|
+
|
|
181
220
|
function __ball_to_string(v: any): string {
|
|
182
221
|
if (v === null || v === undefined) return 'null';
|
|
183
222
|
if (typeof v === 'bigint') return v.toString();
|