hqlwcpp.cpp 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120
  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_selectmap:
  1119. generateChildExpr(expr, 0);
  1120. out.append("[<");
  1121. generateChildExpr(expr, 1);
  1122. out.append(">]");
  1123. break;
  1124. case no_postinc:
  1125. case no_postdec:
  1126. generateChildExpr(expr, 0);
  1127. out.append(getOpText(op));
  1128. break;
  1129. case no_reference:
  1130. {
  1131. IHqlExpression * child = expr->queryChild(0);
  1132. generateChildExpr(expr, 0);
  1133. if (hasWrapperModifier(child->queryType()))
  1134. {
  1135. out.append(".");
  1136. ITypeInfo * type = expr->queryType();
  1137. switch (type->getTypeCode())
  1138. {
  1139. case type_string:
  1140. case type_varstring:
  1141. case type_qstring:
  1142. case type_utf8:
  1143. out.append("refstr()");
  1144. break;
  1145. case type_data:
  1146. out.append("refdata()");
  1147. break;
  1148. case type_row:
  1149. out.append("getbytes()");
  1150. break;
  1151. case type_set:
  1152. case type_dictionary:
  1153. case type_table:
  1154. case type_groupedtable:
  1155. if (hasLinkCountedModifier(type))
  1156. out.append("refrows()");
  1157. else
  1158. out.append("refdata()");
  1159. break;
  1160. case type_unicode:
  1161. case type_varunicode:
  1162. out.append("refustr()");
  1163. break;
  1164. }
  1165. }
  1166. break;
  1167. }
  1168. case no_address:
  1169. {
  1170. IHqlExpression * child = expr->queryChild(0);
  1171. ITypeInfo * childType = child->queryType();
  1172. if (hasWrapperModifier(childType))
  1173. {
  1174. generateChildExpr(expr, 0).append(".");
  1175. switch (childType->getTypeCode())
  1176. {
  1177. case type_string:
  1178. case type_varstring:
  1179. case type_qstring:
  1180. case type_utf8:
  1181. out.append("addrstr()");
  1182. break;
  1183. case type_data:
  1184. out.append("addrdata()");
  1185. break;
  1186. case type_row:
  1187. throwUnexpected();
  1188. out.append("getbytes()"); //????
  1189. break;
  1190. case type_set:
  1191. case type_dictionary:
  1192. case type_table:
  1193. case type_groupedtable:
  1194. if (hasLinkCountedModifier(childType))
  1195. out.append("addrrows()");
  1196. else
  1197. out.append("addrdata()");
  1198. break;
  1199. case type_unicode:
  1200. case type_varunicode:
  1201. out.append("addrustr()");
  1202. break;
  1203. default:
  1204. UNIMPLEMENTED;
  1205. }
  1206. }
  1207. else
  1208. {
  1209. out.append(getOpText(op));
  1210. generateChildExpr(expr, 0);
  1211. }
  1212. break;
  1213. }
  1214. case no_negate:
  1215. case no_not:
  1216. case no_bnot:
  1217. case no_deref:
  1218. case no_preinc:
  1219. case no_predec:
  1220. out.append(getOpText(op));
  1221. generateChildExpr(expr, 0);
  1222. break;
  1223. case no_quoted:
  1224. case no_variable:
  1225. return expr->toString(out);
  1226. case no_field:
  1227. return expr->toString(out); //MORE!!!
  1228. case no_create_initializer:
  1229. generateInitializer(expr->queryChild(0));
  1230. break;
  1231. case no_pure:
  1232. case no_impure:
  1233. generateExprCpp(expr->queryChild(0));
  1234. break;
  1235. case no_param:
  1236. generateParamCpp(expr);
  1237. break;
  1238. case no_callback:
  1239. {
  1240. IHqlDelayedCodeGenerator * generator = (IHqlDelayedCodeGenerator *)expr->queryUnknownExtra();
  1241. generator->generateCpp(out);
  1242. break;
  1243. }
  1244. case no_funcdef:
  1245. {
  1246. IHqlExpression * body = expr->queryChild(0);
  1247. assertex(body->getOperator() == no_external);
  1248. IHqlExpression * entrypoint = queryPropertyChild(body, entrypointAtom, 0);
  1249. getStringValue(out, entrypoint);
  1250. break;
  1251. }
  1252. case no_nullptr:
  1253. out.append("NULL");
  1254. break;
  1255. // case no_self: return out.append("self");
  1256. default:
  1257. return expr->toString(out.append("<?")).append("?>");
  1258. }
  1259. return out;
  1260. }
  1261. StringBuffer & HqlCppWriter::generateChildExpr(IHqlExpression * expr, unsigned childIndex)
  1262. {
  1263. IHqlExpression * child = expr->queryChild(childIndex);
  1264. unsigned p = getPrecedence(expr);
  1265. unsigned cp = getPrecedence(child);
  1266. bool needBra = true;
  1267. if (p < cp)
  1268. needBra = false;
  1269. else if (p == cp)
  1270. {
  1271. if (isCast(expr) && isCast(child))
  1272. needBra = false;
  1273. node_operator op = expr->getOperator();
  1274. if (op == child->getOperator())
  1275. {
  1276. switch (op)
  1277. {
  1278. case no_and:
  1279. case no_or:
  1280. case no_add:
  1281. case no_band:
  1282. case no_bor:
  1283. needBra = false;
  1284. break;
  1285. }
  1286. }
  1287. }
  1288. if (!needBra)
  1289. return generateExprCpp(child);
  1290. out.append('(');
  1291. return generateExprCpp(child).append(')');
  1292. }
  1293. StringBuffer & HqlCppWriter::generateCommaChildren(IHqlExpression * expr)
  1294. {
  1295. unsigned numArgs = expr->numChildren();
  1296. unsigned startLength = out.length();
  1297. for (unsigned index = 0; index < numArgs; index++)
  1298. {
  1299. if (index != 0)
  1300. out.append(',');
  1301. unsigned newLength = out.length();
  1302. if (newLength - startLength > PREFERRED_LINE_LIMIT)
  1303. {
  1304. newline().append("\t");
  1305. startLength = out.length();
  1306. }
  1307. generateExprCpp(expr->queryChild(index));
  1308. }
  1309. return out;
  1310. }
  1311. StringBuffer & HqlCppWriter::generateExprAsChar(IHqlExpression * expr)
  1312. {
  1313. switch (expr->getOperator())
  1314. {
  1315. case no_constant:
  1316. {
  1317. StringBuffer temp;
  1318. IValue * value = expr->queryValue();
  1319. value->getStringValue(temp);
  1320. out.append((int)temp.charAt(0));
  1321. }
  1322. break;
  1323. default:
  1324. //create an indexed node and generate that - much better
  1325. generateExprCpp(expr).append("[0]");
  1326. break;
  1327. }
  1328. return out;
  1329. }
  1330. void HqlCppWriter::generateOrderExpr(IHqlExpression * left, IHqlExpression * right)
  1331. {
  1332. ITypeInfo * lType = left->queryType();
  1333. ITypeInfo * rType = right->queryType();
  1334. ITypeInfo * lBaseType = lType;
  1335. ITypeInfo * rBaseType = rType;
  1336. if (lType->getTypeCode() == type_pointer)
  1337. lBaseType = lType->queryChildType();
  1338. if (rType->getTypeCode() == type_pointer)
  1339. rBaseType = rType->queryChildType();
  1340. assertex(isSameBasicType(lBaseType, rBaseType));
  1341. switch (lBaseType->getTypeCode())
  1342. {
  1343. case type_string:
  1344. case type_data:
  1345. case type_qstring:
  1346. case type_varstring:
  1347. case type_unicode:
  1348. case type_varunicode:
  1349. case type_utf8:
  1350. {
  1351. throwUnexpectedType(lBaseType);
  1352. break;
  1353. }
  1354. default:
  1355. out.append("(");
  1356. generateExprCpp(left).append(" < ");
  1357. generateExprCpp(right).append(" ? -1 : ");
  1358. generateExprCpp(left).append(" > ");
  1359. generateExprCpp(right).append(" ? +1 : 0)");
  1360. break;
  1361. }
  1362. }
  1363. //---------------------------------------------------------------------------
  1364. HqlCppWriter::HqlCppWriter(StringBuffer & _out, CompilerType _compiler) : out(_out)
  1365. {
  1366. curIndent = 0;
  1367. startOffset = 0;
  1368. compiler = _compiler;
  1369. outputLineNum = 1;
  1370. }
  1371. HqlCppWriter::HqlCppWriter(CompilerType _compiler) : out(defaultOut)
  1372. {
  1373. curIndent = 0;
  1374. startOffset = 0;
  1375. compiler = _compiler;
  1376. outputLineNum = 1;
  1377. }
  1378. StringBuffer & HqlCppWriter::indent()
  1379. {
  1380. #ifdef INDENT_SOURCE
  1381. unsigned i = curIndent;
  1382. for (;i > 10;i-=10)
  1383. out.append("\t\t\t\t\t\t\t\t\t\t");
  1384. out.append(i, "\t\t\t\t\t\t\t\t\t\t");
  1385. #endif
  1386. return out;
  1387. }
  1388. void HqlCppWriter::flush()
  1389. {
  1390. if (target)
  1391. {
  1392. target->write(out.length(), out.toCharArray());
  1393. out.clear();
  1394. startOffset = 0;
  1395. }
  1396. }
  1397. void HqlCppWriter::generateStmtForPass(IHqlStmt * stmt, unsigned pass)
  1398. {
  1399. switch (stmt->getStmt())
  1400. {
  1401. case pass_stmt:
  1402. if (stmt->queryExpr(0)->queryValue()->getIntValue() == pass)
  1403. generateStmt(stmt);
  1404. break;
  1405. case indirect_stmt:
  1406. {
  1407. ForEachChild(i, stmt)
  1408. generateStmtForPass(stmt->queryChild(i), pass);
  1409. break;
  1410. }
  1411. default:
  1412. generateStmt(stmt);
  1413. break;
  1414. }
  1415. }
  1416. void HqlCppWriter::generateStatementsForPass(HqlStmts & stmts, unsigned delta, unsigned pass)
  1417. {
  1418. indent((int)delta);
  1419. ForEachItemIn(i, stmts)
  1420. generateStmtForPass(&stmts.item(i), pass);
  1421. indent(-(int)delta);
  1422. flush();
  1423. }
  1424. void HqlCppWriter::generate(HqlStmtArray & stmts)
  1425. {
  1426. ForEachItemIn(idx, stmts)
  1427. {
  1428. IHqlStmt & cur = stmts.item(idx);
  1429. generateStmt(&cur);
  1430. switch (cur.getStmt())
  1431. {
  1432. case break_stmt:
  1433. case return_stmt:
  1434. case goto_stmt:
  1435. case continue_stmt:
  1436. //After these, any other expressions are irrelevant..
  1437. return;
  1438. }
  1439. }
  1440. }
  1441. void HqlCppWriter::generateChildren(IHqlStmt * stmt, bool addBraces)
  1442. {
  1443. if (addBraces)
  1444. {
  1445. queryIndent().append("{");
  1446. newline();
  1447. indent(1);
  1448. }
  1449. unsigned count = stmt->numChildren();
  1450. for (unsigned index = 0; index < count; index++)
  1451. generateStmt(stmt->queryChild(index));
  1452. if (addBraces)
  1453. {
  1454. indent(-1);
  1455. indent().append("}");
  1456. newline();
  1457. }
  1458. }
  1459. void HqlCppWriter::generateStmt(IHqlStmt * stmt)
  1460. {
  1461. if (!stmt->isIncluded())
  1462. return;
  1463. unsigned kind = stmt->getStmt();
  1464. switch (kind)
  1465. {
  1466. case assign_stmt:
  1467. generateStmtAssign(stmt);
  1468. break;
  1469. case block_stmt:
  1470. generateChildren(stmt, true);
  1471. break;
  1472. case break_stmt:
  1473. indent().append("break;");
  1474. newline();
  1475. break;
  1476. case continue_stmt:
  1477. indent().append("continue;");
  1478. newline();
  1479. break;
  1480. case case_stmt:
  1481. generateStmtCase(stmt);
  1482. break;
  1483. case declare_stmt:
  1484. case external_stmt:
  1485. generateStmtDeclare(stmt);
  1486. break;
  1487. case default_stmt:
  1488. indent().append("default:");
  1489. generateChildren(stmt, true);
  1490. break;
  1491. case expr_stmt:
  1492. indent();
  1493. generateExprCpp(stmt->queryExpr(0)).append(';');
  1494. newline();
  1495. break;
  1496. case filter_stmt:
  1497. generateStmtFilter(stmt);
  1498. break;
  1499. case goto_stmt:
  1500. indent().append("goto ");
  1501. generateExprCpp(stmt->queryExpr(0)).append(';');
  1502. newline();
  1503. break;
  1504. case function_stmt:
  1505. generateStmtFunction(stmt);
  1506. break;
  1507. case alias_stmt:
  1508. case group_stmt:
  1509. case pass_stmt:
  1510. case indirect_stmt:
  1511. generateChildren(stmt, false);
  1512. break;
  1513. case label_stmt:
  1514. generateExprCpp(stmt->queryExpr(0)).append(": ;");
  1515. newline();
  1516. break;
  1517. case loop_stmt:
  1518. generateStmtLoop(stmt);
  1519. break;
  1520. case line_stmt:
  1521. generateStmtLine(stmt);
  1522. break;
  1523. case quote_compoundopt_stmt:
  1524. case quote_stmt:
  1525. case quote_compound_stmt:
  1526. {
  1527. indent();
  1528. unsigned prevLen = out.length();
  1529. stmt->getTextExtra(out);
  1530. outputLineNum += memcount(out.length()-prevLen,out.str()+prevLen,'\n');
  1531. if (kind != quote_stmt)
  1532. {
  1533. out.append(" {");
  1534. newline();
  1535. indent(1);
  1536. generateChildren(stmt, false);
  1537. indent(-1);
  1538. indent().append("}");
  1539. IHqlExpression * extra = stmt->queryExpr(0);
  1540. if (extra)
  1541. generateExprCpp(extra);
  1542. newline();
  1543. }
  1544. else
  1545. newline();
  1546. break;
  1547. }
  1548. case return_stmt:
  1549. {
  1550. IHqlExpression * value = stmt->queryExpr(0);
  1551. if (value)
  1552. {
  1553. indent().append("return ");
  1554. generateExprCpp(stmt->queryExpr(0)).append(';');
  1555. }
  1556. else
  1557. indent().append("return;");
  1558. newline();
  1559. break;
  1560. }
  1561. case switch_stmt:
  1562. generateStmtSwitch(stmt);
  1563. break;
  1564. case assigninc_stmt:
  1565. case assigndec_stmt:
  1566. generateStmtAssignModify(stmt);
  1567. break;
  1568. }
  1569. }
  1570. void HqlCppWriter::generateSimpleAssign(IHqlExpression * target, IHqlExpression * source)
  1571. {
  1572. indent();
  1573. generateExprCpp(target).append(" = ");
  1574. generateExprCpp(source).append(";");
  1575. }
  1576. void HqlCppWriter::generateStmtAssign(IHqlStmt * assign)
  1577. {
  1578. IHqlExpression * target = assign->queryExpr(0);
  1579. IHqlExpression * source = assign->queryExpr(1);
  1580. ITypeInfo * type = target->queryType();
  1581. switch (type->getTypeCode())
  1582. {
  1583. case type_char:
  1584. case type_int:
  1585. case type_swapint:
  1586. case type_packedint:
  1587. case type_real:
  1588. case type_boolean:
  1589. case type_bitfield:
  1590. case type_pointer:
  1591. case type_enumerated:
  1592. case type_record:
  1593. generateSimpleAssign(target, source);
  1594. break;
  1595. case type_varstring:
  1596. case type_varunicode:
  1597. if (hasModifier(type, typemod_ref))
  1598. generateSimpleAssign(target, source);
  1599. else if (type->getSize() == UNKNOWN_LENGTH)
  1600. {
  1601. indent();
  1602. generateExprCpp(target).append(".setown(");
  1603. generateExprCpp(source).append(");");
  1604. }
  1605. else
  1606. throwUnexpected();
  1607. break;
  1608. case type_dictionary:
  1609. case type_table:
  1610. case type_groupedtable:
  1611. if (hasWrapperModifier(type))
  1612. {
  1613. if (hasLinkCountedModifier(type))
  1614. {
  1615. assertex(source->getOperator() == no_complex);
  1616. indent();
  1617. generateExprCpp(target).append(".setown(");
  1618. generateExprCpp(source->queryChild(0)).append(",");
  1619. generateExprCpp(source->queryChild(1)).append(");");
  1620. }
  1621. else
  1622. {
  1623. indent();
  1624. generateExprCpp(target).append(".setown(");
  1625. generateExprCpp(source).append(");");
  1626. }
  1627. }
  1628. else
  1629. generateSimpleAssign(target, source);
  1630. break;
  1631. case type_set:
  1632. case type_row:
  1633. if (hasWrapperModifier(type))
  1634. {
  1635. indent();
  1636. generateExprCpp(target).append(".setown(");
  1637. generateExprCpp(source).append(");");
  1638. }
  1639. else
  1640. generateSimpleAssign(target, source);
  1641. break;
  1642. case type_qstring:
  1643. case type_string:
  1644. case type_data:
  1645. case type_unicode:
  1646. case type_utf8:
  1647. if (hasModifier(type, typemod_ref))
  1648. generateSimpleAssign(target, source);
  1649. else
  1650. throwUnexpected();
  1651. break;
  1652. default:
  1653. if (hasModifier(type, typemod_ref))
  1654. generateSimpleAssign(target, source);
  1655. else
  1656. {
  1657. type->getTypeCode();
  1658. assertex(!"Unexpected type assignment!");
  1659. generateSimpleAssign(target, source);
  1660. out.append("$$BadType$$");
  1661. }
  1662. break;
  1663. }
  1664. newline();
  1665. }
  1666. void HqlCppWriter::generateStmtAssignModify(IHqlStmt * assign)
  1667. {
  1668. IHqlExpression * target = assign->queryExpr(0);
  1669. IHqlExpression * source = assign->queryExpr(1);
  1670. ITypeInfo * type = target->queryType();
  1671. switch (type->getTypeCode())
  1672. {
  1673. case type_row:
  1674. case type_dictionary:
  1675. case type_table:
  1676. case type_groupedtable:
  1677. //check it is a pointer increment
  1678. assertex(hasReferenceModifier(type));
  1679. case type_int:
  1680. case type_real:
  1681. case type_boolean:
  1682. case type_pointer:
  1683. indent();
  1684. generateExprCpp(target);
  1685. if (assign->getStmt() == assigninc_stmt)
  1686. out.append(" += ");
  1687. else
  1688. out.append(" -= ");
  1689. generateExprCpp(source).append(";");
  1690. break;
  1691. default:
  1692. throwUnexpected();
  1693. break;
  1694. }
  1695. newline();
  1696. }
  1697. void HqlCppWriter::generateStmtCase(IHqlStmt * stmt)
  1698. {
  1699. queryIndent().append("case ");
  1700. generateExprCpp(stmt->queryExpr(0)).append(":");
  1701. unsigned childCount = stmt->numChildren();
  1702. switch (childCount)
  1703. {
  1704. case 0:
  1705. //if case label contains nothing then it is commoned up with the next case
  1706. break;
  1707. case 1:
  1708. newline();
  1709. indent(1);
  1710. generateChildren(stmt, false);
  1711. if (stmt->queryChild(childCount-1)->getStmt() != return_stmt)
  1712. {
  1713. indent().append("break;");
  1714. newline();
  1715. }
  1716. indent(-1);
  1717. break;
  1718. default:
  1719. generateChildren(stmt, true);
  1720. if (stmt->queryChild(childCount-1)->getStmt() != return_stmt)
  1721. {
  1722. indent().append("break;");
  1723. newline();
  1724. }
  1725. }
  1726. }
  1727. void HqlCppWriter::generateStmtDeclare(IHqlStmt * declare)
  1728. {
  1729. IHqlExpression * name = declare->queryExpr(0);
  1730. IHqlExpression * value = declare->queryExpr(1);
  1731. ITypeInfo * type = name->queryType();
  1732. StringBuffer targetName;
  1733. assertex(name->getOperator() == no_variable);
  1734. name->toString(targetName);
  1735. if (declare->getStmt() == external_stmt)
  1736. out.append("extern ");
  1737. size32_t typeSize = type->getSize();
  1738. if (hasWrapperModifier(type))
  1739. {
  1740. if (hasModifier(type, typemod_builder))
  1741. indent().append("mutable rtlRowBuilder ").append(targetName);
  1742. else if (hasStreamedModifier(type))
  1743. {
  1744. indent().append("Owned<IRowStream> ").append(targetName);
  1745. }
  1746. else if (hasLinkCountedModifier(type))
  1747. {
  1748. if (type->getTypeCode() == type_row)
  1749. indent().append("rtlRowAttr ").append(targetName);
  1750. else
  1751. indent().append("rtlRowsAttr ").append(targetName);
  1752. }
  1753. else if (typeSize != UNKNOWN_LENGTH)
  1754. indent().append("rtlFixedSizeDataAttr<").append(typeSize).append("> ").append(targetName);
  1755. else
  1756. indent().append("rtlDataAttr ").append(targetName);
  1757. }
  1758. else
  1759. {
  1760. indent();
  1761. generateType(type, targetName.str());
  1762. }
  1763. if (value)
  1764. {
  1765. out.append(" = ");
  1766. generateExprCpp(value);
  1767. }
  1768. out.append(";");
  1769. newline();
  1770. }
  1771. void HqlCppWriter::generateStmtFilter(IHqlStmt * stmt)
  1772. {
  1773. IHqlExpression * condition = stmt->queryExpr(0);
  1774. IValue * value = condition->queryValue();
  1775. //optimize generation of if (false) which can't be optimized earlier.
  1776. if (value)
  1777. {
  1778. IHqlStmt * folded = (value->getBoolValue()) ? stmt->queryChild(0) : stmt->queryChild(1);
  1779. if (folded)
  1780. {
  1781. if (folded->getStmt() == block_stmt)
  1782. generateChildren(folded, false);
  1783. else
  1784. generateStmt(folded);
  1785. }
  1786. }
  1787. else
  1788. {
  1789. indent().append("if (");
  1790. generateExprCpp(condition).append(")");
  1791. generateStmt(stmt->queryChild(0));
  1792. IHqlStmt * elseCode = stmt->queryChild(1);
  1793. if (elseCode)
  1794. {
  1795. indent().append("else");
  1796. generateStmt(elseCode);
  1797. }
  1798. }
  1799. }
  1800. void HqlCppWriter::generateStmtFunction(IHqlStmt * stmt)
  1801. {
  1802. IHqlExpression * funcdef = stmt->queryExpr(0);
  1803. indent();
  1804. generateFunctionPrototype(funcdef);
  1805. generateChildren(stmt, true);
  1806. }
  1807. void HqlCppWriter::generateStmtLoop(IHqlStmt * stmt)
  1808. {
  1809. IHqlExpression * cond = stmt->queryExpr(0);
  1810. IHqlExpression * inc = stmt->queryExpr(1);
  1811. bool atEnd = false;
  1812. if (inc)
  1813. {
  1814. if (inc->isAttribute())
  1815. {
  1816. atEnd = true;
  1817. inc = NULL;
  1818. }
  1819. else
  1820. {
  1821. if (stmt->queryExpr(2) != NULL)
  1822. atEnd = true;
  1823. }
  1824. }
  1825. if (atEnd)
  1826. {
  1827. indent().append("do {").newline();
  1828. indent(1);
  1829. generateChildren(stmt, false);
  1830. if (inc)
  1831. {
  1832. indent();
  1833. generateExprCpp(inc).append(";");
  1834. newline();
  1835. }
  1836. indent(-1);
  1837. indent().append("} while (");
  1838. generateExprCpp(cond);
  1839. out.append(");");
  1840. newline();
  1841. }
  1842. else
  1843. {
  1844. indent().append("for (;");
  1845. if (cond)
  1846. generateExprCpp(cond);
  1847. out.append(";");
  1848. if (inc)
  1849. generateExprCpp(inc);
  1850. out.append(")");
  1851. generateChildren(stmt, true);
  1852. }
  1853. }
  1854. void HqlCppWriter::generateStmtLine(IHqlStmt * stmt)
  1855. {
  1856. IHqlExpression * filename = stmt->queryExpr(0);
  1857. IHqlExpression * line = stmt->queryExpr(1);
  1858. if (filename && line)
  1859. {
  1860. out.append("#line ");
  1861. generateExprCpp(line).append(" ");
  1862. generateExprCpp(filename);
  1863. newline();
  1864. }
  1865. else
  1866. {
  1867. //NB: Sets the line number of the next line...
  1868. const char * targetFilename = targetFile->queryFilename();
  1869. out.append("#line ").append(outputLineNum+1).append(" \"");
  1870. appendStringAsCPP(out, strlen(targetFilename), targetFilename, false).append("\"");
  1871. newline();
  1872. }
  1873. }
  1874. void HqlCppWriter::generateStmtSwitch(IHqlStmt * stmt)
  1875. {
  1876. indent().append("switch (");
  1877. generateExprCpp(stmt->queryExpr(0)).append(")");
  1878. generateChildren(stmt, true);
  1879. }
  1880. StringBuffer & HqlCppWriter::newline()
  1881. {
  1882. outputLineNum++;
  1883. out.newline();
  1884. if (target && (out.length() > FILE_CHUNK_SIZE))
  1885. flush();
  1886. startOffset = out.length();
  1887. return out;
  1888. }
  1889. StringBuffer & HqlCppWriter::queryIndent()
  1890. {
  1891. if (out.length() - startOffset > REASONABLE_LINE_LIMIT)
  1892. newline();
  1893. if (out.length() == startOffset)
  1894. return indent();
  1895. return out.append(" ");
  1896. }
  1897. StringBuffer & HqlCppWriter::queryBreakLine()
  1898. {
  1899. if (out.length() - startOffset > REASONABLE_LINE_LIMIT)
  1900. {
  1901. newline();
  1902. indent().append("\t");
  1903. }
  1904. return out;
  1905. }
  1906. void HqlCppWriter::queryNewline()
  1907. {
  1908. if (out.length() != startOffset)
  1909. newline();
  1910. }
  1911. void HqlCppWriter::setOutput(IFile * _targetFile, IIOStream * _target)
  1912. {
  1913. flush();
  1914. targetFile.set(_targetFile);
  1915. target.set(_target);
  1916. out.ensureCapacity(FILE_CHUNK_SIZE + 2 * REASONABLE_LINE_LIMIT);
  1917. }
  1918. void HqlCppSectionWriter::generateSection(unsigned delta, _ATOM section, unsigned pass)
  1919. {
  1920. HqlStmts * match = instance.querySection(section);
  1921. if (match)
  1922. writer.generateStatementsForPass(*match, delta, pass);
  1923. }
  1924. //---------------------------------------------------------------------------
  1925. ITemplateExpander * createTemplateExpander(IFile * output, const char * filename, const char *dir)
  1926. {
  1927. Owned<CppWriterTemplate> expander = new CppWriterTemplate;
  1928. if (expander->loadTemplate(filename, dir) || expander->loadTemplate(filename, ""))
  1929. {
  1930. expander->setOutput(output);
  1931. return expander.getClear();
  1932. }
  1933. return NULL;
  1934. }
  1935. ISectionWriter * createCppWriter(IHqlCppInstance & _instance, CompilerType compiler)
  1936. {
  1937. return new HqlCppSectionWriter(_instance, compiler);
  1938. }
  1939. extern HQLCPP_API StringBuffer & generateExprCpp(StringBuffer & out, IHqlExpression * expr, CompilerType compiler)
  1940. {
  1941. HqlCppWriter writer(out, compiler);
  1942. writer.generateExprCpp(expr);
  1943. return out;
  1944. }
  1945. extern HQLCPP_API StringBuffer & generateTypeCpp(StringBuffer & out, ITypeInfo * type, const char * name, CompilerType compiler)
  1946. {
  1947. HqlCppWriter writer(out, compiler);
  1948. writer.generateType(type, name);
  1949. return out;
  1950. }
  1951. void generateFunctionReturnType(StringBuffer & prefix, StringBuffer & params, ITypeInfo * retType, IHqlExpression * attrs, CompilerType compiler)
  1952. {
  1953. HqlCppWriter writer(prefix, compiler);
  1954. writer.generateFunctionReturnType(params, retType, attrs);
  1955. }
  1956. bool generateFunctionPrototype(StringBuffer & out, IHqlExpression * funcdef, CompilerType compiler)
  1957. {
  1958. HqlCppWriter writer(out, compiler);
  1959. return writer.generateFunctionPrototype(funcdef);
  1960. }