Packages
livebook
0.14.0-rc.1
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Current section
Files
Jump to
Current section
Files
lib/livebook/runtime/evaluator/tracer.ex
defmodule Livebook.Runtime.Evaluator.Tracer do
# Compilation tracer used by the evaluator.
#
# Events are pre-processed and sent to the group leader, where the
# tracer state is accumulated. After evaluation the evaluator reads
# the accumulated state.
alias Livebook.Runtime.Evaluator
defstruct modules_used: MapSet.new(),
modules_defined: %{},
aliases_used: MapSet.new(),
aliases_defined: %{},
requires_used: MapSet.new(),
requires_defined: MapSet.new(),
imports_used?: false,
imports_defined?: false
@type t :: %__MODULE__{
modules_used: MapSet.t(),
modules_defined: map(),
aliases_used: MapSet.t(),
aliases_defined: map(),
requires_used: MapSet.t(),
requires_defined: MapSet.t(),
imports_used?: boolean(),
imports_defined?: boolean()
}
@doc false
def trace(event, env) do
case event_to_updates(event, env) do
[] ->
:ok
updates ->
io_proxy = Process.group_leader()
Evaluator.IOProxy.tracer_updates(io_proxy, updates)
end
:ok
end
defp event_to_updates(event, env) do
# Note that import/require/alias/defmodule don't trigger `:alias_reference`
# for the used alias, so we add it explicitly
case event do
:start ->
if Code.ensure_loaded?(env.module) do
raise CompileError,
line: env.line,
file: env.file,
description: "module #{inspect(env.module)} is already defined"
end
[]
{:import, _meta, module, _opts} ->
if(env.module, do: [], else: [:import_defined]) ++
[{:module_used, module}, {:alias_used, module}]
{:imported_function, _meta, module, _name, _arity} ->
[{:module_used, module}, :import_used]
{:imported_macro, _meta, module, _name, _arity} ->
[{:module_used, module}, :import_used]
{:alias, _meta, alias, as, _opts} ->
if(env.module, do: [], else: [{:alias_defined, as, alias}]) ++
[{:alias_used, alias}]
{:alias_expansion, _meta, as, _alias} ->
[{:alias_used, as}]
{:alias_reference, _meta, alias} ->
[{:alias_used, alias}]
{:require, _meta, module, _opts} ->
if(env.module, do: [], else: [{:require_defined, module}]) ++
[{:module_used, module}, {:alias_used, module}]
{:struct_expansion, _meta, module, _keys} ->
[{:module_used, module}]
{:remote_function, _meta, module, _name, _arity} ->
[{:module_used, module}]
{:remote_macro, _meta, module, _name, _arity} ->
[{:module_used, module}, {:require_used, module}]
{:on_module, bytecode, _ignore} ->
module = env.module
vars = Map.keys(env.versioned_vars)
Evaluator.write_module!(module, bytecode)
[{:module_defined, module, vars}, {:alias_used, module}]
_ ->
[]
end
end
@doc """
Applies updates to the tracer state.
"""
@spec apply_updates(%__MODULE__{}, list()) :: %__MODULE__{}
def apply_updates(info, updates) do
Enum.reduce(updates, info, &apply_update(&2, &1))
end
defp apply_update(info, {:module_used, module}) do
update_in(info.modules_used, &MapSet.put(&1, module))
end
defp apply_update(info, {:module_defined, module, vars}) do
put_in(info.modules_defined[module], vars)
end
defp apply_update(info, {:alias_used, alias}) do
update_in(info.aliases_used, &MapSet.put(&1, alias))
end
defp apply_update(info, {:alias_defined, as, alias}) do
put_in(info.aliases_defined[as], alias)
end
defp apply_update(info, {:require_used, module}) do
update_in(info.requires_used, &MapSet.put(&1, module))
end
defp apply_update(info, {:require_defined, module}) do
update_in(info.requires_defined, &MapSet.put(&1, module))
end
defp apply_update(info, :import_used) do
put_in(info.imports_used?, true)
end
defp apply_update(info, :import_defined) do
put_in(info.imports_defined?, true)
end
end