Host Environment
Inject script-visible time, time-zone, and random providers without changing infrastructure clocks.
Executive Summary
- Every engine owns a
TGocciaHostEnvironmentthat supplies JavaScript-visible wall time, monotonic time, default time zone, and randomness. - Pascal embedders inject implementations of
IGocciaHostClockandIGocciaHostRandombefore attaching runtime extensions or executing source. GocciaScriptLoader --host-environment=<module>accepts the same providers as callable named JavaScript exports.- Child engines share the clock and receive derived random stream identifiers, so realms remain reproducible without replaying the parent stream.
- Timeouts, profiling, benchmarks, and other infrastructure continue to use the real clocks in
TimingUtils.
JavaScript Provider Modules
Pass a module with four callable named exports:
export const epochNanoseconds = () => 1700000000000000000n;export const monotonicNanoseconds = () => 0n;export const timeZoneIdentifier = () => "UTC";export const random = (streamId) => streamId === 0n ? 0.25 : 0.75;
Then run a script with the provider:
./build/GocciaScriptLoader app.js \--host-environment=./examples/custom-host-environment.js
The epoch and monotonic callbacks must return either an Int64-range BigInt or a safe integer Number. The time-zone callback must return a supported identifier. The random callback must return a finite Number in the interval [0, 1).
streamId is an opaque BigInt. The initial engine receives 0n; child engines receive derived identifiers. Providers that maintain random state should key it by this value, as shown in the complete example.
The provider module is evaluated after file loading is available but before the loader runtime profile extensions attach. Its exported callbacks remain rooted for the engine lifetime. A provider callback must not recursively read the source it supplies—for example, random must not call Math.random(), and a clock callback must not call Date.now().
--host-environment and --deterministic are mutually exclusive. The equivalent configuration-file key is "host-environment".
Pascal Embedders
Implement the two narrow provider interfaces and configure the engine before attaching runtime extensions or executing JavaScript:
typeTApplicationClock = class(TInterfacedObject, IGocciaHostClock)publicfunction EpochNanoseconds: Int64;function MonotonicNanoseconds: Int64;function TimeZoneIdentifier: string;end;TApplicationRandom = class(TInterfacedObject, IGocciaHostRandom)privateFState: QWord;publicconstructor Create(const ASeed: QWord);function NextDouble: Double;function Fork(const AStreamId: QWord): IGocciaHostRandom;end;Engine := TGocciaEngine.Create('app.js', Source, Executor);Engine.HostEnvironment.Configure(TApplicationClock.Create,TApplicationRandom.Create(Seed));AttachRuntime(Engine);Engine.Execute;
Fork must return a distinct random stream derived from both the provider's current stream identity and AStreamId. The engine shares the clock with child engines because wall and monotonic time belong to the host, while random state is isolated per child.
For a fixed built-in profile, call Engine.HostEnvironment.UseDeterministicProfile instead of implementing providers. It supplies epoch and monotonic time 0, UTC, and portable seeded SplitMix64 randomness.
Default Compatibility
Without an explicit provider, the system host environment preserves each API's established default behavior. Temporal and Date observe the system time zone; Intl.DateTimeFormat retains GocciaScript's historical UTC default. An explicitly configured host time zone overrides both surfaces.