Skip to content

Commit b12a9a3

Browse files
committed
Handle more scenarios and update formatter
1 parent 835c84b commit b12a9a3

File tree

5 files changed

+898
-788
lines changed

5 files changed

+898
-788
lines changed

Diff for: lib/elixir/lib/code.ex

+83-14
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)