Skip to content

Commit 9078aed

Browse files
committed
Outputting diagnostic information from elixirscript compiler
1 parent e03df89 commit 9078aed

File tree

5 files changed

+93
-57
lines changed

5 files changed

+93
-57
lines changed

lib/elixir_script/beam.ex

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ defmodule ElixirScript.Beam do
3030
case do_debug_info(Module.concat(ElixirScript, module)) do
3131
{:ok, info} ->
3232
{:ok, Map.put(info, :module, module)}
33+
3334
e ->
3435
e
3536
end
@@ -49,28 +50,32 @@ defmodule ElixirScript.Beam do
4950
case :code.get_object_code(module) do
5051
{_, beam, beam_path} ->
5152
do_debug_info(beam, beam_path)
53+
5254
:error ->
5355
{:error, "Unknown module"}
5456
end
5557
end
5658

5759
defp do_debug_info(beam, beam_path) do
58-
with {:ok, {module, [debug_info: {:debug_info_v1, backend, data}]}} <- :beam_lib.chunks(beam, [:debug_info]),
59-
{:ok, {^module, attribute_info}} = :beam_lib.chunks(beam, [:attributes]) do
60-
61-
if Keyword.get(attribute_info[:attributes], :protocol) do
62-
get_protocol_implementations(module, beam_path)
63-
else
64-
backend.debug_info(:elixir_v1, module, data, [])
65-
|> process_debug_info(beam_path)
66-
end
60+
with {:ok, {module, [debug_info: {:debug_info_v1, backend, data}]}} <-
61+
:beam_lib.chunks(beam, [:debug_info]),
62+
{:ok, {^module, attribute_info}} = :beam_lib.chunks(beam, [:attributes]) do
63+
if Keyword.get(attribute_info[:attributes], :protocol) do
64+
get_protocol_implementations(module, beam_path)
65+
else
66+
backend.debug_info(:elixir_v1, module, data, [])
67+
|> process_debug_info(beam_path)
68+
end
6769
else
6870
:error ->
6971
{:error, "Unknown module"}
72+
7073
{:error, :beam_lib, {:unknown_chunk, "non_existing.beam", :debug_info}} ->
7174
{:error, "Unsupported version of Erlang"}
72-
{:error, :beam_lib, {:missing_chunk, _ , _}} ->
75+
76+
{:error, :beam_lib, {:missing_chunk, _, _}} ->
7377
{:error, "Debug info not available"}
78+
7479
{:error, :beam_lib, {:file_error, "non_existing.beam", :enoent}} ->
7580
{:error, "Debug info not available"}
7681
end
@@ -82,12 +87,14 @@ defmodule ElixirScript.Beam do
8287
end
8388

8489
defp process_debug_info({:ok, info}, beam_path) do
85-
info = case File.stat(beam_path, time: :posix) do
86-
{:ok, file_info} ->
87-
Map.put(info, :last_modified, file_info.mtime)
88-
_ ->
89-
Map.put(info, :last_modified, nil)
90-
end
90+
info =
91+
case File.stat(beam_path, time: :posix) do
92+
{:ok, file_info} ->
93+
Map.put(info, :last_modified, file_info.mtime)
94+
95+
_ ->
96+
Map.put(info, :last_modified, nil)
97+
end
9198

9299
info = Map.put(info, :beam_path, beam_path)
93100

@@ -101,36 +108,39 @@ defmodule ElixirScript.Beam do
101108
defp get_protocol_implementations(module, beam_path) do
102109
{:ok, protocol_module_info} = process_debug_info({:ok, %{}}, beam_path)
103110

104-
implementations = module
105-
|> Protocol.extract_impls(:code.get_path())
106-
|> Enum.map(fn(x) -> Module.concat([module, x]) end)
107-
|> Enum.map(fn(x) ->
108-
case debug_info(x) do
109-
{:ok, info} ->
110-
{x, info}
111-
_ ->
112-
raise "Unable to compile protocol implementation #{inspect x}"
113-
end
114-
end)
111+
implementations =
112+
module
113+
|> Protocol.extract_impls(:code.get_path())
114+
|> Enum.map(fn x -> Module.concat([module, x]) end)
115+
|> Enum.map(fn x ->
116+
case debug_info(x) do
117+
{:ok, info} ->
118+
{x, info}
119+
120+
_ ->
121+
raise ElixirScript.CompileError,
122+
message: "Unable to compile protocol implementation #{inspect(x)}",
123+
severity: :error
124+
end
125+
end)
115126

116127
{:ok, module, protocol_module_info, implementations}
117128
end
118129

119130
defp replace_definitions(original_definitions, replacement_definitions) do
120-
Enum.map(original_definitions, fn
121-
{{function, arity}, type, _, _} = ast ->
122-
ex_ast = Enum.find(replacement_definitions, fn
123-
{{ex_function, ex_arity}, ex_type, _, _} ->
124-
ex_function == function and ex_arity == arity and ex_type == type
131+
Enum.map(original_definitions, fn {{function, arity}, type, _, _} = ast ->
132+
ex_ast =
133+
Enum.find(replacement_definitions, fn {{ex_function, ex_arity}, ex_type, _, _} ->
134+
ex_function == function and ex_arity == arity and ex_type == type
125135
end)
126136

127-
case ex_ast do
128-
nil ->
129-
ast
130-
_ ->
131-
ex_ast
132-
end
137+
case ex_ast do
138+
nil ->
139+
ast
140+
141+
_ ->
142+
ex_ast
143+
end
133144
end)
134145
end
135-
136146
end

lib/elixir_script/compile_error.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
defmodule ElixirScript.CompileError do
2-
defexception [:message]
2+
defexception [:message, :severity]
33
end

lib/elixir_script/compiler.ex

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,20 @@ defmodule ElixirScript.Compiler do
121121

122122
Enum.reduce(modules, %{}, fn
123123
{module, info}, current_data ->
124+
diagnostics =
125+
Map.get(info, :diagnostics, [])
126+
|> Enum.map(fn x ->
127+
Map.put(x, :file, Map.get(info, :file))
128+
end)
129+
124130
info = %{
125131
references: info.used_modules,
126132
last_modified: info.last_modified,
127133
beam_path: Map.get(info, :beam_path),
128134
source: Map.get(info, :file),
129135
js_path: Path.join(output_path, "#{module}.js"),
130136
js_code: Keyword.get(compiled_js, module),
131-
diagnostics: Map.get(info, :diagnostics, []),
137+
diagnostics: diagnostics,
132138
type: :module
133139
}
134140

@@ -148,8 +154,7 @@ defmodule ElixirScript.Compiler do
148154
references: [],
149155
last_modified: last_modified,
150156
beam_path: nil,
151-
source: nil,
152-
js_input_path: js_input_path,
157+
source: js_input_path,
153158
js_path: js_output_path,
154159
js_code: nil,
155160
diagnostics: [],

lib/elixir_script/passes/find_used_modules.ex

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,9 @@ defmodule ElixirScript.FindUsedModules do
4343
})
4444

4545
{:error, error} ->
46-
ModuleState.put_diagnostic(pid, module, %{
47-
severity: :error,
48-
message: "An error occurred while compiling #{inspect(module)}: #{error}"
49-
})
50-
5146
raise ElixirScript.CompileError,
52-
"An error occurred while compiling #{inspect(module)}: #{error}"
47+
message: "An error occurred while compiling #{inspect(module)}: #{error}",
48+
severity: :error
5349
end
5450
end
5551

lib/mix/tasks/compile.elixir_script.ex

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
defmodule Mix.Tasks.Compile.ElixirScript do
22
use Mix.Task.Compiler
33
alias ElixirScript.Manifest
4+
alias ElixirScript.Compiler
45

56
@recursive true
67
@manifest ".compile.elixir_script"
@@ -35,17 +36,41 @@ defmodule Mix.Tasks.Compile.ElixirScript do
3536
The mix compiler will also compile any dependencies that have the elixirscript compiler in its mix compilers as well
3637
"""
3738

38-
@spec run(any()) :: :ok
39+
@spec run([binary()]) ::
40+
:ok | :noop | {:ok | :noop | :error, [Mix.Task.Compiler.Diagnostic.t()]}
3941
def run(_) do
40-
do_compile()
41-
:ok
42-
end
43-
44-
defp do_compile() do
4542
{input, opts} = get_compiler_params()
46-
result = ElixirScript.Compiler.compile(input, opts)
4743

48-
Manifest.write_manifest(manifest(), result)
44+
try do
45+
result = Compiler.compile(input, opts)
46+
Manifest.write_manifest(manifest(), result)
47+
48+
result
49+
|> Enum.map(fn {_module, info} ->
50+
info.diagnositcs
51+
end)
52+
|> List.flatten()
53+
|> Enum.map(fn x ->
54+
%Mix.Task.Compiler.Diagnostic{
55+
compiler_name: "elixir_script",
56+
file: x.file,
57+
message: x.message,
58+
position: x.position,
59+
severity: x.severity
60+
}
61+
end)
62+
rescue
63+
x in [ElixirScript.CompileError] ->
64+
[
65+
%Mix.Task.Compiler.Diagnostic{
66+
compiler_name: "elixir_script",
67+
message: x.message,
68+
severity: x.severity,
69+
position: nil,
70+
file: nil
71+
}
72+
]
73+
end
4974
end
5075

5176
def clean do

0 commit comments

Comments
 (0)