Skip to content

Commit f284529

Browse files
committed
[libSyntax] Add a unsafe but fast SyntaxDataRef version of SyntaxData
In contrast to SyntaxData, SyntaxDataRef is not memory-safe, but designed to be fast. In particular, the following guarantees from SyntaxData are being dropped: - SyntaxDataRef does not retain the SyntaxArena containing its RawSyntax. The user of SyntaxDataRef has to provide that guarantee. However, that's usually pretty easily done by just retaining the SyntaxArena of the tree's root node. - The parent of a SyntaxDataRef must outlive the child node. This is the more tricky constraint, but if a tree is just walked top to bottom with nodes stored on the stack, this is given by the way the stack is being unrolled.
1 parent 1451960 commit f284529

File tree

4 files changed

+382
-176
lines changed

4 files changed

+382
-176
lines changed

include/swift/Syntax/AbsoluteRawSyntax.h

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -218,37 +218,144 @@ struct AbsoluteRawSyntax {
218218
const AbsoluteSyntaxInfo Info;
219219

220220
public:
221+
/// Create a null \c AbsoluteRawSyntax to which a real \c AbsoluteRawSyntax
222+
/// can be stored later.
223+
explicit AbsoluteRawSyntax()
224+
: Raw(nullptr), Info(AbsoluteSyntaxPosition(0, 0),
225+
SyntaxIdentifier(0, SyntaxIndexInTree::zero())) {}
226+
227+
/// Create a new \c AbsoluteRawData backed by \p Raw and with additional \p
228+
/// Info. The caller of this constructor is responsible to ensure that the
229+
/// Arena of \p Raw (and thus \p Raw itself) outlives this \c
230+
/// AbsoluteRawSyntax.
221231
AbsoluteRawSyntax(const RawSyntax *Raw, AbsoluteSyntaxInfo Info)
222-
: Raw(Raw), Info(Info) {}
232+
: Raw(Raw), Info(Info) {
233+
assert(Raw != nullptr &&
234+
"A AbsoluteRawSyntax created through the memberwise constructor "
235+
"should always have a RawSyntax");
236+
}
237+
238+
/// Whether this is a null \c AbsoluteRawSyntax created through the default
239+
/// constructor.
240+
bool isNull() const { return Raw == nullptr; }
223241

224242
/// Construct a \c AbsoluteRawSyntax for a \c RawSyntax node that represents
225243
/// the syntax tree's root.
226244
static AbsoluteRawSyntax forRoot(const RawSyntax *Raw) {
227245
return AbsoluteRawSyntax(Raw, AbsoluteSyntaxInfo::forRoot());
228246
}
229247

230-
const RawSyntax *getRaw() const { return Raw; }
248+
const RawSyntax *getRaw() const {
249+
assert(!isNull() && "Cannot get Raw of a null AbsoluteRawSyntax");
250+
return Raw;
251+
}
231252

232-
AbsoluteSyntaxInfo getInfo() const { return Info; }
253+
AbsoluteSyntaxInfo getInfo() const {
254+
assert(!isNull() && "Cannot get Raw of a null AbsoluteRawSyntax");
255+
return Info;
256+
}
233257

234258
/// Get the position at which the leading triva of this node starts.
235-
AbsoluteSyntaxPosition getPosition() const { return Info.getPosition(); };
259+
AbsoluteSyntaxPosition getPosition() const {
260+
return getInfo().getPosition();
261+
};
236262

237-
SyntaxIdentifier getNodeId() const { return Info.getNodeId(); };
263+
SyntaxIdentifier getNodeId() const { return getInfo().getNodeId(); };
238264

239265
AbsoluteSyntaxPosition::IndexInParentType getIndexInParent() const {
240266
return getPosition().getIndexInParent();
241267
}
242268

269+
size_t getNumChildren() const { return getRaw()->getLayout().size(); }
270+
271+
/// Get the child at \p Index if it exists. If the node does not have a child
272+
/// at \p Index, return \c None. Asserts that \p Index < \c NumChildren
273+
Optional<AbsoluteRawSyntax>
274+
getChild(AbsoluteSyntaxPosition::IndexInParentType Index) const {
275+
assert(Index < getNumChildren() && "Index out of bounds");
276+
auto RawChild = getRaw()->getChild(Index);
277+
if (RawChild) {
278+
return getPresentChild(Index);
279+
} else {
280+
return None;
281+
}
282+
}
283+
284+
/// Get the child at \p Index, asserting that it exists. This is slightly
285+
/// more performant than \c getChild in these cases since the \c
286+
/// AbsoluteRawSyntax node does not have to be wrapped in an \c Optional.
287+
AbsoluteRawSyntax
288+
getPresentChild(AbsoluteSyntaxPosition::IndexInParentType Index) const {
289+
assert(Index < getNumChildren() && "Index out of bounds");
290+
auto RawChild = getRaw()->getChild(Index);
291+
assert(RawChild &&
292+
"Child retrieved using getPresentChild must always exist");
293+
294+
AbsoluteSyntaxPosition Position = getPosition().advancedToFirstChild();
295+
SyntaxIdentifier NodeId = getNodeId().advancedToFirstChild();
296+
297+
for (size_t I = 0; I < Index; ++I) {
298+
Position = Position.advancedBy(getRaw()->getChild(I));
299+
NodeId = NodeId.advancedBy(getRaw()->getChild(I));
300+
}
301+
302+
AbsoluteSyntaxInfo Info(Position, NodeId);
303+
return AbsoluteRawSyntax(RawChild, Info);
304+
}
305+
306+
/// Get the first non-missing token node in this tree. Return \c None if
307+
/// this node does not contain non-missing tokens.
308+
Optional<AbsoluteRawSyntax> getFirstToken() const {
309+
if (getRaw()->isToken() && !getRaw()->isMissing()) {
310+
return *this;
311+
}
312+
313+
size_t NumChildren = getNumChildren();
314+
for (size_t I = 0; I < NumChildren; ++I) {
315+
if (auto Child = getChild(I)) {
316+
if (Child->getRaw()->isMissing()) {
317+
continue;
318+
}
319+
320+
if (auto Token = Child->getFirstToken()) {
321+
return Token;
322+
}
323+
}
324+
}
325+
return None;
326+
}
327+
328+
/// Get the last non-missing token node in this tree. Return \c None if
329+
/// this node does not contain non-missing tokens.
330+
Optional<AbsoluteRawSyntax> getLastToken() const {
331+
if (getRaw()->isToken() && !getRaw()->isMissing()) {
332+
return *this;
333+
}
334+
335+
for (int I = getNumChildren() - 1; I >= 0; --I) {
336+
if (auto Child = getChild(I)) {
337+
if (Child->getRaw()->isMissing()) {
338+
continue;
339+
}
340+
341+
if (auto Token = Child->getLastToken()) {
342+
return Token;
343+
}
344+
}
345+
}
346+
return None;
347+
}
348+
243349
/// Construct a new \c AbsoluteRawSyntax node that has the same info as the
244350
/// current one, but
245351
/// - the \p NewRaw as the backing storage
246352
/// - the \p NewRootId as the RootId
247353
AbsoluteRawSyntax
248354
replacingSelf(const RawSyntax *NewRaw,
249355
SyntaxIdentifier::RootIdType NewRootId) const {
250-
SyntaxIdentifier NewNodeId(NewRootId, Info.getNodeId().getIndexInTree());
251-
AbsoluteSyntaxInfo NewInfo(Info.getPosition(), NewNodeId);
356+
SyntaxIdentifier NewNodeId(NewRootId,
357+
getInfo().getNodeId().getIndexInTree());
358+
AbsoluteSyntaxInfo NewInfo(getInfo().getPosition(), NewNodeId);
252359
return AbsoluteRawSyntax(NewRaw, NewInfo);
253360
}
254361
};

include/swift/Syntax/RawSyntax.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ class RawSyntax final
450450
/// Get a child based on a particular node's "Cursor", indicating
451451
/// the position of the terms in the production of the Swift grammar.
452452
const RawSyntax *getChild(CursorIndex Index) const {
453+
assert(Index < getNumChildren() && "Index out of bounds");
453454
return getLayout()[Index];
454455
}
455456

0 commit comments

Comments
 (0)