104 lines
2.7 KiB
Elixir
104 lines
2.7 KiB
Elixir
defmodule Mix.Tasks.Clje.Run do
|
|
@moduledoc """
|
|
Compile and run a CljElixir file.
|
|
|
|
## Usage
|
|
|
|
mix clje.run examples/chat_room.clje
|
|
mix clje.run -e '(println "hello")' script.clje
|
|
|
|
Like `elixir script.exs` or `bb script.clj`. The file is compiled and
|
|
evaluated. Modules defined in the file become available.
|
|
|
|
## Options
|
|
|
|
* `-e` / `--eval` - evaluate expression before running the file
|
|
* `--no-halt` - keep the system running after execution (useful for spawned processes)
|
|
|
|
Arguments after `--` are available via `System.argv()`.
|
|
"""
|
|
|
|
use Mix.Task
|
|
|
|
@shortdoc "Run a CljElixir file"
|
|
|
|
@impl Mix.Task
|
|
def run(args) do
|
|
# Split on "--" to separate mix opts from script args
|
|
{before_dashdash, script_args} = split_on_dashdash(args)
|
|
|
|
{opts, positional, _} =
|
|
OptionParser.parse(before_dashdash,
|
|
switches: [eval: :keep, no_halt: :boolean],
|
|
aliases: [e: :eval]
|
|
)
|
|
|
|
Mix.Task.run("compile")
|
|
Mix.Task.run("app.start")
|
|
|
|
# Make script args available via System.argv()
|
|
System.argv(script_args)
|
|
|
|
# Evaluate any -e expressions first
|
|
bindings =
|
|
opts
|
|
|> Keyword.get_values(:eval)
|
|
|> Enum.reduce([], fn expr, bindings ->
|
|
case CljElixir.Compiler.eval_string(expr, bindings: bindings) do
|
|
{:ok, result, new_bindings} ->
|
|
IO.puts(CljElixir.Printer.pr_str(result))
|
|
new_bindings
|
|
|
|
{:error, diagnostics} ->
|
|
print_diagnostics(diagnostics)
|
|
System.halt(1)
|
|
end
|
|
end)
|
|
|
|
# Run file(s)
|
|
case positional do
|
|
[] ->
|
|
unless Keyword.has_key?(opts, :eval) do
|
|
Mix.shell().error("Usage: mix clje.run [options] <file.clje>")
|
|
System.halt(1)
|
|
end
|
|
|
|
files ->
|
|
Enum.reduce(files, bindings, fn file, bindings ->
|
|
case CljElixir.Compiler.eval_file(file, bindings: bindings) do
|
|
{:ok, _result, new_bindings} ->
|
|
new_bindings
|
|
|
|
{:error, diagnostics} ->
|
|
print_diagnostics(diagnostics)
|
|
System.halt(1)
|
|
end
|
|
end)
|
|
end
|
|
|
|
if opts[:no_halt] do
|
|
Process.sleep(:infinity)
|
|
end
|
|
end
|
|
|
|
defp split_on_dashdash(args) do
|
|
case Enum.split_while(args, &(&1 != "--")) do
|
|
{before, ["--" | rest]} -> {before, rest}
|
|
{before, []} -> {before, []}
|
|
end
|
|
end
|
|
|
|
defp print_diagnostics(diagnostics) do
|
|
Enum.each(diagnostics, fn diag ->
|
|
loc =
|
|
case {Map.get(diag, :file), Map.get(diag, :line, 0)} do
|
|
{nil, _} -> ""
|
|
{_f, 0} -> "#{diag.file}: "
|
|
{_f, l} -> "#{diag.file}:#{l}: "
|
|
end
|
|
|
|
Mix.shell().error("#{loc}#{diag.severity}: #{diag.message}")
|
|
end)
|
|
end
|
|
end
|