aboutsummaryrefslogtreecommitdiff
path: root/lib/elixir_math_parser.ex
diff options
context:
space:
mode:
authorWilliam Hergès <william@herges.fr>2025-11-09 13:23:05 +0100
committerWilliam Hergès <william@herges.fr>2025-11-09 13:23:05 +0100
commit3b0cc79dee76244da55d2326cc4244a384d85e44 (patch)
tree7a2819f658fe987f942633ad82997a75850e16ef /lib/elixir_math_parser.ex
parent8f9730d89e66ab1cbf08cbc0dea2a429d135e0da (diff)
feat(calc)): supports factorial
Diffstat (limited to 'lib/elixir_math_parser.ex')
-rw-r--r--lib/elixir_math_parser.ex22
1 files changed, 19 insertions, 3 deletions
diff --git a/lib/elixir_math_parser.ex b/lib/elixir_math_parser.ex
index f7f916f..863ecd8 100644
--- a/lib/elixir_math_parser.ex
+++ b/lib/elixir_math_parser.ex
@@ -10,9 +10,9 @@ defmodule ElixirMathParser do
{:ok, value <~> 1}
end
- defp reduce_to_value({:var, _line, var}, state) do
+ defp reduce_to_value({:var, line, var}, state) do
if !Map.has_key?(state, var) do
- {:error, "value not found for " <> to_string(var)}
+ {:error, line, "value not found for " <> to_string(var)}
else
{:ok, state[var]}
end
@@ -46,9 +46,25 @@ defmodule ElixirMathParser do
end
end
- defp evaluate_tree([{:assign, {:var, _line, lhs}, rhs} | tail], state) do
+ defp reduce_to_value({:factor_op, lhs}, state) do
+ with {:ok, op} <- reduce_to_value(lhs, state),
+ true <- Ratio.denominator(op) == 1,
+ true <- Ratio.numerator(op) >= 0 do
+ {:ok, factor(Ratio.numerator(op), 1)}
+ else
+ {:error, line, reason} -> {:error, line, reason}
+ false -> {:error, "must have a positive integer for the factorial"}
+ end
+ end
+
+ defp factor(n, acc) when n > 0, do: factor(n - 1, acc * n)
+ defp factor(0, acc), do: acc
+
+ defp evaluate_tree([{:assign, {:var, line, lhs}, rhs} | tail], state) do
with {:ok, val} <- reduce_to_value(rhs, state) do
evaluate_tree(tail, Map.merge(state, %{lhs => val}))
+ else
+ {:error, reason} -> {:error, line, reason}
end
end