Skip to content

Commit c9e9a02

Browse files
committed
Handle more scenarios and update formatter
1 parent e3e4fac commit c9e9a02

File tree

5 files changed

+898
-788
lines changed

5 files changed

+898
-788
lines changed

lib/elixir/lib/code.ex

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)