Skip to content

Commit

Permalink
a few good tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Adzz committed Sep 6, 2021
1 parent c8e77e8 commit 2855e98
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 37 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# MatchA
# MatchA 🍵

**TODO: Add description**

Expand Down
63 changes: 30 additions & 33 deletions lib/match_a.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,45 @@ defimpl Match, for: List do
[%Variable{}, %Rest{binding: %Variable{name: :thing}}]
"""
# def a(x, p), do: p |> IO.inspect(limit: :infinity, label: "")
# raise("Invalid Match Syntax")
def a([], []), do: raise("Invalid Match Syntax")
def a([], {:case, [:empty]}), do: {:match, %{}}
def a([], {:case, [:empty], continuation}), do: {:match, %{}, continuation}

def a(_, {:case, [:empty]}), do: raise("no matches!")
def a(_, {:case, [:empty | _]}), do: raise("Invalid Match Syntax")
def a(_, {:case, [:empty], _}), do: raise("no matches!")
def a(_, {:case, [:empty | _], _}), do: raise("Invalid Match Syntax")

# The one element is special because it has two things in it really.
def a([_], {:case, [:wildcard, {:rest, :wildcard}]}), do: {:match, %{}}
def a([_], {:case, [:wildcard, {:rest, {:variable, name}}]}), do: {:match, %{name => []}}
def a([_], {:case, [:wildcard, {:rest, :wildcard}], continuation}) do
{:match, %{}, continuation}
end

def a([_], {:case, [:wildcard, {:rest, {:variable, name}}], continuation}) do
{:match, %{name => []}, continuation}
end

def a([element], {:case, [{:variable, first}, {:rest, :wildcard}]}) do
{:match, %{first => element}}
def a([element], {:case, [variable: first, rest: :wildcard], continuation}) do
{:match, %{first => element}, continuation}
end

def a([element], {:case, [{:variable, first}, {:rest, {:variable, name}}]}) do
{:match, %{first => element, name => []}}
def a([element], {:case, [variable: first, rest: {:variable, name}], continuation}) do
{:match, %{first => element, name => []}, continuation}
end

def a([_], {:case, [_, _]}), do: raise("Invalid Match Syntax")
def a([_], {:case, [_, _], _}), do: raise("Invalid Match Syntax")

# lol at pattern matching to implement pattern matching.
def a([element], {:case, [{:variable, name}]}), do: {:match, %{name => element}}
def a([_element], {:case, [:wildcard]}), do: {:match, %{}}
def a([element], {:case, [{:variable, name}], continuation}) do
{:match, %{name => element}, continuation}
end

def a([_element], {:case, [:wildcard], continuation}) do
{:match, %{}, continuation}
end

# Rest doesn't makes sense for the first element in a one element list.
def a([_element], {:case, [{:rest, _}]}), do: raise("Invalid Match Syntax")
def a([_element], {:case, [_]}), do: raise("Invalid Match Syntax")
def a([_element], {:case, [{:rest, _}], _}), do: raise("Invalid Match Syntax")
def a([_element], {:case, [_], _}), do: raise("Invalid Match Syntax")

def a(list, {:case, pattern, continuation}) when is_list(pattern) do
# A list could have anything in it so we need a unique value to be able to determine
Expand Down Expand Up @@ -101,16 +114,7 @@ defmodule MatchA do

@doc """
"""
def match(pattern_cases, data) do
do_the_match(pattern_cases, data, false)
end

# match/2 is really `bindings/2` and this is like do
def match_and_continue(pattern_cases, data) do
do_the_match(pattern_cases, data, true)
end

defp do_the_match({:pattern_cases, cases}, data, continue?) do
def match({:pattern_cases, cases}, data) do
Enum.reduce_while(cases, :no_match, fn pattern, acc ->
# I guess each thing needs to be able to define the way it can be matched. So lists,
# tuples all that. That means we need to know BOTH what are we matching on AND with what
Expand All @@ -122,15 +126,8 @@ defmodule MatchA do
end
end)
|> case do
{:match, bindings, continuation} ->
if continue? do
continuation.(bindings)
else
bindings
end

:no_match ->
raise "no matches!"
{:match, bindings, continuation} -> continuation.(bindings)
:no_match -> raise "no matches!"
end
end

Expand Down
35 changes: 32 additions & 3 deletions test/match_a_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,22 @@ defmodule MatchATest do
import MatchA

describe "list implementation" do
test "[head _]" do
test "[head, _] = [1, 2]" do
pattern = pattern_cases([pattern_case([variable(:head), wildcard()])])
assert MatchA.match(pattern, [1, 2]) == %{head: 1}

# With continuation...
pattern =
pattern_cases([
pattern_case([variable(:head), wildcard()], fn bindings ->
Map.put(bindings, :head, bindings.head + 1)
end)
])

assert MatchA.match(pattern, [1, 2]) == %{head: 2}
end

test "[head | rest]" do
test "[head | rest] = [1, 2]" do
pattern =
pattern_cases([
pattern_case([variable(:head), rest(variable(:rest))])
Expand All @@ -18,13 +28,32 @@ defmodule MatchATest do
assert MatchA.match(pattern, [1, 2]) == %{head: 1, rest: [2]}
end

test "[head | _]" do
test "[head | _] = [1, 2]" do
pattern =
pattern_cases([
pattern_case([variable(:head), rest(wildcard())])
])

assert MatchA.match(pattern, [1, 2]) == %{head: 1}

pattern =
pattern_cases([
pattern_case([variable(:head), rest()])
])

assert MatchA.match(pattern, [1, 2]) == %{head: 1}
end

test "[head | rest] = [1]" do
pattern =
pattern_cases([
pattern_case([variable(:head), rest()])
])

assert MatchA.match(pattern, [1]) == %{head: 1}
end

test "..." do
end
end
end

0 comments on commit 2855e98

Please sign in to comment.