aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/stdlib/doc/src/erl_pp.xml6
-rw-r--r--lib/stdlib/src/erl_pp.erl51
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl18
3 files changed, 63 insertions, 12 deletions
diff --git a/lib/stdlib/doc/src/erl_pp.xml b/lib/stdlib/doc/src/erl_pp.xml
index f1c3aa5a41..0a46139db6 100644
--- a/lib/stdlib/doc/src/erl_pp.xml
+++ b/lib/stdlib/doc/src/erl_pp.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>1996</year>
- <year>2016</year>
+ <year>2019</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -65,6 +65,10 @@
</datatype>
<datatype>
<name name="option"/>
+ <desc>
+ <p>The option <c>quote_singleton_atom_types</c>
+ is used to add quotes to all singleton atom types.</p>
+ </desc>
</datatype>
<datatype>
<name name="options"/>
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 3e68c1b225..2630c60859 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -41,10 +41,11 @@
io_lib:chars())).
-type(option() :: {hook, hook_function()}
- | {encoding, latin1 | unicode | utf8}).
+ | {encoding, latin1 | unicode | utf8}
+ | {quote_singleton_atom_types, boolean()}).
-type(options() :: hook_function() | [option()]).
--record(pp, {value_fun, string_fun, char_fun}).
+-record(pp, {value_fun, singleton_atom_type_fun, string_fun, char_fun}).
-record(options, {hook, encoding, opts}).
@@ -206,22 +207,43 @@ options(Hook) ->
#options{hook = Hook, encoding = encoding([]), opts = Hook}.
state(Options) when is_list(Options) ->
+ Quote = proplists:get_bool(quote_singleton_atom_types, Options),
case encoding(Options) of
- latin1 -> state();
- unicode -> unicode_state()
+ latin1 -> latin1_state(Quote);
+ unicode -> unicode_state(Quote)
end;
state(_Hook) ->
- state().
+ latin1_state(false).
-state() ->
+latin1_state(Quote) ->
Options = [{encoding,latin1}],
- #pp{value_fun = fun(V) -> io_lib_pretty:print(V, Options) end,
+ ValueFun = fun(V) -> io_lib_pretty:print(V, Options) end,
+ SingletonFun =
+ case Quote of
+ true ->
+ fun(A) ->
+ io_lib:write_string_as_latin1(atom_to_list(A), $')
+ end; %'
+ false ->
+ ValueFun
+ end,
+ #pp{value_fun = ValueFun,
+ singleton_atom_type_fun = SingletonFun,
string_fun = fun io_lib:write_string_as_latin1/1,
char_fun = fun io_lib:write_char_as_latin1/1}.
-unicode_state() ->
+unicode_state(Quote) ->
Options = [{encoding,unicode}],
- #pp{value_fun = fun(V) -> io_lib_pretty:print(V, Options) end,
+ ValueFun = fun(V) -> io_lib_pretty:print(V, Options) end,
+ SingletonFun =
+ case Quote of
+ true ->
+ fun(A) -> io_lib:write_string(atom_to_list(A), $') end; %'
+ false ->
+ ValueFun
+ end,
+ #pp{value_fun = ValueFun,
+ singleton_atom_type_fun = SingletonFun,
string_fun = fun io_lib:write_string/1,
char_fun = fun io_lib:write_char/1}.
@@ -350,7 +372,7 @@ ltype({user_type,Line,T,Ts}, _) ->
ltype({remote_type,Line,[M,F,Ts]}, _) ->
simple_type({remote,Line,M,F}, Ts);
ltype({atom,_,T}, _) ->
- {atom,T};
+ {singleton_atom_type,T};
ltype(E, P) ->
lexpr(E, P, options(none)).
@@ -933,6 +955,7 @@ frmt(Item, I, PP) ->
%%% - {prefer_nl,Sep,IPs}: forces linebreak between Is unlesss negative
%%% indentation.
%%% - {atom,A}: an atom
+%%% - {singleton_atom_type,A}: an singleton atom type
%%% - {char,C}: a character
%%% - {string,S}: a string.
%%% - {value,T}: a term.
@@ -1000,6 +1023,8 @@ f({value,V}, I, ST, WT, PP) ->
f(write_a_value(V, PP), I, ST, WT, PP);
f({atom,A}, I, ST, WT, PP) ->
f(write_an_atom(A, PP), I, ST, WT, PP);
+f({singleton_atom_type,A}, I, ST, WT, PP) ->
+ f(write_a_singleton_atom_type(A, PP), I, ST, WT, PP);
f({char,C}, I, ST, WT, PP) ->
f(write_a_char(C, PP), I, ST, WT, PP);
f({string,S}, I, ST, WT, PP) ->
@@ -1144,6 +1169,9 @@ write_a_value(V, PP) ->
write_an_atom(A, PP) ->
flat_leaf(write_atom(A, PP)).
+write_a_singleton_atom_type(A, PP) ->
+ flat_leaf(write_singleton_atom_type(A, PP)).
+
write_a_char(C, PP) ->
flat_leaf(write_char(C, PP)).
@@ -1178,6 +1206,9 @@ write_value(V, PP) ->
write_atom(A, PP) ->
(PP#pp.value_fun)(A).
+write_singleton_atom_type(A, PP) ->
+ (PP#pp.singleton_atom_type_fun)(A).
+
write_string(S, PP) ->
(PP#pp.string_fun)(S).
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index e5d1910070..c79e29eb11 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -47,6 +47,7 @@
hook/1,
neg_indent/1,
maps_syntax/1,
+ quoted_atom_types/1,
otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1,
otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1,
@@ -74,7 +75,7 @@ groups() ->
[{expr, [],
[func, call, recs, try_catch, if_then, receive_after,
bits, head_tail, cond1, block, case1, ops,
- messages, maps_syntax
+ messages, maps_syntax, quoted_atom_types
]},
{attributes, [], [misc_attrs, import_export, dialyzer_attrs]},
{tickets, [],
@@ -912,6 +913,21 @@ maps_syntax(Config) when is_list(Config) ->
ok = pp_forms(F),
ok.
+quoted_atom_types(Config) when is_list(Config) ->
+ Q = [{quote_singleton_atom_types, true}],
+ U = [{encoding,unicode}],
+ L = [{encoding,latin1}],
+ F = "-type t() :: a | a().",
+ "-type t() :: 'a' | a().\n" =
+ lists:flatten(parse_and_pp_forms(F, Q ++ L)),
+ "-type t() :: 'a' | a().\n" =
+ lists:flatten(parse_and_pp_forms(F, Q ++ U)),
+ UF = "-type t() :: '\x{400}' | '\x{400}'().",
+ "-type t() :: '\\x{400}' | '\\x{400}'().\n" =
+ lists:flatten(parse_and_pp_forms(UF, Q ++ L)),
+ "-type t() :: '\x{400}' | '\x{400}'().\n" =
+ lists:flatten(parse_and_pp_forms(UF, Q ++ U)),
+ ok.
%% OTP_8567. Avoid duplicated 'undefined' in record field types.
otp_8567(Config) when is_list(Config) ->