PageRenderTime 63ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/generator/typesystem.cpp

http://qtd.googlecode.com/
C++ | 1618 lines | 1349 code | 204 blank | 65 comment | 319 complexity | cf3c7f87276144fc5b604834391c9a45 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 1992-2008 Nokia. All rights reserved.
  4. **
  5. ** This file is part of Qt Jambi.
  6. **
  7. ** * Commercial Usage
  8. * Licensees holding valid Qt Commercial licenses may use this file in
  9. * accordance with the Qt Commercial License Agreement provided with the
  10. * Software or, alternatively, in accordance with the terms contained in
  11. * a written agreement between you and Nokia.
  12. *
  13. *
  14. * GNU General Public License Usage
  15. * Alternatively, this file may be used under the terms of the GNU
  16. * General Public License versions 2.0 or 3.0 as published by the Free
  17. * Software Foundation and appearing in the file LICENSE.GPL included in
  18. * the packaging of this file. Please review the following information
  19. * to ensure GNU General Public Licensing requirements will be met:
  20. * http://www.fsf.org/licensing/licenses/info/GPLv2.html and
  21. * http://www.gnu.org/copyleft/gpl.html. In addition, as a special
  22. * exception, Nokia gives you certain additional rights. These rights
  23. * are described in the Nokia Qt GPL Exception version 1.2, included in
  24. * the file GPL_EXCEPTION.txt in this package.
  25. *
  26. * Qt for Windows(R) Licensees
  27. * As a special exception, Nokia, as the sole copyright holder for Qt
  28. * Designer, grants users of the Qt/Eclipse Integration plug-in the
  29. * right for the Qt/Eclipse Integration to link to functionality
  30. * provided by Qt Designer and its related libraries.
  31. *
  32. *
  33. * If you are unsure which license is appropriate for your use, please
  34. * contact the sales department at qt-sales@nokia.com.
  35. **
  36. ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
  37. ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  38. **
  39. ****************************************************************************/
  40. #include "typesystem.h"
  41. #include "generator.h"
  42. #include "customtypes.h"
  43. #include <reporthandler.h>
  44. #include <QtXml>
  45. QString strings_Object = QLatin1String("Object");
  46. QString strings_String = QLatin1String("string");
  47. QString strings_Thread = QLatin1String("Thread");
  48. QString strings_char = QLatin1String("char");
  49. QString strings_java_lang = QLatin1String("java.lang");
  50. QString strings_jchar = QLatin1String("jchar");
  51. QString strings_jobject = QLatin1String("jobject");
  52. static void addRemoveFunctionToTemplates(TypeDatabase *db);
  53. class StackElement
  54. {
  55. public:
  56. enum ElementType {
  57. None = 0x0,
  58. // Type tags (0x1, ... , 0xff)
  59. ObjectTypeEntry = 0x1,
  60. ValueTypeEntry = 0x2,
  61. InterfaceTypeEntry = 0x3,
  62. NamespaceTypeEntry = 0x4,
  63. ComplexTypeEntryMask = 0xf,
  64. // Non-complex type tags (0x10, 0x20, ... , 0xf0)
  65. PrimitiveTypeEntry = 0x10,
  66. EnumTypeEntry = 0x20,
  67. TypeEntryMask = 0xff,
  68. // Simple tags (0x100, 0x200, ... , 0xf00)
  69. ExtraIncludes = 0x100,
  70. Include = 0x200,
  71. ModifyFunction = 0x300,
  72. ModifyField = 0x400,
  73. Root = 0x500,
  74. CustomMetaConstructor = 0x600,
  75. CustomMetaDestructor = 0x700,
  76. ArgumentMap = 0x800,
  77. SuppressedWarning = 0x900,
  78. Rejection = 0xa00,
  79. LoadTypesystem = 0xb00,
  80. RejectEnumValue = 0xc00,
  81. Template = 0xd00,
  82. TemplateInstanceEnum = 0xe00,
  83. Replace = 0xf00,
  84. SimpleMask = 0xf00,
  85. // qtd stuff
  86. AddClass = 0x1100,
  87. // Code snip tags (0x1000, 0x2000, ... , 0xf000)
  88. InjectCode = 0x1000,
  89. InjectCodeInFunction = 0x2000,
  90. CodeSnipMask = 0xf000,
  91. // Function modifier tags (0x010000, 0x020000, ... , 0xf00000)
  92. Access = 0x010000,
  93. Removal = 0x020000,
  94. Rename = 0x040000,
  95. ModifyArgument = 0x080000,
  96. FunctionModifiers = 0xff0000,
  97. StoreResult = 0x110000,
  98. // Argument modifier tags (0x01000000 ... 0xf0000000)
  99. ConversionRule = 0x01000000,
  100. ReplaceType = 0x02000000,
  101. ReplaceDefaultExpression = 0x04000000,
  102. RemoveArgument = 0x08000000,
  103. DefineOwnership = 0x10000000,
  104. RemoveDefaultExpression = 0x20000000,
  105. NoNullPointers = 0x40000000,
  106. ReferenceCount = 0x80000000,
  107. ArgumentModifiers = 0xff000000
  108. };
  109. StackElement(StackElement *p) : entry(0), type(None), parent(p){ }
  110. TypeEntry *entry;
  111. ElementType type;
  112. StackElement *parent;
  113. union {
  114. TemplateInstance *templateInstance;
  115. TemplateEntry *templateEntry;
  116. CustomFunction *customFunction;
  117. } value;
  118. };
  119. class Handler : public QXmlDefaultHandler
  120. {
  121. public:
  122. Handler(TypeDatabase *database, bool generate)
  123. : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
  124. {
  125. m_current_enum = 0;
  126. current = 0;
  127. tagNames["rejection"] = StackElement::Rejection;
  128. tagNames["primitive-type"] = StackElement::PrimitiveTypeEntry;
  129. tagNames["object-type"] = StackElement::ObjectTypeEntry;
  130. tagNames["value-type"] = StackElement::ValueTypeEntry;
  131. tagNames["interface-type"] = StackElement::InterfaceTypeEntry;
  132. tagNames["namespace-type"] = StackElement::NamespaceTypeEntry;
  133. tagNames["enum-type"] = StackElement::EnumTypeEntry;
  134. tagNames["extra-includes"] = StackElement::ExtraIncludes;
  135. tagNames["include"] = StackElement::Include;
  136. tagNames["inject-code"] = StackElement::InjectCode;
  137. tagNames["modify-function"] = StackElement::ModifyFunction;
  138. tagNames["modify-field"] = StackElement::ModifyField;
  139. tagNames["access"] = StackElement::Access;
  140. tagNames["remove"] = StackElement::Removal;
  141. tagNames["rename"] = StackElement::Rename;
  142. tagNames["typesystem"] = StackElement::Root;
  143. tagNames["custom-constructor"] = StackElement::CustomMetaConstructor;
  144. tagNames["custom-destructor"] = StackElement::CustomMetaDestructor;
  145. tagNames["argument-map"] = StackElement::ArgumentMap;
  146. tagNames["suppress-warning"] = StackElement::SuppressedWarning;
  147. tagNames["load-typesystem"] = StackElement::LoadTypesystem;
  148. tagNames["define-ownership"] = StackElement::DefineOwnership;
  149. tagNames["replace-default-expression"] = StackElement::ReplaceDefaultExpression;
  150. tagNames["reject-enum-value"] = StackElement::RejectEnumValue;
  151. tagNames["replace-type"] = StackElement::ReplaceType;
  152. tagNames["conversion-rule"] = StackElement::ConversionRule;
  153. tagNames["modify-argument"] = StackElement::ModifyArgument;
  154. tagNames["remove-argument"] = StackElement::RemoveArgument;
  155. tagNames["remove-default-expression"] = StackElement::RemoveDefaultExpression;
  156. tagNames["template"] = StackElement::Template;
  157. tagNames["insert-template"] = StackElement::TemplateInstanceEnum;
  158. tagNames["replace"] = StackElement::Replace;
  159. tagNames["no-null-pointer"] = StackElement::NoNullPointers;
  160. tagNames["reference-count"] = StackElement::ReferenceCount;
  161. // qtd
  162. tagNames["add-class"] = StackElement::AddClass;
  163. tagNames["store-result"] = StackElement::StoreResult;
  164. }
  165. bool startElement(const QString &namespaceURI, const QString &localName,
  166. const QString &qName, const QXmlAttributes &atts);
  167. bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);
  168. QString errorString() const { return m_error; }
  169. bool error(const QXmlParseException &exception);
  170. bool fatalError(const QXmlParseException &exception);
  171. bool warning(const QXmlParseException &exception);
  172. bool characters(const QString &ch);
  173. private:
  174. void fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
  175. QHash<QString, QString> *acceptedAttributes);
  176. bool importFileElement(const QXmlAttributes &atts);
  177. bool convertBoolean(const QString &, const QString &, bool);
  178. TypeDatabase *m_database;
  179. StackElement* current;
  180. QString m_defaultPackage;
  181. QString m_defaultSuperclass;
  182. QString m_error;
  183. TypeEntry::CodeGeneration m_generate;
  184. EnumTypeEntry *m_current_enum;
  185. CodeSnipList m_code_snips;
  186. FunctionModificationList m_function_mods;
  187. FieldModificationList m_field_mods;
  188. QHash<QString, StackElement::ElementType> tagNames;
  189. };
  190. bool Handler::error(const QXmlParseException &e)
  191. {
  192. qWarning("Error: line=%d, column=%d, message=%s\n",
  193. e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
  194. return false;
  195. }
  196. bool Handler::fatalError(const QXmlParseException &e)
  197. {
  198. qWarning("Fatal error: line=%d, column=%d, message=%s\n",
  199. e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
  200. return false;
  201. }
  202. bool Handler::warning(const QXmlParseException &e)
  203. {
  204. qWarning("Warning: line=%d, column=%d, message=%s\n",
  205. e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
  206. return false;
  207. }
  208. void Handler::fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
  209. QHash<QString, QString> *acceptedAttributes)
  210. {
  211. Q_ASSERT(acceptedAttributes != 0);
  212. for (int i=0; i<atts.length(); ++i) {
  213. QString key = atts.localName(i).toLower();
  214. QString val = atts.value(i);
  215. if (!acceptedAttributes->contains(key)) {
  216. ReportHandler::warning(QString("Unknown attribute for '%1': '%2'").arg(name).arg(key));
  217. } else {
  218. (*acceptedAttributes)[key] = val;
  219. }
  220. }
  221. }
  222. bool Handler::endElement(const QString &, const QString &localName, const QString &)
  223. {
  224. QString tagName = localName.toLower();
  225. if(tagName == "import-file")
  226. return true;
  227. if (!current)
  228. return true;
  229. switch (current->type) {
  230. case StackElement::ObjectTypeEntry:
  231. case StackElement::ValueTypeEntry:
  232. case StackElement::InterfaceTypeEntry:
  233. case StackElement::NamespaceTypeEntry:
  234. {
  235. ComplexTypeEntry *centry = static_cast<ComplexTypeEntry *>(current->entry);
  236. centry->setFunctionModifications(m_function_mods);
  237. centry->setFieldModifications(m_field_mods);
  238. centry->setCodeSnips(m_code_snips);
  239. if (centry->designatedInterface()) {
  240. centry->designatedInterface()->setCodeSnips(m_code_snips);
  241. centry->designatedInterface()->setFunctionModifications(m_function_mods);
  242. }
  243. m_code_snips = CodeSnipList();
  244. m_function_mods = FunctionModificationList();
  245. m_field_mods = FieldModificationList();
  246. }
  247. break;
  248. case StackElement::CustomMetaConstructor:
  249. {
  250. current->entry->setCustomConstructor(*current->value.customFunction);
  251. delete current->value.customFunction;
  252. }
  253. break;
  254. case StackElement::CustomMetaDestructor:
  255. {
  256. current->entry->setCustomDestructor(*current->value.customFunction);
  257. delete current->value.customFunction;
  258. }
  259. break;
  260. case StackElement::EnumTypeEntry:
  261. m_current_enum = 0;
  262. break;
  263. case StackElement::Template:
  264. m_database->addTemplate(current->value.templateEntry);
  265. break;
  266. case StackElement::TemplateInstanceEnum:
  267. if(current->parent->type == StackElement::InjectCode){
  268. m_code_snips.last().addTemplateInstance(current->value.templateInstance);
  269. }else if(current->parent->type == StackElement::Template){
  270. current->parent->value.templateEntry->addTemplateInstance(current->value.templateInstance);
  271. }else if(current->parent->type == StackElement::CustomMetaConstructor || current->parent->type == StackElement::CustomMetaConstructor){
  272. current->parent->value.customFunction->addTemplateInstance(current->value.templateInstance);
  273. }else if(current->parent->type == StackElement::ConversionRule){
  274. m_function_mods.last().argument_mods.last().conversion_rules.last().addTemplateInstance(current->value.templateInstance);
  275. }else if(current->parent->type == StackElement::InjectCodeInFunction){
  276. m_function_mods.last().snips.last().addTemplateInstance(current->value.templateInstance);
  277. }
  278. break;
  279. default:
  280. break;
  281. }
  282. StackElement *child = current;
  283. current=current->parent;
  284. delete(child);
  285. return true;
  286. }
  287. bool Handler::characters(const QString &ch)
  288. {
  289. if(current->type == StackElement::Template){
  290. current->value.templateEntry->addCode(ch);
  291. return true;
  292. }
  293. if (current->type == StackElement::CustomMetaConstructor || current->type == StackElement::CustomMetaDestructor){
  294. current->value.customFunction->addCode(ch);
  295. return true;
  296. }
  297. if (current->type == StackElement::ConversionRule){
  298. m_function_mods.last().argument_mods.last().conversion_rules.last().addCode(ch);
  299. return true;
  300. }
  301. if (current->parent){
  302. if ((current->type & StackElement::CodeSnipMask) != 0) {
  303. switch (current->parent->type) {
  304. case StackElement::Root:
  305. ((TypeSystemTypeEntry *) current->parent->entry)->snips.last().addCode(ch);
  306. break;
  307. case StackElement::ModifyFunction:
  308. m_function_mods.last().snips.last().addCode(ch);
  309. break;
  310. case StackElement::NamespaceTypeEntry:
  311. case StackElement::ObjectTypeEntry:
  312. case StackElement::ValueTypeEntry:
  313. case StackElement::InterfaceTypeEntry:
  314. m_code_snips.last().addCode(ch);
  315. break;
  316. default:
  317. Q_ASSERT(false);
  318. };
  319. return true;
  320. }
  321. }
  322. return true;
  323. }
  324. bool Handler::importFileElement(const QXmlAttributes &atts)
  325. {
  326. QString fileName = atts.value("name");
  327. if(fileName.isEmpty()){
  328. m_error = "Required attribute 'name' missing for include-file tag.";
  329. return false;
  330. }
  331. QFile file(fileName);
  332. if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
  333. file.setFileName(":/trolltech/generator/" + fileName);
  334. if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
  335. m_error = QString("Could not open file: '%1'").arg(fileName);
  336. return false;
  337. }
  338. }
  339. QString quoteFrom = atts.value("quote-after-line");
  340. bool foundFromOk = quoteFrom.isEmpty();
  341. bool from = quoteFrom.isEmpty();
  342. QString quoteTo = atts.value("quote-before-line");
  343. bool foundToOk = quoteTo.isEmpty();
  344. bool to = true;
  345. QTextStream in(&file);
  346. while (!in.atEnd()) {
  347. QString line = in.readLine();
  348. if(from && to && line.contains(quoteTo)) {
  349. to = false;
  350. foundToOk = true;
  351. break;
  352. }
  353. if(from && to)
  354. characters(line + "\n");
  355. if(!from && line.contains(quoteFrom)) {
  356. from = true;
  357. foundFromOk = true;
  358. }
  359. }
  360. if(!foundFromOk || !foundToOk){
  361. QString fromError = QString("Could not find quote-after-line='%1' in file '%2'.").arg(quoteFrom).arg(fileName);
  362. QString toError = QString("Could not find quote-before-line='%1' in file '%2'.").arg(quoteTo).arg(fileName);
  363. if(!foundToOk)
  364. m_error = toError;
  365. if(!foundFromOk)
  366. m_error = fromError;
  367. if(!foundFromOk && !foundToOk)
  368. m_error = fromError + " " + toError;
  369. return false;
  370. }
  371. return true;
  372. }
  373. bool Handler::convertBoolean(const QString &_value, const QString &attributeName, bool defaultValue)
  374. {
  375. QString value = _value.toLower();
  376. if (value == "true" || value == "yes") {
  377. return true;
  378. } else if (value == "false" || value == "no") {
  379. return false;
  380. } else {
  381. QString warn = QString("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.")
  382. .arg(value).arg(attributeName).arg(defaultValue ? "yes" : "no");
  383. ReportHandler::warning(warn);
  384. return defaultValue;
  385. }
  386. }
  387. bool Handler::startElement(const QString &, const QString &n,
  388. const QString &, const QXmlAttributes &atts)
  389. {
  390. QString tagName = n.toLower();
  391. if(tagName == "import-file"){
  392. return importFileElement(atts);
  393. }
  394. StackElement *element = new StackElement(current);
  395. if (!tagNames.contains(tagName)) {
  396. m_error = QString("Unknown tag name: '%1'").arg(tagName);
  397. return false;
  398. }
  399. element->type = tagNames[tagName];
  400. if (element->type & StackElement::TypeEntryMask) {
  401. if (current->type != StackElement::Root) {
  402. m_error = "Nested types not supported";
  403. return false;
  404. }
  405. QHash<QString, QString> attributes;
  406. attributes["name"] = QString();
  407. switch (element->type) {
  408. case StackElement::PrimitiveTypeEntry:
  409. attributes["java-name"] = QString();
  410. attributes["jni-name"] = QString();
  411. attributes["preferred-conversion"] = "yes";
  412. attributes["preferred-java-type"] = "yes";
  413. break;
  414. case StackElement::EnumTypeEntry:
  415. attributes["flags"] = "no";
  416. attributes["upper-bound"] = QString();
  417. attributes["lower-bound"] = QString();
  418. attributes["force-integer"] = "no";
  419. attributes["extensible"] = "no";
  420. break;
  421. case StackElement::ObjectTypeEntry:
  422. case StackElement::ValueTypeEntry:
  423. attributes["force-abstract"] = QString("no");
  424. attributes["deprecated"] = QString("no");
  425. attributes["wrap"] = QString();
  426. // fall throooough
  427. case StackElement::InterfaceTypeEntry:
  428. attributes["default-superclass"] = m_defaultSuperclass;
  429. attributes["polymorphic-id-expression"] = QString();
  430. attributes["delete-in-main-thread"] = QString("no");
  431. // fall through
  432. case StackElement::NamespaceTypeEntry:
  433. attributes["java-name"] = QString();
  434. attributes["package"] = m_defaultPackage;
  435. attributes["expense-cost"] = "1";
  436. attributes["expense-limit"] = "none";
  437. attributes["polymorphic-base"] = QString("no");
  438. attributes["generate"] = QString("yes");
  439. attributes["target-type"] = QString();
  440. attributes["generic-class"] = QString("no");
  441. break;
  442. default:
  443. ; // nada
  444. };
  445. fetchAttributeValues(tagName, atts, &attributes);
  446. QString name = attributes["name"];
  447. // We need to be able to have duplicate primitive type entries, or it's not possible to
  448. // cover all primitive java types (which we need to do in order to support fake
  449. // meta objects)
  450. if (element->type != StackElement::PrimitiveTypeEntry) {
  451. TypeEntry *tmp = m_database->findType(name);
  452. if (tmp != 0) {
  453. ReportHandler::warning(QString("Duplicate type entry: '%1'").arg(name));
  454. }
  455. }
  456. if (name.isEmpty()) {
  457. m_error = "no 'name' attribute specified";
  458. return false;
  459. }
  460. switch (element->type) {
  461. case StackElement::PrimitiveTypeEntry:
  462. {
  463. QString java_name = attributes["java-name"];
  464. QString jni_name = attributes["jni-name"];
  465. QString preferred_conversion = attributes["preferred-conversion"].toLower();
  466. QString preferred_java_type = attributes["preferred-java-type"].toLower();
  467. if (java_name.isEmpty())
  468. java_name = name;
  469. if (jni_name.isEmpty())
  470. jni_name = name;
  471. PrimitiveTypeEntry *type = new PrimitiveTypeEntry(name);
  472. type->setCodeGeneration(m_generate);
  473. type->setTargetLangName(java_name);
  474. type->setJniName(jni_name);
  475. type->setPreferredConversion(convertBoolean(preferred_conversion, "preferred-conversion", true));
  476. type->setPreferredTargetLangType(convertBoolean(preferred_java_type, "preferred-java-type", true));
  477. element->entry = type;
  478. }
  479. break;
  480. case StackElement::EnumTypeEntry: {
  481. QStringList names = name.split(QLatin1String("::"));
  482. if (names.size() == 1) {
  483. m_current_enum = new EnumTypeEntry(QString(), name);
  484. }
  485. else
  486. m_current_enum =
  487. new EnumTypeEntry(QStringList(names.mid(0, names.size() - 1)).join("::"),
  488. names.last());
  489. element->entry = m_current_enum;
  490. m_current_enum->setCodeGeneration(m_generate);
  491. m_current_enum->setTargetLangPackage(m_defaultPackage);
  492. m_current_enum->setUpperBound(attributes["upper-bound"]);
  493. m_current_enum->setLowerBound(attributes["lower-bound"]);
  494. m_current_enum->setForceInteger(convertBoolean(attributes["force-integer"], "force-integer", false));
  495. m_current_enum->setExtensible(convertBoolean(attributes["extensible"], "extensible", false));
  496. // put in the flags parallel...
  497. if (!attributes["flags"].isEmpty() && attributes["flags"].toLower() != "no") {
  498. FlagsTypeEntry *ftype = new FlagsTypeEntry("QFlags<" + name + ">");
  499. ftype->setOriginator(m_current_enum);
  500. ftype->setOriginalName(attributes["flags"]);
  501. ftype->setCodeGeneration(m_generate);
  502. QString n = ftype->originalName();
  503. QStringList lst = n.split("::");
  504. if (QStringList(lst.mid(0, lst.size() - 1)).join("::") != m_current_enum->javaQualifier()) {
  505. ReportHandler::warning(QString("enum %1 and flags %2 differ in qualifiers")
  506. .arg(m_current_enum->javaQualifier())
  507. .arg(lst.at(0)));
  508. }
  509. ftype->setFlagsName(lst.last());
  510. m_current_enum->setFlags(ftype);
  511. m_database->addFlagsType(ftype);
  512. m_database->addType(ftype);
  513. }
  514. }
  515. break;
  516. case StackElement::InterfaceTypeEntry:
  517. {
  518. ObjectTypeEntry *otype = new ObjectTypeEntry(name);
  519. QString javaName = attributes["java-name"];
  520. if (javaName.isEmpty())
  521. javaName = name;
  522. InterfaceTypeEntry *itype =
  523. new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(javaName));
  524. if (!convertBoolean(attributes["generate"], "generate", true))
  525. itype->setCodeGeneration(TypeEntry::GenerateForSubclass);
  526. else
  527. itype->setCodeGeneration(m_generate);
  528. otype->setDesignatedInterface(itype);
  529. itype->setOrigin(otype);
  530. element->entry = otype;
  531. }
  532. // fall through
  533. case StackElement::NamespaceTypeEntry:
  534. if (element->entry == 0) {
  535. element->entry = new NamespaceTypeEntry(name);
  536. }
  537. // fall through
  538. case StackElement::ObjectTypeEntry:
  539. if (element->entry == 0) {
  540. element->entry = new ObjectTypeEntry(name);
  541. }
  542. // fall through
  543. case StackElement::ValueTypeEntry:
  544. {
  545. if (element->entry == 0) {
  546. if(name == "QVariant")
  547. element->entry = new VariantTypeEntry(name);
  548. else
  549. element->entry = new ValueTypeEntry(name);
  550. }
  551. ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
  552. ctype->setTargetLangPackage(attributes["package"]);
  553. ctype->setDefaultSuperclass(attributes["default-superclass"]);
  554. ctype->setGenericClass(convertBoolean(attributes["generic-class"], "generic-class", false));
  555. // qtd
  556. QString wrap = attributes["wrap"];
  557. ctype->setStructInD(wrap == "struct" ? true : false);
  558. //
  559. if (!convertBoolean(attributes["generate"], "generate", true))
  560. element->entry->setCodeGeneration(TypeEntry::GenerateForSubclass);
  561. else
  562. element->entry->setCodeGeneration(m_generate);
  563. QString javaName = attributes["java-name"];
  564. if (!javaName.isEmpty())
  565. ctype->setTargetLangName(javaName);
  566. // The expense policy
  567. QString limit = attributes["expense-limit"];
  568. if (!limit.isEmpty() && limit != "none") {
  569. ExpensePolicy ep;
  570. ep.limit = limit.toInt();
  571. ep.cost = attributes["expense-cost"];
  572. ctype->setExpensePolicy(ep);
  573. }
  574. ctype->setIsPolymorphicBase(convertBoolean(attributes["polymorphic-base"], "polymorphic-base", false));
  575. ctype->setPolymorphicIdValue(attributes["polymorphic-id-expression"]);
  576. if (element->type == StackElement::ObjectTypeEntry || element->type == StackElement::ValueTypeEntry) {
  577. if (convertBoolean(attributes["force-abstract"], "force-abstract", false))
  578. ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract);
  579. if (convertBoolean(attributes["deprecated"], "deprecated", false))
  580. ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
  581. }
  582. if (element->type == StackElement::InterfaceTypeEntry ||
  583. element->type == StackElement::ValueTypeEntry ||
  584. element->type == StackElement::ObjectTypeEntry) {
  585. if (convertBoolean(attributes["delete-in-main-thread"], "delete-in-main-thread", false))
  586. ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DeleteInMainThread);
  587. }
  588. QString targetType = attributes["target-type"];
  589. if (!targetType.isEmpty() && element->entry->isComplex())
  590. static_cast<ComplexTypeEntry *>(element->entry)->setTargetType(targetType);
  591. // ctype->setInclude(Include(Include::IncludePath, ctype->name()));
  592. ctype = ctype->designatedInterface();
  593. if (ctype != 0)
  594. ctype->setTargetLangPackage(attributes["package"]);
  595. }
  596. break;
  597. default:
  598. Q_ASSERT(false);
  599. };
  600. if (element->entry)
  601. m_database->addType(element->entry);
  602. else
  603. ReportHandler::warning(QString("Type: %1 was rejected by typesystem").arg(name));
  604. } else if (element->type != StackElement::None) {
  605. bool topLevel = element->type == StackElement::Root
  606. || element->type == StackElement::SuppressedWarning
  607. || element->type == StackElement::Rejection
  608. || element->type == StackElement::LoadTypesystem
  609. || element->type == StackElement::InjectCode
  610. || element->type == StackElement::Template;
  611. if (!topLevel && current->type == StackElement::Root) {
  612. m_error = QString("Tag requires parent: '%1'").arg(tagName);
  613. return false;
  614. }
  615. StackElement topElement = current==0 ? StackElement(0) : *current;
  616. element->entry = topElement.entry;
  617. QHash<QString, QString> attributes;
  618. switch (element->type) {
  619. case StackElement::Root:
  620. attributes["package"] = QString();
  621. attributes["default-superclass"] = QString();
  622. break;
  623. case StackElement::LoadTypesystem:
  624. attributes["name"] = QString();
  625. attributes["generate"] = "yes";
  626. break;
  627. case StackElement::NoNullPointers:
  628. attributes["default-value"] = QString();
  629. break;
  630. case StackElement::SuppressedWarning:
  631. attributes["text"] = QString();
  632. break;
  633. case StackElement::ReplaceDefaultExpression:
  634. attributes["with"] = QString();
  635. break;
  636. case StackElement::DefineOwnership:
  637. attributes["class"] = "java";
  638. attributes["owner"] = "";
  639. break;
  640. case StackElement::ModifyFunction:
  641. attributes["signature"] = QString();
  642. attributes["access"] = QString();
  643. attributes["remove"] = QString();
  644. attributes["rename"] = QString();
  645. attributes["deprecated"] = QString("no");
  646. attributes["associated-to"] = QString();
  647. attributes["virtual-slot"] = QString("no");
  648. break;
  649. case StackElement::ModifyArgument:
  650. attributes["index"] = QString();
  651. attributes["replace-value"] = QString();
  652. attributes["invalidate-after-use"] = QString("no");
  653. break;
  654. case StackElement::ModifyField:
  655. attributes["name"] = QString();
  656. attributes["write"] = "true";
  657. attributes["read"] = "true";
  658. break;
  659. case StackElement::Access:
  660. attributes["modifier"] = QString();
  661. break;
  662. case StackElement::Include:
  663. attributes["file-name"] = QString();
  664. attributes["location"] = QString();
  665. break;
  666. case StackElement::CustomMetaConstructor:
  667. attributes["name"] = topElement.entry->name().toLower() + "_create";
  668. attributes["param-name"] = "copy";
  669. break;
  670. case StackElement::CustomMetaDestructor:
  671. attributes["name"] = topElement.entry->name().toLower() + "_delete";
  672. attributes["param-name"] = "copy";
  673. break;
  674. case StackElement::ReplaceType:
  675. attributes["modified-type"] = QString();
  676. break;
  677. case StackElement::InjectCode:
  678. attributes["class"] = "java";
  679. attributes["position"] = "beginning";
  680. break;
  681. case StackElement::ConversionRule:
  682. attributes["class"] = "";
  683. break;
  684. case StackElement::RejectEnumValue:
  685. attributes["name"] = "";
  686. break;
  687. case StackElement::ArgumentMap:
  688. attributes["index"] = "1";
  689. attributes["meta-name"] = QString();
  690. break;
  691. case StackElement::Rename:
  692. attributes["to"] = QString();
  693. break;
  694. case StackElement::Rejection:
  695. attributes["class"] = "*";
  696. attributes["function-name"] = "*";
  697. attributes["field-name"] = "*";
  698. attributes["enum-name"] = "*";
  699. break;
  700. case StackElement::Removal:
  701. attributes["class"] = "all";
  702. break;
  703. case StackElement::Template:
  704. attributes["name"] = QString();
  705. break;
  706. case StackElement::TemplateInstanceEnum:
  707. attributes["name"] = QString();
  708. break;
  709. case StackElement::Replace:
  710. attributes["from"] = QString();
  711. attributes["to"] = QString();
  712. break;
  713. case StackElement::ReferenceCount:
  714. attributes["action"] = QString();
  715. attributes["variable-name"] = QString();
  716. attributes["thread-safe"] = QString("no");
  717. attributes["declare-variable"] = QString();
  718. attributes["access"] = QString("private");
  719. attributes["conditional"] = QString("");
  720. break;
  721. // qtd
  722. case StackElement::AddClass:
  723. attributes["name"] = QString();
  724. break;
  725. default:
  726. ; // nada
  727. };
  728. if (attributes.count() > 0)
  729. fetchAttributeValues(tagName, atts, &attributes);
  730. switch (element->type) {
  731. case StackElement::Root:
  732. m_defaultPackage = attributes["package"];
  733. m_defaultSuperclass = attributes["default-superclass"];
  734. element->type = StackElement::Root;
  735. element->entry = new TypeSystemTypeEntry(m_defaultPackage);
  736. TypeDatabase::instance()->addType(element->entry);
  737. break;
  738. case StackElement::LoadTypesystem:
  739. {
  740. QString name = attributes["name"];
  741. if (name.isEmpty()) {
  742. m_error = "No typesystem name specified";
  743. return false;
  744. }
  745. if (!m_database->parseFile(name, convertBoolean(attributes["generate"], "generate", true))) {
  746. m_error = QString("Failed to parse: '%1'").arg(name);
  747. return false;
  748. }
  749. }
  750. break;
  751. case StackElement::RejectEnumValue: {
  752. if (!m_current_enum) {
  753. m_error = "<reject-enum-value> node must be used inside a <enum-type> node";
  754. return false;
  755. }
  756. QString name = attributes["name"];
  757. bool added = false;
  758. if (!name.isEmpty()) {
  759. added = true;
  760. m_current_enum->addEnumValueRejection(name);
  761. }
  762. } break;
  763. case StackElement::ReplaceType:
  764. {
  765. if (topElement.type != StackElement::ModifyArgument) {
  766. m_error = "Type replacement can only be specified for argument modifications";
  767. return false;
  768. }
  769. if (attributes["modified-type"].isEmpty()) {
  770. m_error = "Type replacement requires 'modified-type' attribute";
  771. return false;
  772. }
  773. m_function_mods.last().argument_mods.last().modified_type = attributes["modified-type"];
  774. }
  775. break;
  776. case StackElement::ConversionRule:
  777. {
  778. if (topElement.type != StackElement::ModifyArgument) {
  779. m_error = "Conversion rules can only be specified for argument modification";
  780. return false;
  781. }
  782. static QHash<QString, TypeSystem::Language> languageNames;
  783. if (languageNames.isEmpty()) {
  784. languageNames["native"] = TypeSystem::NativeCode;
  785. languageNames["shell"] = TypeSystem::ShellCode;
  786. }
  787. CodeSnip snip;
  788. QString languageAttribute = attributes["class"].toLower();
  789. TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
  790. if (lang == TypeSystem::NoLanguage) {
  791. m_error = QString("unsupported class attribute: '%1'").arg(languageAttribute);
  792. return false;
  793. }
  794. snip.language = lang;
  795. m_function_mods.last().argument_mods.last().conversion_rules.append(snip);
  796. }
  797. break;
  798. case StackElement::StoreResult:
  799. {
  800. if (topElement.type != StackElement::ModifyFunction) {
  801. m_error = QString::fromLatin1("result storage requires function"
  802. " modification as parent, was %1")
  803. .arg(topElement.type, 0, 16);
  804. return false;
  805. }
  806. m_function_mods.last().store_result = true;
  807. }
  808. break;
  809. case StackElement::ModifyArgument:
  810. {
  811. if (topElement.type != StackElement::ModifyFunction) {
  812. m_error = QString::fromLatin1("argument modification requires function"
  813. " modification as parent, was %1")
  814. .arg(topElement.type, 0, 16);
  815. return false;
  816. }
  817. QString index = attributes["index"];
  818. if (index == "return")
  819. index = "0";
  820. else if (index == "this")
  821. index = "-1";
  822. bool ok = false;
  823. int idx = index.toInt(&ok);
  824. if (!ok) {
  825. m_error = QString("Cannot convert '%1' to integer").arg(index);
  826. return false;
  827. }
  828. QString replace_value = attributes["replace-value"];
  829. if (!replace_value.isEmpty() && idx != 0) {
  830. m_error = QString("replace-value is only supported for return values (index=0).");
  831. return false;
  832. }
  833. ArgumentModification argumentModification = ArgumentModification(idx);
  834. argumentModification.replace_value = replace_value;
  835. argumentModification.reset_after_use = convertBoolean(attributes["invalidate-after-use"], "invalidate-after-use", false);
  836. m_function_mods.last().argument_mods.append(argumentModification);
  837. }
  838. break;
  839. case StackElement::NoNullPointers:
  840. {
  841. if (topElement.type != StackElement::ModifyArgument) {
  842. m_error = "no-null-pointer requires argument modification as parent";
  843. return false;
  844. }
  845. m_function_mods.last().argument_mods.last().no_null_pointers = true;
  846. if (m_function_mods.last().argument_mods.last().index == 0) {
  847. m_function_mods.last().argument_mods.last().null_pointer_default_value = attributes["default-value"];
  848. } else if (!attributes["default-value"].isEmpty()) {
  849. ReportHandler::warning("default values for null pointer guards are only effective for return values");
  850. }
  851. }
  852. break;
  853. case StackElement::DefineOwnership:
  854. {
  855. if (topElement.type != StackElement::ModifyArgument) {
  856. m_error = "define-ownership requires argument modification as parent";
  857. return false;
  858. }
  859. static QHash<QString, TypeSystem::Language> languageNames;
  860. if (languageNames.isEmpty()) {
  861. languageNames["java"] = TypeSystem::TargetLangCode;
  862. languageNames["shell"] = TypeSystem::ShellCode;
  863. }
  864. QString classAttribute = attributes["class"].toLower();
  865. TypeSystem::Language lang = languageNames.value(classAttribute, TypeSystem::NoLanguage);
  866. if (lang == TypeSystem::NoLanguage) {
  867. m_error = QString("unsupported class attribute: '%1'").arg(classAttribute);
  868. return false;
  869. }
  870. static QHash<QString, TypeSystem::Ownership> ownershipNames;
  871. if (ownershipNames.isEmpty()) {
  872. ownershipNames["java"] = TypeSystem::TargetLangOwnership;
  873. ownershipNames["c++"] = TypeSystem::CppOwnership;
  874. ownershipNames["default"] = TypeSystem::DefaultOwnership;
  875. }
  876. QString ownershipAttribute = attributes["owner"].toLower();
  877. TypeSystem::Ownership owner = ownershipNames.value(ownershipAttribute, TypeSystem::InvalidOwnership);
  878. if (owner == TypeSystem::InvalidOwnership) {
  879. m_error = QString("unsupported owner attribute: '%1'").arg(ownershipAttribute);
  880. return false;
  881. }
  882. m_function_mods.last().argument_mods.last().ownerships[lang] = owner;
  883. }
  884. break;
  885. case StackElement::SuppressedWarning:
  886. if (attributes["text"].isEmpty())
  887. ReportHandler::warning("Suppressed warning with no text specified");
  888. else
  889. m_database->addSuppressedWarning(attributes["text"]);
  890. break;
  891. case StackElement::ArgumentMap:
  892. {
  893. if (!(topElement.type & StackElement::CodeSnipMask)) {
  894. m_error = "Argument maps requires code injection as parent";
  895. return false;
  896. }
  897. bool ok;
  898. int pos = attributes["index"].toInt(&ok);
  899. if (!ok) {
  900. m_error = QString("Can't convert position '%1' to integer")
  901. .arg(attributes["position"]);
  902. return false;
  903. }
  904. if (pos <= 0) {
  905. m_error = QString("Argument position %1 must be a positive number").arg(pos);
  906. return false;
  907. }
  908. QString meta_name = attributes["meta-name"];
  909. if (meta_name.isEmpty()) {
  910. ReportHandler::warning("Empty meta name in argument map");
  911. }
  912. if (topElement.type == StackElement::InjectCodeInFunction) {
  913. m_function_mods.last().snips.last().argumentMap[pos] = meta_name;
  914. } else {
  915. ReportHandler::warning("Argument maps are only useful for injection of code "
  916. "into functions.");
  917. }
  918. }
  919. break;
  920. case StackElement::Removal:
  921. {
  922. if (topElement.type != StackElement::ModifyFunction) {
  923. m_error = "Function modification parent required";
  924. return false;
  925. }
  926. static QHash<QString, TypeSystem::Language> languageNames;
  927. if (languageNames.isEmpty()) {
  928. languageNames["java"] = TypeSystem::TargetLangAndNativeCode;
  929. languageNames["all"] = TypeSystem::All;
  930. }
  931. QString languageAttribute = attributes["class"].toLower();
  932. TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
  933. if (lang == TypeSystem::NoLanguage) {
  934. m_error = QString("unsupported class attribute: '%1'").arg(languageAttribute);
  935. return false;
  936. }
  937. m_function_mods.last().removal = lang;
  938. }
  939. break;
  940. case StackElement::Rename:
  941. case StackElement::Access:
  942. {
  943. if (topElement.type != StackElement::ModifyField
  944. && topElement.type != StackElement::ModifyFunction) {
  945. m_error = "Function or field modification parent required";
  946. return false;
  947. }
  948. Modification *mod = 0;
  949. if (topElement.type == StackElement::ModifyFunction)
  950. mod = &m_function_mods.last();
  951. else
  952. mod = &m_field_mods.last();
  953. QString modifier;
  954. if (element->type == StackElement::Rename) {
  955. modifier = "rename";
  956. QString renamed_to = attributes["to"];
  957. if (renamed_to.isEmpty()) {
  958. m_error = "Rename modifier requires 'to' attribute";
  959. return false;
  960. }
  961. if (topElement.type == StackElement::ModifyFunction)
  962. mod->setRenamedTo(renamed_to);
  963. else
  964. mod->setRenamedTo(renamed_to);
  965. } else {
  966. modifier = attributes["modifier"].toLower();
  967. }
  968. if (modifier.isEmpty()) {
  969. m_error = "No access modification specified";
  970. return false;
  971. }
  972. static QHash<QString, FunctionModification::Modifiers> modifierNames;
  973. if (modifierNames.isEmpty()) {
  974. modifierNames["private"] = Modification::Private;
  975. modifierNames["public"] = Modification::Public;
  976. modifierNames["protected"] = Modification::Protected;
  977. modifierNames["friendly"] = Modification::Friendly;
  978. modifierNames["rename"] = Modification::Rename;
  979. modifierNames["final"] = Modification::Final;
  980. modifierNames["non-final"] = Modification::NonFinal;
  981. }
  982. if (!modifierNames.contains(modifier)) {
  983. m_error = QString("Unknown access modifier: '%1'").arg(modifier);
  984. return false;
  985. }
  986. mod->modifiers |= modifierNames[modifier];
  987. }
  988. break;
  989. case StackElement::RemoveArgument:
  990. if (topElement.type != StackElement::ModifyArgument) {
  991. m_error = "Removing argument requires argument modification as parent";
  992. return false;
  993. }
  994. m_function_mods.last().argument_mods.last().removed = true;
  995. break;
  996. case StackElement::ModifyField:
  997. {
  998. QString name = attributes["name"];
  999. if (name.isEmpty())
  1000. break;
  1001. FieldModification fm;
  1002. fm.name = name;
  1003. fm.modifiers = 0;
  1004. QString read = attributes["read"];
  1005. QString write = attributes["write"];
  1006. if (read == "true") fm.modifiers |= FieldModification::Readable;
  1007. if (write == "true") fm.modifiers |= FieldModification::Writable;
  1008. m_field_mods << fm;
  1009. }
  1010. break;
  1011. case StackElement::AddClass: // qtd - fully :)
  1012. {
  1013. if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
  1014. m_error = QString::fromLatin1("Add class to module requires complex type as parent"
  1015. ", was=%1").arg(topElement.type, 0, 16);
  1016. return false;
  1017. }
  1018. QString class_name = attributes["name"];
  1019. ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(topElement.entry);
  1020. if(!class_name.isEmpty())
  1021. ctype->includedClasses << class_name;
  1022. }
  1023. break;
  1024. case StackElement::ModifyFunction:
  1025. {
  1026. if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
  1027. m_error = QString::fromLatin1("Modify function requires complex type as parent"
  1028. ", was=%1").arg(topElement.type, 0, 16);
  1029. return false;
  1030. }
  1031. QString signature = attributes["signature"];
  1032. signature = QMetaObject::normalizedSignature(signature.toLocal8Bit().constData());
  1033. if (signature.isEmpty()) {
  1034. m_error = "No signature for modified function";
  1035. return false;
  1036. }
  1037. FunctionModification mod;
  1038. mod.signature = signature;
  1039. QString access = attributes["access"].toLower();
  1040. if (!access.isEmpty()) {
  1041. if (access == QLatin1String("private"))
  1042. mod.modifiers |= Modification::Private;
  1043. else if (access == QLatin1String("protected"))
  1044. mod.modifiers |= Modification::Protected;
  1045. else if (access == QLatin1String("public"))
  1046. mod.modifiers |= Modification::Public;
  1047. else if (access == QLatin1String("final"))
  1048. mod.modifiers |= Modification::Final;
  1049. else if (access == QLatin1String("non-final"))
  1050. mod.modifiers |= Modification::NonFinal;
  1051. else {
  1052. m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
  1053. return false;
  1054. }
  1055. }
  1056. if (convertBoolean(attributes["deprecated"], "deprecated", false)) {
  1057. mod.modifiers |= Modification::Deprecated;
  1058. }
  1059. QString remove = attributes["remove"].toLower();
  1060. if (!remove.isEmpty()) {
  1061. if (remove == QLatin1String("all"))
  1062. mod.removal = TypeSystem::All;
  1063. else if (remove == QLatin1String("java"))
  1064. mod.removal = TypeSystem::TargetLangAndNativeCode;
  1065. else {
  1066. m_error = QString::fromLatin1("Bad removal type '%1'").arg(remove);
  1067. return false;
  1068. }
  1069. }
  1070. QString rename = attributes["rename"];
  1071. if (!rename.isEmpty()) {
  1072. mod.renamedToName = rename;
  1073. mod.modifiers |= Modification::Rename;
  1074. }
  1075. QString association = attributes["associated-to"];
  1076. if (!association.isEmpty())
  1077. mod.association = association;
  1078. mod.modifiers |= (convertBoolean(attri

Large files files are truncated, but you can click here to view the full file