@@ -1204,6 +1204,12 @@ defmodule Code do
12041204 * `:emit_warnings` (since v1.16.0) - when `false`, does not emit
12051205 tokenizing/parsing related warnings. Defaults to `true`.
12061206
1207+ * `:include_comments` (since v1.19.0) - when `true`, includes comments
1208+ in the quoted form. Defaults to `false`. If this option is set to
1209+ `true`, the `:literal_encoder` option must be set to a function
1210+ that ensures all literals are annotated, for example
1211+ `&{:ok, {:__block__, &2, [&1]}}`.
1212+
12071213 ## `Macro.to_string/2`
12081214
12091215 The opposite of converting a string to its quoted form is
@@ -1243,21 +1249,87 @@ defmodule Code do
12431249 * atoms used to represent single-letter sigils like `:sigil_X`
12441250 (but multi-letter sigils like `:sigil_XYZ` are encoded).
12451251
1252+ ## Comments
1253+
1254+ When `include_comments: true` is passed, comments are included in the
1255+ quoted form.
1256+
1257+ There are three types of comments:
1258+ - `:leading_comments`: Comments that are located before a node,
1259+ or in the same line.
1260+
1261+ Examples:
1262+
1263+ # This is a leading comment
1264+ foo # This one too
1265+
1266+ - `:trailing_comments`: Comments that are located after a node, and
1267+ before the end of the parent enclosing the node(or the root document).
1268+
1269+ Examples:
1270+
1271+ foo
1272+ # This is a trailing comment
1273+ # This one too
1274+
1275+ - `:inner_comments`: Comments that are located inside an empty node.
1276+
1277+ Examples:
1278+
1279+ foo do
1280+ # This is an inner comment
1281+ end
1282+
1283+ [
1284+ # This is an inner comment
1285+ ]
1286+
1287+ %{
1288+ # This is an inner comment
1289+ }
1290+
1291+ A comment may be considered inner or trailing depending on wether the enclosing
1292+ node is empty or not. For example, in the following code:
1293+
1294+ foo do
1295+ # This is an inner comment
1296+ end
1297+
1298+ The comment is considered inner because the `do` block is empty. However, in the
1299+ following code:
1300+
1301+ foo do
1302+ bar
1303+ # This is a trailing comment
1304+ end
1305+
1306+ The comment is considered trailing to `bar` because the `do` block is not empty.
1307+
1308+ In the case no nodes are present in the AST but there are comments, they are
1309+ inserted into a placeholder `:__block__` node as `:inner_comments`.
12461310 """
12471311 @ spec string_to_quoted ( List.Chars . t ( ) , keyword ) ::
12481312 { :ok , Macro . t ( ) } | { :error , { location :: keyword , binary | { binary , binary } , binary } }
12491313 def string_to_quoted ( string , opts \\ [ ] ) when is_list ( opts ) do
12501314 file = Keyword . get ( opts , :file , "nofile" )
12511315 line = Keyword . get ( opts , :line , 1 )
12521316 column = Keyword . get ( opts , :column , 1 )
1253- include_comments = Keyword . get ( opts , :include_comments , false )
1317+ include_comments? = Keyword . get ( opts , :include_comments , false )
12541318
12551319 Process . put ( :code_formatter_comments , [ ] )
1256- opts = [ preserve_comments: & preserve_comments / 5 ] ++ opts
1320+ opts =
1321+ if include_comments? do
1322+ [
1323+ preserve_comments: & preserve_comments / 5 ,
1324+ token_metadata: true ,
1325+ ] ++ opts
1326+ else
1327+ opts
1328+ end
12571329
12581330 with { :ok , tokens } <- :elixir . string_to_tokens ( to_charlist ( string ) , line , column , file , opts ) ,
12591331 { :ok , quoted } <- :elixir . tokens_to_quoted ( tokens , file , opts ) do
1260- if include_comments do
1332+ if include_comments? do
12611333 quoted = Code.Normalizer . normalize ( quoted )
12621334 quoted = Code.Comments . merge_comments ( quoted , Process . get ( :code_formatter_comments ) )
12631335
@@ -1287,26 +1359,23 @@ defmodule Code do
12871359 file = Keyword . get ( opts , :file , "nofile" )
12881360 line = Keyword . get ( opts , :line , 1 )
12891361 column = Keyword . get ( opts , :column , 1 )
1290- include_comments = Keyword . get ( opts , :include_comments , false )
1362+ include_comments? = Keyword . get ( opts , :include_comments , false )
12911363
12921364 Process . put ( :code_formatter_comments , [ ] )
12931365
1294- opts =
1295- if include_comments do
1296- [ preserve_comments: & preserve_comments / 5 ,
1297- literal_encoder: & { :ok , { :__block__ , & 2 , [ & 1 ] } } ,
1298- token_metadata: true ,
1299- unescape: false ,
1300- columns: true ,
1301- ] ++ opts
1366+ opts =
1367+ if include_comments? do
1368+ [
1369+ preserve_comments: & preserve_comments / 5 ,
1370+ token_metadata: true ,
1371+ ] ++ opts
13021372 else
13031373 opts
13041374 end
13051375
13061376 quoted = :elixir . string_to_quoted! ( to_charlist ( string ) , line , column , file , opts )
13071377
1308- if include_comments do
1309- # quoted = Code.Normalizer.normalize(quoted)
1378+ if include_comments? do
13101379 Code.Comments . merge_comments ( quoted , Process . get ( :code_formatter_comments ) )
13111380 else
13121381 quoted
0 commit comments