| 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 | #ifndef DOCPARSER_H |
| 4 | #define DOCPARSER_H |
| 5 | |
| 6 | #include "atom.h" |
| 7 | #include "config.h" |
| 8 | #include "doc.h" |
| 9 | #include "docutilities.h" |
| 10 | #include "location.h" |
| 11 | #include "openedlist.h" |
| 12 | #include "quoter.h" |
| 13 | |
| 14 | #include "filesystem/fileresolver.h" |
| 15 | |
| 16 | #include <QtCore/QCoreApplication> |
| 17 | #include <QtCore/qglobalstatic.h> |
| 18 | #include <QtCore/qhash.h> |
| 19 | #include <QtCore/qstack.h> |
| 20 | #include <QtCore/qstring.h> |
| 21 | |
| 22 | QT_BEGIN_NAMESPACE |
| 23 | |
| 24 | class DocPrivate; |
| 25 | class CodeMarker; |
| 26 | struct Macro; |
| 27 | |
| 28 | class DocParser |
| 29 | { |
| 30 | public: |
| 31 | void parse(const QString &source, DocPrivate *docPrivate, const QSet<QString> &metaCommandSet, |
| 32 | const QSet<QString> &possibleTopics); |
| 33 | |
| 34 | static void initialize(const Config &config, FileResolver& file_resolver); |
| 35 | static int endCmdFor(int cmd); |
| 36 | static QString cmdName(int cmd); |
| 37 | static QString endCmdName(int cmd); |
| 38 | static QString untabifyEtc(const QString &str); |
| 39 | static int indentLevel(const QString &str); |
| 40 | static QString dedent(int level, const QString &str); |
| 41 | |
| 42 | static int s_tabSize; |
| 43 | static QStringList s_ignoreWords; |
| 44 | static bool s_quoting; |
| 45 | |
| 46 | private: |
| 47 | |
| 48 | enum class ArgumentParsingOptions { |
| 49 | Default, |
| 50 | Verbatim, |
| 51 | MacroArguments |
| 52 | }; |
| 53 | |
| 54 | Location &location(); |
| 55 | QString detailsUnknownCommand(const QSet<QString> &metaCommandSet, const QString &str); |
| 56 | void insertTarget(const QString &target); |
| 57 | void insertKeyword(const QString &keyword); |
| 58 | void include(const QString &fileName, const QString &identifier, const QStringList ¶meters); |
| 59 | void startFormat(const QString &format, int cmd); |
| 60 | bool openCommand(int cmd); |
| 61 | bool closeCommand(int endCmd); |
| 62 | void startSection(Doc::Sections unit, int cmd); |
| 63 | void endSection(int unit, int endCmd); |
| 64 | void parseAlso(); |
| 65 | void appendAtom(const Atom&); |
| 66 | void appendAtom(const LinkAtom&); |
| 67 | void appendChar(QChar ch); |
| 68 | void appendWord(const QString &word); |
| 69 | void appendToCode(const QString &code); |
| 70 | void appendToCode(const QString &code, Atom::AtomType defaultType); |
| 71 | void enterPara(Atom::AtomType leftType = Atom::ParaLeft, |
| 72 | Atom::AtomType rightType = Atom::ParaRight, const QString &string = QString()); |
| 73 | void leavePara(); |
| 74 | void leaveValue(); |
| 75 | void leaveValueList(); |
| 76 | void leaveTableRow(); |
| 77 | void quoteFromFile(const QString& filename); |
| 78 | bool expandMacro(ArgumentParsingOptions options); |
| 79 | void expandMacro(const QString &def, const QStringList &args); |
| 80 | QString expandMacroToString(const QString &name, const Macro ¯o); |
| 81 | Doc::Sections getSectioningUnit(); |
| 82 | QString getArgument(ArgumentParsingOptions options = ArgumentParsingOptions::Default); |
| 83 | QString getBracedArgument(ArgumentParsingOptions options); |
| 84 | QString getBracketedArgument(); |
| 85 | QStringList getMacroArguments(const QString &name, const Macro ¯o); |
| 86 | QString getOptionalArgument(); |
| 87 | QString getRestOfLine(); |
| 88 | QString getMetaCommandArgument(const QString &cmdStr); |
| 89 | QString getUntilEnd(int cmd); |
| 90 | QString getCode(int cmd, CodeMarker *marker, const QString &argStr = QString()); |
| 91 | |
| 92 | inline bool isAutoLinkString(const QString &word); |
| 93 | bool isAutoLinkString(const QString &word, qsizetype &curPos); |
| 94 | bool isBlankLine(); |
| 95 | bool isLeftBraceAhead(); |
| 96 | bool isLeftBracketAhead(); |
| 97 | void skipSpacesOnLine(); |
| 98 | void skipSpacesOrOneEndl(); |
| 99 | void skipAllSpaces(); |
| 100 | void skipToNextPreprocessorCommand(); |
| 101 | static bool isCode(const Atom *atom); |
| 102 | static bool isQuote(const Atom *atom); |
| 103 | static void expandArgumentsInString(QString &str, const QStringList &args); |
| 104 | void cmd_image(int cmd); |
| 105 | void cmd_overload(); |
| 106 | |
| 107 | QStack<qsizetype> m_openedInputs {}; |
| 108 | |
| 109 | QString m_input {}; |
| 110 | qsizetype m_position {}; |
| 111 | qsizetype m_backslashPosition {}; |
| 112 | qsizetype m_endPosition {}; |
| 113 | qsizetype m_inputLength {}; |
| 114 | Location m_cachedLocation {}; |
| 115 | qsizetype m_cachedPosition {}; |
| 116 | |
| 117 | DocPrivate *m_private { nullptr }; |
| 118 | enum ParagraphState { OutsideParagraph, InSingleLineParagraph, InMultiLineParagraph }; |
| 119 | ParagraphState m_paragraphState {}; |
| 120 | bool {}; |
| 121 | bool m_inTableRow {}; |
| 122 | bool m_inTableItem {}; |
| 123 | bool m_indexStartedParagraph {}; // ### rename |
| 124 | Atom::AtomType m_pendingParagraphLeftType {}; |
| 125 | Atom::AtomType m_pendingParagraphRightType {}; |
| 126 | QString m_pendingParagraphString {}; |
| 127 | |
| 128 | int m_braceDepth {}; |
| 129 | Doc::Sections m_currentSection {}; |
| 130 | QMap<QString, Location> m_targetMap {}; |
| 131 | QMap<int, QString> m_pendingFormats {}; |
| 132 | QStack<int> m_openedCommands {}; |
| 133 | QStack<OpenedList> m_openedLists {}; |
| 134 | Quoter m_quoter {}; |
| 135 | Atom *m_lastAtom { nullptr }; |
| 136 | |
| 137 | static DocUtilities &s_utilities; |
| 138 | |
| 139 | // KLUDGE: When parsing documentation, there is a need to find |
| 140 | // files to resolve quoting commands. Ideally, the system that |
| 141 | // takes care of this would be a non-static member that is a |
| 142 | // reference that is passed at |
| 143 | // construction time. |
| 144 | // Nonetheless, with how the current codebase is constructed, this |
| 145 | // has proven to be extremely difficult until more changes are |
| 146 | // done. In particular, the construction of a DocParser happens in |
| 147 | // multiple places at multiple depths and, in particular, happens |
| 148 | // in one of Doc's constructor. |
| 149 | // Doc itself is built, again, in multiple places at multiple |
| 150 | // depths, making it clumsy and sometimes infeasible to pass the |
| 151 | // dependency around so that it is available at the required |
| 152 | // places. In particular, this stems from the fact that Doc is |
| 153 | // holding many responsabilities and is spread troughtout much of |
| 154 | // the codebase in different ways. DocParser mostly depends on Doc |
| 155 | // and Doc currently depends on DocParser, making the two |
| 156 | // difficult to separate. |
| 157 | // |
| 158 | // In the future, we expect Doc to mostly be removed, such as to |
| 159 | // remove this dependencies and the parsing of documentation to |
| 160 | // happen near main and atomically from other endevours, producing |
| 161 | // an intermediate representation that is consumed by later |
| 162 | // phases. |
| 163 | // At that point, it should be possible to not have this kind of |
| 164 | // indirection while, for now, the only accessible way to pass |
| 165 | // this dependency is trough the initialize method which passes |
| 166 | // for Doc::initialize. |
| 167 | // |
| 168 | // Furthemore, as we cannot late-bind a reference, and having a |
| 169 | // desire to avoid an unnecessary copy, we are thus forced to use |
| 170 | // a different storage method, in this case a pointer. |
| 171 | // This too should be removed later on, using reference or move |
| 172 | // semantic depending on the required data-flow. |
| 173 | static FileResolver* file_resolver; |
| 174 | }; |
| 175 | |
| 176 | QT_END_NAMESPACE |
| 177 | |
| 178 | #endif // DOCPARSER_H |
| 179 | |