mirror of
https://github.com/kanaka/mal.git
synced 2024-11-13 01:43:50 +03:00
Add read/print functionality up to quote (step 1)
This commit is contained in:
parent
51c2c1fea7
commit
b5aff35fe8
13
elixir/lib/mal/printer.ex
Normal file
13
elixir/lib/mal/printer.ex
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
defmodule Mal.Printer do
|
||||||
|
def print_str(mal) when is_atom(mal), do: Atom.to_string(mal)
|
||||||
|
def print_str(mal) when is_integer(mal), do: Integer.to_string(mal)
|
||||||
|
def print_str(mal) when is_bitstring(mal), do: mal
|
||||||
|
def print_str({ :symbol, value }), do: value
|
||||||
|
def print_str(mal) when is_list(mal) do
|
||||||
|
output = mal
|
||||||
|
|> Enum.map(fn(x) -> print_str(x) end)
|
||||||
|
|> Enum.join(" ")
|
||||||
|
|
||||||
|
"(#{output})"
|
||||||
|
end
|
||||||
|
end
|
58
elixir/lib/mal/reader.ex
Normal file
58
elixir/lib/mal/reader.ex
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# TODO: def -> defp for everything but read_str
|
||||||
|
defmodule Mal.Reader do
|
||||||
|
import Mal.Types
|
||||||
|
|
||||||
|
def read_str(input) do
|
||||||
|
output = tokenize(input)
|
||||||
|
|> read_form
|
||||||
|
|> elem(0)
|
||||||
|
{:ok, output}
|
||||||
|
catch
|
||||||
|
{:invalid, message} -> {:error, message}
|
||||||
|
end
|
||||||
|
|
||||||
|
def tokenize(input) do
|
||||||
|
regex = ~r/[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/
|
||||||
|
Regex.scan(regex, input, capture: :all_but_first)
|
||||||
|
|> List.flatten
|
||||||
|
|> List.delete_at(-1) # Remove the last match, which is an empty string
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_form([next | rest] = tokens) do
|
||||||
|
case next do
|
||||||
|
"(" <> _ ->
|
||||||
|
read_list(tokens)
|
||||||
|
_ ->
|
||||||
|
token = read_atom(next)
|
||||||
|
{token, rest}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_list([_ | tokens]), do: do_read_list(tokens, [])
|
||||||
|
|
||||||
|
defp do_read_list([], acc), do: throw({:invalid, "expected ')', got EOF"})
|
||||||
|
defp do_read_list([head | tail] = tokens, acc) do
|
||||||
|
case head do
|
||||||
|
")" <> _ -> {Enum.reverse(acc), tail}
|
||||||
|
_ ->
|
||||||
|
{token, rest} = read_form(tokens)
|
||||||
|
do_read_list(rest, [token | acc])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_atom("nil"), do: nil
|
||||||
|
def read_atom("true"), do: true
|
||||||
|
def read_atom("false"), do: false
|
||||||
|
def read_atom(":" <> rest), do: String.to_atom(rest)
|
||||||
|
def read_atom(token) do
|
||||||
|
cond do
|
||||||
|
String.starts_with?(token, "\"") -> token
|
||||||
|
String.starts_with?(token, "'") -> token
|
||||||
|
integer?(token) ->
|
||||||
|
Integer.parse(token)
|
||||||
|
|> elem(0)
|
||||||
|
|
||||||
|
true -> {:symbol, token}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
9
elixir/lib/mal/types.ex
Normal file
9
elixir/lib/mal/types.ex
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
defmodule Mal.Types do
|
||||||
|
def integer?(input) do
|
||||||
|
Regex.match?(~r/^-?[0-9]+$/, input)
|
||||||
|
end
|
||||||
|
|
||||||
|
def float?(input) do
|
||||||
|
Regex.match?(~r/^-?[0-9][0-9.]*$/, input)
|
||||||
|
end
|
||||||
|
end
|
32
elixir/lib/mix/tasks/step1_read_print.ex
Normal file
32
elixir/lib/mix/tasks/step1_read_print.ex
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
defmodule Mix.Tasks.Step1ReadPrint do
|
||||||
|
def run(_), do: main
|
||||||
|
|
||||||
|
def main do
|
||||||
|
IO.write(:stdio, "user> ")
|
||||||
|
IO.read(:stdio, :line)
|
||||||
|
|> read_eval_print
|
||||||
|
|
||||||
|
main
|
||||||
|
end
|
||||||
|
|
||||||
|
def read(input) do
|
||||||
|
Mal.Reader.read_str(input)
|
||||||
|
end
|
||||||
|
|
||||||
|
def eval({:ok, input}), do: {:ok, input}
|
||||||
|
def eval({:error, message}), do: {:error, message}
|
||||||
|
|
||||||
|
def print({:ok, output}) do
|
||||||
|
IO.puts(Mal.Printer.print_str(output))
|
||||||
|
end
|
||||||
|
def print({:error, message}) do
|
||||||
|
IO.puts(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_eval_print(:eof), do: exit(0)
|
||||||
|
def read_eval_print(line) do
|
||||||
|
read(line)
|
||||||
|
|> eval
|
||||||
|
|> print
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user