@@ -1209,6 +1209,12 @@ defmodule Code do
12091209 * `:emit_warnings` (since v1.16.0) - when `false`, does not emit
12101210 tokenizing/parsing related warnings. Defaults to `true`.
12111211
1212+ * `:include_comments` (since v1.19.0) - when `true`, includes comments
1213+ in the quoted form. Defaults to `false`. If this option is set to
1214+ `true`, the `:literal_encoder` option must be set to a function
1215+ that ensures all literals are annotated, for example
1216+ `&{:ok, {:__block__, &2, [&1]}}`.
1217+
12121218 ## `Macro.to_string/2`
12131219
12141220 The opposite of converting a string to its quoted form is
@@ -1248,21 +1254,87 @@ defmodule Code do
12481254 * atoms used to represent single-letter sigils like `:sigil_X`
12491255 (but multi-letter sigils like `:sigil_XYZ` are encoded).
12501256
1257+ ## Comments
1258+
1259+ When `include_comments: true` is passed, comments are included in the
1260+ quoted form.
1261+
1262+ There are three types of comments:
1263+ - `:leading_comments`: Comments that are located before a node,
1264+ or in the same line.
1265+
1266+ Examples:
1267+
1268+ # This is a leading comment
1269+ foo # This one too
1270+
1271+ - `:trailing_comments`: Comments that are located after a node, and
1272+ before the end of the parent enclosing the node(or the root document).
1273+
1274+ Examples:
1275+
1276+ foo
1277+ # This is a trailing comment
1278+ # This one too
1279+
1280+ - `:inner_comments`: Comments that are located inside an empty node.
1281+
1282+ Examples:
1283+
1284+ foo do
1285+ # This is an inner comment
1286+ end
1287+
1288+ [
1289+ # This is an inner comment
1290+ ]
1291+
1292+ %{
1293+ # This is an inner comment
1294+ }
1295+
1296+ A comment may be considered inner or trailing depending on wether the enclosing
1297+ node is empty or not. For example, in the following code:
1298+
1299+ foo do
1300+ # This is an inner comment
1301+ end
1302+
1303+ The comment is considered inner because the `do` block is empty. However, in the
1304+ following code:
1305+
1306+ foo do
1307+ bar
1308+ # This is a trailing comment
1309+ end
1310+
1311+ The comment is considered trailing to `bar` because the `do` block is not empty.
1312+
1313+ In the case no nodes are present in the AST but there are comments, they are
1314+ inserted into a placeholder `:__block__` node as `:inner_comments`.
12511315 """
12521316 @ spec string_to_quoted ( List.Chars . t ( ) , keyword ) ::
12531317 { :ok , Macro . t ( ) } | { :error , { location :: keyword , binary | { binary , binary } , binary } }
12541318 def string_to_quoted ( string , opts \\ [ ] ) when is_list ( opts ) do
12551319 file = Keyword . get ( opts , :file , "nofile" )
12561320 line = Keyword . get ( opts , :line , 1 )
12571321 column = Keyword . get ( opts , :column , 1 )
1258- include_comments = Keyword . get ( opts , :include_comments , false )
1322+ include_comments? = Keyword . get ( opts , :include_comments , false )
12591323
12601324 Process . put ( :code_formatter_comments , [ ] )
1261- opts = [ preserve_comments: & preserve_comments / 5 ] ++ opts
1325+ opts =
1326+ if include_comments? do
1327+ [
1328+ preserve_comments: & preserve_comments / 5 ,
1329+ token_metadata: true ,
1330+ ] ++ opts
1331+ else
1332+ opts
1333+ end
12621334
12631335 with { :ok , tokens } <- :elixir . string_to_tokens ( to_charlist ( string ) , line , column , file , opts ) ,
12641336 { :ok , quoted } <- :elixir . tokens_to_quoted ( tokens , file , opts ) do
1265- if include_comments do
1337+ if include_comments? do
12661338 quoted = Code.Normalizer . normalize ( quoted )
12671339 quoted = Code.Comments . merge_comments ( quoted , Process . get ( :code_formatter_comments ) )
12681340
@@ -1292,26 +1364,23 @@ defmodule Code do
12921364 file = Keyword . get ( opts , :file , "nofile" )
12931365 line = Keyword . get ( opts , :line , 1 )
12941366 column = Keyword . get ( opts , :column , 1 )
1295- include_comments = Keyword . get ( opts , :include_comments , false )
1367+ include_comments? = Keyword . get ( opts , :include_comments , false )
12961368
12971369 Process . put ( :code_formatter_comments , [ ] )
12981370
1299- opts =
1300- if include_comments do
1301- [ preserve_comments: & preserve_comments / 5 ,
1302- literal_encoder: & { :ok , { :__block__ , & 2 , [ & 1 ] } } ,
1303- token_metadata: true ,
1304- unescape: false ,
1305- columns: true ,
1306- ] ++ opts
1371+ opts =
1372+ if include_comments? do
1373+ [
1374+ preserve_comments: & preserve_comments / 5 ,
1375+ token_metadata: true ,
1376+ ] ++ opts
13071377 else
13081378 opts
13091379 end
13101380
13111381 quoted = :elixir . string_to_quoted! ( to_charlist ( string ) , line , column , file , opts )
13121382
1313- if include_comments do
1314- # quoted = Code.Normalizer.normalize(quoted)
1383+ if include_comments? do
13151384 Code.Comments . merge_comments ( quoted , Process . get ( :code_formatter_comments ) )
13161385 else
13171386 quoted
0 commit comments