Skip to content

Commit 5cbe0ba

Browse files
author
José Valim
committed
Merge pull request #1081 from alco/iex-token-missing-error
TokenMissingError fix
2 parents 441c333 + 98ed304 commit 5cbe0ba

File tree

1 file changed

+37
-13
lines changed

1 file changed

+37
-13
lines changed

lib/iex/lib/iex/server.ex

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,12 @@ defmodule IEx.Server do
1010

1111
defp do_loop(config) do
1212
counter = config.counter
13-
cache = config.cache
14-
code = cache ++ io_get(config)
13+
code = config.cache ++ io_get(config)
1514

1615
new_config =
1716
try do
18-
{ result, new_binding, scope } =
19-
:elixir.eval(code, config.binding, counter, config.scope)
20-
21-
io_put result
22-
23-
config = config.result(result)
24-
update_history(config.cache(code).scope(nil))
25-
config.update_counter(&1+1).cache('').binding(new_binding).scope(scope)
17+
eval(code, counter, config)
2618
rescue
27-
TokenMissingError ->
28-
config.cache(code)
2919
exception ->
3020
print_stacktrace System.stacktrace, fn ->
3121
"** (#{inspect exception.__record__(:name)}) #{exception.message}"
@@ -42,6 +32,40 @@ defmodule IEx.Server do
4232
do_loop(new_config)
4333
end
4434

35+
# Instead of doing just `:elixir.eval`, we first parse the expression to see
36+
# if it's well formed. If parsing succeeds, we evaluate the AST as usual.
37+
#
38+
# If parsing fails, this might be a TokenMissingError which we treat in
39+
# a special way (to allow for continuation of an expression on the next
40+
# line in IEx). In case of any other error, we let :elixir_translator
41+
# to re-raise it.
42+
#
43+
# Returns updated config.
44+
defp eval(code, line, config) do
45+
file = "iex"
46+
case :elixir_translator.forms(code, line, file, []) do
47+
{ :ok, forms } ->
48+
{ result, new_binding, scope } =
49+
:elixir.eval_forms(forms, config.binding, config.scope)
50+
51+
io_put result
52+
53+
config = config.result(result)
54+
update_history(config.cache(code).scope(nil))
55+
config.update_counter(&1+1).cache('').binding(new_binding).scope(scope)
56+
57+
{ :error, { line, error, token } } ->
58+
if token == [] do
59+
# Update config.cache so that IEx continues to add new input to
60+
# the unfinished expression in `code`
61+
config.cache(code)
62+
else
63+
# Encountered malformed expression
64+
:elixir_errors.parse_error(line, file, error, token)
65+
end
66+
end
67+
end
68+
4569
defp print_stacktrace(trace, callback) do
4670
try do
4771
io_error callback.()
@@ -84,4 +108,4 @@ defmodule IEx.Server do
84108
defp remote_prefix do
85109
if node == node(:erlang.group_leader), do: "iex", else: "rem"
86110
end
87-
end
111+
end

0 commit comments

Comments
 (0)