defmodule LispTest do use ExUnit.Case describe "tokenize tokenizes" do test "left-paren" do assert {:lp, ""} = Lisp.tokenize("(") assert {:lp, " "} = Lisp.tokenize("( ") assert {:lp, "foo"} = Lisp.tokenize("(foo") end test "right-paren" do assert {:rp, ""} = Lisp.tokenize(")") assert {:rp, " "} = Lisp.tokenize(") ") end test "spaces are ignored" do assert {nil, ""} = Lisp.tokenize(" ") assert {nil, " "} = Lisp.tokenize(" ") end test "identifiers" do assert {"foo", ""} = Lisp.tokenize("foo") assert {"foo", " "} = Lisp.tokenize("foo ") assert {"foo", " bar"} = Lisp.tokenize("foo bar") assert {"foo", " 1"} = Lisp.tokenize("foo 1") assert {"foo2", ""} = Lisp.tokenize("foo2") end test "numbers" do assert {1, ""} = Lisp.tokenize("1") assert {1, " "} = Lisp.tokenize("1 ") assert {47, " foo"} = Lisp.tokenize("47 foo") end test "operators" do assert {"+", ""} = Lisp.tokenize("+") assert {"+", " "} = Lisp.tokenize("+ ") assert {"+", "foo"} = Lisp.tokenize("+foo") assert {"+", "47"} = Lisp.tokenize("+47") end end describe "string_to_tokens/1" do test "puts together the tokens" do assert [:lp, "foo", :rp] == Lisp.string_to_tokens("(foo)") assert [:lp, "foo", :rp] == Lisp.string_to_tokens("( foo )") assert [:lp, "foo", 47, :rp] == Lisp.string_to_tokens("(foo 47)") assert [:lp, "foo47", :rp] == Lisp.string_to_tokens("(foo47)") end test "syntax errors are not detected" do assert [:lp, :lp] == Lisp.string_to_tokens("((") assert [:rp, :lp] == Lisp.string_to_tokens(")(") end end describe "when sent through the parser" do test "empty list is empty list" do assert [] == Lisp.parse("()") end test "an basic token is a basic token" do assert 47 == Lisp.parse("47") assert "foo" == Lisp.parse("foo") assert "+" == Lisp.parse("+") end test "lists work" do assert [] == Lisp.parse("()") assert ["foo", "bar"] == Lisp.parse("(foo bar)") end test "nested lists work" do assert [["foo", "bar"], 3] == Lisp.parse("((foo bar) 3)") end test "wierd stuff causes syntax error" do assert_raise RuntimeError, fn -> Lisp.parse("(()") end assert_raise RuntimeError, fn -> Lisp.parse("())") end assert_raise RuntimeError, fn -> Lisp.parse("foo bar") end end test "the example parses" do assert ["first", ["list", 1, ["+", 2, 3], 9]] == Lisp.parse("(first (list 1 (+ 2 3) 9))") end end end