@@ -367,16 +367,21 @@ defmodule Module.Types.Descr do
367
367
368
368
@ doc """
369
369
Converts a descr to its quoted representation.
370
+
371
+ ## Options
372
+
373
+ * `:collapse_structs` - do not show struct fields that match
374
+ their default type
370
375
"""
371
- def to_quoted ( descr ) do
376
+ def to_quoted ( descr , opts \\ [ ] ) do
372
377
if term_type? ( descr ) do
373
378
{ :term , [ ] , [ ] }
374
379
else
375
380
# Dynamic always come first for visibility
376
381
{ dynamic , descr } =
377
382
case :maps . take ( :dynamic , descr ) do
378
383
:error -> { [ ] , descr }
379
- { dynamic , descr } -> { to_quoted ( :dynamic , dynamic ) , descr }
384
+ { dynamic , descr } -> { to_quoted ( :dynamic , dynamic , opts ) , descr }
380
385
end
381
386
382
387
# Merge empty list and list together if they both exist
@@ -385,7 +390,7 @@ defmodule Module.Types.Descr do
385
390
% { list: list , bitmap: bitmap } when ( bitmap &&& @ bit_empty_list ) != 0 ->
386
391
descr = descr |> Map . delete ( :list ) |> Map . replace! ( :bitmap , bitmap - @ bit_empty_list )
387
392
388
- case list_to_quoted ( list , :list ) do
393
+ case list_to_quoted ( list , :list , opts ) do
389
394
[ ] -> { [ { :empty_list , [ ] , [ ] } ] , descr }
390
395
unions -> { unions , descr }
391
396
end
@@ -396,7 +401,9 @@ defmodule Module.Types.Descr do
396
401
397
402
unions =
398
403
dynamic ++
399
- Enum . sort ( extra ++ Enum . flat_map ( descr , fn { key , value } -> to_quoted ( key , value ) end ) )
404
+ Enum . sort (
405
+ extra ++ Enum . flat_map ( descr , fn { key , value } -> to_quoted ( key , value , opts ) end )
406
+ )
400
407
401
408
case unions do
402
409
[ ] -> { :none , [ ] , [ ] }
@@ -405,19 +412,19 @@ defmodule Module.Types.Descr do
405
412
end
406
413
end
407
414
408
- defp to_quoted ( :atom , val ) , do: atom_to_quoted ( val )
409
- defp to_quoted ( :bitmap , val ) , do: bitmap_to_quoted ( val )
410
- defp to_quoted ( :dynamic , descr ) , do: dynamic_to_quoted ( descr )
411
- defp to_quoted ( :map , dnf ) , do: map_to_quoted ( dnf )
412
- defp to_quoted ( :list , dnf ) , do: list_to_quoted ( dnf , :non_empty_list )
413
- defp to_quoted ( :tuple , dnf ) , do: tuple_to_quoted ( dnf )
415
+ defp to_quoted ( :atom , val , _opts ) , do: atom_to_quoted ( val )
416
+ defp to_quoted ( :bitmap , val , _opts ) , do: bitmap_to_quoted ( val )
417
+ defp to_quoted ( :dynamic , descr , opts ) , do: dynamic_to_quoted ( descr , opts )
418
+ defp to_quoted ( :map , dnf , opts ) , do: map_to_quoted ( dnf , opts )
419
+ defp to_quoted ( :list , dnf , opts ) , do: list_to_quoted ( dnf , :non_empty_list , opts )
420
+ defp to_quoted ( :tuple , dnf , opts ) , do: tuple_to_quoted ( dnf , opts )
414
421
415
422
@ doc """
416
423
Converts a descr to its quoted string representation.
417
424
"""
418
- def to_quoted_string ( descr ) do
425
+ def to_quoted_string ( descr , opts \\ [ ] ) do
419
426
descr
420
- |> to_quoted ( )
427
+ |> to_quoted ( opts )
421
428
|> Code.Formatter . to_algebra ( )
422
429
|> Inspect.Algebra . format ( 98 )
423
430
|> IO . iodata_to_binary ( )
@@ -1045,16 +1052,16 @@ defmodule Module.Types.Descr do
1045
1052
end
1046
1053
end
1047
1054
1048
- defp list_to_quoted ( dnf , name ) do
1055
+ defp list_to_quoted ( dnf , name , opts ) do
1049
1056
dnf = list_normalize ( dnf )
1050
1057
1051
1058
for { list_type , last_type , negs } <- dnf , reduce: [ ] do
1052
1059
acc ->
1053
1060
arguments =
1054
1061
if subtype? ( last_type , @ empty_list ) do
1055
- [ to_quoted ( list_type ) ]
1062
+ [ to_quoted ( list_type , opts ) ]
1056
1063
else
1057
- [ to_quoted ( list_type ) , to_quoted ( last_type ) ]
1064
+ [ to_quoted ( list_type , opts ) , to_quoted ( last_type , opts ) ]
1058
1065
end
1059
1066
1060
1067
if negs == [ ] do
@@ -1064,9 +1071,9 @@ defmodule Module.Types.Descr do
1064
1071
|> Enum . map ( fn { ty , lst } ->
1065
1072
args =
1066
1073
if subtype? ( lst , @ empty_list ) do
1067
- [ to_quoted ( ty ) ]
1074
+ [ to_quoted ( ty , opts ) ]
1068
1075
else
1069
- [ to_quoted ( ty ) , to_quoted ( lst ) ]
1076
+ [ to_quoted ( ty , opts ) , to_quoted ( lst , opts ) ]
1070
1077
end
1071
1078
1072
1079
{ name , [ ] , args }
@@ -1176,7 +1183,7 @@ defmodule Module.Types.Descr do
1176
1183
end
1177
1184
end
1178
1185
1179
- defp dynamic_to_quoted ( descr ) do
1186
+ defp dynamic_to_quoted ( descr , opts ) do
1180
1187
cond do
1181
1188
term_type? ( descr ) ->
1182
1189
[ { :dynamic , [ ] , [ ] } ]
@@ -1185,7 +1192,7 @@ defmodule Module.Types.Descr do
1185
1192
[ single ]
1186
1193
1187
1194
true ->
1188
- case to_quoted ( descr ) do
1195
+ case to_quoted ( descr , opts ) do
1189
1196
{ :none , _meta , [ ] } = none -> [ none ]
1190
1197
descr -> [ { :dynamic , [ ] , [ descr ] } ]
1191
1198
end
@@ -1786,51 +1793,77 @@ defmodule Module.Types.Descr do
1786
1793
end ) )
1787
1794
end
1788
1795
1789
- defp map_to_quoted ( dnf ) do
1796
+ defp map_to_quoted ( dnf , opts ) do
1790
1797
dnf
1791
1798
|> map_normalize ( )
1792
- |> Enum . map ( & map_each_to_quoted / 1 )
1799
+ |> Enum . map ( & map_each_to_quoted ( & 1 , opts ) )
1793
1800
end
1794
1801
1795
- defp map_each_to_quoted ( { tag , positive_map , negative_maps } ) do
1802
+ defp map_each_to_quoted ( { tag , positive_map , negative_maps } , opts ) do
1796
1803
case negative_maps do
1797
1804
[ ] ->
1798
- map_literal_to_quoted ( { tag , positive_map } )
1805
+ map_literal_to_quoted ( { tag , positive_map } , opts )
1799
1806
1800
1807
_ ->
1801
1808
negative_maps
1802
- |> Enum . map ( & map_literal_to_quoted / 1 )
1809
+ |> Enum . map ( & map_literal_to_quoted ( & 1 , opts ) )
1803
1810
|> Enum . reduce ( & { :or , [ ] , [ & 2 , & 1 ] } )
1804
1811
|> Kernel . then (
1805
- & { :and , [ ] , [ map_literal_to_quoted ( { tag , positive_map } ) , { :not , [ ] , [ & 1 ] } ] }
1812
+ & { :and , [ ] , [ map_literal_to_quoted ( { tag , positive_map } , opts ) , { :not , [ ] , [ & 1 ] } ] }
1806
1813
)
1807
1814
end
1808
1815
end
1809
1816
1810
- def map_literal_to_quoted ( { :closed , fields } ) when map_size ( fields ) == 0 do
1817
+ def map_literal_to_quoted ( { :closed , fields } , _opts ) when map_size ( fields ) == 0 do
1811
1818
{ :empty_map , [ ] , [ ] }
1812
1819
end
1813
1820
1814
- def map_literal_to_quoted ( { tag , fields } ) do
1821
+ def map_literal_to_quoted ( { tag , fields } , opts ) do
1815
1822
case tag do
1816
1823
:closed ->
1817
1824
with % { __struct__: struct_descr } <- fields ,
1818
1825
{ _ , [ struct ] } <- atom_fetch ( struct_descr ) do
1826
+ fields = Map . delete ( fields , :__struct__ )
1827
+
1828
+ fields =
1829
+ with true <- Keyword . get ( opts , :collapse_structs , false ) ,
1830
+ [ _ | _ ] = info <- maybe_struct ( struct ) ,
1831
+ true <- Enum . all? ( info , & is_map_key ( fields , & 1 . field ) ) do
1832
+ Enum . reduce ( info , fields , fn % { field: field } , acc ->
1833
+ # TODO: This should consider the struct default value
1834
+ if Map . fetch! ( acc , field ) == term ( ) do
1835
+ Map . delete ( acc , field )
1836
+ else
1837
+ acc
1838
+ end
1839
+ end )
1840
+ else
1841
+ _ -> fields
1842
+ end
1843
+
1819
1844
{ :% , [ ] ,
1820
1845
[
1821
1846
literal_to_quoted ( struct ) ,
1822
- { :%{} , [ ] , map_fields_to_quoted ( tag , Map . delete ( fields , :__struct__ ) ) }
1847
+ { :%{} , [ ] , map_fields_to_quoted ( tag , fields , opts ) }
1823
1848
] }
1824
1849
else
1825
- _ -> { :%{} , [ ] , map_fields_to_quoted ( tag , fields ) }
1850
+ _ -> { :%{} , [ ] , map_fields_to_quoted ( tag , fields , opts ) }
1826
1851
end
1827
1852
1828
1853
:open ->
1829
- { :%{} , [ ] , [ { :... , [ ] , nil } | map_fields_to_quoted ( tag , fields ) ] }
1854
+ { :%{} , [ ] , [ { :... , [ ] , nil } | map_fields_to_quoted ( tag , fields , opts ) ] }
1855
+ end
1856
+ end
1857
+
1858
+ defp maybe_struct ( struct ) do
1859
+ try do
1860
+ struct . __info__ ( :struct )
1861
+ rescue
1862
+ _ -> nil
1830
1863
end
1831
1864
end
1832
1865
1833
- defp map_fields_to_quoted ( tag , map ) do
1866
+ defp map_fields_to_quoted ( tag , map , opts ) do
1834
1867
sorted = Enum . sort ( Map . to_list ( map ) )
1835
1868
keyword? = Inspect.List . keyword? ( sorted )
1836
1869
@@ -1846,9 +1879,9 @@ defmodule Module.Types.Descr do
1846
1879
{ optional? , type } = pop_optional_static ( type )
1847
1880
1848
1881
cond do
1849
- not optional? -> { key , to_quoted ( type ) }
1882
+ not optional? -> { key , to_quoted ( type , opts ) }
1850
1883
empty? ( type ) -> { key , { :not_set , [ ] , [ ] } }
1851
- true -> { key , { :if_set , [ ] , [ to_quoted ( type ) ] } }
1884
+ true -> { key , { :if_set , [ ] , [ to_quoted ( type , opts ) ] } }
1852
1885
end
1853
1886
end
1854
1887
end
@@ -1969,11 +2002,11 @@ defmodule Module.Types.Descr do
1969
2002
# This is a cheap optimization that relies on structural equality.
1970
2003
defp tuple_union ( left , right ) , do: left ++ ( right -- left )
1971
2004
1972
- defp tuple_to_quoted ( dnf ) do
2005
+ defp tuple_to_quoted ( dnf , opts ) do
1973
2006
dnf
1974
2007
|> tuple_simplify ( )
1975
2008
|> tuple_fusion ( )
1976
- |> Enum . map ( & tuple_each_to_quoted / 1 )
2009
+ |> Enum . map ( & tuple_each_to_quoted ( & 1 , opts ) )
1977
2010
end
1978
2011
1979
2012
# Given a dnf of tuples, fuses the tuple unions when possible,
@@ -2020,27 +2053,27 @@ defmodule Module.Types.Descr do
2020
2053
{ tag , fused_elements , [ ] }
2021
2054
end
2022
2055
2023
- defp tuple_each_to_quoted ( { tag , positive_tuple , negative_tuples } ) do
2056
+ defp tuple_each_to_quoted ( { tag , positive_tuple , negative_tuples } , opts ) do
2024
2057
case negative_tuples do
2025
2058
[ ] ->
2026
- tuple_literal_to_quoted ( { tag , positive_tuple } )
2059
+ tuple_literal_to_quoted ( { tag , positive_tuple } , opts )
2027
2060
2028
2061
_ ->
2029
2062
negative_tuples
2030
- |> Enum . map ( & tuple_literal_to_quoted / 1 )
2063
+ |> Enum . map ( & tuple_literal_to_quoted ( & 1 , opts ) )
2031
2064
|> Enum . reduce ( & { :or , [ ] , [ & 2 , & 1 ] } )
2032
2065
|> Kernel . then (
2033
- & { :and , [ ] , [ tuple_literal_to_quoted ( { tag , positive_tuple } ) , { :not , [ ] , [ & 1 ] } ] }
2066
+ & { :and , [ ] , [ tuple_literal_to_quoted ( { tag , positive_tuple } , opts ) , { :not , [ ] , [ & 1 ] } ] }
2034
2067
)
2035
2068
end
2036
2069
end
2037
2070
2038
- defp tuple_literal_to_quoted ( { :closed , [ ] } ) , do: { :{} , [ ] , [ ] }
2071
+ defp tuple_literal_to_quoted ( { :closed , [ ] } , _opts ) , do: { :{} , [ ] , [ ] }
2039
2072
2040
- defp tuple_literal_to_quoted ( { tag , elements } ) do
2073
+ defp tuple_literal_to_quoted ( { tag , elements } , opts ) do
2041
2074
case tag do
2042
- :closed -> { :{} , [ ] , Enum . map ( elements , & to_quoted / 1 ) }
2043
- :open -> { :{} , [ ] , Enum . map ( elements , & to_quoted / 1 ) ++ [ { :... , [ ] , nil } ] }
2075
+ :closed -> { :{} , [ ] , Enum . map ( elements , & to_quoted ( & 1 , opts ) ) }
2076
+ :open -> { :{} , [ ] , Enum . map ( elements , & to_quoted ( & 1 , opts ) ) ++ [ { :... , [ ] , nil } ] }
2044
2077
end
2045
2078
end
2046
2079
0 commit comments