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 "location.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
116QString Atom::s_noError = QString();
117
118static const struct
119{
120 const char *english;
121 int no;
122} atms[] = { { .english: "AnnotatedList", .no: Atom::AnnotatedList },
123 { .english: "AutoLink", .no: Atom::AutoLink },
124 { .english: "BaseName", .no: Atom::BaseName },
125 { .english: "br", .no: Atom::BR },
126 { .english: "BriefLeft", .no: Atom::BriefLeft },
127 { .english: "BriefRight", .no: Atom::BriefRight },
128 { .english: "C", .no: Atom::C },
129 { .english: "CaptionLeft", .no: Atom::CaptionLeft },
130 { .english: "CaptionRight", .no: Atom::CaptionRight },
131 { .english: "Code", .no: Atom::Code },
132 { .english: "CodeBad", .no: Atom::CodeBad },
133 { .english: "CodeQuoteArgument", .no: Atom::CodeQuoteArgument },
134 { .english: "CodeQuoteCommand", .no: Atom::CodeQuoteCommand },
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::appendString(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/*! \fn Atom *Atom::next()
255 Return the next atom in the atom list.
256 \also type(), string()
257*/
258
259/*!
260 Return the next Atom in the list if it is of AtomType \a t.
261 Otherwise return 0.
262 */
263const Atom *Atom::next(AtomType t) const
264{
265 return (m_next && (m_next->type() == t)) ? m_next : nullptr;
266}
267
268/*!
269 Return the next Atom in the list if it is of AtomType \a t
270 and its string part is \a s. Otherwise return 0.
271 */
272const Atom *Atom::next(AtomType t, const QString &s) const
273{
274 return (m_next && (m_next->type() == t) && (m_next->string() == s)) ? m_next : nullptr;
275}
276
277/*! \fn const Atom *Atom::next() const
278 Return the next atom in the atom list.
279 \also type(), string()
280*/
281
282/*! \fn AtomType Atom::type() const
283 Return the type of this atom.
284 \also string(), next()
285*/
286
287/*!
288 Return the type of this atom as a string. Return "Invalid" if
289 type() returns an impossible value.
290
291 This is only useful for debugging.
292
293 \also type()
294*/
295QString Atom::typeString() const
296{
297 static bool deja = false;
298
299 if (!deja) {
300 int i = 0;
301 while (atms[i].english != nullptr) {
302 if (atms[i].no != i)
303 Location::internalError(QStringLiteral("QDoc::Atom: atom %1 missing").arg(a: i));
304 ++i;
305 }
306 deja = true;
307 }
308
309 int i = static_cast<int>(type());
310 if (i < 0 || i > static_cast<int>(Last))
311 return QLatin1String("Invalid");
312 return QLatin1String(atms[i].english);
313}
314
315/*! \fn const QString &Atom::string() const
316
317 Returns the string parameter that together with the type
318 characterizes this atom.
319
320 \also type(), next()
321*/
322
323/*!
324 For a link atom, returns the string representing the link text
325 if one exist in the list of atoms.
326*/
327QString Atom::linkText() const
328{
329 Q_ASSERT(m_type == Atom::Link);
330 QString result;
331
332 if (next() && next()->string() == ATOM_FORMATTING_LINK) {
333 auto *atom = next()->next();
334 while (atom && atom->type() != Atom::FormattingRight) {
335 result += atom->string();
336 atom = atom->next();
337 }
338 return result;
339 }
340
341 return string();
342}
343
344/*!
345 The only constructor for LinkAtom. It creates an Atom of
346 type Atom::Link. \a p1 being the link target. \a p2 is the
347 parameters in square brackets. Normally there is just one
348 word in the square brackets, but there can be up to three
349 words separated by spaces. The constructor splits \a p2 on
350 the space character.
351 */
352LinkAtom::LinkAtom(const QString &p1, const QString &p2)
353 : Atom(Atom::Link, p1),
354 m_resolved(false),
355 m_genus(Node::DontCare),
356 m_domain(nullptr),
357 m_squareBracketParams(p2)
358{
359 // nada.
360}
361
362/*!
363 This function resolves the parameters that were enclosed in
364 square brackets. If the parameters have already been resolved,
365 it does nothing and returns immediately.
366 */
367void LinkAtom::resolveSquareBracketParams()
368{
369 if (m_resolved)
370 return;
371 const QStringList params = m_squareBracketParams.toLower().split(sep: QLatin1Char(' '));
372 for (const auto &param : params) {
373 if (!m_domain) {
374 m_domain = QDocDatabase::qdocDB()->findTree(t: param);
375 if (m_domain) {
376 continue;
377 }
378 }
379
380 if (param == "qml") {
381 m_genus = Node::QML;
382 continue;
383 }
384 if (param == "cpp") {
385 m_genus = Node::CPP;
386 continue;
387 }
388 if (param == "doc") {
389 m_genus = Node::DOC;
390 continue;
391 }
392 if (param == "api") {
393 m_genus = Node::API;
394 continue;
395 }
396 m_error = m_squareBracketParams;
397 break;
398 }
399 m_resolved = true;
400}
401
402/*!
403 Standard copy constructor of LinkAtom \a t.
404 */
405LinkAtom::LinkAtom(const LinkAtom &t)
406 : Atom(Link, t.string()),
407 m_resolved(t.m_resolved),
408 m_genus(t.m_genus),
409 m_domain(t.m_domain),
410 m_error(t.m_error),
411 m_squareBracketParams(t.m_squareBracketParams)
412{
413 // nothing
414}
415
416/*!
417 Special copy constructor of LinkAtom \a t, where
418 where the new LinkAtom will not be the first one
419 in the list.
420 */
421LinkAtom::LinkAtom(Atom *previous, const LinkAtom &t)
422 : Atom(previous, Link, t.string()),
423 m_resolved(t.m_resolved),
424 m_genus(t.m_genus),
425 m_domain(t.m_domain),
426 m_error(t.m_error),
427 m_squareBracketParams(t.m_squareBracketParams)
428{
429 previous->m_next = this;
430}
431
432QT_END_NAMESPACE
433

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