@ball-lang/compiler 1.3.9 → 1.4.0

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.
@@ -177,6 +177,7 @@ export declare class BallCompiler {
177
177
  private compileLambda;
178
178
  private compileCall;
179
179
  private compileStdCall;
180
+ private compileMemoryCall;
180
181
  private typeRefMetaToString;
181
182
  private wrapWithTypeArgs;
182
183
  private emitIsCheck;
@@ -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
@@ -75,13 +75,30 @@ export class BallCompiler {
75
75
  }
76
76
  // Collect ALL non-base modules (entry + user library modules).
77
77
  const userModules = [];
78
+ let usesStdMemory = false;
78
79
  for (const mod of this.program.modules ?? []) {
79
80
  const fns = mod.functions ?? [];
80
81
  const allBase = fns.length > 0 && fns.every((f) => f.isBase);
81
- if (allBase)
82
+ if (allBase) {
83
+ if (mod.name === "std_memory")
84
+ usesStdMemory = true;
82
85
  continue;
86
+ }
83
87
  userModules.push(mod);
84
88
  }
89
+ // ── Linear memory runtime preamble ──
90
+ // If the program imports `std_memory` (linear memory simulation), inject
91
+ // the runtime variables backing the `ByteData`/`Endian` shims already
92
+ // defined in the (always-included) runtime preamble. Mirrors the Dart
93
+ // compiler's conditional injection (dart/compiler/lib/compiler.dart,
94
+ // "Linear memory runtime preamble") — only emitted when actually used.
95
+ if (usesStdMemory) {
96
+ sf.addStatements("// Ball linear memory runtime\n" +
97
+ "const _ballMemory = new ByteData(65536);\n" +
98
+ "let _ballHeapPtr = 0;\n" +
99
+ "const _ballStackFrames: number[] = [];\n" +
100
+ "let _ballStackPtr = 65536;\n");
101
+ }
85
102
  // Seed the function-name + typeDef lookup tables from ALL user modules.
86
103
  this.allFunctionNames = new Set(userModules.flatMap((m) => (m.functions ?? []).map((f) => f.name)));
87
104
  this.asyncFnNames = new Set(userModules.flatMap((m) => (m.functions ?? [])
@@ -3777,6 +3794,8 @@ function __isUnknownFnError(e: any): boolean {
3777
3794
  }
3778
3795
  compileStdCall(call) {
3779
3796
  const fn = call.function;
3797
+ if (call.module === "std_memory")
3798
+ return this.compileMemoryCall(call);
3780
3799
  const f = fieldMap(call.input?.messageCreation?.fields ?? []);
3781
3800
  const fg = (...names) => {
3782
3801
  for (const n of names) {
@@ -4679,6 +4698,175 @@ function __isUnknownFnError(e: any): boolean {
4679
4698
  }
4680
4699
  }
4681
4700
  }
4701
+ // ── std_memory → TS linear-memory compilation ──────────────────────
4702
+ //
4703
+ // Mirrors the Dart compiler's `_compileMemoryCall` (dart/compiler/lib/
4704
+ // compiler.dart): lowers std_memory base calls to a `ByteData`-backed
4705
+ // linear memory simulation. The `ByteData`/`Endian` shims live in the
4706
+ // runtime preamble (preamble.ts, "dart:typed_data shims"); `compile()`
4707
+ // conditionally emits the `_ballMemory`/`_ballHeapPtr`/`_ballStackFrames`/
4708
+ // `_ballStackPtr` runtime variables only when the program actually
4709
+ // imports `std_memory` (see `usesStdMemory` in `compile()`).
4710
+ //
4711
+ // Every std_memory base function declared in dart/shared/lib/std_memory.dart
4712
+ // MUST have a case below. An unhandled function throws a compile-time
4713
+ // Error naming it — never falls through to a bare/undefined identifier.
4714
+ compileMemoryCall(call) {
4715
+ const f = fieldMap(call.input?.messageCreation?.fields ?? []);
4716
+ const addrExpr = () => {
4717
+ const a = f.get("address") ?? f.get("dest") ?? f.get("a");
4718
+ return a ? this.expr(a) : "0";
4719
+ };
4720
+ const valExpr = () => {
4721
+ const v = f.get("value");
4722
+ return v ? this.expr(v) : "0";
4723
+ };
4724
+ // i64/u64 memory cells are backed by ByteData's bigint-typed
4725
+ // getInt64/getUint64/setInt64/setUint64 (see preamble.ts). Ball int
4726
+ // literals below Number.MAX_SAFE_INTEGER compile to plain JS `number`
4727
+ // literals (compileLiteral), so writing them straight into a
4728
+ // bigint-typed setter would throw "Cannot mix BigInt and other types"
4729
+ // at runtime — coerce explicitly.
4730
+ const valExprBigInt = () => `BigInt(${valExpr()})`;
4731
+ const ptrArith = (op) => {
4732
+ const addr = f.get("address");
4733
+ const offset = f.get("offset");
4734
+ const elemSize = f.get("element_size");
4735
+ const a = addr ? this.expr(addr) : "0";
4736
+ const o = offset ? this.expr(offset) : "0";
4737
+ const es = elemSize ? this.expr(elemSize) : "1";
4738
+ return `(${a} ${op} (${o} * ${es}))`;
4739
+ };
4740
+ switch (call.function) {
4741
+ // ── Allocation ──
4742
+ case "memory_alloc": {
4743
+ const size = f.get("size");
4744
+ const sizeStr = size ? this.expr(size) : "0";
4745
+ return `(() => { const __addr = _ballHeapPtr; _ballHeapPtr += ${sizeStr}; return __addr; })()`;
4746
+ }
4747
+ case "memory_free":
4748
+ return `(/* free(${addrExpr()}) — noop in TS */ undefined)`;
4749
+ case "memory_realloc": {
4750
+ // Bump-allocates the new block, then copies the old block's bytes
4751
+ // in (mirrors the Dart compiler's `_memRealloc`; see its doc
4752
+ // comment re: realloc semantics and issue #141).
4753
+ const addr = f.get("address") ?? f.get("value");
4754
+ const addrStr = addr ? this.expr(addr) : "0";
4755
+ const size = f.get("new_size") ?? f.get("size");
4756
+ const sizeStr = size ? this.expr(size) : "0";
4757
+ return `(() => { const __old = ${addrStr}; const __size = ${sizeStr}; ` +
4758
+ `const __addr = _ballHeapPtr; _ballHeapPtr += __size; ` +
4759
+ `let __n = __size; ` +
4760
+ `if (__old + __n > _ballMemory.lengthInBytes) { __n = _ballMemory.lengthInBytes - __old; } ` +
4761
+ `if (__addr + __n > _ballMemory.lengthInBytes) { __n = _ballMemory.lengthInBytes - __addr; } ` +
4762
+ `for (let __i = 0; __i < __n; __i++) { _ballMemory.setUint8(__addr + __i, _ballMemory.getUint8(__old + __i)); } ` +
4763
+ `return __addr; })()`;
4764
+ }
4765
+ // ── Typed reads (little-endian) ──
4766
+ case "memory_read_i8": return `_ballMemory.getInt8(${addrExpr()})`;
4767
+ case "memory_read_u8": return `_ballMemory.getUint8(${addrExpr()})`;
4768
+ case "memory_read_i16": return `_ballMemory.getInt16(${addrExpr()}, Endian.little)`;
4769
+ case "memory_read_u16": return `_ballMemory.getUint16(${addrExpr()}, Endian.little)`;
4770
+ case "memory_read_i32": return `_ballMemory.getInt32(${addrExpr()}, Endian.little)`;
4771
+ case "memory_read_u32": return `_ballMemory.getUint32(${addrExpr()}, Endian.little)`;
4772
+ case "memory_read_i64": return `_ballMemory.getInt64(${addrExpr()}, Endian.little)`;
4773
+ case "memory_read_u64": return `_ballMemory.getUint64(${addrExpr()}, Endian.little)`;
4774
+ case "memory_read_f32": return `_ballMemory.getFloat32(${addrExpr()}, Endian.little)`;
4775
+ case "memory_read_f64": return `_ballMemory.getFloat64(${addrExpr()}, Endian.little)`;
4776
+ // ── Typed writes (little-endian) ──
4777
+ case "memory_write_i8": return `_ballMemory.setInt8(${addrExpr()}, ${valExpr()})`;
4778
+ case "memory_write_u8": return `_ballMemory.setUint8(${addrExpr()}, ${valExpr()})`;
4779
+ case "memory_write_i16": return `_ballMemory.setInt16(${addrExpr()}, ${valExpr()}, Endian.little)`;
4780
+ case "memory_write_u16": return `_ballMemory.setUint16(${addrExpr()}, ${valExpr()}, Endian.little)`;
4781
+ case "memory_write_i32": return `_ballMemory.setInt32(${addrExpr()}, ${valExpr()}, Endian.little)`;
4782
+ case "memory_write_u32": return `_ballMemory.setUint32(${addrExpr()}, ${valExpr()}, Endian.little)`;
4783
+ case "memory_write_i64": return `_ballMemory.setInt64(${addrExpr()}, ${valExprBigInt()}, Endian.little)`;
4784
+ case "memory_write_u64": return `_ballMemory.setUint64(${addrExpr()}, ${valExprBigInt()}, Endian.little)`;
4785
+ case "memory_write_f32": return `_ballMemory.setFloat32(${addrExpr()}, ${valExpr()}, Endian.little)`;
4786
+ case "memory_write_f64": return `_ballMemory.setFloat64(${addrExpr()}, ${valExpr()}, Endian.little)`;
4787
+ // ── Bulk operations ──
4788
+ case "memory_copy": {
4789
+ const dest = f.get("dest"), src = f.get("src"), size = f.get("size");
4790
+ const d = dest ? this.expr(dest) : "0";
4791
+ const s = src ? this.expr(src) : "0";
4792
+ const n = size ? this.expr(size) : "0";
4793
+ return `(() => { for (let __i = 0; __i < ${n}; __i++) _ballMemory.setUint8(${d} + __i, _ballMemory.getUint8(${s} + __i)); })()`;
4794
+ }
4795
+ case "memory_set": {
4796
+ const addr = f.get("address"), val = f.get("value"), size = f.get("size");
4797
+ const a = addr ? this.expr(addr) : "0";
4798
+ const v = val ? this.expr(val) : "0";
4799
+ const n = size ? this.expr(size) : "0";
4800
+ return `(() => { for (let __i = 0; __i < ${n}; __i++) _ballMemory.setUint8(${a} + __i, ${v}); })()`;
4801
+ }
4802
+ case "memory_compare": {
4803
+ const a = f.get("a"), b = f.get("b"), size = f.get("size");
4804
+ const aStr = a ? this.expr(a) : "0";
4805
+ const bStr = b ? this.expr(b) : "0";
4806
+ const n = size ? this.expr(size) : "0";
4807
+ return `(() => { for (let __i = 0; __i < ${n}; __i++) { const __d = _ballMemory.getUint8(${aStr} + __i) - _ballMemory.getUint8(${bStr} + __i); if (__d !== 0) return __d; } return 0; })()`;
4808
+ }
4809
+ // ── Pointer arithmetic ──
4810
+ case "ptr_add": return ptrArith("+");
4811
+ case "ptr_sub": return ptrArith("-");
4812
+ case "ptr_diff": {
4813
+ const a = f.get("address"), b = f.get("offset"), elemSize = f.get("element_size");
4814
+ const aStr = a ? this.expr(a) : "0";
4815
+ const bStr = b ? this.expr(b) : "0";
4816
+ const es = elemSize ? this.expr(elemSize) : "1";
4817
+ return `Math.trunc((${aStr} - ${bStr}) / ${es})`;
4818
+ }
4819
+ // ── Stack frame ──
4820
+ case "stack_alloc": {
4821
+ const size = f.get("size");
4822
+ const sizeStr = size ? this.expr(size) : "0";
4823
+ return `(() => { _ballStackPtr -= ${sizeStr}; return _ballStackPtr; })()`;
4824
+ }
4825
+ case "stack_push_frame": return `_ballStackFrames.push(_ballStackPtr)`;
4826
+ case "stack_pop_frame": return `(_ballStackPtr = _ballStackFrames.pop()!)`;
4827
+ // ── Sizeof ──
4828
+ case "memory_sizeof": {
4829
+ const typeName = f.get("type_name")?.literal?.stringValue ?? "int";
4830
+ switch (typeName) {
4831
+ case "int8":
4832
+ case "uint8":
4833
+ case "char":
4834
+ case "bool": return "1";
4835
+ case "int16":
4836
+ case "uint16":
4837
+ case "short": return "2";
4838
+ case "int32":
4839
+ case "uint32":
4840
+ case "int":
4841
+ case "float": return "4";
4842
+ case "int64":
4843
+ case "uint64":
4844
+ case "long":
4845
+ case "double":
4846
+ case "long long": return "8";
4847
+ case "void": return "1";
4848
+ default: return "8"; // default pointer-size
4849
+ }
4850
+ }
4851
+ // ── Address-of / deref (should be resolved by normalizer) ──
4852
+ case "address_of": return `(/* address_of: ${valExpr()} */ undefined)`;
4853
+ case "deref": {
4854
+ const ptr = f.get("pointer");
4855
+ const ptrStr = ptr ? this.expr(ptr) : "0";
4856
+ // Default: read as 64-bit int (pointer-sized).
4857
+ return `_ballMemory.getInt64(${ptrStr}, Endian.little)`;
4858
+ }
4859
+ // ── Null pointer ──
4860
+ case "nullptr": return "0";
4861
+ // ── Info ──
4862
+ case "memory_heap_size": return `_ballMemory.lengthInBytes`;
4863
+ case "memory_stack_size": return `(_ballMemory.lengthInBytes - _ballStackPtr)`;
4864
+ default:
4865
+ // Fail loud (repo CLAUDE.md): never emit a bare/undefined identifier
4866
+ // for an unimplemented std_memory function.
4867
+ throw new Error(`TS compiler: std_memory.${call.function} is not implemented (compileMemoryCall)`);
4868
+ }
4869
+ }
4682
4870
  typeRefMetaToString(ref) {
4683
4871
  let s = ref?.name ?? '';
4684
4872
  const args = ref?.type_args;