@ball-lang/compiler 1.7.5 → 1.7.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"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"}
package/dist/compiler.js CHANGED
@@ -4160,8 +4160,14 @@ function __isUnknownFnError(e: any): boolean {
4160
4160
  case "null_aware_call": {
4161
4161
  const target = f.get("target");
4162
4162
  const method = f.get("method");
4163
- if (!target || !method)
4164
- return "/* null_aware_call missing */";
4163
+ // A bare `/* ... */` comment used to stand in for the missing
4164
+ // field context-dependent behavior (silently becomes `undefined`
4165
+ // in return position, a hard-to-diagnose SyntaxError mid-expression)
4166
+ // instead of a clear compile-time error naming the malformed call
4167
+ // (#257).
4168
+ if (!target || !method) {
4169
+ throw new Error("TS compiler: null_aware_call requires a \"target\" and a \"method\" field");
4170
+ }
4165
4171
  const methodName = method.literal?.stringValue ?? "";
4166
4172
  const inputFields = call.input?.messageCreation?.fields ?? [];
4167
4173
  const otherArgs = inputFields
@@ -4173,15 +4179,17 @@ function __isUnknownFnError(e: any): boolean {
4173
4179
  case "null_aware_index": {
4174
4180
  const self_ = f.get("self") ?? f.get("target");
4175
4181
  const idx = f.get("index") ?? f.get("key");
4176
- if (!self_ || !idx)
4177
- return "/* null_aware_index missing */";
4182
+ if (!self_ || !idx) {
4183
+ throw new Error("TS compiler: null_aware_index requires a \"self\"/\"target\" and an \"index\"/\"key\" field");
4184
+ }
4178
4185
  return `${this.expr(self_)}[${this.expr(idx)}]`;
4179
4186
  }
4180
4187
  case "null_aware_access": {
4181
4188
  const target = f.get("target");
4182
4189
  const fieldE = f.get("field");
4183
- if (!target || !fieldE)
4184
- return "/* null_aware_access missing */";
4190
+ if (!target || !fieldE) {
4191
+ throw new Error("TS compiler: null_aware_access requires a \"target\" and a \"field\" field");
4192
+ }
4185
4193
  return `${this.expr(target)}?.${fieldE.literal?.stringValue ?? ""}`;
4186
4194
  }
4187
4195
  case "typed_list": {
@@ -4203,14 +4211,19 @@ function __isUnknownFnError(e: any): boolean {
4203
4211
  return "new Map()";
4204
4212
  const pairs = [];
4205
4213
  for (const e of entryExprs) {
4206
- if (e.messageCreation) {
4207
- const mc = e.messageCreation;
4208
- const mFields = mc.fields ?? [];
4209
- const k = mFields.find((fd) => fd.name === "key")?.value;
4210
- const v = mFields.find((fd) => fd.name === "value")?.value;
4211
- if (k && v)
4212
- pairs.push(`[${this.expr(k)}, ${this.expr(v)}]`);
4214
+ // A malformed entry (not a messageCreation, or missing key/value)
4215
+ // used to be silently dropped from the resulting Map instead of
4216
+ // surfaced fail loud on the malformed IR instead (#257).
4217
+ if (!e.messageCreation) {
4218
+ throw new Error("TS compiler: typed_map entry is not a key/value messageCreation");
4219
+ }
4220
+ const mFields = e.messageCreation.fields ?? [];
4221
+ const k = mFields.find((fd) => fd.name === "key")?.value;
4222
+ const v = mFields.find((fd) => fd.name === "value")?.value;
4223
+ if (!k || !v) {
4224
+ throw new Error("TS compiler: typed_map entry is missing \"key\" or \"value\"");
4213
4225
  }
4226
+ pairs.push(`[${this.expr(k)}, ${this.expr(v)}]`);
4214
4227
  }
4215
4228
  return `new Map([${pairs.join(", ")}])`;
4216
4229
  }
@@ -4567,8 +4580,11 @@ function __isUnknownFnError(e: any): boolean {
4567
4580
  case "map_get": {
4568
4581
  const map = f.get("map");
4569
4582
  const key = f.get("key");
4583
+ // __ball_require_map fails loud on a non-Map instead of silently
4584
+ // returning undefined via bare bracket access (#257, same family
4585
+ // as #218's map_keys/map_values/map_entries).
4570
4586
  if (map && key)
4571
- return `${this.expr(map)}[${this.expr(key)}]`;
4587
+ return `__ball_require_map(${this.expr(map)}, 'map_get')[${this.expr(key)}]`;
4572
4588
  return "undefined";
4573
4589
  }
4574
4590
  case "map_set": {
@@ -4576,14 +4592,17 @@ function __isUnknownFnError(e: any): boolean {
4576
4592
  const key = f.get("key");
4577
4593
  const value = f.get("value");
4578
4594
  if (map && key && value)
4579
- return `(${this.expr(map)}[${this.expr(key)}] = ${this.expr(value)})`;
4595
+ return `(__ball_require_map(${this.expr(map)}, 'map_set')[${this.expr(key)}] = ${this.expr(value)})`;
4580
4596
  return "undefined";
4581
4597
  }
4582
4598
  case "map_contains_key": {
4583
4599
  const map = f.get("map");
4584
4600
  const key = f.get("key");
4601
+ // `in` throws for a primitive receiver already, but not for a List
4602
+ // (checks index membership instead of throwing "not a map") — the
4603
+ // require-map guard closes that gap (#257).
4585
4604
  if (map && key)
4586
- return `(${this.expr(key)} in ${this.expr(map)})`;
4605
+ return `(${this.expr(key)} in __ball_require_map(${this.expr(map)}, 'map_contains_key'))`;
4587
4606
  return "false";
4588
4607
  }
4589
4608
  case "map_keys": {
@@ -4608,25 +4627,27 @@ function __isUnknownFnError(e: any): boolean {
4608
4627
  }
4609
4628
  case "map_length": {
4610
4629
  const map = f.get("map") ?? f.get("value");
4611
- return map ? `Object.keys(${this.expr(map)}).length` : "0";
4630
+ return map ? `Object.keys(__ball_require_map(${this.expr(map)}, 'map_length')).length` : "0";
4612
4631
  }
4613
4632
  case "map_is_empty": {
4614
4633
  const map = f.get("map") ?? f.get("value");
4615
- return map ? `(Object.keys(${this.expr(map)}).length === 0)` : "true";
4634
+ return map ? `(Object.keys(__ball_require_map(${this.expr(map)}, 'map_is_empty')).length === 0)` : "true";
4616
4635
  }
4617
4636
  case "map_delete":
4618
4637
  case "map_remove": {
4619
4638
  const map = f.get("map");
4620
4639
  const key = f.get("key");
4621
4640
  if (map && key)
4622
- return `(() => { const __m = ${this.expr(map)}; const __k = ${this.expr(key)}; const __v = __m[__k]; delete __m[__k]; return __v; })()`;
4641
+ return `(() => { const __m = __ball_require_map(${this.expr(map)}, 'map_delete'); const __k = ${this.expr(key)}; const __v = __m[__k]; delete __m[__k]; return __v; })()`;
4623
4642
  return "undefined";
4624
4643
  }
4625
4644
  case "map_merge": {
4626
4645
  const l = f.get("left") ?? f.get("map");
4627
4646
  const r = f.get("right") ?? f.get("other");
4647
+ // Spreading a non-object silently produces {} (or a partial merge)
4648
+ // instead of throwing — same class as the other map_* guards (#257).
4628
4649
  if (l && r)
4629
- return `{...${this.expr(l)}, ...${this.expr(r)}}`;
4650
+ return `{...__ball_require_map(${this.expr(l)}, 'map_merge'), ...__ball_require_map(${this.expr(r)}, 'map_merge')}`;
4630
4651
  return "{}";
4631
4652
  }
4632
4653
  case "map_from_entries": {
@@ -4644,6 +4665,14 @@ function __isUnknownFnError(e: any): boolean {
4644
4665
  return `${this.expr(list)}.join('')`;
4645
4666
  return "''";
4646
4667
  }
4668
+ // Neither encoder ever emits these as a direct `std.<fn>` base-
4669
+ // function call — a Set method call (mySet.union(other), etc.)
4670
+ // routes through compileCall's generic "self"-field method dispatch
4671
+ // onto native JS Set.prototype methods instead, so this case is
4672
+ // never actually reached. The old fallback compiled it to a call on
4673
+ // a nonexistent bare identifier (a confusing runtime ReferenceError
4674
+ // if it WERE ever hit); fail loud at compile time instead, matching
4675
+ // the policy above (#257).
4647
4676
  case "set_add":
4648
4677
  case "set_remove":
4649
4678
  case "set_contains":
@@ -4652,11 +4681,8 @@ function __isUnknownFnError(e: any): boolean {
4652
4681
  case "set_difference":
4653
4682
  case "set_length":
4654
4683
  case "set_is_empty":
4655
- case "set_to_list": {
4656
- const allFields = call.input?.messageCreation?.fields ?? [];
4657
- const args = allFields.map((fd) => this.expr(fd.value)).join(", ");
4658
- return `/* std.${fn} */ ${sanitize(fn)}(${args})`;
4659
- }
4684
+ case "set_to_list":
4685
+ throw new Error(`TS compiler: std.${fn} is not implemented (compileStdCall) — Set method calls should route through native JS Set methods, not this base function`);
4660
4686
  // I/O
4661
4687
  case "print_error": {
4662
4688
  const msg = f.get("message") ?? f.get("value");
@@ -4765,7 +4791,10 @@ function __isUnknownFnError(e: any): boolean {
4765
4791
  // match first and any duplicate entry here would be genuinely
4766
4792
  // unreachable dead code. Removed (#62 Phase-2c); only cases with
4767
4793
  // no outer-switch equivalent belong in this fallback.
4768
- case "map_contains_value": return `Object.values(${this.expr(f.get("map"))}).includes(${this.expr(f.get("value"))})`;
4794
+ // Same silent-degradation class as map_keys/map_values/map_entries
4795
+ // (#218) — the sibling case that fix missed, since it lives in
4796
+ // this SECOND nested switch under a different function name (#257).
4797
+ case "map_contains_value": return `Object.values(__ball_require_map(${this.expr(f.get("map"))}, 'map_contains_value')).includes(${this.expr(f.get("value"))})`;
4769
4798
  case "list_insert": return `(${this.expr(f.get("list"))}.splice(${this.expr(f.get("index"))}, 0, ${this.expr(f.get("value"))}), ${this.expr(f.get("list"))})`;
4770
4799
  case "list_remove_at": return `${this.expr(f.get("list"))}.splice(${this.expr(f.get("index"))}, 1)[0]`;
4771
4800
  case "list_clear": return `(${this.expr(f.get("list"))}.length = 0, ${this.expr(f.get("list"))})`;
@@ -4793,7 +4822,7 @@ function __isUnknownFnError(e: any): boolean {
4793
4822
  case "map_foreach": {
4794
4823
  const map = this.expr(f.get("map") ?? f.get("value"));
4795
4824
  const cb = this.expr(f.get("function") ?? f.get("callback") ?? f.get("value"));
4796
- return `Object.entries(${map}).forEach(([k, v]) => ${cb}(k, v))`;
4825
+ return `Object.entries(__ball_require_map(${map}, 'map_foreach')).forEach(([k, v]) => ${cb}(k, v))`;
4797
4826
  }
4798
4827
  case "list_reversed": return `[...${this.expr(f.get("list"))}].reverse()`;
4799
4828
  case "compare_to": {
@@ -4860,10 +4889,16 @@ function __isUnknownFnError(e: any): boolean {
4860
4889
  const body = this.emitCollectionElement({ call }, "list", "__r");
4861
4890
  return `(() => { const __r: any[] = []; ${body} return __r; })()`;
4862
4891
  }
4863
- default: {
4864
- const args = Array.from(f.values()).map((e) => this.expr(e)).join(", ");
4865
- return `/* std.${fn} */ ${sanitize(fn)}(${args})`;
4866
- }
4892
+ default:
4893
+ // Fail loud (repo CLAUDE.md): never emit a bare/undefined
4894
+ // identifier for an unimplemented std function — mirrors
4895
+ // compileMemoryCall's rule above. The old
4896
+ // `/* std.${fn} */ ${sanitize(fn)}(${args})` fallback compiled
4897
+ // to a call on a nonexistent identifier, deferring the failure
4898
+ // to a confusing runtime ReferenceError instead of a clear
4899
+ // compile-time error naming the actual unimplemented function
4900
+ // (#257).
4901
+ throw new Error(`TS compiler: std.${fn} is not implemented (compileStdCall)`);
4867
4902
  }
4868
4903
  }
4869
4904
  }