1 /******************************************************************************
2  *
3  *
4  *
5  * Copyright (C) 1997-2015 by Dimitri van Heesch.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation under the terms of the GNU General Public License is hereby
9  * granted. No representations are made about the suitability of this software
10  * for any purpose. It is provided "as is" without express or implied warranty.
11  * See the GNU General Public License for more details.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17 
18 #ifndef PARSERINTF_H
19 #define PARSERINTF_H
20 
21 #include <functional>
22 #include <memory>
23 #include <map>
24 #include <string>
25 
26 #include "types.h"
27 #include "containers.h"
28 
29 class Entry;
30 class FileDef;
31 class CodeOutputInterface;
32 class MemberDef;
33 class Definition;
34 class ClangTUParser;
35 
36 /** \brief Abstract interface for outline parsers.
37  *
38  *  By implementing the methods of this interface one can add
39  *  a new language parser to doxygen. The parser implementation can make use of the
40  *  comment block parser to parse the contents of special comment blocks.
41  */
42 class OutlineParserInterface
43 {
44   public:
~OutlineParserInterface()45     virtual ~OutlineParserInterface() {}
46 
47     /** Parses a single input file with the goal to build an Entry tree.
48      *  @param[in] fileName    The full name of the file.
49      *  @param[in] fileBuf     The contents of the file (zero terminated).
50      *  @param[in,out] root    The root of the tree of Entry *nodes
51      *             representing the information extracted from the file.
52      *  @param[in] clangParser The clang translation unit parser object
53      *                         or nullptr if disabled.
54      */
55     virtual void parseInput(const QCString &fileName,
56                             const char *fileBuf,
57                             const std::shared_ptr<Entry> &root,
58                             ClangTUParser *clangParser) = 0;
59 
60     /** Returns TRUE if the language identified by \a extension needs
61      *  the C preprocessor to be run before feed the result to the input
62      *  parser.
63      *  @see parseInput()
64      */
65     virtual bool needsPreprocessing(const QCString &extension) const = 0;
66 
67     /** Callback function called by the comment block scanner.
68      *  It provides a string \a text containing the prototype of a function
69      *  or variable. The parser should parse this and store the information
70      *  in the Entry node that corresponds with the node for which the
71      *  comment block parser was invoked.
72      */
73     virtual void parsePrototype(const QCString &text) = 0;
74 
75 };
76 
77 /** \brief Abstract interface for code parsers.
78  *
79  *  By implementing the methods of this interface one can add
80  *  a new language parser to doxygen. This interface is used for
81  *  syntax highlighting, but also to extract cross references and call graphs.
82  */
83 class CodeParserInterface
84 {
85   public:
~CodeParserInterface()86     virtual ~CodeParserInterface() {}
87 
88     /** Parses a source file or fragment with the goal to produce
89      *  highlighted and cross-referenced output.
90      *  @param[in] codeOutIntf Abstract interface for writing the result.
91      *  @param[in] scopeName Name of scope to which the code belongs.
92      *  @param[in] input Actual code in the form of a string
93      *  @param[in] lang The programming language of the code fragment.
94      *  @param[in] isExampleBlock TRUE iff the code is part of an example.
95      *  @param[in] exampleName Name of the example.
96      *  @param[in] fileDef File definition to which the code
97      *             is associated.
98      *  @param[in] startLine Starting line in case of a code fragment.
99      *  @param[in] endLine Ending line of the code fragment.
100      *  @param[in] inlineFragment Code fragment that is to be shown inline
101      *             as part of the documentation.
102      *  @param[in] memberDef Member definition to which the code
103      *             is associated (non null in case of an inline fragment
104      *             for a member).
105      *  @param[in] showLineNumbers if set to TRUE and also fileDef is not 0,
106      *             line numbers will be added to the source fragment
107      *  @param[in] searchCtx context under which search data has to be stored.
108      *  @param[in] collectXRefs collect cross-reference relations.
109      */
110     virtual void parseCode(CodeOutputInterface &codeOutIntf,
111                            const QCString &scopeName,
112                            const QCString &input,
113                            SrcLangExt lang,
114                            bool isExampleBlock,
115                            const QCString &exampleName=QCString(),
116                            const FileDef *fileDef=0,
117                            int startLine=-1,
118                            int endLine=-1,
119                            bool inlineFragment=FALSE,
120                            const MemberDef *memberDef=0,
121                            bool showLineNumbers=TRUE,
122                            const Definition *searchCtx=0,
123                            bool collectXRefs=TRUE
124                           ) = 0;
125 
126     /** Resets the state of the code parser.
127      *  Since multiple code fragments can together form a single example, an
128      *  explicit function is used to reset the code parser state.
129      *  @see parseCode()
130      */
131     virtual void resetCodeParserState() = 0;
132 
133 };
134 
135 //-----------------------------------------------------------------------------
136 
137 using OutlineParserFactory = std::function<std::unique_ptr<OutlineParserInterface>()>;
138 using CodeParserFactory    = std::function<std::unique_ptr<CodeParserInterface>()>;
139 
140 /** \brief Manages programming language parsers.
141  *
142  *  This class manages the language parsers in the system. One can
143  *  register parsers, and obtain a parser given a file extension.
144  */
145 class ParserManager
146 {
147 
148     struct ParserPair
149     {
ParserPairParserPair150       ParserPair(OutlineParserFactory opf, CodeParserFactory cpf, const QCString &pn)
151         : outlineParserFactory(opf), codeParserFactory(cpf), parserName(pn)
152       {
153       }
154 
155       OutlineParserFactory outlineParserFactory;
156       CodeParserFactory    codeParserFactory;
157       QCString parserName;
158     };
159 
160   public:
161     /** Create the parser manager
162      *  @param outlineParserFactory the fallback outline parser factory to use for unknown extensions
163      *  @param codeParserFactory    the fallback code parser factory to use for unknown extensions
164      */
ParserManager(OutlineParserFactory outlineParserFactory,CodeParserFactory codeParserFactory)165     ParserManager(OutlineParserFactory outlineParserFactory,
166                   CodeParserFactory    codeParserFactory)
167       : m_defaultParsers(outlineParserFactory,codeParserFactory, QCString())
168     {
169     }
170 
171     /** Registers an additional parser.
172      *  @param[in] name          A symbolic name of the parser, i.e. "c",
173      *                           "python", "fortran", "vhdl", ...
174      *  @param[in] outlineParserFactory A factory method to create a language parser (scanner) that
175      *                           is to be used for the given name.
176      *  @param[in] codeParserFactory    A factory method to create a code parser that is to be used
177      *                           for the given name.
178      */
registerParser(const QCString & name,OutlineParserFactory outlineParserFactory,CodeParserFactory codeParserFactory)179     void registerParser(const QCString &name,OutlineParserFactory outlineParserFactory,
180                                          CodeParserFactory    codeParserFactory)
181     {
182       m_parsers.emplace(name.str(),ParserPair(outlineParserFactory,codeParserFactory,name));
183     }
184 
185     /** Registers a file \a extension with a parser with name \a parserName.
186      *  Returns TRUE if the extension was successfully registered.
187      */
registerExtension(const QCString & extension,const QCString & parserName)188     bool registerExtension(const QCString &extension, const QCString &parserName)
189     {
190       if (parserName.isEmpty() || extension.isEmpty()) return FALSE;
191 
192       const auto &parserIt = m_parsers.find(parserName.str());
193       if (parserIt == m_parsers.end()) return FALSE;
194 
195       auto extensionIt = m_extensions.find(extension.str());
196       if (extensionIt != m_extensions.end()) // extension already exists
197       {
198         m_extensions.erase(extensionIt); // remove it (e.g. user specified extension overrules built in one)
199       }
200       m_extensions.emplace(extension.str(),parserIt->second); // add new mapping
201       return TRUE;
202     }
203 
204     /** Gets the interface to the parser associated with a given \a extension.
205      *  If there is no parser explicitly registered for the supplied extension,
206      *  the interface to the default parser will be returned.
207      */
getOutlineParser(const QCString & extension)208     std::unique_ptr<OutlineParserInterface> getOutlineParser(const QCString &extension)
209     {
210       return getParsers(extension).outlineParserFactory();
211     }
212 
213     /** Gets the interface to the parser associated with a given \a extension.
214      *  If there is no parser explicitly registered for the supplied extension,
215      *  the interface to the default parser will be returned.
216      */
getCodeParser(const QCString & extension)217     std::unique_ptr<CodeParserInterface> getCodeParser(const QCString &extension)
218     {
219       auto factory = getCodeParserFactory(extension);
220       return factory();
221     }
222 
223     /** Get the factory for create code parser objects with a given \a extension. */
getCodeParserFactory(const QCString & extension)224     CodeParserFactory &getCodeParserFactory(const QCString &extension)
225     {
226       return getParsers(extension).codeParserFactory;
227     }
228 
229     /** Gets the name of the parser associated with given \a extension.
230      *  If there is no parser explicitly registered for the supplied extension,
231      *  te empty string  will be reurned.
232      */
getParserName(const QCString & extension)233     QCString getParserName(const QCString &extension)
234     {
235       return getParsers(extension).parserName;
236     }
237 
238   private:
getParsers(const QCString & extension)239     ParserPair &getParsers(const QCString &extension)
240     {
241       QCString ext = extension.lower();
242       if (ext.isEmpty()) ext=".no_extension";
243       auto it = m_extensions.find(ext.data());
244       if (it==m_extensions.end() && ext.length()>4)
245       {
246         it = m_extensions.find(ext.left(4).data());
247       }
248       return it!=m_extensions.end() ? it->second : m_defaultParsers;
249     }
250 
251     std::map<std::string,ParserPair> m_parsers;
252     std::map<std::string,ParserPair &> m_extensions;
253     ParserPair m_defaultParsers;
254 };
255 
256 #endif
257