Packages
livebook
0.18.6
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, env.line}, {: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, line}) do
put_in(info.modules_defined[module], {line, 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