1 defmodule Mix
.Tasks
.Step7Quote
do
6 env
= Mal
.Env
.initialize()
7 Mal
.Env
.merge(env
, Mal
.Core
.namespace
)
13 defp
load_file([], _env
), do: nil
14 defp
load_file([file_name | _args
], env
) do
16 (load-file "#
{file_name
}")
21 defp
bootstrap(args
, env
) do
25 (fn* (a) (if a false true)))
32 (eval (read-string (str "(do " (slurp f) ")")))))
35 Mal
.Env
.set(env
, "eval", fn
[ast
] ->
40 [_file_name | rest
] -> Mal
.Env
.set(env
, "*ARGV*", list(rest
))
41 [] -> Mal
.Env
.set(env
, "*ARGV*", list([]))
46 IO
.write(:stdio
, "user> ")
47 IO
.read(:stdio
, :line
)
48 |
> read_eval_print(env
)
54 defp
eval_ast({:list
, ast
, meta
}, env
) when
is_list(ast
) do
55 {:list
, Enum
.map(ast
, fn elem
-> eval(elem
, env
) end), meta
}
58 defp
eval_ast({:map
, ast
, meta
}, env
) do
59 map
= for {key
, value} <- ast
, into
: %{} do
60 {eval(key
, env
), eval(value, env
)}
66 defp
eval_ast({:vector
, ast
, meta
}, env
) do
67 {:vector
, Enum
.map(ast
, fn elem
-> eval(elem
, env
) end), meta
}
70 defp
eval_ast({:symbol
, symbol
}, env
) do
71 case Mal
.Env
.get(env
, symbol
) do
73 :not_found
-> throw({:error
, "'#{symbol}' not found"})
77 defp
eval_ast(ast
, _env
), do: ast
80 Mal
.Reader
.read_str(input
)
83 defp
eval_bindings([], _env
), do: _env
84 defp
eval_bindings([{:symbol
, key
}, binding | tail
], env
) do
85 evaluated
= eval(binding
, env
)
86 Mal
.Env
.set(env
, key
, evaluated
)
87 eval_bindings(tail
, env
)
89 defp
eval_bindings(_bindings
, _env
), do: throw({:error
, "Unbalanced let* bindings"})
91 defp
quasi_list([], _env
), do: list([{:symbol
, "quote"}, list([])])
92 defp
quasi_list([{:symbol
, "unquote"}, arg
], _env
), do: arg
93 defp
quasi_list([{:list
, [{:symbol
, "splice-unquote"}, first
], _meta
} | tail
], env
) do
98 list([{:symbol
, "concat"}, first
, right
])
100 defp
quasi_list([head | tail
], env
) do
101 left
= quasiquote(head
, env
)
106 list([{:symbol
, "cons"}, left
, right
])
109 defp
quasiquote({list_type
, ast
, _
}, env
)
110 when list_type in
[:list
, :vector
] do
113 defp
quasiquote(ast
, _env
), do: list([{:symbol
, "quote"}, ast
])
115 defp
eval({:list
, ast
, meta
}, env
), do: eval_list(ast
, env
, meta
)
116 defp
eval(ast
, env
), do: eval_ast(ast
, env
)
118 defp
eval_list([{:symbol
, "if"}, condition
, if_true | if_false
], env
, _
) do
119 result
= eval(condition
, env
)
120 if result
== nil
or result
== false
do
123 [body
] -> eval(body
, env
)
130 defp
eval_list([{:symbol
, "do"} | ast
], env
, _
) do
132 |
> List
.delete_at(-1)
135 eval(List
.last(ast
), env
)
138 defp
eval_list([{:symbol
, "def!"}, {:symbol
, key
}, value], env
, _
) do
139 evaluated
= eval(value, env
)
140 Mal
.Env
.set(env
, key
, evaluated
)
144 defp
eval_list([{:symbol
, "let*"}, {list_type
, bindings
, _
}, body
], env
, _
)
145 when list_type
== :list
or list_type
== :vector
do
146 let_env
= Mal
.Env
.initialize(env
)
147 eval_bindings(bindings
, let_env
)
151 defp
eval_list([{:symbol
, "fn*"}, {list_type
, params
, _
}, body
], env
, _
)
152 when list_type
== :list
or list_type
== :vector
do
153 param_symbols
= for {:symbol
, symbol
} <- params
, do: symbol
156 inner
= Mal
.Env
.initialize(env
, param_symbols
, args
)
160 %Function
{value: closure
}
163 defp
eval_list([{:symbol
, "quote"}, arg
], _env
, _
), do: arg
165 defp
eval_list([{:symbol
, "quasiquote"}, ast
], env
, _
) do
170 defp
eval_list(ast
, env
, meta
) do
171 {:list
, [func | args
], _
} = eval_ast({:list
, ast
, meta
}, env
)
173 %Function
{value: closure
} -> closure
.(args
)
179 Mal
.Printer
.print_str(value)
182 defp
read_eval_print(:eof
, _env
), do: exit(:normal
)
183 defp
read_eval_print(line
, env
) do
188 {:error
, message
} -> IO
.puts("Error: #{message}")