Branch
Hash :
1533add8
Author :
Thomas de Grivel
Date :
2022-02-18T10:08:21
VARIABLES
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
defmodule Pure do
@moduledoc """
Documentation for `Pure`.
"""
@doc """
Checks if string is a valid guard expression.
## Examples
iex> i = 0
iex> Pure.string_is_guard?("i == 1", __ENV__)
true
"""
def string_is_guard?(str, env) when is_binary(str) do
{:ok, quoted} = Code.string_to_quoted(str)
is_guard?(quoted, env)
end
@doc """
Checks if quoted expression is a valid guard expression.
## Examples
iex> i = 0
iex> Pure.is_guard?(quote do i == 1 end, __ENV__)
true
"""
def is_guard?(quoted, env) do
{erl, _, _, _env} = :elixir.quoted_to_erl(quoted, env)
result = :erl_lint.is_guard_test(erl)
IO.inspect([:is_guard?, quoted, result])
result
end
@doc """
Checks if string is a pattern expression.
## Examples
iex> Pure.string_is_pattern?("{a, b}", __ENV__)
true
"""
def string_is_pattern?(str, env) when is_binary(str) do
{:ok, quoted} = Code.string_to_quoted("#{str} = nil")
is_match?(quoted, env)
end
@doc """
Checks if string is a match expression.
## Examples
iex> Pure.string_is_match?("{a, b} = {1, 2}", __ENV__)
true
"""
def string_is_match?(str, env) when is_binary(str) do
{:ok, quoted} = Code.string_to_quoted(str)
is_match?(quoted, env)
end
@doc """
Checks if quoted expression is a match expression.
## Examples
iex> Pure.is_match?(quote do {a, b} = nil end, __ENV__)
true
"""
def is_match?(quoted, env) do
{erl, _, _, _env} = :elixir.quoted_to_erl(quoted, env)
#IO.inspect(erl)
case erl do
{:match, _, a, b} ->
a_is_pattern? = :pure.is_pattern_expr(a)
b_is_guard? = :erl_lint.is_guard_test(b)
result = a_is_pattern? && b_is_guard?
IO.inspect([:is_match?, quoted,
a: a, is_pattern?: a_is_pattern?,
b: b, is_guard?: b_is_guard?,
result: result])
result
_ ->
IO.inspect([:is_match?, quoted, false])
false
end
end
def is_pure?(quoted = {:__block__, _, block}, env) do
is_pure_block?(quoted, env, block, [])
end
def is_pure?(quoted, env) do
result = is_guard?(quoted, env) || is_match?(quoted, env)
IO.inspect([:is_pure?, quoted, result])
result
end
def is_pure_block?(quoted, _env, [], _acc) do
IO.inspect([:is_pure?, quoted, true])
true
end
def is_pure_block?(quoted, env, [first | rest], acc) do
env = env_eval(env, {:__block__, 1, Enum.reverse(acc)})
if is_pure?(first, env) do
is_pure_block?(quoted, env, rest, [first | acc])
else
IO.inspect([:is_pure?, quoted, false])
false
end
end
def env_eval(env, quoted) do
IO.inspect([:env_eval, quoted])
{env1, _} = Code.eval_quoted(quote do unquote(quoted); __ENV__ end, [], env)
env1
end
defmacro eval(str) when is_binary(str) do
{:ok, q} = Code.string_to_quoted(str)
quote do
require Pure
Pure.eval(unquote(q))
end
end
defmacro eval(q) do
if is_pure?(q, __ENV__) do
q
else
raise ArgumentError, "not a pure expression: #{Macro.to_string(q)}"
end
end
end