hqlwcpp.cpp 61 KB

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