@@ -10,22 +10,12 @@ defmodule IEx.Server do
10
10
11
11
defp do_loop ( config ) do
12
12
counter = config . counter
13
- cache = config . cache
14
- code = cache ++ io_get ( config )
13
+ code = config . cache ++ io_get ( config )
15
14
16
15
new_config =
17
16
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 )
26
18
rescue
27
- TokenMissingError ->
28
- config . cache ( code )
29
19
exception ->
30
20
print_stacktrace System . stacktrace , fn ->
31
21
"** (#{ inspect exception . __record__ ( :name ) } ) #{ exception . message } "
@@ -42,6 +32,40 @@ defmodule IEx.Server do
42
32
do_loop ( new_config )
43
33
end
44
34
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
+
45
69
defp print_stacktrace ( trace , callback ) do
46
70
try do
47
71
io_error callback . ( )
@@ -84,4 +108,4 @@ defmodule IEx.Server do
84
108
defp remote_prefix do
85
109
if node == node ( :erlang . group_leader ) , do: "iex" , else: "rem"
86
110
end
87
- end
111
+ end
0 commit comments