PageRenderTime 116ms CodeModel.GetById 75ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/libs/geometry/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_xml_parser.hpp

http://hadesmem.googlecode.com/
C++ Header | 538 lines | 435 code | 49 blank | 54 comment | 194 complexity | 98b9bda834f5286f9fefd1775e09f83e MD5 | raw file
  1// Boost.Geometry (aka GGL, Generic Geometry Library)
  2//
  3// Copyright (c) 2010-2011 Barend Gehrels, Amsterdam, the Netherlands.
  4// Use, modification and distribution is subject to the Boost Software License,
  5// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6// http://www.boost.org/LICENSE_1_0.txt)
  7//
  8//
  9#ifndef DOXYGEN_XML_PARSER_HPP
 10#define DOXYGEN_XML_PARSER_HPP
 11
 12
 13#include <string>
 14#include <vector>
 15
 16#include <boost/algorithm/string.hpp>
 17
 18#include <rapidxml_util.hpp>
 19#include <doxygen_elements.hpp>
 20#include <parameter_predicates.hpp>
 21#include <configuration.hpp>
 22
 23
 24inline std::string keep_after(std::string const& input, std::string const& sig)
 25{
 26    std::size_t pos = input.rfind(sig);
 27    if (pos != std::string::npos)
 28    {
 29        std::string copy = input.substr(pos + sig.length());
 30        return copy;
 31    }
 32    return input;
 33}
 34
 35
 36static inline void add_or_set(std::vector<parameter>& parameters, parameter const& p)
 37{
 38    std::vector<parameter>::iterator it = std::find_if(parameters.begin(), parameters.end(), par_by_name(p.name));
 39    if (it != parameters.end())
 40    {
 41        if (it->brief_description.empty()) it->brief_description = p.brief_description;
 42        if (it->type.empty()) it->type = p.type;
 43        if (it->fulltype.empty()) it->fulltype = p.fulltype;
 44        if (it->default_value.empty()) it->default_value = p.default_value;
 45    }
 46    else
 47    {
 48        parameters.push_back(p);
 49    }
 50}
 51
 52
 53
 54
 55/// Parses a "para" element 
 56/*
 57This is used for different purposes within Doxygen. 
 58- Either a detailed description, possibly containing several sections (para's)
 59  -> so parse next siblings
 60- Or a detailed description also containing qbk records
 61
 62So we have to list explicitly either where to recurse, or where not to...
 63
 64*/
 65static void parse_para(rapidxml::xml_node<>* node, std::string& contents, bool& skip, bool first = true)
 66{
 67    if (node != NULL)
 68    {
 69        if (node->type() == rapidxml::node_element)
 70        {
 71            //std::cout << "ELEMENT: " << node->name() << "=" << node->value() << std::endl;
 72            std::string name = node->name();
 73            if (boost::equals(name, "qbk.skip"))
 74            {
 75                skip = true;
 76                return;
 77            }
 78            else if (! (
 79                (boost::equals(name, "para") && first)
 80                || boost::equals(name, "ref")
 81                || boost::equals(name, "defval")
 82                || boost::equals(name, "verbatim")
 83                || boost::equals(name, "bold")
 84                || boost::equals(name, "emphasis")
 85                || boost::equals(name, "linebreak")
 86                ))
 87            {
 88                return;
 89            }
 90        }
 91        else if (node->type() == rapidxml::node_data)
 92        {
 93            contents += node->value();
 94            //std::cout << "DATA: " << node->name() << "=" << node->value() << std::endl;
 95        }
 96        else
 97        {
 98            //std::cout << "OTHER: " << node->name() << "=" << node->value() << std::endl;
 99        }
100        parse_para(node->first_node(), contents, skip, false);
101        parse_para(node->next_sibling(), contents, skip, false);
102    }
103}
104
105
106static void parse_parameter(rapidxml::xml_node<>* node, parameter& p)
107{
108    // #define: <param><defname>Point</defname></param>
109    // template: <param><type>typename</type><declname>CoordinateType</declname><defname>CoordinateType</defname></param>
110    // template with default: <param><type>typename</type><declname>CoordinateSystem</declname><defname>CoordinateSystem</defname><defval><ref ....>cs::cartesian</ref></defval></param>
111    // with enum: <type><ref refid="group__enum_1ga7d33eca9a5389952bdf719972eb802b6" kindref="member">closure_selector</ref></type>
112    if (node != NULL)
113    {
114        std::string name = node->name();
115        if (name == "type")
116        {
117            get_contents(node->first_node(), p.fulltype);
118            p.type = p.fulltype;
119            boost::replace_all(p.type, " const", "");
120            boost::trim(p.type);
121            boost::replace_all(p.type, "&", "");
122            boost::replace_all(p.type, "*", "");
123            boost::trim(p.type);
124        }
125        else if (name == "declname") p.name = node->value();
126        else if (name == "parametername") p.name = node->value();
127        else if (name == "defname") p.name = node->value(); 
128        else if (name == "defval") 
129        {
130             parse_para(node, p.default_value, p.skip);
131        }
132        else if (name == "para")
133        {
134             parse_para(node, p.brief_description, p.skip);
135        }
136
137        parse_parameter(node->first_node(), p);
138        parse_parameter(node->next_sibling(), p);
139    }
140}
141
142static void parse_enumeration_value(rapidxml::xml_node<>* node, enumeration_value& value)
143{
144    // <enumvalue><name>green</name><initializer> 2</initializer>
145    //    <briefdescription><para>...</para></briefdescription>
146    //    <detaileddescription><para>...</para></detaileddescription>
147    // </enumvalue>
148    if (node != NULL)
149    {
150        std::string node_name = node->name();
151
152        if (node_name == "name") value.name = node->value();
153        else if (node_name == "para")
154        {
155            // Parses both brief AND detailed into this description
156            parse_para(node, value.brief_description, value.skip);
157        }
158        else if (node_name == "initializer")
159        {
160            value.initializer = node->value();
161        }
162
163        parse_enumeration_value(node->first_node(), value);
164        parse_enumeration_value(node->next_sibling(), value);
165    }
166}
167
168// Definition is a function or a class/struct
169template <typename Parameters>
170static void parse_parameter_list(rapidxml::xml_node<>* node, Parameters& parameters)
171{
172    if (node != NULL)
173    {
174        std::string name = node->name();
175
176        if (name == "parameteritem")
177        {
178            parameter p;
179            parse_parameter(node->first_node(), p);
180            if (! p.name.empty())
181            {
182                // Copy its description
183                std::vector<parameter>::iterator it = std::find_if(parameters.begin(),
184                    parameters.end(), par_by_name(p.name));
185                if (it != parameters.end())
186                {
187                    it->brief_description = p.brief_description;
188                }
189                else
190                {
191                    parameters.push_back(p);
192                }
193            }
194        }
195        else if (name == "param")
196        {
197            // Element of 'templateparamlist.param (.type,.declname,.defname)'
198            parameter p;
199            parse_parameter(node->first_node(), p);
200
201            // Doxygen handles templateparamlist param's differently:
202            //
203            // Case 1:
204            // <param><type>typename T</type></param>
205            // -> no name, assign type to name, replace typename
206            //
207            // Case 2:
208            // <type>typename</type><declname>T</declname><defname>T</defname>
209            // -> set full type
210            if (p.name.empty())
211            {
212                // Case 1
213                p.name = p.type;
214                boost::replace_all(p.name, "typename", "");
215                boost::trim(p.name);
216            }
217            else
218            {
219                // Case 2
220                p.fulltype = p.type + " " + p.name;
221            }
222
223            add_or_set(parameters, p);
224        }
225
226        parse_parameter_list(node->first_node(), parameters);
227        parse_parameter_list(node->next_sibling(), parameters);
228    }
229}
230
231
232template <typename Element>
233static void parse_element(rapidxml::xml_node<>* node, configuration const& config, std::string const& parent, Element& el)
234{
235    if (node != NULL)
236    {
237        std::string name = node->name();
238        std::string full = parent + "." + name;
239
240        if (full == ".briefdescription.para")
241        {
242            parse_para(node, el.brief_description, el.skip);
243        }
244        else if (full == ".detaileddescription.para")
245        {
246            std::string para;
247            parse_para(node, para, el.skip);
248            if (!para.empty() && !el.detailed_description.empty())
249            {
250                el.detailed_description += "\n\n";
251            }
252            el.detailed_description += para;
253        }
254        else if (full == ".location")
255        {
256            std::string loc = get_attribute(node, "file");
257            // Location of (header)file. It is a FULL path, so find the start
258            // and strip the rest
259            std::size_t pos = loc.rfind(config.start_include);
260            if (pos != std::string::npos)
261            {
262                loc = loc.substr(pos);
263            }
264            el.location = loc;
265            el.line = atol(get_attribute(node, "line").c_str());
266        }
267        else if (full == ".detaileddescription.para.qbk")
268        {
269            el.qbk_markup.push_back(markup(node->value()));
270        }
271        else if (full == ".detaileddescription.para.qbk.after.synopsis")
272        {
273            el.qbk_markup.push_back(markup(markup_after, markup_synopsis, node->value()));
274        }
275        else if (full == ".detaileddescription.para.qbk.before.synopsis")
276        {
277            el.qbk_markup.push_back(markup(markup_before, markup_synopsis, node->value()));
278        }
279        else if (full == ".detaileddescription.para.qbk.distinguish")
280        {
281            el.additional_description = node->value();
282            boost::trim(el.additional_description);
283        }
284        else if (full == ".templateparamlist")
285        {
286            parse_parameter_list(node->first_node(), el.template_parameters);
287        }
288        else if (full == ".detaileddescription.para.parameterlist")
289        {
290            std::string kind = get_attribute(node, "kind");
291            if (kind == "param")
292            {
293                parse_parameter_list(node->first_node(), el.parameters);
294            }
295            else if (kind == "templateparam")
296            {
297                parse_parameter_list(node->first_node(), el.template_parameters);
298            }
299        }
300
301        parse_element(node->first_node(), config, full, el);
302        parse_element(node->next_sibling(), config, parent, el);
303    }
304}
305
306static void parse_function(rapidxml::xml_node<>* node, configuration const& config, std::string const& parent, function& f)
307{
308    if (node != NULL)
309    {
310        std::string name = node->name();
311        std::string full = parent + "." + name;
312
313        if (full == ".name") f.name = node->value();
314        else if (full == ".argsstring") f.argsstring = node->value();
315        else if (full == ".definition")
316        {
317            f.definition = node->value();
318            if (! config.skip_namespace.empty())
319            {
320                boost::replace_all(f.definition, config.skip_namespace, "");
321            }
322        }
323        else if (full == ".param")
324        {
325            parameter p;
326            parse_parameter(node->first_node(), p);
327            add_or_set(f.parameters, p);
328        }
329        else if (full == ".type")
330        {
331            get_contents(node->first_node(), f.return_type);
332        }
333        else if (full == ".detaileddescription.para.simplesect")
334        {
335            std::string kind = get_attribute(node, "kind");
336            if (kind == "return")
337            {
338                get_contents(node->first_node(), f.return_description);
339            }
340            /*else if (kind == "param")
341            {
342                get_contents(node->first_node(), f.paragraphs);
343            }*/
344        }
345        else if (full == ".detaileddescription.para.image")
346        {
347        }
348
349        parse_function(node->first_node(), config, full, f);
350        parse_function(node->next_sibling(), config, parent, f);
351    }
352}
353
354static void parse_enumeration(rapidxml::xml_node<>* node, configuration const& config, std::string const& parent, enumeration& e)
355{
356    if (node != NULL)
357    {
358        std::string name = node->name();
359        std::string full = parent + "." + name;
360
361        if (full == ".name") e.name = node->value();
362        else if (full == ".enumvalue")
363        {
364            enumeration_value value;
365            parse_enumeration_value(node->first_node(), value);
366            e.enumeration_values.push_back(value);
367        }
368
369        parse_enumeration(node->first_node(), config, full, e);
370        parse_enumeration(node->next_sibling(), config, parent, e);
371    }
372}
373
374
375static std::string parse_named_node(rapidxml::xml_node<>* node, std::string const& look_for_name)
376{
377    if (node != NULL)
378    {
379        std::string node_name = node->name();
380        std::string contents;
381
382        if (boost::equals(node_name, look_for_name))
383        {
384            contents = node->value();
385        }
386
387        return contents
388            + parse_named_node(node->first_node(), look_for_name)
389            + parse_named_node(node->next_sibling(), look_for_name);
390    }
391    return "";
392}
393
394
395
396
397static void parse(rapidxml::xml_node<>* node, configuration const& config, documentation& doc, bool member = false)
398{
399    if (node != NULL)
400    {
401        bool recurse = false;
402        bool is_member = member;
403
404        std::string nodename = node->name();
405
406        if (nodename == "doxygen")
407        {
408            recurse = true;
409        }
410        else if (nodename == "sectiondef")
411        {
412            std::string kind = get_attribute(node, "kind");
413
414            if (kind == "func"
415                || kind == "define"
416                || kind == "enum"
417                )
418            {
419                recurse = true;
420            }
421            else if (boost::starts_with(kind, "public"))
422            {
423                recurse = true;
424                is_member = true;
425            }
426        }
427        else if (nodename == "compounddef")
428        {
429            std::string kind = get_attribute(node, "kind");
430            if (kind == "group")
431            {
432                recurse = true;
433            }
434            else if (kind == "struct")
435            {
436                recurse = true;
437                doc.cos.is_class = false;
438                parse_element(node->first_node(), config, "", doc.cos);
439            }
440            else if (kind == "class")
441            {
442                recurse = true;
443                doc.cos.is_class = true;
444                parse_element(node->first_node(), config, "", doc.cos);
445            }
446        }
447        else if (nodename == "memberdef")
448        {
449            std::string kind = get_attribute(node, "kind");
450            if (kind == "function")
451            {
452                function f;
453                parse_element(node->first_node(), config, "", f);
454                parse_function(node->first_node(), config, "", f);
455                if (member)
456                {
457                    f.type = boost::equals(f.name, doc.cos.name) 
458                        ? function_constructor 
459                        : function_member;
460                    doc.cos.functions.push_back(f);
461                }
462                else
463                {
464                    f.type = function_free;
465                    doc.functions.push_back(f);
466                }
467            }
468            else if (kind == "define")
469            {
470                function f;
471                f.type = function_define;
472                parse_element(node->first_node(), config, "", f);
473                parse_function(node->first_node(), config, "", f);
474                doc.functions.push_back(f);
475            }
476            else if (kind == "enum")
477            {
478                enumeration e;
479                parse_element(node->first_node(), config, "", e);
480                parse_enumeration(node->first_node(), config, "", e);
481                doc.enumerations.push_back(e);
482            }
483            else if (kind == "typedef")
484            {
485                if (boost::equals(get_attribute(node, "prot"), "public"))
486                {
487                    std::string name = parse_named_node(node->first_node(), "name");
488                    doc.cos.typedefs.push_back(base_element(name));
489                }
490            }
491            else if (kind == "variable")
492            {
493                if (boost::equals(get_attribute(node, "static"), "yes")
494                    && boost::equals(get_attribute(node, "mutable"), "no")
495                    && boost::equals(get_attribute(node, "prot"), "public"))
496                {
497                    std::string name = parse_named_node(node->first_node(), "name");
498                    doc.cos.variables.push_back(base_element(name));
499                }
500            }
501
502        }
503        else if (nodename == "compoundname")
504        {
505            std::string name = node->value();
506            if (name.find("::") != std::string::npos)
507            {
508                doc.cos.fullname = name;
509
510                // For a class, it should have "boost::something::" before
511                // set its name without namespace
512                doc.cos.name = keep_after(name, "::");
513            }
514        }
515        else if (nodename == "basecompoundref")
516        {
517            base_class bc;
518            bc.name = node->value();
519            bc.derivation = get_attribute(node, "prot");
520            bc.virtuality = get_attribute(node, "virt");
521            doc.cos.base_classes.push_back(bc);
522        }
523        else
524        {
525            //std::cout << nodename << " ignored." << std::endl;
526        }
527
528
529        if (recurse)
530        {
531            // First recurse into childnodes, then handle next siblings
532            parse(node->first_node(), config, doc, is_member);
533        }
534        parse(node->next_sibling(), config, doc, is_member);
535    }
536}
537
538#endif // DOXYGEN_XML_PARSER_HPP