hqlwcpp.cpp 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "jliball.hpp"
  15. #include "hql.hpp"
  16. #include "platform.h"
  17. #include "jlib.hpp"
  18. #include "jexcept.hpp"
  19. #include "jmisc.hpp"
  20. #include "hqlexpr.hpp"
  21. #include "hqlattr.hpp"
  22. #include "hqlstmt.hpp"
  23. #include "hqlfunc.hpp"
  24. #include "hqlcerrors.hpp"
  25. #include "hqlcpp.ipp"
  26. #include "hqlwcpp.hpp"
  27. #include "hqlwcpp.ipp"
  28. #define INDENT_SOURCE
  29. #define FILE_CHUNK_SIZE 65000
  30. #define PREFERRED_LINE_LIMIT 160
  31. #define REASONABLE_LINE_LIMIT 512
  32. static const char * vcIntTypes[] = { "char","short","int","int","__int64","__int64","__int64","__int64" };
  33. static const char * vcUIntTypes[] = { "unsigned char","unsigned short","unsigned","unsigned","unsigned __int64","unsigned __int64","unsigned __int64","unsigned __int64" };
  34. static const char * gccIntTypes[] = { "char","short","int","int","long long","long long","long long","long long" };
  35. static const char * gccUIntTypes[] = { "unsigned char","unsigned short","unsigned","unsigned","unsigned long long","unsigned long long","unsigned long long","unsigned long long" };
  36. // ITypeInfo and IValue implementations
  37. inline const char * intTypeName(unsigned len, CompilerType compiler, bool isSigned)
  38. {
  39. switch (compiler)
  40. {
  41. case GccCppCompiler:
  42. return isSigned ? gccIntTypes[len] : gccUIntTypes[len];
  43. case Vs6CppCompiler:
  44. return isSigned ? vcIntTypes[len] : vcUIntTypes[len];
  45. default:
  46. throwUnexpected();
  47. }
  48. }
  49. bool isTypePassedByAddress(ITypeInfo * type)
  50. {
  51. switch (type->getTypeCode())
  52. {
  53. case type_decimal:
  54. case type_string:
  55. case type_data:
  56. case type_qstring:
  57. case type_varstring:
  58. case type_unicode:
  59. case type_varunicode:
  60. case type_utf8:
  61. case type_set:
  62. case type_row:
  63. return true;
  64. case type_dictionary:
  65. case type_table:
  66. case type_groupedtable:
  67. return !isArrayRowset(type);
  68. case type_record:
  69. throwUnexpected();
  70. }
  71. return false;
  72. }
  73. static StringBuffer & appendCapital(StringBuffer & s, StringBuffer & _name)
  74. {
  75. const char * name = _name.str();
  76. if (name && name[0])
  77. {
  78. s.append((char)toupper(*name));
  79. s.append(name+1);
  80. }
  81. return s;
  82. }
  83. //---------------------------------------------------------------------------
  84. CppWriterTemplate::CppWriterTemplate()
  85. {
  86. text = NULL;
  87. len = 0;
  88. }
  89. CppWriterTemplate::~CppWriterTemplate()
  90. {
  91. free(text);
  92. }
  93. void CppWriterTemplate::generate(ISectionWriter & writer, unsigned pass, IProperties * properties)
  94. {
  95. writer.setOutput(out, outStream);
  96. const char * finger = text;
  97. bool output = true;
  98. BoolArray outputStack;
  99. StringBuffer temp;
  100. ForEachItemIn(idx, sections)
  101. {
  102. CppTemplateSection & cur = (CppTemplateSection &)sections.item(idx);
  103. if (output && (cur.position > finger))
  104. outputQuoted(writer, cur.position-finger, finger);
  105. switch (cur.type)
  106. {
  107. case TplEmbed:
  108. if (output && cur.id)
  109. writer.generateSection(cur.indent, cur.id, pass);
  110. break;
  111. case TplExpand:
  112. if (output && properties)
  113. {
  114. temp.clear();
  115. properties->getProp(cur.id->str(), temp);
  116. outputQuoted(writer, temp.length(), temp.str());
  117. }
  118. break;
  119. case TplCondition:
  120. outputStack.append(output);
  121. if (output)
  122. output = (properties && properties->hasProp(cur.id->str()));
  123. break;
  124. case TplEndCondition:
  125. output = outputStack.pop();
  126. break;
  127. }
  128. finger = cur.position + cur.len;
  129. }
  130. char * end = text+len;
  131. if (output && (end > finger))
  132. outputQuoted(writer, end-finger, finger);
  133. writer.setOutput(NULL, NULL);
  134. }
  135. bool CppWriterTemplate::loadTemplate(const char * filename, const char *dir)
  136. {
  137. StringBuffer tpl(dir);
  138. if(tpl.length())
  139. tpl.append(PATHSEPCHAR);
  140. tpl.append(filename);
  141. Owned<IFile> file = createIFile(tpl);
  142. Owned<IFileIO> io = file->openShared(IFOread, IFSHread);
  143. if (!io)
  144. return false;
  145. offset_t size = (size32_t)io->size();
  146. if (size != (size32_t)size)
  147. return false;
  148. text = (char *)malloc((size_t)size);
  149. len=io->read(0, (size32_t)size, text);
  150. unsigned index=0;
  151. unsigned startLine = 0;
  152. while (index != len)
  153. {
  154. char c = text[index];
  155. switch (c)
  156. {
  157. case '$':
  158. case '@':
  159. {
  160. unsigned start = index+1;
  161. TplSectionType type = TplEmbed;
  162. if (c == '$')
  163. {
  164. type = TplExpand;
  165. if ((start < len) && (text[start] == '?'))
  166. {
  167. start++;
  168. type = TplCondition;
  169. if ((start < len) && (text[start] == c))
  170. type = TplEndCondition;
  171. }
  172. }
  173. unsigned end = start;
  174. loop
  175. {
  176. if (end >= len)
  177. throwError(HQLERR_MissingTemplateTerminator);
  178. if (text[end] == c)
  179. break;
  180. ++end;
  181. }
  182. unsigned indent = 0;
  183. while (indent < index - startLine && isspace((byte)text[index-indent-1]))
  184. indent++;
  185. CppTemplateSection * next = new CppTemplateSection;
  186. next->type = type;
  187. next->position = text+index - indent;
  188. next->len = end+1 - index + indent;
  189. next->indent = indent;
  190. next->id = createAtom(text+start, end-start);
  191. if (end == index+1)
  192. next->len--; // quoted character => include the next @/$
  193. sections.append(*next);
  194. index = end+1;
  195. break;
  196. }
  197. case '\r':
  198. case '\n':
  199. startLine = index+1;
  200. index++;
  201. break;
  202. default:
  203. index++;
  204. break;
  205. }
  206. }
  207. return true;
  208. }
  209. //---------------------------------------------------------------------------
  210. const char * getOpText(node_operator op)
  211. {
  212. switch (op)
  213. {
  214. case no_mul: return "*";
  215. case no_div: return "/";
  216. case no_modulus: return "%";
  217. case no_negate: return "-";
  218. case no_add: return "+";
  219. case no_sub: return "-";
  220. case no_eq: return "==";
  221. case no_ne: return "!=";
  222. case no_lt: return "<";
  223. case no_le: return "<=";
  224. case no_gt: return ">";
  225. case no_ge: return ">=";
  226. case no_not: return "!";
  227. case no_and: return "&&";
  228. case no_or: return "||";
  229. case no_xor: return "xor"; //doesn't actually exist, should be transformed
  230. case no_comma: return ",";
  231. case no_compound: return ",";
  232. case no_select: return ".";
  233. case no_bnot: return "~";
  234. case no_band: return "&";
  235. case no_bor: return "|";
  236. case no_bxor: return "^";
  237. case no_postinc: return "++";
  238. case no_postdec: return "--";
  239. case no_preinc: return "++";
  240. case no_predec: return "--";
  241. case no_pselect: return "->";
  242. case no_address: return "&";
  243. case no_deref: return "*";
  244. case no_lshift: return "<<";
  245. case no_rshift: return ">>";
  246. }
  247. throwUnexpectedOp(op);
  248. }
  249. unsigned getPrecedence(IHqlExpression * expr)
  250. {
  251. node_operator op = expr->getOperator();
  252. if (op == no_typetransfer)
  253. return getPrecedence(expr->queryChild(0));
  254. switch (op)
  255. {
  256. case no_order: //pseudo operator always generated in brackets
  257. return 20;
  258. // :: = 18
  259. case no_pselect: case no_select: case no_index: case no_externalcall: case no_call:
  260. case no_reference:
  261. return 17;
  262. case no_postinc: case no_postdec:
  263. return 16;
  264. case no_not: case no_negate:
  265. case no_preinc: case no_predec:
  266. case no_bnot: case no_address: case no_deref:
  267. return 15;
  268. case no_cast:
  269. case no_implicitcast:
  270. return 14;
  271. case no_mul: case no_div: case no_modulus:
  272. return 13;
  273. case no_add: case no_sub:
  274. return 12;
  275. case no_lshift: case no_rshift:
  276. return 11;
  277. case no_lt: case no_gt: case no_le: case no_ge:
  278. return 10;
  279. case no_eq: case no_ne:
  280. return 9;
  281. case no_band:
  282. return 8;
  283. case no_bxor:
  284. return 7;
  285. case no_bor:
  286. return 6;
  287. case no_and:
  288. return 5;
  289. case no_or:
  290. return 4;
  291. case no_if:
  292. return 3;
  293. case no_assign: //op no_plus_assign etc.
  294. return 2;
  295. case no_compound:
  296. case no_comma:
  297. return 1;
  298. }
  299. return 50;
  300. }
  301. //---------------------------------------------------------------------------
  302. class TypeNameBuilder
  303. {
  304. public:
  305. TypeNameBuilder(const char * name) { typeOnLeft = false; str.append(name); }
  306. void addPrefix(const char * text)
  307. {
  308. if (str.length())
  309. str.insert(0, " ");
  310. str.insert(0, text);
  311. typeOnLeft = true;
  312. }
  313. StringBuffer & addSuffix()
  314. {
  315. if (typeOnLeft)
  316. {
  317. str.insert(0, "(").append(")");
  318. typeOnLeft = false;
  319. }
  320. return str;
  321. }
  322. StringBuffer & addArray(unsigned length)
  323. {
  324. return addSuffix().append("[").append(length ? length : 1).append("]");
  325. }
  326. void get(StringBuffer & out) { out.append(str); }
  327. protected:
  328. StringBuffer str;
  329. bool typeOnLeft;
  330. };
  331. void HqlCppWriter::generateType(StringBuffer & result, ITypeInfo * type, const char * name)
  332. {
  333. ::generateTypeCpp(result, type, name, compiler);
  334. }
  335. void HqlCppWriter::generateType(ITypeInfo * type, const char * name)
  336. {
  337. TypeNameBuilder result(name);
  338. loop
  339. {
  340. bool isPointer = false;
  341. bool outOfLine= false;
  342. ITypeInfo * fullType = type;
  343. loop
  344. {
  345. typemod_t tmod = type->queryModifier();
  346. if (tmod == typemod_none)
  347. break;
  348. switch (tmod)
  349. {
  350. case typemod_const:
  351. // result.addPrefix("const");
  352. break;
  353. case typemod_outofline:
  354. outOfLine = false;
  355. break;
  356. case typemod_ref:
  357. isPointer = true;
  358. break;
  359. }
  360. type = type->queryTypeBase();
  361. }
  362. ITypeInfo * next = type->queryChildType();
  363. type_t tc = type->getTypeCode();
  364. size32_t size = type->getSize();
  365. const char * prefix = NULL;
  366. switch (tc)
  367. {
  368. case type_pointer:
  369. {
  370. prefix = "*";
  371. break;
  372. }
  373. case type_bitfield:
  374. result.addSuffix().append(":").append(type->getBitSize());
  375. break;
  376. case type_array:
  377. {
  378. unsigned dim = type->getCardinality();
  379. result.addSuffix().append("[");
  380. if (dim && (dim != UNKNOWN_LENGTH))
  381. result.addSuffix().append(dim);
  382. result.addSuffix().append("]");
  383. break;
  384. }
  385. case type_decimal:
  386. //MORE: decimal different as parameters???
  387. case type_varstring:
  388. case type_string:
  389. case type_qstring:
  390. case type_data:
  391. case type_utf8:
  392. {
  393. if ((size != UNKNOWN_LENGTH) && !isPointer)
  394. {
  395. result.addArray(size);
  396. }
  397. else
  398. isPointer = true;
  399. if (tc == type_data)
  400. {
  401. if (isPointer)
  402. prefix = "void";
  403. else
  404. prefix = "byte";
  405. }
  406. else if (tc == type_decimal)
  407. {
  408. //make this to byte
  409. if (isPointer)
  410. prefix = "void";
  411. else
  412. prefix = "char";
  413. }
  414. else
  415. prefix = "char";
  416. break;
  417. }
  418. case type_varunicode:
  419. case type_unicode:
  420. {
  421. if ((type->getSize() != UNKNOWN_LENGTH) && !isPointer)
  422. result.addArray(size/2);
  423. else
  424. isPointer = true;
  425. prefix = "UChar";
  426. break;
  427. }
  428. case type_char:
  429. prefix = "char";
  430. break;
  431. case type_row:
  432. case type_sortlist:
  433. if (hasLinkCountedModifier(fullType))
  434. isPointer = true;
  435. prefix = "byte";
  436. next = NULL;
  437. break;
  438. case type_groupedtable:
  439. //next = next->queryChildType();
  440. isPointer = false;
  441. break;
  442. case type_dictionary:// MORE - is this right?
  443. case type_table:
  444. if (isArrayRowset(fullType))
  445. {
  446. prefix = "*";
  447. }
  448. else
  449. {
  450. isPointer = false;
  451. prefix = "*";
  452. }
  453. break;
  454. case type_class:
  455. prefix = type->queryTypeName();
  456. break;
  457. case type_boolean:
  458. prefix = "bool";
  459. break;
  460. case type_int:
  461. case type_swapint:
  462. prefix = intTypeName(size-1, compiler, type->isSigned());
  463. break;
  464. case type_real:
  465. prefix = (size == 4) ? "float" : "double";
  466. break;
  467. case type_packedint:
  468. case type_enumerated:
  469. //recurse to child type
  470. break;
  471. case type_void:
  472. case no_any:
  473. prefix = "void";
  474. break;
  475. case type_set:
  476. if (isPointer)
  477. {
  478. prefix = "byte";
  479. next = NULL;
  480. }
  481. else if (!next)
  482. {
  483. result.addPrefix("char * *");
  484. // result.addPrefix("byte");
  485. isPointer = false;
  486. }
  487. break;
  488. case type_function:
  489. {
  490. StringBuffer parameterText;
  491. IFunctionTypeExtra * extra = queryFunctionTypeExtra(type);
  492. IHqlExpression * args = static_cast<IHqlExpression *>(extra->queryParameters());
  493. ForEachChild(i, args)
  494. {
  495. if (i)
  496. parameterText.append(", ");
  497. generateExprCpp(parameterText, args->queryChild(i));
  498. }
  499. //Walk args and add the types
  500. result.addSuffix().append("(").append(parameterText).append(")");
  501. }
  502. break;
  503. case type_transform:
  504. default:
  505. throwUnexpected();
  506. }
  507. if (isPointer)
  508. {
  509. result.addPrefix("*");
  510. isPointer = false;
  511. }
  512. if (prefix)
  513. result.addPrefix(prefix);
  514. if (!next)
  515. {
  516. result.get(out);
  517. return;
  518. }
  519. type = next;
  520. }
  521. }
  522. bool HqlCppWriter::generateFunctionPrototype(IHqlExpression * funcdef)
  523. {
  524. IHqlExpression *body = funcdef->queryChild(0);
  525. StringBuffer name;
  526. getProperty(body, entrypointAtom, name);
  527. if (!name.length())
  528. name.append(funcdef->queryName());
  529. return generateFunctionPrototype(funcdef, name);
  530. }
  531. bool HqlCppWriter::generateFunctionPrototype(IHqlExpression * funcdef, const char * name)
  532. {
  533. IHqlExpression *body = funcdef->queryChild(0);
  534. IHqlExpression *formals = funcdef->queryChild(1);
  535. if (body->hasProperty(includeAtom) || body->hasProperty(ctxmethodAtom) || body->hasProperty(gctxmethodAtom) || body->hasProperty(methodAtom) || body->hasProperty(sysAtom) || body->hasProperty(omethodAtom))
  536. return false;
  537. enum { ServiceApi, RtlApi, BcdApi, CApi, LocalApi } api = ServiceApi;
  538. bool isVirtual = funcdef->hasProperty(virtualAtom);
  539. bool isLocal = body->hasProperty(localAtom);
  540. if (body->hasProperty(eclrtlAtom))
  541. api = RtlApi;
  542. else if (body->hasProperty(bcdAtom))
  543. api = BcdApi;
  544. else if (body->hasProperty(cAtom))
  545. api = CApi;
  546. else if (isLocal || isVirtual)
  547. api = LocalApi;
  548. if (isVirtual)
  549. out.append("virtual");
  550. else
  551. out.append("extern ");
  552. if ((api == ServiceApi) || api == CApi)
  553. out.append("\"C\" ");
  554. switch (api)
  555. {
  556. case ServiceApi: out.append(" SERVICE_API"); break;
  557. case RtlApi: out.append(" RTL_API"); break;
  558. case BcdApi: out.append(" BCD_API"); break;
  559. }
  560. out.append(" ");
  561. StringBuffer returnParameters;
  562. ITypeInfo * retType = funcdef->queryType()->queryChildType();
  563. generateFunctionReturnType(returnParameters, retType, body);
  564. switch (api)
  565. {
  566. case CApi:
  567. switch (compiler)
  568. {
  569. case Vs6CppCompiler:
  570. out.append(" _cdecl");
  571. break;
  572. }
  573. break;
  574. case BcdApi:
  575. switch (compiler)
  576. {
  577. case Vs6CppCompiler:
  578. out.append(" __fastcall");
  579. break;
  580. }
  581. break;
  582. }
  583. out.append(" ").append(name);
  584. bool firstParam = true;
  585. out.append('(');
  586. if (body->hasProperty(contextAtom))
  587. {
  588. out.append("ICodeContext * ctx");
  589. firstParam = false;
  590. }
  591. else if (body->hasProperty(globalContextAtom) )
  592. {
  593. out.append("IGlobalCodeContext * gctx");
  594. firstParam = false;
  595. }
  596. else if (body->hasProperty(userMatchFunctionAtom))
  597. {
  598. out.append("IMatchWalker * results");
  599. firstParam = false;
  600. }
  601. if (returnParameters.length())
  602. {
  603. if (!firstParam)
  604. out.append(',');
  605. out.append(returnParameters);
  606. firstParam = false;
  607. }
  608. ForEachChild(i, formals)
  609. {
  610. if (!firstParam)
  611. out.append(',');
  612. else
  613. firstParam = false;
  614. IHqlExpression * param = formals->queryChild(i);
  615. generateParamCpp(param);
  616. }
  617. out.append(")");
  618. return true;
  619. }
  620. void HqlCppWriter::generateInitializer(IHqlExpression * expr)
  621. {
  622. IValue * value = expr->queryValue();
  623. assertex(value);
  624. ITypeInfo * type = value->queryType();
  625. type_t tc = type->getTypeCode();
  626. size32_t size = value->getSize();
  627. const byte * raw = (const byte *)value->queryValue();
  628. out.append("{ ");
  629. switch (tc)
  630. {
  631. case type_data:
  632. case type_qstring:
  633. case type_decimal:
  634. {
  635. for (unsigned i=0; i < size; i++)
  636. {
  637. if (i)
  638. out.append(",");
  639. queryBreakLine();
  640. out.append((unsigned)raw[i]);
  641. }
  642. break;
  643. }
  644. case type_string:
  645. case type_varstring:
  646. case type_utf8:
  647. {
  648. for (unsigned i = 0; i < size; i++)
  649. {
  650. if (i)
  651. out.append(",");
  652. queryBreakLine();
  653. byte next = raw[i];
  654. switch (next)
  655. {
  656. case '\\': case '\'':
  657. out.append("'\\").append((char)next).append('\'');
  658. break;
  659. default:
  660. if (isprint(next))
  661. out.append('\'').append((char)next).append('\'');
  662. else
  663. out.append((int)next);
  664. break;
  665. }
  666. }
  667. break;
  668. }
  669. case type_unicode:
  670. case type_varunicode:
  671. {
  672. unsigned max = size/2;
  673. for (unsigned i = 0; i < max; i++)
  674. {
  675. if (i)
  676. out.append(",");
  677. queryBreakLine();
  678. UChar next = ((UChar *)raw)[i];
  679. switch (next)
  680. {
  681. case '\\': case '\'':
  682. out.append("'\\").append((char)next).append('\'');
  683. break;
  684. default:
  685. if ((next >= 32) && (next <= 126))
  686. out.append('\'').append((char)next).append('\'');
  687. else
  688. out.append((unsigned)next);
  689. break;
  690. }
  691. }
  692. break;
  693. }
  694. default:
  695. throwUnexpected();
  696. }
  697. out.append(" }");
  698. }
  699. void HqlCppWriter::generateParamCpp(IHqlExpression * param)
  700. {
  701. ITypeInfo *paramType = param->queryType();
  702. //Case is significant if these parameters are use for BEGINC++ sections
  703. _ATOM paramName = param->queryName();
  704. StringBuffer paramNameText;
  705. paramNameText.append(paramName).toLowerCase();
  706. bool isOut = false;
  707. bool isConst = false;
  708. unsigned maxAttr = param->numChildren();
  709. unsigned attrIdx;
  710. for (attrIdx = 0; attrIdx < maxAttr; attrIdx++)
  711. {
  712. IHqlExpression * attr = param->queryChild(attrIdx);
  713. if (attr->isAttribute())
  714. {
  715. if (attr->queryName() == constAtom)
  716. isConst = true;
  717. else if (attr->queryName() == outAtom)
  718. isOut = true;
  719. }
  720. }
  721. switch (paramType->getTypeCode())
  722. {
  723. case type_string:
  724. case type_qstring:
  725. case type_data:
  726. case type_unicode:
  727. case type_utf8:
  728. case type_dictionary:
  729. case type_table:
  730. case type_groupedtable:
  731. if (paramType->getSize() == UNKNOWN_LENGTH)
  732. {
  733. out.append("size32_t");
  734. if (isOut)
  735. out.append(" &");
  736. if (paramName)
  737. appendCapital(out.append(" len"), paramNameText);
  738. out.append(",");
  739. }
  740. break;
  741. case type_set:
  742. if (!queryProperty(paramType, oldSetFormatAtom))
  743. {
  744. out.append("bool");
  745. if (paramName)
  746. appendCapital(out.append(" isAll"), paramNameText);
  747. out.append(",size32_t ");
  748. if(paramName)
  749. appendCapital(out.append(" len"), paramNameText);
  750. }
  751. else
  752. {
  753. out.append("unsigned");
  754. if(paramName)
  755. appendCapital(out.append(" num"), paramNameText);
  756. }
  757. out.append(",");
  758. break;
  759. case type_row:
  760. isConst = true;
  761. break;
  762. }
  763. bool nameappended = false;
  764. switch (paramType->getTypeCode())
  765. {
  766. case type_record:
  767. out.append("IOutputMetaData * ");
  768. break;
  769. case type_dictionary:
  770. case type_table:
  771. case type_groupedtable:
  772. if (isConst)
  773. out.append("const ");
  774. out.append("void *");
  775. if (isOut)
  776. out.append(" &");
  777. break;
  778. case type_set:
  779. if (!queryProperty(paramType, oldSetFormatAtom))
  780. {
  781. if (isConst)
  782. out.append("const ");
  783. out.append("void *");
  784. if (isOut)
  785. out.append(" &");
  786. break;
  787. }
  788. else
  789. {
  790. ITypeInfo* childType = paramType->queryChildType();
  791. if(!childType)
  792. break;
  793. if(isStringType(childType)) {
  794. // process stringn and varstringn specially.
  795. if(childType->getSize() > 0) {
  796. out.append("char ");
  797. if(paramName) {
  798. out.append(paramNameText);
  799. nameappended = true;
  800. }
  801. out.append("[][");
  802. unsigned setlen = childType->getSize();
  803. out.append(setlen);
  804. out.append("]");
  805. }
  806. // Process string and varstring specially
  807. else {
  808. out.append("char *");
  809. if(paramName) {
  810. out.append(paramNameText);
  811. nameappended = true;
  812. }
  813. out.append("[]");
  814. }
  815. }
  816. else
  817. {
  818. OwnedITypeInfo pointerType = makePointerType(LINK(childType));
  819. generateType(pointerType, NULL);
  820. }
  821. break;
  822. }
  823. // Other set types just fall through and will be treated like other types.
  824. case type_qstring: case type_string: case type_varstring: case type_data:
  825. default:
  826. {
  827. if (isConst)
  828. out.append("const ");
  829. Owned<ITypeInfo> argType = LINK(paramType);
  830. if (argType->getTypeCode() == type_function)
  831. argType.setown(makePointerType(LINK(argType)));
  832. if (isTypePassedByAddress(argType))
  833. argType.setown(makeReferenceModifier(LINK(argType)));
  834. generateType(argType, paramName->str());
  835. nameappended = true;
  836. if (isOut)
  837. out.append(" &");
  838. break;
  839. }
  840. }
  841. if (paramName && !nameappended)
  842. out.append(" ").append(paramNameText);
  843. }
  844. void HqlCppWriter::generateFunctionReturnType(StringBuffer & params, ITypeInfo * retType, IHqlExpression * attrs)
  845. {
  846. type_t tc = retType->getTypeCode();
  847. switch (tc)
  848. {
  849. case type_varstring:
  850. case type_varunicode:
  851. if (retType->getSize() == UNKNOWN_LENGTH)
  852. {
  853. generateType(retType, NULL);
  854. break;
  855. }
  856. //fall through
  857. case type_qstring:
  858. case type_string:
  859. case type_data:
  860. case type_unicode:
  861. case type_utf8:
  862. {
  863. OwnedITypeInfo ptrType = makeReferenceModifier(LINK(retType));
  864. out.append("void");
  865. if (retType->getSize() == UNKNOWN_LENGTH)
  866. {
  867. if (retType->getTypeCode() != type_varstring)
  868. params.append("size32_t & __lenResult,");
  869. // if (hasConstModifier(retType))
  870. // params.append("const ");
  871. generateType(params, retType, NULL);
  872. params.append(" & __result");
  873. }
  874. else
  875. {
  876. generateType(params, ptrType, "__result");
  877. }
  878. break;
  879. }
  880. case type_transform:
  881. out.append("size32_t");
  882. params.append("ARowBuilder & __self");
  883. break;
  884. case type_dictionary:
  885. case type_table:
  886. case type_groupedtable:
  887. if (hasStreamedModifier(retType))
  888. {
  889. out.append("IRowStream *");
  890. params.append("IEngineRowAllocator * _resultAllocator");
  891. }
  892. else if (hasLinkCountedModifier(retType))
  893. {
  894. out.append("void");
  895. params.append("size32_t & __countResult,");
  896. // if (hasConstModifier(retType))
  897. // params.append("const ");
  898. params.append("byte * * & __result");
  899. if (hasNonNullRecord(retType) && getBoolProperty(attrs, allocatorAtom, true))
  900. params.append(", IEngineRowAllocator * _resultAllocator");
  901. }
  902. else
  903. {
  904. out.append("void");
  905. params.append("size32_t & __lenResult,");
  906. // if (hasConstModifier(retType))
  907. // params.append("const ");
  908. params.append("void * & __result");
  909. }
  910. break;
  911. case type_set:
  912. {
  913. out.append("void");
  914. if (!getBoolProperty(attrs, oldSetFormatAtom))
  915. {
  916. params.append("bool & __isAllResult,");
  917. params.append("size32_t & __lenResult,");
  918. }
  919. else
  920. params.append("unsigned & __numResult,");
  921. // if (hasConstModifier(retType))
  922. // params.append("const ");
  923. params.append("void * & __result");
  924. break;
  925. }
  926. case type_row:
  927. out.append("void");
  928. params.append("byte * __result");
  929. break;
  930. default:
  931. generateType(retType, NULL);
  932. break;
  933. }
  934. }
  935. StringBuffer & HqlCppWriter::generateExprCpp(StringBuffer & result, IHqlExpression * expr)
  936. {
  937. return ::generateExprCpp(result, expr, compiler);
  938. }
  939. StringBuffer & HqlCppWriter::generateExprCpp(IHqlExpression * expr)
  940. {
  941. node_operator op = expr->getOperator();
  942. switch (op)
  943. {
  944. case no_constant:
  945. {
  946. unsigned prevLen = out.length();
  947. expr->queryValue()->generateCPP(out, compiler);
  948. outputLineNum += memcount(out.length()-prevLen,out.str()+prevLen,'\n');
  949. break;
  950. }
  951. case no_eq:
  952. case no_ne:
  953. case no_lt:
  954. case no_le:
  955. case no_gt:
  956. case no_ge:
  957. case no_mul:
  958. case no_div:
  959. case no_modulus:
  960. case no_add:
  961. case no_sub:
  962. case no_and:
  963. case no_or:
  964. case no_xor:
  965. case no_comma:
  966. case no_compound:
  967. case no_band:
  968. case no_bor:
  969. case no_bxor:
  970. case no_lshift:
  971. case no_rshift:
  972. {
  973. unsigned numArgs = expr->numChildren();
  974. for (unsigned index = 0; index < numArgs; index++)
  975. {
  976. if (index != 0)
  977. out.append(' ').append(getOpText(op)).append(' ');
  978. //would be nicer if it broke at PREFERRED_LINE_LIMIT if not inside a ()
  979. queryBreakLine();
  980. generateChildExpr(expr, index);
  981. }
  982. break;
  983. }
  984. case no_pselect:
  985. case no_select:
  986. generateExprCpp(expr->queryChild(0));
  987. out.append(getOpText(op));
  988. generateExprCpp(expr->queryChild(1));
  989. break;
  990. case no_if:
  991. {
  992. generateChildExpr(expr, 0);
  993. out.append(" ? ");
  994. queryBreakLine();
  995. generateChildExpr(expr, 1);
  996. out.append(" : ");
  997. queryBreakLine();
  998. generateChildExpr(expr, 2);
  999. break;
  1000. }
  1001. case no_list:
  1002. {
  1003. out.append('{');
  1004. generateCommaChildren(expr);
  1005. out.append('}');
  1006. break;
  1007. }
  1008. case no_externalcall:
  1009. {
  1010. IHqlExpression *funcdef = expr->queryExternalDefinition();
  1011. IHqlExpression *props = funcdef->queryChild(0);
  1012. unsigned firstArg = 0;
  1013. unsigned numArgs = expr->numChildren();
  1014. if (props->hasProperty(ctxmethodAtom))
  1015. {
  1016. out.append("ctx->");
  1017. }
  1018. else if (props->hasProperty(gctxmethodAtom))
  1019. {
  1020. out.append("gctx->");
  1021. }
  1022. else if (props->hasProperty(methodAtom))
  1023. {
  1024. generateExprCpp(expr->queryChild(firstArg)).append("->");
  1025. ++firstArg;
  1026. }
  1027. else if (props->hasProperty(omethodAtom))
  1028. {
  1029. generateExprCpp(expr->queryChild(firstArg)).append(".");
  1030. ++firstArg;
  1031. }
  1032. getProperty(props, entrypointAtom, out);
  1033. out.append('(');
  1034. if (props->hasProperty(contextAtom))
  1035. {
  1036. out.append("ctx");
  1037. if (numArgs)
  1038. out.append(',');
  1039. }
  1040. else if (props->hasProperty(globalContextAtom))
  1041. {
  1042. out.append("gctx");
  1043. if (numArgs)
  1044. out.append(',');
  1045. }
  1046. for (unsigned index = firstArg; index < numArgs; index++)
  1047. {
  1048. if (index != firstArg) out.append(',');
  1049. generateExprCpp(expr->queryChild(index));
  1050. }
  1051. out.append(')');
  1052. break;
  1053. }
  1054. case no_cast:
  1055. case no_implicitcast:
  1056. {
  1057. ITypeInfo * type = expr->queryType();
  1058. IHqlExpression * child = expr->queryChild(0);
  1059. if (hasWrapperModifier(child->queryType()))
  1060. {
  1061. generateChildExpr(expr, 0).append(".");
  1062. switch (type->getTypeCode())
  1063. {
  1064. case type_string:
  1065. case type_varstring:
  1066. case type_qstring:
  1067. case type_utf8:
  1068. out.append("getstr()");
  1069. break;
  1070. case type_data:
  1071. out.append("getdata()");
  1072. break;
  1073. case type_row:
  1074. out.append("getbytes()");
  1075. break;
  1076. case type_set:
  1077. case type_dictionary:
  1078. case type_table:
  1079. case type_groupedtable:
  1080. if (hasLinkCountedModifier(type))
  1081. out.append("queryrows()");
  1082. else
  1083. out.append("getbytes()");
  1084. break;
  1085. case type_unicode:
  1086. case type_varunicode:
  1087. out.append("getustr()");
  1088. break;
  1089. default:
  1090. UNIMPLEMENTED;
  1091. }
  1092. break;
  1093. }
  1094. out.append("(");
  1095. generateType(type, NULL);
  1096. out.append(")");
  1097. generateChildExpr(expr, 0);
  1098. }
  1099. break;
  1100. case no_typetransfer:
  1101. generateExprCpp(expr->queryChild(0));
  1102. break;
  1103. case no_translated:
  1104. #ifdef _DEBUG
  1105. out.append("$translated$");//Cause a compile error.
  1106. #endif
  1107. generateExprCpp(expr->queryChild(0));
  1108. break;
  1109. case no_order:
  1110. generateOrderExpr(expr->queryChild(0), expr->queryChild(1));
  1111. break;
  1112. case no_index:
  1113. generateChildExpr(expr, 0);
  1114. out.append('[');
  1115. generateChildExpr(expr, 1);
  1116. out.append(']');
  1117. break;
  1118. case no_postinc:
  1119. case no_postdec:
  1120. generateChildExpr(expr, 0);
  1121. out.append(getOpText(op));
  1122. break;
  1123. case no_reference:
  1124. {
  1125. IHqlExpression * child = expr->queryChild(0);
  1126. generateChildExpr(expr, 0);
  1127. if (hasWrapperModifier(child->queryType()))
  1128. {
  1129. out.append(".");
  1130. ITypeInfo * type = expr->queryType();
  1131. switch (type->getTypeCode())
  1132. {
  1133. case type_string:
  1134. case type_varstring:
  1135. case type_qstring:
  1136. case type_utf8:
  1137. out.append("refstr()");
  1138. break;
  1139. case type_data:
  1140. out.append("refdata()");
  1141. break;
  1142. case type_row:
  1143. out.append("getbytes()");
  1144. break;
  1145. case type_set:
  1146. case type_dictionary:
  1147. case type_table:
  1148. case type_groupedtable:
  1149. if (hasLinkCountedModifier(type))
  1150. out.append("refrows()");
  1151. else
  1152. out.append("refdata()");
  1153. break;
  1154. case type_unicode:
  1155. case type_varunicode:
  1156. out.append("refustr()");
  1157. break;
  1158. }
  1159. }
  1160. break;
  1161. }
  1162. case no_address:
  1163. {
  1164. IHqlExpression * child = expr->queryChild(0);
  1165. ITypeInfo * childType = child->queryType();
  1166. if (hasWrapperModifier(childType))
  1167. {
  1168. generateChildExpr(expr, 0).append(".");
  1169. switch (childType->getTypeCode())
  1170. {
  1171. case type_string:
  1172. case type_varstring:
  1173. case type_qstring:
  1174. case type_utf8:
  1175. out.append("addrstr()");
  1176. break;
  1177. case type_data:
  1178. out.append("addrdata()");
  1179. break;
  1180. case type_row:
  1181. throwUnexpected();
  1182. out.append("getbytes()"); //????
  1183. break;
  1184. case type_set:
  1185. case type_dictionary:
  1186. case type_table:
  1187. case type_groupedtable:
  1188. if (hasLinkCountedModifier(childType))
  1189. out.append("addrrows()");
  1190. else
  1191. out.append("addrdata()");
  1192. break;
  1193. case type_unicode:
  1194. case type_varunicode:
  1195. out.append("addrustr()");
  1196. break;
  1197. default:
  1198. UNIMPLEMENTED;
  1199. }
  1200. }
  1201. else
  1202. {
  1203. out.append(getOpText(op));
  1204. generateChildExpr(expr, 0);
  1205. }
  1206. break;
  1207. }
  1208. case no_negate:
  1209. case no_not:
  1210. case no_bnot:
  1211. case no_deref:
  1212. case no_preinc:
  1213. case no_predec:
  1214. out.append(getOpText(op));
  1215. generateChildExpr(expr, 0);
  1216. break;
  1217. case no_quoted:
  1218. case no_variable:
  1219. return expr->toString(out);
  1220. case no_field:
  1221. return expr->toString(out); //MORE!!!
  1222. case no_create_initializer:
  1223. generateInitializer(expr->queryChild(0));
  1224. break;
  1225. case no_pure:
  1226. case no_impure:
  1227. generateExprCpp(expr->queryChild(0));
  1228. break;
  1229. case no_param:
  1230. generateParamCpp(expr);
  1231. break;
  1232. case no_callback:
  1233. {
  1234. IHqlDelayedCodeGenerator * generator = (IHqlDelayedCodeGenerator *)expr->queryUnknownExtra();
  1235. generator->generateCpp(out);
  1236. break;
  1237. }
  1238. case no_funcdef:
  1239. {
  1240. IHqlExpression * body = expr->queryChild(0);
  1241. assertex(body->getOperator() == no_external);
  1242. IHqlExpression * entrypoint = queryPropertyChild(body, entrypointAtom, 0);
  1243. getStringValue(out, entrypoint);
  1244. break;
  1245. }
  1246. case no_nullptr:
  1247. out.append("NULL");
  1248. break;
  1249. // case no_self: return out.append("self");
  1250. default:
  1251. return expr->toString(out.append("<?")).append("?>");
  1252. }
  1253. return out;
  1254. }
  1255. StringBuffer & HqlCppWriter::generateChildExpr(IHqlExpression * expr, unsigned childIndex)
  1256. {
  1257. IHqlExpression * child = expr->queryChild(childIndex);
  1258. unsigned p = getPrecedence(expr);
  1259. unsigned cp = getPrecedence(child);
  1260. bool needBra = true;
  1261. if (p < cp)
  1262. needBra = false;
  1263. else if (p == cp)
  1264. {
  1265. if (isCast(expr) && isCast(child))
  1266. needBra = false;
  1267. node_operator op = expr->getOperator();
  1268. if (op == child->getOperator())
  1269. {
  1270. switch (op)
  1271. {
  1272. case no_and:
  1273. case no_or:
  1274. case no_add:
  1275. case no_band:
  1276. case no_bor:
  1277. needBra = false;
  1278. break;
  1279. }
  1280. }
  1281. }
  1282. if (!needBra)
  1283. return generateExprCpp(child);
  1284. out.append('(');
  1285. return generateExprCpp(child).append(')');
  1286. }
  1287. StringBuffer & HqlCppWriter::generateCommaChildren(IHqlExpression * expr)
  1288. {
  1289. unsigned numArgs = expr->numChildren();
  1290. unsigned startLength = out.length();
  1291. for (unsigned index = 0; index < numArgs; index++)
  1292. {
  1293. if (index != 0)
  1294. out.append(',');
  1295. unsigned newLength = out.length();
  1296. if (newLength - startLength > PREFERRED_LINE_LIMIT)
  1297. {
  1298. newline().append("\t");
  1299. startLength = out.length();
  1300. }
  1301. generateExprCpp(expr->queryChild(index));
  1302. }
  1303. return out;
  1304. }
  1305. StringBuffer & HqlCppWriter::generateExprAsChar(IHqlExpression * expr)
  1306. {
  1307. switch (expr->getOperator())
  1308. {
  1309. case no_constant:
  1310. {
  1311. StringBuffer temp;
  1312. IValue * value = expr->queryValue();
  1313. value->getStringValue(temp);
  1314. out.append((int)temp.charAt(0));
  1315. }
  1316. break;
  1317. default:
  1318. //create an indexed node and generate that - much better
  1319. generateExprCpp(expr).append("[0]");
  1320. break;
  1321. }
  1322. return out;
  1323. }
  1324. void HqlCppWriter::generateOrderExpr(IHqlExpression * left, IHqlExpression * right)
  1325. {
  1326. ITypeInfo * lType = left->queryType();
  1327. ITypeInfo * rType = right->queryType();
  1328. ITypeInfo * lBaseType = lType;
  1329. ITypeInfo * rBaseType = rType;
  1330. if (lType->getTypeCode() == type_pointer)
  1331. lBaseType = lType->queryChildType();
  1332. if (rType->getTypeCode() == type_pointer)
  1333. rBaseType = rType->queryChildType();
  1334. assertex(isSameBasicType(lBaseType, rBaseType));
  1335. switch (lBaseType->getTypeCode())
  1336. {
  1337. case type_string:
  1338. case type_data:
  1339. case type_qstring:
  1340. case type_varstring:
  1341. case type_unicode:
  1342. case type_varunicode:
  1343. case type_utf8:
  1344. {
  1345. throwUnexpectedType(lBaseType);
  1346. break;
  1347. }
  1348. default:
  1349. out.append("(");
  1350. generateExprCpp(left).append(" < ");
  1351. generateExprCpp(right).append(" ? -1 : ");
  1352. generateExprCpp(left).append(" > ");
  1353. generateExprCpp(right).append(" ? +1 : 0)");
  1354. break;
  1355. }
  1356. }
  1357. //---------------------------------------------------------------------------
  1358. HqlCppWriter::HqlCppWriter(StringBuffer & _out, CompilerType _compiler) : out(_out)
  1359. {
  1360. curIndent = 0;
  1361. startOffset = 0;
  1362. compiler = _compiler;
  1363. outputLineNum = 1;
  1364. }
  1365. HqlCppWriter::HqlCppWriter(CompilerType _compiler) : out(defaultOut)
  1366. {
  1367. curIndent = 0;
  1368. startOffset = 0;
  1369. compiler = _compiler;
  1370. outputLineNum = 1;
  1371. }
  1372. StringBuffer & HqlCppWriter::indent()
  1373. {
  1374. #ifdef INDENT_SOURCE
  1375. unsigned i = curIndent;
  1376. for (;i > 10;i-=10)
  1377. out.append("\t\t\t\t\t\t\t\t\t\t");
  1378. out.append(i, "\t\t\t\t\t\t\t\t\t\t");
  1379. #endif
  1380. return out;
  1381. }
  1382. void HqlCppWriter::flush()
  1383. {
  1384. if (target)
  1385. {
  1386. target->write(out.length(), out.toCharArray());
  1387. out.clear();
  1388. startOffset = 0;
  1389. }
  1390. }
  1391. void HqlCppWriter::generateStmtForPass(IHqlStmt * stmt, unsigned pass)
  1392. {
  1393. switch (stmt->getStmt())
  1394. {
  1395. case pass_stmt:
  1396. if (stmt->queryExpr(0)->queryValue()->getIntValue() == pass)
  1397. generateStmt(stmt);
  1398. break;
  1399. case indirect_stmt:
  1400. {
  1401. ForEachChild(i, stmt)
  1402. generateStmtForPass(stmt->queryChild(i), pass);
  1403. break;
  1404. }
  1405. default:
  1406. generateStmt(stmt);
  1407. break;
  1408. }
  1409. }
  1410. void HqlCppWriter::generateStatementsForPass(HqlStmts & stmts, unsigned delta, unsigned pass)
  1411. {
  1412. indent((int)delta);
  1413. ForEachItemIn(i, stmts)
  1414. generateStmtForPass(&stmts.item(i), pass);
  1415. indent(-(int)delta);
  1416. flush();
  1417. }
  1418. void HqlCppWriter::generate(HqlStmtArray & stmts)
  1419. {
  1420. ForEachItemIn(idx, stmts)
  1421. {
  1422. IHqlStmt & cur = stmts.item(idx);
  1423. generateStmt(&cur);
  1424. switch (cur.getStmt())
  1425. {
  1426. case break_stmt:
  1427. case return_stmt:
  1428. case goto_stmt:
  1429. case continue_stmt:
  1430. //After these, any other expressions are irrelevant..
  1431. return;
  1432. }
  1433. }
  1434. }
  1435. void HqlCppWriter::generateChildren(IHqlStmt * stmt, bool addBraces)
  1436. {
  1437. if (addBraces)
  1438. {
  1439. queryIndent().append("{");
  1440. newline();
  1441. indent(1);
  1442. }
  1443. unsigned count = stmt->numChildren();
  1444. for (unsigned index = 0; index < count; index++)
  1445. generateStmt(stmt->queryChild(index));
  1446. if (addBraces)
  1447. {
  1448. indent(-1);
  1449. indent().append("}");
  1450. newline();
  1451. }
  1452. }
  1453. void HqlCppWriter::generateStmt(IHqlStmt * stmt)
  1454. {
  1455. if (!stmt->isIncluded())
  1456. return;
  1457. unsigned kind = stmt->getStmt();
  1458. switch (kind)
  1459. {
  1460. case assign_stmt:
  1461. generateStmtAssign(stmt);
  1462. break;
  1463. case block_stmt:
  1464. generateChildren(stmt, true);
  1465. break;
  1466. case break_stmt:
  1467. indent().append("break;");
  1468. newline();
  1469. break;
  1470. case continue_stmt:
  1471. indent().append("continue;");
  1472. newline();
  1473. break;
  1474. case case_stmt:
  1475. generateStmtCase(stmt);
  1476. break;
  1477. case declare_stmt:
  1478. case external_stmt:
  1479. generateStmtDeclare(stmt);
  1480. break;
  1481. case default_stmt:
  1482. indent().append("default:");
  1483. generateChildren(stmt, true);
  1484. break;
  1485. case expr_stmt:
  1486. indent();
  1487. generateExprCpp(stmt->queryExpr(0)).append(';');
  1488. newline();
  1489. break;
  1490. case filter_stmt:
  1491. generateStmtFilter(stmt);
  1492. break;
  1493. case goto_stmt:
  1494. indent().append("goto ");
  1495. generateExprCpp(stmt->queryExpr(0)).append(';');
  1496. newline();
  1497. break;
  1498. case function_stmt:
  1499. generateStmtFunction(stmt);
  1500. break;
  1501. case alias_stmt:
  1502. case group_stmt:
  1503. case pass_stmt:
  1504. case indirect_stmt:
  1505. generateChildren(stmt, false);
  1506. break;
  1507. case label_stmt:
  1508. generateExprCpp(stmt->queryExpr(0)).append(": ;");
  1509. newline();
  1510. break;
  1511. case loop_stmt:
  1512. generateStmtLoop(stmt);
  1513. break;
  1514. case line_stmt:
  1515. generateStmtLine(stmt);
  1516. break;
  1517. case quote_compoundopt_stmt:
  1518. case quote_stmt:
  1519. case quote_compound_stmt:
  1520. {
  1521. indent();
  1522. unsigned prevLen = out.length();
  1523. stmt->getTextExtra(out);
  1524. outputLineNum += memcount(out.length()-prevLen,out.str()+prevLen,'\n');
  1525. if (kind != quote_stmt)
  1526. {
  1527. out.append(" {");
  1528. newline();
  1529. indent(1);
  1530. generateChildren(stmt, false);
  1531. indent(-1);
  1532. indent().append("}");
  1533. IHqlExpression * extra = stmt->queryExpr(0);
  1534. if (extra)
  1535. generateExprCpp(extra);
  1536. newline();
  1537. }
  1538. else
  1539. newline();
  1540. break;
  1541. }
  1542. case return_stmt:
  1543. {
  1544. IHqlExpression * value = stmt->queryExpr(0);
  1545. if (value)
  1546. {
  1547. indent().append("return ");
  1548. generateExprCpp(stmt->queryExpr(0)).append(';');
  1549. }
  1550. else
  1551. indent().append("return;");
  1552. newline();
  1553. break;
  1554. }
  1555. case switch_stmt:
  1556. generateStmtSwitch(stmt);
  1557. break;
  1558. case assigninc_stmt:
  1559. case assigndec_stmt:
  1560. generateStmtAssignModify(stmt);
  1561. break;
  1562. }
  1563. }
  1564. void HqlCppWriter::generateSimpleAssign(IHqlExpression * target, IHqlExpression * source)
  1565. {
  1566. indent();
  1567. generateExprCpp(target).append(" = ");
  1568. generateExprCpp(source).append(";");
  1569. }
  1570. void HqlCppWriter::generateStmtAssign(IHqlStmt * assign)
  1571. {
  1572. IHqlExpression * target = assign->queryExpr(0);
  1573. IHqlExpression * source = assign->queryExpr(1);
  1574. ITypeInfo * type = target->queryType();
  1575. switch (type->getTypeCode())
  1576. {
  1577. case type_char:
  1578. case type_int:
  1579. case type_swapint:
  1580. case type_packedint:
  1581. case type_real:
  1582. case type_boolean:
  1583. case type_bitfield:
  1584. case type_pointer:
  1585. case type_enumerated:
  1586. case type_record:
  1587. generateSimpleAssign(target, source);
  1588. break;
  1589. case type_varstring:
  1590. case type_varunicode:
  1591. if (hasModifier(type, typemod_ref))
  1592. generateSimpleAssign(target, source);
  1593. else if (type->getSize() == UNKNOWN_LENGTH)
  1594. {
  1595. indent();
  1596. generateExprCpp(target).append(".setown(");
  1597. generateExprCpp(source).append(");");
  1598. }
  1599. else
  1600. throwUnexpected();
  1601. break;
  1602. case type_dictionary:
  1603. case type_table:
  1604. case type_groupedtable:
  1605. if (hasWrapperModifier(type))
  1606. {
  1607. if (hasLinkCountedModifier(type))
  1608. {
  1609. assertex(source->getOperator() == no_complex);
  1610. indent();
  1611. generateExprCpp(target).append(".setown(");
  1612. generateExprCpp(source->queryChild(0)).append(",");
  1613. generateExprCpp(source->queryChild(1)).append(");");
  1614. }
  1615. else
  1616. {
  1617. indent();
  1618. generateExprCpp(target).append(".setown(");
  1619. generateExprCpp(source).append(");");
  1620. }
  1621. }
  1622. else
  1623. generateSimpleAssign(target, source);
  1624. break;
  1625. case type_set:
  1626. case type_row:
  1627. if (hasWrapperModifier(type))
  1628. {
  1629. indent();
  1630. generateExprCpp(target).append(".setown(");
  1631. generateExprCpp(source).append(");");
  1632. }
  1633. else
  1634. generateSimpleAssign(target, source);
  1635. break;
  1636. case type_qstring:
  1637. case type_string:
  1638. case type_data:
  1639. case type_unicode:
  1640. case type_utf8:
  1641. if (hasModifier(type, typemod_ref))
  1642. generateSimpleAssign(target, source);
  1643. else
  1644. throwUnexpected();
  1645. break;
  1646. default:
  1647. if (hasModifier(type, typemod_ref))
  1648. generateSimpleAssign(target, source);
  1649. else
  1650. {
  1651. type->getTypeCode();
  1652. assertex(!"Unexpected type assignment!");
  1653. generateSimpleAssign(target, source);
  1654. out.append("$$BadType$$");
  1655. }
  1656. break;
  1657. }
  1658. newline();
  1659. }
  1660. void HqlCppWriter::generateStmtAssignModify(IHqlStmt * assign)
  1661. {
  1662. IHqlExpression * target = assign->queryExpr(0);
  1663. IHqlExpression * source = assign->queryExpr(1);
  1664. ITypeInfo * type = target->queryType();
  1665. switch (type->getTypeCode())
  1666. {
  1667. case type_row:
  1668. case type_dictionary:
  1669. case type_table:
  1670. case type_groupedtable:
  1671. //check it is a pointer increment
  1672. assertex(hasReferenceModifier(type));
  1673. case type_int:
  1674. case type_real:
  1675. case type_boolean:
  1676. case type_pointer:
  1677. indent();
  1678. generateExprCpp(target);
  1679. if (assign->getStmt() == assigninc_stmt)
  1680. out.append(" += ");
  1681. else
  1682. out.append(" -= ");
  1683. generateExprCpp(source).append(";");
  1684. break;
  1685. default:
  1686. throwUnexpected();
  1687. break;
  1688. }
  1689. newline();
  1690. }
  1691. void HqlCppWriter::generateStmtCase(IHqlStmt * stmt)
  1692. {
  1693. queryIndent().append("case ");
  1694. generateExprCpp(stmt->queryExpr(0)).append(":");
  1695. unsigned childCount = stmt->numChildren();
  1696. switch (childCount)
  1697. {
  1698. case 0:
  1699. //if case label contains nothing then it is commoned up with the next case
  1700. break;
  1701. case 1:
  1702. newline();
  1703. indent(1);
  1704. generateChildren(stmt, false);
  1705. if (stmt->queryChild(childCount-1)->getStmt() != return_stmt)
  1706. {
  1707. indent().append("break;");
  1708. newline();
  1709. }
  1710. indent(-1);
  1711. break;
  1712. default:
  1713. generateChildren(stmt, true);
  1714. if (stmt->queryChild(childCount-1)->getStmt() != return_stmt)
  1715. {
  1716. indent().append("break;");
  1717. newline();
  1718. }
  1719. }
  1720. }
  1721. void HqlCppWriter::generateStmtDeclare(IHqlStmt * declare)
  1722. {
  1723. IHqlExpression * name = declare->queryExpr(0);
  1724. IHqlExpression * value = declare->queryExpr(1);
  1725. ITypeInfo * type = name->queryType();
  1726. StringBuffer targetName;
  1727. assertex(name->getOperator() == no_variable);
  1728. name->toString(targetName);
  1729. if (declare->getStmt() == external_stmt)
  1730. out.append("extern ");
  1731. size32_t typeSize = type->getSize();
  1732. if (hasWrapperModifier(type))
  1733. {
  1734. if (hasModifier(type, typemod_builder))
  1735. indent().append("mutable rtlRowBuilder ").append(targetName);
  1736. else if (hasStreamedModifier(type))
  1737. {
  1738. indent().append("Owned<IRowStream> ").append(targetName);
  1739. }
  1740. else if (hasLinkCountedModifier(type))
  1741. {
  1742. if (type->getTypeCode() == type_row)
  1743. indent().append("rtlRowAttr ").append(targetName);
  1744. else
  1745. indent().append("rtlRowsAttr ").append(targetName);
  1746. }
  1747. else if (typeSize != UNKNOWN_LENGTH)
  1748. indent().append("rtlFixedSizeDataAttr<").append(typeSize).append("> ").append(targetName);
  1749. else
  1750. indent().append("rtlDataAttr ").append(targetName);
  1751. }
  1752. else
  1753. {
  1754. indent();
  1755. generateType(type, targetName.str());
  1756. }
  1757. if (value)
  1758. {
  1759. out.append(" = ");
  1760. generateExprCpp(value);
  1761. }
  1762. out.append(";");
  1763. newline();
  1764. }
  1765. void HqlCppWriter::generateStmtFilter(IHqlStmt * stmt)
  1766. {
  1767. IHqlExpression * condition = stmt->queryExpr(0);
  1768. IValue * value = condition->queryValue();
  1769. //optimize generation of if (false) which can't be optimized earlier.
  1770. if (value)
  1771. {
  1772. IHqlStmt * folded = (value->getBoolValue()) ? stmt->queryChild(0) : stmt->queryChild(1);
  1773. if (folded)
  1774. {
  1775. if (folded->getStmt() == block_stmt)
  1776. generateChildren(folded, false);
  1777. else
  1778. generateStmt(folded);
  1779. }
  1780. }
  1781. else
  1782. {
  1783. indent().append("if (");
  1784. generateExprCpp(condition).append(")");
  1785. generateStmt(stmt->queryChild(0));
  1786. IHqlStmt * elseCode = stmt->queryChild(1);
  1787. if (elseCode)
  1788. {
  1789. indent().append("else");
  1790. generateStmt(elseCode);
  1791. }
  1792. }
  1793. }
  1794. void HqlCppWriter::generateStmtFunction(IHqlStmt * stmt)
  1795. {
  1796. IHqlExpression * funcdef = stmt->queryExpr(0);
  1797. indent();
  1798. generateFunctionPrototype(funcdef);
  1799. generateChildren(stmt, true);
  1800. }
  1801. void HqlCppWriter::generateStmtLoop(IHqlStmt * stmt)
  1802. {
  1803. IHqlExpression * cond = stmt->queryExpr(0);
  1804. IHqlExpression * inc = stmt->queryExpr(1);
  1805. bool atEnd = false;
  1806. if (inc)
  1807. {
  1808. if (inc->isAttribute())
  1809. {
  1810. atEnd = true;
  1811. inc = NULL;
  1812. }
  1813. else
  1814. {
  1815. if (stmt->queryExpr(2) != NULL)
  1816. atEnd = true;
  1817. }
  1818. }
  1819. if (atEnd)
  1820. {
  1821. indent().append("do {").newline();
  1822. indent(1);
  1823. generateChildren(stmt, false);
  1824. if (inc)
  1825. {
  1826. indent();
  1827. generateExprCpp(inc).append(";");
  1828. newline();
  1829. }
  1830. indent(-1);
  1831. indent().append("} while (");
  1832. generateExprCpp(cond);
  1833. out.append(");");
  1834. newline();
  1835. }
  1836. else
  1837. {
  1838. indent().append("for (;");
  1839. if (cond)
  1840. generateExprCpp(cond);
  1841. out.append(";");
  1842. if (inc)
  1843. generateExprCpp(inc);
  1844. out.append(")");
  1845. generateChildren(stmt, true);
  1846. }
  1847. }
  1848. void HqlCppWriter::generateStmtLine(IHqlStmt * stmt)
  1849. {
  1850. IHqlExpression * filename = stmt->queryExpr(0);
  1851. IHqlExpression * line = stmt->queryExpr(1);
  1852. if (filename && line)
  1853. {
  1854. out.append("#line ");
  1855. generateExprCpp(line).append(" ");
  1856. generateExprCpp(filename);
  1857. newline();
  1858. }
  1859. else
  1860. {
  1861. //NB: Sets the line number of the next line...
  1862. const char * targetFilename = targetFile->queryFilename();
  1863. out.append("#line ").append(outputLineNum+1).append(" \"");
  1864. appendStringAsCPP(out, strlen(targetFilename), targetFilename, false).append("\"");
  1865. newline();
  1866. }
  1867. }
  1868. void HqlCppWriter::generateStmtSwitch(IHqlStmt * stmt)
  1869. {
  1870. indent().append("switch (");
  1871. generateExprCpp(stmt->queryExpr(0)).append(")");
  1872. generateChildren(stmt, true);
  1873. }
  1874. StringBuffer & HqlCppWriter::newline()
  1875. {
  1876. outputLineNum++;
  1877. out.newline();
  1878. if (target && (out.length() > FILE_CHUNK_SIZE))
  1879. flush();
  1880. startOffset = out.length();
  1881. return out;
  1882. }
  1883. StringBuffer & HqlCppWriter::queryIndent()
  1884. {
  1885. if (out.length() - startOffset > REASONABLE_LINE_LIMIT)
  1886. newline();
  1887. if (out.length() == startOffset)
  1888. return indent();
  1889. return out.append(" ");
  1890. }
  1891. StringBuffer & HqlCppWriter::queryBreakLine()
  1892. {
  1893. if (out.length() - startOffset > REASONABLE_LINE_LIMIT)
  1894. {
  1895. newline();
  1896. indent().append("\t");
  1897. }
  1898. return out;
  1899. }
  1900. void HqlCppWriter::queryNewline()
  1901. {
  1902. if (out.length() != startOffset)
  1903. newline();
  1904. }
  1905. void HqlCppWriter::setOutput(IFile * _targetFile, IIOStream * _target)
  1906. {
  1907. flush();
  1908. targetFile.set(_targetFile);
  1909. target.set(_target);
  1910. out.ensureCapacity(FILE_CHUNK_SIZE + 2 * REASONABLE_LINE_LIMIT);
  1911. }
  1912. void HqlCppSectionWriter::generateSection(unsigned delta, _ATOM section, unsigned pass)
  1913. {
  1914. HqlStmts * match = instance.querySection(section);
  1915. if (match)
  1916. writer.generateStatementsForPass(*match, delta, pass);
  1917. }
  1918. //---------------------------------------------------------------------------
  1919. ITemplateExpander * createTemplateExpander(IFile * output, const char * filename, const char *dir)
  1920. {
  1921. Owned<CppWriterTemplate> expander = new CppWriterTemplate;
  1922. if (expander->loadTemplate(filename, dir) || expander->loadTemplate(filename, ""))
  1923. {
  1924. expander->setOutput(output);
  1925. return expander.getClear();
  1926. }
  1927. return NULL;
  1928. }
  1929. ISectionWriter * createCppWriter(IHqlCppInstance & _instance, CompilerType compiler)
  1930. {
  1931. return new HqlCppSectionWriter(_instance, compiler);
  1932. }
  1933. extern HQLCPP_API StringBuffer & generateExprCpp(StringBuffer & out, IHqlExpression * expr, CompilerType compiler)
  1934. {
  1935. HqlCppWriter writer(out, compiler);
  1936. writer.generateExprCpp(expr);
  1937. return out;
  1938. }
  1939. extern HQLCPP_API StringBuffer & generateTypeCpp(StringBuffer & out, ITypeInfo * type, const char * name, CompilerType compiler)
  1940. {
  1941. HqlCppWriter writer(out, compiler);
  1942. writer.generateType(type, name);
  1943. return out;
  1944. }
  1945. void generateFunctionReturnType(StringBuffer & prefix, StringBuffer & params, ITypeInfo * retType, IHqlExpression * attrs, CompilerType compiler)
  1946. {
  1947. HqlCppWriter writer(prefix, compiler);
  1948. writer.generateFunctionReturnType(params, retType, attrs);
  1949. }
  1950. bool generateFunctionPrototype(StringBuffer & out, IHqlExpression * funcdef, CompilerType compiler)
  1951. {
  1952. HqlCppWriter writer(out, compiler);
  1953. return writer.generateFunctionPrototype(funcdef);
  1954. }