cstlcompiler.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. Copyright 2017 Herik Lima de Castro and Marcelo Medeiros Eler
  3. Distributed under MIT license, or public domain if desired and
  4. recognized in your jurisdiction.
  5. See file LICENSE for detail.
  6. */
  7. #include "cstlcompiler.h"
  8. #include "constants.h"
  9. #include "cstlcompilerattributes.h"
  10. #include "cstlcompilerfor.h"
  11. #include "cstlcompilerif.h"
  12. #include "cstlcompilerimport.h"
  13. #include "cstlcompilerobject.h"
  14. #include <utility>
  15. CWF_BEGIN_NAMESPACE
  16. CSTLCompiler::CSTLCompiler(const QByteArray &str,
  17. QString path,
  18. QMap<QString, QObject *> &objects,
  19. bool isStrFileName)
  20. : str(str)
  21. , path(std::move(path))
  22. , objects(objects)
  23. , isStrFileName(isStrFileName)
  24. {
  25. if (isStrFileName) {
  26. isView = str.toLower().endsWith(".view");
  27. }
  28. }
  29. QByteArray CSTLCompiler::openFile(QXmlStreamReader &xml)
  30. {
  31. if (isStrFileName) {
  32. QFile file(str);
  33. if (!file.open(QIODevice::ReadOnly)) {
  34. return "<html><body>" + file.errorString().toUtf8() + "</body></html>";
  35. }
  36. QByteArray content(file.readAll());
  37. file.close();
  38. if (isView) {
  39. xml.addData(content);
  40. } else {
  41. return content;
  42. }
  43. } else {
  44. xml.addData(str);
  45. }
  46. if (xml.hasError()) {
  47. return "<html><body>XML ERROR: " + xml.errorString().toUtf8() + "</body></html>";
  48. }
  49. return "";
  50. }
  51. QByteArray CSTLCompiler::processOutTag(QMap<QString, QString> &attr)
  52. {
  53. int size = attr.size();
  54. if (size < 1) {
  55. return "";
  56. }
  57. if (size > 1) {
  58. return "***ERROR - OUT TAG DOES NOT HAS MORE THAN PROPERTY***";
  59. }
  60. return CSTLCompilerAttributes(objects).buildAttributes(attr, false).toUtf8();
  61. }
  62. QByteArray CSTLCompiler::getBody(QXmlStreamReader &xml, const QString &tagName)
  63. {
  64. QByteArray name, text, content(CSTL::TAG::BEGIN);
  65. QByteArray att;
  66. CSTLCompilerAttributes compilerAttributes(objects);
  67. QMap<QString, QString> attributes;
  68. QMap<QString, QString>::iterator it;
  69. int start = 0, end = 0;
  70. xml.readNext();
  71. while (!xml.atEnd()) {
  72. name = xml.name().toUtf8().toLower();
  73. text = xml.text().toUtf8();
  74. if (xml.isStartElement()) {
  75. if (name == tagName) {
  76. ++start;
  77. }
  78. attributes = compilerAttributes.getAttributes(xml.attributes());
  79. for (it = attributes.begin(); it != attributes.end(); ++it) {
  80. att += " " + it.key().toUtf8() + "=\"" + it.value().toUtf8() + "\"";
  81. }
  82. content += "<" + name + att + ">" + text;
  83. attributes.clear();
  84. att.clear();
  85. } else if (xml.isEndElement() && name == tagName) {
  86. if (end < start) {
  87. content += text + "</" + name + ">";
  88. }
  89. ++end;
  90. if (end >= start) {
  91. break;
  92. }
  93. } else if (xml.isEndElement()) {
  94. content += text + "</" + name + ">";
  95. } else {
  96. content += text;
  97. }
  98. xml.readNext();
  99. }
  100. return content + CSTL::TAG::END;
  101. }
  102. void CSTLCompiler::processText(QString &text)
  103. {
  104. QString copy(std::move(text));
  105. CSTLCompilerAttributes(objects).compile(copy, text);
  106. }
  107. QByteArray CSTLCompiler::processForTag(QXmlStreamReader &xml)
  108. {
  109. QByteArray htmlOut;
  110. CSTLCompilerFor forAttributes(xml.attributes());
  111. CSTLCompilerAttributes compilerAttributes(objects);
  112. if (forAttributes.attributes.contains(CSTL::TAG::PROPERTY::ERROR)) {
  113. getBody(xml, CSTL::TAG::FOR);
  114. htmlOut = forAttributes.attributes[CSTL::TAG::PROPERTY::ERROR].toUtf8();
  115. } else {
  116. QString items(forAttributes.attributes[CSTL::TAG::PROPERTY::FOR::ITEMS]);
  117. items.replace("#{", "").replace("}", "");
  118. if (objects.contains(items)) {
  119. auto *object = static_cast<QObject *>(objects[items]);
  120. QString type(object->metaObject()->className());
  121. if (!items.isEmpty()) {
  122. if (type != CSTL::SUPPORTED_TYPES::CWF_QLISTOBJECT) {
  123. htmlOut = "***ERROR - " + type.toUtf8() + " ISN'T A CWF::QListObject***";
  124. getBody(xml, CSTL::TAG::FOR);
  125. } else {
  126. auto *qListObject = dynamic_cast<QListObject *>(object);
  127. QString ret(getBody(xml, CSTL::TAG::FOR));
  128. QString var(forAttributes.attributes[CSTL::TAG::PROPERTY::VAR]);
  129. var.replace("#{", "").replace("}", "");
  130. for (int iL = 0; iL < qListObject->size(); ++iL) {
  131. objects.insert(var, qListObject->operator[](iL));
  132. QXmlStreamReader forBody(ret);
  133. htmlOut += processXml(forBody);
  134. objects.remove(var);
  135. }
  136. }
  137. }
  138. } else {
  139. int from = forAttributes.attributes[CSTL::TAG::PROPERTY::FOR::FROM].toInt();
  140. int to = forAttributes.attributes[CSTL::TAG::PROPERTY::FOR::TO].toInt();
  141. int increment = forAttributes.attributes[CSTL::TAG::PROPERTY::FOR::INCREMENT].toInt();
  142. QString tagBody(getBody(xml, CSTL::TAG::FOR));
  143. QString &var = forAttributes.attributes[CSTL::TAG::PROPERTY::VAR];
  144. for (int i = from; i <= to; i += increment) {
  145. QString copy(tagBody);
  146. CSTLCompilerObject obj;
  147. obj.setValue(QString::number(i));
  148. objects.insert(var, &obj);
  149. copy.replace(XML::HEADER, "");
  150. QString outPutText;
  151. compilerAttributes.compile(copy, outPutText);
  152. copy = "<out>" + outPutText + "</out>";
  153. copy = XML::HEADER + copy;
  154. QXmlStreamReader forBody(copy);
  155. htmlOut += processXml(forBody);
  156. objects.remove(var);
  157. }
  158. }
  159. }
  160. return htmlOut;
  161. }
  162. QByteArray CSTLCompiler::processIfTag(QXmlStreamReader &xml)
  163. {
  164. QByteArray htmlOut;
  165. CSTLCompilerIf ifAttributes(xml.attributes());
  166. if (ifAttributes.relationalOperator == RelationalOperator::ERROR) {
  167. getBody(xml, CSTL::TAG::IF);
  168. htmlOut = ifAttributes.attributes[CSTL::TAG::PROPERTY::ERROR].toUtf8();
  169. } else {
  170. QString var(ifAttributes.attributes[CSTL::TAG::PROPERTY::VAR]),
  171. condition(ifAttributes.attributes[CSTL::TAG::PROPERTY::CONDITION]);
  172. CSTLCompilerObject conditionObj, varObj;
  173. bool removeVar = false, removeCondition = false;
  174. if (!objects.contains(var)) {
  175. removeVar = true;
  176. varObj.setValue(var);
  177. objects.insert(var, &varObj);
  178. }
  179. if (!objects.contains(condition)) {
  180. removeCondition = true;
  181. conditionObj.setValue(condition);
  182. objects.insert(condition, &conditionObj);
  183. }
  184. CSTLCompilerAttributes compilerAttributes(objects);
  185. QString tagBody(getBody(xml, CSTL::TAG::IF));
  186. compilerAttributes.compileAttributes(ifAttributes.attributes);
  187. bool isTrue = false;
  188. if (ifAttributes.relationalOperator == RelationalOperator::EQUAL) {
  189. isTrue = ifAttributes.attributes[CSTL::TAG::PROPERTY::VAR]
  190. == ifAttributes.attributes[CSTL::TAG::PROPERTY::CONDITION];
  191. } else if (ifAttributes.relationalOperator == RelationalOperator::DIFFERENT) {
  192. isTrue = ifAttributes.attributes[CSTL::TAG::PROPERTY::VAR]
  193. != ifAttributes.attributes[CSTL::TAG::PROPERTY::CONDITION];
  194. } else if (ifAttributes.relationalOperator == RelationalOperator::GREATER) {
  195. if (ifAttributes.isNumber) {
  196. isTrue = ifAttributes.attributes[CSTL::TAG::PROPERTY::VAR].toDouble()
  197. > ifAttributes.attributes[CSTL::TAG::PROPERTY::CONDITION].toDouble();
  198. } else {
  199. isTrue = ifAttributes.attributes[CSTL::TAG::PROPERTY::VAR]
  200. > ifAttributes.attributes[CSTL::TAG::PROPERTY::CONDITION];
  201. }
  202. } else if (ifAttributes.relationalOperator == RelationalOperator::GREATER_EQUAL) {
  203. if (ifAttributes.isNumber) {
  204. isTrue = ifAttributes.attributes[CSTL::TAG::PROPERTY::VAR].toDouble()
  205. >= ifAttributes.attributes[CSTL::TAG::PROPERTY::CONDITION].toDouble();
  206. } else {
  207. isTrue = ifAttributes.attributes[CSTL::TAG::PROPERTY::VAR]
  208. >= ifAttributes.attributes[CSTL::TAG::PROPERTY::CONDITION];
  209. }
  210. } else if (ifAttributes.relationalOperator == RelationalOperator::LESS) {
  211. if (ifAttributes.isNumber) {
  212. isTrue = ifAttributes.attributes[CSTL::TAG::PROPERTY::VAR].toDouble()
  213. < ifAttributes.attributes[CSTL::TAG::PROPERTY::CONDITION].toDouble();
  214. } else {
  215. isTrue = ifAttributes.attributes[CSTL::TAG::PROPERTY::VAR]
  216. < ifAttributes.attributes[CSTL::TAG::PROPERTY::CONDITION];
  217. }
  218. } else if (ifAttributes.relationalOperator == RelationalOperator::LESS_EQUAL) {
  219. if (ifAttributes.isNumber) {
  220. isTrue = ifAttributes.attributes[CSTL::TAG::PROPERTY::VAR].toDouble()
  221. <= ifAttributes.attributes[CSTL::TAG::PROPERTY::CONDITION].toDouble();
  222. } else {
  223. isTrue = ifAttributes.attributes[CSTL::TAG::PROPERTY::VAR]
  224. <= ifAttributes.attributes[CSTL::TAG::PROPERTY::CONDITION];
  225. }
  226. }
  227. if (isTrue) {
  228. if (!tagBody.contains("<") || !tagBody.contains("</")) {
  229. tagBody.replace(XML::HEADER, "");
  230. QString outPutText;
  231. compilerAttributes.compile(tagBody, outPutText);
  232. tagBody = XML::HEADER + "<out>" + outPutText + "</out>";
  233. }
  234. QXmlStreamReader forBody(tagBody);
  235. htmlOut += processXml(forBody);
  236. }
  237. if (removeVar) {
  238. objects.remove(var);
  239. }
  240. if (removeCondition) {
  241. objects.remove(condition);
  242. }
  243. }
  244. return htmlOut;
  245. }
  246. QByteArray CSTLCompiler::processXml(QXmlStreamReader &xml)
  247. {
  248. QByteArray htmlOut;
  249. while (!xml.atEnd()) {
  250. CSTLCompilerAttributes compilerAttributes(objects);
  251. QString name(xml.name().toString().toLower());
  252. QString text(xml.text().toString());
  253. QString tagAttributes;
  254. QMap<QString, QString> attr;
  255. if (name == CSTL::TAG::OUT && xml.isStartElement()) {
  256. attr = compilerAttributes.getAttributes(xml.attributes());
  257. htmlOut += processOutTag(attr);
  258. name.clear();
  259. } else if (name == CSTL::TAG::FOR && xml.isStartElement()) {
  260. htmlOut += processForTag(xml);
  261. name.clear();
  262. } else if (name == CSTL::TAG::IF && xml.isStartElement()) {
  263. htmlOut += processIfTag(xml);
  264. name.clear();
  265. } else if (name == CSTL::TAG::IMPORT && xml.isStartElement()) {
  266. CSTLCompilerImport importUrl(xml.attributes(), path);
  267. if (!importUrl.attributes.contains(CSTL::TAG::PROPERTY::ERROR)) {
  268. htmlOut += importUrl.attributes[CSTL::TAG::PROPERTY::IMPORT::URL].toUtf8();
  269. } else {
  270. htmlOut += importUrl.attributes[CSTL::TAG::PROPERTY::ERROR].toUtf8();
  271. }
  272. name.clear();
  273. } else {
  274. if (name != CSTL::TAG::OUT && name != CSTL::TAG::IF && name != CSTL::TAG::FOR) {
  275. attr = compilerAttributes.getAttributes(xml.attributes());
  276. tagAttributes = compilerAttributes.buildAttributes(attr);
  277. if (xml.isStartElement()) {
  278. name = "<" + name + tagAttributes + ">";
  279. } else if (xml.isEndElement()) {
  280. name = "</" + name + ">";
  281. }
  282. } else {
  283. name.clear();
  284. }
  285. }
  286. processText(text);
  287. htmlOut += name.toUtf8() + text.toUtf8();
  288. xml.readNext();
  289. if (xml.hasError()) {
  290. return "<html><body>XML ERROR: " + xml.errorString().toUtf8() + "</body></html>";
  291. }
  292. }
  293. return htmlOut;
  294. }
  295. QByteArray CSTLCompiler::output()
  296. {
  297. QXmlStreamReader xml;
  298. QByteArray htmlOutput(openFile(xml));
  299. if (isView) {
  300. if (htmlOutput.isEmpty()) {
  301. return processXml(xml).replace(CSTL::TAG::BEGIN, "").replace(CSTL::TAG::END, "");
  302. }
  303. }
  304. return htmlOutput;
  305. }
  306. CWF_END_NAMESPACE