defmodule Ethyl do @moduledoc """ A non-general, purely functional subset of Elixir """ alias Ethyl.{AstTransforms, Context} @doc """ Compiles an ethyl reduction This can be used to write ethyl code inline in Elixir code """ defmacro ethyl(do: body) do Ethyl.from_elixir_ast( body, Context.from_elixir_env(__CALLER__) ) end @doc """ Transpiles an Elixir AST into an Ethyl AST """ @spec from_elixir_ast(ast :: tuple(), context :: Context.t()) :: ast :: tuple() def from_elixir_ast(ast, context) do ast |> AstTransforms.expand_aliases() |> AstTransforms.alter_compile_directives(context) |> AstTransforms.expand_imports() |> AstTransforms.expand_apply_3() |> AstTransforms.recursive_expand() end @doc """ Evaluates an ethyl expression in the given path with the given context This function is used under the hood by `from_elixir_ast/2` when using `import`. Note that this function calls out to `Code.eval_quoted/3` which is potentially dangerous: only use this function if you know ahead of time that the contents of `path` are safe to evaluate. """ @spec eval_file!(String.t(), Context.t(), Code.binding(), Keyword.t()) :: {term(), Code.binding()} def eval_file!(path, context, bindings \\ [], opts \\ []) do opts = Keyword.merge([file: path], opts) path |> File.read!() |> Code.string_to_quoted!() |> from_elixir_ast(context) |> Code.eval_quoted(bindings, opts) end end