aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example/input.txt2
-rw-r--r--lib/elixir_math_parser.ex23
-rw-r--r--src/elixir_math_parser.yrl8
-rw-r--r--src/elixir_math_parser_lexer.xrl1
4 files changed, 31 insertions, 3 deletions
diff --git a/example/input.txt b/example/input.txt
index 7efcb9c..8cb02c5 100644
--- a/example/input.txt
+++ b/example/input.txt
@@ -5,3 +5,5 @@ x = 20
y = 2!
z = y/2
10 + 4(z / y)(x / 4)
+
+x^(0-y)
diff --git a/lib/elixir_math_parser.ex b/lib/elixir_math_parser.ex
index 863ecd8..b5e99bd 100644
--- a/lib/elixir_math_parser.ex
+++ b/lib/elixir_math_parser.ex
@@ -57,9 +57,32 @@ defmodule ElixirMathParser do
end
end
+ defp reduce_to_value({:exp_op, lhs, rhs}, state) do
+ with {:ok, op1} <- reduce_to_value(lhs, state),
+ {:ok, op2} <- reduce_to_value(rhs, state) do
+ if Ratio.denominator(op2) == 1 do
+ {:ok, expo(op1, Ratio.numerator(op2), 1)}
+ else
+ {:error, "unsupported operation"}
+ end
+ end
+ end
+
+ #  Functions for maths
+
defp factor(n, acc) when n > 0, do: factor(n - 1, acc * n)
defp factor(0, acc), do: acc
+ defp expo(value, exponent, acc) when exponent != 0 do
+ if exponent > 0 do
+ expo(value, exponent - 1, acc * value)
+ else
+ expo(value, exponent + 1, acc / value)
+ end
+ end
+
+ defp expo(_value, 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}))
diff --git a/src/elixir_math_parser.yrl b/src/elixir_math_parser.yrl
index 0808683..006c768 100644
--- a/src/elixir_math_parser.yrl
+++ b/src/elixir_math_parser.yrl
@@ -10,7 +10,7 @@ Terminals
int
var
break
- '+' '-' '*' '/' '!'
+ '+' '-' '*' '/' '!' '^'
'='
'(' ')'
.
@@ -25,7 +25,8 @@ Left 300 '-'.
Left 400 '*'.
Left 400 '/'.
Right 500 '!'.
-Left 600 '('.
+Left 600 '^'.
+Left 700 '('.
root -> statements : '$1'.
@@ -46,8 +47,9 @@ expr -> exprs '+' exprs : {add_op, '$1', '$3'}.
expr -> exprs '-' exprs : {sub_op, '$1', '$3'}.
expr -> exprs '*' exprs : {mul_op, '$1', '$3'}.
expr -> exprs '/' exprs : {div_op, '$1', '$3'}.
-expr -> '(' exprs ')' : '$2'.
expr -> expr '!' : {factor_op, '$1'}.
+expr -> exprs '^' exprs : {exp_op, '$1', '$3'}.
+expr -> '(' exprs ')' : '$2'.
Erlang code.
diff --git a/src/elixir_math_parser_lexer.xrl b/src/elixir_math_parser_lexer.xrl
index 5bdcbef..c29416e 100644
--- a/src/elixir_math_parser_lexer.xrl
+++ b/src/elixir_math_parser_lexer.xrl
@@ -14,6 +14,7 @@ Rules.
\( : {token, {'(', TokenLine}}.
\) : {token, {')', TokenLine}}.
! : {token, {'!', TokenLine}}.
+\^ : {token, {'^', TokenLine}}.
{BREAK}+ : {token, {break, TokenLine}}.
{NAME} : {token, {var, TokenLine, TokenChars}}.
{INT} : {token, {int, TokenLine, TokenChars}}.