summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@plataformatec.com.br>2017-05-26 22:09:23 +0200
committerJosé Valim <jose.valim@plataformatec.com.br>2017-05-26 22:09:23 +0200
commit2e8eb159ca2d9710f2258985cf4f59716fa93b19 (patch)
tree452afed84d2e3338879e2585bf2c75bbadbe77da
parent6164e5024266b8c166ae383790071a3e66826e34 (diff)
downloadelixir-2e8eb159ca2d9710f2258985cf4f59716fa93b19.tar.gz
Improve error messages
-rw-r--r--lib/elixir/src/elixir_tokenizer.erl15
-rw-r--r--lib/elixir/test/elixir/kernel/errors_test.exs24
-rw-r--r--lib/elixir/unicode/tokenizer.ex2
3 files changed, 28 insertions, 13 deletions
diff --git a/lib/elixir/src/elixir_tokenizer.erl b/lib/elixir/src/elixir_tokenizer.erl
index 18914e498..c5b810625 100644
--- a/lib/elixir/src/elixir_tokenizer.erl
+++ b/lib/elixir/src/elixir_tokenizer.erl
@@ -471,11 +471,11 @@ tokenize(String, Line, Column, Scope, Tokens) ->
Reason = {Line, "keyword argument must be followed by space after: ", AtomName},
{error, Reason, String, Tokens};
_ when HasAt ->
- Reason = {Line, invalid_character_error($@), atom_to_list(Atom)},
+ Reason = {Line, invalid_character_error(Kind, $@), atom_to_list(Atom)},
{error, Reason, String, Tokens};
_ when Kind == alias ->
tokenize_alias(Rest, Line, Column, Atom, Length, Ascii, Special, Scope, Tokens);
- _ when Kind == var ->
+ _ when Kind == identifier ->
tokenize_other(Rest, Line, Column, Atom, Length, Scope, Tokens);
_ ->
unexpected_token(String, Line, Column, Tokens)
@@ -837,7 +837,7 @@ tokenize([H | T]) when ?is_upcase(H) ->
{alias, lists:reverse(Acc), Rest, Length, true, Special};
tokenize([H | T]) when ?is_downcase(H); H == $_ ->
{Acc, Rest, Length, Special} = tokenize_continue(T, [H], 1, []),
- {var, lists:reverse(Acc), Rest, Length, true, Special};
+ {identifier, lists:reverse(Acc), Rest, Length, true, Special};
tokenize(_List) ->
{error, empty}.
@@ -869,11 +869,12 @@ tokenize_alias(Rest, Line, Column, Atom, Length, Ascii, Special, Scope, Tokens)
if
not Ascii ->
AtomName = atom_to_list(Atom),
- Reason = {Line, "aliases must have only ascii characters", AtomName},
+ Invalid = hd([C || C <- AtomName, C > 127]),
+ Reason = {Line, invalid_character_error("alias (only ascii characters are allowed)", Invalid), AtomName},
{error, Reason, AtomName ++ Rest, Tokens};
Special /= [] ->
AtomName = atom_to_list(Atom),
- Reason = {Line, invalid_character_error(hd(Special)), AtomName},
+ Reason = {Line, invalid_character_error("alias", hd(Special)), AtomName},
{error, Reason, AtomName ++ Rest, Tokens};
true ->
tokenize(Rest, Line, Column + Length, Scope, [{aliases, {Line, Column, Column + Length}, [Atom]} | Tokens])
@@ -1062,8 +1063,8 @@ keyword('catch') -> block;
keyword(_) -> false.
-invalid_character_error(Char) ->
- io_lib:format("invalid character \"~ts\" (codepoint U+~4.16.0B) in token: ", [[Char], Char]).
+invalid_character_error(What, Char) ->
+ io_lib:format("invalid character \"~ts\" (codepoint U+~4.16.0B) in ~ts: ", [[Char], Char, What]).
invalid_do_error(Prefix) ->
Prefix ++ ". In case you wanted to write a \"do\" expression, "
diff --git a/lib/elixir/test/elixir/kernel/errors_test.exs b/lib/elixir/test/elixir/kernel/errors_test.exs
index bc67d627b..ecfffa49f 100644
--- a/lib/elixir/test/elixir/kernel/errors_test.exs
+++ b/lib/elixir/test/elixir/kernel/errors_test.exs
@@ -38,12 +38,26 @@ defmodule Kernel.ErrorsTest do
end
test "invalid identifier" do
- msg = fn name -> "nofile:1: invalid character \"@\" (codepoint U+0040) in token: #{name}" end
+ message = fn name -> "nofile:1: invalid character \"@\" (codepoint U+0040) in identifier: #{name}" end
+ assert_compile_fail SyntaxError, message.("foo@"), 'foo@'
+ assert_compile_fail SyntaxError, message.("foo@"), 'foo@ '
+ assert_compile_fail SyntaxError, message.("foo@bar"), 'foo@bar'
- assert_compile_fail SyntaxError, msg.("foo@"), 'foo@'
- assert_compile_fail SyntaxError, msg.("foo@"), 'foo@ '
- assert_compile_fail SyntaxError, msg.("foo@bar"), 'foo@bar'
- assert_compile_fail SyntaxError, msg.("Foo@"), 'Foo@'
+ message = fn name -> "nofile:1: invalid character \"@\" (codepoint U+0040) in alias: #{name}" end
+ assert_compile_fail SyntaxError, message.("Foo@"), 'Foo@'
+ assert_compile_fail SyntaxError, message.("Foo@bar"), 'Foo@bar'
+
+ message = "nofile:1: invalid character \"!\" (codepoint U+0021) in alias: Foo!"
+ assert_compile_fail SyntaxError, message, 'Foo!'
+
+ message = "nofile:1: invalid character \"?\" (codepoint U+003F) in alias: Foo?"
+ assert_compile_fail SyntaxError, message, 'Foo?'
+
+ # TODO: Remove this check once we depend on OTP 20+
+ if :erlang.system_info(:otp_release) >= '20' do
+ message = "invalid character \"ó\" (codepoint U+00F3) in alias (only ascii characters are allowed): Foó"
+ assert_compile_fail SyntaxError, message, 'Foó'
+ end
end
test "invalid fn" do
diff --git a/lib/elixir/unicode/tokenizer.ex b/lib/elixir/unicode/tokenizer.ex
index d65a8a4b4..a3cf0bd38 100644
--- a/lib/elixir/unicode/tokenizer.ex
+++ b/lib/elixir/unicode/tokenizer.ex
@@ -140,7 +140,7 @@ defmodule String.Tokenizer do
ascii_upper?(head) ->
validate(continue(tail, [head], 1, true, []), :alias)
ascii_start?(head) ->
- validate(continue(tail, [head], 1, true, []), :var)
+ validate(continue(tail, [head], 1, true, []), :identifier)
unicode_start?(head) or unicode_upper?(head) ->
validate(continue(tail, [head], 1, false, []), :atom)
true ->