I am a per-session evaluation GenServer.
Each instance corresponds to a GT view's evaluation context
(LeSharedSnippetContext). All snippets within the same view
share one Eval process (same bindings).
I track object IDs registered in GtBridge.ObjectRegistry during
my lifetime. When I terminate (session closed), I batch-remove
all tracked objects from the registry.
Cleanup
GT's BeamSessionFinalizer sends POST /SESSION_CLOSE when the
per-view GtSharedVariablesBindings is GC'd (page/inspector closed).
The router calls EvalRegistry.remove/1 which terminates me, and
terminate/2 batch-removes all tracked objects from the registry.
Summary
Functions
Returns a specification to start this module under a supervisor.
I encode an evaluation result for the wire.
I evaluate in the calling process and return the value, so the answer can travel back in the HTTP response rather than as a second message.
I drain and return all messages received by the eval process.
I return the current bindings as a map of name→serialized value. Internal bindings (:port, :command_id, :pid) are filtered out. Non-primitive values are registered in ObjectRegistry.
I return documentation for a module, function, or type.
Remove an object from the registry. Called by GT when a proxy object is garbage collected.
Types
@type t() :: %GtBridge.Eval{ bindings: Code.binding() | nil, env: Macro.Env.t() | nil, locals: [{atom(), arity()}], port: non_neg_integer(), registered_ids: MapSet.t(non_neg_integer()) }
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec complete(GenServer.server(), String.t(), String.t() | nil) :: [String.t()]
I encode an evaluation result for the wire.
I register complex values in GtBridge.ObjectRegistry and send an
%{exid, exclass} reference, so GT receives a proxy it can inspect
lazily rather than a fully materialised copy. Primitives travel by
value.
@spec eval(GenServer.server(), String.t(), String.t() | nil) :: any()
@spec eval_stateless_sync(String.t(), String.t() | nil, pos_integer() | nil) :: term()
I evaluate in the calling process and return the value, so the answer can travel back in the HTTP response rather than as a second message.
A request already runs in its own process, so running inline gives the same isolation a spawned Task would.
@spec flush() :: [term()]
I drain and return all messages received by the eval process.
Like IEx's flush/0. Useful when user code subscribes the eval
process to event brokers and you want to see what arrived.
flush()
@spec get_bindings(GenServer.server()) :: map()
I return the current bindings as a map of name→serialized value. Internal bindings (:port, :command_id, :pid) are filtered out. Non-primitive values are registered in ObjectRegistry.
I return documentation for a module, function, or type.
Bound as h in every eval session. Because I am a macro, I can
parse dot-syntax like h(Enum.map) and h(Enum.map/2).
h(Enum)
h(Enum.map)
h(Enum.map/2)
h({Enum, :map})
h({Enum, :map, 2})
@spec remove(non_neg_integer()) :: :ok
Remove an object from the registry. Called by GT when a proxy object is garbage collected.