aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Bolinder <[email protected]>2019-03-21 09:25:16 +0100
committerHans Bolinder <[email protected]>2019-04-12 08:56:38 +0200
commit16055085f761531ed1679c55fdcc14928aec1e1d (patch)
tree88b4d845b9d579b03743284b37e5c25918042670
parentf99398161726821c67d9da07eb869221d4ecf539 (diff)
downloadotp-16055085f761531ed1679c55fdcc14928aec1e1d.tar.gz
otp-16055085f761531ed1679c55fdcc14928aec1e1d.tar.bz2
otp-16055085f761531ed1679c55fdcc14928aec1e1d.zip
stdlib: Add option 'quote_singleton_atom_types' to erl_pp
The new option can be used by Dialyzer, which has traditionally quoted singleton atom types. The OTP team has decided not to use the convention in OTP documentation, at least not for now. That is why the option is needed. EDoc does not use the new option. Syntax Tools does not have a similar option.
-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) ->