1 //===--- Bracket.cpp - Analyze bracket structure --------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // The basic phases of our bracket matching are:
11 // 1) A simple "greedy" match looks for well-nested subsequences.
13 // We can't fully trust the results of this, consider:
18 // Greedy matching will match B=C, when we should at least consider A=C.
19 // However for the correct parts of the file, the greedy match gives the
20 // right answer. It produces useful candidates for phase 2.
22 // simplePairBrackets handles this step.
24 // 2) Try to identify places where formatting indicates that the greedy match
25 // was correct. This is similar to how a human would scan a large file.
35 // We can "verify" that X..Y looks like a braced block, and the greedy match
36 // tells us that substring is perfectly nested.
37 // We trust the pairings of those brackets and don't examine them further.
38 // However in the first example above, we do not trust B=C because the brace
39 // indentation is suspect.
41 // FIXME: implement this step.
43 // 3) Run full best-match optimization on remaining brackets.
45 // Conceptually, this considers all possible matchings and optimizes cost:
46 // - there is a cost for failing to match a bracket
47 // - there is a variable cost for matching two brackets.
48 // (For example if brace indentation doesn't match).
50 // In the first example we have three alternatives, and they are ranked:
53 // 3) skip A, skip B, skip C
54 // The cost for skipping a bracket is high, so option 3 is worst.
55 // B=C costs more than A=C, because the indentation doesn't match.
57 // It would be correct to run this step alone, but it would be too slow.
58 // The implementation is dynamic programming in N^3 space and N^2 time.
59 // Having earlier steps filter out most brackets is key to performance.
61 // FIXME: implement this step.
63 //===----------------------------------------------------------------------===//
72 using Index
= unsigned;
73 constexpr static Index None
= -1;
75 enum BracketKind
: char { Paren
, Brace
, Square
} Kind
;
76 enum Direction
: bool { Open
, Close
} Dir
;
80 Bracket::Index Pair
= None
;
83 // Find brackets in the stream and convert to Bracket struct.
84 std::vector
<Bracket
> findBrackets(const TokenStream
&Stream
) {
85 std::vector
<Bracket
> Brackets
;
86 auto Add
= [&](const Token
&Tok
, Bracket::BracketKind K
,
87 Bracket::Direction D
) {
89 {K
, D
, Tok
.Line
, Tok
.Indent
, Stream
.index(Tok
), Bracket::None
});
91 for (const auto &Tok
: Stream
.tokens()) {
93 case clang::tok::l_paren
:
94 Add(Tok
, Bracket::Paren
, Bracket::Open
);
96 case clang::tok::r_paren
:
97 Add(Tok
, Bracket::Paren
, Bracket::Close
);
99 case clang::tok::l_brace
:
100 Add(Tok
, Bracket::Brace
, Bracket::Open
);
102 case clang::tok::r_brace
:
103 Add(Tok
, Bracket::Brace
, Bracket::Close
);
105 case clang::tok::l_square
:
106 Add(Tok
, Bracket::Square
, Bracket::Open
);
108 case clang::tok::r_square
:
109 Add(Tok
, Bracket::Square
, Bracket::Close
);
118 // Write the bracket pairings from Brackets back to Tokens.
119 void applyPairings(ArrayRef
<Bracket
> Brackets
, TokenStream
&Tokens
) {
120 for (const auto &B
: Brackets
)
121 Tokens
.tokens()[B
.Tok
].Pair
=
122 (B
.Pair
== Bracket::None
) ? 0 : (int32_t)Brackets
[B
.Pair
].Tok
- B
.Tok
;
125 // Find perfect pairings (ignoring whitespace) via greedy algorithm.
126 // This means two brackets are paired if they match and the brackets between
127 // them nest perfectly, with no skipped or crossed brackets.
128 void simplePairBrackets(MutableArrayRef
<Bracket
> Brackets
) {
129 std::vector
<unsigned> Stack
;
130 for (unsigned I
= 0; I
< Brackets
.size(); ++I
) {
131 if (Brackets
[I
].Dir
== Bracket::Open
) {
133 } else if (!Stack
.empty() &&
134 Brackets
[Stack
.back()].Kind
== Brackets
[I
].Kind
) {
135 Brackets
[Stack
.back()].Pair
= I
;
136 Brackets
[I
].Pair
= Stack
.back();
139 // Unpaired closer, no brackets on stack are part of a perfect sequence.
143 // Any remaining brackets on the stack stay unpaired.
148 void pairBrackets(TokenStream
&Stream
) {
149 auto Brackets
= findBrackets(Stream
);
150 simplePairBrackets(Brackets
);
151 applyPairings(Brackets
, Stream
);
154 } // namespace clangd