1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "atom.h"
5
6#include "genustypes.h"
7#include "qdocdatabase.h"
8
9#include <QtCore/qregularexpression.h>
10
11#include <cstdio>
12
13QT_BEGIN_NAMESPACE
14
15/*! \class Atom
16 \brief The Atom class is the fundamental unit for representing
17 documents internally.
18
19 Atoms have a \i type and are completed by a \i string whose
20 meaning depends on the \i type. For example, the string
21 \quotation
22 \i italic text looks nicer than \bold bold text
23 \endquotation
24 is represented by the following atoms:
25 \quotation
26 (FormattingLeft, ATOM_FORMATTING_ITALIC)
27 (String, "italic")
28 (FormattingRight, ATOM_FORMATTING_ITALIC)
29 (String, " text is more attractive than ")
30 (FormattingLeft, ATOM_FORMATTING_BOLD)
31 (String, "bold")
32 (FormattingRight, ATOM_FORMATTING_BOLD)
33 (String, " text")
34 \endquotation
35
36 \also Text
37*/
38
39/*! \enum Atom::AtomType
40
41 \value AnnotatedList
42 \value AutoLink
43 \value BaseName
44 \value BriefLeft
45 \value BriefRight
46 \value C
47 \value CaptionLeft
48 \value CaptionRight
49 \value Code
50 \value CodeBad
51 \value CodeQuoteArgument
52 \value CodeQuoteCommand
53 \value DetailsLeft
54 \value DetailsRight
55 \value DivLeft
56 \value DivRight
57 \value ExampleFileLink
58 \value ExampleImageLink
59 \value FormatElse
60 \value FormatEndif
61 \value FormatIf
62 \value FootnoteLeft
63 \value FootnoteRight
64 \value FormattingLeft
65 \value FormattingRight
66 \value GeneratedList
67 \value Image
68 \value ImageText
69 \value ImportantNote
70 \value InlineImage
71 \value Keyword
72 \value LineBreak
73 \value Link
74 \value LinkNode
75 \value ListLeft
76 \value ListItemNumber
77 \value ListTagLeft
78 \value ListTagRight
79 \value ListItemLeft
80 \value ListItemRight
81 \value ListRight
82 \value NavAutoLink
83 \value NavLink
84 \value Nop
85 \value Note
86 \value ParaLeft
87 \value ParaRight
88 \value Qml
89 \value QuotationLeft
90 \value QuotationRight
91 \value RawString
92 \value SectionLeft
93 \value SectionRight
94 \value SectionHeadingLeft
95 \value SectionHeadingRight
96 \value SidebarLeft
97 \value SidebarRight
98 \value SinceList
99 \value SinceTagLeft
100 \value SinceTagRight
101 \value String
102 \value TableLeft
103 \value TableRight
104 \value TableHeaderLeft
105 \value TableHeaderRight
106 \value TableRowLeft
107 \value TableRowRight
108 \value TableItemLeft
109 \value TableItemRight
110 \value TableOfContents
111 \value Target
112 \value UnhandledFormat
113 \value UnknownCommand
114*/
115
116static const struct
117{
118 const char *english;
119 int no;
120} atms[] = { { .english: "AnnotatedList", .no: Atom::AnnotatedList },
121 { .english: "AutoLink", .no: Atom::AutoLink },
122 { .english: "BaseName", .no: Atom::BaseName },
123 { .english: "br", .no: Atom::BR },
124 { .english: "BriefLeft", .no: Atom::BriefLeft },
125 { .english: "BriefRight", .no: Atom::BriefRight },
126 { .english: "C", .no: Atom::C },
127 { .english: "CaptionLeft", .no: Atom::CaptionLeft },
128 { .english: "CaptionRight", .no: Atom::CaptionRight },
129 { .english: "Code", .no: Atom::Code },
130 { .english: "CodeBad", .no: Atom::CodeBad },
131 { .english: "CodeQuoteArgument", .no: Atom::CodeQuoteArgument },
132 { .english: "CodeQuoteCommand", .no: Atom::CodeQuoteCommand },
133 { .english: "ComparesLeft", .no: Atom::ComparesLeft },
134 { .english: "ComparesRight", .no: Atom::ComparesRight },
135 { .english: "DetailsLeft", .no: Atom::DetailsLeft },
136 { .english: "DetailsRight", .no: Atom::DetailsRight },
137 { .english: "DivLeft", .no: Atom::DivLeft },
138 { .english: "DivRight", .no: Atom::DivRight },
139 { .english: "ExampleFileLink", .no: Atom::ExampleFileLink },
140 { .english: "ExampleImageLink", .no: Atom::ExampleImageLink },
141 { .english: "FootnoteLeft", .no: Atom::FootnoteLeft },
142 { .english: "FootnoteRight", .no: Atom::FootnoteRight },
143 { .english: "FormatElse", .no: Atom::FormatElse },
144 { .english: "FormatEndif", .no: Atom::FormatEndif },
145 { .english: "FormatIf", .no: Atom::FormatIf },
146 { .english: "FormattingLeft", .no: Atom::FormattingLeft },
147 { .english: "FormattingRight", .no: Atom::FormattingRight },
148 { .english: "GeneratedList", .no: Atom::GeneratedList },
149 { .english: "hr", .no: Atom::HR },
150 { .english: "Image", .no: Atom::Image },
151 { .english: "ImageText", .no: Atom::ImageText },
152 { .english: "ImportantLeft", .no: Atom::ImportantLeft },
153 { .english: "ImportantRight", .no: Atom::ImportantRight },
154 { .english: "InlineImage", .no: Atom::InlineImage },
155 { .english: "Keyword", .no: Atom::Keyword },
156 { .english: "LegaleseLeft", .no: Atom::LegaleseLeft },
157 { .english: "LegaleseRight", .no: Atom::LegaleseRight },
158 { .english: "LineBreak", .no: Atom::LineBreak },
159 { .english: "Link", .no: Atom::Link },
160 { .english: "LinkNode", .no: Atom::LinkNode },
161 { .english: "ListLeft", .no: Atom::ListLeft },
162 { .english: "ListItemNumber", .no: Atom::ListItemNumber },
163 { .english: "ListTagLeft", .no: Atom::ListTagLeft },
164 { .english: "ListTagRight", .no: Atom::ListTagRight },
165 { .english: "ListItemLeft", .no: Atom::ListItemLeft },
166 { .english: "ListItemRight", .no: Atom::ListItemRight },
167 { .english: "ListRight", .no: Atom::ListRight },
168 { .english: "NavAutoLink", .no: Atom::NavAutoLink },
169 { .english: "NavLink", .no: Atom::NavLink },
170 { .english: "Nop", .no: Atom::Nop },
171 { .english: "NoteLeft", .no: Atom::NoteLeft },
172 { .english: "NoteRight", .no: Atom::NoteRight },
173 { .english: "ParaLeft", .no: Atom::ParaLeft },
174 { .english: "ParaRight", .no: Atom::ParaRight },
175 { .english: "Qml", .no: Atom::Qml },
176 { .english: "QuotationLeft", .no: Atom::QuotationLeft },
177 { .english: "QuotationRight", .no: Atom::QuotationRight },
178 { .english: "RawString", .no: Atom::RawString },
179 { .english: "SectionLeft", .no: Atom::SectionLeft },
180 { .english: "SectionRight", .no: Atom::SectionRight },
181 { .english: "SectionHeadingLeft", .no: Atom::SectionHeadingLeft },
182 { .english: "SectionHeadingRight", .no: Atom::SectionHeadingRight },
183 { .english: "SidebarLeft", .no: Atom::SidebarLeft },
184 { .english: "SidebarRight", .no: Atom::SidebarRight },
185 { .english: "SinceList", .no: Atom::SinceList },
186 { .english: "SinceTagLeft", .no: Atom::SinceTagLeft },
187 { .english: "SinceTagRight", .no: Atom::SinceTagRight },
188 { .english: "SnippetCommand", .no: Atom::SnippetCommand },
189 { .english: "SnippetIdentifier", .no: Atom::SnippetIdentifier },
190 { .english: "SnippetLocation", .no: Atom::SnippetLocation },
191 { .english: "String", .no: Atom::String },
192 { .english: "TableLeft", .no: Atom::TableLeft },
193 { .english: "TableRight", .no: Atom::TableRight },
194 { .english: "TableHeaderLeft", .no: Atom::TableHeaderLeft },
195 { .english: "TableHeaderRight", .no: Atom::TableHeaderRight },
196 { .english: "TableRowLeft", .no: Atom::TableRowLeft },
197 { .english: "TableRowRight", .no: Atom::TableRowRight },
198 { .english: "TableItemLeft", .no: Atom::TableItemLeft },
199 { .english: "TableItemRight", .no: Atom::TableItemRight },
200 { .english: "TableOfContents", .no: Atom::TableOfContents },
201 { .english: "Target", .no: Atom::Target },
202 { .english: "UnhandledFormat", .no: Atom::UnhandledFormat },
203 { .english: "WarningLeft", .no: Atom::WarningLeft },
204 { .english: "WarningRight", .no: Atom::WarningRight },
205 { .english: "UnknownCommand", .no: Atom::UnknownCommand },
206 { .english: nullptr, .no: 0 } };
207
208/*! \fn Atom::Atom(AtomType type, const QString &string)
209
210 Constructs an atom of the specified \a type with the single
211 parameter \a string and does not put the new atom in a list.
212*/
213
214/*! \fn Atom::Atom(AtomType type, const QString &p1, const QString &p2)
215
216 Constructs an atom of the specified \a type with the two
217 parameters \a p1 and \a p2 and does not put the new atom
218 in a list.
219*/
220
221/*! \fn Atom(Atom *previous, AtomType type, const QString &string)
222
223 Constructs an atom of the specified \a type with the single
224 parameter \a string and inserts the new atom into the list
225 after the \a previous atom.
226*/
227
228/*! \fn Atom::Atom(Atom *previous, AtomType type, const QString &p1, const QString &p2)
229
230 Constructs an atom of the specified \a type with the two
231 parameters \a p1 and \a p2 and inserts the new atom into
232 the list after the \a previous atom.
233*/
234
235/*! \fn void Atom::appendChar(QChar ch)
236
237 Appends \a ch to the string parameter of this atom.
238
239 \also string()
240*/
241
242/*! \fn void Atom::concatenateString(const QString &string)
243
244 Appends \a string to the string parameter of this atom.
245
246 \also string()
247*/
248
249/*! \fn void Atom::chopString()
250
251 \also string()
252*/
253
254/*!
255 Starting from this Atom, searches the linked list for the
256 atom of specified type \a t and returns it. Returns \nullptr
257 if no such atom is found.
258*/
259const Atom *Atom::find(AtomType t) const
260{
261 const auto *a{this};
262 while (a && a->type() != t)
263 a = a->next();
264 return a;
265}
266
267/*!
268 Starting from this Atom, searches the linked list for the
269 atom of specified type \a t and string \a s, and returns it.
270 Returns \nullptr if no such atom is found.
271*/
272const Atom *Atom::find(AtomType t, const QString &s) const
273{
274 const auto *a{this};
275 while (a && (a->type() != t || a->string() != s))
276 a = a->next();
277 return a;
278}
279
280/*! \fn Atom *Atom::next()
281 Return the next atom in the atom list.
282 \also type(), string()
283*/
284
285/*!
286 Return the next Atom in the list if it is of AtomType \a t.
287 Otherwise return 0.
288 */
289const Atom *Atom::next(AtomType t) const
290{
291 return (m_next && (m_next->type() == t)) ? m_next : nullptr;
292}
293
294/*!
295 Return the next Atom in the list if it is of AtomType \a t
296 and its string part is \a s. Otherwise return 0.
297 */
298const Atom *Atom::next(AtomType t, const QString &s) const
299{
300 return (m_next && (m_next->type() == t) && (m_next->string() == s)) ? m_next : nullptr;
301}
302
303/*! \fn const Atom *Atom::next() const
304 Return the next atom in the atom list.
305 \also type(), string()
306*/
307
308/*! \fn AtomType Atom::type() const
309 Return the type of this atom.
310 \also string(), next()
311*/
312
313/*!
314 Return the type of this atom as a string. Return "Invalid" if
315 type() returns an impossible value.
316
317 This is only useful for debugging.
318
319 \also type()
320*/
321QString Atom::typeString() const
322{
323 static bool deja = false;
324
325 if (!deja) {
326 int i = 0;
327 while (atms[i].english != nullptr) {
328 if (atms[i].no != i)
329 Location::internalError(QStringLiteral("QDoc::Atom: atom %1 missing").arg(a: i));
330 ++i;
331 }
332 deja = true;
333 }
334
335 int i = static_cast<int>(type());
336 if (i < 0 || i > static_cast<int>(Last))
337 return QLatin1String("Invalid");
338 return QLatin1String(atms[i].english);
339}
340
341/*! \fn const QString &Atom::string() const
342
343 Returns the string parameter that together with the type
344 characterizes this atom.
345
346 \also type(), next()
347*/
348
349/*!
350 For a link atom, returns the string representing the link text
351 if one exist in the list of atoms.
352*/
353QString Atom::linkText() const
354{
355 Q_ASSERT(m_type == Atom::Link);
356 QString result;
357
358 if (next() && next()->string() == ATOM_FORMATTING_LINK) {
359 auto *atom = next()->next();
360 while (atom && atom->type() != Atom::FormattingRight) {
361 result += atom->string();
362 atom = atom->next();
363 }
364 return result;
365 }
366
367 return string();
368}
369
370/*!
371 The only constructor for LinkAtom. It creates an Atom of
372 type Atom::Link. \a p1 being the link target. \a p2 is the
373 parameters in square brackets. Normally there is just one
374 word in the square brackets, but there can be up to three
375 words separated by spaces. The constructor splits \a p2 on
376 the space character.
377 */
378LinkAtom::LinkAtom(const QString &p1, const QString &p2, Location location)
379 : Atom(Atom::Link, p1),
380 location(location),
381 m_resolved(false),
382 m_genus(Genus::DontCare),
383 m_domain(nullptr),
384 m_squareBracketParams(p2)
385{
386 // nada.
387}
388
389/*!
390 This function resolves the parameters that were enclosed in
391 square brackets. If the parameters have already been resolved,
392 it does nothing and returns immediately.
393 */
394void LinkAtom::resolveSquareBracketParams()
395{
396 if (m_resolved)
397 return;
398 const QStringList params = m_squareBracketParams.toLower().split(sep: QLatin1Char(' '));
399 for (const auto &param : params) {
400 if (!m_domain) {
401 m_domain = QDocDatabase::qdocDB()->findTree(t: param);
402 if (m_domain) {
403 continue;
404 }
405 }
406
407 if (param == "qml") {
408 m_genus = Genus::QML;
409 continue;
410 }
411 if (param == "cpp") {
412 m_genus = Genus::CPP;
413 continue;
414 }
415 if (param == "doc") {
416 m_genus = Genus::DOC;
417 continue;
418 }
419 if (param == "api") {
420 m_genus = Genus::API;
421 continue;
422 }
423 break;
424 }
425 m_resolved = true;
426}
427
428/*!
429 Standard copy constructor of LinkAtom \a t.
430 */
431LinkAtom::LinkAtom(const LinkAtom &t)
432 : Atom(Link, t.string()),
433 location(t.location),
434 m_resolved(t.m_resolved),
435 m_genus(t.m_genus),
436 m_domain(t.m_domain),
437 m_squareBracketParams(t.m_squareBracketParams)
438{
439 // nothing
440}
441
442/*!
443 Special copy constructor of LinkAtom \a t, where
444 where the new LinkAtom will not be the first one
445 in the list.
446 */
447LinkAtom::LinkAtom(Atom *previous, const LinkAtom &t)
448 : Atom(previous, Link, t.string()),
449 location(t.location),
450 m_resolved(t.m_resolved),
451 m_genus(t.m_genus),
452 m_domain(t.m_domain),
453 m_squareBracketParams(t.m_squareBracketParams)
454{
455 previous->m_next = this;
456}
457
458QT_END_NAMESPACE
459

source code of qttools/src/qdoc/qdoc/src/qdoc/atom.cpp