Skip to content

Commit 9d59cd2

Browse files
committed
[incrParse] Add a stable id to the syntax nodes
The id is meant to be stable across incremental parses
1 parent dfad6f7 commit 9d59cd2

File tree

7 files changed

+190
-77
lines changed

7 files changed

+190
-77
lines changed

include/swift/Syntax/RawSyntax.h

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,13 @@ class RawSyntax final
221221
TriviaPiece> {
222222
friend TrailingObjects;
223223

224+
/// The ID that shall be used for the next node that is created and does not
225+
/// have a manually specified id
226+
static unsigned NextFreeNodeId;
227+
228+
/// An ID of this node that is stable across incremental parses
229+
unsigned NodeId;
230+
224231
union {
225232
uint64_t OpaqueBits;
226233
struct {
@@ -272,13 +279,17 @@ class RawSyntax final
272279
}
273280

274281
/// Constructor for creating layout nodes
282+
/// If \p NodeId is \c None, the next free NodeId is used, if it is passed,
283+
/// the caller needs to assure that the node ID has not been used yet.
275284
RawSyntax(SyntaxKind Kind, ArrayRef<RC<RawSyntax>> Layout,
276-
SourcePresence Presence, bool ManualMemory);
285+
SourcePresence Presence, bool ManualMemory,
286+
llvm::Optional<unsigned> NodeId);
277287
/// Constructor for creating token nodes
278-
RawSyntax(tok TokKind, OwnedString Text,
279-
ArrayRef<TriviaPiece> LeadingTrivia,
280-
ArrayRef<TriviaPiece> TrailingTrivia,
281-
SourcePresence Presence, bool ManualMemory);
288+
/// If \p NodeId is \c None, the next free NodeId is used, if it is passed,
289+
/// the caller needs to assure that the NodeId has not been used yet.
290+
RawSyntax(tok TokKind, OwnedString Text, ArrayRef<TriviaPiece> LeadingTrivia,
291+
ArrayRef<TriviaPiece> TrailingTrivia, SourcePresence Presence,
292+
bool ManualMemory, llvm::Optional<unsigned> NodeId);
282293

283294
public:
284295
~RawSyntax();
@@ -300,14 +311,16 @@ class RawSyntax final
300311
/// Make a raw "layout" syntax node.
301312
static RC<RawSyntax> make(SyntaxKind Kind, ArrayRef<RC<RawSyntax>> Layout,
302313
SourcePresence Presence,
303-
SyntaxArena *Arena = nullptr);
314+
SyntaxArena *Arena = nullptr,
315+
llvm::Optional<unsigned> NodeId = llvm::None);
304316

305317
/// Make a raw "token" syntax node.
306318
static RC<RawSyntax> make(tok TokKind, OwnedString Text,
307319
ArrayRef<TriviaPiece> LeadingTrivia,
308320
ArrayRef<TriviaPiece> TrailingTrivia,
309321
SourcePresence Presence,
310-
SyntaxArena *Arena = nullptr);
322+
SyntaxArena *Arena = nullptr,
323+
llvm::Optional<unsigned> NodeId = llvm::None);
311324

312325
/// Make a missing raw "layout" syntax node.
313326
static RC<RawSyntax> missing(SyntaxKind Kind, SyntaxArena *Arena = nullptr) {
@@ -335,6 +348,9 @@ class RawSyntax final
335348
return static_cast<SyntaxKind>(Bits.Common.Kind);
336349
}
337350

351+
/// Get an ID for this node that is stable across incremental parses
352+
unsigned getId() const { return NodeId; }
353+
338354
/// Returns true if the node is "missing" in the source (i.e. it was
339355
/// expected (or optional) but not written.
340356
bool isMissing() const { return getPresence() == SourcePresence::Missing; }

include/swift/Syntax/Serialization/SyntaxDeserialization.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,30 @@ template <> struct MappingTraits<swift::RC<swift::RawSyntax>> {
156156
in.mapRequired("trailingTrivia", trailingTrivia);
157157
swift::SourcePresence presence;
158158
in.mapRequired("presence", presence);
159-
value = swift::RawSyntax::make(tokenKind, text, leadingTrivia,
160-
trailingTrivia, presence, nullptr);
159+
/// FIXME: This is a workaround for existing bug from llvm yaml parser
160+
/// which would raise error when deserializing number with trailing
161+
/// character like "1\n". See https://bugs.llvm.org/show_bug.cgi?id=15505
162+
StringRef nodeIdString;
163+
in.mapRequired("id", nodeIdString);
164+
unsigned nodeId = std::atoi(nodeIdString.data());
165+
value =
166+
swift::RawSyntax::make(tokenKind, text, leadingTrivia, trailingTrivia,
167+
presence, /*Arena=*/nullptr, nodeId);
161168
} else {
162169
swift::SyntaxKind kind;
163170
in.mapRequired("kind", kind);
164171
std::vector<swift::RC<swift::RawSyntax>> layout;
165172
in.mapRequired("layout", layout);
166173
swift::SourcePresence presence;
167174
in.mapRequired("presence", presence);
168-
value = swift::RawSyntax::make(kind, layout, presence, nullptr);
175+
/// FIXME: This is a workaround for existing bug from llvm yaml parser
176+
/// which would raise error when deserializing number with trailing
177+
/// character like "1\n". See https://bugs.llvm.org/show_bug.cgi?id=15505
178+
StringRef nodeIdString;
179+
in.mapRequired("id", nodeIdString);
180+
unsigned nodeId = std::atoi(nodeIdString.data());
181+
value = swift::RawSyntax::make(kind, layout, presence, /*Arena=*/nullptr,
182+
nodeId);
169183
}
170184
}
171185
};

include/swift/Syntax/Serialization/SyntaxSerialization.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ struct ObjectTraits<syntax::RawSyntax> {
141141
}
142142
auto presence = value.getPresence();
143143
out.mapRequired("presence", presence);
144+
auto nodeId = value.getId();
145+
out.mapRequired("id", nodeId);
144146
}
145147
};
146148

include/swift/Syntax/Syntax.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ class Syntax {
8484
/// Get the shared raw syntax.
8585
RC<RawSyntax> getRaw() const;
8686

87+
/// Get an ID for this node that is stable across incremental parses
88+
unsigned getId() const { return getRaw()->getId(); }
89+
8790
/// Get the number of child nodes in this piece of syntax, not including
8891
/// tokens.
8992
size_t getNumChildren() const;

lib/Syntax/RawSyntax.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,19 @@ static void dumpTokenKind(llvm::raw_ostream &OS, tok Kind) {
6767

6868
} // end of anonymous namespace
6969

70+
unsigned RawSyntax::NextFreeNodeId = 1;
71+
7072
RawSyntax::RawSyntax(SyntaxKind Kind, ArrayRef<RC<RawSyntax>> Layout,
71-
SourcePresence Presence, bool ManualMemory) {
73+
SourcePresence Presence, bool ManualMemory,
74+
llvm::Optional<unsigned> NodeId) {
7275
assert(Kind != SyntaxKind::Token &&
7376
"'token' syntax node must be constructed with dedicated constructor");
77+
if (NodeId.hasValue()) {
78+
this->NodeId = NodeId.getValue();
79+
NextFreeNodeId = std::max(this->NodeId + 1, NextFreeNodeId);
80+
} else {
81+
this->NodeId = NextFreeNodeId++;
82+
}
7483
Bits.Common.Kind = unsigned(Kind);
7584
Bits.Common.Presence = unsigned(Presence);
7685
Bits.Common.ManualMemory = unsigned(ManualMemory);
@@ -92,7 +101,14 @@ RawSyntax::RawSyntax(SyntaxKind Kind, ArrayRef<RC<RawSyntax>> Layout,
92101
RawSyntax::RawSyntax(tok TokKind, OwnedString Text,
93102
ArrayRef<TriviaPiece> LeadingTrivia,
94103
ArrayRef<TriviaPiece> TrailingTrivia,
95-
SourcePresence Presence, bool ManualMemory) {
104+
SourcePresence Presence, bool ManualMemory,
105+
llvm::Optional<unsigned> NodeId) {
106+
if (NodeId.hasValue()) {
107+
this->NodeId = NodeId.getValue();
108+
NextFreeNodeId = std::max(this->NodeId + 1, NextFreeNodeId);
109+
} else {
110+
this->NodeId = NextFreeNodeId++;
111+
}
96112
Bits.Common.Kind = unsigned(SyntaxKind::Token);
97113
Bits.Common.Presence = unsigned(Presence);
98114
Bits.Common.ManualMemory = unsigned(ManualMemory);
@@ -126,25 +142,28 @@ RawSyntax::~RawSyntax() {
126142
}
127143

128144
RC<RawSyntax> RawSyntax::make(SyntaxKind Kind, ArrayRef<RC<RawSyntax>> Layout,
129-
SourcePresence Presence, SyntaxArena *Arena) {
145+
SourcePresence Presence, SyntaxArena *Arena,
146+
llvm::Optional<unsigned> NodeId) {
130147
auto size = totalSizeToAlloc<RC<RawSyntax>, OwnedString, TriviaPiece>(
131148
Layout.size(), 0, 0);
132149
void *data = Arena ? Arena->AllocateRawSyntax(size, alignof(RawSyntax))
133150
: ::operator new(size);
134-
return RC<RawSyntax>(new (data)
135-
RawSyntax(Kind, Layout, Presence, bool(Arena)));
151+
return RC<RawSyntax>(
152+
new (data) RawSyntax(Kind, Layout, Presence, bool(Arena), NodeId));
136153
}
137154

138155
RC<RawSyntax> RawSyntax::make(tok TokKind, OwnedString Text,
139156
ArrayRef<TriviaPiece> LeadingTrivia,
140157
ArrayRef<TriviaPiece> TrailingTrivia,
141-
SourcePresence Presence, SyntaxArena *Arena) {
158+
SourcePresence Presence, SyntaxArena *Arena,
159+
llvm::Optional<unsigned> NodeId) {
142160
auto size = totalSizeToAlloc<RC<RawSyntax>, OwnedString, TriviaPiece>(
143161
0, 1, LeadingTrivia.size() + TrailingTrivia.size());
144162
void *data = Arena ? Arena->AllocateRawSyntax(size, alignof(RawSyntax))
145163
: ::operator new(size);
146-
return RC<RawSyntax>(new (data) RawSyntax(
147-
TokKind, Text, LeadingTrivia, TrailingTrivia, Presence, bool(Arena)));
164+
return RC<RawSyntax>(new (data) RawSyntax(TokKind, Text, LeadingTrivia,
165+
TrailingTrivia, Presence,
166+
bool(Arena), NodeId));
148167
}
149168

150169
RC<RawSyntax> RawSyntax::append(RC<RawSyntax> NewLayoutElement) const {

test/Syntax/Inputs/serialize_multiple_decls.json

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
"value": 1
4141
}
4242
],
43-
"presence": "Present"
43+
"presence": "Present",
44+
"id": 1
4445
},
4546
{
4647
"tokenKind": {
@@ -54,7 +55,8 @@
5455
"value": 1
5556
}
5657
],
57-
"presence": "Present"
58+
"presence": "Present",
59+
"id": 2
5860
},
5961
null,
6062
null,
@@ -68,12 +70,14 @@
6870
},
6971
"leadingTrivia": [],
7072
"trailingTrivia": [],
71-
"presence": "Present"
73+
"presence": "Present",
74+
"id": 3
7275
},
7376
{
7477
"kind": "MemberDeclList",
7578
"layout": [],
76-
"presence": "Present"
79+
"presence": "Present",
80+
"id": 4
7781
},
7882
{
7983
"tokenKind": {
@@ -86,18 +90,22 @@
8690
}
8791
],
8892
"trailingTrivia": [],
89-
"presence": "Present"
93+
"presence": "Present",
94+
"id": 5
9095
}
9196
],
92-
"presence": "Present"
97+
"presence": "Present",
98+
"id": 6
9399
}
94100
],
95-
"presence": "Present"
101+
"presence": "Present",
102+
"id": 7
96103
},
97104
null,
98105
null
99106
],
100-
"presence": "Present"
107+
"presence": "Present",
108+
"id": 8
101109
},
102110
{
103111
"kind": "CodeBlockItem",
@@ -123,7 +131,8 @@
123131
"value": 1
124132
}
125133
],
126-
"presence": "Present"
134+
"presence": "Present",
135+
"id": 9
127136
},
128137
{
129138
"tokenKind": {
@@ -137,7 +146,8 @@
137146
"value": 1
138147
}
139148
],
140-
"presence": "Present"
149+
"presence": "Present",
150+
"id": 10
141151
},
142152
null,
143153
null,
@@ -151,12 +161,14 @@
151161
},
152162
"leadingTrivia": [],
153163
"trailingTrivia": [],
154-
"presence": "Present"
164+
"presence": "Present",
165+
"id": 11
155166
},
156167
{
157168
"kind": "MemberDeclList",
158169
"layout": [],
159-
"presence": "Present"
170+
"presence": "Present",
171+
"id": 12
160172
},
161173
{
162174
"tokenKind": {
@@ -169,21 +181,26 @@
169181
}
170182
],
171183
"trailingTrivia": [],
172-
"presence": "Present"
184+
"presence": "Present",
185+
"id": 13
173186
}
174187
],
175-
"presence": "Present"
188+
"presence": "Present",
189+
"id": 14
176190
}
177191
],
178-
"presence": "Present"
192+
"presence": "Present",
193+
"id": 15
179194
},
180195
null,
181196
null
182197
],
183-
"presence": "Present"
198+
"presence": "Present",
199+
"id": 16
184200
}
185201
],
186-
"presence": "Present"
202+
"presence": "Present",
203+
"id": 19
187204
},
188205
{
189206
"tokenKind": {
@@ -197,8 +214,10 @@
197214
}
198215
],
199216
"trailingTrivia": [],
200-
"presence": "Present"
217+
"presence": "Present",
218+
"id": 18
201219
}
202220
],
203-
"presence": "Present"
221+
"presence": "Present",
222+
"id": 20
204223
}

0 commit comments

Comments
 (0)