Skip to content

Commit

Permalink
Halt work on livebook compiler.
Browse files Browse the repository at this point in the history
  • Loading branch information
christhekeele committed Apr 26, 2024
1 parent bf0453b commit 85a280e
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 320 deletions.
153 changes: 90 additions & 63 deletions lib/mix/tasks/compile/livebooks.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ defmodule Mix.Tasks.Compile.Livebooks do
require Logger

@impl true
def run(_args) do
def run(args) do
Application.ensure_all_started(:livebooks)
warnings_as_errors? = "--warnings-as-errors" in args
project = Mix.Project.config()
livebook_search_paths = project[:livebook_paths] || ["lib"]
livebook_output_path = project[:livebook_output_dir] || Mix.Project.compile_path(project)

base_dir =
Mix.Project.project_file()
Expand All @@ -21,73 +24,97 @@ defmodule Mix.Tasks.Compile.Livebooks do
|> Enum.map(&Path.relative_to(&1, base_dir))
end)

case length(livebook_paths) do
0 -> :ok
1 -> Mix.Shell.IO.info("Compiling 1 file (.livemd)")
n -> Mix.Shell.IO.info("Compiling #{n} files (.livemd)")
end

for livebook_path <- livebook_paths do
{rel_dir, base, _ext} =
{Path.dirname(livebook_path), Path.basename(livebook_path, ".livemd"),
Path.extname(livebook_path)}
{rel_dir, base} =
{Path.dirname(livebook_path), Path.basename(livebook_path, ".livemd")}

output_path = Path.join([livebook_output_path, rel_dir, "#{base}.exs"])

output_dir = Path.dirname(output_path)

{:ok, livebook_ast, comments} =
livebook_path
|> File.read!()
|> Livebook.live_markdown_to_elixir()
|> Code.string_to_quoted_with_comments(emit_warnings: false)

{livebook_ast, comments} =
livebook_ast
|> Macro.postwalk(comments, fn
mix_install = {{:., meta, [{:__aliases__, _, [:Mix]}, :install]}, _, install_args},
comments ->
# line = Keyword.fetch!(meta, :line)
# IO.inspect(install_args)
# {:mix_install, [%{line: line, comments]}
{mix_install, comments}

ast, comments ->
{ast, comments}
end)

livebook_script =
livebook_ast
|> Code.quoted_to_algebra(comments: comments)
|> Inspect.Algebra.format(%Inspect.Opts{}.width)
|> IO.iodata_to_binary()
|> tap(&IO.puts/1)

File.mkdir_p!(output_dir)
File.write!(output_path, livebook_script)

output_path
end
|> Kernel.ParallelCompiler.require(return_diagnostics: true)
|> case do
{:ok, _mods, warnings} ->
if warnings_as_errors? do
{:error, warnings_to_diagnostics(warnings)}
else
:ok
end

{:error, errors, warnings} ->
if warnings_as_errors? do
{:error, errors_to_diagnostics(errors) ++ warnings_to_diagnostics(warnings)}
else
{:error, errors_to_diagnostics(errors)}
end
end
end

output_path = Path.join([base_dir, "test", rel_dir, "#{base}_test.exs"])
defp warnings_to_diagnostics(%{
runtime_warnings: runtime_warnings,
compile_warnings: compile_warnings
}) do
code_diagnostics_to_compile_diagnostics(runtime_warnings) ++
code_diagnostics_to_compile_diagnostics(compile_warnings)
end

Task.async(fn ->
compile(livebook_path, output_path)
end)
end
|> Task.await_many()
defp errors_to_diagnostics(errors) do
code_diagnostics_to_compile_diagnostics(errors)
end

:ok
defp code_diagnostics_to_compile_diagnostics(diagnostics) do
Enum.map(diagnostics, &code_diagnostic_to_compile_diagnostic/1)
end

def compile(livebook_path, output_path) do
output_dir = Path.dirname(output_path)

livebook_elixir =
livebook_path
|> File.read!()
|> Livebook.live_markdown_to_elixir()

File.mkdir_p!(output_dir)
File.write!(output_path, livebook_elixir)

try do
Code.string_to_quoted!(livebook_elixir,
file: output_path,
columns: true,
emit_warnings: true
)

:ok
rescue
e in [EEx.SyntaxError, SyntaxError, TokenMissingError] ->
message = Exception.message(e)

diagnostic = %Mix.Task.Compiler.Diagnostic{
compiler_name: "Livebook",
file: livebook_path,
position: {e.line, e.column},
message: message,
severity: :error
}

{:error, diagnostic}

e ->
message = Exception.message(e)

diagnostic = %Mix.Task.Compiler.Diagnostic{
compiler_name: "Livebook",
file: livebook_path,
position: {1, 1},
message: message,
severity: :error
}

# e.g. https://github.com/elixir-lang/elixir/issues/12926
Logger.warning(
"Unexpected parser error, please report it to elixir project https://github.com/elixir-lang/elixir/issues\n" <>
Exception.format(:error, e, __STACKTRACE__)
)

{:error, diagnostic}
end
defp code_diagnostic_to_compile_diagnostic(diagnostic) do
%Mix.Task.Compiler.Diagnostic{
compiler_name: "Livebook",
details: diagnostic[:severity],
file: diagnostic[:file],
message: diagnostic[:message],
position: diagnostic[:position],
severity: diagnostic[:severity],
source: diagnostic[:severity],
span: diagnostic[:severity],
stacktrace: diagnostic[:severity]
}
end
end
2 changes: 1 addition & 1 deletion livebooks/conways-game-of-life.livemd
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ default_board_text = """
"""

# initial_board_input =
initial_board_input =
"Initial Game Board: "
|> Kino.Input.textarea(default: default_board_text)
foo = 1
Expand Down
24 changes: 6 additions & 18 deletions livebooks/surreal-numbers.livemd
Original file line number Diff line number Diff line change
Expand Up @@ -340,33 +340,21 @@ end
```

```elixir
import Kernel, except: [-: 1, +: 2, -: 2, *: 2, /: 2, <>: 2]
import Surreal

(to_surreal(2) + to_surreal(2)) |> IO.inspect()
Surreal.+(Surreal.to_surreal(2), Surreal.to_surreal(2)) |> IO.inspect()
```

```elixir
import Kernel, except: [-: 1, +: 2, -: 2, *: 2, /: 2, <>: 2]
import Surreal

(to_surreal(2) * to_surreal(2)) |> IO.inspect()
Surreal.*(Surreal.to_surreal(2), Surreal.to_surreal(2)) |> IO.inspect()
```

```elixir
import Kernel, except: [-: 1, +: 2, -: 2, *: 2, /: 2, <>: 2]
import Surreal

six = to_surreal(2) * to_surreal(3)
six = Surreal.*(Surreal.to_surreal(2), Surreal.to_surreal(3))
IO.inspect(six)
six |> to_number
six |> Surreal.to_number
```

```elixir
import Kernel, except: [-: 1, +: 2, -: 2, *: 2, /: 2, <>: 2]
import Surreal

nine = to_surreal(3) * to_surreal(3)
nine = Surreal.*(Surreal.to_surreal(3), Surreal.to_surreal(3))
IO.inspect(six)
nine |> to_number
nine |> Surreal.to_number
```
6 changes: 4 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,10 @@ defmodule Livebooks.MixProject do
elixirc_paths: ["lib", "livebooks", "test"],
start_permanent: Mix.env() == :prod,
version: Version.to_string(@version),
compilers: Mix.compilers() ++ [:livebooks],
# ++ [:livebooks],
compilers: Mix.compilers(),
livebook_paths: ["livebooks"],
livebook_output_dir: "test",
# Informational
name: @name,
description: @description,
Expand Down Expand Up @@ -199,7 +201,7 @@ defmodule Livebooks.MixProject do
defp deps(),
do: [
{:matcha, "~> 0.1"},
{:livebook, "~> 0.12", runtime: false},
# {:livebook, "~> 0.12", runtime: false},
# Site generation
{:ex_doc, "~> 0.30", only: @doc_envs, runtime: false},
# Static analysis
Expand Down
Loading

0 comments on commit 85a280e

Please sign in to comment.