parser.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // SuperTux - Scripting reference generator
  2. // Copyright (C) 2023 Vankata453
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. #include "parser.hpp"
  17. #include <string>
  18. #include <iostream>
  19. #include "util.hpp"
  20. namespace Parser {
  21. Class* cl = nullptr;
  22. void parse_compounddef(tinyxml2::XMLElement* p_root, Class& cls)
  23. {
  24. tinyxml2::XMLElement* p_compounddef = p_root->FirstChildElement("compounddef");
  25. // Get general class info
  26. cls.name = p_compounddef->FirstChildElement("compoundname")->GetText();
  27. replace(cls.name, "scripting::", ""); // Leave only the class name
  28. // Get additional info
  29. tinyxml2::XMLElement* p_detaileddescpara = p_compounddef->FirstChildElement("detaileddescription")->FirstChildElement("para");
  30. if (p_detaileddescpara) // Detailed description (possibly containing additional info) is available
  31. {
  32. tinyxml2::XMLElement* p_xrefsect = p_detaileddescpara->FirstChildElement("xrefsect");
  33. while (p_xrefsect)
  34. {
  35. // Check if the "xrefsect" title matches any of the additional info titles
  36. const std::string title = p_xrefsect->FirstChildElement("xreftitle")->GetText();
  37. if (title == "Summary")
  38. parse_xrefsect_desc(p_xrefsect, cls.summary);
  39. else if (title == "Instances")
  40. parse_xrefsect_desc(p_xrefsect, cls.instances);
  41. p_xrefsect = p_xrefsect->NextSiblingElement("xrefsect");
  42. }
  43. }
  44. cl = &cls;
  45. parse_sectiondef(p_compounddef);
  46. cl = nullptr;
  47. }
  48. void parse_sectiondef(tinyxml2::XMLElement* p_compounddef)
  49. {
  50. if (!cl) return;
  51. tinyxml2::XMLElement* p_sectiondef = p_compounddef->FirstChildElement("sectiondef");
  52. while (p_sectiondef)
  53. {
  54. if (attr_equal(p_sectiondef, "kind", "public-func") ||
  55. attr_equal(p_sectiondef, "kind", "public-static-attrib")) // Is public, contains public class functions or static attributes
  56. {
  57. parse_memberdef(p_sectiondef);
  58. }
  59. p_sectiondef = p_sectiondef->NextSiblingElement("sectiondef");
  60. }
  61. }
  62. void parse_memberdef(tinyxml2::XMLElement* p_sectiondef)
  63. {
  64. if (!cl) return;
  65. tinyxml2::XMLElement* p_memberdef = p_sectiondef->FirstChildElement("memberdef");
  66. while (p_memberdef)
  67. {
  68. if (attr_equal(p_memberdef, "kind", "function") &&
  69. attr_equal(p_memberdef, "static", "no") &&
  70. !el_equal(p_memberdef, "type", "")) // Try searching for non-static, typed functions
  71. {
  72. /** Parse the function **/
  73. Function func;
  74. // Get general info
  75. func.type = p_memberdef->FirstChildElement("type")->GetText();
  76. func.name = p_memberdef->FirstChildElement("name")->GetText();
  77. if (starts_with(func.name, cl->name + "_")) // If function name starts with the string "{CLASS}_", remove it
  78. func.name.erase(0, cl->name.size() + 1);
  79. tinyxml2::XMLElement* p_descpara = p_memberdef->FirstChildElement("briefdescription")->FirstChildElement("para");
  80. tinyxml2::XMLElement* p_detaileddescpara = p_memberdef->FirstChildElement("detaileddescription")->FirstChildElement("para");
  81. if (p_descpara) // Brief description has been provided
  82. {
  83. XMLTextReader read(func.description);
  84. p_descpara->Accept(&read);
  85. }
  86. if (p_detaileddescpara && p_detaileddescpara->GetText()) // The description may also continue in the detailed description. Check if more text is available.
  87. func.description += p_detaileddescpara->GetText();
  88. /** Parse function parameters **/
  89. parse_parameterlist(p_memberdef, func);
  90. // Add to function list
  91. cl->functions.push_back(func);
  92. }
  93. else if (attr_equal(p_memberdef, "kind", "variable") &&
  94. !el_equal(p_memberdef, "type", "") &&
  95. starts_with(p_memberdef->FirstChildElement("type")->GetText(), "const ")) // Otherwise, try searching for constant variables
  96. {
  97. /** Parse the constant **/
  98. Constant con;
  99. // Get general info
  100. con.type = p_memberdef->FirstChildElement("type")->GetText();
  101. con.type.erase(0, 6); // Remove the "const " part from the type string
  102. con.name = p_memberdef->FirstChildElement("name")->GetText();
  103. tinyxml2::XMLElement* p_descpara = p_memberdef->FirstChildElement("briefdescription")->FirstChildElement("para");
  104. tinyxml2::XMLElement* p_detaileddescpara = p_memberdef->FirstChildElement("detaileddescription")->FirstChildElement("para");
  105. if (p_descpara) // Brief description has been provided
  106. {
  107. XMLTextReader read(con.description);
  108. p_descpara->Accept(&read);
  109. }
  110. if (p_detaileddescpara && p_detaileddescpara->GetText()) // The description may also continue in the detailed description. Check if more text is available.
  111. con.description += p_detaileddescpara->GetText();
  112. // Add to constants list
  113. cl->constants.push_back(con);
  114. }
  115. p_memberdef = p_memberdef->NextSiblingElement("memberdef");
  116. }
  117. }
  118. void parse_parameterlist(tinyxml2::XMLElement* p_memberdef, Function& func)
  119. {
  120. if (!cl) return;
  121. tinyxml2::XMLElement* p_detaileddescpara = p_memberdef->FirstChildElement("detaileddescription")->FirstChildElement("para");
  122. if (!p_detaileddescpara) return; // There is no detailed description, hence no parameter list
  123. tinyxml2::XMLElement* p_parameterlist = p_detaileddescpara->FirstChildElement("parameterlist");
  124. if (!p_parameterlist) return; // No parameter list
  125. tinyxml2::XMLElement* p_parameteritem = p_parameterlist->FirstChildElement("parameteritem");
  126. while (p_parameteritem)
  127. {
  128. /** Parse the parameter **/
  129. Parameter param;
  130. tinyxml2::XMLElement* p_parameternamelist = p_parameteritem->FirstChildElement("parameternamelist");
  131. tinyxml2::XMLElement* p_parametertype = p_parameternamelist->FirstChildElement("parametertype");
  132. if (p_parametertype) // Type has been provided
  133. param.type = p_parametertype->GetText();
  134. tinyxml2::XMLElement* p_parametername = p_parameternamelist->FirstChildElement("parametername");
  135. if (p_parametername) // Name has been provided
  136. param.name = p_parametername->GetText();
  137. if (starts_with(param.name, "$")) // Parameter names may start with "$" so they can have types assigned. Remove the "$" if so
  138. param.name.erase(0, 1);
  139. tinyxml2::XMLElement* p_parameterdescpara = p_parameteritem->FirstChildElement("parameterdescription")->FirstChildElement("para");
  140. if (p_parameterdescpara) // Description has been provided
  141. {
  142. XMLTextReader read(param.description);
  143. p_parameterdescpara->Accept(&read);
  144. }
  145. // Add to parameter list
  146. func.parameters.push_back(param);
  147. p_parameteritem = p_parameteritem->NextSiblingElement("parameteritem");
  148. }
  149. }
  150. void parse_xrefsect_desc(tinyxml2::XMLElement* p_xrefsect, std::string& dest)
  151. {
  152. tinyxml2::XMLElement* p_xrefsectdescpara = p_xrefsect->FirstChildElement("xrefdescription")->FirstChildElement("para");
  153. if (p_xrefsectdescpara) // Description has been provided
  154. {
  155. XMLTextReader read(dest);
  156. p_xrefsectdescpara->Accept(&read);
  157. }
  158. }
  159. } // namespace Parser