diff options
Diffstat (limited to 'lib/syntax_tools/src')
-rw-r--r-- | lib/syntax_tools/src/epp_dodger.erl | 34 | ||||
-rw-r--r-- | lib/syntax_tools/src/erl_comment_scan.erl | 13 | ||||
-rw-r--r-- | lib/syntax_tools/src/erl_syntax.erl | 35 |
3 files changed, 77 insertions, 5 deletions
diff --git a/lib/syntax_tools/src/epp_dodger.erl b/lib/syntax_tools/src/epp_dodger.erl index 131be4e8e4..3ca7a8197e 100644 --- a/lib/syntax_tools/src/epp_dodger.erl +++ b/lib/syntax_tools/src/epp_dodger.erl @@ -88,7 +88,7 @@ %% This is a so-called Erlang I/O ErrorInfo structure; see the {@link %% //stdlib/io} module for details. --type errorinfo() :: term(). % {integer(), atom(), term()}. +-type errorinfo() :: {integer(), atom(), term()}. -type option() :: atom() | {atom(), term()}. @@ -184,16 +184,42 @@ quick_parse_file(File, Options) -> parse_file(File, fun quick_parse/3, Options ++ [no_fail]). parse_file(File, Parser, Options) -> + case do_parse_file(utf8, File, Parser, Options) of + {ok, Forms}=Ret -> + case find_invalid_unicode(Forms) of + none -> + Ret; + invalid_unicode -> + case epp:read_encoding(File) of + utf8 -> + Ret; + _ -> + do_parse_file(latin1, File, Parser, Options) + end + end; + Else -> + Else + end. + +do_parse_file(DefEncoding, File, Parser, Options) -> case file:open(File, [read]) of {ok, Dev} -> - _ = epp:set_encoding(Dev), + _ = epp:set_encoding(Dev, DefEncoding), try Parser(Dev, 1, Options) after ok = file:close(Dev) end; - {error, _} = Error -> - Error + {error, Error} -> + {error, {0, file, Error}} % defer to file:format_error/1 end. +find_invalid_unicode([H|T]) -> + case H of + {error, {_Line, file_io_server, invalid_unicode}} -> + invalid_unicode; + _Other -> + find_invalid_unicode(T) + end; +find_invalid_unicode([]) -> none. %% ===================================================================== %% @spec parse(IODevice) -> {ok, Forms} | {error, errorinfo()} diff --git a/lib/syntax_tools/src/erl_comment_scan.erl b/lib/syntax_tools/src/erl_comment_scan.erl index dae7530ce7..03429d4d42 100644 --- a/lib/syntax_tools/src/erl_comment_scan.erl +++ b/lib/syntax_tools/src/erl_comment_scan.erl @@ -72,13 +72,24 @@ file(Name) -> {ok, V} -> case V of {ok, B} -> - Enc = case epp:read_encoding(Name) of + Encoding = epp:read_encoding_from_binary(B), + Enc = case Encoding of none -> epp:default_encoding(); Enc0 -> Enc0 end, case catch unicode:characters_to_list(B, Enc) of String when is_list(String) -> string(String); + R when Encoding =:= none -> + case + catch unicode:characters_to_list(B, latin1) + of + String when is_list(String) -> + string(String); + _ -> + error_read_file(Name1), + exit(R) + end; R -> error_read_file(Name1), exit(R) diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl index 46a5ca48df..40372a2106 100644 --- a/lib/syntax_tools/src/erl_syntax.erl +++ b/lib/syntax_tools/src/erl_syntax.erl @@ -669,6 +669,9 @@ is_leaf(Node) -> operator -> true; % nonstandard type string -> true; text -> true; % nonstandard type + map_expr -> + map_expr_fields(Node) =:= [] andalso + map_expr_argument(Node) =:= none; tuple -> tuple_elements(Node) =:= []; underscore -> true; variable -> true; @@ -6093,6 +6096,9 @@ abstract([]) -> nil(); abstract(T) when is_tuple(T) -> tuple(abstract_list(tuple_to_list(T))); +abstract(T) when is_map(T) -> + map_expr([map_field_assoc(abstract(Key),abstract(Value)) + || {Key,Value} <- maps:to_list(T)]); abstract(T) when is_binary(T) -> binary([binary_field(integer(B)) || B <- binary_to_list(T)]); abstract(T) -> @@ -6154,6 +6160,14 @@ concrete(Node) -> | concrete(list_tail(Node))]; tuple -> list_to_tuple(concrete_list(tuple_elements(Node))); + map_expr -> + As = [tuple([map_field_assoc_name(F), + map_field_assoc_value(F)]) || F <- map_expr_fields(Node)], + M0 = maps:from_list(concrete_list(As)), + case map_expr_argument(Node) of + none -> M0; + Node0 -> maps:merge(concrete(Node0),M0) + end; binary -> Fs = [revert_binary_field( binary_field(binary_field_body(F), @@ -6209,10 +6223,31 @@ is_literal(T) -> is_literal(list_head(T)) andalso is_literal(list_tail(T)); tuple -> lists:all(fun is_literal/1, tuple_elements(T)); + map_expr -> + case map_expr_argument(T) of + none -> true; + Arg -> is_literal(Arg) + end andalso lists:all(fun is_literal_map_field/1, map_expr_fields(T)); + binary -> + lists:all(fun is_literal_binary_field/1, binary_fields(T)); _ -> false end. +is_literal_binary_field(F) -> + case binary_field_types(F) of + [] -> is_literal(binary_field_body(F)); + _ -> false + end. + +is_literal_map_field(F) -> + case type(F) of + map_field_assoc -> + is_literal(map_field_assoc_name(F)) andalso + is_literal(map_field_assoc_value(F)); + map_field_exact -> + false + end. %% ===================================================================== %% @doc Returns an `erl_parse'-compatible representation of a |