@@ 1,30 1,64 @@
defmodule Lixp do
def eval(str) do
- {:ok, [res], _, _, _, _} = Lixp.Parser.program(str)
- eval(res, %{})
+ {:ok, prog, _, _, _, _} = Lixp.Parser.program(str)
+
+ {val, _} =
+ Enum.reduce(prog, {nil, %{}}, fn p, {_, e} ->
+ eval(p, e)
+ end)
+
+ val
end
- defp eval(num, _env) when is_number(num) do
- num
+ defp eval(num, env) when is_number(num) do
+ {num, env}
end
- defp eval(atom, _env) when is_atom(atom) do
- atom
+ defp eval(atom, env) when is_atom(atom) do
+ {atom, env}
end
defp eval({:symbol, sym}, env) do
- env[sym]
+ {env[sym], env}
+ end
+ defp eval([{:symbol, "quote"} | [rest]], env) do
+ rest = Enum.map(rest, fn
+ [{:symbol, "unquote"} | [body]] ->
+ {val, _} = eval(body, env)
+ val
+ x -> x
+ end)
+
+ {rest, env}
+ end
+ defp eval([{:symbol, "ffi"} | rest], env) do
+ [m, f, a] = rest
+ {m, env} = eval(m, env)
+ {f, env} = eval(f, env)
+ {a, env} = eval(a, env)
+ {apply(m, f, a), env}
+ end
+ defp eval([{:symbol, "define"} | rest], env) do
+ [{:symbol, name}, body] = rest
+ {val, env} = eval(body, env)
+ env = Map.put(env, name, val)
+
+ {val, env}
end
defp eval([{:symbol, "lambda"} | rest ], env) do
[ arg_names | [body] ] = rest
- fn args ->
+ {fn args ->
arg_names = Enum.map(arg_names, fn {:symbol, name} -> name end)
combination = Enum.zip(arg_names, args)
- eval(body, extend(combination, env))
- end
+ {val, _} = eval(body, extend(combination, env))
+ val
+ end, env}
end
defp eval([h | t], env) do
- f = eval(h, env)
- args = Enum.map(t, &eval(&1, env))
+ {f, env} = eval(h, env)
+ args = Enum.map(t, fn x ->
+ {val, _} = eval(x, env)
+ val
+ end)
- f.(args)
+ {f.(args), env}
end
defp extend([{name, val} | rest], env) do
extend(rest, Map.put(env, name, val))
@@ 64,7 64,7 @@ defmodule Lixp.Parser do
)
defparsec(
:term,
- choice([list, number(), atom, symbol, ignore(string(" "))])
+ choice([list, number(), atom, symbol, ignore(string(" ")), ignore(string("\n"))])
)
defparsec(